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