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),
278 ('version_suffix', 'install lyx as lyx-suffix', ''),
280 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
282 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
284 PathOption('aikasurus_path', 'Path to aikasurus library', None),
285 # environment variable can be set as options. (DO NOT set defaults)
287 ('LINK', '$LINK', None),
288 ('CPP', '$CPP', None),
289 ('CXX', '$CXX', None),
290 ('CXXCPP', '$CXXCPP', None),
291 ('CCFLAGS', '$CCFLAGS', None),
292 ('CPPFLAGS', '$CPPFLAGS', None),
293 ('LDFLAGS', '$LDFLAGS', None),
297 #---------------------------------------------------------
298 # Setting up environment
299 #---------------------------------------------------------
301 env = Environment(options = opts)
303 # Determine the frontend to use, which may be loaded
305 frontend = env.get('frontend', default_frontend)
306 # make sure the key exists
307 env['frontend'] = frontend
309 use_X11 = env.get('X11', default_with_x)
311 # whether or not use current config.h, and cached tests
312 if env['fast_start'] and os.path.isfile(env_cache_file):
314 SetOption('implicit_cache', 1)
315 cache_file = open(env_cache_file)
316 env_cache = cPickle.load(cache_file)
318 print '------------ fast_start mode --------------------'
319 print ' Use cached test results and current config.h'
320 print ' use fast_start=no to override'
321 print '-------------------------------------------------'
324 SetOption('implicit_cache', 0)
327 # set individual variables since I do not really like ENV = os.environ
328 env['ENV']['PATH'] = os.environ.get('PATH')
329 env['ENV']['HOME'] = os.environ.get('HOME')
330 env['TOP_SRC_DIR'] = TOP_SRC_DIR
331 env['SCONS_DIR'] = SCONS_DIR
332 # install to default_prefix by default
333 env['PREFIX'] = env.get('prefix', default_prefix)
334 if env.has_key('exec_prefix'):
335 env['BIN_DIR'] = env['exec_prefix']
337 env['BIN_DIR'] = os.path.join(env['PREFIX'], 'bin')
339 if env.has_key('version_suffix'):
340 env['PROGRAM_SUFFIX'] = env['version_suffix']
342 env['PROGRAM_SUFFIX'] = ''
343 env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables
344 env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX'])
345 env['MAN_DIR'] = os.path.join(env['PREFIX'], man_dir)
346 env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir)
349 # this is a bit out of place (after auto-configration) but
350 # it is required to do the tests. Since Tool('mingw') will
351 # reset CCFLAGS etc, this should be before getEnvVariable
352 if platform_name == 'win32':
354 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
357 # speed up source file processing
358 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
359 #env['CXXSUFFIX'] = ['.C']
361 def getEnvVariable(env, name):
362 # first try command line argument (override environment settings)
363 if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
364 env[name] = ARGUMENTS[name]
365 # then use environment default
366 elif os.environ.has_key(name) and os.environ[name].strip() != '':
367 env[name] = os.environ[name]
368 print "Acquiring varaible %s from system environment: %s" % (name, env[name])
369 # finally, env['CC'] etc is set to the default values of Options.
370 # and env['CPP'] etc does not exist
372 getEnvVariable(env, 'CC')
373 getEnvVariable(env, 'LINK')
374 getEnvVariable(env, 'CPP')
375 getEnvVariable(env, 'CXX')
376 getEnvVariable(env, 'CXXCPP')
377 getEnvVariable(env, 'CCFLAGS')
378 getEnvVariable(env, 'CXXFLAGS')
379 getEnvVariable(env, 'CPPFLAGS')
380 getEnvVariable(env, 'LDFLAGS')
384 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
386 env['mode'] = env.get('mode', default_build_mode)
387 # lyx will be built to $build/build_dir so it is possible
388 # to build multiple build_dirs using the same source
389 # $mode can be debug or release
390 if env.has_key('build_dir') and env['build_dir']:
391 build_dir = env['build_dir']
392 env['BUILDDIR'] = build_dir
394 # Determine the name of the build $mode
395 env['BUILDDIR'] = '#' + env['mode']
396 # all built libraries will go to build_dir/libs
397 # (This is different from the make file approach)
398 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
399 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
402 # QTDIR, QT_LIB_PATH, QT_INC_PATH
404 if env.has_key('qt_dir') and env['qt_dir']:
405 env['QTDIR'] = env['qt_dir']
406 # add path to the qt tools
407 env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')])
408 # set environment so that moc etc can be found even if its path is not set properly
409 env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin'))
411 env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
413 if env.has_key('qt_lib_path') and env['qt_lib_path']:
414 env['QT_LIB_PATH'] = env['qt_lib_path']
416 env['QT_LIB_PATH'] = '$QTDIR/lib'
417 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
418 # qt4 seems to be using pkg_config
419 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
421 if env.has_key('qt_inc_path') and env['qt_inc_path']:
422 env['QT_INC_PATH'] = env['qt_inc_path']
423 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
424 env['QT_INC_PATH'] = '$QTDIR/include'
425 else: # have to guess
426 env['QT_INC_PATH'] = '/usr/include/$frontend/'
427 # Note that this CPPPATH is for testing only
428 # it will be removed before calling SConscript
429 env['CPPPATH'] = [env['QT_INC_PATH']]
432 # extra_inc_path and extra_lib_path
434 if env.has_key('extra_inc_path') and env['extra_inc_path']:
435 env.AppendUnique(CPPPATH = [env['extra_inc_path']])
436 if env.has_key('extra_lib_path') and env['extra_lib_path']:
437 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
438 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
439 env.AppendUnique(CPPPATH = [env['extra_inc_path1']])
440 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
441 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
442 if env.has_key('aikasurus_path') and env['aikasurus_path']:
443 env.AppendUnique(LIBPATH = [env['aikasurus_path']])
446 # under windows, scons is confused by .C/.c and uses gcc instead of
447 # g++. I am forcing the use of g++ here. This is expected to change
448 # after lyx renames all .C files to .cpp
450 # Note that this step has to be after env.Tool('mingw') step
451 # since env.Tool('mingw') will set env['CC'] etc.
453 # save the old c compiler
454 env['C_COMPILER'] = env['CC']
455 if env.has_key('CXX') and env['CXX']:
456 env['CC'] = env['CXX']
457 env['LINK'] = env['CXX']
463 #----------------------------------------------------------
465 #----------------------------------------------------------
467 conf = Configure(env,
469 'CheckPkgConfig' : utils.checkPkgConfig,
470 'CheckPackage' : utils.checkPackage,
471 'CheckMkdirOneArg' : utils.checkMkdirOneArg,
472 'CheckSelectArgType' : utils.checkSelectArgType,
473 'CheckBoostLibraries' : utils.checkBoostLibraries,
474 'CheckCommand' : utils.checkCommand,
478 # pkg-config? (if not, we use hard-coded options)
480 if conf.CheckPkgConfig('0.15.0'):
481 env['HAS_PKG_CONFIG'] = True
483 print 'pkg-config >= 0.1.50 is not found'
484 env['HAS_PKG_CONFIG'] = False
485 env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG']
487 env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG']
489 # zlib? This is required. (fast_start assumes the existance of zlib)
490 if not fast_start and not conf.CheckLibWithHeader('z', 'zlib.h', 'C'):
491 print 'Did not find libz or zlib.h, exiting!'
497 # qt3 does not use pkg_config
498 if frontend == 'qt3':
499 if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
500 print 'Did not find qt libraries, exiting!'
502 elif frontend == 'qt4':
504 # first: try pkg_config
505 if env['HAS_PKG_CONFIG']:
506 succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
507 env['QT4_PKG_CONFIG'] = succ
508 # second: try to link to it
510 # FIXME: under linux, I can test the following perfectly
511 # However, under windows, lib names need to passed as libXXX4.a ...
512 succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
513 conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
514 # third: try to look up the path
517 for lib in ['QtCore', 'QtGui']:
518 # windows version has something like QtGui4 ...
519 if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
520 os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
523 # still can not find it
525 print "Qt4 libraries are found."
527 print 'Did not find qt libraries, exiting!'
533 env['SOCKET_LIBS'] = []
534 if conf.CheckLib('socket'):
535 env['SOCKET_LIBS'].append('socket')
537 # nsl is the network services library and provides a
538 # transport-level interface to networking services.
539 if conf.CheckLib('nsl'):
540 env['SOCKET_LIBS'].append('nsl')
542 env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS']
544 env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS']
547 # check boost libraries
548 boost_opt = ARGUMENTS.get('boost', default_boost_opt)
549 # check for system boost
551 if boost_opt in ['auto', 'system']:
552 pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
553 sig = conf.CheckBoostLibraries('boost_signals', pathes)
554 reg = conf.CheckBoostLibraries('boost_regex', pathes)
555 fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
556 ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
557 # if any of them is not found
558 if ('' in [sig[0], reg[0], fil[0], ios[0]]):
559 if boost_opt == 'system':
560 print "Can not find system boost libraries"
561 print "Please supply a path through extra_lib_path and try again."
562 print "Or use boost=included to use included boost libraries."
565 env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
566 # assume all boost libraries are in the same path...
567 env.AppendUnique(LIBPATH = [sig[0]])
568 env['INCLUDED_BOOST'] = False
570 # now, auto and succ = false, or boost=included
572 # we do not need to set LIBPATH now.
573 env['BOOST_LIBRARIES'] = ['boost_signals', 'boost_regex',
574 'boost_filesystem', 'boost_iostreams']
575 env['INCLUDED_BOOST'] = True
576 env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES']
577 env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST']
579 env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES']
580 env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST']
583 if not env.has_key('nls') or env['nls']:
584 env['ENABLE_NLS'] = True
587 if not env['ENABLE_NLS']:
589 env['INCLUDED_GETTEXT'] = False
591 # check gettext libraries
592 gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt)
593 # check for system gettext
595 if gettext_opt in ['auto', 'system']:
596 if conf.CheckLib('intl'):
597 env['INCLUDED_GETTEXT'] = False
600 if gettext_opt == 'system':
601 print "Can not find system gettext library"
602 print "Please supply a path through extra_lib_path and try again."
603 print "Or use gettext=included to use included gettext libraries."
605 # now, auto and succ = false, or gettext=included
607 # we do not need to set LIBPATH now.
608 env['INCLUDED_GETTEXT'] = True
609 env['INTL_LIB'] = ['intl']
610 env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT']
611 env_cache['INTL_LIB'] = env['INTL_LIB']
613 env['INTL_LIB'] = env_cache['INTL_LIB']
614 env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT']
617 # check for msgfmt command
619 env['MSGFMT'] = conf.CheckCommand('msgfmt')
620 env_cache['MSGFMT'] = env['MSGFMT']
622 env['MSGFMT'] = env_cache['MSGFMT']
625 #----------------------------------------------------------
626 # Generating config.h
627 #----------------------------------------------------------
629 print "Generating ", utils.config_h, "..."
631 # I do not handle all macros in src/config.h.in, rather I am following a list
632 # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr>
634 # Note: addToConfig etc are defined in scons_util
635 utils.startConfigH(TOP_SRC_DIR)
655 ('io.h', 'HAVE_IO_H', 'c'),
656 ('limits.h', 'HAVE_LIMITS_H', 'c'),
657 ('locale.h', 'HAVE_LOCALE_H', 'c'),
658 ('locale', 'HAVE_LOCALE', 'cxx'),
659 ('process.h', 'HAVE_PROCESS_H', 'c'),
660 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
661 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
662 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
663 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
664 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
665 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
666 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
667 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
668 ('utime.h', 'HAVE_UTIME_H', 'c'),
669 ('istream', 'HAVE_ISTREAM', 'cxx'),
670 ('ostream', 'HAVE_OSTREAM', 'cxx'),
671 ('ios', 'HAVE_IOS', 'cxx')
674 for header in headers:
675 if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
676 (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
677 utils.addToConfig('#define %s 1' % header[1], TOP_SRC_DIR)
679 utils.addToConfig('/* #undef %s */' % header[1], TOP_SRC_DIR)
701 ('open', 'HAVE_OPEN', None),
702 ('close', 'HAVE_CLOSE', None),
703 ('popen', 'HAVE_POPEN', None),
704 ('pclose', 'HAVE_PCLOSE', None),
705 ('_open', 'HAVE__OPEN', None),
706 ('_close', 'HAVE__CLOSE', None),
707 ('_popen', 'HAVE__POPEN', None),
708 ('_pclose', 'HAVE__PCLOSE', None),
709 ('getpid', 'HAVE_GETPID', None),
710 ('_getpid', 'HAVE__GETPID', None),
711 ('mkdir', 'HAVE_MKDIR', None),
712 ('_mkdir', 'HAVE__MKDIR', None),
713 ('putenv', 'HAVE_PUTENV', None),
714 ('mktemp', 'HAVE_MKTEMP', None),
715 ('mkstemp', 'HAVE_MKSTEMP', None),
716 ('strerror', 'HAVE_STRERROR', None),
717 ('count', 'HAVE_STD_COUNT', '''
722 return std::count(a, a+5, 'l');
733 for func in functions:
734 if conf.CheckFunc(func[0], header=func[2]):
735 utils.addToConfig('#define %s 1' % func[1], TOP_SRC_DIR)
737 utils.addToConfig('/* #undef %s */' % func[1], TOP_SRC_DIR)
740 ('asprintf', 'HAVE_ASPRINTF'),
741 ('wprintf', 'HAVE_WPRINTF'),
742 ('snprintf', 'HAVE_SNPRINTF'),
743 ('printf', 'HAVE_POSIX_PRINTF'),
744 ('fcntl', 'HAVE_FCNTL')
747 for func in env_functions:
748 if conf.CheckFunc(func[0]):
749 utils.addToConfig('#define %s 1' % func[1], TOP_SRC_DIR)
752 utils.addToConfig('/* #undef %s */' % func[1], TOP_SRC_DIR)
756 # HAVE_INTTYPES_H_WITH_UINTMAX
757 # HAVE_DECL_ISTREAMBUF_ITERATOR
758 if conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
759 conf.CheckType('intmax_t', includes='#include <inttypes.h>'):
760 utils.addToConfig('#define HAVE_INTMAX_T 1', TOP_SRC_DIR)
762 utils.addToConfig('/* #undef HAVE_INTMAX_T */', TOP_SRC_DIR)
764 if conf.CheckType('uintmax_t', includes='#include <inttypes.h>'):
765 utils.addToConfig('#define HAVE_INTTYPES_H_WITH_UINTMAX 1', TOP_SRC_DIR)
767 utils.addToConfig('/* #undef HAVE_INTTYPES_H_WITH_UINTMAX */', TOP_SRC_DIR)
769 if conf.CheckType('std::istreambuf_iterator<std::istream>',
770 includes='#include <streambuf>\n#include <istream>'):
771 utils.addToConfig('#define HAVE_DECL_ISTREAMBUF_ITERATOR 1', TOP_SRC_DIR)
773 utils.addToConfig('/* #undef HAVE_DECL_ISTREAMBUF_ITERATOR */', TOP_SRC_DIR)
779 utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX']), TOP_SRC_DIR)
780 utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION, TOP_SRC_DIR)
782 utils.addToConfig('#define DEVEL_VERSION 1', TOP_SRC_DIR)
787 # _GLIBCXX_CONCEPT_CHECKS
789 # items are (ENV, ARGUMENTS)
791 ('ENABLE_ASSERTIONS', 'assertions'),
792 ('ENABLE_NLS', 'nls'),
793 ('WITH_WARNINGS', 'warnings'),
794 ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
798 if (env.has_key(val[0]) and env[val[0]]) or \
799 ARGUMENTS.get(val[1]):
800 utils.addToConfig('#define %s 1' % val[0], TOP_SRC_DIR)
802 utils.addToConfig('/* #undef %s */' % val[0], TOP_SRC_DIR)
805 env['EXTRA_LIBS'] = []
807 # AIKSAURUS_H_LOCATION
808 if conf.CheckLib('Aiksaurus'):
809 utils.addToConfig("#define HAVE_LIBAIKSAURUS 1", TOP_SRC_DIR)
810 if (conf.CheckCXXHeader("Aiksaurus.h")):
811 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>", TOP_SRC_DIR)
812 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
813 utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>", TOP_SRC_DIR)
815 utils.addToConfig("#define AIKSAURUS_H_LOCATION", TOP_SRC_DIR)
816 env['EXTRA_LIBS'].append('Aiksaurus')
822 # determine headers to use
823 spell_engine = ARGUMENTS.get('spell', 'auto')
824 spell_detected = False
825 if spell_engine in ['auto', 'aspell'] and \
826 conf.CheckLib('aspell'):
827 utils.addToConfig('#define USE_ASPELL 1', TOP_SRC_DIR)
828 env['USE_ASPELL'] = True
829 env['USE_PSPELL'] = False
830 env['USE_ISPELL'] = False
831 env['EXTRA_LIBS'].append('aspell')
832 spell_detected = True
833 elif spell_engine in ['auto', 'pspell'] and \
834 conf.CheckLib('pspell'):
835 utils.addToConfig('#define USE_PSPELL 1', TOP_SRC_DIR)
836 env['USE_ASPELL'] = False
837 env['USE_PSPELL'] = True
838 env['USE_ISPELL'] = False
839 env['EXTRA_LIBS'].append('pspell')
840 spell_detected = True
841 elif spell_engine in ['auto', 'ispell'] and \
842 conf.CheckLib('ispell'):
843 utils.addToConfig('#define USE_ISPELL 1', TOP_SRC_DIR)
844 env['USE_ASPELL'] = False
845 env['USE_PSPELL'] = False
846 env['USE_ISPELL'] = True
847 env['EXTRA_LIBS'].append('ispell')
848 spell_detected = True
850 if not spell_detected:
851 env['USE_ASPELL'] = False
852 env['USE_PSPELL'] = False
853 env['USE_ISPELL'] = False
854 # FIXME: can lyx work without an spell engine
855 if spell_engine == 'auto':
856 print "Warning: Can not locate any spell checker"
858 print "Warning: Can not locate specified spell checker:", spell_engine
860 # USE_POSIX_PACKAGING
861 # USE_MACOSX_PACKAGING
862 # USE_WINDOWS_PACKAGING
863 if packaging_method == 'windows':
864 utils.addToConfig('#define USE_WINDOWS_PACKAGING 1', TOP_SRC_DIR)
865 elif packaging_method == 'posix':
866 utils.addToConfig('#define USE_POSIX_PACKAGING 1', TOP_SRC_DIR)
867 elif packaging_method == 'mac':
868 utils.addToConfig('#define USE_MACOSX_PACKAGING 1', TOP_SRC_DIR)
872 utils.addToConfig('#define BOOST_POSIX 1', TOP_SRC_DIR)
874 utils.addToConfig('/* #undef BOOST_POSIX */', TOP_SRC_DIR)
876 # MKDIR_TAKES_ONE_ARG
877 if conf.CheckMkdirOneArg():
878 utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1', TOP_SRC_DIR)
880 utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */', TOP_SRC_DIR)
885 (arg1, arg234, arg5) = conf.CheckSelectArgType()
886 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1, TOP_SRC_DIR)
887 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234, TOP_SRC_DIR)
888 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5, TOP_SRC_DIR)
892 # WANT_GETFILEATTRIBUTESEX_WRAPPER
893 utils.endConfigH(TOP_SRC_DIR)
895 # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed
896 # NOTE that we do *not* save qt_libs in environment.
897 env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS'])
898 env_cache['USE_ASPELL'] = env['USE_ASPELL']
899 env_cache['USE_PSPELL'] = env['USE_PSPELL']
900 env_cache['USE_ISPELL'] = env['USE_ISPELL']
901 env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF']
902 env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF']
903 env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF']
904 env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF']
905 env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL']
909 # this comes as a big surprise, without this line
910 # (doing nothing obvious), adding fast_start=yes
911 # to a build with fast_start=no will result in a rebuild
912 # Note that the exact header file to check does not matter
913 conf.CheckCHeader('io.h')
914 # only a few variables need to be rescanned
915 env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS'])
916 env['USE_ASPELL'] = env_cache['USE_ASPELL']
917 env['USE_PSPELL'] = env_cache['USE_PSPELL']
918 env['USE_ISPELL'] = env_cache['USE_ISPELL']
919 env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF']
920 env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF']
921 env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF']
922 env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF']
923 env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL']
926 # Finish auto-configuration
929 #----------------------------------------------------------
930 # Now set up our build process accordingly
931 #----------------------------------------------------------
934 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
936 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
937 # in their respective directory and specialized env.
939 if frontend == 'qt3':
940 # note: env.Tool('qt') my set QT_LIB to qt
941 env['QT_LIB'] = 'qt-mt'
942 env['EXTRA_LIBS'].append('qt-mt')
943 if platform_name == 'cygwin' and use_X11:
944 env['EXTRA_LIBS'].extend(['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
945 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
947 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
948 elif frontend == 'qt4':
949 if platform_name == "win32":
950 env['QT_LIB'] = ['QtCore4', 'QtGui4']
952 env['QT_LIB'] = ['QtCore', 'QtGui']
953 env['EXTRA_LIBS'] += env['QT_LIB']
955 print "Can not locate qt tools"
956 print "What I get is "
957 print " QTDIR: ", env['QTDIR']
960 if platform_name in ['win32', 'cygwin']:
961 # the final link step needs stdc++ to succeed under mingw
962 # FIXME: shouldn't g++ automatically link to stdc++?
963 env['SYSTEM_LIBS'] = ['shlwapi', 'z', 'stdc++']
965 env['SYSTEM_LIBS'] = ['z']
968 # Build parameters CPPPATH etc
970 # boost is always in, src is needed for config.h
972 # QT_INC_PATH is not needed for *every* source file
973 env['CPPPATH'].remove(env['QT_INC_PATH'])
974 env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src']
976 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
977 # for debug/release mode
978 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
979 env.AppendUnique(CCFLAGS = [])
981 env.AppendUnique(CCFLAGS = [])
984 # Customized builders
986 # install customized builders
987 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
990 # A Link script for cygwin see
991 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
992 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
995 if platform_name == 'cygwin':
996 ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
997 ld_script = utils.installCygwinLDScript(ld_script_path)
998 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
999 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1004 # src/support/package.C.in needs the following to replace
1005 # LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx)
1006 env['LYX_DIR'] = env['SHARE_DIR']
1007 # LYX_ABS_INSTALLED_LOCALEDIR
1008 env['LOCALEDIR'] = env['LOCALE_DIR']
1009 env['TOP_SRCDIR'] = env['TOP_SRC_DIR']
1010 # needed by src/version.C.in => src/version.C
1011 env['PACKAGE_VERSION'] = PACKAGE_VERSION
1012 # fill in the version info
1013 env['VERSION_INFO'] = '''Configuration
1015 Special build flags: %s
1017 C Compiler flags: %s %s
1019 C++ Compiler LyX flags: %s
1020 C++ Compiler flags: %s %s
1022 Linker user flags: %s
1024 Builing directory: %s
1025 Local library directory: %s
1026 Libraries pathes: %s
1029 System libraries: %s
1030 include search path: %s
1037 ''' % (platform_name,
1038 env.subst('$CCFLAGS'), env.subst('$CC'),
1039 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1040 env.subst('$CXX'), env.subst('$CXXFLAGS'),
1041 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1042 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1043 env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1044 str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
1045 str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']),
1046 env['frontend'], packaging_method,
1047 env['PREFIX'], env['BIN_DIR'], env['SHARE_DIR'])
1049 if env['frontend'] in ['qt3', 'qt4']:
1050 env['VERSION_INFO'] += ''' include dir: %s
1053 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
1056 print env['VERSION_INFO']
1059 # Mingw command line may be too short for our link usage,
1060 # Here we use a trick from scons wiki
1061 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1063 # I also would like to add logging (commands only) capacity to the
1065 logfile = env.get('logfile', default_log_file)
1066 if logfile != '' or platform_name == 'win32':
1068 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1069 info = '''# This is a log of commands used by scons to build lyx
1073 ''' % (time.asctime(), ' '.join(sys.argv),
1074 env['VERSION_INFO'].replace('\n','\n# ')) )
1080 # -h will print out help info
1081 Help(opts.GenerateHelpText(env))
1082 # save environment settings (for fast_start option)
1083 cache_file = open(env_cache_file, 'w')
1084 cPickle.dump(env_cache, cache_file)
1087 #----------------------------------------------------------
1089 #----------------------------------------------------------
1092 # this has been the source of problems on some platforms...
1093 # I find that I need to supply it with full path name
1094 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1095 # this usage needs further investigation.
1096 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1098 env['BUILD_TARGETS'] = BUILD_TARGETS
1100 print "Building all targets recursively"
1102 env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)