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