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