]> git.lyx.org Git - features.git/blob - development/scons/SConstruct
scons: fix lyxclient build error handling under windows, extra_inc_path problems.
[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 PROGRAM_SUFFIX = ''
115
116 # various cache/log files
117 default_log_file = 'scons_lyx.log'
118 env_cache_file = 'env.cache'
119
120
121 #----------------------------------------------------------
122 # platform dependent settings
123 #----------------------------------------------------------
124 if os.name == 'nt':
125   platform_name = 'win32'
126   default_frontend = 'qt4'
127   # boost and gettext are unlikely to be installed already
128   default_boost_opt = 'included'
129   default_gettext_opt = 'included'
130   default_pch_opt = False
131   default_with_x = False
132   spell_checker = 'auto'
133   # boost_posix indicates to boost which API to use (posix or windows).
134   # If not specified, boost tries to figure out by itself, but it may fail.
135   boost_posix = False
136   packaging_method = 'windows'
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   default_prefix = '/usr/local/'
152   share_dir = 'share/lyx'
153   man_dir = 'man/man1'
154   locale_dir = 'share/locale'
155 elif os.name == 'posix' and sys.platform == 'cygwin':
156   platform_name = 'cygwin'
157   default_frontend = 'qt3'
158   # force the use of cygwin/boost/gettext
159   default_boost_opt = 'system'
160   default_gettext_opt = 'system'
161   default_pch_opt = False
162   default_with_x = True
163   boost_posix = True
164   packaging_method = 'posix'
165   default_prefix = '/usr/local/'
166   share_dir = 'share/lyx'
167   man_dir = 'man/man1'
168   locale_dir = 'share/locale'
169 elif os.name == 'darwin':
170   platform_name = 'mac'
171   default_frontend = 'qt3'
172   # to be safe
173   default_boost_opt = 'included'
174   default_gettext_opt = 'included'
175   default_pch_opt = False
176   default_with_x = False
177   boost_posix = True
178   packaging_method = 'mac'
179   # FIXME: where to install?
180   default_prefix = '/usr/local/'
181   share_dir = 'Resources'
182   man_dir = 'Resources/man/man1'
183   locale_dir = 'Resources/locale'
184 else:  # unsupported system
185   platform_name = 'others'
186   default_frontend = 'qt3'
187   # to be safe
188   default_boost_opt = 'included'
189   default_gettext_opt = 'included'
190   default_pch_opt = False
191   default_with_x = True
192   boost_posix = False
193   packaging_method = 'posix'
194   default_prefix = '/usr/local/'
195   share_dir = 'share/lyx'
196   man_dir = 'man/man1'
197   locale_dir = 'share/locale'
198
199
200 #---------------------------------------------------------
201 # Handling options
202 #----------------------------------------------------------
203 #
204 if os.path.isfile('config.py'):
205   print "Getting options from config.py..."
206   print open('config.py').read()
207
208 opts = Options(['config.py'])
209 opts.AddOptions(
210   # frontend,
211   EnumOption('frontend', 'Main GUI', default_frontend,
212     allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ),
213   # debug or release build
214   EnumOption('mode', 'Building method', default_build_mode,
215     allowed_values = ('debug', 'release') ),
216   # boost libraries
217   EnumOption('boost',
218     'Use included, system boost library, or try sytem boost first.',
219     default_boost_opt,
220     allowed_values = (
221       'auto',       # detect boost, if not found, use included
222       'included',   # always use included boost
223       'system',     # always use system boost, fail if can not find
224       ) ),
225   # FIXME: not implemented yet.
226   EnumOption('gettext',
227     'Use included, system gettext library, or try sytem gettext first',
228     default_gettext_opt,
229     allowed_values = (
230       'auto',       # detect gettext, if not found, use included
231       'included',   # always use included gettext
232       'system',     # always use system gettext, fail if can not find
233       ) ),
234   #
235   EnumOption('spell', 'Choose spell checker to use.', 'auto',
236     allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
237   #
238   BoolOption('fast_start', 'Whether or not use cached tests and keep current config.h', True),
239   # FIXME: I do not know how pch is working. Ignore this option now.
240   BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
241   # FIXME: Not implemented yet.
242   BoolOption('version_suffix', '(NA) Whether or not add version suffix', False),
243   # enable assertion, (config.h has ENABLE_ASSERTIOS
244   BoolOption('assertions', 'Use assertions', True),
245   # enable warning, (config.h has WITH_WARNINGS)
246   BoolOption('warnings', 'Use warnings', True),
247   # enable glib, (config.h has _GLIBCXX_CONCEPT_CHECKS)
248   BoolOption('concept_checks', 'Enable concept checks', True),
249   # FIXME: I do not know what is nls
250   BoolOption('nls', '(NA) Whether or not use native language support', False),
251   # FIXME: not implemented
252   BoolOption('profile', '(NA) Whether or not enable profiling', False),
253   # FIXME: not implemented
254   BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
255   # using x11?
256   BoolOption('X11', 'Use x11 windows system', default_with_x),
257   # FIXME: not implemented
258   BoolOption('libintl', '(NA) Use libintl library', False),
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   #
278   PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
279   # FIXME: not implemented
280   PathOption('intl_prefix', '(NA) Path to intl library', 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 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir)
339 env['MAN_DIR'] = os.path.join(env['PREFIX'], man_dir)
340 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
341
342 # speed up source file processing
343 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
344 #env['CXXSUFFIX'] = ['.C']
345
346 def getEnvVariable(env, name):
347   # first try command line argument (override environment settings)
348   if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
349     env[name] = ARGUMENTS[name]
350   # then use environment default
351   elif os.environ.has_key(name) and os.environ[name].strip() != '':
352     env[name] = os.environ[name]
353     print "Acquiring varaible %s from system environment: %s" % (name, env[name])
354   # finally, env['CC'] etc is set to the default values of Options.
355   # and env['CPP'] etc does not exist
356
357 getEnvVariable(env, 'CC')
358 getEnvVariable(env, 'LINK')
359 getEnvVariable(env, 'CPP')
360 getEnvVariable(env, 'CXX')
361 getEnvVariable(env, 'CXXCPP')
362 getEnvVariable(env, 'CCFLAGS')
363 getEnvVariable(env, 'CXXFLAGS')
364 getEnvVariable(env, 'CPPFLAGS')
365 getEnvVariable(env, 'LDFLAGS')
366
367
368 #
369 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
370 #
371 env['mode'] = env.get('mode', default_build_mode)
372 # lyx will be built to $build/build_dir so it is possible
373 # to build multiple build_dirs using the same source
374 # $mode can be debug or release
375 if env.has_key('build_dir') and env['build_dir']:
376   build_dir = env['build_dir']
377   env['BUILDDIR'] = build_dir
378 else:
379   # Determine the name of the build $mode
380   env['BUILDDIR'] = '#' + env['mode']
381 # all built libraries will go to build_dir/libs
382 # (This is different from the make file approach)
383 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
384 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
385
386 #
387 # QTDIR, QT_LIB_PATH, QT_INC_PATH
388 #
389 if env.has_key('qt_dir') and env['qt_dir']:
390   env['QTDIR'] = env['qt_dir']
391   # add path to the qt tools
392   env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
393   # set environment so that moc etc can be found even if its path is not set properly
394   env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
395 else:
396   env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
397
398 if env.has_key('qt_lib_path') and env['qt_lib_path']:
399   env['QT_LIB_PATH'] = env['qt_lib_path']
400 else:
401   env['QT_LIB_PATH'] = '$QTDIR/lib'
402 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
403 # qt4 seems to be using pkg_config
404 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
405
406 if env.has_key('qt_inc_path') and env['qt_inc_path']:
407   env['QT_INC_PATH'] = env['qt_inc_path']
408 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
409   env['QT_INC_PATH'] = '$QTDIR/include'
410 else: # have to guess
411   env['QT_INC_PATH'] = '/usr/include/$frontend/'
412 # Note that this CPPPATH is for testing only
413 # it will be removed before calling SConscript
414 env['CPPPATH'] = [env['QT_INC_PATH']]
415
416 #
417 # extra_inc_path and extra_lib_path
418 #
419 if env.has_key('extra_inc_path') and env['extra_inc_path']:
420   env.AppendUnique(CPPPATH = [env['extra_inc_path']])
421 if env.has_key('extra_lib_path') and env['extra_lib_path']:
422   env.AppendUnique(LIBPATH = [env['extra_lib_path']])
423 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
424   env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
425 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
426   env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
427 if env.has_key('aikasurus_path') and env['aikasurus_path']:
428   env.AppendUnique(LIBPATH = [env['aikasurus_path']])
429
430 #
431 # this is a bit out of place (after auto-configration)
432 # but it is required to do the tests.
433 if platform_name == 'win32':
434   env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
435   env.Tool('mingw')
436
437 # under windows, scons is confused by .C/.c and uses gcc instead of
438 # g++. I am forcing the use of g++ here. This is expected to change
439 # after lyx renames all .C files to .cpp
440 #
441 # Note that this step has to be after env.Tool('mingw') step
442 # since env.Tool('mingw') will set env['CC'] etc.
443 #
444 if env.has_key('CXX') and env['CXX']:
445   env['CC'] = env['CXX']
446   env['LINK'] = env['CXX']
447 else:
448   env['CC'] = 'g++'
449   env['LINK'] = 'g++'
450
451
452 #----------------------------------------------------------
453 # Autoconf business
454 #----------------------------------------------------------
455
456 conf = Configure(env,
457   custom_tests = {
458     'CheckPkgConfig' : utils.checkPkgConfig,
459     'CheckPackage' : utils.checkPackage,
460     'CheckPutenv' : utils.checkPutenv,
461     'CheckIstreambufIterator' : utils.checkIstreambufIterator,
462     'CheckMkdirOneArg' : utils.checkMkdirOneArg,
463     'CheckStdCount' : utils.checkStdCount,
464     'CheckSelectArgType' : utils.checkSelectArgType,
465     'CheckBoostLibraries' : utils.checkBoostLibraries,
466     'CheckMsgFmt' : utils.checkMsgFmt,
467   }
468 )
469
470 # pkg-config? (if not, we use hard-coded options)
471 if not fast_start:
472   if conf.CheckPkgConfig('0.15.0'):
473     env['HAS_PKG_CONFIG'] = True
474   else:
475     print 'pkg-config >= 0.1.50 is not found'
476     env['HAS_PKG_CONFIG'] = False
477   env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG']
478 else:
479   env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG']
480
481 # zlib? This is required. (fast_start assumes the existance of zlib)
482 if not fast_start and not conf.CheckLibWithHeader('z', 'zlib.h', 'C'):
483     print 'Did not find libz or zlib.h, exiting!'
484     Exit(1)
485
486 # qt libraries?
487 if not fast_start:
488   #
489   # qt3 does not use pkg_config
490   if frontend == 'qt3':
491     if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
492       print 'Did not find qt libraries, exiting!'
493       Exit(1)
494   elif frontend == 'qt4':
495     succ = False
496     # first: try pkg_config
497     if env['HAS_PKG_CONFIG']:
498       succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
499       env['QT4_PKG_CONFIG'] = succ
500     # second: try to link to it
501     if not succ:
502       # FIXME: under linux, I can test the following perfectly
503       # However, under windows, lib names need to passed as libXXX4.a ...
504       succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
505         conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
506     # third: try to look up the path
507     if not succ:
508       succ = True
509       for lib in ['QtCore', 'QtGui']:
510         # windows version has something like QtGui4 ...
511         if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
512           os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
513           succ = False
514           break
515     # still can not find it
516     if succ:
517       print "Qt4 libraries are found."
518     else:
519       print 'Did not find qt libraries, exiting!'
520       Exit(1)
521
522
523 # check socket libs
524 if not fast_start:
525   env['SOCKET_LIBS'] = []
526   if conf.CheckLib('socket'):
527     env['SOCKET_LIBS'].append('socket')
528     env['HAS_SOCKET_LIB'] = True
529   else:
530     env['HAS_SOCKET_LIB'] = False
531
532   # nsl is the network services library and provides a
533   # transport-level interface to networking services.
534   if conf.CheckLib('nsl'):
535     env['SOCKET_LIBS'].append('nsl')
536
537   env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
538   env_cache['HAS_SOCKET_LIB'] = env['HAS_SOCKET_LIB']
539 else:
540   env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
541   env['HAS_SOCKET_LIB'] = env_cache['HAS_SOCKET_LIB']
542
543 if not fast_start:
544   # check boost libraries
545   boost_opt = ARGUMENTS.get('boost', default_boost_opt)
546   # check for system boost
547   succ = False
548   if boost_opt in ['auto', 'system']:
549     pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
550     sig = conf.CheckBoostLibraries('boost_signals', pathes)
551     reg = conf.CheckBoostLibraries('boost_regex', pathes)
552     fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
553     ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
554     # if any of them is not found
555     if ('' in [sig[0], reg[0], fil[0], ios[0]]):
556       if boost_opt == 'system':
557         print "Can not find system boost libraries"
558         print "Please supply a path through extra_lib_path and try again."
559         print "Or use boost=included to use included boost libraries."
560         Exit(2)
561     else:
562       env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
563       # assume all boost libraries are in the same path...
564       env.AppendUnique(LIBPATH = [sig[0]])
565       env['INCLUDED_BOOST'] = False
566       succ = True
567   # now, auto and succ = false, or boost=included
568   if not succ:
569     # we do not need to set LIBPATH now.
570     env['BOOST_LIBRARIES'] = ['boost_signals', 'boost_regex',
571       'boost_filesystem', 'boost_iostreams']
572     env['INCLUDED_BOOST'] = True
573   env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
574   env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
575 else:
576   env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
577   env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
578
579 #
580 # check for msgfmt command
581 if not fast_start:
582   env['MSGFMT'] = conf.CheckMsgFmt()
583   env_cache['MSGFMT'] = env['MSGFMT']
584 else:
585   env['MSGFMT'] = env_cache['MSGFMT']
586
587
588 #----------------------------------------------------------
589 # Generating config.h
590 #----------------------------------------------------------
591 if not fast_start:
592   print "Generating ", utils.config_h, "..."
593
594   # I do not handle all macros in src/config.h.in, rather I am following a list
595   # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
596   #
597   # Note: addToConfig etc are defined in scons_util
598   utils.startConfigH(TOP_SRC_DIR)
599
600   # HAVE_IO_H
601   # HAVE_LIMITS_H
602   # HAVE_LOCALE_H
603   # HAVE_LOCALE
604   # HAVE_PROCESS_H
605   # HAVE_STDLIB_H
606   # HAVE_SYS_STAT_H
607   # HAVE_SYS_TIME_H
608   # HAVE_SYS_TYPES_H
609   # HAVE_SYS_UTIME_H
610   # HAVE_UNISTD_H
611   # HAVE_UTIME_H
612   # HAVE_ISTREAM
613   # HAVE_OSTREAM
614   # HAVE_IOS
615
616   # Check header files
617   headers = [
618     ('io.h', 'HAVE_IO_H', 'c'),
619     ('limits.h', 'HAVE_LIMITS_H', 'c'),
620     ('locale.h', 'HAVE_LOCALE_H', 'c'),
621     ('locale', 'HAVE_LOCALE', 'cxx'),
622     ('process.h', 'HAVE_PROCESS_H', 'c'),
623     ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
624     ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
625     ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
626     ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
627     ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
628     ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
629     ('unistd.h', 'HAVE_UNISTD_H', 'c'),
630     ('utime.h', 'HAVE_UTIME_H', 'c'),
631     ('istream', 'HAVE_ISTREAM', 'cxx'),
632     ('ostream', 'HAVE_OSTREAM', 'cxx'),
633     ('ios', 'HAVE_IOS', 'cxx')
634   ]
635
636   for header in headers:
637     if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
638       (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
639       utils.addToConfig('#define %s 1' % header[1], TOP_SRC_DIR)
640     else:
641       utils.addToConfig('/* #undef %s */' % header[1], TOP_SRC_DIR)
642
643   # HAVE_OPEN
644   # HAVE_CLOSE
645   # HAVE_POPEN
646   # HAVE_PCLOSE
647   # HAVE__OPEN
648   # HAVE__CLOSE
649   # HAVE__POPEN
650   # HAVE__PCLOSE
651   # HAVE_GETPID
652   # HAVE__GETPID
653   # HAVE_MKDIR
654   # HAVE__MKDIR
655   # HAVE_MKTEMP
656   # HAVE_MKSTEMP
657   # HAVE_STRERROR
658   # HAVE_FCNTL
659
660   # Check functions
661   functions = [
662     ('open', 'HAVE_OPEN'),
663     ('close', 'HAVE_CLOSE'),
664     ('popen', 'HAVE_POPEN'),
665     ('pclose', 'HAVE_PCLOSE'),
666     ('_open', 'HAVE__OPEN'),
667     ('_close', 'HAVE__CLOSE'),
668     ('_popen', 'HAVE__POPEN'),
669     ('_pclose', 'HAVE__PCLOSE'),
670     ('getpid', 'HAVE_GETPID'),
671     ('_getpid', 'HAVE__GETPID'),
672     ('mkdir', 'HAVE_MKDIR'),
673     ('_mkdir', 'HAVE__MKDIR'),
674     ('mktemp', 'HAVE_MKTEMP'),
675     ('mkstemp', 'HAVE_MKSTEMP'),
676     ('strerror', 'HAVE_STRERROR'),
677     ('fcntl', 'HAVE_FCNTL')
678   ]
679
680   for func in functions:
681     if conf.CheckFunc(func[0]):
682       utils.addToConfig('#define %s 1' % func[1], TOP_SRC_DIR)
683     else:
684       utils.addToConfig('/* #undef %s */' % func[1], TOP_SRC_DIR)
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
830 else:
831   # only a few variables need to be rescanned
832   env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
833   env['USE_ASPELL'] = env_cache['USE_ASPELL']
834   env['USE_PSPELL'] = env_cache['USE_PSPELL']
835   env['USE_ISPELL'] = env_cache['USE_ISPELL']
836
837 #
838 # Finish auto-configuration
839 env = conf.Finish()
840
841 #----------------------------------------------------------
842 # Now set up our build process accordingly
843 #----------------------------------------------------------
844
845 #
846 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
847 #
848 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
849 # in their respective directory and specialized env.
850 try:
851   if frontend == 'qt3':
852     # note: env.Tool('qt') my set QT_LIB to qt
853     env['QT_LIB'] = 'qt-mt'
854     env['EXTRA_LIBS'].append('qt-mt')
855     if platform_name == 'cygwin' and use_X11:
856       env['EXTRA_LIBS'].extend(['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
857         'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
858         'pthread'])
859       env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
860   elif frontend == 'qt4':
861     if platform_name == "win32":
862       env['QT_LIB'] = ['QtCore4', 'QtGui4']
863     else:
864       env['QT_LIB'] = ['QtCore', 'QtGui']
865     env['EXTRA_LIBS'] += env['QT_LIB']
866 except:
867   print "Can not locate qt tools"
868   print "What I get is "
869   print "  QTDIR: ", env['QTDIR']
870
871
872 if platform_name in ['win32', 'cygwin']:
873   # the final link step needs stdc++ to succeed under mingw
874   # FIXME: shouldn't g++ automatically link to stdc++?
875   env['SYSTEM_LIBS'] = ['shlwapi', 'z', 'stdc++']
876 else:
877   env['SYSTEM_LIBS'] = ['z']
878
879 #
880 # Build parameters CPPPATH etc
881 #
882 # boost is always in, src is needed for config.h
883
884 # QT_INC_PATH is not needed for *every* source file
885 env['CPPPATH'].remove(env['QT_INC_PATH'])
886 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
887
888 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
889 # for debug/release mode
890 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
891   env.AppendUnique(CCFLAGS = [])
892 else:
893   env.AppendUnique(CCFLAGS = [])
894
895 #
896 # Customized builders
897 #
898 # install customized builders
899 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
900 # FIXME: there must be a better way.
901 env['BUILDERS']['fileCopy'] = Builder(action = utils.env_filecopy)
902
903 #
904 # A Link script for cygwin see
905 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
906 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
907 # for details
908 #
909 if platform_name == 'cygwin':
910   ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
911   ld_script = utils.installCygwinLDScript(ld_script_path)
912   env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
913     '-Wl,--script,%s' % ld_script, '-Wl,-s'])
914
915 #
916 # Report results
917 #
918 # src/support/package.C.in needs the following to replace
919 #  LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
920 env['LYX_DIR'] = env['SHARE_DIR']
921 #  LYX_ABS_INSTALLED_LOCALEDIR
922 env['LOCALEDIR'] = env['LOCALE_DIR']
923 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
924 env['PROGRAM_SUFFIX'] = PROGRAM_SUFFIX
925 # needed by src/version.C.in => src/version.C
926 env['PACKAGE_VERSION'] = PACKAGE_VERSION
927 # fill in the version info
928 env['VERSION_INFO'] = '''Configuration
929   Host type:                      %s
930   Special build flags:            %s
931   C   Compiler:                   %s
932   C   Compiler flags:             %s %s
933   C++ Compiler:                   %s
934   C++ Compiler LyX flags:         %s
935   C++ Compiler flags:             %s %s
936   Linker flags:                   %s
937   Linker user flags:              %s
938 Build info:
939   Builing directory:              %s
940   Local library directory:        %s
941   Libraries pathes:               %s
942   Boost libraries:                %s
943   Extra libraries:                %s
944   System libraries:               %s
945   include search path:            %s
946 Frontend:
947   Frontend:                       %s
948   Packaging:                      %s
949   LyX dir:                        %s
950   LyX binary dir:                 %s
951   LyX files dir:                  %s
952 ''' % (platform_name,
953   env.subst('$CCFLAGS'), env.subst('$CC'),
954   env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
955   env.subst('$CXX'), env.subst('$CXXFLAGS'),
956   env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
957   env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
958   env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
959   str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
960   str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
961   env['frontend'], packaging_method,
962   env['PREFIX'], env['BIN_DIR'], env['SHARE_DIR'])
963
964 if env['frontend'] in ['qt3', 'qt4']:
965   env['VERSION_INFO'] += '''  include dir:                    %s
966   library dir:                    %s
967   X11:                            %s
968 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
969
970 if not fast_start:
971   print env['VERSION_INFO']
972
973 #
974 # Mingw command line may be too short for our link usage,
975 # Here we use a trick from scons wiki
976 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
977 #
978 # I also would like to add logging (commands only) capacity to the
979 # spawn system.
980 logfile = env.get('logfile', default_log_file)
981 if logfile != '' or platform_name == 'win32':
982   import time
983   utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
984     info = '''# This is a log of commands used by scons to build lyx
985 # Time: %s
986 # Command: %s
987 # Info: %s
988 ''' % (time.asctime(), ' '.join(sys.argv),
989   env['VERSION_INFO'].replace('\n','\n# ')) )
990
991
992 #
993 # Cleanup stuff
994 #
995 # -h will print out help info
996 Help(opts.GenerateHelpText(env))
997 # save environment settings (for fast_start option)
998 cache_file = open(env_cache_file, 'w')
999 cPickle.dump(env_cache, cache_file)
1000 cache_file.close()
1001
1002 #----------------------------------------------------------
1003 # Start building
1004 #----------------------------------------------------------
1005 Export('env')
1006
1007 # this has been the source of problems on some platforms...
1008 # I find that I need to supply it with full path name
1009 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1010 # this usage needs further investigation.
1011 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1012
1013 env['BUILD_TARGETS'] = BUILD_TARGETS
1014
1015 print "Building all targets recursively"
1016
1017 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)
1018
1019