]> git.lyx.org Git - features.git/blob - development/scons/SConstruct
Scons: test for the availability of debug version of qt libraries before linking...
[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         if platform_name == 'win32' and use_vc:
686             succ = conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
687         else:
688             succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
689     # still can not find it
690     if not succ:
691         print 'Did not find qt libraries, exiting!'
692         Exit(1)
693     #
694     # Now, determine the correct suffix:
695     qt_libs = ['QtCore', 'QtGui']
696     if platform_name == 'win32':
697         if mode == 'debug' and use_vc and \
698             conf.CheckLibWithHeader('QtCored4', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
699             qt_lib_suffix = 'd4'
700         else:
701             qt_lib_suffix = '4'
702     else:
703         if mode == 'debug' and conf.CheckLibWithHeader('QtCore_debug', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
704             qt_lib_suffix = '_debug'
705         else:
706             qt_lib_suffix = ''
707     frontend_libs = [x + qt_lib_suffix for x in qt_libs]
708     qtcore_lib = ['QtCore' + qt_lib_suffix]
709     
710
711 # now, if msvc2005 is used, we will need that QT_LIB_PATH/QT_LIB.manifest file
712 if use_vc:
713     if frontend == 'qt4':
714         if mode == 'debug':
715             manifest = os.path.join(qt_lib_path, 'QtGuid4.dll.manifest')
716         else:
717             manifest = os.path.join(qt_lib_path, 'QtGui4.dll.manifest')
718     if os.path.isfile(manifest):
719         env['LINKCOM'] = [env['LINKCOM'], 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % manifest]
720
721 # check socket libs
722 socket_libs = []
723 if conf.CheckLib('socket'):
724     socket_libs.append('socket')
725 # nsl is the network services library and provides a
726 # transport-level interface to networking services.
727 if conf.CheckLib('nsl'):
728     socket_libs.append('nsl')
729
730 # check available boost libs (since lyx1.4 does not use iostream)
731 boost_libs = []
732 for lib in ['signals', 'regex', 'filesystem', 'iostreams']:
733     if os.path.isdir(os.path.join(top_src_dir, 'boost', 'libs', lib)):
734         boost_libs.append(lib)
735
736 # check boost libraries
737 boost_opt = ARGUMENTS.get('boost', 'auto')
738 # check for system boost
739 lib_paths = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
740 inc_paths = env['CPPPATH'] + ['/usr/include', '/usr/local/include']
741 # default to $BUILDDIR/libs (use None since this path will be added anyway)
742 boost_libpath = None
743 # here I assume that all libraries are in the same directory
744 if boost_opt == 'included':
745     boost_libraries = ['included_boost_%s' % x for x in boost_libs]
746     included_boost = True
747     env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
748 elif boost_opt == 'auto':
749     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
750     # if not found, use local boost
751     if res[0] is None:
752         boost_libraries = ['included_boost_%s' % x for x in boost_libs]
753         included_boost = True
754         env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
755     else:
756         included_boost = False
757         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
758 elif boost_opt == 'system':
759     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
760     if res[0] is None:
761         print "Can not find system boost libraries with version %s " % boost_version
762         print "Please supply a path through extra_lib_path and try again."
763         print "Or use boost=included to use included boost libraries."
764         Exit(2)
765     else:
766         included_boost = False
767         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
768
769
770 if boost_libpath is not None:
771     env.AppendUnique(LIBPATH = [boost_libpath])
772
773
774 env['ENABLE_NLS'] = env['nls']
775
776 if not env['ENABLE_NLS']:
777     intl_libs = []
778     included_gettext = False
779 else:
780     # check gettext libraries
781     gettext_opt = ARGUMENTS.get('gettext', 'auto')
782     # check for system gettext
783     succ = False
784     if gettext_opt in ['auto', 'system']:
785         if conf.CheckFunc('gettext'):
786             included_gettext = False
787             intl_libs = []
788             succ = True
789         elif conf.CheckLib('intl'):
790             included_gettext = False
791             intl_libs = ['intl']
792             succ = True
793         else: # no found
794             if gettext_opt == 'system':
795                 print "Can not find system gettext library"
796                 print "Please supply a path through extra_lib_path and try again."
797                 print "Or use gettext=included to use included gettext libraries."
798                 Exit(2)
799     # now, auto and succ = false, or gettext=included
800     if not succ:
801         # we do not need to set LIBPATH now.
802         included_gettext = True
803         intl_libs = ['included_intl']
804
805
806 #
807 # check for msgfmt command
808 env['MSGFMT'] = conf.CheckCommand('msgfmt')
809
810 # cygwin packaging requires the binaries to be stripped
811 if platform_name == 'cygwin':
812     env['STRIP'] = conf.CheckCommand('strip')
813
814 # check uic and moc commands for qt frontends
815 if frontend[:2] == 'qt' and (conf.CheckCommand('uic') == None \
816     or conf.CheckCommand('moc') == None):
817     print 'uic or moc command is not found for frontend', frontend
818     Exit(1)
819
820 #
821 # Customized builders
822 #
823 # install customized builders
824 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
825
826
827 #----------------------------------------------------------
828 # Generating config.h
829 #----------------------------------------------------------
830 aspell_lib = 'aspell'
831 # assume that we use aspell, aspelld compiled for msvc
832 if platform_name == 'win32' and mode == 'debug' and use_vc:
833     aspell_lib = 'aspelld'
834
835 # check the existence of config.h
836 config_h = os.path.join(env.Dir('$BUILDDIR/common').path, 'config.h')
837 boost_config_h = os.path.join(env.Dir('$BUILDDIR/boost').path, 'config.h')
838 #
839 print "Creating %s..." % boost_config_h
840 #
841 utils.createConfigFile(conf,
842     config_file = boost_config_h,
843     config_pre = '''/* boost/config.h.  Generated by SCons.  */
844
845 /* -*- C++ -*- */
846 /*
847 * \file config.h
848 * This file is part of LyX, the document processor.
849 * Licence details can be found in the file COPYING.
850 *
851 * This is the compilation configuration file for LyX.
852 * It was generated by scon.
853 * You might want to change some of the defaults if something goes wrong
854 * during the compilation.
855 */
856
857 #ifndef _BOOST_CONFIG_H
858 #define _BOOST_CONFIG_H
859 ''',
860     headers = [
861         ('ostream', 'HAVE_OSTREAM', 'cxx'),
862         ('locale', 'HAVE_LOCALE', 'cxx'),
863         ('sstream', 'HAVE_SSTREAM', 'cxx'),
864         #('newapis.h', 'HAVE_NEWAPIS_H', 'c'),
865     ],
866     custom_tests = [
867         (env.has_key('assertions') and env['assertions'],
868             'ENABLE_ASSERTIONS',
869             'Define if you want assertions to be enabled in the code'
870         ),
871     ],
872     types = [
873         ('wchar_t', 'HAVE_WCHAR_T', None),
874     ],
875     config_post = '''
876
877 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
878 #  define USE_BOOST_FORMAT 1
879 #else
880 #  define USE_BOOST_FORMAT 0
881 #endif
882
883 #if !defined(ENABLE_ASSERTIONS)
884 #  define BOOST_DISABLE_ASSERTS 1
885 #endif
886 #define BOOST_ENABLE_ASSERT_HANDLER 1
887
888 #define BOOST_DISABLE_THREADS 1
889 #define BOOST_NO_WSTRING 1
890
891 #ifdef __CYGWIN__
892 #  define BOOST_POSIX 1
893 #  define BOOST_POSIX_API 1
894 #  define BOOST_POSIX_PATH 1
895 #endif
896
897 #define BOOST_ALL_NO_LIB 1
898
899 #if defined(HAVE_NEWAPIS_H)
900 #  define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
901 #endif
902
903 #if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4
904 #  define LIBC_WCTYPE_USES_UCS4
905 #endif
906
907 #endif
908 '''
909 )
910 #
911 print "\nGenerating %s..." % config_h
912
913 # AIKSAURUS_H_LOCATION
914 if (conf.CheckCXXHeader("Aiksaurus.h")):
915     aik_location = '<Aiksaurus.h>'
916 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
917     aik_location = '<Aiksaurus/Aiksaurus.h>'
918 else:
919     aik_location = ''
920
921 # determine headers to use
922 spell_opt = ARGUMENTS.get('spell', 'auto')
923 env['USE_ASPELL'] = False
924 env['USE_PSPELL'] = False
925 env['USE_ISPELL'] = False
926 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
927     spell_engine = 'USE_ASPELL'
928 elif spell_opt in ['auto', 'pspell'] and conf.CheckLib('pspell'):
929     spell_engine = 'USE_PSPELL'
930 elif spell_opt in ['auto', 'ispell'] and conf.CheckLib('ispell'):
931     spell_engine = 'USE_ISPELL'
932 else:
933     spell_engine = None
934
935 if spell_engine is not None:
936     env[spell_engine] = True
937 else:
938     if spell_opt == 'auto':
939         print "Warning: Can not locate any spell checker"
940     elif spell_opt != 'no':
941         print "Warning: Can not locate specified spell checker:", spell_opt
942         Exit(1)
943
944 # check arg types of select function
945 (select_arg1, select_arg234, select_arg5) = conf.CheckSelectArgType()
946
947 # check the size of wchar_t
948 sizeof_wchar_t = conf.CheckSizeOfWChar()
949 # something wrong
950 if sizeof_wchar_t == 0:
951     print 'Error: Can not determine the size of wchar_t.'
952     Exit(1)
953
954 #
955 # create config.h
956 result = utils.createConfigFile(conf,
957     config_file = config_h,
958     config_pre = '''/* config.h.  Generated by SCons.  */
959
960 /* -*- C++ -*- */
961 /*
962 * \file config.h
963 * This file is part of LyX, the document processor.
964 * Licence details can be found in the file COPYING.
965 *
966 * This is the compilation configuration file for LyX.
967 * It was generated by scon.
968 * You might want to change some of the defaults if something goes wrong
969 * during the compilation.
970 */
971
972 #ifndef _CONFIG_H
973 #define _CONFIG_H
974 ''',
975     headers = [
976         ('io.h', 'HAVE_IO_H', 'c'),
977         ('limits.h', 'HAVE_LIMITS_H', 'c'),
978         ('locale.h', 'HAVE_LOCALE_H', 'c'),
979         ('process.h', 'HAVE_PROCESS_H', 'c'),
980         ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
981         ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
982         ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
983         ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
984         ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
985         ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
986         ('unistd.h', 'HAVE_UNISTD_H', 'c'),
987         ('utime.h', 'HAVE_UTIME_H', 'c'),
988         ('direct.h', 'HAVE_DIRECT_H', 'c'),
989         ('istream', 'HAVE_ISTREAM', 'cxx'),
990         ('ios', 'HAVE_IOS', 'cxx'),
991     ],
992     functions = [
993         ('open', 'HAVE_OPEN', None),
994         ('chmod', 'HAVE_CHMOD', None),
995         ('close', 'HAVE_CLOSE', None),
996         ('popen', 'HAVE_POPEN', None),
997         ('pclose', 'HAVE_PCLOSE', None),
998         ('_open', 'HAVE__OPEN', None),
999         ('_close', 'HAVE__CLOSE', None),
1000         ('_popen', 'HAVE__POPEN', None),
1001         ('_pclose', 'HAVE__PCLOSE', None),
1002         ('getpid', 'HAVE_GETPID', None),
1003         ('_getpid', 'HAVE__GETPID', None),
1004         ('mkdir', 'HAVE_MKDIR', None),
1005         ('_mkdir', 'HAVE__MKDIR', None),
1006         ('mktemp', 'HAVE_MKTEMP', None),
1007         ('mkstemp', 'HAVE_MKSTEMP', None),
1008         ('strerror', 'HAVE_STRERROR', None),
1009         ('count', 'HAVE_STD_COUNT', '''
1010 #include <algorithm>
1011 int count()
1012 {
1013 char a[] = "hello";
1014 return std::count(a, a+5, 'l');
1015 }
1016 '''),
1017         ('getcwd', 'HAVE_GETCWD', None),
1018         ('setenv', 'HAVE_SETENV', None),
1019         ('putenv', 'HAVE_PUTENV', None),
1020         ('fcntl', 'HAVE_FCNTL', None),
1021     ],
1022     types = [
1023         ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
1024             '#include <streambuf>\n#include <istream>'),
1025         ('wchar_t', 'HAVE_WCHAR_T', None),
1026         ('mode_t', 'HAVE_MODE_T', "#include <sys/types.h>"),
1027     ],
1028     libs = [
1029         ('gdi32', 'HAVE_LIBGDI32'),
1030         (('Aiksaurus', 'libAiksaurus'), 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB'),
1031     ],
1032     custom_tests = [
1033         (conf.CheckType('pid_t', includes='#include <sys/types.h>'),
1034             'HAVE_PID_T',
1035             'Define is sys/types.h does not have pid_t',
1036             '',
1037             '#define pid_t int',
1038         ),
1039         (conf.CheckCXXGlobalCstd(),
1040             'CXX_GLOBAL_CSTD',
1041             'Define if your C++ compiler puts C library functions in the global namespace'
1042         ),
1043         (conf.CheckMkdirOneArg(),
1044             'MKDIR_TAKES_ONE_ARG',
1045             'Define if mkdir takes only one argument.'
1046         ),
1047         (conf.CheckIconvConst(),
1048             'ICONV_CONST',
1049             'Define as const if the declaration of iconv() needs const.',
1050             '#define ICONV_CONST const',
1051             '#define ICONV_CONST',
1052         ),
1053         (conf.CheckLC_MESSAGES(),
1054             'HAVE_LC_MESSAGES',
1055             'Define if your <locale.h> file defines LC_MESSAGES.'
1056         ),
1057         (devel_version, 'DEVEL_VERSION', 'Whether or not a development version'),
1058         (env['nls'],
1059             'ENABLE_NLS',
1060             "Define to 1 if translation of program messages to the user's native anguage is requested.",
1061         ),
1062         (env['nls'] and not included_gettext,
1063             'HAVE_GETTEXT',
1064             'Define to 1 if using system gettext library'
1065         ),
1066         (env.has_key('warnings') and env['warnings'],
1067             'WITH_WARNINGS',
1068             'Define this if you want to see the warning directives put here and there by the developpers to get attention'
1069         ),
1070         (env.has_key('concept_checks') and env['concept_checks'],
1071             '_GLIBCXX_CONCEPT_CHECKS',
1072             'libstdc++ concept checking'
1073         ),
1074         (env.has_key('stdlib_debug') and env['stdlib_debug'],
1075             '_GLIBCXX_DEBUG',
1076             'libstdc++ debug mode'
1077         ),
1078         (env.has_key('stdlib_debug') and env['stdlib_debug'],
1079             '_GLIBCXX_DEBUG_PEDANTIC',
1080             'libstdc++ pedantic debug mode'
1081         ),
1082         (os.name != 'nt', 'BOOST_POSIX',
1083             'Indicates to boost < 1.34 which API to use (posix or windows).'
1084         ),
1085         (os.name != 'nt', 'BOOST_POSIX_API',
1086             'Indicates to boost 1.34 which API to use (posix or windows).'
1087         ),
1088         (os.name != 'nt', 'BOOST_POSIX_PATH',
1089             'Indicates to boost 1.34 which path style to use (posix or windows).'
1090         ),
1091         (spell_engine is not None, spell_engine,
1092             'Spell engine to use'
1093         ),
1094         # we need to know the byte order for unicode conversions
1095         (sys.byteorder == 'big', 'WORDS_BIGENDIAN',
1096             'Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).'
1097         ),
1098     ],
1099     extra_items = [
1100         ('#define PACKAGE "%s%s"' % (package, program_suffix),
1101             'Name of package'),
1102         ('#define PACKAGE_BUGREPORT "%s"' % package_bugreport,
1103             'Define to the address where bug reports for this package should be sent.'),
1104         ('#define PACKAGE_NAME "%s"' % package_name,
1105             'Define to the full name of this package.'),
1106         ('#define PACKAGE_STRING "%s"' % package_string,
1107             'Define to the full name and version of this package.'),
1108         ('#define PACKAGE_TARNAME "%s"' % package_tarname,
1109             'Define to the one symbol short name of this package.'),
1110         ('#define PACKAGE_VERSION "%s"' % package_version,
1111             'Define to the version of this package.'),
1112         ('#define BOOST_ALL_NO_LIB 1',
1113             'disable automatic linking of boost libraries.'),
1114         ('#define USE_%s_PACKAGING 1' % packaging_method.upper(),
1115             'Packaging method'),
1116         ('#define AIKSAURUS_H_LOCATION ' + aik_location,
1117             'Aiksaurus include file'),
1118         ('#define SELECT_TYPE_ARG1 %s' % select_arg1,
1119             "Define to the type of arg 1 for `select'."),
1120         ('#define SELECT_TYPE_ARG234 %s' % select_arg234,
1121             "Define to the type of arg 2, 3, 4 for `select'."),
1122         ('#define SELECT_TYPE_ARG5 %s' % select_arg5,
1123             "Define to the type of arg 5 for `select'."),
1124         ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1125             'Define to be the size of type wchar_t'),
1126     ],
1127     config_post = '''/************************************************************
1128 ** You should not need to change anything beyond this point */
1129
1130 #ifndef HAVE_STRERROR
1131 #if defined(__cplusplus)
1132 extern "C"
1133 #endif
1134 char * strerror(int n);
1135 #endif
1136
1137 #ifdef HAVE_MKSTEMP
1138 #ifndef HAVE_DECL_MKSTEMP
1139 #if defined(__cplusplus)
1140 extern "C"
1141 #endif
1142 int mkstemp(char*);
1143 #endif
1144 #endif
1145
1146 #include <../boost/config.h>
1147
1148 #endif
1149 '''
1150 )
1151
1152 # these keys are needed in env
1153 for key in ['USE_ASPELL', 'USE_PSPELL', 'USE_ISPELL', 'HAVE_FCNTL',\
1154     'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
1155     # USE_ASPELL etc does not go through result
1156     if result.has_key(key):
1157         env[key] = result[key]
1158
1159 #
1160 # if nls=yes and gettext=included, create intl/config.h
1161 # intl/libintl.h etc
1162 #
1163 intl_config_h = os.path.join(env.Dir('$BUILDDIR/intl').path, 'config.h')
1164 if env['nls'] and included_gettext:
1165     #
1166     print "Creating %s..." % intl_config_h
1167     #
1168     # create intl/config.h
1169     result = utils.createConfigFile(conf,
1170         config_file = intl_config_h,
1171         config_pre = '''/* intl/config.h.  Generated by SCons.  */
1172
1173 /* -*- C++ -*- */
1174 /*
1175 * \file config.h
1176 * This file is part of LyX, the document processor.
1177 * Licence details can be found in the file COPYING.
1178 *
1179 * This is the compilation configuration file for LyX.
1180 * It was generated by scon.
1181 * You might want to change some of the defaults if something goes wrong
1182 * during the compilation.
1183 */
1184
1185 #ifndef _CONFIG_H
1186 #define _CONFIG_H
1187 ''',
1188         headers = [
1189             ('unistd.h', 'HAVE_UNISTD_H', 'c'),
1190             ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
1191             ('string.h', 'HAVE_STRING_H', 'c'),
1192             ('strings.h', 'HAVE_STRINGS_H', 'c'),
1193             ('argz.h', 'HAVE_ARGZ_H', 'c'),
1194             ('limits.h', 'HAVE_LIMITS_H', 'c'),
1195             ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
1196             ('stddef.h', 'HAVE_STDDEF_H', 'c'),
1197             ('stdint.h', 'HAVE_STDINT_H', 'c'),
1198             ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c'),
1199         ],
1200         functions = [
1201             ('getcwd', 'HAVE_GETCWD', None),
1202             ('stpcpy', 'HAVE_STPCPY', None),
1203             ('strcasecmp', 'HAVE_STRCASECMP', None),
1204             ('strdup', 'HAVE_STRDUP', None),
1205             ('strtoul', 'HAVE_STRTOUL', None),
1206             ('alloca', 'HAVE_ALLOCA', None),
1207             ('__fsetlocking', 'HAVE___FSETLOCKING', None),
1208             ('mempcpy', 'HAVE_MEMPCPY', None),
1209             ('__argz_count', 'HAVE___ARGZ_COUNT', None),
1210             ('__argz_next', 'HAVE___ARGZ_NEXT', None),
1211             ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
1212             ('setlocale', 'HAVE_SETLOCALE', None),
1213             ('tsearch', 'HAVE_TSEARCH', None),
1214             ('getegid', 'HAVE_GETEGID', None),
1215             ('getgid', 'HAVE_GETGID', None),
1216             ('getuid', 'HAVE_GETUID', None),
1217             ('wcslen', 'HAVE_WCSLEN', None),
1218             ('asprintf', 'HAVE_ASPRINTF', None),
1219             ('wprintf', 'HAVE_WPRINTF', None),
1220             ('snprintf', 'HAVE_SNPRINTF', None),
1221             ('printf', 'HAVE_POSIX_PRINTF', None),
1222             ('fcntl', 'HAVE_FCNTL', None),
1223         ],
1224         types = [
1225             ('intmax_t', 'HAVE_INTMAX_T', None),
1226             ('long double', 'HAVE_LONG_DOUBLE', None),
1227             ('long long', 'HAVE_LONG_LONG', None),
1228             ('wchar_t', 'HAVE_WCHAR_T', None),
1229             ('wint_t', 'HAVE_WINT_T', None),
1230             ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
1231             ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
1232         ],
1233         libs = [
1234             ('c', 'HAVE_LIBC'),
1235         ],
1236         custom_tests = [
1237             (conf.CheckLC_MESSAGES(),
1238                 'HAVE_LC_MESSAGES',
1239                 'Define if your <locale.h> file defines LC_MESSAGES.'
1240             ),
1241             (conf.CheckIconvConst(),
1242                 'ICONV_CONST',
1243                 'Define as const if the declaration of iconv() needs const.',
1244                 '#define ICONV_CONST const',
1245                 '#define ICONV_CONST',
1246             ),
1247             (conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
1248             conf.CheckType('intmax_t', includes='#include <inttypes.h>'),
1249                 'HAVE_INTMAX_T',
1250                 "Define to 1 if you have the `intmax_t' type."
1251             ),
1252             (env.has_key('nls') and env['nls'],
1253                 'ENABLE_NLS',
1254                 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1255             ),
1256         ],
1257         extra_items = [
1258             ('#define HAVE_ICONV 1', 'Define if iconv or libiconv is found'),
1259             ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1260                 'Define to be the size of type wchar_t'),
1261         ],
1262         config_post = '#endif'
1263     )
1264
1265     # these keys are needed in env
1266     for key in ['HAVE_ASPRINTF', 'HAVE_WPRINTF', 'HAVE_SNPRINTF', \
1267         'HAVE_POSIX_PRINTF', 'HAVE_LIBC']:
1268         # USE_ASPELL etc does not go through result
1269         if result.has_key(key):
1270             env[key] = result[key]
1271
1272
1273 # this looks misplaced, but intl/libintl.h is needed by src/message.C
1274 if env['nls'] and included_gettext:
1275     # libgnuintl.h.in => libintl.h
1276     env.Depends('$TOP_SRCDIR/intl/libintl.h', '$BUILDDIR/intl/config.h')
1277     env.substFile('$BUILDDIR/intl/libintl.h', '$TOP_SRCDIR/intl/libgnuintl.h.in')
1278     env.Command('$BUILDDIR/intl/libgnuintl.h', '$BUILDDIR/intl/libintl.h',
1279         [Copy('$TARGET', '$SOURCE')])
1280
1281 #
1282 # Finish auto-configuration
1283 env = conf.Finish()
1284
1285 #----------------------------------------------------------
1286 # Now set up our build process accordingly
1287 #----------------------------------------------------------
1288
1289
1290
1291 if env['ICONV_LIB'] is None:
1292     system_libs = []
1293 else:
1294     system_libs = [env['ICONV_LIB']]
1295 if platform_name in ['win32', 'cygwin']:
1296     # the final link step needs stdc++ to succeed under mingw
1297     # FIXME: shouldn't g++ automatically link to stdc++?
1298     if use_vc:
1299         system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll']
1300     else:
1301         system_libs += ['shlwapi', 'stdc++', 'z']
1302 elif platform_name == 'cygwin' and env['X11']:
1303     system_libs += ['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr',
1304         'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 
1305         'resolv', 'pthread', 'z']
1306 else:
1307     system_libs += ['z']
1308
1309 libs = [
1310     ('HAVE_LIBGDI32', 'gdi32'),
1311     ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
1312     ('USE_ASPELL', aspell_lib),
1313     ('USE_ISPELL', 'ispell'),
1314     ('USE_PSPELL', 'pspell'),
1315 ]
1316
1317 for lib in libs:
1318     if env[lib[0]]:
1319         system_libs.append(lib[1])
1320
1321 #
1322 # Build parameters CPPPATH etc
1323 #
1324 if env['X11']:
1325     env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1326
1327 #
1328 # boost: for boost header files
1329 # BUILDDIR/common: for config.h
1330 # TOP_SRCDIR/src: for support/* etc
1331 #
1332 env['CPPPATH'] += ['$BUILDDIR/common', '$TOP_SRCDIR/src']
1333 #
1334 # Separating boost directories from CPPPATH stops scons from building
1335 # the dependency tree for boost header files, and effectively reduce
1336 # the null build time of lyx from 29s to 16s. Since lyx may tweak local
1337 # boost headers, this is only done for system boost headers.
1338 if included_boost:
1339     env.AppendUnique(CPPPATH = ['$BOOST_INC_PATH'])
1340 else:
1341     if use_vc:
1342         env.PrependUnique(CCFLAGS = ['/I$BOOST_INC_PATH'])
1343     else:
1344         env.PrependUnique(CCFLAGS = ['-I$BOOST_INC_PATH'])
1345
1346 # for intl/config.h, intl/libintl.h and intl/libgnuintl.h
1347 if env['nls'] and included_gettext:
1348     env['CPPPATH'].append('$BUILDDIR/intl')
1349 #
1350 # QT_INC_PATH is not needed for *every* source file
1351 env['CPPPATH'].remove(qt_inc_path)
1352
1353 #
1354 # A Link script for cygwin see
1355 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1356 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1357 # for details
1358 #
1359 if platform_name == 'cygwin':
1360     ld_script_path = '/tmp'
1361     ld_script = utils.installCygwinLDScript(ld_script_path)
1362     env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1363         '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1364
1365 #
1366 # Report results
1367 #
1368 # fill in the version info
1369 env['VERSION_INFO'] = '''Configuration
1370   Host type:                      %s
1371   Special build flags:            %s
1372   C   Compiler:                   %s
1373   C   Compiler flags:             %s %s
1374   C++ Compiler:                   %s
1375   C++ Compiler LyX flags:         %s
1376   C++ Compiler flags:             %s %s
1377   Linker flags:                   %s
1378   Linker user flags:              %s
1379 Build info:
1380   Builing directory:              %s
1381   Local library directory:        %s
1382   Libraries paths:                %s
1383   Boost libraries:                %s
1384   Frontend libraries:             %s
1385   System libraries:               %s
1386   include search path:            %s
1387 Frontend:
1388   Frontend:                       %s
1389   Packaging:                      %s
1390   LyX dir:                        %s
1391   LyX files dir:                  %s
1392 ''' % (platform_name,
1393     env.subst('$CCFLAGS'), env.subst('$CC'),
1394     env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1395     env.subst('$CXX'), env.subst('$CXXFLAGS'),
1396     env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1397     env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1398     env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1399     str(env['LIBPATH']), str(boost_libraries),
1400     str(frontend_libs), str(system_libs), str(env['CPPPATH']),
1401     frontend, packaging_method,
1402     prefix, env['LYX_DIR'])
1403
1404 if frontend in ['qt4']:
1405     env['VERSION_INFO'] += '''  include dir:                    %s
1406   library dir:                    %s
1407   X11:                            %s
1408 ''' % (qt_inc_path, qt_lib_path, env['X11'])
1409
1410 print env['VERSION_INFO']
1411
1412 #
1413 # Mingw command line may be too short for our link usage,
1414 # Here we use a trick from scons wiki
1415 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1416 #
1417 # I also would like to add logging (commands only) capacity to the
1418 # spawn system.
1419 logfile = env.get('logfile', default_log_file)
1420 if logfile != '' or platform_name == 'win32':
1421     import time
1422     utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1423         info = '''# This is a log of commands used by scons to build lyx
1424 # Time: %s
1425 # Command: %s
1426 # Info: %s
1427 ''' % (time.asctime(), ' '.join(sys.argv),
1428     env['VERSION_INFO'].replace('\n','\n# ')) )
1429
1430
1431 # Cleanup stuff
1432 #
1433 # -h will print out help info
1434 Help(opts.GenerateHelpText(env))
1435
1436
1437
1438 #----------------------------------------------------------
1439 # Start building
1440 #----------------------------------------------------------
1441 # this has been the source of problems on some platforms...
1442 # I find that I need to supply it with full path name
1443 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1444 # this usage needs further investigation.
1445 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1446
1447 print "Building all targets recursively"
1448
1449 if env.has_key('rebuild'):
1450     rebuild_targets = env['rebuild'].split(',')
1451     if 'none' in rebuild_targets or 'no' in rebuild_targets:
1452         rebuild_targets = []
1453     elif 'all' in rebuild_targets or 'yes' in rebuild_targets:
1454         # None: let scons decide which components to build
1455         # Forcing all components to be rebuilt is in theory not necessary
1456         rebuild_targets = None    
1457 else:
1458     rebuild_targets = None
1459
1460 def libExists(libname):
1461     ''' Check whether or not lib $LOCALLIBNAME/libname already exists'''
1462     return os.path.isfile(File(env.subst('$LOCALLIBPATH/${LIBPREFIX}%s$LIBSUFFIX'%libname)).abspath)
1463
1464 def appExists(apppath, appname):
1465     ''' Check whether or not application already exists'''
1466     return os.path.isfile(File(env.subst('$BUILDDIR/common/%s/${PROGPREFIX}%s$PROGSUFFIX' % (apppath, appname))).abspath)
1467
1468 targets = BUILD_TARGETS
1469 # msvc need to pass full target name, so I have to look for path/lyx etc
1470 build_lyx = targets == [] or True in ['lyx' in x for x in targets] \
1471     or 'install' in targets or 'all' in targets
1472 build_boost = (included_boost and not libExists('boost_regex')) or 'boost' in targets
1473 build_intl = (included_gettext and not libExists('included_intl')) or 'intl' in targets
1474 build_support = build_lyx or True in [x in targets for x in ['support', 'client', 'tex2lyx']]
1475 build_mathed = build_lyx or 'mathed' in targets
1476 build_insets = build_lyx or 'insets' in targets
1477 build_frontends = build_lyx or 'frontends' in targets
1478 build_graphics = build_lyx or 'graphics' in targets
1479 build_controllers = build_lyx or 'controllers' in targets
1480 build_client = True in ['client' in x for x in targets] \
1481     or 'install' in targets or 'all' in targets
1482 build_tex2lyx = True in ['tex2lyx' in x for x in targets] \
1483     or 'install' in targets or 'all' in targets
1484 build_lyxbase = build_lyx or 'lyxbase' in targets
1485 build_po = 'po' in targets or 'install' in targets or 'all' in targets
1486 build_qt4 = (build_lyx and frontend == 'qt4') or 'qt4' in targets
1487 build_msvs_projects = use_vc and 'msvs_projects' in targets
1488
1489
1490 # now, if rebuild_targets is specified, do not rebuild some targets
1491 if rebuild_targets is not None:
1492     #
1493     def ifBuildLib(name, libname, old_value):
1494         # explicitly asked to rebuild
1495         if name in rebuild_targets:
1496             return True
1497         # else if not rebuild, and if the library already exists
1498         elif libExists(libname):
1499             return False
1500         # do not change the original value
1501         else:
1502             return old_value
1503     build_boost = ifBuildLib('boost', 'included_boost_filesystem', build_boost)
1504     build_intl = ifBuildLib('intl', 'included_intl', build_intl)
1505     build_support = ifBuildLib('support', 'support', build_support)
1506     build_mathed = ifBuildLib('mathed', 'mathed', build_mathed)
1507     build_insets = ifBuildLib('insets', 'insets', build_insets)
1508     build_frontends = ifBuildLib('frontends', 'frontends', build_frontends)
1509     build_graphics = ifBuildLib('graphics', 'graphics', build_graphics)
1510     build_controllers = ifBuildLib('controllers', 'controllers', build_controllers)
1511     build_lyxbase = ifBuildLib('lyxbase', 'lyxbase_pre', build_lyxbase)
1512     build_qt4 = ifBuildLib('qt4', 'qt4', build_qt4)
1513     #
1514     def ifBuildApp(name, appname, 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 appExists(name, appname):
1520             return False
1521         # do not change the original value
1522         else:
1523             return old_value
1524     build_tex2lyx = ifBuildApp('tex2lyx', 'tex2lyx', build_tex2lyx)
1525     build_client = ifBuildApp('client', 'lyxclient', build_client)
1526
1527 # sync frontend and frontend (?)
1528 if build_qt4:
1529     frontend = 'qt4'
1530
1531
1532 if build_boost:
1533     #
1534     # boost libraries
1535     #
1536     # special builddir
1537     env.BuildDir('$BUILDDIR/boost', '$TOP_SRCDIR/boost/libs', duplicate = 0)
1538
1539     boostenv = env.Copy()
1540     #
1541     # boost use its own config.h
1542     boostenv['CPPPATH'] = ['$TOP_SRCDIR/boost', '$BUILDDIR/boost'] + extra_inc_paths
1543     boostenv.AppendUnique(CCFLAGS = ['-DBOOST_USER_CONFIG="<config.h>"'])
1544
1545     for lib in boost_libs:
1546         print 'Processing files in boost/libs/%s/src...' % lib
1547         boostlib = boostenv.StaticLibrary(
1548             target = '$LOCALLIBPATH/included_boost_%s' % lib,
1549             source = ['$BUILDDIR/boost/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1550         )
1551         Alias('boost', boostlib)
1552
1553
1554 if build_intl:
1555     #
1556     # intl
1557     #
1558     intlenv = env.Copy()
1559
1560     print "Processing files in intl..."
1561
1562     env.BuildDir('$BUILDDIR/intl', '$TOP_SRCDIR/intl', duplicate = 0)
1563
1564     # we need the original C compiler for these files
1565     intlenv['CC'] = C_COMPILER
1566     intlenv['CCFLAGS'] = C_CCFLAGS
1567     if use_vc:
1568         intlenv.Append(CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
1569     # intl does not use global config.h
1570     intlenv['CPPPATH'] = ['$BUILDDIR/intl'] + extra_inc_paths
1571
1572     intlenv.Append(CCFLAGS = [
1573         r'-DLOCALEDIR=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1574         r'-DLOCALE_ALIAS_PATH=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1575         r'-DLIBDIR=\"' + env['TOP_SRCDIR'].replace('\\', '\\\\') + r'/lib\"',
1576         '-DIN_LIBINTL',
1577         '-DENABLE_RELOCATABLE=1',
1578         '-DIN_LIBRARY',
1579         r'-DINSTALLDIR=\"' + prefix.replace('\\', '\\\\') + r'/lib\"',
1580         '-DNO_XMALLOC',
1581         '-Dset_relocation_prefix=libintl_set_relocation_prefix',
1582         '-Drelocate=libintl_relocate',
1583         '-DDEPENDS_ON_LIBICONV=1',
1584         '-DHAVE_CONFIG_H'
1585         ]
1586     )
1587
1588     intl = intlenv.StaticLibrary(
1589         target = '$LOCALLIBPATH/included_intl',
1590         LIBS = ['c'],
1591         source = ['$BUILDDIR/intl/%s' % x for x in intl_files]
1592     )
1593     Alias('intl', intl)
1594
1595
1596 #
1597 # Now, src code under src/
1598 #
1599 env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1600
1601
1602 if build_support:
1603     #
1604     # src/support
1605     #
1606     print "Processing files in src/support..."
1607
1608     env.Depends('$BUILDDIR/common/support/package.C', '$BUILDDIR/common/config.h')
1609     env.substFile('$BUILDDIR/common/support/package.C', '$TOP_SRCDIR/src/support/package.C.in')
1610
1611     support = env.StaticLibrary(
1612         target = '$LOCALLIBPATH/support',
1613         source = ['$BUILDDIR/common/support/%s' % x for x in src_support_files],
1614         CPPPATH = ['$CPPPATH', qt_inc_path, os.path.join(qt_inc_path, 'QtCore')]
1615     )
1616     Alias('support', support)
1617
1618
1619 if build_mathed:
1620     #
1621     # src/mathed
1622     #
1623     print "Processing files in src/mathed..."
1624     #
1625     mathed = env.StaticLibrary(
1626         target = '$LOCALLIBPATH/mathed',
1627         source = ['$BUILDDIR/common/mathed/%s' % x for x in src_mathed_files]
1628     )
1629     Alias('mathed', mathed)
1630
1631
1632 if build_insets:
1633     #
1634     # src/insets
1635     #
1636     print "Processing files in src/insets..."
1637     #
1638     insets = env.StaticLibrary(
1639         target = '$LOCALLIBPATH/insets',
1640         source = ['$BUILDDIR/common/insets/%s' % x for x in src_insets_files]
1641     )
1642     Alias('insets', insets)
1643
1644
1645 if build_frontends:
1646     #
1647     # src/frontends
1648     #
1649     print "Processing files in src/frontends..."
1650
1651     frontends = env.StaticLibrary(
1652         target = '$LOCALLIBPATH/frontends',
1653         source = ['$BUILDDIR/common/frontends/%s' % x for x in src_frontends_files]
1654     )
1655     Alias('frontends', frontends)
1656
1657
1658 if build_graphics:
1659     #
1660     # src/graphics
1661     #
1662     print "Processing files in src/graphics..."
1663
1664     graphics = env.StaticLibrary(
1665         target = '$LOCALLIBPATH/graphics',
1666         source = ['$BUILDDIR/common/graphics/%s' % x for x in src_graphics_files]
1667     )
1668     Alias('graphics', graphics)
1669
1670
1671 if build_controllers:
1672     #
1673     # src/frontends/controllers
1674     #
1675     print "Processing files in src/frontends/controllers..."
1676
1677     controllers = env.StaticLibrary(
1678         target = '$LOCALLIBPATH/controllers',
1679         source = ['$BUILDDIR/common/frontends/controllers/%s' % x for x in src_frontends_controllers_files]
1680     )
1681     Alias('controllers', controllers)
1682
1683
1684 #
1685 # src/frontend/qt4
1686 #
1687 if build_qt4:
1688     env.BuildDir('$BUILDDIR/$frontend', '$TOP_SRCDIR/src/frontend/$frontend', duplicate = 0)
1689
1690     print "Processing files in src/frontends/qt4..."
1691
1692     qt4env = env.Copy()
1693     qt4env['QT_AUTOSCAN'] = 0
1694
1695     # local qt4 toolset from
1696     # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
1697     #
1698     # NOTE: I have to patch qt4.py since it does not automatically
1699     # process .C file!!! (add to cxx_suffixes )
1700     #
1701     qt4env.Tool('qt4', [scons_dir])
1702     qt4env.EnableQt4Modules(qt_libs, debug = (mode == 'debug'))
1703     qt4env['QT4_AUTOSCAN'] = 0
1704     qt4env['QT4_UICDECLFLAGS'] = '-tr lyx::qt_'
1705
1706     qt4env.AppendUnique(CPPPATH = [
1707         '$BUILDDIR/common',
1708         '$BUILDDIR/common/images',
1709         '$BUILDDIR/common/frontends',
1710         '$BUILDDIR/common/frontends/qt4',
1711         '$BUILDDIR/common/frontends/controllers',
1712         qt_inc_path
1713         ]
1714     )
1715
1716     # FIXME: replace by something from pkg_config
1717     qt4env.Append(CCFLAGS = [
1718         '-DHAVE_CONFIG_H',
1719         '-DQT_CLEAN_NAMESPACE',
1720         '-DQT_GENUINE_STR',
1721         '-DQT_NO_STL',
1722         '-DQT_NO_KEYWORDS',
1723         ]
1724     )
1725
1726
1727     qt4_moc_files = ["$BUILDDIR/common/frontends/qt4/%s" % x for x in src_frontends_qt4_moc_files]
1728
1729     #
1730     # Compile resources
1731     #
1732     resources = [qt4env.Uic4(x.split('.')[0]) for x in \
1733         ["$BUILDDIR/common/frontends/qt4/ui/%s" % x for x in src_frontends_qt4_ui_files]]
1734
1735     #
1736     # moc qt4_moc_files, the moced files are included in the original files
1737     #
1738     qt4_moced_files = [qt4env.Moc4(x.replace('.C', '_moc.cpp'), x.replace('.C', '.h')) for x in qt4_moc_files]
1739
1740     qt4 = qt4env.StaticLibrary(
1741         target = '$LOCALLIBPATH/qt4',
1742         source = ['$BUILDDIR/common/frontends/qt4/%s' % x for x in src_frontends_qt4_files]
1743     )
1744     Alias('qt4', qt4)
1745
1746
1747 if build_client:
1748     #
1749     # src/client
1750     #
1751     env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1752
1753     print "Processing files in src/client..."
1754
1755     if env['HAVE_FCNTL']:
1756         client = env.Program(
1757             target = '$BUILDDIR/common/client/lyxclient',
1758             LIBS = ['support'] + intl_libs + system_libs +
1759                 socket_libs + boost_libraries + qtcore_lib,
1760             source = ['$BUILDDIR/common/client/%s' % x for x in src_client_files]
1761         )
1762         Alias('client', env.Command(os.path.join('$BUILDDIR', os.path.split(str(client[0]))[1]),
1763             client, [Copy('$TARGET', '$SOURCE')]))
1764     else:
1765         client = None
1766     Alias('client', client)
1767 else:
1768     if env['HAVE_FCNTL']:
1769         # define client even if lyxclient is not built with rebuild=no
1770         client = [env.subst('$BUILDDIR/common/client/${PROGPREFIX}lyxclient$PROGSUFFIX')]
1771     else:
1772         client = None
1773
1774
1775 if build_tex2lyx:
1776     #
1777     # tex2lyx
1778     #
1779     print "Processing files in src/tex2lyx..."
1780
1781     tex2lyx_env = env.Copy()
1782     #
1783     tex2lyx_env.Prepend(CPPPATH = ['$BUILDDIR/common/tex2lyx'])
1784     tex2lyx_env.AppendUnique(LIBPATH = ['#$LOCALLIBPATH'])
1785
1786     for file in ['FloatList.C', 'Floating.C', 'counters.C', 'lyxlayout.h', 'lyxlayout.C', 
1787         'lyxtextclass.h', 'lyxtextclass.C', 'lyxlex.C', 'lyxlex_pimpl.C']:
1788         env.Command('$BUILDDIR/common/tex2lyx/'+file, '$TOP_SRCDIR/src/'+file,
1789             [Copy('$TARGET', '$SOURCE')])
1790
1791     tex2lyx = tex2lyx_env.Program(
1792         target = '$BUILDDIR/common/tex2lyx/tex2lyx',
1793         LIBS = ['support'] + boost_libraries + intl_libs + system_libs + qtcore_lib,
1794         source = ['$BUILDDIR/common/tex2lyx/%s' % x for x in src_tex2lyx_files]
1795     )
1796     Alias('tex2lyx', env.Command(os.path.join('$BUILDDIR', os.path.split(str(tex2lyx[0]))[1]),
1797         tex2lyx, [Copy('$TARGET', '$SOURCE')]))
1798     Alias('tex2lyx', tex2lyx)
1799 else:
1800     # define tex2lyx even if tex2lyx is not built with rebuild=no
1801     tex2lyx = [env.subst('$BUILDDIR/common/tex2lyx/${PROGPREFIX}tex2lyx$PROGSUFFIX')]
1802
1803
1804 if build_lyxbase:
1805     #
1806     # src/
1807     #
1808     print "Processing files in src..."
1809
1810     env.Depends('$BUILDDIR/common/version.C', '$BUILDDIR/common/config.h')
1811     env.substFile('$BUILDDIR/common/version.C', '$TOP_SRCDIR/src/version.C.in')
1812
1813     if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
1814         src_post_files.append('aspell.C')
1815     elif env.has_key('USE_PSPELL') and env['USE_PSPELL']:
1816         src_post_files.append('pspell.C')
1817     elif env.has_key('USE_ISPELL') and env['USE_ISPELL']:
1818         src_post_files.append('ispell.C')
1819
1820     # msvc requires at least one source file with main()
1821     # so I exclude main.C from lyxbase
1822     lyxbase_pre = env.StaticLibrary(
1823         target = '$LOCALLIBPATH/lyxbase_pre',
1824         source = ['$BUILDDIR/common/%s' % x for x in src_pre_files]
1825     )
1826     lyxbase_post = env.StaticLibrary(
1827         target = '$LOCALLIBPATH/lyxbase_post',
1828         source = ["$BUILDDIR/common/%s" % x for x in src_post_files]
1829     )
1830     Alias('lyxbase', lyxbase_pre)
1831     Alias('lyxbase', lyxbase_post)
1832
1833
1834 if build_lyx:
1835     #
1836     # Build lyx with given frontend
1837     #
1838     lyx = env.Program(
1839         target = '$BUILDDIR/lyx',
1840         source = ['$BUILDDIR/common/main.C'],
1841         LIBS = [
1842             'lyxbase_pre',
1843             'mathed',
1844             'insets',
1845             'frontends',
1846             frontend,
1847             'controllers',
1848             'graphics',
1849             'support',
1850             'lyxbase_post',
1851             ] +
1852             boost_libraries +
1853             frontend_libs +
1854             intl_libs +
1855             socket_libs +
1856             system_libs
1857     )
1858     Alias('lyx', lyx)
1859 else:
1860     # define lyx even if lyx is not built with rebuild=no
1861     lyx = [env.subst('$BUILDDIR/${PROGPREFIX}lyx$PROGSUFFIX')]
1862
1863
1864 if build_msvs_projects:
1865     def build_project(target, full_target = None,
1866         src = [], inc = [], res = [], rebuildTargetOnly = True):
1867         ''' build mavs project files
1868             target:      alias (correspond to directory name)
1869             full_target: full path/filename of the target
1870             src:         source files
1871             inc:         include files
1872             res:         resource files
1873             rebuildTargetOnly:     whether or not only rebuild this target
1874
1875         For non-debug-able targets like static libraries, target (alias) is
1876         enough to build the target. For executable targets, msvs need to know
1877         the full path to start debug them.
1878         '''
1879         if rebuildTargetOnly:
1880             cmds = 'rebuild='+target
1881         else:
1882             cmds = ''
1883         if full_target is None:
1884             build_target = target
1885         else:
1886             build_target = full_target
1887         # project
1888         proj = env.MSVSProject(
1889             target = target + env['MSVSPROJECTSUFFIX'],
1890             # this allows easy access to header files (along with source)
1891             srcs = [env.subst(x) for x in src + inc],
1892             incs = [env.subst('$TOP_SRCDIR/src/config.h')],
1893             localincs = [env.subst(x) for x in inc],
1894             resources = [env.subst(x) for x in res],
1895             buildtarget = build_target,
1896             cmdargs = cmds,
1897             variant = 'Debug'
1898         )
1899         Alias('msvs_projects', proj)
1900     #
1901     boost_src = []
1902     for lib in boost_libs:
1903         boost_src += ['$TOP_SRCDIR/boost/libs/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1904     build_project('boost', src = boost_src)
1905     #
1906     build_project('intl', src = ['$TOP_SRCDIR/intl/%s' % x for x in intl_files], 
1907         inc = ['$TOP_SRCDIR/intl/%s' % x for x in intl_header_files])
1908     #
1909     build_project('support', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1910         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1911     #
1912     build_project('mathed', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1913         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1914     #
1915     build_project('insets', src = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files], 
1916         inc = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files])
1917     #
1918     build_project('frontends', src = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files], 
1919         inc = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files])
1920     #
1921     build_project('graphics', src = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files], 
1922         inc = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files])
1923     #
1924     build_project('controllers', src = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files], 
1925         inc = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files])
1926     #
1927     build_project('qt4', src = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1928         inc = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1929         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files])
1930     #
1931     build_project('client', src = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_files],
1932         inc = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files],
1933         rebuildTargetOnly = False,
1934         full_target = File(env.subst('$BUILDDIR/common/client/lyxclient$PROGSUFFIX')).abspath)
1935     #
1936     build_project('tex2lyx', src = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files],
1937         inc = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files],
1938         rebuildTargetOnly = False,
1939         full_target = File(env.subst('$BUILDDIR/common/tex2lyx/tex2lyx$PROGSUFFIX')).abspath)
1940     #
1941     build_project('lyxbase', src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files],
1942         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files])
1943     build_project('lyx', 
1944         src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files] + \
1945             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files] + \
1946             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_files] + \
1947             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files] + \
1948             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files] + \
1949             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files] + \
1950             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files] + \
1951             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1952         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files] + \
1953             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files] + \
1954             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files] + \
1955             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files] + \
1956             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files] + \
1957             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files] + \
1958             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files] + \
1959             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1960         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1961         rebuildTargetOnly = False,
1962         full_target = File(env.subst('$BUILDDIR/lyx$PROGSUFFIX')).abspath)
1963
1964
1965 if build_po:
1966     #
1967     # po/
1968     #
1969     print 'Processing files in po...'
1970
1971     import glob
1972     # handle po files
1973     #
1974     # files to translate
1975     transfiles = glob.glob(os.path.join(env.subst('$TOP_SRCDIR'), 'po', '*.po'))
1976     # possibly *only* handle these languages
1977     languages = None
1978     if env.has_key('languages'):
1979         languages = env.make_list(env['lanauges'])
1980     # use defulat msgfmt
1981     gmo_files = []
1982     if not env['MSGFMT']:
1983         print 'msgfmt does not exist. Can not process po files'
1984     else:
1985         # create a builder
1986         env['BUILDERS']['Transfiles'] = Builder(action='$MSGFMT $SOURCE -o $TARGET',suffix='.gmo',src_suffix='.po')
1987         #
1988         for f in transfiles:
1989             # get filename
1990             fname = os.path.split(f)[1]
1991             # country code
1992             country = fname.split('.')[0]
1993             #
1994             if not languages or country in languages:
1995                 gmo_files.extend(env.Transfiles(f))
1996
1997
1998 if 'install' in targets:
1999     #
2000     # this part is a bit messy right now. Since scons will provide
2001     # --DESTDIR option soon, at least the dest_dir handling can be 
2002     # removed later.
2003     #
2004     # how to join dest_dir and prefix
2005     def joinPaths(path1, path2):
2006         ''' join path1 and path2, do not use os.path.join because
2007             under window, c:\destdir\d:\program is invalid '''
2008         if path1 == '':
2009             return os.path.normpath(path2)
2010         # separate drive letter
2011         (drive, path) = os.path.splitdrive(os.path.normpath(path2))
2012         # ignore drive letter, so c:\destdir + c:\program = c:\destdir\program
2013         return os.path.join(os.path.normpath(path1), path[1:])
2014     #
2015     # install to dest_dir/prefix
2016     dest_dir = env.get('DESTDIR', '')
2017     dest_prefix_dir = joinPaths(dest_dir, env.Dir(prefix).abspath)
2018     # create the directory if needed
2019     if not os.path.isdir(dest_prefix_dir):
2020         try:
2021             os.makedirs(dest_prefix_dir)
2022         except:
2023             pass
2024         if not os.path.isdir(dest_prefix_dir):
2025             print 'Can not create directory', dest_prefix_dir
2026             Exit(3)
2027     #
2028     if env.has_key('exec_prefix'):
2029         bin_dest_dir = joinPaths(dest_dir, Dir(env['exec_prefix']).abspath)
2030     else:
2031         bin_dest_dir = os.path.join(dest_prefix_dir, 'bin')
2032     if add_suffix:
2033         share_dest_dir = os.path.join(dest_prefix_dir, share_dir + program_suffix)
2034     else:
2035         share_dest_dir = os.path.join(dest_prefix_dir, share_dir)
2036     man_dest_dir = os.path.join(dest_prefix_dir, man_dir)
2037     locale_dest_dir = os.path.join(dest_prefix_dir, locale_dir)
2038     #
2039     import glob
2040     #
2041     # install executables (lyxclient may be None)
2042     #
2043     if add_suffix:
2044         version_suffix = program_suffix
2045     else:
2046         version_suffix = ''
2047     #
2048     # install lyx, if in release mode, try to strip the binary
2049     if env.has_key('STRIP') and env['STRIP'] is not None and mode != 'debug':
2050         # create a builder to strip and install
2051         env['BUILDERS']['StripInstallAs'] = Builder(action='$STRIP $SOURCE -o $TARGET')
2052
2053     # install executables
2054     for (name, obj) in (('lyx', lyx), ('tex2lyx', tex2lyx), ('client', client)):
2055         if obj is None:
2056             continue
2057         target_name = os.path.split(str(obj[0]))[1].replace(name, '%s%s' % (name, version_suffix))
2058         target = os.path.join(bin_dest_dir, target_name)
2059         if env['BUILDERS'].has_key('StripInstallAs'):
2060             env.StripInstallAs(target, obj)
2061         else:
2062             env.InstallAs(target, obj)
2063         Alias('install', target)
2064
2065     # share/lyx
2066     dirs = []
2067     for (dir,files) in [
2068             ('.', lib_files),  
2069             ('clipart', lib_clipart_files),
2070             ('examples', lib_examples_files),
2071             ('images', lib_images_files),
2072             ('images/math', lib_images_math_files),
2073             ('bind', lib_bind_files),
2074             ('kbd', lib_kbd_files),
2075             ('layouts', lib_layouts_files),
2076             ('scripts', lib_scripts_files),
2077             ('templates', lib_templates_files),
2078             ('tex', lib_tex_files),
2079             ('ui', lib_ui_files),
2080             ('doc', lib_doc_files),
2081             ('lyx2lyx', lib_lyx2lyx_files)]:
2082         dirs.append(env.Install(os.path.join(share_dest_dir, dir),
2083             [env.subst('$TOP_SRCDIR/lib/%s/%s' % (dir, file)) for file in files]))
2084     Alias('install', dirs)
2085     
2086     if platform_name == 'cygwin':
2087         # cygwin packaging requires a file /usr/share/doc/Cygwin/foot-vendor-suffix.README
2088         Cygwin_README = os.path.join(dest_prefix_dir, 'share', 'doc', 'Cygwin', 
2089             '%s-%s.README' % (package, package_cygwin_version))
2090         env.InstallAs(Cygwin_README,
2091             os.path.join(env.subst('$TOP_SRCDIR'), 'README.cygwin'))
2092         Alias('install', Cygwin_README)
2093         # also a directory /usr/share/doc/lyx for README etc
2094         Cygwin_Doc = os.path.join(dest_prefix_dir, 'share', 'doc', package)
2095         env.Install(Cygwin_Doc, [os.path.join(env.subst('$TOP_SRCDIR'), x) for x in \
2096             ['INSTALL', 'README', 'README.Cygwin', 'RELEASE-NOTES', 'COPYING', 'ANNOUNCE']])
2097         Alias('install', Cygwin_Doc)
2098         # cygwin fonts also need to be installed
2099         Cygwin_fonts = os.path.join(share_dest_dir, 'fonts')
2100         env.Install(Cygwin_fonts, 
2101             [env.subst('$TOP_SRCDIR/development/Win32/packaging/bakoma/%s' % file) \
2102                   for file in win32_bakoma_fonts])
2103         Alias('install', Cygwin_fonts)
2104         # we also need a post installation script
2105         tmp_script = utils.installCygwinPostinstallScript('/tmp')
2106         postinstall_path = os.path.join(dest_dir, 'etc', 'postinstall')
2107         env.Install(postinstall_path, tmp_script)
2108         Alias('install', postinstall_path)
2109
2110     # subst and install lyx2lyx_version.py which is not in scons_manifest.py
2111     env.Depends(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py', '$BUILDDIR/common/config.h')
2112     env.substFile(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py',
2113         '$TOP_SRCDIR/lib/lyx2lyx/lyx2lyx_version.py.in')
2114     Alias('install', share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2115
2116     # man
2117     env.InstallAs(os.path.join(man_dest_dir, 'lyx' + version_suffix + '.1'),
2118         env.subst('$TOP_SRCDIR/lyx.man'))
2119     env.InstallAs(os.path.join(man_dest_dir, 'tex2lyx' + version_suffix + '.1'),
2120         env.subst('$TOP_SRCDIR/src/tex2lyx/tex2lyx.man'))
2121     env.InstallAs(os.path.join(man_dest_dir, 'lyxclient' + version_suffix + '.1'),
2122         env.subst('$TOP_SRCDIR/src/client/lyxclient.man'))
2123     Alias('install', [os.path.join(man_dest_dir, x + version_suffix + '.1') for
2124         x in ['lyx', 'tex2lyx', 'lyxclient']])
2125     # locale files?
2126     # ru.gmo ==> ru/LC_MESSAGES/lyxSUFFIX.mo
2127     for gmo in gmo_files:
2128         lan = os.path.split(str(gmo))[1].split('.')[0]
2129         dest_file = os.path.join(locale_dest_dir, lan, 'LC_MESSAGES', 'lyx' + program_suffix + '.mo')
2130         env.InstallAs(dest_file, gmo)
2131         Alias('install', dest_file)
2132
2133
2134 Default('lyx')
2135 Alias('all', ['lyx', 'client', 'tex2lyx'])