]> git.lyx.org Git - lyx.git/blob - development/scons/SConstruct
* src/frontends/qt4/QCharacter.C:
[lyx.git] / development / scons / SConstruct
1 # vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
2 #
3 # file SConstruct
4 #
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
7 #
8 # \author Bo Peng
9 # Full author contact details are available in file CREDITS.
10 #
11 # This is a scons based building system for lyx, please refer
12 # to INSTALL.scons for detailed instructions.
13 #
14
15 import os, sys, copy, cPickle, glob, time
16
17 # scons_utils.py defines a few utility function
18 sys.path.append('config')
19 import scons_utils as utils
20 # import all file lists
21 from scons_manifest import *
22
23 #----------------------------------------------------------
24 # Required runtime environment
25 #----------------------------------------------------------
26
27 # scons asks for 1.5.2, lyx requires 2.3
28 EnsurePythonVersion(2, 3)
29 # Please use at least 0.96.92 (not 0.96.1)
30 EnsureSConsVersion(0, 96)
31 # also check for minor version number for scons 0.96
32 from SCons import __version__
33 version = map(int, __version__.split('.'))
34 if version[0] == 0 and version[1] == 96 and version[2] < 92:
35     print "Scons >= 0.96.92 is required."
36     Exit(1)
37
38 # determine where I am ...
39 #
40 from SCons.Node.FS import default_fs
41 # default_fs.SConstruct_dir is where SConstruct file is located.
42 scons_dir = default_fs.SConstruct_dir.path
43 # get the ../.. of scons_dir
44 top_src_dir = os.path.split(os.path.split(default_fs.SConstruct_dir.abspath)[0])[0]
45
46
47 #----------------------------------------------------------
48 # Global definitions
49 #----------------------------------------------------------
50
51 # some global settings
52 #
53 # get version number from configure.ac so that JMarc does
54 # not have to change SConstruct during lyx release
55 package_version = utils.getVerFromConfigure(top_src_dir)
56 package_cygwin_version = '%s-1' % package_version
57 boost_version = ['1_34']
58
59 if 'svn' in package_version:
60     devel_version = True
61     default_build_mode = 'debug'
62 else:
63     devel_version = False
64     default_build_mode = 'release'
65
66 package = 'lyx'
67 package_bugreport = 'lyx-devel@lists.lyx.org'
68 package_name = 'LyX'
69 package_tarname = 'lyx'
70 package_string = '%s %s' % (package_name, package_version)
71
72 # various cache/log files
73 default_log_file = 'scons_lyx.log'
74 opt_cache_file = 'opt.cache'
75
76
77 #----------------------------------------------------------
78 # platform dependent settings
79 #----------------------------------------------------------
80
81 if os.name == 'nt':
82     platform_name = 'win32'
83     default_prefix = 'c:/program files/lyx'
84     default_with_x = False
85     default_packaging_method = 'windows'
86 elif os.name == 'posix' and sys.platform != 'cygwin':
87     platform_name = sys.platform
88     default_prefix = '/usr/local'
89     default_with_x = True
90     default_packaging_method = 'posix'
91 elif os.name == 'posix' and sys.platform == 'cygwin':
92     platform_name = 'cygwin'
93     default_prefix = '/usr'
94     default_with_x = True
95     default_packaging_method = 'posix'
96 elif os.name == 'darwin':
97     platform_name = 'macosx'
98     # FIXME: macOSX default prefix?
99     default_prefix = '.'
100     default_with_x = False
101     default_packaging_method = 'macosx'
102 else:  # unsupported system, assume posix behavior
103     platform_name = 'others'
104     default_prefix = '.'
105     default_with_x = True
106     default_packaging_method = 'posix'
107
108 #---------------------------------------------------------
109 # Handling options
110 #----------------------------------------------------------
111 #
112 # You can set perminant default values in config.py
113 if os.path.isfile('config.py'):
114     print "Getting options from config.py..."
115     print open('config.py').read()
116
117 opts = Options(['config.py'])
118 opts.AddOptions(
119     # frontend
120     EnumOption('frontend', 'Main GUI', 'qt4',
121         allowed_values = ('qt4',) ),
122     # debug or release build
123     EnumOption('mode', 'Building method', default_build_mode,
124         allowed_values = ('debug', 'release') ),
125     # boost libraries
126     EnumOption('boost',
127         'Use included, system boost library, or try sytem boost first.',
128         'auto', allowed_values = (
129             'auto',       # detect boost, if not found, use included
130             'included',   # always use included boost
131             'system',     # always use system boost, fail if can not find
132             ) ),
133     #
134     EnumOption('gettext',
135         'Use included, system gettext library, or try sytem gettext first',
136         'auto', allowed_values = (
137             'auto',       # detect gettext, if not found, use included
138             'included',   # always use included gettext
139             'system',     # always use system gettext, fail if can not find
140             ) ),
141     #
142     EnumOption('spell', 'Choose spell checker to use.', 'auto',
143         allowed_values = ('aspell', 'pspell', 'ispell', 'auto', 'no') ),
144     # packaging method
145     EnumOption('packaging', 'Packaging method to use.', default_packaging_method,
146         allowed_values = ('windows', 'posix', 'macosx')),
147     #
148     BoolOption('fast_start', 'This option is obsolete.', False),
149     # No precompiled header support (too troublesome to make it work for msvc)
150     # BoolOption('pch', 'Whether or not use pch', False),
151     # enable assertion, (config.h has ENABLE_ASSERTIOS
152     BoolOption('assertions', 'Use assertions', True),
153     # enable warning, (config.h has WITH_WARNINGS)
154     # default to False since MSVC does not have #warning
155     BoolOption('warnings', 'Use warnings', False),
156     # config.h define _GLIBCXX_CONCEPT_CHECKS
157     # Note: for earlier version of gcc (3.3) define _GLIBCPP_CONCEPT_CHECKS
158     BoolOption('concept_checks', 'Enable concept checks', True),
159     #
160     BoolOption('nls', 'Whether or not use native language support', True),
161     #
162     BoolOption('profiling', 'Whether or not enable profiling', False),
163     # config.h define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
164     BoolOption('stdlib_debug', 'Whether or not turn on stdlib debug', False),
165     # using x11?
166     BoolOption('X11', 'Use x11 windows system', default_with_x),
167     # use MS VC++ to build lyx
168     BoolOption('use_vc', 'Use MS VC++ to build lyx (cl.exe will be probed)', None),
169     #
170     PathOption('qt_dir', 'Path to qt directory', None),
171     #
172     PathOption('qt_inc_path', 'Path to qt include directory', None),
173     #
174     PathOption('qt_lib_path', 'Path to qt library directory', None),
175     # extra include and libpath
176     PathOption('extra_inc_path', 'Extra include path', None),
177     #
178     PathOption('extra_lib_path', 'Extra library path', None),
179     #
180     PathOption('extra_bin_path', 'A convenient way to add a path to $PATH', None),
181     #
182     PathOption('extra_inc_path1', 'Extra include path', None),
183     #
184     PathOption('extra_lib_path1', 'Extra library path', None),
185     # rebuild only specifed, comma separated targets
186     ('rebuild', '''rebuild only specifed, comma separated targets.
187         yes or all (default): rebuild everything
188         no or none: rebuild nothing (usually used for installation)
189         comp1,comp2,...: rebuild specified targets''', None),
190     # can be set to a non-existing directory
191     ('prefix', 'install architecture-independent files in PREFIX', default_prefix),
192     # build directory, will use $mode if not set
193     ('build_dir', 'Build directory', None),
194     # version suffix
195     ('version_suffix', 'install lyx as lyx-suffix', None),
196     # how to load options
197     ('load_option', '''load option from previous scons run. option can be
198         yes (default): load all options
199         no: do not load any option
200         opt1,opt2: load specified options
201         -opt1,opt2: load all options other than specified ones''', 'yes'),
202     #
203     ('optimization', 'optimization CCFLAGS option.', None),
204     #
205     PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
206     # log file
207     ('logfile', 'save commands (not outputs) to logfile', default_log_file),
208     # provided for backward compatibility
209     ('dest_dir', 'install to DESTDIR. (Provided for backward compatibility only)', None),
210     # environment variable can be set as options.
211     ('DESTDIR', 'install to DESTDIR', None),
212     ('CC', 'replace default $CC', None),
213     ('LINK', 'replace default $LINK', None),
214     ('CPP', 'replace default $CPP', None),
215     ('CXX', 'replace default $CXX', None),
216     ('CXXCPP', 'replace default $CXXCPP', None),
217     ('CCFLAGS', 'replace default $CCFLAGS', None),
218     ('CPPFLAGS', 'replace default $CPPFLAGS', None),
219     ('LINKFLAGS', 'replace default $LINKFLAGS', None),
220 )
221
222 # allowed options
223 all_options = [x.key for x in opts.options]
224
225 # copied from SCons/Options/BoolOption.py
226 # We need to use them before a boolean ARGUMENTS option is available
227 # in env as bool.
228 true_strings  = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
229 false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
230
231 if ARGUMENTS.has_key('fast_start'):
232     print 'fast_start option is obsolete'
233
234 # if load_option=yes (default), load saved comand line options
235 #
236 # This option can take value yes/no/opt1,opt2/-opt1,opt2
237 # and tries to be clever in choosing options to load
238 if (not ARGUMENTS.has_key('load_option') or \
239     ARGUMENTS['load_option'] not in false_strings) \
240     and os.path.isfile(opt_cache_file):
241     cache_file = open(opt_cache_file)
242     opt_cache = cPickle.load(cache_file)
243     cache_file.close()
244     # import cached options, but we should ignore qt_dir when frontend changes
245     if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
246         and ARGUMENTS['frontend'] != opt_cache['frontend'] \
247         and opt_cache.has_key('qt_dir'):
248         opt_cache.pop('qt_dir')
249     # and we do not cache some options (dest_dir is obsolete)
250     for arg in ['load_option', 'dest_dir']:
251         if opt_cache.has_key(arg):
252             opt_cache.pop(arg)
253     # remove obsolete cached keys (well, SConstruct is evolving. :-)
254     for arg in opt_cache.keys():
255         if arg not in all_options:
256             print 'Option %s is obsolete, do not load it' % arg
257             opt_cache.pop(arg)
258     # now, if load_option=opt1,opt2 or -opt1,opt2
259     if ARGUMENTS.has_key('load_option') and \
260         ARGUMENTS['load_option'] not in true_strings + false_strings:
261         # if -opt1,opt2 is specified, do not load these options
262         if ARGUMENTS['load_option'][0] == '-':
263             for arg in ARGUMENTS['load_option'][1:].split(','):
264                 if opt_cache.has_key(arg):
265                     opt_cache.pop(arg)
266         # if opt1,opt2 is specified, only load specified options
267         else:
268             args = ARGUMENTS['load_option'].split(',')
269             for arg in opt_cache.keys():
270                 if arg not in args:
271                     opt_cache.pop(arg)
272     # now restore options as if entered from command line
273     for key in opt_cache.keys():
274         if not ARGUMENTS.has_key(key):
275             ARGUMENTS[key] = opt_cache[key]
276             print "Restoring cached option  %s=%s" % (key, ARGUMENTS[key])
277     print
278
279 # check if there is unused (or misspelled) argument
280 for arg in ARGUMENTS.keys():
281     if arg not in all_options:
282         import textwrap
283         print "Unknown option '%s'... exiting." % arg
284         print
285         print "Available options are (check 'scons -help' for details):"
286         print '    ' + '\n    '.join(textwrap.wrap(',  '.join(all_options)))
287         Exit(1)
288
289 # save options used
290 cache_file = open(opt_cache_file, 'w')
291 cPickle.dump(ARGUMENTS, cache_file)
292 cache_file.close()
293
294 #---------------------------------------------------------
295 # Setting up environment
296 #---------------------------------------------------------
297
298 # I do not really like ENV=os.environ, but you may add it
299 # here if you experience some environment related problem
300 env = Environment(options = opts)
301
302 # set individual variables since I do not really like ENV = os.environ
303 env['ENV']['PATH'] = os.environ.get('PATH')
304 env['ENV']['HOME'] = os.environ.get('HOME')
305 # these are defined for MSVC
306 env['ENV']['LIB'] = os.environ.get('LIB')
307 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
308
309 # for simplicity, use var instead of env[var]
310 frontend = env['frontend']
311 prefix = env['prefix']
312 mode = env['mode']
313
314 if platform_name == 'win32':
315     if env.has_key('use_vc'):
316         use_vc = env['use_vc']
317         if WhereIs('cl.exe') is None:
318             print "cl.exe is not found. Are you using the MSVC environment?"
319             Exit(2)
320     elif WhereIs('cl.exe') is not None:
321         use_vc = True
322     else:
323         use_vc = False
324 else:
325     use_vc = False
326
327 # lyx will be built to $build/build_dir so it is possible
328 # to build multiple build_dirs using the same source
329 # $mode can be debug or release
330 if env.has_key('build_dir') and env['build_dir'] is not None:
331     # create the directory if needed
332     if not os.path.isdir(env['build_dir']):
333         try:
334             os.makedirs(env['build_dir'])
335         except:
336             pass
337         if not os.path.isdir(env['build_dir']):
338             print 'Can not create directory', env['build_dir']
339             Exit(3)
340     env['BUILDDIR'] = env['build_dir']
341 else:
342     # Determine the name of the build $mode
343     env['BUILDDIR'] = '#' + mode
344
345 # all built libraries will go to build_dir/libs
346 # (This is different from the make file approach)
347 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
348 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
349
350
351 # Here is a summary of variables defined in env
352 # 1. defined options
353 # 2. undefined options with a non-None default value
354 # 3. compiler commands and flags like CCFLAGS.
355 #     MSGFMT used to process po files
356 # 4. Variables that will be used to replace variables in some_file.in
357 #     src/support/package.C.in:
358 #       TOP_SRCDIR, LOCALEDIR, LYX_DIR, PROGRAM_SUFFIX
359 #     lib/lyx2lyx/lyx2lyx_version.py.in
360 #       PACKAGE_VERSION
361 #     src/version.C.in
362 #       PACKAGE_VERSION, LYX_DATE, VERSION_INFO
363
364 # full path name is used to build msvs project files
365 # and to replace TOP_SRCDIR in package.C
366 env['TOP_SRCDIR'] = Dir(top_src_dir).abspath
367 # needed by src/version.C.in => src/version.C
368 env['PACKAGE_VERSION'] = package_version
369 env['LYX_DATE'] = time.asctime()
370
371 # determine share_dir etc
372 packaging_method = env.get('packaging')
373 if packaging_method == 'windows':
374     share_dir = 'Resources'
375     man_dir = 'Resources/man/man1'
376     locale_dir = 'Resources/locale'
377 else:
378     share_dir = 'share/lyx'
379     locale_dir = 'share/locale'
380     if platform_name == 'cygwin':
381         man_dir = 'share/man/man1'
382     else:
383         man_dir = 'man/man1'
384
385 # program suffix: can be yes, or a string
386 if env.has_key('version_suffix'):
387     if env['version_suffix'] in true_strings:
388         program_suffix = package_version
389     elif env['version_suffix'] in false_strings:
390         program_suffix = ''
391     else:
392         program_suffix = env['version_suffix']
393 else:
394     program_suffix = ''
395 # used by package.C.in
396 env['PROGRAM_SUFFIX'] = program_suffix
397
398 # whether or not add suffix to file and directory names
399 add_suffix = packaging_method != 'windows'
400 # LYX_DIR are different (used in package.C.in)
401 if add_suffix:
402     env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir + program_suffix)).abspath
403 else:
404     env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir)).abspath
405 # we need absolute path for package.C
406 env['LOCALEDIR'] = Dir(os.path.join(prefix, locale_dir)).abspath
407
408
409 #---------------------------------------------------------
410 # Setting building environment (Tools, compiler flags etc)
411 #---------------------------------------------------------
412
413 # Since Tool('mingw') will reset CCFLAGS etc, this should be
414 # done before getEnvVariable
415 if platform_name == 'win32':
416     if use_vc:
417         env.Tool('msvc')
418         env.Tool('mslink')
419     else:
420         env.Tool('mingw')
421         env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
422         # fix a scons winres bug (there is a missing space between ${RCINCPREFIX} and ${SOURCE.dir}
423         # in version 0.96.93
424         env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
425     
426
427 # we differentiate between hard-coded options and default options
428 # hard-coded options are required and will always be there
429 # default options can be replaced by enviromental variables or command line options
430 CCFLAGS_required = []
431 LINKFLAGS_required = []
432 CCFLAGS_default = []
433
434 # under windows, scons is confused by .C/.c and uses gcc instead of
435 # g++. I am forcing the use of g++ here. This is expected to change
436 # after lyx renames all .C files to .cpp
437 #
438 # save the old c compiler and CCFLAGS (used by libintl)
439 C_COMPILER = env.subst('$CC')
440 C_CCFLAGS = env.subst('$CCFLAGS').split()
441 # if we use ms vc, the commands are fine (cl.exe and link.exe)
442 if use_vc:
443     # /TP treat all source code as C++
444     # C4819: The file contains a character that cannot be represented
445     #   in the current code page (number)
446     # C4996: foo was decleared deprecated
447     CCFLAGS_required.extend(['/TP', '/EHsc'])
448     if mode == 'debug':
449         CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
450         # the flags are also needed in C mode (for intl lib)
451         C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
452     else:
453         CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
454         C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
455 else:
456     if env.has_key('CXX') and env['CXX']:
457         env['CC'] = env.subst('$CXX')
458         env['LINK'] = env.subst('$CXX')
459     else:
460         env['CC'] = 'g++'
461         env['LINK'] = 'g++'
462
463 # for debug/release mode
464 if env.has_key('optimization') and env['optimization'] is not None:
465     # if user supplies optimization flags, use it anyway
466     CCFLAGS_required.extend(env['optimization'].split())
467     # and do not use default
468     set_default_optimization_flags = False
469 else:
470     set_default_optimization_flags = True
471
472 if mode == 'debug':
473     if use_vc:
474         CCFLAGS_required.append('/Zi')
475         LINKFLAGS_required.extend(['/debug', '/map'])
476     else:
477         CCFLAGS_required.append('-g')
478         CCFLAGS_default.append('-O')
479 elif mode == 'release' and set_default_optimization_flags:
480     if use_vc:
481         CCFLAGS_default.append('/O2')
482     else:
483         CCFLAGS_default.append('-O2')
484
485 # msvc uses separate tools for profiling
486 if env.has_key('profiling') and env['profiling']:
487     if use_vc:
488         print 'Visual C++ does not use profiling options'
489     else:
490         CCFLAGS_required.append('-pg')
491         LINKFLAGS_required.append('-pg')
492
493 if env.has_key('warnings') and env['warnings']:
494     if use_vc:
495         CCFLAGS_default.append('/W2')
496     else:
497         # Note: autotools detect gxx version and pass -W for 3.x
498         # and -Wextra for other versions of gcc
499         CCFLAGS_default.append('-Wall')
500
501 # Now, set the variables as follows:
502 # 1. if command line option exists: replace default
503 # 2. then if s envronment variable exists: replace default
504 # 3. set variable to required + default
505 def setEnvVariable(env, name, required = None, default = None, split = True):
506     ''' env: environment to set variable
507             name: variable
508             required: hardcoded options
509             default: default options that can be replaced by command line or
510                 environment variables
511             split: whether or not split obtained variable like '-02 -g'
512     '''
513     # 1. ARGUMENTS is already set to env[name], override default.
514     if ARGUMENTS.has_key(name):
515         # env[name] may be rewritten when building tools are reloaded
516         # if that is the case, commandline option will override it.
517         env[name] = ARGUMENTS[name]
518         default = None
519     # then use environment default
520     elif os.environ.has_key(name):
521         print "Acquiring variable %s from system environment: %s" % (name, os.environ[name])
522         default = os.environ[name]
523         if split:
524             default = default.split()
525     # the real value should be env[name] + default + required
526     if split:
527         value = []
528         if env.has_key(name):
529             value = str(env[name]).split()
530         if required is not None:
531             value += required
532         if default is not None:
533             value += default
534     else:
535         value = ""
536         if env.has_key(name):
537             value = str(env[name])
538         if required is not None:
539             value += " " + required
540         if default is not None:
541             value += " " + default
542     env[name] = value
543     # print name, env[name]
544
545 setEnvVariable(env, 'DESTDIR', split=False)
546 setEnvVariable(env, 'CC')
547 setEnvVariable(env, 'LINK')
548 setEnvVariable(env, 'CPP')
549 setEnvVariable(env, 'CXX')
550 setEnvVariable(env, 'CXXCPP')
551 setEnvVariable(env, 'CCFLAGS', CCFLAGS_required, CCFLAGS_default)
552 setEnvVariable(env, 'CXXFLAGS')
553 setEnvVariable(env, 'CPPFLAGS')
554 setEnvVariable(env, 'LINKFLAGS', LINKFLAGS_required)
555
556 # if DESTDIR is not set...
557 if env.has_key('dest_dir'):
558     print "This option is obsolete. Please use DESTDIR instead."
559     env['DESTDIR'] = env['dest_dir']
560
561 #
562 # extra_inc_path and extra_lib_path
563 #
564 extra_inc_paths = []
565 if env.has_key('extra_inc_path') and env['extra_inc_path']:
566     extra_inc_paths.append(env['extra_inc_path'])
567 if env.has_key('extra_lib_path') and env['extra_lib_path']:
568     env.AppendUnique(LIBPATH = [env['extra_lib_path']])
569 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
570     extra_inc_paths.append(env['extra_inc_path1'])
571 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
572     env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
573 if env.has_key('extra_bin_path') and env['extra_bin_path']:
574     # only the first one is needed (a scons bug?)
575     os.environ['PATH'] += os.pathsep + env['extra_bin_path']
576     env.PrependENVPath('PATH', env['extra_bin_path'])
577 # extra_inc_paths will be used later by intlenv etc
578 env.AppendUnique(CPPPATH = extra_inc_paths)
579
580
581 #----------------------------------------------------------
582 # Autoconf business
583 #----------------------------------------------------------
584
585 conf = Configure(env,
586     custom_tests = {
587         'CheckPkgConfig' : utils.checkPkgConfig,
588         'CheckPackage' : utils.checkPackage,
589         'CheckMkdirOneArg' : utils.checkMkdirOneArg,
590         'CheckSelectArgType' : utils.checkSelectArgType,
591         'CheckBoostLibraries' : utils.checkBoostLibraries,
592         'CheckCommand' : utils.checkCommand,
593         'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd,
594         'CheckLC_MESSAGES' : utils.checkLC_MESSAGES,
595         'CheckIconvConst' : utils.checkIconvConst,
596         'CheckSizeOfWChar' : utils.checkSizeOfWChar,
597     }
598 )
599
600 # pkg-config? (if not, we use hard-coded options)
601 if conf.CheckPkgConfig('0.15.0'):
602     env['HAS_PKG_CONFIG'] = True
603 else:
604     print 'pkg-config >= 0.1.50 is not found'
605     env['HAS_PKG_CONFIG'] = False
606
607 # zlib? This is required.
608 if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \
609     or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')):
610     print 'Did not find zdll.lib or zlib.h, exiting!'
611     Exit(1)
612 if conf.CheckLib('iconv'):
613     env['ICONV_LIB'] = 'iconv'
614 elif conf.CheckLib('libiconv'):
615     env['ICONV_LIB'] = 'libiconv'
616 elif conf.CheckFunc('iconv_open'):
617     env['ICONV_LIB'] = None
618 else:
619     print 'Did not find iconv or libiconv, exiting!'
620     Exit(1)
621
622 # check socket libs
623 socket_libs = []
624 if conf.CheckLib('socket'):
625     socket_libs.append('socket')
626 # nsl is the network services library and provides a
627 # transport-level interface to networking services.
628 if conf.CheckLib('nsl'):
629     socket_libs.append('nsl')
630
631 # check available boost libs (since lyx1.4 does not use iostream)
632 boost_libs = []
633 for lib in ['signals', 'regex', 'filesystem', 'iostreams']:
634     if os.path.isdir(os.path.join(top_src_dir, 'boost', 'libs', lib)):
635         boost_libs.append(lib)
636
637 # check boost libraries
638 boost_opt = ARGUMENTS.get('boost', 'auto')
639 # check for system boost
640 lib_paths = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
641 inc_paths = env['CPPPATH'] + ['/usr/include', '/usr/local/include']
642 # default to $BUILDDIR/libs (use None since this path will be added anyway)
643 boost_libpath = None
644 # here I assume that all libraries are in the same directory
645 if boost_opt == 'included':
646     boost_libraries = ['included_boost_%s' % x for x in boost_libs]
647     included_boost = True
648     env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
649 elif boost_opt == 'auto':
650     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
651     # if not found, use local boost
652     if res[0] is None:
653         boost_libraries = ['included_boost_%s' % x for x in boost_libs]
654         included_boost = True
655         env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
656     else:
657         included_boost = False
658         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
659 elif boost_opt == 'system':
660     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
661     if res[0] is None:
662         print "Can not find system boost libraries with version %s " % boost_version
663         print "Please supply a path through extra_lib_path and try again."
664         print "Or use boost=included to use included boost libraries."
665         Exit(2)
666     else:
667         included_boost = False
668         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
669
670
671 if boost_libpath is not None:
672     env.AppendUnique(LIBPATH = [boost_libpath])
673
674
675 env['ENABLE_NLS'] = env['nls']
676
677 if not env['ENABLE_NLS']:
678     intl_libs = []
679     included_gettext = False
680 else:
681     # check gettext libraries
682     gettext_opt = ARGUMENTS.get('gettext', 'auto')
683     # check for system gettext
684     succ = False
685     if gettext_opt in ['auto', 'system']:
686         if conf.CheckFunc('gettext'):
687             included_gettext = False
688             intl_libs = []
689             succ = True
690         elif conf.CheckLib('intl'):
691             included_gettext = False
692             intl_libs = ['intl']
693             succ = True
694         else: # no found
695             if gettext_opt == 'system':
696                 print "Can not find system gettext library"
697                 print "Please supply a path through extra_lib_path and try again."
698                 print "Or use gettext=included to use included gettext libraries."
699                 Exit(2)
700     # now, auto and succ = false, or gettext=included
701     if not succ:
702         # we do not need to set LIBPATH now.
703         included_gettext = True
704         intl_libs = ['included_intl']
705
706
707 #
708 # check for msgfmt command
709 env['MSGFMT'] = conf.CheckCommand('msgfmt')
710
711 # cygwin packaging requires the binaries to be stripped
712 if platform_name == 'cygwin':
713     env['STRIP'] = conf.CheckCommand('strip')
714
715 #
716 # Customized builders
717 #
718 # install customized builders
719 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
720
721
722 #----------------------------------------------------------
723 # Generating config.h
724 #----------------------------------------------------------
725 aspell_lib = 'aspell'
726 # assume that we use aspell, aspelld compiled for msvc
727 if platform_name == 'win32' and mode == 'debug' and use_vc:
728     aspell_lib = 'aspelld'
729
730 # check the existence of config.h
731 config_h = os.path.join(env.Dir('$BUILDDIR/common').path, 'config.h')
732 boost_config_h = os.path.join(env.Dir('$BUILDDIR/boost').path, 'config.h')
733 #
734 print "Creating %s..." % boost_config_h
735 #
736 utils.createConfigFile(conf,
737     config_file = boost_config_h,
738     config_pre = '''/* boost/config.h.  Generated by SCons.  */
739
740 /* -*- C++ -*- */
741 /*
742 * \file config.h
743 * This file is part of LyX, the document processor.
744 * Licence details can be found in the file COPYING.
745 *
746 * This is the compilation configuration file for LyX.
747 * It was generated by scon.
748 * You might want to change some of the defaults if something goes wrong
749 * during the compilation.
750 */
751
752 #ifndef _BOOST_CONFIG_H
753 #define _BOOST_CONFIG_H
754 ''',
755     headers = [
756         ('ostream', 'HAVE_OSTREAM', 'cxx'),
757         ('locale', 'HAVE_LOCALE', 'cxx'),
758         ('sstream', 'HAVE_SSTREAM', 'cxx'),
759         #('newapis.h', 'HAVE_NEWAPIS_H', 'c'),
760     ],
761     custom_tests = [
762         (env.has_key('assertions') and env['assertions'],
763             'ENABLE_ASSERTIONS',
764             'Define if you want assertions to be enabled in the code'
765         ),
766     ],
767     types = [
768         ('wchar_t', 'HAVE_WCHAR_T', None),
769     ],
770     config_post = '''
771
772 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
773 #  define USE_BOOST_FORMAT 1
774 #else
775 #  define USE_BOOST_FORMAT 0
776 #endif
777
778 #if !defined(ENABLE_ASSERTIONS)
779 #  define BOOST_DISABLE_ASSERTS 1
780 #endif
781 #define BOOST_ENABLE_ASSERT_HANDLER 1
782
783 #define BOOST_DISABLE_THREADS 1
784 #define BOOST_NO_WSTRING 1
785
786 #ifdef __CYGWIN__
787 #  define BOOST_POSIX 1
788 #  define BOOST_POSIX_API 1
789 #  define BOOST_POSIX_PATH 1
790 #endif
791
792 #define BOOST_ALL_NO_LIB 1
793
794 #if defined(HAVE_NEWAPIS_H)
795 #  define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
796 #endif
797
798 #if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4
799 #  define LIBC_WCTYPE_USES_UCS4
800 #endif
801
802 #endif
803 '''
804 )
805 #
806 print "\nGenerating %s..." % config_h
807
808 # AIKSAURUS_H_LOCATION
809 if (conf.CheckCXXHeader("Aiksaurus.h")):
810     aik_location = '<Aiksaurus.h>'
811 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
812     aik_location = '<Aiksaurus/Aiksaurus.h>'
813 else:
814     aik_location = ''
815
816 # determine headers to use
817 spell_opt = ARGUMENTS.get('spell', 'auto')
818 env['USE_ASPELL'] = False
819 env['USE_PSPELL'] = False
820 env['USE_ISPELL'] = False
821 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
822     spell_engine = 'USE_ASPELL'
823 elif spell_opt in ['auto', 'pspell'] and conf.CheckLib('pspell'):
824     spell_engine = 'USE_PSPELL'
825 elif spell_opt in ['auto', 'ispell'] and conf.CheckLib('ispell'):
826     spell_engine = 'USE_ISPELL'
827 else:
828     spell_engine = None
829
830 if spell_engine is not None:
831     env[spell_engine] = True
832 else:
833     if spell_opt == 'auto':
834         print "Warning: Can not locate any spell checker"
835     elif spell_opt != 'no':
836         print "Warning: Can not locate specified spell checker:", spell_opt
837         Exit(1)
838
839 # check arg types of select function
840 (select_arg1, select_arg234, select_arg5) = conf.CheckSelectArgType()
841
842 # check the size of wchar_t
843 sizeof_wchar_t = conf.CheckSizeOfWChar()
844 # something wrong
845 if sizeof_wchar_t == 0:
846     print 'Error: Can not determine the size of wchar_t.'
847     Exit(1)
848
849 #
850 # create config.h
851 result = utils.createConfigFile(conf,
852     config_file = config_h,
853     config_pre = '''/* config.h.  Generated by SCons.  */
854
855 /* -*- C++ -*- */
856 /*
857 * \file config.h
858 * This file is part of LyX, the document processor.
859 * Licence details can be found in the file COPYING.
860 *
861 * This is the compilation configuration file for LyX.
862 * It was generated by scon.
863 * You might want to change some of the defaults if something goes wrong
864 * during the compilation.
865 */
866
867 #ifndef _CONFIG_H
868 #define _CONFIG_H
869 ''',
870     headers = [
871         ('io.h', 'HAVE_IO_H', 'c'),
872         ('limits.h', 'HAVE_LIMITS_H', 'c'),
873         ('locale.h', 'HAVE_LOCALE_H', 'c'),
874         ('process.h', 'HAVE_PROCESS_H', 'c'),
875         ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
876         ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
877         ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
878         ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
879         ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
880         ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
881         ('unistd.h', 'HAVE_UNISTD_H', 'c'),
882         ('utime.h', 'HAVE_UTIME_H', 'c'),
883         ('direct.h', 'HAVE_DIRECT_H', 'c'),
884         ('istream', 'HAVE_ISTREAM', 'cxx'),
885         ('ios', 'HAVE_IOS', 'cxx'),
886     ],
887     functions = [
888         ('open', 'HAVE_OPEN', None),
889         ('chmod', 'HAVE_CHMOD', None),
890         ('close', 'HAVE_CLOSE', None),
891         ('popen', 'HAVE_POPEN', None),
892         ('pclose', 'HAVE_PCLOSE', None),
893         ('_open', 'HAVE__OPEN', None),
894         ('_close', 'HAVE__CLOSE', None),
895         ('_popen', 'HAVE__POPEN', None),
896         ('_pclose', 'HAVE__PCLOSE', None),
897         ('getpid', 'HAVE_GETPID', None),
898         ('_getpid', 'HAVE__GETPID', None),
899         ('mkdir', 'HAVE_MKDIR', None),
900         ('_mkdir', 'HAVE__MKDIR', None),
901         ('mktemp', 'HAVE_MKTEMP', None),
902         ('mkstemp', 'HAVE_MKSTEMP', None),
903         ('strerror', 'HAVE_STRERROR', None),
904         ('count', 'HAVE_STD_COUNT', '''
905 #include <algorithm>
906 int count()
907 {
908 char a[] = "hello";
909 return std::count(a, a+5, 'l');
910 }
911 '''),
912         ('getcwd', 'HAVE_GETCWD', None),
913         ('setenv', 'HAVE_SETENV', None),
914         ('putenv', 'HAVE_PUTENV', None),
915         ('fcntl', 'HAVE_FCNTL', None),
916     ],
917     types = [
918         ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
919             '#include <streambuf>\n#include <istream>'),
920         ('wchar_t', 'HAVE_WCHAR_T', None),
921         ('mode_t', 'HAVE_MODE_T', "#include <sys/types.h>"),
922     ],
923     libs = [
924         ('gdi32', 'HAVE_LIBGDI32'),
925         (('Aiksaurus', 'libAiksaurus'), 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB'),
926     ],
927     custom_tests = [
928         (conf.CheckType('pid_t', includes='#include <sys/types.h>'),
929             'HAVE_PID_T',
930             'Define is sys/types.h does not have pid_t',
931             '',
932             '#define pid_t int',
933         ),
934         (conf.CheckCXXGlobalCstd(),
935             'CXX_GLOBAL_CSTD',
936             'Define if your C++ compiler puts C library functions in the global namespace'
937         ),
938         (conf.CheckMkdirOneArg(),
939             'MKDIR_TAKES_ONE_ARG',
940             'Define if mkdir takes only one argument.'
941         ),
942         (conf.CheckIconvConst(),
943             'ICONV_CONST',
944             'Define as const if the declaration of iconv() needs const.',
945             '#define ICONV_CONST const',
946             '#define ICONV_CONST',
947         ),
948         (conf.CheckLC_MESSAGES(),
949             'HAVE_LC_MESSAGES',
950             'Define if your <locale.h> file defines LC_MESSAGES.'
951         ),
952         (devel_version, 'DEVEL_VERSION', 'Whether or not a development version'),
953         (env['nls'],
954             'ENABLE_NLS',
955             "Define to 1 if translation of program messages to the user's native anguage is requested.",
956         ),
957         (env['nls'] and not included_gettext,
958             'HAVE_GETTEXT',
959             'Define to 1 if using system gettext library'
960         ),
961         (env.has_key('warnings') and env['warnings'],
962             'WITH_WARNINGS',
963             'Define this if you want to see the warning directives put here and there by the developpers to get attention'
964         ),
965         (env.has_key('concept_checks') and env['concept_checks'],
966             '_GLIBCXX_CONCEPT_CHECKS',
967             'libstdc++ concept checking'
968         ),
969         (env.has_key('stdlib_debug') and env['stdlib_debug'],
970             '_GLIBCXX_DEBUG',
971             'libstdc++ debug mode'
972         ),
973         (env.has_key('stdlib_debug') and env['stdlib_debug'],
974             '_GLIBCXX_DEBUG_PEDANTIC',
975             'libstdc++ pedantic debug mode'
976         ),
977         (os.name != 'nt', 'BOOST_POSIX',
978             'Indicates to boost < 1.34 which API to use (posix or windows).'
979         ),
980         (os.name != 'nt', 'BOOST_POSIX_API',
981             'Indicates to boost 1.34 which API to use (posix or windows).'
982         ),
983         (os.name != 'nt', 'BOOST_POSIX_PATH',
984             'Indicates to boost 1.34 which path style to use (posix or windows).'
985         ),
986         (spell_engine is not None, spell_engine,
987             'Spell engine to use'
988         ),
989         # we need to know the byte order for unicode conversions
990         (sys.byteorder == 'big', 'WORDS_BIGENDIAN',
991             'Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).'
992         ),
993     ],
994     extra_items = [
995         ('#define PACKAGE "%s%s"' % (package, program_suffix),
996             'Name of package'),
997         ('#define PACKAGE_BUGREPORT "%s"' % package_bugreport,
998             'Define to the address where bug reports for this package should be sent.'),
999         ('#define PACKAGE_NAME "%s"' % package_name,
1000             'Define to the full name of this package.'),
1001         ('#define PACKAGE_STRING "%s"' % package_string,
1002             'Define to the full name and version of this package.'),
1003         ('#define PACKAGE_TARNAME "%s"' % package_tarname,
1004             'Define to the one symbol short name of this package.'),
1005         ('#define PACKAGE_VERSION "%s"' % package_version,
1006             'Define to the version of this package.'),
1007         ('#define BOOST_ALL_NO_LIB 1',
1008             'disable automatic linking of boost libraries.'),
1009         ('#define USE_%s_PACKAGING 1' % packaging_method.upper(),
1010             'Packaging method'),
1011         ('#define AIKSAURUS_H_LOCATION ' + aik_location,
1012             'Aiksaurus include file'),
1013         ('#define SELECT_TYPE_ARG1 %s' % select_arg1,
1014             "Define to the type of arg 1 for `select'."),
1015         ('#define SELECT_TYPE_ARG234 %s' % select_arg234,
1016             "Define to the type of arg 2, 3, 4 for `select'."),
1017         ('#define SELECT_TYPE_ARG5 %s' % select_arg5,
1018             "Define to the type of arg 5 for `select'."),
1019         ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1020             'Define to be the size of type wchar_t'),
1021     ],
1022     config_post = '''/************************************************************
1023 ** You should not need to change anything beyond this point */
1024
1025 #ifndef HAVE_STRERROR
1026 #if defined(__cplusplus)
1027 extern "C"
1028 #endif
1029 char * strerror(int n);
1030 #endif
1031
1032 #ifdef HAVE_MKSTEMP
1033 #ifndef HAVE_DECL_MKSTEMP
1034 #if defined(__cplusplus)
1035 extern "C"
1036 #endif
1037 int mkstemp(char*);
1038 #endif
1039 #endif
1040
1041 #include <../boost/config.h>
1042
1043 #endif
1044 '''
1045 )
1046
1047 # these keys are needed in env
1048 for key in ['USE_ASPELL', 'USE_PSPELL', 'USE_ISPELL', 'HAVE_FCNTL',\
1049     'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
1050     # USE_ASPELL etc does not go through result
1051     if result.has_key(key):
1052         env[key] = result[key]
1053
1054 #
1055 # if nls=yes and gettext=included, create intl/config.h
1056 # intl/libintl.h etc
1057 #
1058 intl_config_h = os.path.join(env.Dir('$BUILDDIR/intl').path, 'config.h')
1059 if env['nls'] and included_gettext:
1060     #
1061     print "Creating %s..." % intl_config_h
1062     #
1063     # create intl/config.h
1064     result = utils.createConfigFile(conf,
1065         config_file = intl_config_h,
1066         config_pre = '''/* intl/config.h.  Generated by SCons.  */
1067
1068 /* -*- C++ -*- */
1069 /*
1070 * \file config.h
1071 * This file is part of LyX, the document processor.
1072 * Licence details can be found in the file COPYING.
1073 *
1074 * This is the compilation configuration file for LyX.
1075 * It was generated by scon.
1076 * You might want to change some of the defaults if something goes wrong
1077 * during the compilation.
1078 */
1079
1080 #ifndef _CONFIG_H
1081 #define _CONFIG_H
1082 ''',
1083         headers = [
1084             ('unistd.h', 'HAVE_UNISTD_H', 'c'),
1085             ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
1086             ('string.h', 'HAVE_STRING_H', 'c'),
1087             ('strings.h', 'HAVE_STRINGS_H', 'c'),
1088             ('argz.h', 'HAVE_ARGZ_H', 'c'),
1089             ('limits.h', 'HAVE_LIMITS_H', 'c'),
1090             ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
1091             ('stddef.h', 'HAVE_STDDEF_H', 'c'),
1092             ('stdint.h', 'HAVE_STDINT_H', 'c'),
1093             ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c'),
1094         ],
1095         functions = [
1096             ('getcwd', 'HAVE_GETCWD', None),
1097             ('stpcpy', 'HAVE_STPCPY', None),
1098             ('strcasecmp', 'HAVE_STRCASECMP', None),
1099             ('strdup', 'HAVE_STRDUP', None),
1100             ('strtoul', 'HAVE_STRTOUL', None),
1101             ('alloca', 'HAVE_ALLOCA', None),
1102             ('__fsetlocking', 'HAVE___FSETLOCKING', None),
1103             ('mempcpy', 'HAVE_MEMPCPY', None),
1104             ('__argz_count', 'HAVE___ARGZ_COUNT', None),
1105             ('__argz_next', 'HAVE___ARGZ_NEXT', None),
1106             ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
1107             ('setlocale', 'HAVE_SETLOCALE', None),
1108             ('tsearch', 'HAVE_TSEARCH', None),
1109             ('getegid', 'HAVE_GETEGID', None),
1110             ('getgid', 'HAVE_GETGID', None),
1111             ('getuid', 'HAVE_GETUID', None),
1112             ('wcslen', 'HAVE_WCSLEN', None),
1113             ('asprintf', 'HAVE_ASPRINTF', None),
1114             ('wprintf', 'HAVE_WPRINTF', None),
1115             ('snprintf', 'HAVE_SNPRINTF', None),
1116             ('printf', 'HAVE_POSIX_PRINTF', None),
1117             ('fcntl', 'HAVE_FCNTL', None),
1118         ],
1119         types = [
1120             ('intmax_t', 'HAVE_INTMAX_T', None),
1121             ('long double', 'HAVE_LONG_DOUBLE', None),
1122             ('long long', 'HAVE_LONG_LONG', None),
1123             ('wchar_t', 'HAVE_WCHAR_T', None),
1124             ('wint_t', 'HAVE_WINT_T', None),
1125             ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
1126             ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
1127         ],
1128         libs = [
1129             ('c', 'HAVE_LIBC'),
1130         ],
1131         custom_tests = [
1132             (conf.CheckLC_MESSAGES(),
1133                 'HAVE_LC_MESSAGES',
1134                 'Define if your <locale.h> file defines LC_MESSAGES.'
1135             ),
1136             (conf.CheckIconvConst(),
1137                 'ICONV_CONST',
1138                 'Define as const if the declaration of iconv() needs const.',
1139                 '#define ICONV_CONST const',
1140                 '#define ICONV_CONST',
1141             ),
1142             (conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
1143             conf.CheckType('intmax_t', includes='#include <inttypes.h>'),
1144                 'HAVE_INTMAX_T',
1145                 "Define to 1 if you have the `intmax_t' type."
1146             ),
1147             (env.has_key('nls') and env['nls'],
1148                 'ENABLE_NLS',
1149                 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1150             ),
1151         ],
1152         extra_items = [
1153             ('#define HAVE_ICONV 1', 'Define if iconv or libiconv is found'),
1154             ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1155                 'Define to be the size of type wchar_t'),
1156         ],
1157         config_post = '#endif'
1158     )
1159
1160     # these keys are needed in env
1161     for key in ['HAVE_ASPRINTF', 'HAVE_WPRINTF', 'HAVE_SNPRINTF', \
1162         'HAVE_POSIX_PRINTF', 'HAVE_LIBC']:
1163         # USE_ASPELL etc does not go through result
1164         if result.has_key(key):
1165             env[key] = result[key]
1166
1167
1168 # this looks misplaced, but intl/libintl.h is needed by src/message.C
1169 if env['nls'] and included_gettext:
1170     # libgnuintl.h.in => libintl.h
1171     env.Depends('$TOP_SRCDIR/intl/libintl.h', '$BUILDDIR/intl/config.h')
1172     env.substFile('$BUILDDIR/intl/libintl.h', '$TOP_SRCDIR/intl/libgnuintl.h.in')
1173     env.Command('$BUILDDIR/intl/libgnuintl.h', '$BUILDDIR/intl/libintl.h',
1174         [Copy('$TARGET', '$SOURCE')])
1175
1176 #
1177 # Finish auto-configuration
1178 env = conf.Finish()
1179
1180 #----------------------------------------------------------
1181 # Now set up our build process accordingly
1182 #----------------------------------------------------------
1183
1184 if env['ICONV_LIB'] is None:
1185     system_libs = []
1186 else:
1187     system_libs = [env['ICONV_LIB']]
1188 if platform_name in ['win32', 'cygwin']:
1189     # the final link step needs stdc++ to succeed under mingw
1190     # FIXME: shouldn't g++ automatically link to stdc++?
1191     if use_vc:
1192         system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll']
1193     else:
1194         system_libs += ['shlwapi', 'stdc++', 'z']
1195 elif platform_name == 'cygwin' and env['X11']:
1196     system_libs += ['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr',
1197         'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 
1198         'resolv', 'pthread', 'z']
1199 else:
1200     system_libs += ['z']
1201
1202 libs = [
1203     ('HAVE_LIBGDI32', 'gdi32'),
1204     ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
1205     ('USE_ASPELL', aspell_lib),
1206     ('USE_ISPELL', 'ispell'),
1207     ('USE_PSPELL', 'pspell'),
1208 ]
1209
1210 for lib in libs:
1211     if env[lib[0]]:
1212         system_libs.append(lib[1])
1213
1214 #
1215 # Build parameters CPPPATH etc
1216 #
1217 if env['X11']:
1218     env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1219
1220 #
1221 # boost: for boost header files
1222 # BUILDDIR/common: for config.h
1223 # TOP_SRCDIR/src: for support/* etc
1224 #
1225 env['CPPPATH'] += ['$BUILDDIR/common', '$TOP_SRCDIR/src']
1226 #
1227 # Separating boost directories from CPPPATH stops scons from building
1228 # the dependency tree for boost header files, and effectively reduce
1229 # the null build time of lyx from 29s to 16s. Since lyx may tweak local
1230 # boost headers, this is only done for system boost headers.
1231 if included_boost:
1232     env.AppendUnique(CPPPATH = ['$BOOST_INC_PATH'])
1233 else:
1234     if use_vc:
1235         env.PrependUnique(CCFLAGS = ['/I$BOOST_INC_PATH'])
1236     else:
1237         env.PrependUnique(CCFLAGS = ['-I$BOOST_INC_PATH'])
1238
1239 # for intl/config.h, intl/libintl.h and intl/libgnuintl.h
1240 if env['nls'] and included_gettext:
1241     env['CPPPATH'].append('$BUILDDIR/intl')
1242 #
1243
1244 #
1245 # A Link script for cygwin see
1246 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1247 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1248 # for details
1249 #
1250 if platform_name == 'cygwin':
1251     ld_script_path = '/tmp'
1252     ld_script = utils.installCygwinLDScript(ld_script_path)
1253     env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1254         '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1255
1256
1257 #---------------------------------------------------------
1258 # Frontend related variables (QTDIR etc)
1259 #---------------------------------------------------------
1260
1261 #
1262 # create a separate environment so that other files do not have
1263 # to be built with all the include directories etc
1264 #
1265 if frontend == 'qt4':
1266     frontend_env = env.Copy()
1267
1268     # handle qt related user specified paths
1269     # set environment so that moc etc can be found even if its path is not set properly
1270     if frontend_env.has_key('qt_dir') and frontend_env['qt_dir']:
1271         frontend_env['QTDIR'] = frontend_env['qt_dir']
1272         if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'bin')):
1273             os.environ['PATH'] += os.pathsep + os.path.join(frontend_env['qt_dir'], 'bin')
1274             frontend_env.PrependENVPath('PATH', os.path.join(frontend_env['qt_dir'], 'bin'))
1275         if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'lib')):
1276             frontend_env.PrependENVPath('PKG_CONFIG_PATH', os.path.join(frontend_env['qt_dir'], 'lib'))
1277
1278     # if separate qt_lib_path is given
1279     if frontend_env.has_key('qt_lib_path') and frontend_env['qt_lib_path']:
1280         qt_lib_path = frontend_env.subst('$qt_lib_path')
1281         frontend_env.AppendUnique(LIBPATH = [qt_lib_path])
1282         frontend_env.PrependENVPath('PKG_CONFIG_PATH', qt_lib_path)
1283     else:
1284         qt_lib_path = None
1285
1286     # if separate qt_inc_path is given
1287     if frontend_env.has_key('qt_inc_path') and frontend_env['qt_inc_path']:
1288         qt_inc_path = frontend_env['qt_inc_path']
1289     else:
1290         qt_inc_path = None
1291
1292     # local qt4 toolset from
1293     # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
1294     #
1295     # NOTE: I have to patch qt4.py since it does not automatically
1296     # process .C file!!! (add to cxx_suffixes )
1297     #
1298     frontend_env.Tool('qt4', [scons_dir])
1299     frontend_env['QT_AUTOSCAN'] = 0
1300     frontend_env['QT4_AUTOSCAN'] = 0
1301     frontend_env['QT4_UICDECLFLAGS'] = '-tr lyx::qt_'
1302
1303     if qt_lib_path is None:
1304         qt_lib_path = os.path.join(frontend_env.subst('$QTDIR'), 'lib')
1305     if qt_inc_path is None:
1306         qt_inc_path = os.path.join(frontend_env.subst('$QTDIR'), 'include')
1307
1308
1309     conf = Configure(frontend_env,
1310         custom_tests = { 
1311             'CheckPackage' : utils.checkPackage,
1312             'CheckCommand' : utils.checkCommand,
1313         }
1314     )
1315
1316     succ = False
1317     # first: try pkg_config
1318     if frontend_env['HAS_PKG_CONFIG']:
1319         succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
1320         # FIXME: use pkg_config information?
1321         #frontend_env['QT4_PKG_CONFIG'] = succ
1322     # second: try to link to it
1323     if not succ:
1324         # Under linux, I can test the following perfectly
1325         # Under windows, lib names need to passed as libXXX4.a ...
1326         if platform_name == 'win32':
1327             succ = conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1328         else:
1329             succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1330     # still can not find it
1331     if not succ:
1332         print 'Did not find qt libraries, exiting!'
1333         Exit(1)
1334     #
1335     # Now, determine the correct suffix:
1336     qt_libs = ['QtCore', 'QtGui']
1337     if platform_name == 'win32':
1338         if mode == 'debug' and use_vc and \
1339             conf.CheckLibWithHeader('QtCored4', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1340             qt_lib_suffix = 'd4'
1341             use_qt_debug_libs = True
1342         else:
1343             qt_lib_suffix = '4'
1344             use_qt_debug_libs = False
1345     else:
1346         if mode == 'debug' and conf.CheckLibWithHeader('QtCore_debug', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1347             qt_lib_suffix = '_debug'
1348             use_qt_debug_libs = True
1349         else:
1350             qt_lib_suffix = ''
1351             use_qt_debug_libs = False
1352     frontend_env.EnableQt4Modules(qt_libs, debug = (mode == 'debug' and use_qt_debug_libs))
1353     frontend_libs = [x + qt_lib_suffix for x in qt_libs]
1354     qtcore_lib = ['QtCore' + qt_lib_suffix]
1355
1356     # check uic and moc commands for qt frontends
1357     if conf.CheckCommand('uic') == None or conf.CheckCommand('moc') == None:
1358         print 'uic or moc command is not found for frontend', frontend
1359         Exit(1)
1360     
1361     # now, if msvc2005 is used, we will need that QT_LIB_PATH/QT_LIB.manifest file
1362     if use_vc:
1363         if mode == 'debug':
1364             if qt_lib_path is not None:
1365                 manifest = os.path.join(qt_lib_path, 'QtGuid4.dll.manifest')
1366             else:
1367                 manifest = 'QtGuid4.dll.manifest'
1368         else:
1369             if qt_lib_path is not None:
1370                 manifest = os.path.join(qt_lib_path, 'QtGui4.dll.manifest')
1371             else:
1372                 manifest = 'QtGui4.dll.manifest'
1373         if os.path.isfile(manifest):
1374             frontend_env['LINKCOM'] = [frontend_env['LINKCOM'], 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % manifest]
1375
1376     frontend_env = conf.Finish()
1377
1378 #
1379 # Report results
1380 #
1381 # fill in the version info
1382 env['VERSION_INFO'] = '''Configuration
1383   Host type:                      %s
1384   Special build flags:            %s
1385   C   Compiler:                   %s
1386   C   Compiler flags:             %s %s
1387   C++ Compiler:                   %s
1388   C++ Compiler LyX flags:         %s
1389   C++ Compiler flags:             %s %s
1390   Linker flags:                   %s
1391   Linker user flags:              %s
1392 Build info:
1393   Builing directory:              %s
1394   Local library directory:        %s
1395   Libraries paths:                %s
1396   Boost libraries:                %s
1397   Frontend libraries:             %s
1398   System libraries:               %s
1399   include search path:            %s
1400 Frontend:
1401   Frontend:                       %s
1402   Packaging:                      %s
1403   LyX dir:                        %s
1404   LyX files dir:                  %s
1405 ''' % (platform_name,
1406     env.subst('$CCFLAGS'), env.subst('$CC'),
1407     env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1408     env.subst('$CXX'), env.subst('$CXXFLAGS'),
1409     env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1410     env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1411     env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1412     str(env['LIBPATH']), str(boost_libraries),
1413     str(frontend_libs), str(system_libs), str(env['CPPPATH']),
1414     frontend, packaging_method,
1415     prefix, env['LYX_DIR'])
1416
1417 if frontend in ['qt4']:
1418     env['VERSION_INFO'] += '''  include dir:                    %s
1419   library dir:                    %s
1420   X11:                            %s
1421 ''' % (qt_inc_path, qt_lib_path, env['X11'])
1422
1423 print env['VERSION_INFO']
1424
1425 #
1426 # Mingw command line may be too short for our link usage,
1427 # Here we use a trick from scons wiki
1428 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1429 #
1430 # I also would like to add logging (commands only) capacity to the
1431 # spawn system.
1432 logfile = env.get('logfile', default_log_file)
1433 if logfile != '' or platform_name == 'win32':
1434     import time
1435     utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1436         info = '''# This is a log of commands used by scons to build lyx
1437 # Time: %s
1438 # Command: %s
1439 # Info: %s
1440 ''' % (time.asctime(), ' '.join(sys.argv),
1441     env['VERSION_INFO'].replace('\n','\n# ')) )
1442
1443
1444 # Cleanup stuff
1445 #
1446 # -h will print out help info
1447 Help(opts.GenerateHelpText(env))
1448
1449
1450
1451 #----------------------------------------------------------
1452 # Start building
1453 #----------------------------------------------------------
1454 # this has been the source of problems on some platforms...
1455 # I find that I need to supply it with full path name
1456 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1457 # this usage needs further investigation.
1458 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1459
1460 print "Building all targets recursively"
1461
1462 if env.has_key('rebuild'):
1463     rebuild_targets = env['rebuild'].split(',')
1464     if 'none' in rebuild_targets or 'no' in rebuild_targets:
1465         rebuild_targets = []
1466     elif 'all' in rebuild_targets or 'yes' in rebuild_targets:
1467         # None: let scons decide which components to build
1468         # Forcing all components to be rebuilt is in theory not necessary
1469         rebuild_targets = None    
1470 else:
1471     rebuild_targets = None
1472
1473 def libExists(libname):
1474     ''' Check whether or not lib $LOCALLIBNAME/libname already exists'''
1475     return os.path.isfile(File(env.subst('$LOCALLIBPATH/${LIBPREFIX}%s$LIBSUFFIX'%libname)).abspath)
1476
1477 def appExists(apppath, appname):
1478     ''' Check whether or not application already exists'''
1479     return os.path.isfile(File(env.subst('$BUILDDIR/common/%s/${PROGPREFIX}%s$PROGSUFFIX' % (apppath, appname))).abspath)
1480
1481 targets = BUILD_TARGETS
1482 # msvc need to pass full target name, so I have to look for path/lyx etc
1483 build_lyx = targets == [] or True in ['lyx' in x for x in targets] \
1484     or 'install' in targets or 'all' in targets
1485 build_boost = (included_boost and not libExists('boost_regex')) or 'boost' in targets
1486 build_intl = (included_gettext and not libExists('included_intl')) or 'intl' in targets
1487 build_support = build_lyx or True in [x in targets for x in ['support', 'client', 'tex2lyx']]
1488 build_mathed = build_lyx or 'mathed' in targets
1489 build_insets = build_lyx or 'insets' in targets
1490 build_frontends = build_lyx or 'frontends' in targets
1491 build_graphics = build_lyx or 'graphics' in targets
1492 build_controllers = build_lyx or 'controllers' in targets
1493 build_client = True in ['client' in x for x in targets] \
1494     or 'install' in targets or 'all' in targets
1495 build_tex2lyx = True in ['tex2lyx' in x for x in targets] \
1496     or 'install' in targets or 'all' in targets
1497 build_lyxbase = build_lyx or 'lyxbase' in targets
1498 build_po = 'po' in targets or 'install' in targets or 'all' in targets
1499 build_qt4 = (build_lyx and frontend == 'qt4') or 'qt4' in targets
1500 build_msvs_projects = use_vc and 'msvs_projects' in targets
1501
1502
1503 # now, if rebuild_targets is specified, do not rebuild some targets
1504 if rebuild_targets is not None:
1505     #
1506     def ifBuildLib(name, libname, old_value):
1507         # explicitly asked to rebuild
1508         if name in rebuild_targets:
1509             return True
1510         # else if not rebuild, and if the library already exists
1511         elif libExists(libname):
1512             return False
1513         # do not change the original value
1514         else:
1515             return old_value
1516     build_boost = ifBuildLib('boost', 'included_boost_filesystem', build_boost)
1517     build_intl = ifBuildLib('intl', 'included_intl', build_intl)
1518     build_support = ifBuildLib('support', 'support', build_support)
1519     build_mathed = ifBuildLib('mathed', 'mathed', build_mathed)
1520     build_insets = ifBuildLib('insets', 'insets', build_insets)
1521     build_frontends = ifBuildLib('frontends', 'frontends', build_frontends)
1522     build_graphics = ifBuildLib('graphics', 'graphics', build_graphics)
1523     build_controllers = ifBuildLib('controllers', 'controllers', build_controllers)
1524     build_lyxbase = ifBuildLib('lyxbase', 'lyxbase_pre', build_lyxbase)
1525     build_qt4 = ifBuildLib('qt4', 'qt4', build_qt4)
1526     #
1527     def ifBuildApp(name, appname, old_value):
1528         # explicitly asked to rebuild
1529         if name in rebuild_targets:
1530             return True
1531         # else if not rebuild, and if the library already exists
1532         elif appExists(name, appname):
1533             return False
1534         # do not change the original value
1535         else:
1536             return old_value
1537     build_tex2lyx = ifBuildApp('tex2lyx', 'tex2lyx', build_tex2lyx)
1538     build_client = ifBuildApp('client', 'lyxclient', build_client)
1539
1540 # sync frontend and frontend (?)
1541 if build_qt4:
1542     frontend = 'qt4'
1543
1544
1545 if build_boost:
1546     #
1547     # boost libraries
1548     #
1549     # special builddir
1550     env.BuildDir('$BUILDDIR/boost', '$TOP_SRCDIR/boost/libs', duplicate = 0)
1551
1552     boostenv = env.Copy()
1553     #
1554     # boost use its own config.h
1555     boostenv['CPPPATH'] = ['$TOP_SRCDIR/boost', '$BUILDDIR/boost'] + extra_inc_paths
1556     boostenv.AppendUnique(CCFLAGS = ['-DBOOST_USER_CONFIG="<config.h>"'])
1557
1558     for lib in boost_libs:
1559         print 'Processing files in boost/libs/%s/src...' % lib
1560         boostlib = boostenv.StaticLibrary(
1561             target = '$LOCALLIBPATH/included_boost_%s' % lib,
1562             source = ['$BUILDDIR/boost/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1563         )
1564         Alias('boost', boostlib)
1565
1566
1567 if build_intl:
1568     #
1569     # intl
1570     #
1571     intlenv = env.Copy()
1572
1573     print "Processing files in intl..."
1574
1575     env.BuildDir('$BUILDDIR/intl', '$TOP_SRCDIR/intl', duplicate = 0)
1576
1577     # we need the original C compiler for these files
1578     intlenv['CC'] = C_COMPILER
1579     intlenv['CCFLAGS'] = C_CCFLAGS
1580     if use_vc:
1581         intlenv.Append(CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
1582     # intl does not use global config.h
1583     intlenv['CPPPATH'] = ['$BUILDDIR/intl'] + extra_inc_paths
1584
1585     intlenv.Append(CCFLAGS = [
1586         r'-DLOCALEDIR=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1587         r'-DLOCALE_ALIAS_PATH=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1588         r'-DLIBDIR=\"' + env['TOP_SRCDIR'].replace('\\', '\\\\') + r'/lib\"',
1589         '-DIN_LIBINTL',
1590         '-DENABLE_RELOCATABLE=1',
1591         '-DIN_LIBRARY',
1592         r'-DINSTALLDIR=\"' + prefix.replace('\\', '\\\\') + r'/lib\"',
1593         '-DNO_XMALLOC',
1594         '-Dset_relocation_prefix=libintl_set_relocation_prefix',
1595         '-Drelocate=libintl_relocate',
1596         '-DDEPENDS_ON_LIBICONV=1',
1597         '-DHAVE_CONFIG_H'
1598         ]
1599     )
1600
1601     intl = intlenv.StaticLibrary(
1602         target = '$LOCALLIBPATH/included_intl',
1603         LIBS = ['c'],
1604         source = ['$BUILDDIR/intl/%s' % x for x in intl_files]
1605     )
1606     Alias('intl', intl)
1607
1608
1609 #
1610 # Now, src code under src/
1611 #
1612 env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1613
1614
1615 if build_support:
1616     #
1617     # src/support
1618     #
1619     print "Processing files in src/support..."
1620
1621     frontend_env.Depends('$BUILDDIR/common/support/package.C', '$BUILDDIR/common/config.h')
1622     env.substFile('$BUILDDIR/common/support/package.C', '$TOP_SRCDIR/src/support/package.C.in')
1623
1624     support = frontend_env.StaticLibrary(
1625         target = '$LOCALLIBPATH/support',
1626         source = ['$BUILDDIR/common/support/%s' % x for x in src_support_files],
1627     )
1628     Alias('support', support)
1629
1630
1631 if build_mathed:
1632     #
1633     # src/mathed
1634     #
1635     print "Processing files in src/mathed..."
1636     #
1637     mathed = env.StaticLibrary(
1638         target = '$LOCALLIBPATH/mathed',
1639         source = ['$BUILDDIR/common/mathed/%s' % x for x in src_mathed_files]
1640     )
1641     Alias('mathed', mathed)
1642
1643
1644 if build_insets:
1645     #
1646     # src/insets
1647     #
1648     print "Processing files in src/insets..."
1649     #
1650     insets = env.StaticLibrary(
1651         target = '$LOCALLIBPATH/insets',
1652         source = ['$BUILDDIR/common/insets/%s' % x for x in src_insets_files]
1653     )
1654     Alias('insets', insets)
1655
1656
1657 if build_frontends:
1658     #
1659     # src/frontends
1660     #
1661     print "Processing files in src/frontends..."
1662
1663     frontends = env.StaticLibrary(
1664         target = '$LOCALLIBPATH/frontends',
1665         source = ['$BUILDDIR/common/frontends/%s' % x for x in src_frontends_files]
1666     )
1667     Alias('frontends', frontends)
1668
1669
1670 if build_graphics:
1671     #
1672     # src/graphics
1673     #
1674     print "Processing files in src/graphics..."
1675
1676     graphics = env.StaticLibrary(
1677         target = '$LOCALLIBPATH/graphics',
1678         source = ['$BUILDDIR/common/graphics/%s' % x for x in src_graphics_files]
1679     )
1680     Alias('graphics', graphics)
1681
1682
1683 if build_controllers:
1684     #
1685     # src/frontends/controllers
1686     #
1687     print "Processing files in src/frontends/controllers..."
1688
1689     controllers = env.StaticLibrary(
1690         target = '$LOCALLIBPATH/controllers',
1691         source = ['$BUILDDIR/common/frontends/controllers/%s' % x for x in src_frontends_controllers_files]
1692     )
1693     Alias('controllers', controllers)
1694
1695
1696 #
1697 # src/frontend/qt4
1698 #
1699 if build_qt4:
1700     env.BuildDir('$BUILDDIR/$frontend', '$TOP_SRCDIR/src/frontend/$frontend', duplicate = 0)
1701
1702     print "Processing files in src/frontends/qt4..."
1703
1704     qt4_moc_files = ["$BUILDDIR/common/frontends/qt4/%s" % x for x in src_frontends_qt4_moc_files]
1705
1706     #
1707     # Compile resources
1708     #
1709     resources = [frontend_env.Uic4(x.split('.')[0]) for x in \
1710         ["$BUILDDIR/common/frontends/qt4/ui/%s" % x for x in src_frontends_qt4_ui_files]]
1711
1712     #
1713     # moc qt4_moc_files, the moced files are included in the original files
1714     #
1715     qt4_moced_files = [frontend_env.Moc4(x.replace('.C', '_moc.cpp'), x.replace('.C', '.h')) for x in qt4_moc_files]
1716
1717     qt4 = frontend_env.StaticLibrary(
1718         target = '$LOCALLIBPATH/qt4',
1719         source = ['$BUILDDIR/common/frontends/qt4/%s' % x for x in src_frontends_qt4_files],
1720         CPPPATH = [
1721             '$CPPPATH',
1722             '$BUILDDIR/common',
1723             '$BUILDDIR/common/images',
1724             '$BUILDDIR/common/frontends',
1725             '$BUILDDIR/common/frontends/qt4',
1726             '$BUILDDIR/common/frontends/controllers'
1727         ],
1728         CCFLAGS =  [
1729             '$CCFLAGS',
1730             '-DHAVE_CONFIG_H',
1731             '-DQT_CLEAN_NAMESPACE',
1732             '-DQT_GENUINE_STR',
1733             '-DQT_NO_STL',
1734             '-DQT_NO_KEYWORDS',
1735         ]
1736     )
1737     Alias('qt4', qt4)
1738
1739
1740 if build_client:
1741     #
1742     # src/client
1743     #
1744     frontend_env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1745
1746     print "Processing files in src/client..."
1747
1748     if env['HAVE_FCNTL']:
1749         client = frontend_env.Program(
1750             target = '$BUILDDIR/common/client/lyxclient',
1751             LIBS = ['support'] + intl_libs + system_libs +
1752                 socket_libs + boost_libraries + qtcore_lib,
1753             source = ['$BUILDDIR/common/client/%s' % x for x in src_client_files] + \
1754                 utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/client.rc')
1755         )
1756         Alias('client', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(client[0]))[1]),
1757             client, [Copy('$TARGET', '$SOURCE')]))
1758     else:
1759         client = None
1760     Alias('client', client)
1761 else:
1762     if env['HAVE_FCNTL']:
1763         # define client even if lyxclient is not built with rebuild=no
1764         client = [env.subst('$BUILDDIR/common/client/${PROGPREFIX}lyxclient$PROGSUFFIX')]
1765     else:
1766         client = None
1767
1768
1769 if build_tex2lyx:
1770     #
1771     # tex2lyx
1772     #
1773     print "Processing files in src/tex2lyx..."
1774
1775     #
1776     for file in ['FloatList.C', 'Floating.C', 'counters.C', 'lyxlayout.h', 'lyxlayout.C', 
1777         'lyxtextclass.h', 'lyxtextclass.C', 'lyxlex.C', 'lyxlex_pimpl.C']:
1778         frontend_env.Command('$BUILDDIR/common/tex2lyx/'+file, '$TOP_SRCDIR/src/'+file,
1779             [Copy('$TARGET', '$SOURCE')])
1780
1781     tex2lyx = frontend_env.Program(
1782         target = '$BUILDDIR/common/tex2lyx/tex2lyx',
1783         LIBS = ['support'] + boost_libraries + intl_libs + system_libs + qtcore_lib,
1784         source = ['$BUILDDIR/common/tex2lyx/%s' % x for x in src_tex2lyx_files] + \
1785             utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/tex2lyx.rc'),
1786         CPPPATH = ['$BUILDDIR/common/tex2lyx', '$CPPPATH'],
1787         LIBPATH = ['#$LOCALLIBPATH', '$LIBPATH'],
1788     )
1789     Alias('tex2lyx', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(tex2lyx[0]))[1]),
1790         tex2lyx, [Copy('$TARGET', '$SOURCE')]))
1791     Alias('tex2lyx', tex2lyx)
1792 else:
1793     # define tex2lyx even if tex2lyx is not built with rebuild=no
1794     tex2lyx = [frontend_env.subst('$BUILDDIR/common/tex2lyx/${PROGPREFIX}tex2lyx$PROGSUFFIX')]
1795
1796
1797 if build_lyxbase:
1798     #
1799     # src/
1800     #
1801     print "Processing files in src..."
1802
1803     env.Depends('$BUILDDIR/common/version.C', '$BUILDDIR/common/config.h')
1804     env.substFile('$BUILDDIR/common/version.C', '$TOP_SRCDIR/src/version.C.in')
1805
1806     if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
1807         src_post_files.append('aspell.C')
1808     elif env.has_key('USE_PSPELL') and env['USE_PSPELL']:
1809         src_post_files.append('pspell.C')
1810     elif env.has_key('USE_ISPELL') and env['USE_ISPELL']:
1811         src_post_files.append('ispell.C')
1812
1813     # msvc requires at least one source file with main()
1814     # so I exclude main.C from lyxbase
1815     lyxbase_pre = env.StaticLibrary(
1816         target = '$LOCALLIBPATH/lyxbase_pre',
1817         source = ['$BUILDDIR/common/%s' % x for x in src_pre_files]
1818     )
1819     lyxbase_post = env.StaticLibrary(
1820         target = '$LOCALLIBPATH/lyxbase_post',
1821         source = ["$BUILDDIR/common/%s" % x for x in src_post_files]
1822     )
1823     Alias('lyxbase', lyxbase_pre)
1824     Alias('lyxbase', lyxbase_post)
1825
1826
1827 if build_lyx:
1828     #
1829     # Build lyx with given frontend
1830     #
1831     lyx = frontend_env.Program(
1832         target = '$BUILDDIR/lyx',
1833         source = ['$BUILDDIR/common/main.C'] + \
1834             utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/lyx.rc'),
1835         LIBS = [
1836             'lyxbase_pre',
1837             'mathed',
1838             'insets',
1839             'frontends',
1840             frontend,
1841             'controllers',
1842             'graphics',
1843             'support',
1844             'lyxbase_post',
1845             ] +
1846             boost_libraries +
1847             frontend_libs +
1848             intl_libs +
1849             socket_libs +
1850             system_libs
1851     )
1852     Alias('lyx', lyx)
1853 else:
1854     # define lyx even if lyx is not built with rebuild=no
1855     lyx = [frontend_env.subst('$BUILDDIR/${PROGPREFIX}lyx$PROGSUFFIX')]
1856
1857
1858 if build_msvs_projects:
1859     def build_project(target, full_target = None,
1860         src = [], inc = [], res = [], rebuildTargetOnly = True):
1861         ''' build mavs project files
1862             target:      alias (correspond to directory name)
1863             full_target: full path/filename of the target
1864             src:         source files
1865             inc:         include files
1866             res:         resource files
1867             rebuildTargetOnly:     whether or not only rebuild this target
1868
1869         For non-debug-able targets like static libraries, target (alias) is
1870         enough to build the target. For executable targets, msvs need to know
1871         the full path to start debug them.
1872         '''
1873         if rebuildTargetOnly:
1874             cmds = 'rebuild='+target
1875         else:
1876             cmds = ''
1877         if full_target is None:
1878             build_target = target
1879         else:
1880             build_target = full_target
1881         # project
1882         proj = env.MSVSProject(
1883             target = target + env['MSVSPROJECTSUFFIX'],
1884             # this allows easy access to header files (along with source)
1885             srcs = [env.subst(x) for x in src + inc],
1886             incs = [env.subst('$TOP_SRCDIR/src/config.h')],
1887             localincs = [env.subst(x) for x in inc],
1888             resources = [env.subst(x) for x in res],
1889             buildtarget = build_target,
1890             cmdargs = cmds,
1891             variant = 'Debug'
1892         )
1893         Alias('msvs_projects', proj)
1894     #
1895     boost_src = []
1896     for lib in boost_libs:
1897         boost_src += ['$TOP_SRCDIR/boost/libs/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1898     build_project('boost', src = boost_src)
1899     #
1900     build_project('intl', src = ['$TOP_SRCDIR/intl/%s' % x for x in intl_files], 
1901         inc = ['$TOP_SRCDIR/intl/%s' % x for x in intl_header_files])
1902     #
1903     build_project('support', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1904         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1905     #
1906     build_project('mathed', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1907         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1908     #
1909     build_project('insets', src = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files], 
1910         inc = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files])
1911     #
1912     build_project('frontends', src = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files], 
1913         inc = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files])
1914     #
1915     build_project('graphics', src = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files], 
1916         inc = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files])
1917     #
1918     build_project('controllers', src = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files], 
1919         inc = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files])
1920     #
1921     build_project('qt4', src = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1922         inc = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1923         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files])
1924     #
1925     build_project('client', src = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_files],
1926         inc = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files],
1927         rebuildTargetOnly = False,
1928         full_target = File(env.subst('$BUILDDIR/common/client/lyxclient$PROGSUFFIX')).abspath)
1929     #
1930     build_project('tex2lyx', src = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files],
1931         inc = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files],
1932         rebuildTargetOnly = False,
1933         full_target = File(env.subst('$BUILDDIR/common/tex2lyx/tex2lyx$PROGSUFFIX')).abspath)
1934     #
1935     build_project('lyxbase', src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files],
1936         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files])
1937     build_project('lyx', 
1938         src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files] + \
1939             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files] + \
1940             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_files] + \
1941             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files] + \
1942             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files] + \
1943             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files] + \
1944             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files] + \
1945             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1946         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files] + \
1947             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files] + \
1948             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files] + \
1949             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files] + \
1950             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files] + \
1951             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files] + \
1952             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files] + \
1953             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1954         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1955         rebuildTargetOnly = False,
1956         full_target = File(env.subst('$BUILDDIR/lyx$PROGSUFFIX')).abspath)
1957
1958
1959 if build_po:
1960     #
1961     # po/
1962     #
1963     print 'Processing files in po...'
1964
1965     import glob
1966     # handle po files
1967     #
1968     # files to translate
1969     transfiles = glob.glob(os.path.join(env.subst('$TOP_SRCDIR'), 'po', '*.po'))
1970     # possibly *only* handle these languages
1971     languages = None
1972     if env.has_key('languages'):
1973         languages = env.make_list(env['lanauges'])
1974     # use defulat msgfmt
1975     gmo_files = []
1976     if not env['MSGFMT']:
1977         print 'msgfmt does not exist. Can not process po files'
1978     else:
1979         # create a builder
1980         env['BUILDERS']['Transfiles'] = Builder(action='$MSGFMT $SOURCE -o $TARGET',suffix='.gmo',src_suffix='.po')
1981         #
1982         for f in transfiles:
1983             # get filename
1984             fname = os.path.split(f)[1]
1985             # country code
1986             country = fname.split('.')[0]
1987             #
1988             if not languages or country in languages:
1989                 gmo_files.extend(env.Transfiles(f))
1990
1991
1992 if 'install' in targets:
1993     #
1994     # this part is a bit messy right now. Since scons will provide
1995     # --DESTDIR option soon, at least the dest_dir handling can be 
1996     # removed later.
1997     #
1998     # how to join dest_dir and prefix
1999     def joinPaths(path1, path2):
2000         ''' join path1 and path2, do not use os.path.join because
2001             under window, c:\destdir\d:\program is invalid '''
2002         if path1 == '':
2003             return os.path.normpath(path2)
2004         # separate drive letter
2005         (drive, path) = os.path.splitdrive(os.path.normpath(path2))
2006         # ignore drive letter, so c:\destdir + c:\program = c:\destdir\program
2007         return os.path.join(os.path.normpath(path1), path[1:])
2008     #
2009     # install to dest_dir/prefix
2010     dest_dir = env.get('DESTDIR', '')
2011     dest_prefix_dir = joinPaths(dest_dir, env.Dir(prefix).abspath)
2012     # create the directory if needed
2013     if not os.path.isdir(dest_prefix_dir):
2014         try:
2015             os.makedirs(dest_prefix_dir)
2016         except:
2017             pass
2018         if not os.path.isdir(dest_prefix_dir):
2019             print 'Can not create directory', dest_prefix_dir
2020             Exit(3)
2021     #
2022     if env.has_key('exec_prefix'):
2023         bin_dest_dir = joinPaths(dest_dir, Dir(env['exec_prefix']).abspath)
2024     else:
2025         bin_dest_dir = os.path.join(dest_prefix_dir, 'bin')
2026     if add_suffix:
2027         share_dest_dir = os.path.join(dest_prefix_dir, share_dir + program_suffix)
2028     else:
2029         share_dest_dir = os.path.join(dest_prefix_dir, share_dir)
2030     man_dest_dir = os.path.join(dest_prefix_dir, man_dir)
2031     locale_dest_dir = os.path.join(dest_prefix_dir, locale_dir)
2032     #
2033     import glob
2034     #
2035     # install executables (lyxclient may be None)
2036     #
2037     if add_suffix:
2038         version_suffix = program_suffix
2039     else:
2040         version_suffix = ''
2041     #
2042     # install lyx, if in release mode, try to strip the binary
2043     if env.has_key('STRIP') and env['STRIP'] is not None and mode != 'debug':
2044         # create a builder to strip and install
2045         env['BUILDERS']['StripInstallAs'] = Builder(action='$STRIP $SOURCE -o $TARGET')
2046
2047     # install executables
2048     for (name, obj) in (('lyx', lyx), ('tex2lyx', tex2lyx), ('client', client)):
2049         if obj is None:
2050             continue
2051         target_name = os.path.split(str(obj[0]))[1].replace(name, '%s%s' % (name, version_suffix))
2052         target = os.path.join(bin_dest_dir, target_name)
2053         if env['BUILDERS'].has_key('StripInstallAs'):
2054             env.StripInstallAs(target, obj)
2055         else:
2056             env.InstallAs(target, obj)
2057         Alias('install', target)
2058
2059     # share/lyx
2060     dirs = []
2061     for (dir,files) in [
2062             ('.', lib_files),  
2063             ('clipart', lib_clipart_files),
2064             ('examples', lib_examples_files),
2065             ('images', lib_images_files),
2066             ('images/math', lib_images_math_files),
2067             ('bind', lib_bind_files),
2068             ('kbd', lib_kbd_files),
2069             ('layouts', lib_layouts_files),
2070             ('scripts', lib_scripts_files),
2071             ('templates', lib_templates_files),
2072             ('tex', lib_tex_files),
2073             ('ui', lib_ui_files),
2074             ('doc', lib_doc_files),
2075             ('lyx2lyx', lib_lyx2lyx_files)]:
2076         dirs.append(env.Install(os.path.join(share_dest_dir, dir),
2077             [env.subst('$TOP_SRCDIR/lib/%s/%s' % (dir, file)) for file in files]))
2078     Alias('install', dirs)
2079     
2080     if platform_name == 'cygwin':
2081         # cygwin packaging requires a file /usr/share/doc/Cygwin/foot-vendor-suffix.README
2082         Cygwin_README = os.path.join(dest_prefix_dir, 'share', 'doc', 'Cygwin', 
2083             '%s-%s.README' % (package, package_cygwin_version))
2084         env.InstallAs(Cygwin_README,
2085             os.path.join(env.subst('$TOP_SRCDIR'), 'README.cygwin'))
2086         Alias('install', Cygwin_README)
2087         # also a directory /usr/share/doc/lyx for README etc
2088         Cygwin_Doc = os.path.join(dest_prefix_dir, 'share', 'doc', package)
2089         env.Install(Cygwin_Doc, [os.path.join(env.subst('$TOP_SRCDIR'), x) for x in \
2090             ['INSTALL', 'README', 'README.Cygwin', 'RELEASE-NOTES', 'COPYING', 'ANNOUNCE']])
2091         Alias('install', Cygwin_Doc)
2092         # cygwin fonts also need to be installed
2093         Cygwin_fonts = os.path.join(share_dest_dir, 'fonts')
2094         env.Install(Cygwin_fonts, 
2095             [env.subst('$TOP_SRCDIR/development/Win32/packaging/bakoma/%s' % file) \
2096                   for file in win32_bakoma_fonts])
2097         Alias('install', Cygwin_fonts)
2098         # we also need a post installation script
2099         tmp_script = utils.installCygwinPostinstallScript('/tmp')
2100         postinstall_path = os.path.join(dest_dir, 'etc', 'postinstall')
2101         env.Install(postinstall_path, tmp_script)
2102         Alias('install', postinstall_path)
2103
2104     # subst and install lyx2lyx_version.py which is not in scons_manifest.py
2105     env.Depends(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py', '$BUILDDIR/common/config.h')
2106     env.substFile(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py',
2107         '$TOP_SRCDIR/lib/lyx2lyx/lyx2lyx_version.py.in')
2108     Alias('install', share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2109
2110     # man
2111     env.InstallAs(os.path.join(man_dest_dir, 'lyx' + version_suffix + '.1'),
2112         env.subst('$TOP_SRCDIR/lyx.man'))
2113     env.InstallAs(os.path.join(man_dest_dir, 'tex2lyx' + version_suffix + '.1'),
2114         env.subst('$TOP_SRCDIR/src/tex2lyx/tex2lyx.man'))
2115     env.InstallAs(os.path.join(man_dest_dir, 'lyxclient' + version_suffix + '.1'),
2116         env.subst('$TOP_SRCDIR/src/client/lyxclient.man'))
2117     Alias('install', [os.path.join(man_dest_dir, x + version_suffix + '.1') for
2118         x in ['lyx', 'tex2lyx', 'lyxclient']])
2119     # locale files?
2120     # ru.gmo ==> ru/LC_MESSAGES/lyxSUFFIX.mo
2121     for gmo in gmo_files:
2122         lan = os.path.split(str(gmo))[1].split('.')[0]
2123         dest_file = os.path.join(locale_dest_dir, lan, 'LC_MESSAGES', 'lyx' + program_suffix + '.mo')
2124         env.InstallAs(dest_file, gmo)
2125         Alias('install', dest_file)
2126
2127
2128 Default('lyx')
2129 Alias('all', ['lyx', 'client', 'tex2lyx'])