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