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