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