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