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, glob
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'
111 PACKAGE_BUGREPORT = 'lyx-devel@lists.lyx.org'
113 PACKAGE_TARNAME = 'lyx'
114 PACKAGE_STRING = '%s %s' % (PACKAGE_NAME, PACKAGE_VERSION)
116 # various cache/log files
117 default_log_file = 'scons_lyx.log'
118 env_cache_file = 'env.cache'
121 #----------------------------------------------------------
122 # platform dependent settings
123 #----------------------------------------------------------
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.
136 packaging_method = 'windows'
137 add_suffix_to_executables = False
138 default_prefix = 'c:/program files/lyx'
139 share_dir = 'Resources'
140 man_dir = 'Resources/man/man1'
141 locale_dir = 'Resources/locale'
142 elif os.name == 'posix' and sys.platform != 'cygwin':
143 platform_name = sys.platform
144 default_frontend = 'qt3'
145 # try to use system boost/gettext libraries
146 default_boost_opt = 'auto'
147 default_gettext_opt = 'auto'
148 default_pch_opt = False
149 default_with_x = True
151 packaging_method = 'posix'
152 add_suffix_to_executables = True
153 default_prefix = '/usr/local/'
154 share_dir = 'share/lyx'
156 locale_dir = 'share/locale'
157 elif os.name == 'posix' and sys.platform == 'cygwin':
158 platform_name = 'cygwin'
159 default_frontend = 'qt3'
160 # force the use of cygwin/boost/gettext
161 default_boost_opt = 'system'
162 default_gettext_opt = 'system'
163 default_pch_opt = False
164 default_with_x = True
166 packaging_method = 'posix'
167 add_suffix_to_executables = True
168 default_prefix = '/usr/local/'
169 share_dir = 'share/lyx'
171 locale_dir = 'share/locale'
172 elif os.name == 'darwin':
173 platform_name = 'mac'
174 default_frontend = 'qt3'
176 default_boost_opt = 'included'
177 default_gettext_opt = 'included'
178 default_pch_opt = False
179 default_with_x = False
181 packaging_method = 'mac'
182 add_suffix_to_executables = True
183 # FIXME: where to install?
184 default_prefix = '/usr/local/'
185 share_dir = 'Resources'
186 man_dir = 'Resources/man/man1'
187 locale_dir = 'Resources/locale'
188 else: # unsupported system
189 platform_name = 'others'
190 default_frontend = 'qt3'
192 default_boost_opt = 'included'
193 default_gettext_opt = 'included'
194 default_pch_opt = False
195 default_with_x = True
197 packaging_method = 'posix'
198 add_suffix_to_executables = True
199 default_prefix = '/usr/local/'
200 share_dir = 'share/lyx'
202 locale_dir = 'share/locale'
205 #---------------------------------------------------------
207 #----------------------------------------------------------
209 if os.path.isfile('config.py'):
210 print "Getting options from config.py..."
211 print open('config.py').read()
213 opts = Options(['config.py'])
216 EnumOption('frontend', 'Main GUI', default_frontend,
217 allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ),
218 # debug or release build
219 EnumOption('mode', 'Building method', default_build_mode,
220 allowed_values = ('debug', 'release') ),
223 'Use included, system boost library, or try sytem boost first.',
226 'auto', # detect boost, if not found, use included
227 'included', # always use included boost
228 'system', # always use system boost, fail if can not find
230 # FIXME: not implemented yet.
231 EnumOption('gettext',
232 'Use included, system gettext library, or try sytem gettext first',
235 'auto', # detect gettext, if not found, use included
236 'included', # always use included gettext
237 'system', # always use system gettext, fail if can not find
240 EnumOption('spell', 'Choose spell checker to use.', 'auto',
241 allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
243 BoolOption('fast_start', 'Whether or not use cached tests and keep current config.h', True),
245 BoolOption('load_option', 'load option from previous scons run', True),
246 # FIXME: I do not know how pch is working. Ignore this option now.
247 BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
248 # enable assertion, (config.h has ENABLE_ASSERTIOS
249 BoolOption('assertions', 'Use assertions', True),
250 # enable warning, (config.h has WITH_WARNINGS)
251 BoolOption('warnings', 'Use warnings', True),
252 # enable glib, (config.h has _GLIBCXX_CONCEPT_CHECKS)
253 BoolOption('concept_checks', 'Enable concept checks', True),
255 BoolOption('nls', 'Whether or not use native language support', True),
256 # FIXME: not implemented
257 BoolOption('profile', '(NA) Whether or not enable profiling', False),
258 # FIXME: not implemented
259 BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
261 BoolOption('X11', 'Use x11 windows system', default_with_x),
262 # use MS VC++ to build lyx
263 BoolOption('use_vc', 'Use MS VC++ to build lyx', False),
265 PathOption('qt_dir', 'Path to qt directory', None),
267 PathOption('qt_include_path', 'Path to qt include directory', None),
269 PathOption('qt_lib_path', 'Path to qt library directory', None),
270 # build directory, will use $mode if not set
271 PathOption('build_dir', 'Build directory', None),
272 # extra include and libpath
273 PathOption('extra_inc_path', 'Extra include path', None),
275 PathOption('extra_lib_path', 'Extra library path', None),
277 PathOption('extra_inc_path1', 'Extra include path', None),
279 PathOption('extra_lib_path1', 'Extra library path', None),
280 # rebuild only specifed, comma separated targets
281 ('rebuild', 'rebuild only specifed, comma separated targets', None),
282 # can be set to a non-existing directory
283 ('prefix', 'install architecture-independent files in PREFIX', None),
284 # will install to dest_dir if defined. Otherwise, prefix will be used.
285 ('dest_dir', 'install to dest_dir', None),
287 ('version_suffix', 'install lyx as lyx-suffix', ''),
289 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
291 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
293 PathOption('aikasurus_path', 'Path to aikasurus library', None),
294 # environment variable can be set as options. (DO NOT set defaults)
296 ('LINK', '$LINK', None),
297 ('CPP', '$CPP', None),
298 ('CXX', '$CXX', None),
299 ('CXXCPP', '$CXXCPP', None),
300 ('CCFLAGS', '$CCFLAGS', None),
301 ('CPPFLAGS', '$CPPFLAGS', None),
302 ('LDFLAGS', '$LDFLAGS', None),
305 # whether or not use current config.h, and cached tests
306 if (not ARGUMENTS.has_key('fast_start') or \
307 ARGUMENTS['fast_start'] in ['y', 'yes', 't', 'true', '1', 'all']) \
308 and os.path.isfile(env_cache_file):
310 cache_file = open(env_cache_file)
311 env_cache = cPickle.load(cache_file)
313 print '------------ fast_start mode --------------------'
314 print ' Use cached test results and current config.h'
315 print ' use fast_start=no to override'
321 if (not ARGUMENTS.has_key('load_option') or \
322 ARGUMENTS['load_option'] in ['y', 'yes', 't', 'true', '1', 'all']) \
323 and os.path.isfile(env_cache_file):
324 cache_file = open(env_cache_file)
325 opt_cache = cPickle.load(cache_file)['arg_cache']
327 # import cached options, but we should ignore qt_dir when frontend changes
328 if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
329 and ARGUMENTS['frontend'] != opt_cache['frontend'] \
330 and opt_cache.has_key('qt_dir'):
331 opt_cache.pop('qt_dir')
332 # and we do not cache fast_start
333 if opt_cache.has_key('fast_start'):
334 opt_cache.pop('fast_start')
335 for key in opt_cache.keys():
336 if not ARGUMENTS.has_key(key):
337 ARGUMENTS[key] = opt_cache[key]
338 print "Restoring cached option %s=%s" % (key, ARGUMENTS[key])
342 env_cache['arg_cache'] = ARGUMENTS
345 #---------------------------------------------------------
346 # Setting up environment
347 #---------------------------------------------------------
349 # Note that I do not really like ENV=os.environ, but you may
350 # add it here if you experience some environment related problem
351 env = Environment(options = opts)
353 # Determine the frontend to use, which may be loaded
355 frontend = env.get('frontend', default_frontend)
356 # make sure the key exists
357 env['frontend'] = frontend
358 env['LYX_EXT'] = lyx_ext
360 use_X11 = env.get('X11', default_with_x)
361 use_vc = env.get('use_vc', False)
362 # use it only once for s scons-bug, will remove it later.
363 env['USE_VC'] = use_vc
366 # set individual variables since I do not really like ENV = os.environ
367 env['ENV']['PATH'] = os.environ.get('PATH')
368 env['ENV']['HOME'] = os.environ.get('HOME')
369 # these are defined for MSVC
370 env['ENV']['LIB'] = os.environ.get('LIB')
371 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
372 env['TOP_SRC_DIR'] = TOP_SRC_DIR
373 env['SCONS_DIR'] = SCONS_DIR
374 # install to default_prefix by default
375 env['PREFIX'] = env.get('prefix', default_prefix)
377 if env.has_key('version_suffix'):
378 env['PROGRAM_SUFFIX'] = env['version_suffix']
380 env['PROGRAM_SUFFIX'] = ''
381 env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables
382 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX'])
383 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
385 # if dest_dir is different from prefix.
386 env['DEST_DIR'] = env.get('dest_dir', env['PREFIX'])
387 if env.has_key('exec_prefix'):
388 env['BIN_DEST_DIR'] = env['exec_prefix']
390 env['BIN_DEST_DIR'] = os.path.join(env['DEST_DIR'], 'bin')
391 env['SHARE_DEST_DIR'] = os.path.join(env['DEST_DIR'], share_dir + env['PROGRAM_SUFFIX'])
392 env['MAN_DEST_DIR'] = os.path.join(env['DEST_DIR'], man_dir)
393 env['LOCALE_DEST_DIR'] = os.path.join(env['DEST_DIR'], locale_dir)
396 # this is a bit out of place (after auto-configration) but
397 # it is required to do the tests. Since Tool('mingw') will
398 # reset CCFLAGS etc, this should be done before getEnvVariable
399 if platform_name == 'win32' and not use_vc:
401 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
407 # speed up source file processing
408 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
409 #env['CXXSUFFIX'] = ['.C']
411 def getEnvVariable(env, name):
412 # first try command line argument (override environment settings)
413 if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
414 # multiple options may be passed like "-02 -g"
415 env[name] = ARGUMENTS[name].split()
416 # it does not seem necessary, but it is safer to change ['a'] back to 'a'
417 if len(env[name]) == 1:
418 env[name] = env[name][0]
419 # then use environment default
420 elif os.environ.has_key(name) and os.environ[name].strip() != '':
421 print "Acquiring varaible %s from system environment: %s" % (name, env[name])
422 env[name] = os.environ[name].split()
423 if len(env[name]) == 1:
424 env[name] = env[name][0]
425 # finally, env['CC'] etc is set to the default values of Options.
426 # and env['CPP'] etc does not exist
428 getEnvVariable(env, 'CC')
429 getEnvVariable(env, 'LINK')
430 getEnvVariable(env, 'CPP')
431 getEnvVariable(env, 'CXX')
432 getEnvVariable(env, 'CXXCPP')
433 getEnvVariable(env, 'CCFLAGS')
434 getEnvVariable(env, 'CXXFLAGS')
435 getEnvVariable(env, 'CPPFLAGS')
436 getEnvVariable(env, 'LDFLAGS')
440 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
442 env['mode'] = env.get('mode', default_build_mode)
443 # lyx will be built to $build/build_dir so it is possible
444 # to build multiple build_dirs using the same source
445 # $mode can be debug or release
446 if env.has_key('build_dir') and env['build_dir']:
447 build_dir = env['build_dir']
448 env['BUILDDIR'] = build_dir
450 # Determine the name of the build $mode
451 env['BUILDDIR'] = '#' + env['mode']
452 # all built libraries will go to build_dir/libs
453 # (This is different from the make file approach)
454 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
455 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
458 # QTDIR, QT_LIB_PATH, QT_INC_PATH
460 if env.has_key('qt_dir') and env['qt_dir']:
461 env['QTDIR'] = env['qt_dir']
462 # add path to the qt tools
463 env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
464 # set environment so that moc etc can be found even if its path is not set properly
465 env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
467 env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
469 if env.has_key('qt_lib_path') and env['qt_lib_path']:
470 env['QT_LIB_PATH'] = env['qt_lib_path']
472 env['QT_LIB_PATH'] = '$QTDIR/lib'
473 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
474 # qt4 seems to be using pkg_config
475 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
477 if env.has_key('qt_inc_path') and env['qt_inc_path']:
478 env['QT_INC_PATH'] = env['qt_inc_path']
479 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
480 env['QT_INC_PATH'] = '$QTDIR/include'
481 else: # have to guess
482 env['QT_INC_PATH'] = '/usr/include/$frontend/'
483 # Note that this CPPPATH is for testing only
484 # it will be removed before calling SConscript
485 env['CPPPATH'] = [env['QT_INC_PATH']]
488 # extra_inc_path and extra_lib_path
490 if env.has_key('extra_inc_path') and env['extra_inc_path']:
491 env.AppendUnique(CPPPATH = [env['extra_inc_path']])
492 if env.has_key('extra_lib_path') and env['extra_lib_path']:
493 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
494 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
495 env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
496 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
497 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
498 if env.has_key('aikasurus_path') and env['aikasurus_path']:
499 env.AppendUnique(LIBPATH = [env['aikasurus_path']])
502 # under windows, scons is confused by .C/.c and uses gcc instead of
503 # g++. I am forcing the use of g++ here. This is expected to change
504 # after lyx renames all .C files to .cpp
506 # Note that this step has to be after env.Tool('mingw') step
507 # since env.Tool('mingw') will set env['CC'] etc.
509 # save the old c compiler and CCFLAGS (used by libintl)
510 env['C_COMPILER'] = env.subst('$CC')
511 env['C_CCFLAGS'] = env.subst('$CCFLAGS').split()
512 # if we use ms vc, the commands are fine (cl.exe and link.exe)
514 if env.has_key('CXX') and env['CXX']:
515 env['CC'] = env.subst('$CXX')
516 env['LINK'] = env.subst('$CXX')
521 # /TP treat all source code as C++
522 # C4819: The file contains a character that cannot be represented
523 # in the current code page (number)
524 # C4996: foo was decleared deprecated
525 env.Append(CCFLAGS=['/TP', '/EHsc', '/wd4819', '/wd4996'])
526 env.Append(C_CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
529 #----------------------------------------------------------
531 #----------------------------------------------------------
533 conf = Configure(env,
535 'CheckPkgConfig' : utils.checkPkgConfig,
536 'CheckPackage' : utils.checkPackage,
537 'CheckMkdirOneArg' : utils.checkMkdirOneArg,
538 'CheckSelectArgType' : utils.checkSelectArgType,
539 'CheckBoostLibraries' : utils.checkBoostLibraries,
540 'CheckCommand' : utils.checkCommand,
541 'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd,
545 # pkg-config? (if not, we use hard-coded options)
547 if conf.CheckPkgConfig('0.15.0'):
548 env['HAS_PKG_CONFIG'] = True
550 print 'pkg-config >= 0.1.50 is not found'
551 env['HAS_PKG_CONFIG'] = False
552 env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG']
554 env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG']
556 # zlib? This is required. (fast_start assumes the existance of zlib)
558 if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \
559 or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')):
560 print 'Did not find zdll.lib or zlib.h, exiting!'
566 # qt3 does not use pkg_config
567 if frontend == 'qt3':
568 if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
569 print 'Did not find qt libraries, exiting!'
571 elif frontend == 'qt4':
573 # first: try pkg_config
574 if env['HAS_PKG_CONFIG']:
575 succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
576 env['QT4_PKG_CONFIG'] = succ
577 # second: try to link to it
579 # FIXME: under linux, I can test the following perfectly
580 # However, under windows, lib names need to passed as libXXX4.a ...
581 succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
582 conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
583 # third: try to look up the path
586 for lib in ['QtCore', 'QtGui']:
587 # windows version has something like QtGui4 ...
588 if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
589 os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
592 # still can not find it
594 print "Qt4 libraries are found."
596 print 'Did not find qt libraries, exiting!'
599 # now, if msvc2005 is used, we will need that QT_LIB_PATH/QT_LIB.manifest file
601 # glob file xxx.dll.manifest (msvc 2003 may not have it)
602 manifests = glob.glob(os.path.join(env.subst('$QT_LIB_PATH'), '*.dll.manifest'))
604 env['LINKCOM'] = [env['LINKCOM'], 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % manifests[0]]
608 env['SOCKET_LIBS'] = []
609 if conf.CheckLib('socket'):
610 env['SOCKET_LIBS'].append('socket')
612 # nsl is the network services library and provides a
613 # transport-level interface to networking services.
614 if conf.CheckLib('nsl'):
615 env['SOCKET_LIBS'].append('nsl')
617 env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
619 env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
622 # check boost libraries
623 boost_opt = ARGUMENTS.get('boost', default_boost_opt)
624 # check for system boost
626 if boost_opt in ['auto', 'system']:
627 pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
628 sig = conf.CheckBoostLibraries('boost_signals', pathes)
629 reg = conf.CheckBoostLibraries('boost_regex', pathes)
630 fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
631 ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
632 # if any of them is not found
633 if ('' in [sig[0], reg[0], fil[0], ios[0]]):
634 if boost_opt == 'system':
635 print "Can not find system boost libraries"
636 print "Please supply a path through extra_lib_path and try again."
637 print "Or use boost=included to use included boost libraries."
640 env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
641 # assume all boost libraries are in the same path...
642 env.AppendUnique(LIBPATH = [sig[0]])
643 env['INCLUDED_BOOST'] = False
645 # now, auto and succ = false, or boost=included
647 # we do not need to set LIBPATH now.
648 env['BOOST_LIBRARIES'] = ['included_boost_signals', 'included_boost_regex',
649 'included_boost_filesystem', 'included_boost_iostreams']
650 env['INCLUDED_BOOST'] = True
651 env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
652 env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
654 env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
655 env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
658 env['ENABLE_NLS'] = not env.has_key('nls') or env['nls']
661 if not env['ENABLE_NLS']:
662 env['INTL_LIBS'] = []
663 env['INCLUDED_GETTEXT'] = False
665 # check gettext libraries
666 gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt)
667 # check for system gettext
669 if gettext_opt in ['auto', 'system']:
670 if conf.CheckLib('intl'):
671 env['INCLUDED_GETTEXT'] = False
672 env['INTL_LIBS'] = ['intl']
675 if gettext_opt == 'system':
676 print "Can not find system gettext library"
677 print "Please supply a path through extra_lib_path and try again."
678 print "Or use gettext=included to use included gettext libraries."
680 # now, auto and succ = false, or gettext=included
682 # we do not need to set LIBPATH now.
683 env['INCLUDED_GETTEXT'] = True
684 env['INTL_LIBS'] = ['included_intl']
685 if platform_name == 'win32' and not use_vc:
686 # for functions AddFontResouceA, RemoveFontResourceA
687 # if use_vc, gdi32 will be added anyway later
688 env['INTL_LIBS'].append('gdi32')
689 env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT']
690 env_cache['INTL_LIBS'] = env['INTL_LIBS']
692 env['INTL_LIBS'] = env_cache['INTL_LIBS']
693 env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT']
696 # check for msgfmt command
698 env['MSGFMT'] = conf.CheckCommand('msgfmt')
699 env_cache['MSGFMT'] = env['MSGFMT']
701 env['MSGFMT'] = env_cache['MSGFMT']
704 #----------------------------------------------------------
705 # Generating config.h
706 #----------------------------------------------------------
708 print "Generating ", utils.config_h, "..."
710 # I do not handle all macros in src/config.h.in, rather I am following a list
711 # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
713 # Note: addToConfig etc are defined in scons_util
734 # for libintl % grep HAVE * | grep _H | cut -d: -f2 | sort -u
750 ('io.h', 'HAVE_IO_H', 'c'),
751 ('limits.h', 'HAVE_LIMITS_H', 'c'),
752 ('locale.h', 'HAVE_LOCALE_H', 'c'),
753 ('locale', 'HAVE_LOCALE', 'cxx'),
754 ('process.h', 'HAVE_PROCESS_H', 'c'),
755 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
756 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
757 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
758 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
759 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
760 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
761 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
762 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
763 ('utime.h', 'HAVE_UTIME_H', 'c'),
764 ('string.h', 'HAVE_STRING_H', 'c'),
765 ('strings.h', 'HAVE_STRINGS_H', 'c'),
766 ('direct.h', 'HAVE_DIRECT_H', 'c'),
767 ('istream', 'HAVE_ISTREAM', 'cxx'),
768 ('ostream', 'HAVE_OSTREAM', 'cxx'),
769 ('ios', 'HAVE_IOS', 'cxx'),
770 ('argz.h', 'HAVE_ARGZ_H', 'c'),
771 ('limits.h', 'HAVE_LIMITS_H', 'c'),
772 ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
773 ('stddef.h', 'HAVE_STDDEF_H', 'c'),
774 ('stdint.h', 'HAVE_STDINT_H', 'c'),
775 ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c')
778 for header in headers:
779 utils.addToConfig("/* Define to 1 if you have the <%s> header file. */" % header[0], newline=1)
780 if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
781 (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
782 utils.addToConfig('#define %s 1' % header[1])
784 utils.addToConfig('/* #undef %s */' % header[1])
816 # HAVE___ARGZ_STRINGIFY
826 ('open', 'HAVE_OPEN', None),
827 ('close', 'HAVE_CLOSE', None),
828 ('popen', 'HAVE_POPEN', None),
829 ('pclose', 'HAVE_PCLOSE', None),
830 ('_open', 'HAVE__OPEN', None),
831 ('_close', 'HAVE__CLOSE', None),
832 ('_popen', 'HAVE__POPEN', None),
833 ('_pclose', 'HAVE__PCLOSE', None),
834 ('getpid', 'HAVE_GETPID', None),
835 ('_getpid', 'HAVE__GETPID', None),
836 ('mkdir', 'HAVE_MKDIR', None),
837 ('_mkdir', 'HAVE__MKDIR', None),
838 ('putenv', 'HAVE_PUTENV', None),
839 ('mktemp', 'HAVE_MKTEMP', None),
840 ('mkstemp', 'HAVE_MKSTEMP', None),
841 ('strerror', 'HAVE_STRERROR', None),
842 ('count', 'HAVE_STD_COUNT', '''
847 return std::count(a, a+5, 'l');
850 ('getcwd', 'HAVE_GETCWD', None),
851 ('stpcpy', 'HAVE_STPCPY', None),
852 ('strcasecmp', 'HAVE_STRCASECMP', None),
853 ('strdup', 'HAVE_STRDUP', None),
854 ('strtoul', 'HAVE_STRTOUL', None),
855 ('alloca', 'HAVE_ALLOCA', None),
856 ('__fsetlocking', 'HAVE___FSETLOCKING', None),
857 ('mempcpy', 'HAVE_MEMPCPY', None),
858 ('__argz_count', 'HAVE___ARGZ_COUNT', None),
859 ('__argz_next', 'HAVE___ARGZ_NEXT', None),
860 ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
861 ('setlocale', 'HAVE_SETLOCALE', None),
862 ('tsearch', 'HAVE_TSEARCH', None),
863 ('getegid', 'HAVE_GETEGID', None),
864 ('getgid', 'HAVE_GETGID', None),
865 ('getuid', 'HAVE_GETUID', None),
866 ('wcslen', 'HAVE_WCSLEN', None)
875 for func in functions:
876 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
877 if conf.CheckFunc(func[0], header=func[2]):
878 utils.addToConfig('#define %s 1' % func[1])
880 utils.addToConfig('/* #undef %s */' % func[1])
883 ('asprintf', 'HAVE_ASPRINTF'),
884 ('wprintf', 'HAVE_WPRINTF'),
885 ('snprintf', 'HAVE_SNPRINTF'),
886 ('printf', 'HAVE_POSIX_PRINTF'),
887 ('fcntl', 'HAVE_FCNTL')
890 for func in env_functions:
891 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
892 if conf.CheckFunc(func[0]):
893 utils.addToConfig('#define %s 1' % func[1])
896 utils.addToConfig('/* #undef %s */' % func[1])
900 # HAVE_DECL_ISTREAMBUF_ITERATOR
901 utils.addToConfig("/* Define to 1 if you have the `intmax_t' type. */", newline=1)
902 if conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
903 conf.CheckType('intmax_t', includes='#include <inttypes.h>'):
904 utils.addToConfig('#define HAVE_INTMAX_T 1')
906 utils.addToConfig('/* #undef HAVE_INTMAX_T */')
913 # HAVE_INTTYPES_H_WITH_UINTMAX
914 # HAVE_STDINT_H_WITH_UINTMAX
917 ('intmax_t', 'HAVE_INTMAX_T', None),
918 ('long double', 'HAVE_LONG_DOUBLE', None),
919 ('long long', 'HAVE_LONG_LONG', None),
920 ('wchar_t', 'HAVE_WCHAR_T', None),
921 ('wint_t', 'HAVE_WINT_T', None),
922 ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
923 ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
924 ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
925 '#include <streambuf>\n#include <istream>')
928 utils.addToConfig("/* Define to 1 if you have the `%s' type. */" % t[0], newline=1)
929 if conf.CheckType(t[0], includes=t[2]):
930 utils.addToConfig('#define %s 1' % t[1])
932 utils.addToConfig('/* #undef %s */' % t[1])
934 # windows/msvc sys/types.h does not have pid_t
935 # FIXME: #include <windows.h> is the right way?
936 if not conf.CheckType('pid_t', includes='#include <sys/types.h>'):
937 utils.addToConfig('#define pid_t int')
939 # determine the use of std::tolower or tolower
940 if conf.CheckCXXGlobalCstd():
941 utils.addToConfig('#define CXX_GLOBAL_CSTD 1')
943 utils.addToConfig('/* #undef CXX_GLOBAL_CSTD */')
948 utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX']))
949 utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION)
951 utils.addToConfig('#define DEVEL_VERSION 1')
956 # _GLIBCXX_CONCEPT_CHECKS
958 # items are (ENV, ARGUMENTS)
960 ('ENABLE_ASSERTIONS', 'assertions'),
961 ('ENABLE_NLS', 'nls'),
962 ('WITH_WARNINGS', 'warnings'),
963 ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
967 if (env.has_key(val[0]) and env[val[0]]) or \
968 (env.has_key(val[1]) and env[val[1]]):
969 utils.addToConfig('#define %s 1' % val[0])
971 utils.addToConfig('/* #undef %s */' % val[0])
973 # disable automatic linking of boost libraries.
974 # This is an interesting feature that is supposed to be useful under
975 # windows but since I can not find a way to use it on all platforms,
976 # I disable it for now.
977 utils.addToConfig('#define BOOST_ALL_NO_LIB 1')
979 env['EXTRA_LIBS'] = []
981 # AIKSAURUS_H_LOCATION
982 if conf.CheckLib('Aiksaurus'):
983 utils.addToConfig("#define HAVE_LIBAIKSAURUS 1")
984 if (conf.CheckCXXHeader("Aiksaurus.h")):
985 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>")
986 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
987 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>")
989 utils.addToConfig("#define AIKSAURUS_H_LOCATION")
990 env['EXTRA_LIBS'].append('Aiksaurus')
996 # determine headers to use
997 spell_engine = ARGUMENTS.get('spell', 'auto')
998 spell_detected = False
999 if spell_engine in ['auto', 'aspell'] and \
1000 conf.CheckLib('aspell'):
1001 utils.addToConfig('#define USE_ASPELL 1')
1002 env['USE_ASPELL'] = True
1003 env['USE_PSPELL'] = False
1004 env['USE_ISPELL'] = False
1005 env['EXTRA_LIBS'].append('aspell')
1006 spell_detected = True
1007 elif spell_engine in ['auto', 'pspell'] and \
1008 conf.CheckLib('pspell'):
1009 utils.addToConfig('#define USE_PSPELL 1')
1010 env['USE_ASPELL'] = False
1011 env['USE_PSPELL'] = True
1012 env['USE_ISPELL'] = False
1013 env['EXTRA_LIBS'].append('pspell')
1014 spell_detected = True
1015 elif spell_engine in ['auto', 'ispell'] and \
1016 conf.CheckLib('ispell'):
1017 utils.addToConfig('#define USE_ISPELL 1')
1018 env['USE_ASPELL'] = False
1019 env['USE_PSPELL'] = False
1020 env['USE_ISPELL'] = True
1021 env['EXTRA_LIBS'].append('ispell')
1022 spell_detected = True
1024 if not spell_detected:
1025 env['USE_ASPELL'] = False
1026 env['USE_PSPELL'] = False
1027 env['USE_ISPELL'] = False
1028 # FIXME: can lyx work without an spell engine
1029 if spell_engine == 'auto':
1030 print "Warning: Can not locate any spell checker"
1032 print "Warning: Can not locate specified spell checker:", spell_engine
1034 # USE_POSIX_PACKAGING
1035 # USE_MACOSX_PACKAGING
1036 # USE_WINDOWS_PACKAGING
1037 if packaging_method == 'windows':
1038 utils.addToConfig('#define USE_WINDOWS_PACKAGING 1')
1039 elif packaging_method == 'posix':
1040 utils.addToConfig('#define USE_POSIX_PACKAGING 1')
1041 elif packaging_method == 'mac':
1042 utils.addToConfig('#define USE_MACOSX_PACKAGING 1')
1046 utils.addToConfig('#define BOOST_POSIX 1')
1048 utils.addToConfig('/* #undef BOOST_POSIX */')
1050 # MKDIR_TAKES_ONE_ARG
1051 if conf.CheckMkdirOneArg():
1052 utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1')
1054 utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */')
1057 # SELECT_TYPE_ARG234
1059 (arg1, arg234, arg5) = conf.CheckSelectArgType()
1060 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1)
1061 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234)
1062 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5)
1066 # WANT_GETFILEATTRIBUTESEX_WRAPPER
1067 utils.endConfigH(TOP_SRC_DIR)
1069 # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed
1070 # NOTE that we do *not* save qt_libs in environment.
1071 env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS'])
1072 env_cache['USE_ASPELL'] = env['USE_ASPELL']
1073 env_cache['USE_PSPELL'] = env['USE_PSPELL']
1074 env_cache['USE_ISPELL'] = env['USE_ISPELL']
1075 env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF']
1076 env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF']
1077 env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF']
1078 env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF']
1079 env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL']
1083 # this comes as a big surprise, without this line
1084 # (doing nothing obvious), adding fast_start=yes
1085 # to a build with fast_start=no will result in a rebuild
1086 # Note that the exact header file to check does not matter
1087 conf.CheckCHeader('io.h')
1088 # only a few variables need to be rescanned
1089 env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
1090 env['USE_ASPELL'] = env_cache['USE_ASPELL']
1091 env['USE_PSPELL'] = env_cache['USE_PSPELL']
1092 env['USE_ISPELL'] = env_cache['USE_ISPELL']
1093 env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF']
1094 env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF']
1095 env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF']
1096 env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF']
1097 env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL']
1100 # Finish auto-configuration
1103 #----------------------------------------------------------
1104 # Now set up our build process accordingly
1105 #----------------------------------------------------------
1108 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
1110 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
1111 # in their respective directory and specialized env.
1113 if frontend == 'qt3':
1114 # note: env.Tool('qt') my set QT_LIB to qt
1115 env['QT_LIB'] = 'qt-mt'
1116 env['EXTRA_LIBS'].append('qt-mt')
1117 if platform_name == 'cygwin' and use_X11:
1118 env['EXTRA_LIBS'].extend(['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
1119 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
1121 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1122 elif frontend == 'qt4':
1123 if platform_name == "win32":
1124 env['QT_LIB'] = ['QtCore4', 'QtGui4']
1126 env['QT_LIB'] = ['QtCore', 'QtGui']
1127 env['EXTRA_LIBS'] += env['QT_LIB']
1129 print "Can not locate qt tools"
1130 print "What I get is "
1131 print " QTDIR: ", env['QTDIR']
1134 if platform_name in ['win32', 'cygwin']:
1135 # the final link step needs stdc++ to succeed under mingw
1136 # FIXME: shouldn't g++ automatically link to stdc++?
1138 env['SYSTEM_LIBS'] = ['shlwapi', 'gdi32', 'shell32', 'advapi32', 'zdll']
1140 env['SYSTEM_LIBS'] = ['shlwapi', 'stdc++', 'z']
1142 env['SYSTEM_LIBS'] = ['z']
1145 # Build parameters CPPPATH etc
1147 # boost is always in, src is needed for config.h
1149 # QT_INC_PATH is not needed for *every* source file
1150 env['CPPPATH'].remove(env['QT_INC_PATH'])
1151 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
1153 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
1154 # for debug/release mode
1155 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
1156 env.AppendUnique(CCFLAGS = [])
1158 env.AppendUnique(CCFLAGS = [])
1161 # Customized builders
1163 # install customized builders
1164 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
1167 # A Link script for cygwin see
1168 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1169 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1172 if platform_name == 'cygwin':
1173 ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
1174 ld_script = utils.installCygwinLDScript(ld_script_path)
1175 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1176 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1181 # src/support/package.C.in needs the following to replace
1182 # LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
1183 env['LYX_DIR'] = env['SHARE_DIR']
1184 # LYX_ABS_INSTALLED_LOCALEDIR
1185 env['LOCALEDIR'] = env['LOCALE_DIR']
1186 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
1187 # needed by src/version.C.in => src/version.C
1188 env['PACKAGE_VERSION'] = PACKAGE_VERSION
1189 # fill in the version info
1190 env['VERSION_INFO'] = '''Configuration
1192 Special build flags: %s
1194 C Compiler flags: %s %s
1196 C++ Compiler LyX flags: %s
1197 C++ Compiler flags: %s %s
1199 Linker user flags: %s
1201 Builing directory: %s
1202 Local library directory: %s
1203 Libraries pathes: %s
1206 System libraries: %s
1207 include search path: %s
1214 ''' % (platform_name,
1215 env.subst('$CCFLAGS'), env.subst('$CC'),
1216 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1217 env.subst('$CXX'), env.subst('$CXXFLAGS'),
1218 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1219 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1220 env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1221 str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
1222 str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
1223 env['frontend'], packaging_method,
1224 env['PREFIX'], env['BIN_DEST_DIR'], env['SHARE_DIR'])
1226 if env['frontend'] in ['qt3', 'qt4']:
1227 env['VERSION_INFO'] += ''' include dir: %s
1230 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
1233 print env['VERSION_INFO']
1236 # Mingw command line may be too short for our link usage,
1237 # Here we use a trick from scons wiki
1238 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1240 # I also would like to add logging (commands only) capacity to the
1242 logfile = env.get('logfile', default_log_file)
1243 if logfile != '' or platform_name == 'win32':
1245 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1246 info = '''# This is a log of commands used by scons to build lyx
1250 ''' % (time.asctime(), ' '.join(sys.argv),
1251 env['VERSION_INFO'].replace('\n','\n# ')) )
1257 # -h will print out help info
1258 Help(opts.GenerateHelpText(env))
1259 # save environment settings (for fast_start option)
1260 cache_file = open(env_cache_file, 'w')
1261 cPickle.dump(env_cache, cache_file)
1264 #----------------------------------------------------------
1266 #----------------------------------------------------------
1269 # this has been the source of problems on some platforms...
1270 # I find that I need to supply it with full path name
1271 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1272 # this usage needs further investigation.
1273 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1275 env['BUILD_TARGETS'] = BUILD_TARGETS
1276 if env.has_key('rebuild'):
1277 env['REBUILD_TARGETS'] = env['rebuild'].split(',')
1279 env['REBUILD_TARGETS'] = None
1281 print "Building all targets recursively"
1283 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)