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),
244 BoolOption('load_option', 'load option from previous scons run', True),
245 # FIXME: I do not know how pch is working. Ignore this option now.
246 BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
247 # enable assertion, (config.h has ENABLE_ASSERTIOS
248 BoolOption('assertions', 'Use assertions', True),
249 # enable warning, (config.h has WITH_WARNINGS)
250 BoolOption('warnings', 'Use warnings', True),
251 # enable glib, (config.h has _GLIBCXX_CONCEPT_CHECKS)
252 BoolOption('concept_checks', 'Enable concept checks', True),
254 BoolOption('nls', 'Whether or not use native language support', True),
255 # FIXME: not implemented
256 BoolOption('profile', '(NA) Whether or not enable profiling', False),
257 # FIXME: not implemented
258 BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
260 BoolOption('X11', 'Use x11 windows system', default_with_x),
261 # use MS VC++ to build lyx
262 BoolOption('use_vc', 'Use MS VC++ to build lyx', False),
264 PathOption('qt_dir', 'Path to qt directory', None),
266 PathOption('qt_include_path', 'Path to qt include directory', None),
268 PathOption('qt_lib_path', 'Path to qt library directory', None),
269 # build directory, will use $mode if not set
270 PathOption('build_dir', 'Build directory', None),
271 # extra include and libpath
272 PathOption('extra_inc_path', 'Extra include path', None),
274 PathOption('extra_lib_path', 'Extra library path', None),
276 PathOption('extra_inc_path1', 'Extra include path', None),
278 PathOption('extra_lib_path1', 'Extra library path', None),
279 # rebuild only specifed, comma separated targets
280 ('rebuild', 'rebuild only specifed, comma separated targets', None),
281 # can be set to a non-existing directory
282 ('prefix', 'install architecture-independent files in PREFIX', None),
283 # will install to dest_dir if defined. Otherwise, prefix will be used.
284 ('dest_dir', 'install to dest_dir', None),
286 ('version_suffix', 'install lyx as lyx-suffix', ''),
288 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
290 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
292 PathOption('aikasurus_path', 'Path to aikasurus library', None),
293 # environment variable can be set as options. (DO NOT set defaults)
295 ('LINK', '$LINK', None),
296 ('CPP', '$CPP', None),
297 ('CXX', '$CXX', None),
298 ('CXXCPP', '$CXXCPP', None),
299 ('CCFLAGS', '$CCFLAGS', None),
300 ('CPPFLAGS', '$CPPFLAGS', None),
301 ('LDFLAGS', '$LDFLAGS', None),
304 # whether or not use current config.h, and cached tests
305 if (not ARGUMENTS.has_key('fast_start') or \
306 ARGUMENTS['fast_start'] in ['y', 'yes', 't', 'true', '1', 'all']) \
307 and os.path.isfile(env_cache_file):
309 cache_file = open(env_cache_file)
310 env_cache = cPickle.load(cache_file)
312 print '------------ fast_start mode --------------------'
313 print ' Use cached test results and current config.h'
314 print ' use fast_start=no to override'
320 if (not ARGUMENTS.has_key('load_option') or \
321 ARGUMENTS['load_option'] in ['y', 'yes', 't', 'true', '1', 'all']) \
322 and os.path.isfile(env_cache_file):
323 cache_file = open(env_cache_file)
324 opt_cache = cPickle.load(cache_file)['arg_cache']
326 # import cached options, but we should ignore qt_dir when frontend changes
327 if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
328 and ARGUMENTS['frontend'] != opt_cache['frontend'] \
329 and opt_cache.has_key('qt_dir'):
330 opt_cache.pop('qt_dir')
331 # and we do not cache fast_start
332 if opt_cache.has_key('fast_start'):
333 opt_cache.pop('fast_start')
334 for key in opt_cache.keys():
335 if not ARGUMENTS.has_key(key):
336 ARGUMENTS[key] = opt_cache[key]
337 print "Restoring cached option %s=%s" % (key, ARGUMENTS[key])
341 env_cache['arg_cache'] = ARGUMENTS
344 #---------------------------------------------------------
345 # Setting up environment
346 #---------------------------------------------------------
348 # Note that I do not really like ENV=os.environ, but you may
349 # add it here if you experience some environment related problem
350 env = Environment(options = opts)
352 # Determine the frontend to use, which may be loaded
354 frontend = env.get('frontend', default_frontend)
355 # make sure the key exists
356 env['frontend'] = frontend
358 use_X11 = env.get('X11', default_with_x)
359 use_vc = env.get('use_vc', False)
360 # use it only once for s scons-bug, will remove it later.
361 env['USE_VC'] = use_vc
364 # set individual variables since I do not really like ENV = os.environ
365 env['ENV']['PATH'] = os.environ.get('PATH')
366 env['ENV']['HOME'] = os.environ.get('HOME')
367 # these are defined for MSVC
368 env['ENV']['LIB'] = os.environ.get('LIB')
369 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
370 env['TOP_SRC_DIR'] = TOP_SRC_DIR
371 env['SCONS_DIR'] = SCONS_DIR
372 # install to default_prefix by default
373 env['PREFIX'] = env.get('prefix', default_prefix)
375 if env.has_key('version_suffix'):
376 env['PROGRAM_SUFFIX'] = env['version_suffix']
378 env['PROGRAM_SUFFIX'] = ''
379 env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables
380 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX'])
381 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
383 # if dest_dir is different from prefix.
384 env['DEST_DIR'] = env.get('dest_dir', env['PREFIX'])
385 if env.has_key('exec_prefix'):
386 env['BIN_DEST_DIR'] = env['exec_prefix']
388 env['BIN_DEST_DIR'] = os.path.join(env['DEST_DIR'], 'bin')
389 env['SHARE_DEST_DIR'] = os.path.join(env['DEST_DIR'], share_dir + env['PROGRAM_SUFFIX'])
390 env['MAN_DEST_DIR'] = os.path.join(env['DEST_DIR'], man_dir)
391 env['LOCALE_DEST_DIR'] = os.path.join(env['DEST_DIR'], locale_dir)
394 # this is a bit out of place (after auto-configration) but
395 # it is required to do the tests. Since Tool('mingw') will
396 # reset CCFLAGS etc, this should be done before getEnvVariable
397 if platform_name == 'win32' and not use_vc:
399 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
405 # speed up source file processing
406 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
407 #env['CXXSUFFIX'] = ['.C']
409 def getEnvVariable(env, name):
410 # first try command line argument (override environment settings)
411 if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
412 # multiple options may be passed like "-02 -g"
413 env[name] = ARGUMENTS[name].split()
414 # it does not seem necessary, but it is safer to change ['a'] back to 'a'
415 if len(env[name]) == 1:
416 env[name] = env[name][0]
417 # then use environment default
418 elif os.environ.has_key(name) and os.environ[name].strip() != '':
419 print "Acquiring varaible %s from system environment: %s" % (name, env[name])
420 env[name] = os.environ[name].split()
421 if len(env[name]) == 1:
422 env[name] = env[name][0]
423 # finally, env['CC'] etc is set to the default values of Options.
424 # and env['CPP'] etc does not exist
426 getEnvVariable(env, 'CC')
427 getEnvVariable(env, 'LINK')
428 getEnvVariable(env, 'CPP')
429 getEnvVariable(env, 'CXX')
430 getEnvVariable(env, 'CXXCPP')
431 getEnvVariable(env, 'CCFLAGS')
432 getEnvVariable(env, 'CXXFLAGS')
433 getEnvVariable(env, 'CPPFLAGS')
434 getEnvVariable(env, 'LDFLAGS')
438 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
440 env['mode'] = env.get('mode', default_build_mode)
441 # lyx will be built to $build/build_dir so it is possible
442 # to build multiple build_dirs using the same source
443 # $mode can be debug or release
444 if env.has_key('build_dir') and env['build_dir']:
445 build_dir = env['build_dir']
446 env['BUILDDIR'] = build_dir
448 # Determine the name of the build $mode
449 env['BUILDDIR'] = '#' + env['mode']
450 # all built libraries will go to build_dir/libs
451 # (This is different from the make file approach)
452 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
453 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
456 # QTDIR, QT_LIB_PATH, QT_INC_PATH
458 if env.has_key('qt_dir') and env['qt_dir']:
459 env['QTDIR'] = env['qt_dir']
460 # add path to the qt tools
461 env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
462 # set environment so that moc etc can be found even if its path is not set properly
463 env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
465 env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
467 if env.has_key('qt_lib_path') and env['qt_lib_path']:
468 env['QT_LIB_PATH'] = env['qt_lib_path']
470 env['QT_LIB_PATH'] = '$QTDIR/lib'
471 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
472 # qt4 seems to be using pkg_config
473 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
475 if env.has_key('qt_inc_path') and env['qt_inc_path']:
476 env['QT_INC_PATH'] = env['qt_inc_path']
477 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
478 env['QT_INC_PATH'] = '$QTDIR/include'
479 else: # have to guess
480 env['QT_INC_PATH'] = '/usr/include/$frontend/'
481 # Note that this CPPPATH is for testing only
482 # it will be removed before calling SConscript
483 env['CPPPATH'] = [env['QT_INC_PATH']]
486 # extra_inc_path and extra_lib_path
488 if env.has_key('extra_inc_path') and env['extra_inc_path']:
489 env.AppendUnique(CPPPATH = [env['extra_inc_path']])
490 if env.has_key('extra_lib_path') and env['extra_lib_path']:
491 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
492 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
493 env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
494 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
495 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
496 if env.has_key('aikasurus_path') and env['aikasurus_path']:
497 env.AppendUnique(LIBPATH = [env['aikasurus_path']])
500 # under windows, scons is confused by .C/.c and uses gcc instead of
501 # g++. I am forcing the use of g++ here. This is expected to change
502 # after lyx renames all .C files to .cpp
504 # Note that this step has to be after env.Tool('mingw') step
505 # since env.Tool('mingw') will set env['CC'] etc.
507 # save the old c compiler and CCFLAGS (used by libintl)
508 env['C_COMPILER'] = env.subst('$CC')
509 env['C_CCFLAGS'] = env.subst('$CCFLAGS')
510 # if we use ms vc, the commands are fine (cl.exe and link.exe)
512 if env.has_key('CXX') and env['CXX']:
513 env['CC'] = env.subst('$CXX')
514 env['LINK'] = env.subst('$CXX')
519 # /TP treat all source code as C++
520 # C4819: The file contains a character that cannot be represented
521 # in the current code page (number)
522 # C4996: foo was decleared deprecated
523 env.Append(CCFLAGS=['/TP', '/EHsc', '/wd4819', '/wd4996'])
524 env['LINKFLAGS'] = [env['LINKFLAGS'], '/MANIFEST']
525 env['LINKCOM' ] = [env['LINKCOM'], 'mt /manifest ${TARGET}.manifest /outputresource:$TARGET']
526 env['SHLINKCOM'] = [env['SHLINKCOM'], 'mt /manifest ${TARGET}.manifest -outputresource:$TARGET;#2']
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!'
602 env['SOCKET_LIBS'] = []
603 if conf.CheckLib('socket'):
604 env['SOCKET_LIBS'].append('socket')
606 # nsl is the network services library and provides a
607 # transport-level interface to networking services.
608 if conf.CheckLib('nsl'):
609 env['SOCKET_LIBS'].append('nsl')
611 env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
613 env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
616 # check boost libraries
617 boost_opt = ARGUMENTS.get('boost', default_boost_opt)
618 # check for system boost
620 if boost_opt in ['auto', 'system']:
621 pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
622 sig = conf.CheckBoostLibraries('boost_signals', pathes)
623 reg = conf.CheckBoostLibraries('boost_regex', pathes)
624 fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
625 ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
626 # if any of them is not found
627 if ('' in [sig[0], reg[0], fil[0], ios[0]]):
628 if boost_opt == 'system':
629 print "Can not find system boost libraries"
630 print "Please supply a path through extra_lib_path and try again."
631 print "Or use boost=included to use included boost libraries."
634 env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
635 # assume all boost libraries are in the same path...
636 env.AppendUnique(LIBPATH = [sig[0]])
637 env['INCLUDED_BOOST'] = False
639 # now, auto and succ = false, or boost=included
641 # we do not need to set LIBPATH now.
642 env['BOOST_LIBRARIES'] = ['included_boost_signals', 'included_boost_regex',
643 'included_boost_filesystem', 'included_boost_iostreams']
644 env['INCLUDED_BOOST'] = True
645 env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
646 env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
648 env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
649 env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
652 env['ENABLE_NLS'] = not env.has_key('nls') or env['nls']
655 if not env['ENABLE_NLS']:
656 env['INTL_LIBS'] = []
657 env['INCLUDED_GETTEXT'] = False
659 # check gettext libraries
660 gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt)
661 # check for system gettext
663 if gettext_opt in ['auto', 'system']:
664 if conf.CheckLib('intl'):
665 env['INCLUDED_GETTEXT'] = False
666 env['INTL_LIBS'] = ['intl']
669 if gettext_opt == 'system':
670 print "Can not find system gettext library"
671 print "Please supply a path through extra_lib_path and try again."
672 print "Or use gettext=included to use included gettext libraries."
674 # now, auto and succ = false, or gettext=included
676 # we do not need to set LIBPATH now.
677 env['INCLUDED_GETTEXT'] = True
678 env['INTL_LIBS'] = ['included_intl']
679 if platform_name == 'win32' and not use_vc:
680 # for functions AddFontResouceA, RemoveFontResourceA
681 # if use_vc, gdi32 will be added anyway later
682 env['INTL_LIBS'].append('gdi32')
683 env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT']
684 env_cache['INTL_LIBS'] = env['INTL_LIBS']
686 env['INTL_LIBS'] = env_cache['INTL_LIBS']
687 env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT']
690 # check for msgfmt command
692 env['MSGFMT'] = conf.CheckCommand('msgfmt')
693 env_cache['MSGFMT'] = env['MSGFMT']
695 env['MSGFMT'] = env_cache['MSGFMT']
698 #----------------------------------------------------------
699 # Generating config.h
700 #----------------------------------------------------------
702 print "Generating ", utils.config_h, "..."
704 # I do not handle all macros in src/config.h.in, rather I am following a list
705 # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
707 # Note: addToConfig etc are defined in scons_util
728 # for libintl % grep HAVE * | grep _H | cut -d: -f2 | sort -u
730 # HAVE_STDINT_H_WITH_UINTMAX
731 # HAVE_INTTYPES_H_WITH_UINTMAX
746 ('io.h', 'HAVE_IO_H', 'c'),
747 ('limits.h', 'HAVE_LIMITS_H', 'c'),
748 ('locale.h', 'HAVE_LOCALE_H', 'c'),
749 ('locale', 'HAVE_LOCALE', 'cxx'),
750 ('process.h', 'HAVE_PROCESS_H', 'c'),
751 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
752 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
753 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
754 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
755 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
756 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
757 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
758 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
759 ('utime.h', 'HAVE_UTIME_H', 'c'),
760 ('string.h', 'HAVE_STRING_H', 'c'),
761 ('strings.h', 'HAVE_STRINGS_H', 'c'),
762 ('direct.h', 'HAVE_DIRECT_H', 'c'),
763 ('istream', 'HAVE_ISTREAM', 'cxx'),
764 ('ostream', 'HAVE_OSTREAM', 'cxx'),
765 ('ios', 'HAVE_IOS', 'cxx'),
766 ('argz.h', 'HAVE_ARGZ_H', 'c'),
767 ('limits.h', 'HAVE_LIMITS_H', 'c'),
768 ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
769 ('stddef.h', 'HAVE_STDDEF_H', 'c'),
770 ('stdint.h', 'HAVE_STDINT_H', 'c'),
771 ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c')
774 for header in headers:
775 utils.addToConfig("/* Define to 1 if you have the <%s> header file. */" % header[0], newline=1)
776 if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
777 (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
778 utils.addToConfig('#define %s 1' % header[1])
780 utils.addToConfig('/* #undef %s */' % header[1])
812 # HAVE___ARGZ_STRINGIFY
822 ('open', 'HAVE_OPEN', None),
823 ('close', 'HAVE_CLOSE', None),
824 ('popen', 'HAVE_POPEN', None),
825 ('pclose', 'HAVE_PCLOSE', None),
826 ('_open', 'HAVE__OPEN', None),
827 ('_close', 'HAVE__CLOSE', None),
828 ('_popen', 'HAVE__POPEN', None),
829 ('_pclose', 'HAVE__PCLOSE', None),
830 ('getpid', 'HAVE_GETPID', None),
831 ('_getpid', 'HAVE__GETPID', None),
832 ('mkdir', 'HAVE_MKDIR', None),
833 ('_mkdir', 'HAVE__MKDIR', None),
834 ('putenv', 'HAVE_PUTENV', None),
835 ('mktemp', 'HAVE_MKTEMP', None),
836 ('mkstemp', 'HAVE_MKSTEMP', None),
837 ('strerror', 'HAVE_STRERROR', None),
838 ('count', 'HAVE_STD_COUNT', '''
843 return std::count(a, a+5, 'l');
846 ('getcwd', 'HAVE_GETCWD', None),
847 ('stpcpy', 'HAVE_STPCPY', None),
848 ('strcasecmp', 'HAVE_STRCASECMP', None),
849 ('strdup', 'HAVE_STRDUP', None),
850 ('strtoul', 'HAVE_STRTOUL', None),
851 ('alloca', 'HAVE_ALLOCA', None),
852 ('__fsetlocking', 'HAVE___FSETLOCKING', None),
853 ('mempcpy', 'HAVE_MEMPCPY', None),
854 ('__argz_count', 'HAVE___ARGZ_COUNT', None),
855 ('__argz_next', 'HAVE___ARGZ_NEXT', None),
856 ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
857 ('setlocale', 'HAVE_SETLOCALE', None),
858 ('tsearch', 'HAVE_TSEARCH', None),
859 ('getegid', 'HAVE_GETEGID', None),
860 ('getgid', 'HAVE_GETGID', None),
861 ('getuid', 'HAVE_GETUID', None),
862 ('wcslen', 'HAVE_WCSLEN', None)
871 for func in functions:
872 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
873 if conf.CheckFunc(func[0], header=func[2]):
874 utils.addToConfig('#define %s 1' % func[1])
876 utils.addToConfig('/* #undef %s */' % func[1])
879 ('asprintf', 'HAVE_ASPRINTF'),
880 ('wprintf', 'HAVE_WPRINTF'),
881 ('snprintf', 'HAVE_SNPRINTF'),
882 ('printf', 'HAVE_POSIX_PRINTF'),
883 ('fcntl', 'HAVE_FCNTL')
886 for func in env_functions:
887 utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1)
888 if conf.CheckFunc(func[0]):
889 utils.addToConfig('#define %s 1' % func[1])
892 utils.addToConfig('/* #undef %s */' % func[1])
896 # HAVE_INTTYPES_H_WITH_UINTMAX
897 # HAVE_DECL_ISTREAMBUF_ITERATOR
898 utils.addToConfig("/* Define to 1 if you have the `intmax_t' type. */", newline=1)
899 if conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
900 conf.CheckType('intmax_t', includes='#include <inttypes.h>'):
901 utils.addToConfig('#define HAVE_INTMAX_T 1')
903 utils.addToConfig('/* #undef HAVE_INTMAX_T */')
910 # HAVE_INTTYPES_H_WITH_UINTMAX
913 ('intmax_t', 'HAVE_INTMAX_T', None),
914 ('long double', 'HAVE_LONG_DOUBLE', None),
915 ('long long', 'HAVE_LONG_LONG', None),
916 ('wchar_t', 'HAVE_WCHAR_T', None),
917 ('wint_t', 'HAVE_WINT_T', None),
918 ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
919 ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
920 '#include <streambuf>\n#include <istream>')
923 utils.addToConfig("/* Define to 1 if you have the `%s' type. */" % t[0], newline=1)
924 if conf.CheckType(t[0], includes=t[2]):
925 utils.addToConfig('#define %s 1' % t[1])
927 utils.addToConfig('/* #undef %s */' % t[1])
929 # windows/msvc sys/types.h does not have pid_t
930 # FIXME: #include <windows.h> is the right way?
931 if not conf.CheckType('pid_t', includes='#include <sys/types.h>'):
932 utils.addToConfig('#define pid_t int')
934 # determine the use of std::tolower or tolower
935 if conf.CheckCXXGlobalCstd():
936 utils.addToConfig('#define CXX_GLOBAL_CSTD 1')
938 utils.addToConfig('/* #undef CXX_GLOBAL_CSTD */')
943 utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX']))
944 utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION)
946 utils.addToConfig('#define DEVEL_VERSION 1')
951 # _GLIBCXX_CONCEPT_CHECKS
953 # items are (ENV, ARGUMENTS)
955 ('ENABLE_ASSERTIONS', 'assertions'),
956 ('ENABLE_NLS', 'nls'),
957 ('WITH_WARNINGS', 'warnings'),
958 ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
962 if (env.has_key(val[0]) and env[val[0]]) or \
963 (env.has_key(val[1]) and env[val[1]]):
964 utils.addToConfig('#define %s 1' % val[0])
966 utils.addToConfig('/* #undef %s */' % val[0])
968 # disable automatic linking of boost libraries.
969 # This is an interesting feature that is supposed to be useful under
970 # windows but since I can not find a way to use it on all platforms,
971 # I disable it for now.
972 utils.addToConfig('#define BOOST_ALL_NO_LIB 1')
974 env['EXTRA_LIBS'] = []
976 # AIKSAURUS_H_LOCATION
977 if conf.CheckLib('Aiksaurus'):
978 utils.addToConfig("#define HAVE_LIBAIKSAURUS 1")
979 if (conf.CheckCXXHeader("Aiksaurus.h")):
980 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>")
981 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
982 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>")
984 utils.addToConfig("#define AIKSAURUS_H_LOCATION")
985 env['EXTRA_LIBS'].append('Aiksaurus')
991 # determine headers to use
992 spell_engine = ARGUMENTS.get('spell', 'auto')
993 spell_detected = False
994 if spell_engine in ['auto', 'aspell'] and \
995 conf.CheckLib('aspell'):
996 utils.addToConfig('#define USE_ASPELL 1')
997 env['USE_ASPELL'] = True
998 env['USE_PSPELL'] = False
999 env['USE_ISPELL'] = False
1000 env['EXTRA_LIBS'].append('aspell')
1001 spell_detected = True
1002 elif spell_engine in ['auto', 'pspell'] and \
1003 conf.CheckLib('pspell'):
1004 utils.addToConfig('#define USE_PSPELL 1')
1005 env['USE_ASPELL'] = False
1006 env['USE_PSPELL'] = True
1007 env['USE_ISPELL'] = False
1008 env['EXTRA_LIBS'].append('pspell')
1009 spell_detected = True
1010 elif spell_engine in ['auto', 'ispell'] and \
1011 conf.CheckLib('ispell'):
1012 utils.addToConfig('#define USE_ISPELL 1')
1013 env['USE_ASPELL'] = False
1014 env['USE_PSPELL'] = False
1015 env['USE_ISPELL'] = True
1016 env['EXTRA_LIBS'].append('ispell')
1017 spell_detected = True
1019 if not spell_detected:
1020 env['USE_ASPELL'] = False
1021 env['USE_PSPELL'] = False
1022 env['USE_ISPELL'] = False
1023 # FIXME: can lyx work without an spell engine
1024 if spell_engine == 'auto':
1025 print "Warning: Can not locate any spell checker"
1027 print "Warning: Can not locate specified spell checker:", spell_engine
1029 # USE_POSIX_PACKAGING
1030 # USE_MACOSX_PACKAGING
1031 # USE_WINDOWS_PACKAGING
1032 if packaging_method == 'windows':
1033 utils.addToConfig('#define USE_WINDOWS_PACKAGING 1')
1034 elif packaging_method == 'posix':
1035 utils.addToConfig('#define USE_POSIX_PACKAGING 1')
1036 elif packaging_method == 'mac':
1037 utils.addToConfig('#define USE_MACOSX_PACKAGING 1')
1041 utils.addToConfig('#define BOOST_POSIX 1')
1043 utils.addToConfig('/* #undef BOOST_POSIX */')
1045 # MKDIR_TAKES_ONE_ARG
1046 if conf.CheckMkdirOneArg():
1047 utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1')
1049 utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */')
1052 # SELECT_TYPE_ARG234
1054 (arg1, arg234, arg5) = conf.CheckSelectArgType()
1055 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1)
1056 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234)
1057 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5)
1061 # WANT_GETFILEATTRIBUTESEX_WRAPPER
1062 utils.endConfigH(TOP_SRC_DIR)
1064 # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed
1065 # NOTE that we do *not* save qt_libs in environment.
1066 env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS'])
1067 env_cache['USE_ASPELL'] = env['USE_ASPELL']
1068 env_cache['USE_PSPELL'] = env['USE_PSPELL']
1069 env_cache['USE_ISPELL'] = env['USE_ISPELL']
1070 env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF']
1071 env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF']
1072 env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF']
1073 env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF']
1074 env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL']
1078 # this comes as a big surprise, without this line
1079 # (doing nothing obvious), adding fast_start=yes
1080 # to a build with fast_start=no will result in a rebuild
1081 # Note that the exact header file to check does not matter
1082 conf.CheckCHeader('io.h')
1083 # only a few variables need to be rescanned
1084 env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
1085 env['USE_ASPELL'] = env_cache['USE_ASPELL']
1086 env['USE_PSPELL'] = env_cache['USE_PSPELL']
1087 env['USE_ISPELL'] = env_cache['USE_ISPELL']
1088 env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF']
1089 env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF']
1090 env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF']
1091 env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF']
1092 env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL']
1095 # Finish auto-configuration
1098 #----------------------------------------------------------
1099 # Now set up our build process accordingly
1100 #----------------------------------------------------------
1103 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
1105 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
1106 # in their respective directory and specialized env.
1108 if frontend == 'qt3':
1109 # note: env.Tool('qt') my set QT_LIB to qt
1110 env['QT_LIB'] = 'qt-mt'
1111 env['EXTRA_LIBS'].append('qt-mt')
1112 if platform_name == 'cygwin' and use_X11:
1113 env['EXTRA_LIBS'].extend(['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
1114 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
1116 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1117 elif frontend == 'qt4':
1118 if platform_name == "win32":
1119 env['QT_LIB'] = ['QtCore4', 'QtGui4']
1121 env['QT_LIB'] = ['QtCore', 'QtGui']
1122 env['EXTRA_LIBS'] += env['QT_LIB']
1124 print "Can not locate qt tools"
1125 print "What I get is "
1126 print " QTDIR: ", env['QTDIR']
1129 if platform_name in ['win32', 'cygwin']:
1130 # the final link step needs stdc++ to succeed under mingw
1131 # FIXME: shouldn't g++ automatically link to stdc++?
1133 env['SYSTEM_LIBS'] = ['shlwapi', 'gdi32', 'shell32', 'advapi32', 'zdll']
1135 env['SYSTEM_LIBS'] = ['shlwapi', 'stdc++', 'z']
1137 env['SYSTEM_LIBS'] = ['z']
1140 # Build parameters CPPPATH etc
1142 # boost is always in, src is needed for config.h
1144 # QT_INC_PATH is not needed for *every* source file
1145 env['CPPPATH'].remove(env['QT_INC_PATH'])
1146 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
1148 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
1149 # for debug/release mode
1150 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
1151 env.AppendUnique(CCFLAGS = [])
1153 env.AppendUnique(CCFLAGS = [])
1156 # Customized builders
1158 # install customized builders
1159 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
1162 # A Link script for cygwin see
1163 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1164 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1167 if platform_name == 'cygwin':
1168 ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
1169 ld_script = utils.installCygwinLDScript(ld_script_path)
1170 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1171 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1176 # src/support/package.C.in needs the following to replace
1177 # LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
1178 env['LYX_DIR'] = env['SHARE_DIR']
1179 # LYX_ABS_INSTALLED_LOCALEDIR
1180 env['LOCALEDIR'] = env['LOCALE_DIR']
1181 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
1182 # needed by src/version.C.in => src/version.C
1183 env['PACKAGE_VERSION'] = PACKAGE_VERSION
1184 # fill in the version info
1185 env['VERSION_INFO'] = '''Configuration
1187 Special build flags: %s
1189 C Compiler flags: %s %s
1191 C++ Compiler LyX flags: %s
1192 C++ Compiler flags: %s %s
1194 Linker user flags: %s
1196 Builing directory: %s
1197 Local library directory: %s
1198 Libraries pathes: %s
1201 System libraries: %s
1202 include search path: %s
1209 ''' % (platform_name,
1210 env.subst('$CCFLAGS'), env.subst('$CC'),
1211 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1212 env.subst('$CXX'), env.subst('$CXXFLAGS'),
1213 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1214 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1215 env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1216 str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
1217 str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
1218 env['frontend'], packaging_method,
1219 env['PREFIX'], env['BIN_DEST_DIR'], env['SHARE_DIR'])
1221 if env['frontend'] in ['qt3', 'qt4']:
1222 env['VERSION_INFO'] += ''' include dir: %s
1225 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
1228 print env['VERSION_INFO']
1231 # Mingw command line may be too short for our link usage,
1232 # Here we use a trick from scons wiki
1233 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1235 # I also would like to add logging (commands only) capacity to the
1237 logfile = env.get('logfile', default_log_file)
1238 if logfile != '' or platform_name == 'win32':
1240 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1241 info = '''# This is a log of commands used by scons to build lyx
1245 ''' % (time.asctime(), ' '.join(sys.argv),
1246 env['VERSION_INFO'].replace('\n','\n# ')) )
1252 # -h will print out help info
1253 Help(opts.GenerateHelpText(env))
1254 # save environment settings (for fast_start option)
1255 cache_file = open(env_cache_file, 'w')
1256 cPickle.dump(env_cache, cache_file)
1259 #----------------------------------------------------------
1261 #----------------------------------------------------------
1264 # this has been the source of problems on some platforms...
1265 # I find that I need to supply it with full path name
1266 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1267 # this usage needs further investigation.
1268 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1270 env['BUILD_TARGETS'] = BUILD_TARGETS
1271 if env.has_key('rebuild'):
1272 env['REBUILD_TARGETS'] = env['rebuild'].split(',')
1274 env['REBUILD_TARGETS'] = None
1276 print "Building all targets recursively"
1278 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)