]> git.lyx.org Git - lyx.git/blob - development/scons/SConstruct
09d5e169d7de121808b4cf864edbbd33146f6d7b
[lyx.git] / development / scons / SConstruct
1 # vi:filetype=python:expandtab:tabstop=2:shiftwidth=2
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 #
12 # This is a scons based building system for lyx, you can use it as follows:
13 #
14 #   $ cd development/scons
15 #   $ scons [options] [targets]
16 # or:
17 #   $ scons -f development/scons/SConstruct [options] [targets]
18 # and:
19 #   $ scons [prefix=.] install
20 #
21 # Where:
22 #   * targets can be one or more of lyx, tex2lyx, client, po, install.
23 #     default to lyx, you can use 'scons all' to build all targets except 
24 #     for install
25 #   * options: use scons -h for details about options, the most important
26 #     one is frontend=qt3|qt4.
27 #     - qt3 is used by default on linux, cygwin and mac
28 #     - qt4 is used by default on win32/mingw
29 #
30 # File layouts (Important):
31 #   * Unless you specify builddir=dir, building will happen
32 #     in $BUILDDIR = $mode, which can be debug or release
33 #   * $BUILDDIR has subdirectories
34 #       libs:      all intermediate libraries
35 #       boost:     boost libraries, if boost=included is used
36 #       qt3/4:     frontend-specific objects
37 #   * executables will be copied to $BUILDDIR/
38 #
39 # Hints:
40 #   * scons fast_start=yes
41 #     If env.cache exists, bypass all tests and use existing src/config.h
42 #
43 #   * scons --config=force
44 #     force re-configuration (use scons -H for details)
45 #
46 #   * check config.log to see why config has failed
47 #
48 #   * use extra_inc_path, extra_lib_path, qt_dir, qt_inc_path
49 #     qt_lib_path to help locate qt and other libraries.
50 #     There are also extra_inc_path1, extra_lib_path1 if you need to spacify
51 #     more than one extra paths.
52 #
53 #   * executed commands will be logged in scons_lyx.log. You can use logfile=
54 #     option to save log to another file.
55 #
56 # Notes:
57 #
58 #   * scons dist etc may be added later. Interested contributors can follow
59 #       http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/AccumulateBuilder
60 #     or
61 #       http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/DistTarBuilder
62 #     Please also see the commented out code in scons_utils.py
63 #   
64 #   * NSIS support can be found here.
65 #     http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
66 #
67 #   * rpm support?
68 #     http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/RpmHonchoTemp
69 #
70 #   However, I decide to wait since scons seems to be standardizing these
71 #   features.
72 #
73
74 import os, sys, copy, cPickle
75
76 # config/scons_utils.py defines a few utility function
77 sys.path.append('config')
78 import scons_utils as utils
79
80 #----------------------------------------------------------
81 # Required runtime environment
82 #----------------------------------------------------------
83
84 # FIXME: I remember lyx requires higher version of python?
85 EnsurePythonVersion(1, 5)
86 # Please use at least 0.96.91 (not 0.96.1)
87 EnsureSConsVersion(0, 96)
88
89 # determine where I am ...
90 #
91 # called as 'scons -f development/scons/SConstruct'
92 if os.path.isfile('SConstruct'):
93   TOP_SRC_DIR = '../..'
94   SCONS_DIR = '.'
95 # called as 'cd development/scons; scons'
96 else:
97   TOP_SRC_DIR = '.'
98   SCONS_DIR = 'development/scons'
99
100 #----------------------------------------------------------
101 # Global definitions
102 #----------------------------------------------------------
103
104 # some global settings
105 PACKAGE_VERSION = '1.5.0svn'
106 DEVEL_VERSION = True
107 default_build_mode = 'debug'
108
109 PACKAGE = 'lyx'
110 PACKAGE_BUGREPORT = 'lyx-devel@lists.lyx.org'
111 PACKAGE_NAME = 'LyX'
112 PACKAGE_TARNAME = 'lyx'
113 PACKAGE_STRING = '%s %s' % (PACKAGE_NAME, PACKAGE_VERSION)
114
115 # various cache/log files
116 default_log_file = 'scons_lyx.log'
117 env_cache_file = 'env.cache'
118
119
120 #----------------------------------------------------------
121 # platform dependent settings
122 #----------------------------------------------------------
123 if os.name == 'nt':
124   platform_name = 'win32'
125   default_frontend = 'qt4'
126   # boost and gettext are unlikely to be installed already
127   default_boost_opt = 'included'
128   default_gettext_opt = 'included'
129   default_pch_opt = False
130   default_with_x = False
131   spell_checker = 'auto'
132   # boost_posix indicates to boost which API to use (posix or windows).
133   # If not specified, boost tries to figure out by itself, but it may fail.
134   boost_posix = False
135   packaging_method = 'windows'
136   add_suffix_to_executables = False
137   default_prefix = 'c:/program files/lyx'
138   share_dir = 'Resources'
139   man_dir = 'Resources/man/man1'
140   locale_dir = 'Resources/locale'
141 elif os.name == 'posix' and sys.platform != 'cygwin':
142   platform_name = sys.platform
143   default_frontend = 'qt3'
144   # try to use system boost/gettext libraries
145   default_boost_opt = 'auto'
146   default_gettext_opt = 'auto'
147   default_pch_opt = False
148   default_with_x = True
149   boost_posix = True
150   packaging_method = 'posix'
151   add_suffix_to_executables = True
152   default_prefix = '/usr/local/'
153   share_dir = 'share/lyx'
154   man_dir = 'man/man1'
155   locale_dir = 'share/locale'
156 elif os.name == 'posix' and sys.platform == 'cygwin':
157   platform_name = 'cygwin'
158   default_frontend = 'qt3'
159   # force the use of cygwin/boost/gettext
160   default_boost_opt = 'system'
161   default_gettext_opt = 'system'
162   default_pch_opt = False
163   default_with_x = True
164   boost_posix = True
165   packaging_method = 'posix'
166   add_suffix_to_executables = True
167   default_prefix = '/usr/local/'
168   share_dir = 'share/lyx'
169   man_dir = 'man/man1'
170   locale_dir = 'share/locale'
171 elif os.name == 'darwin':
172   platform_name = 'mac'
173   default_frontend = 'qt3'
174   # to be safe
175   default_boost_opt = 'included'
176   default_gettext_opt = 'included'
177   default_pch_opt = False
178   default_with_x = False
179   boost_posix = True
180   packaging_method = 'mac'
181   add_suffix_to_executables = True
182   # FIXME: where to install?
183   default_prefix = '/usr/local/'
184   share_dir = 'Resources'
185   man_dir = 'Resources/man/man1'
186   locale_dir = 'Resources/locale'
187 else:  # unsupported system
188   platform_name = 'others'
189   default_frontend = 'qt3'
190   # to be safe
191   default_boost_opt = 'included'
192   default_gettext_opt = 'included'
193   default_pch_opt = False
194   default_with_x = True
195   boost_posix = False
196   packaging_method = 'posix'
197   add_suffix_to_executables = True
198   default_prefix = '/usr/local/'
199   share_dir = 'share/lyx'
200   man_dir = 'man/man1'
201   locale_dir = 'share/locale'
202
203
204 #---------------------------------------------------------
205 # Handling options
206 #----------------------------------------------------------
207 #
208 if os.path.isfile('config.py'):
209   print "Getting options from config.py..."
210   print open('config.py').read()
211
212 opts = Options(['config.py'])
213 opts.AddOptions(
214   # frontend,
215   EnumOption('frontend', 'Main GUI', default_frontend,
216     allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ),
217   # debug or release build
218   EnumOption('mode', 'Building method', default_build_mode,
219     allowed_values = ('debug', 'release') ),
220   # boost libraries
221   EnumOption('boost',
222     'Use included, system boost library, or try sytem boost first.',
223     default_boost_opt,
224     allowed_values = (
225       'auto',       # detect boost, if not found, use included
226       'included',   # always use included boost
227       'system',     # always use system boost, fail if can not find
228       ) ),
229   # FIXME: not implemented yet.
230   EnumOption('gettext',
231     'Use included, system gettext library, or try sytem gettext first',
232     default_gettext_opt,
233     allowed_values = (
234       'auto',       # detect gettext, if not found, use included
235       'included',   # always use included gettext
236       'system',     # always use system gettext, fail if can not find
237       ) ),
238   #
239   EnumOption('spell', 'Choose spell checker to use.', 'auto',
240     allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
241   #
242   BoolOption('fast_start', 'Whether or not use cached tests and keep current config.h', True),
243   # FIXME: I do not know how pch is working. Ignore this option now.
244   BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
245   # enable assertion, (config.h has ENABLE_ASSERTIOS
246   BoolOption('assertions', 'Use assertions', True),
247   # enable warning, (config.h has WITH_WARNINGS)
248   BoolOption('warnings', 'Use warnings', True),
249   # enable glib, (config.h has _GLIBCXX_CONCEPT_CHECKS)
250   BoolOption('concept_checks', 'Enable concept checks', True),
251   # 
252   BoolOption('nls', 'Whether or not use native language support', True),
253   # FIXME: not implemented
254   BoolOption('profile', '(NA) Whether or not enable profiling', False),
255   # FIXME: not implemented
256   BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
257   # using x11?
258   BoolOption('X11', 'Use x11 windows system', default_with_x),
259   # 
260   PathOption('qt_dir', 'Path to qt directory', None),
261   #
262   PathOption('qt_include_path', 'Path to qt include directory', None),
263   #
264   PathOption('qt_lib_path', 'Path to qt library directory', None),
265   # build directory, will use $mode if not set
266   PathOption('build_dir', 'Build directory', None),
267   # extra include and libpath
268   PathOption('extra_inc_path', 'Extra include path', None),
269   #
270   PathOption('extra_lib_path', 'Extra library path', None),
271   #
272   PathOption('extra_inc_path1', 'Extra include path', None),
273   #
274   PathOption('extra_lib_path1', 'Extra library path', None),
275   # can be set to a non-existing directory
276   ('prefix', 'install architecture-independent files in PREFIX', None),
277   # version suffix
278   ('version_suffix', 'install lyx as lyx-suffix', ''),
279   #
280   PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
281   # log file
282   ('logfile', 'save commands (not outputs) to logfile', default_log_file),
283   # Path to aikasurus
284   PathOption('aikasurus_path', 'Path to aikasurus library', None),
285   # environment variable can be set as options. (DO NOT set defaults)
286   ('CC', '$CC', None),
287   ('LINK', '$LINK', None),
288   ('CPP', '$CPP', None),
289   ('CXX', '$CXX', None),
290   ('CXXCPP', '$CXXCPP', None),
291   ('CCFLAGS', '$CCFLAGS', None),
292   ('CPPFLAGS', '$CPPFLAGS', None),
293   ('LDFLAGS', '$LDFLAGS', None),
294 )
295
296
297 #---------------------------------------------------------
298 # Setting up environment
299 #---------------------------------------------------------
300
301 env = Environment(options = opts)
302
303 # Determine the frontend to use, which may be loaded
304 # from option cache
305 frontend = env.get('frontend', default_frontend)
306 # make sure the key exists
307 env['frontend'] = frontend
308 #
309 use_X11 = env.get('X11', default_with_x)
310
311 # whether or not use current config.h, and cached tests
312 if env['fast_start'] and os.path.isfile(env_cache_file):
313   fast_start = True
314   SetOption('implicit_cache', 1)
315   cache_file = open(env_cache_file)
316   env_cache = cPickle.load(cache_file)
317   cache_file.close()
318   print '------------ fast_start mode --------------------'
319   print '  Use cached test results and current config.h'
320   print '  use fast_start=no to override'
321   print '-------------------------------------------------'
322 else:
323   fast_start = False
324   SetOption('implicit_cache', 0)
325   env_cache = {}
326
327 # set individual variables since I do not really like ENV = os.environ
328 env['ENV']['PATH'] = os.environ.get('PATH')
329 env['ENV']['HOME'] = os.environ.get('HOME')
330 env['TOP_SRC_DIR'] = TOP_SRC_DIR
331 env['SCONS_DIR'] = SCONS_DIR
332 # install to default_prefix by default
333 env['PREFIX'] = env.get('prefix', default_prefix)
334 if env.has_key('exec_prefix'):
335   env['BIN_DIR'] = env['exec_prefix']
336 else:
337   env['BIN_DIR'] = os.path.join(env['PREFIX'], 'bin')
338 # program suffix
339 if env.has_key('version_suffix'):
340   env['PROGRAM_SUFFIX'] = env['version_suffix']
341 else:
342   env['PROGRAM_SUFFIX'] = ''
343 env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables
344 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX'])
345 env['MAN_DIR'] = os.path.join(env['PREFIX'], man_dir)
346 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
347
348 #
349 # this is a bit out of place (after auto-configration) but 
350 # it is required to do the tests. Since Tool('mingw') will 
351 # reset CCFLAGS etc, this should be before getEnvVariable
352 if platform_name == 'win32':
353   env.Tool('mingw')
354   env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
355
356
357 # speed up source file processing
358 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
359 #env['CXXSUFFIX'] = ['.C']
360
361 def getEnvVariable(env, name):
362   # first try command line argument (override environment settings)
363   if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
364     env[name] = ARGUMENTS[name]
365   # then use environment default
366   elif os.environ.has_key(name) and os.environ[name].strip() != '':
367     env[name] = os.environ[name]
368     print "Acquiring varaible %s from system environment: %s" % (name, env[name])
369   # finally, env['CC'] etc is set to the default values of Options.
370   # and env['CPP'] etc does not exist
371
372 getEnvVariable(env, 'CC')
373 getEnvVariable(env, 'LINK')
374 getEnvVariable(env, 'CPP')
375 getEnvVariable(env, 'CXX')
376 getEnvVariable(env, 'CXXCPP')
377 getEnvVariable(env, 'CCFLAGS')
378 getEnvVariable(env, 'CXXFLAGS')
379 getEnvVariable(env, 'CPPFLAGS')
380 getEnvVariable(env, 'LDFLAGS')
381
382
383 #
384 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
385 #
386 env['mode'] = env.get('mode', default_build_mode)
387 # lyx will be built to $build/build_dir so it is possible
388 # to build multiple build_dirs using the same source
389 # $mode can be debug or release
390 if env.has_key('build_dir') and env['build_dir']:
391   build_dir = env['build_dir']
392   env['BUILDDIR'] = build_dir
393 else:
394   # Determine the name of the build $mode
395   env['BUILDDIR'] = '#' + env['mode']
396 # all built libraries will go to build_dir/libs
397 # (This is different from the make file approach)
398 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
399 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
400
401 #
402 # QTDIR, QT_LIB_PATH, QT_INC_PATH
403 #
404 if env.has_key('qt_dir') and env['qt_dir']:
405   env['QTDIR'] = env['qt_dir']
406   # add path to the qt tools
407   env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
408   # set environment so that moc etc can be found even if its path is not set properly
409   env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
410 else:
411   env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
412
413 if env.has_key('qt_lib_path') and env['qt_lib_path']:
414   env['QT_LIB_PATH'] = env['qt_lib_path']
415 else:
416   env['QT_LIB_PATH'] = '$QTDIR/lib'
417 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
418 # qt4 seems to be using pkg_config
419 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
420
421 if env.has_key('qt_inc_path') and env['qt_inc_path']:
422   env['QT_INC_PATH'] = env['qt_inc_path']
423 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
424   env['QT_INC_PATH'] = '$QTDIR/include'
425 else: # have to guess
426   env['QT_INC_PATH'] = '/usr/include/$frontend/'
427 # Note that this CPPPATH is for testing only
428 # it will be removed before calling SConscript
429 env['CPPPATH'] = [env['QT_INC_PATH']]
430
431 #
432 # extra_inc_path and extra_lib_path
433 #
434 if env.has_key('extra_inc_path') and env['extra_inc_path']:
435   env.AppendUnique(CPPPATH = [env['extra_inc_path']])
436 if env.has_key('extra_lib_path') and env['extra_lib_path']:
437   env.AppendUnique(LIBPATH = [env['extra_lib_path']])
438 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
439   env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
440 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
441   env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
442 if env.has_key('aikasurus_path') and env['aikasurus_path']:
443   env.AppendUnique(LIBPATH = [env['aikasurus_path']])
444
445
446 # under windows, scons is confused by .C/.c and uses gcc instead of
447 # g++. I am forcing the use of g++ here. This is expected to change
448 # after lyx renames all .C files to .cpp
449 #
450 # Note that this step has to be after env.Tool('mingw') step
451 # since env.Tool('mingw') will set env['CC'] etc.
452 #
453 # save the old c compiler
454 env['C_COMPILER'] = env['CC']
455 if env.has_key('CXX') and env['CXX']:
456   env['CC'] = env['CXX']
457   env['LINK'] = env['CXX']
458 else:
459   env['CC'] = 'g++'
460   env['LINK'] = 'g++'
461
462
463 #----------------------------------------------------------
464 # Autoconf business
465 #----------------------------------------------------------
466
467 conf = Configure(env,
468   custom_tests = {
469     'CheckPkgConfig' : utils.checkPkgConfig,
470     'CheckPackage' : utils.checkPackage,
471     'CheckMkdirOneArg' : utils.checkMkdirOneArg,
472     'CheckSelectArgType' : utils.checkSelectArgType,
473     'CheckBoostLibraries' : utils.checkBoostLibraries,
474     'CheckCommand' : utils.checkCommand,
475   }
476 )
477
478 # pkg-config? (if not, we use hard-coded options)
479 if not fast_start:
480   if conf.CheckPkgConfig('0.15.0'):
481     env['HAS_PKG_CONFIG'] = True
482   else:
483     print 'pkg-config >= 0.1.50 is not found'
484     env['HAS_PKG_CONFIG'] = False
485   env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG']
486 else:
487   env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG']
488
489 # zlib? This is required. (fast_start assumes the existance of zlib)
490 if not fast_start and not conf.CheckLibWithHeader('z', 'zlib.h', 'C'):
491     print 'Did not find libz or zlib.h, exiting!'
492     Exit(1)
493
494 # qt libraries?
495 if not fast_start:
496   #
497   # qt3 does not use pkg_config
498   if frontend == 'qt3':
499     if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
500       print 'Did not find qt libraries, exiting!'
501       Exit(1)
502   elif frontend == 'qt4':
503     succ = False
504     # first: try pkg_config
505     if env['HAS_PKG_CONFIG']:
506       succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
507       env['QT4_PKG_CONFIG'] = succ
508     # second: try to link to it
509     if not succ:
510       # FIXME: under linux, I can test the following perfectly
511       # However, under windows, lib names need to passed as libXXX4.a ...
512       succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
513         conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
514     # third: try to look up the path
515     if not succ:
516       succ = True
517       for lib in ['QtCore', 'QtGui']:
518         # windows version has something like QtGui4 ...
519         if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
520           os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
521           succ = False
522           break
523     # still can not find it
524     if succ:
525       print "Qt4 libraries are found."
526     else:
527       print 'Did not find qt libraries, exiting!'
528       Exit(1)
529
530
531 # check socket libs
532 if not fast_start:
533   env['SOCKET_LIBS'] = []
534   if conf.CheckLib('socket'):
535     env['SOCKET_LIBS'].append('socket')
536
537   # nsl is the network services library and provides a
538   # transport-level interface to networking services.
539   if conf.CheckLib('nsl'):
540     env['SOCKET_LIBS'].append('nsl')
541
542   env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
543 else:
544   env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
545
546 if not fast_start:
547   # check boost libraries
548   boost_opt = ARGUMENTS.get('boost', default_boost_opt)
549   # check for system boost
550   succ = False
551   if boost_opt in ['auto', 'system']:
552     pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
553     sig = conf.CheckBoostLibraries('boost_signals', pathes)
554     reg = conf.CheckBoostLibraries('boost_regex', pathes)
555     fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
556     ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
557     # if any of them is not found
558     if ('' in [sig[0], reg[0], fil[0], ios[0]]):
559       if boost_opt == 'system':
560         print "Can not find system boost libraries"
561         print "Please supply a path through extra_lib_path and try again."
562         print "Or use boost=included to use included boost libraries."
563         Exit(2)
564     else:
565       env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
566       # assume all boost libraries are in the same path...
567       env.AppendUnique(LIBPATH = [sig[0]])
568       env['INCLUDED_BOOST'] = False
569       succ = True
570   # now, auto and succ = false, or boost=included
571   if not succ:
572     # we do not need to set LIBPATH now.
573     env['BOOST_LIBRARIES'] = ['boost_signals', 'boost_regex',
574       'boost_filesystem', 'boost_iostreams']
575     env['INCLUDED_BOOST'] = True
576   env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
577   env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
578 else:
579   env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
580   env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
581
582
583 if not env.has_key('nls') or env['nls']:
584   env['ENABLE_NLS'] = True
585
586 if not fast_start:
587   if not env['ENABLE_NLS']:
588     env['INTL_LIB'] = []
589     env['INCLUDED_GETTEXT'] = False
590   else:
591     # check gettext libraries
592     gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt)
593     # check for system gettext
594     succ = False
595     if gettext_opt in ['auto', 'system']:
596       if conf.CheckLib('intl'):
597         env['INCLUDED_GETTEXT'] = False
598         succ = True
599       else: # no found
600         if gettext_opt == 'system':
601           print "Can not find system gettext library"
602           print "Please supply a path through extra_lib_path and try again."
603           print "Or use gettext=included to use included gettext libraries."
604           Exit(2)
605     # now, auto and succ = false, or gettext=included
606     if not succ:
607       # we do not need to set LIBPATH now.
608       env['INCLUDED_GETTEXT'] = True
609     env['INTL_LIB'] = ['intl']
610   env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT']
611   env_cache['INTL_LIB'] = env['INTL_LIB']
612 else:
613   env['INTL_LIB'] = env_cache['INTL_LIB']
614   env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT']
615
616 #
617 # check for msgfmt command
618 if not fast_start:
619   env['MSGFMT'] = conf.CheckCommand('msgfmt')
620   env_cache['MSGFMT'] = env['MSGFMT']
621 else:
622   env['MSGFMT'] = env_cache['MSGFMT']
623
624
625 #----------------------------------------------------------
626 # Generating config.h
627 #----------------------------------------------------------
628 if not fast_start:
629   print "Generating ", utils.config_h, "..."
630
631   # I do not handle all macros in src/config.h.in, rather I am following a list
632   # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
633   #
634   # Note: addToConfig etc are defined in scons_util
635   utils.startConfigH(TOP_SRC_DIR)
636
637   # HAVE_IO_H
638   # HAVE_LIMITS_H
639   # HAVE_LOCALE_H
640   # HAVE_LOCALE
641   # HAVE_PROCESS_H
642   # HAVE_STDLIB_H
643   # HAVE_SYS_STAT_H
644   # HAVE_SYS_TIME_H
645   # HAVE_SYS_TYPES_H
646   # HAVE_SYS_UTIME_H
647   # HAVE_UNISTD_H
648   # HAVE_UTIME_H
649   # HAVE_ISTREAM
650   # HAVE_OSTREAM
651   # HAVE_IOS
652
653   # Check header files
654   headers = [
655     ('io.h', 'HAVE_IO_H', 'c'),
656     ('limits.h', 'HAVE_LIMITS_H', 'c'),
657     ('locale.h', 'HAVE_LOCALE_H', 'c'),
658     ('locale', 'HAVE_LOCALE', 'cxx'),
659     ('process.h', 'HAVE_PROCESS_H', 'c'),
660     ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
661     ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
662     ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
663     ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
664     ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
665     ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
666     ('unistd.h', 'HAVE_UNISTD_H', 'c'),
667     ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
668     ('utime.h', 'HAVE_UTIME_H', 'c'),
669     ('istream', 'HAVE_ISTREAM', 'cxx'),
670     ('ostream', 'HAVE_OSTREAM', 'cxx'),
671     ('ios', 'HAVE_IOS', 'cxx')
672   ]
673
674   for header in headers:
675     if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
676       (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
677       utils.addToConfig('#define %s 1' % header[1], TOP_SRC_DIR)
678     else:
679       utils.addToConfig('/* #undef %s */' % header[1], TOP_SRC_DIR)
680
681   # HAVE_OPEN
682   # HAVE_CLOSE
683   # HAVE_POPEN
684   # HAVE_PCLOSE
685   # HAVE__OPEN
686   # HAVE__CLOSE
687   # HAVE__POPEN
688   # HAVE__PCLOSE
689   # HAVE_GETPID
690   # HAVE__GETPID
691   # HAVE_MKDIR
692   # HAVE__MKDIR
693   # HAVE_PUTENV
694   # HAVE_MKTEMP
695   # HAVE_MKSTEMP
696   # HAVE_STRERROR
697   # HAVE_STD_COUNT
698
699   # Check functions
700   functions = [
701     ('open', 'HAVE_OPEN', None),
702     ('close', 'HAVE_CLOSE', None),
703     ('popen', 'HAVE_POPEN', None),
704     ('pclose', 'HAVE_PCLOSE', None),
705     ('_open', 'HAVE__OPEN', None),
706     ('_close', 'HAVE__CLOSE', None),
707     ('_popen', 'HAVE__POPEN', None),
708     ('_pclose', 'HAVE__PCLOSE', None),
709     ('getpid', 'HAVE_GETPID', None),
710     ('_getpid', 'HAVE__GETPID', None),
711     ('mkdir', 'HAVE_MKDIR', None),
712     ('_mkdir', 'HAVE__MKDIR', None),
713     ('putenv', 'HAVE_PUTENV', None),
714     ('mktemp', 'HAVE_MKTEMP', None),
715     ('mkstemp', 'HAVE_MKSTEMP', None),
716     ('strerror', 'HAVE_STRERROR', None),
717     ('count', 'HAVE_STD_COUNT', '''
718 #include <algorithm>
719 int count()
720 {
721   char a[] = "hello";
722   return std::count(a, a+5, 'l');
723 }
724 ''')
725   ]
726
727   # HAVE_ASPRINTF
728   # HAVE_WPRINTF
729   # HAVE_SNPRINTF
730   # HAVE_POSIX_PRINTF
731   # HAVE_FCNTL
732   
733   for func in functions:
734     if conf.CheckFunc(func[0], header=func[2]):
735       utils.addToConfig('#define %s 1' % func[1], TOP_SRC_DIR)
736     else:
737       utils.addToConfig('/* #undef %s */' % func[1], TOP_SRC_DIR)
738
739   env_functions = [
740     ('asprintf', 'HAVE_ASPRINTF'),
741     ('wprintf', 'HAVE_WPRINTF'),
742     ('snprintf', 'HAVE_SNPRINTF'),
743     ('printf', 'HAVE_POSIX_PRINTF'),
744     ('fcntl', 'HAVE_FCNTL')
745   ]
746
747   for func in env_functions:
748     if conf.CheckFunc(func[0]):
749       utils.addToConfig('#define %s 1' % func[1], TOP_SRC_DIR)
750       env[func[1]] = 1
751     else:
752       utils.addToConfig('/* #undef %s */' % func[1], TOP_SRC_DIR)
753       env[func[1]] = 0
754
755   # HAVE_INTMAX_T
756   # HAVE_INTTYPES_H_WITH_UINTMAX 
757   # HAVE_DECL_ISTREAMBUF_ITERATOR
758   if conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
759     conf.CheckType('intmax_t', includes='#include <inttypes.h>'):
760     utils.addToConfig('#define HAVE_INTMAX_T 1', TOP_SRC_DIR)
761   else:
762     utils.addToConfig('/* #undef HAVE_INTMAX_T */', TOP_SRC_DIR)
763
764   if conf.CheckType('uintmax_t', includes='#include <inttypes.h>'):
765     utils.addToConfig('#define HAVE_INTTYPES_H_WITH_UINTMAX  1', TOP_SRC_DIR)
766   else:
767     utils.addToConfig('/* #undef HAVE_INTTYPES_H_WITH_UINTMAX  */', TOP_SRC_DIR)
768     
769   if conf.CheckType('std::istreambuf_iterator<std::istream>', 
770     includes='#include <streambuf>\n#include <istream>'):
771     utils.addToConfig('#define HAVE_DECL_ISTREAMBUF_ITERATOR 1', TOP_SRC_DIR)
772   else:
773     utils.addToConfig('/* #undef HAVE_DECL_ISTREAMBUF_ITERATOR */', TOP_SRC_DIR)
774       
775   
776   # PACKAGE
777   # PACKAGE_VERSION
778   # DEVEL_VERSION
779   utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX']), TOP_SRC_DIR)
780   utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION, TOP_SRC_DIR)
781   if DEVEL_VERSION:
782     utils.addToConfig('#define DEVEL_VERSION 1', TOP_SRC_DIR)
783
784   # ENABLE_ASSERTIONS
785   # ENABLE_NLS
786   # WITH_WARNINGS
787   # _GLIBCXX_CONCEPT_CHECKS
788
789   # items are (ENV, ARGUMENTS)
790   values = [
791     ('ENABLE_ASSERTIONS', 'assertions'),
792     ('ENABLE_NLS', 'nls'),
793     ('WITH_WARNINGS', 'warnings'),
794     ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
795   ]
796
797   for val in values:
798     if (env.has_key(val[0]) and env[val[0]]) or \
799         ARGUMENTS.get(val[1]):
800       utils.addToConfig('#define %s 1' % val[0], TOP_SRC_DIR)
801     else:
802       utils.addToConfig('/* #undef %s */' % val[0], TOP_SRC_DIR)
803
804
805   env['EXTRA_LIBS'] = []
806   # HAVE_LIBAIKSAURUS
807   # AIKSAURUS_H_LOCATION
808   if conf.CheckLib('Aiksaurus'):
809     utils.addToConfig("#define HAVE_LIBAIKSAURUS 1", TOP_SRC_DIR)
810     if (conf.CheckCXXHeader("Aiksaurus.h")):
811       utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>", TOP_SRC_DIR)
812     elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
813       utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>", TOP_SRC_DIR)
814     else:
815       utils.addToConfig("#define AIKSAURUS_H_LOCATION", TOP_SRC_DIR)
816     env['EXTRA_LIBS'].append('Aiksaurus')
817
818   # USE_ASPELL
819   # USE_PSPELL
820   # USE_ISPELL
821
822   # determine headers to use
823   spell_engine = ARGUMENTS.get('spell', 'auto')
824   spell_detected = False
825   if spell_engine in ['auto', 'aspell'] and \
826     conf.CheckLib('aspell'):
827     utils.addToConfig('#define USE_ASPELL 1', TOP_SRC_DIR)
828     env['USE_ASPELL'] = True
829     env['USE_PSPELL'] = False
830     env['USE_ISPELL'] = False
831     env['EXTRA_LIBS'].append('aspell')
832     spell_detected = True
833   elif spell_engine in ['auto', 'pspell'] and \
834     conf.CheckLib('pspell'):
835     utils.addToConfig('#define USE_PSPELL 1', TOP_SRC_DIR)
836     env['USE_ASPELL'] = False
837     env['USE_PSPELL'] = True
838     env['USE_ISPELL'] = False
839     env['EXTRA_LIBS'].append('pspell')
840     spell_detected = True
841   elif spell_engine in ['auto', 'ispell'] and \
842     conf.CheckLib('ispell'):
843     utils.addToConfig('#define USE_ISPELL 1', TOP_SRC_DIR)
844     env['USE_ASPELL'] = False
845     env['USE_PSPELL'] = False
846     env['USE_ISPELL'] = True
847     env['EXTRA_LIBS'].append('ispell')
848     spell_detected = True
849
850   if not spell_detected:
851     env['USE_ASPELL'] = False
852     env['USE_PSPELL'] = False
853     env['USE_ISPELL'] = False
854     # FIXME: can lyx work without an spell engine
855     if spell_engine == 'auto':
856       print "Warning: Can not locate any spell checker"
857     else:
858       print "Warning: Can not locate specified spell checker:", spell_engine
859
860   # USE_POSIX_PACKAGING
861   # USE_MACOSX_PACKAGING
862   # USE_WINDOWS_PACKAGING
863   if packaging_method == 'windows':
864     utils.addToConfig('#define USE_WINDOWS_PACKAGING 1', TOP_SRC_DIR)
865   elif packaging_method == 'posix':
866     utils.addToConfig('#define USE_POSIX_PACKAGING 1', TOP_SRC_DIR)
867   elif packaging_method == 'mac':
868     utils.addToConfig('#define USE_MACOSX_PACKAGING 1', TOP_SRC_DIR)
869
870   # BOOST_POSIX
871   if boost_posix:
872     utils.addToConfig('#define BOOST_POSIX 1', TOP_SRC_DIR)
873   else:
874     utils.addToConfig('/* #undef BOOST_POSIX */', TOP_SRC_DIR)
875
876   # MKDIR_TAKES_ONE_ARG
877   if conf.CheckMkdirOneArg():
878     utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1', TOP_SRC_DIR)
879   else:
880     utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */', TOP_SRC_DIR)
881
882   # SELECT_TYPE_ARG1
883   # SELECT_TYPE_ARG234
884   # SELECT_TYPE_ARG5
885   (arg1, arg234, arg5) = conf.CheckSelectArgType()
886   utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1, TOP_SRC_DIR)
887   utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234, TOP_SRC_DIR)
888   utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5, TOP_SRC_DIR)
889
890   # mkstemp
891   # USE_BOOST_FORMAT
892   # WANT_GETFILEATTRIBUTESEX_WRAPPER
893   utils.endConfigH(TOP_SRC_DIR)
894
895   # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed
896   # NOTE that we do *not* save qt_libs in environment.
897   env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS'])
898   env_cache['USE_ASPELL'] = env['USE_ASPELL']
899   env_cache['USE_PSPELL'] = env['USE_PSPELL']
900   env_cache['USE_ISPELL'] = env['USE_ISPELL']
901   env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF']
902   env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF']
903   env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF']
904   env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF']
905   env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL']
906
907 else:
908   #
909   # this comes as a big surprise, without this line 
910   # (doing nothing obvious), adding fast_start=yes
911   # to a build with fast_start=no will result in a rebuild
912   # Note that the exact header file to check does not matter
913   conf.CheckCHeader('io.h')
914   # only a few variables need to be rescanned
915   env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
916   env['USE_ASPELL'] = env_cache['USE_ASPELL']
917   env['USE_PSPELL'] = env_cache['USE_PSPELL']
918   env['USE_ISPELL'] = env_cache['USE_ISPELL']
919   env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF']
920   env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF']
921   env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF']
922   env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF']
923   env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL']
924
925 #
926 # Finish auto-configuration
927 env = conf.Finish()
928
929 #----------------------------------------------------------
930 # Now set up our build process accordingly
931 #----------------------------------------------------------
932
933 #
934 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
935 #
936 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
937 # in their respective directory and specialized env.
938 try:
939   if frontend == 'qt3':
940     # note: env.Tool('qt') my set QT_LIB to qt
941     env['QT_LIB'] = 'qt-mt'
942     env['EXTRA_LIBS'].append('qt-mt')
943     if platform_name == 'cygwin' and use_X11:
944       env['EXTRA_LIBS'].extend(['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
945         'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
946         'pthread'])
947       env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
948   elif frontend == 'qt4':
949     if platform_name == "win32":
950       env['QT_LIB'] = ['QtCore4', 'QtGui4']
951     else:
952       env['QT_LIB'] = ['QtCore', 'QtGui']
953     env['EXTRA_LIBS'] += env['QT_LIB']
954 except:
955   print "Can not locate qt tools"
956   print "What I get is "
957   print "  QTDIR: ", env['QTDIR']
958
959
960 if platform_name in ['win32', 'cygwin']:
961   # the final link step needs stdc++ to succeed under mingw
962   # FIXME: shouldn't g++ automatically link to stdc++?
963   env['SYSTEM_LIBS'] = ['shlwapi', 'z', 'stdc++']
964 else:
965   env['SYSTEM_LIBS'] = ['z']
966
967 #
968 # Build parameters CPPPATH etc
969 #
970 # boost is always in, src is needed for config.h
971
972 # QT_INC_PATH is not needed for *every* source file
973 env['CPPPATH'].remove(env['QT_INC_PATH'])
974 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
975
976 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
977 # for debug/release mode
978 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
979   env.AppendUnique(CCFLAGS = [])
980 else:
981   env.AppendUnique(CCFLAGS = [])
982
983 #
984 # Customized builders
985 #
986 # install customized builders
987 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
988
989 #
990 # A Link script for cygwin see
991 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
992 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
993 # for details
994 #
995 if platform_name == 'cygwin':
996   ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
997   ld_script = utils.installCygwinLDScript(ld_script_path)
998   env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
999     '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1000
1001 #
1002 # Report results
1003 #
1004 # src/support/package.C.in needs the following to replace
1005 #  LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
1006 env['LYX_DIR'] = env['SHARE_DIR']
1007 #  LYX_ABS_INSTALLED_LOCALEDIR
1008 env['LOCALEDIR'] = env['LOCALE_DIR']
1009 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
1010 # needed by src/version.C.in => src/version.C
1011 env['PACKAGE_VERSION'] = PACKAGE_VERSION
1012 # fill in the version info
1013 env['VERSION_INFO'] = '''Configuration
1014   Host type:                      %s
1015   Special build flags:            %s
1016   C   Compiler:                   %s
1017   C   Compiler flags:             %s %s
1018   C++ Compiler:                   %s
1019   C++ Compiler LyX flags:         %s
1020   C++ Compiler flags:             %s %s
1021   Linker flags:                   %s
1022   Linker user flags:              %s
1023 Build info:
1024   Builing directory:              %s
1025   Local library directory:        %s
1026   Libraries pathes:               %s
1027   Boost libraries:                %s
1028   Extra libraries:                %s
1029   System libraries:               %s
1030   include search path:            %s
1031 Frontend:
1032   Frontend:                       %s
1033   Packaging:                      %s
1034   LyX dir:                        %s
1035   LyX binary dir:                 %s
1036   LyX files dir:                  %s
1037 ''' % (platform_name,
1038   env.subst('$CCFLAGS'), env.subst('$CC'),
1039   env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1040   env.subst('$CXX'), env.subst('$CXXFLAGS'),
1041   env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1042   env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1043   env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1044   str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
1045   str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
1046   env['frontend'], packaging_method,
1047   env['PREFIX'], env['BIN_DIR'], env['SHARE_DIR'])
1048
1049 if env['frontend'] in ['qt3', 'qt4']:
1050   env['VERSION_INFO'] += '''  include dir:                    %s
1051   library dir:                    %s
1052   X11:                            %s
1053 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
1054
1055 if not fast_start:
1056   print env['VERSION_INFO']
1057
1058 #
1059 # Mingw command line may be too short for our link usage,
1060 # Here we use a trick from scons wiki
1061 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1062 #
1063 # I also would like to add logging (commands only) capacity to the
1064 # spawn system.
1065 logfile = env.get('logfile', default_log_file)
1066 if logfile != '' or platform_name == 'win32':
1067   import time
1068   utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1069     info = '''# This is a log of commands used by scons to build lyx
1070 # Time: %s
1071 # Command: %s
1072 # Info: %s
1073 ''' % (time.asctime(), ' '.join(sys.argv),
1074   env['VERSION_INFO'].replace('\n','\n# ')) )
1075
1076
1077 #
1078 # Cleanup stuff
1079 #
1080 # -h will print out help info
1081 Help(opts.GenerateHelpText(env))
1082 # save environment settings (for fast_start option)
1083 cache_file = open(env_cache_file, 'w')
1084 cPickle.dump(env_cache, cache_file)
1085 cache_file.close()
1086
1087 #----------------------------------------------------------
1088 # Start building
1089 #----------------------------------------------------------
1090 Export('env')
1091
1092 # this has been the source of problems on some platforms...
1093 # I find that I need to supply it with full path name
1094 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1095 # this usage needs further investigation.
1096 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1097
1098 env['BUILD_TARGETS'] = BUILD_TARGETS
1099
1100 print "Building all targets recursively"
1101
1102 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)
1103
1104