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