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