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