1 # vi:filetype=python:expandtab:tabstop=2:shiftwidth=2
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # Full author contact details are available in file CREDITS.
12 # This is a scons based building system for lyx, you can use it as follows:
14 # $ cd development/scons
15 # $ scons [options] [targets]
17 # $ scons -f development/scons/SConstruct [options] [targets]
19 # $ scons [prefix=.] install
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
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
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/
40 # * scons fast_start=yes
41 # If env.cache exists, bypass all tests and use existing src/config.h
43 # * scons --config=force
44 # force re-configuration (use scons -H for details)
46 # * check config.log to see why config has failed
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.
53 # * executed commands will be logged in scons_lyx.log. You can use logfile=
54 # option to save log to another file.
58 # * scons dist etc may be added later. Interested contributors can follow
59 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/AccumulateBuilder
61 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/DistTarBuilder
62 # Please also see the commented out code in scons_utils.py
64 # * NSIS support can be found here.
65 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
68 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/RpmHonchoTemp
70 # However, I decide to wait since scons seems to be standardizing these
74 import os, sys, copy, cPickle
76 # config/scons_utils.py defines a few utility function
77 sys.path.append('config')
78 import scons_utils as utils
80 #----------------------------------------------------------
81 # Required runtime environment
82 #----------------------------------------------------------
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)
89 # determine where I am ...
91 # called as 'scons -f development/scons/SConstruct'
92 if os.path.isfile('SConstruct'):
95 # called as 'cd development/scons; scons'
98 SCONS_DIR = 'development/scons'
100 #----------------------------------------------------------
102 #----------------------------------------------------------
104 # some global settings
105 PACKAGE_VERSION = '1.5.0svn'
107 default_build_mode = 'debug'
110 PACKAGE_BUGREPORT = 'lyx-devel@lists.lyx.org'
112 PACKAGE_TARNAME = 'lyx'
113 PACKAGE_STRING = '%s %s' % (PACKAGE_NAME, PACKAGE_VERSION)
115 # various cache/log files
116 default_log_file = 'scons_lyx.log'
117 env_cache_file = 'env.cache'
120 #----------------------------------------------------------
121 # platform dependent settings
122 #----------------------------------------------------------
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.
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
150 packaging_method = 'posix'
151 add_suffix_to_executables = True
152 default_prefix = '/usr/local/'
153 share_dir = 'share/lyx'
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
165 packaging_method = 'posix'
166 add_suffix_to_executables = True
167 default_prefix = '/usr/local/'
168 share_dir = 'share/lyx'
170 locale_dir = 'share/locale'
171 elif os.name == 'darwin':
172 platform_name = 'mac'
173 default_frontend = 'qt3'
175 default_boost_opt = 'included'
176 default_gettext_opt = 'included'
177 default_pch_opt = False
178 default_with_x = False
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'
191 default_boost_opt = 'included'
192 default_gettext_opt = 'included'
193 default_pch_opt = False
194 default_with_x = True
196 packaging_method = 'posix'
197 add_suffix_to_executables = True
198 default_prefix = '/usr/local/'
199 share_dir = 'share/lyx'
201 locale_dir = 'share/locale'
204 #---------------------------------------------------------
206 #----------------------------------------------------------
208 if os.path.isfile('config.py'):
209 print "Getting options from config.py..."
210 print open('config.py').read()
212 opts = Options(['config.py'])
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') ),
222 'Use included, system boost library, or try sytem boost first.',
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
229 # FIXME: not implemented yet.
230 EnumOption('gettext',
231 'Use included, system gettext library, or try sytem gettext first',
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
239 EnumOption('spell', 'Choose spell checker to use.', 'auto',
240 allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
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),
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),
258 BoolOption('X11', 'Use x11 windows system', default_with_x),
260 PathOption('qt_dir', 'Path to qt directory', None),
262 PathOption('qt_include_path', 'Path to qt include directory', None),
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),
270 PathOption('extra_lib_path', 'Extra library path', None),
272 PathOption('extra_inc_path1', 'Extra include path', None),
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 # will install to dest_dir if defined. Otherwise, prefix will be used.
278 ('dest_dir', 'install to dest_dir', None),
280 ('version_suffix', 'install lyx as lyx-suffix', ''),
282 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
284 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
286 PathOption('aikasurus_path', 'Path to aikasurus library', None),
287 # environment variable can be set as options. (DO NOT set defaults)
289 ('LINK', '$LINK', None),
290 ('CPP', '$CPP', None),
291 ('CXX', '$CXX', None),
292 ('CXXCPP', '$CXXCPP', None),
293 ('CCFLAGS', '$CCFLAGS', None),
294 ('CPPFLAGS', '$CPPFLAGS', None),
295 ('LDFLAGS', '$LDFLAGS', None),
298 # whether or not use current config.h, and cached tests
299 if (not ARGUMENTS.has_key('fast_start') or \
300 ARGUMENTS['fast_start'] in ['y', 'yes', 't', 'true', '1', 'all']) \
301 and os.path.isfile(env_cache_file):
303 cache_file = open(env_cache_file)
304 env_cache = cPickle.load(cache_file)
306 # import cached options, but we should ignore qt_dir when frontend changes
307 if ARGUMENTS.has_key('frontend') and env_cache['arg_cache'].has_key('frontend') \
308 and ARGUMENTS['frontend'] != env_cache['arg_cache']['frontend'] \
309 and env_cache['arg_cache'].has_key('qt_dir'):
310 env_cache['arg_cache'].pop('qt_dir')
311 # and we do not cache fast_start
312 if env_cache['arg_cache'].has_key('fast_start'):
313 env_cache['arg_cache'].pop('fast_start')
314 print '------------ fast_start mode --------------------'
315 print ' Use cached test results and current config.h'
316 print ' use fast_start=no to override'
318 for key in env_cache['arg_cache'].keys():
319 if not ARGUMENTS.has_key(key):
320 ARGUMENTS[key] = env_cache['arg_cache'][key]
321 print "Restoring cached option %s=%s" % (key, ARGUMENTS[key])
322 print '-------------------------------------------------'
328 env_cache['arg_cache'] = ARGUMENTS
331 #---------------------------------------------------------
332 # Setting up environment
333 #---------------------------------------------------------
335 env = Environment(options = opts)
337 # Determine the frontend to use, which may be loaded
339 frontend = env.get('frontend', default_frontend)
340 # make sure the key exists
341 env['frontend'] = frontend
343 use_X11 = env.get('X11', default_with_x)
346 # set individual variables since I do not really like ENV = os.environ
347 env['ENV']['PATH'] = os.environ.get('PATH')
348 env['ENV']['HOME'] = os.environ.get('HOME')
349 env['TOP_SRC_DIR'] = TOP_SRC_DIR
350 env['SCONS_DIR'] = SCONS_DIR
351 # install to default_prefix by default
352 env['PREFIX'] = env.get('prefix', default_prefix)
354 if env.has_key('version_suffix'):
355 env['PROGRAM_SUFFIX'] = env['version_suffix']
357 env['PROGRAM_SUFFIX'] = ''
358 env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables
359 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX'])
360 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
362 # if dest_dir is different from prefix.
363 env['DEST_DIR'] = env.get('dest_dir', env['PREFIX'])
364 if env.has_key('exec_prefix'):
365 env['BIN_DEST_DIR'] = env['exec_prefix']
367 env['BIN_DEST_DIR'] = os.path.join(env['DEST_DIR'], 'bin')
368 env['SHARE_DEST_DIR'] = os.path.join(env['DEST_DIR'], share_dir + env['PROGRAM_SUFFIX'])
369 env['MAN_DEST_DIR'] = os.path.join(env['DEST_DIR'], man_dir)
370 env['LOCALE_DEST_DIR'] = os.path.join(env['DEST_DIR'], locale_dir)
373 # this is a bit out of place (after auto-configration) but
374 # it is required to do the tests. Since Tool('mingw') will
375 # reset CCFLAGS etc, this should be before getEnvVariable
376 if platform_name == 'win32':
378 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
381 # speed up source file processing
382 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
383 #env['CXXSUFFIX'] = ['.C']
385 def getEnvVariable(env, name):
386 # first try command line argument (override environment settings)
387 if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
388 # multiple options may be passed like "-02 -g"
389 env[name] = ARGUMENTS[name].split()
390 # it does not seem necessary, but it is safer to change ['a'] back to 'a'
391 if len(env[name]) == 1:
392 env[name] = env[name][0]
393 # then use environment default
394 elif os.environ.has_key(name) and os.environ[name].strip() != '':
395 print "Acquiring varaible %s from system environment: %s" % (name, env[name])
396 env[name] = os.environ[name].split()
397 if len(env[name]) == 1:
398 env[name] = env[name][0]
399 # finally, env['CC'] etc is set to the default values of Options.
400 # and env['CPP'] etc does not exist
402 getEnvVariable(env, 'CC')
403 getEnvVariable(env, 'LINK')
404 getEnvVariable(env, 'CPP')
405 getEnvVariable(env, 'CXX')
406 getEnvVariable(env, 'CXXCPP')
407 getEnvVariable(env, 'CCFLAGS')
408 getEnvVariable(env, 'CXXFLAGS')
409 getEnvVariable(env, 'CPPFLAGS')
410 getEnvVariable(env, 'LDFLAGS')
414 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
416 env['mode'] = env.get('mode', default_build_mode)
417 # lyx will be built to $build/build_dir so it is possible
418 # to build multiple build_dirs using the same source
419 # $mode can be debug or release
420 if env.has_key('build_dir') and env['build_dir']:
421 build_dir = env['build_dir']
422 env['BUILDDIR'] = build_dir
424 # Determine the name of the build $mode
425 env['BUILDDIR'] = '#' + env['mode']
426 # all built libraries will go to build_dir/libs
427 # (This is different from the make file approach)
428 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
429 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
432 # QTDIR, QT_LIB_PATH, QT_INC_PATH
434 if env.has_key('qt_dir') and env['qt_dir']:
435 env['QTDIR'] = env['qt_dir']
436 # add path to the qt tools
437 env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
438 # set environment so that moc etc can be found even if its path is not set properly
439 env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
441 env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
443 if env.has_key('qt_lib_path') and env['qt_lib_path']:
444 env['QT_LIB_PATH'] = env['qt_lib_path']
446 env['QT_LIB_PATH'] = '$QTDIR/lib'
447 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
448 # qt4 seems to be using pkg_config
449 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
451 if env.has_key('qt_inc_path') and env['qt_inc_path']:
452 env['QT_INC_PATH'] = env['qt_inc_path']
453 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
454 env['QT_INC_PATH'] = '$QTDIR/include'
455 else: # have to guess
456 env['QT_INC_PATH'] = '/usr/include/$frontend/'
457 # Note that this CPPPATH is for testing only
458 # it will be removed before calling SConscript
459 env['CPPPATH'] = [env['QT_INC_PATH']]
462 # extra_inc_path and extra_lib_path
464 if env.has_key('extra_inc_path') and env['extra_inc_path']:
465 env.AppendUnique(CPPPATH = [env['extra_inc_path']])
466 if env.has_key('extra_lib_path') and env['extra_lib_path']:
467 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
468 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
469 env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
470 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
471 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
472 if env.has_key('aikasurus_path') and env['aikasurus_path']:
473 env.AppendUnique(LIBPATH = [env['aikasurus_path']])
476 # under windows, scons is confused by .C/.c and uses gcc instead of
477 # g++. I am forcing the use of g++ here. This is expected to change
478 # after lyx renames all .C files to .cpp
480 # Note that this step has to be after env.Tool('mingw') step
481 # since env.Tool('mingw') will set env['CC'] etc.
483 # save the old c compiler
484 env['C_COMPILER'] = env['CC']
485 if env.has_key('CXX') and env['CXX']:
486 env['CC'] = env['CXX']
487 env['LINK'] = env['CXX']
493 #----------------------------------------------------------
495 #----------------------------------------------------------
497 conf = Configure(env,
499 'CheckPkgConfig' : utils.checkPkgConfig,
500 'CheckPackage' : utils.checkPackage,
501 'CheckMkdirOneArg' : utils.checkMkdirOneArg,
502 'CheckSelectArgType' : utils.checkSelectArgType,
503 'CheckBoostLibraries' : utils.checkBoostLibraries,
504 'CheckCommand' : utils.checkCommand,
508 # pkg-config? (if not, we use hard-coded options)
510 if conf.CheckPkgConfig('0.15.0'):
511 env['HAS_PKG_CONFIG'] = True
513 print 'pkg-config >= 0.1.50 is not found'
514 env['HAS_PKG_CONFIG'] = False
515 env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG']
517 env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG']
519 # zlib? This is required. (fast_start assumes the existance of zlib)
520 if not fast_start and not conf.CheckLibWithHeader('z', 'zlib.h', 'C'):
521 print 'Did not find libz or zlib.h, exiting!'
527 # qt3 does not use pkg_config
528 if frontend == 'qt3':
529 if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
530 print 'Did not find qt libraries, exiting!'
532 elif frontend == 'qt4':
534 # first: try pkg_config
535 if env['HAS_PKG_CONFIG']:
536 succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
537 env['QT4_PKG_CONFIG'] = succ
538 # second: try to link to it
540 # FIXME: under linux, I can test the following perfectly
541 # However, under windows, lib names need to passed as libXXX4.a ...
542 succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
543 conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
544 # third: try to look up the path
547 for lib in ['QtCore', 'QtGui']:
548 # windows version has something like QtGui4 ...
549 if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
550 os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
553 # still can not find it
555 print "Qt4 libraries are found."
557 print 'Did not find qt libraries, exiting!'
563 env['SOCKET_LIBS'] = []
564 if conf.CheckLib('socket'):
565 env['SOCKET_LIBS'].append('socket')
567 # nsl is the network services library and provides a
568 # transport-level interface to networking services.
569 if conf.CheckLib('nsl'):
570 env['SOCKET_LIBS'].append('nsl')
572 env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
574 env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
577 # check boost libraries
578 boost_opt = ARGUMENTS.get('boost', default_boost_opt)
579 # check for system boost
581 if boost_opt in ['auto', 'system']:
582 pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
583 sig = conf.CheckBoostLibraries('boost_signals', pathes)
584 reg = conf.CheckBoostLibraries('boost_regex', pathes)
585 fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
586 ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
587 # if any of them is not found
588 if ('' in [sig[0], reg[0], fil[0], ios[0]]):
589 if boost_opt == 'system':
590 print "Can not find system boost libraries"
591 print "Please supply a path through extra_lib_path and try again."
592 print "Or use boost=included to use included boost libraries."
595 env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
596 # assume all boost libraries are in the same path...
597 env.AppendUnique(LIBPATH = [sig[0]])
598 env['INCLUDED_BOOST'] = False
600 # now, auto and succ = false, or boost=included
602 # we do not need to set LIBPATH now.
603 env['BOOST_LIBRARIES'] = ['included_boost_signals', 'included_boost_regex',
604 'included_boost_filesystem', 'included_boost_iostreams']
605 env['INCLUDED_BOOST'] = True
606 env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
607 env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
609 env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
610 env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
613 if not env.has_key('nls') or env['nls']:
614 env['ENABLE_NLS'] = True
617 if not env['ENABLE_NLS']:
618 env['INTL_LIBS'] = []
619 env['INCLUDED_GETTEXT'] = False
621 # check gettext libraries
622 gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt)
623 # check for system gettext
625 if gettext_opt in ['auto', 'system']:
626 if conf.CheckLib('intl'):
627 env['INCLUDED_GETTEXT'] = False
628 env['INTL_LIBS'] = ['intl']
631 if gettext_opt == 'system':
632 print "Can not find system gettext library"
633 print "Please supply a path through extra_lib_path and try again."
634 print "Or use gettext=included to use included gettext libraries."
636 # now, auto and succ = false, or gettext=included
638 # we do not need to set LIBPATH now.
639 env['INCLUDED_GETTEXT'] = True
640 env['INTL_LIBS'] = ['included_intl']
641 if platform_name == 'win32':
642 # for functions AddFontResouceA, RemoveFontResourceA
643 env['INTL_LIBS'].append('gdi32')
644 env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT']
645 env_cache['INTL_LIBS'] = env['INTL_LIBS']
647 env['INTL_LIBS'] = env_cache['INTL_LIBS']
648 env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT']
651 # check for msgfmt command
653 env['MSGFMT'] = conf.CheckCommand('msgfmt')
654 env_cache['MSGFMT'] = env['MSGFMT']
656 env['MSGFMT'] = env_cache['MSGFMT']
659 #----------------------------------------------------------
660 # Generating config.h
661 #----------------------------------------------------------
663 print "Generating ", utils.config_h, "..."
665 # I do not handle all macros in src/config.h.in, rather I am following a list
666 # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
668 # Note: addToConfig etc are defined in scons_util
688 # for libintl % grep HAVE * | grep _H | cut -d: -f2 | sort -u
690 # HAVE_STDINT_H_WITH_UINTMAX
691 # HAVE_INTTYPES_H_WITH_UINTMAX
706 ('io.h', 'HAVE_IO_H', 'c'),
707 ('limits.h', 'HAVE_LIMITS_H', 'c'),
708 ('locale.h', 'HAVE_LOCALE_H', 'c'),
709 ('locale', 'HAVE_LOCALE', 'cxx'),
710 ('process.h', 'HAVE_PROCESS_H', 'c'),
711 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
712 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
713 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
714 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
715 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
716 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
717 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
718 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
719 ('utime.h', 'HAVE_UTIME_H', 'c'),
720 ('string.h', 'HAVE_STRING_H', 'c'),
721 ('strings.h', 'HAVE_STRINGS_H', 'c'),
722 ('istream', 'HAVE_ISTREAM', 'cxx'),
723 ('ostream', 'HAVE_OSTREAM', 'cxx'),
724 ('ios', 'HAVE_IOS', 'cxx'),
725 ('argz.h', 'HAVE_ARGZ_H', 'c'),
726 ('limits.h', 'HAVE_LIMITS_H', 'c'),
727 ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
728 ('stddef.h', 'HAVE_STDDEF_H', 'c'),
729 ('stdint.h', 'HAVE_STDINT_H', 'c'),
730 ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c')
733 for header in headers:
734 utils.addToConfig("/* Define to 1 if you have the <%s> header file. */" % header[0], newline=1)
735 if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
736 (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
737 utils.addToConfig('#define %s 1' % header[1])
739 utils.addToConfig('/* #undef %s */' % header[1])
771 # HAVE___ARGZ_STRINGIFY
781 ('open', 'HAVE_OPEN', None),
782 ('close', 'HAVE_CLOSE', None),
783 ('popen', 'HAVE_POPEN', None),
784 ('pclose', 'HAVE_PCLOSE', None),
785 ('_open', 'HAVE__OPEN', None),
786 ('_close', 'HAVE__CLOSE', None),
787 ('_popen', 'HAVE__POPEN', None),
788 ('_pclose', 'HAVE__PCLOSE', None),
789 ('getpid', 'HAVE_GETPID', None),
790 ('_getpid', 'HAVE__GETPID', None),
791 ('mkdir', 'HAVE_MKDIR', None),
792 ('_mkdir', 'HAVE__MKDIR', None),
793 ('putenv', 'HAVE_PUTENV', None),
794 ('mktemp', 'HAVE_MKTEMP', None),
795 ('mkstemp', 'HAVE_MKSTEMP', None),
796 ('strerror', 'HAVE_STRERROR', None),
797 ('count', 'HAVE_STD_COUNT', '''
802 return std::count(a, a+5, 'l');
805 ('getcwd', 'HAVE_GETCWD', None),
806 ('stpcpy', 'HAVE_STPCPY', None),
807 ('strcasecmp', 'HAVE_STRCASECMP', None),
808 ('strdup', 'HAVE_STRDUP', None),
809 ('strtoul', 'HAVE_STRTOUL', None),
810 ('alloca', 'HAVE_ALLOCA', None),
811 ('__fsetlocking', 'HAVE___FSETLOCKING', None),
812 ('mempcpy', 'HAVE_MEMPCPY', None),
813 ('__argz_count', 'HAVE___ARGZ_COUNT', None),
814 ('__argz_next', 'HAVE___ARGZ_NEXT', None),
815 ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
816 ('setlocale', 'HAVE_SETLOCALE', None),
817 ('tsearch', 'HAVE_TSEARCH', None),
818 ('getegid', 'HAVE_GETEGID', None),
819 ('getgid', 'HAVE_GETGID', None),
820 ('getuid', 'HAVE_GETUID', None),
821 ('wcslen', 'HAVE_WCSLEN', None)
830 for func in functions:
831 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
832 if conf.CheckFunc(func[0], header=func[2]):
833 utils.addToConfig('#define %s 1' % func[1])
835 utils.addToConfig('/* #undef %s */' % func[1])
838 ('asprintf', 'HAVE_ASPRINTF'),
839 ('wprintf', 'HAVE_WPRINTF'),
840 ('snprintf', 'HAVE_SNPRINTF'),
841 ('printf', 'HAVE_POSIX_PRINTF'),
842 ('fcntl', 'HAVE_FCNTL')
845 for func in env_functions:
846 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
847 if conf.CheckFunc(func[0]):
848 utils.addToConfig('#define %s 1' % func[1])
851 utils.addToConfig('/* #undef %s */' % func[1])
855 # HAVE_INTTYPES_H_WITH_UINTMAX
856 # HAVE_DECL_ISTREAMBUF_ITERATOR
857 utils.addToConfig("/* Define to 1 if you have the `intmax_t' type. */", newline=1)
858 if conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
859 conf.CheckType('intmax_t', includes='#include <inttypes.h>'):
860 utils.addToConfig('#define HAVE_INTMAX_T 1')
862 utils.addToConfig('/* #undef HAVE_INTMAX_T */')
869 # HAVE_INTTYPES_H_WITH_UINTMAX
872 ('intmax_t', 'HAVE_INTMAX_T', None),
873 ('long double', 'HAVE_LONG_DOUBLE', None),
874 ('long long', 'HAVE_LONG_LONG', None),
875 ('wchar_t', 'HAVE_WCHAR_T', None),
876 ('wint_t', 'HAVE_WINT_T', None),
877 ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
878 ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
879 '#include <streambuf>\n#include <istream>')
882 utils.addToConfig("/* Define to 1 if you have the `%s' type. */" % t[0], newline=1)
883 if conf.CheckType(t[0], includes=t[2]):
884 utils.addToConfig('#define %s 1' % t[1])
886 utils.addToConfig('/* #undef %s */' % t[1])
891 utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX']))
892 utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION)
894 utils.addToConfig('#define DEVEL_VERSION 1')
899 # _GLIBCXX_CONCEPT_CHECKS
901 # items are (ENV, ARGUMENTS)
903 ('ENABLE_ASSERTIONS', 'assertions'),
904 ('ENABLE_NLS', 'nls'),
905 ('WITH_WARNINGS', 'warnings'),
906 ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
910 if (env.has_key(val[0]) and env[val[0]]) or \
911 ARGUMENTS.get(val[1]):
912 utils.addToConfig('#define %s 1' % val[0])
914 utils.addToConfig('/* #undef %s */' % val[0])
917 env['EXTRA_LIBS'] = []
919 # AIKSAURUS_H_LOCATION
920 if conf.CheckLib('Aiksaurus'):
921 utils.addToConfig("#define HAVE_LIBAIKSAURUS 1")
922 if (conf.CheckCXXHeader("Aiksaurus.h")):
923 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>")
924 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
925 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>")
927 utils.addToConfig("#define AIKSAURUS_H_LOCATION")
928 env['EXTRA_LIBS'].append('Aiksaurus')
934 # determine headers to use
935 spell_engine = ARGUMENTS.get('spell', 'auto')
936 spell_detected = False
937 if spell_engine in ['auto', 'aspell'] and \
938 conf.CheckLib('aspell'):
939 utils.addToConfig('#define USE_ASPELL 1')
940 env['USE_ASPELL'] = True
941 env['USE_PSPELL'] = False
942 env['USE_ISPELL'] = False
943 env['EXTRA_LIBS'].append('aspell')
944 spell_detected = True
945 elif spell_engine in ['auto', 'pspell'] and \
946 conf.CheckLib('pspell'):
947 utils.addToConfig('#define USE_PSPELL 1')
948 env['USE_ASPELL'] = False
949 env['USE_PSPELL'] = True
950 env['USE_ISPELL'] = False
951 env['EXTRA_LIBS'].append('pspell')
952 spell_detected = True
953 elif spell_engine in ['auto', 'ispell'] and \
954 conf.CheckLib('ispell'):
955 utils.addToConfig('#define USE_ISPELL 1')
956 env['USE_ASPELL'] = False
957 env['USE_PSPELL'] = False
958 env['USE_ISPELL'] = True
959 env['EXTRA_LIBS'].append('ispell')
960 spell_detected = True
962 if not spell_detected:
963 env['USE_ASPELL'] = False
964 env['USE_PSPELL'] = False
965 env['USE_ISPELL'] = False
966 # FIXME: can lyx work without an spell engine
967 if spell_engine == 'auto':
968 print "Warning: Can not locate any spell checker"
970 print "Warning: Can not locate specified spell checker:", spell_engine
972 # USE_POSIX_PACKAGING
973 # USE_MACOSX_PACKAGING
974 # USE_WINDOWS_PACKAGING
975 if packaging_method == 'windows':
976 utils.addToConfig('#define USE_WINDOWS_PACKAGING 1')
977 elif packaging_method == 'posix':
978 utils.addToConfig('#define USE_POSIX_PACKAGING 1')
979 elif packaging_method == 'mac':
980 utils.addToConfig('#define USE_MACOSX_PACKAGING 1')
984 utils.addToConfig('#define BOOST_POSIX 1')
986 utils.addToConfig('/* #undef BOOST_POSIX */')
988 # MKDIR_TAKES_ONE_ARG
989 if conf.CheckMkdirOneArg():
990 utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1')
992 utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */')
997 (arg1, arg234, arg5) = conf.CheckSelectArgType()
998 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1)
999 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234)
1000 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5)
1004 # WANT_GETFILEATTRIBUTESEX_WRAPPER
1005 utils.endConfigH(TOP_SRC_DIR)
1007 # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed
1008 # NOTE that we do *not* save qt_libs in environment.
1009 env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS'])
1010 env_cache['USE_ASPELL'] = env['USE_ASPELL']
1011 env_cache['USE_PSPELL'] = env['USE_PSPELL']
1012 env_cache['USE_ISPELL'] = env['USE_ISPELL']
1013 env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF']
1014 env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF']
1015 env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF']
1016 env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF']
1017 env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL']
1021 # this comes as a big surprise, without this line
1022 # (doing nothing obvious), adding fast_start=yes
1023 # to a build with fast_start=no will result in a rebuild
1024 # Note that the exact header file to check does not matter
1025 conf.CheckCHeader('io.h')
1026 # only a few variables need to be rescanned
1027 env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
1028 env['USE_ASPELL'] = env_cache['USE_ASPELL']
1029 env['USE_PSPELL'] = env_cache['USE_PSPELL']
1030 env['USE_ISPELL'] = env_cache['USE_ISPELL']
1031 env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF']
1032 env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF']
1033 env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF']
1034 env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF']
1035 env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL']
1038 # Finish auto-configuration
1041 #----------------------------------------------------------
1042 # Now set up our build process accordingly
1043 #----------------------------------------------------------
1046 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
1048 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
1049 # in their respective directory and specialized env.
1051 if frontend == 'qt3':
1052 # note: env.Tool('qt') my set QT_LIB to qt
1053 env['QT_LIB'] = 'qt-mt'
1054 env['EXTRA_LIBS'].append('qt-mt')
1055 if platform_name == 'cygwin' and use_X11:
1056 env['EXTRA_LIBS'].extend(['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
1057 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
1059 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1060 elif frontend == 'qt4':
1061 if platform_name == "win32":
1062 env['QT_LIB'] = ['QtCore4', 'QtGui4']
1064 env['QT_LIB'] = ['QtCore', 'QtGui']
1065 env['EXTRA_LIBS'] += env['QT_LIB']
1067 print "Can not locate qt tools"
1068 print "What I get is "
1069 print " QTDIR: ", env['QTDIR']
1072 if platform_name in ['win32', 'cygwin']:
1073 # the final link step needs stdc++ to succeed under mingw
1074 # FIXME: shouldn't g++ automatically link to stdc++?
1075 env['SYSTEM_LIBS'] = ['shlwapi', 'z', 'stdc++']
1077 env['SYSTEM_LIBS'] = ['z']
1080 # Build parameters CPPPATH etc
1082 # boost is always in, src is needed for config.h
1084 # QT_INC_PATH is not needed for *every* source file
1085 env['CPPPATH'].remove(env['QT_INC_PATH'])
1086 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
1088 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
1089 # for debug/release mode
1090 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
1091 env.AppendUnique(CCFLAGS = [])
1093 env.AppendUnique(CCFLAGS = [])
1096 # Customized builders
1098 # install customized builders
1099 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
1102 # A Link script for cygwin see
1103 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1104 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1107 if platform_name == 'cygwin':
1108 ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
1109 ld_script = utils.installCygwinLDScript(ld_script_path)
1110 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1111 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1116 # src/support/package.C.in needs the following to replace
1117 # LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
1118 env['LYX_DIR'] = env['SHARE_DIR']
1119 # LYX_ABS_INSTALLED_LOCALEDIR
1120 env['LOCALEDIR'] = env['LOCALE_DIR']
1121 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
1122 # needed by src/version.C.in => src/version.C
1123 env['PACKAGE_VERSION'] = PACKAGE_VERSION
1124 # fill in the version info
1125 env['VERSION_INFO'] = '''Configuration
1127 Special build flags: %s
1129 C Compiler flags: %s %s
1131 C++ Compiler LyX flags: %s
1132 C++ Compiler flags: %s %s
1134 Linker user flags: %s
1136 Builing directory: %s
1137 Local library directory: %s
1138 Libraries pathes: %s
1141 System libraries: %s
1142 include search path: %s
1149 ''' % (platform_name,
1150 env.subst('$CCFLAGS'), env.subst('$CC'),
1151 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1152 env.subst('$CXX'), env.subst('$CXXFLAGS'),
1153 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1154 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1155 env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1156 str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
1157 str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
1158 env['frontend'], packaging_method,
1159 env['PREFIX'], env['BIN_DEST_DIR'], env['SHARE_DIR'])
1161 if env['frontend'] in ['qt3', 'qt4']:
1162 env['VERSION_INFO'] += ''' include dir: %s
1165 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
1168 print env['VERSION_INFO']
1171 # Mingw command line may be too short for our link usage,
1172 # Here we use a trick from scons wiki
1173 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1175 # I also would like to add logging (commands only) capacity to the
1177 logfile = env.get('logfile', default_log_file)
1178 if logfile != '' or platform_name == 'win32':
1180 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1181 info = '''# This is a log of commands used by scons to build lyx
1185 ''' % (time.asctime(), ' '.join(sys.argv),
1186 env['VERSION_INFO'].replace('\n','\n# ')) )
1192 # -h will print out help info
1193 Help(opts.GenerateHelpText(env))
1194 # save environment settings (for fast_start option)
1195 cache_file = open(env_cache_file, 'w')
1196 cPickle.dump(env_cache, cache_file)
1199 #----------------------------------------------------------
1201 #----------------------------------------------------------
1204 # this has been the source of problems on some platforms...
1205 # I find that I need to supply it with full path name
1206 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1207 # this usage needs further investigation.
1208 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1210 env['BUILD_TARGETS'] = BUILD_TARGETS
1212 print "Building all targets recursively"
1214 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)