# vi:filetype=python:expandtab:tabstop=2:shiftwidth=2 # # file SConstruct # # This file is part of LyX, the document processor. # Licence details can be found in the file COPYING. # # \author Bo Peng # Full author contact details are available in file CREDITS. # # # This is a scons based building system for lyx, you can use it as follows: # # $ cd development/scons # $ scons [options] [targets] # or: # $ scons -f development/scons/SConstruct [options] [targets] # and: # $ scons [prefix=.] install # # Where: # * targets can be one or more of lyx, tex2lyx, client, po, install. # default to lyx, you can use 'scons all' to build all targets except # for install # * options: use scons -h for details about options, the most important # one is frontend=qt3|qt4. # - qt3 is used by default on linux, cygwin and mac # - qt4 is used by default on win32/mingw # # File layouts (Important): # * Unless you specify builddir=dir, building will happen # in $BUILDDIR = $mode, which can be debug or release # * $BUILDDIR has subdirectories # libs: all intermediate libraries # boost: boost libraries, if boost=included is used # qt3/4: frontend-specific objects # * executables will be copied to $BUILDDIR/ # # Hints: # * scons fast_start=yes # If env.cache exists, bypass all tests and use existing src/config.h # # * scons --config=force # force re-configuration (use scons -H for details) # # * check config.log to see why config has failed # # * use extra_inc_path, extra_lib_path, qt_dir, qt_inc_path # qt_lib_path to help locate qt and other libraries. # There are also extra_inc_path1, extra_lib_path1 if you need to spacify # more than one extra paths. # # * executed commands will be logged in scons_lyx.log. You can use logfile= # option to save log to another file. # # Notes: # # * scons dist etc may be added later. Interested contributors can follow # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/AccumulateBuilder # or # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/DistTarBuilder # Please also see the commented out code in scons_utils.py # # * NSIS support can be found here. # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool # # * rpm support? # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/RpmHonchoTemp # # However, I decide to wait since scons seems to be standardizing these # features. # import os, sys, copy, cPickle, glob # config/scons_utils.py defines a few utility function sys.path.append('config') import scons_utils as utils #---------------------------------------------------------- # Required runtime environment #---------------------------------------------------------- # FIXME: I remember lyx requires higher version of python? EnsurePythonVersion(1, 5) # Please use at least 0.96.91 (not 0.96.1) EnsureSConsVersion(0, 96) # determine where I am ... # # called as 'scons -f development/scons/SConstruct' if os.path.isfile('SConstruct'): TOP_SRC_DIR = '../..' SCONS_DIR = '.' # called as 'cd development/scons; scons' else: TOP_SRC_DIR = '.' SCONS_DIR = 'development/scons' #---------------------------------------------------------- # Global definitions #---------------------------------------------------------- # some global settings PACKAGE_VERSION = '1.5.0svn' DEVEL_VERSION = True default_build_mode = 'debug' lyx_ext = '*.C' PACKAGE = 'lyx' PACKAGE_BUGREPORT = 'lyx-devel@lists.lyx.org' PACKAGE_NAME = 'LyX' PACKAGE_TARNAME = 'lyx' PACKAGE_STRING = '%s %s' % (PACKAGE_NAME, PACKAGE_VERSION) # various cache/log files default_log_file = 'scons_lyx.log' env_cache_file = 'env.cache' #---------------------------------------------------------- # platform dependent settings #---------------------------------------------------------- if os.name == 'nt': platform_name = 'win32' default_frontend = 'qt4' # boost and gettext are unlikely to be installed already default_boost_opt = 'included' default_gettext_opt = 'included' default_pch_opt = False default_with_x = False spell_checker = 'auto' # boost_posix indicates to boost which API to use (posix or windows). # If not specified, boost tries to figure out by itself, but it may fail. boost_posix = False packaging_method = 'windows' add_suffix_to_executables = False default_prefix = 'c:/program files/lyx' share_dir = 'Resources' man_dir = 'Resources/man/man1' locale_dir = 'Resources/locale' elif os.name == 'posix' and sys.platform != 'cygwin': platform_name = sys.platform default_frontend = 'qt3' # try to use system boost/gettext libraries default_boost_opt = 'auto' default_gettext_opt = 'auto' default_pch_opt = False default_with_x = True boost_posix = True packaging_method = 'posix' add_suffix_to_executables = True default_prefix = '/usr/local/' share_dir = 'share/lyx' man_dir = 'man/man1' locale_dir = 'share/locale' elif os.name == 'posix' and sys.platform == 'cygwin': platform_name = 'cygwin' default_frontend = 'qt3' # force the use of cygwin/boost/gettext default_boost_opt = 'system' default_gettext_opt = 'system' default_pch_opt = False default_with_x = True boost_posix = True packaging_method = 'posix' add_suffix_to_executables = True default_prefix = '/usr/local/' share_dir = 'share/lyx' man_dir = 'man/man1' locale_dir = 'share/locale' elif os.name == 'darwin': platform_name = 'mac' default_frontend = 'qt3' # to be safe default_boost_opt = 'included' default_gettext_opt = 'included' default_pch_opt = False default_with_x = False boost_posix = True packaging_method = 'mac' add_suffix_to_executables = True # FIXME: where to install? default_prefix = '/usr/local/' share_dir = 'Resources' man_dir = 'Resources/man/man1' locale_dir = 'Resources/locale' else: # unsupported system platform_name = 'others' default_frontend = 'qt3' # to be safe default_boost_opt = 'included' default_gettext_opt = 'included' default_pch_opt = False default_with_x = True boost_posix = False packaging_method = 'posix' add_suffix_to_executables = True default_prefix = '/usr/local/' share_dir = 'share/lyx' man_dir = 'man/man1' locale_dir = 'share/locale' #--------------------------------------------------------- # Handling options #---------------------------------------------------------- # if os.path.isfile('config.py'): print "Getting options from config.py..." print open('config.py').read() opts = Options(['config.py']) opts.AddOptions( # frontend, EnumOption('frontend', 'Main GUI', default_frontend, allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ), # debug or release build EnumOption('mode', 'Building method', default_build_mode, allowed_values = ('debug', 'release') ), # boost libraries EnumOption('boost', 'Use included, system boost library, or try sytem boost first.', default_boost_opt, allowed_values = ( 'auto', # detect boost, if not found, use included 'included', # always use included boost 'system', # always use system boost, fail if can not find ) ), # FIXME: not implemented yet. EnumOption('gettext', 'Use included, system gettext library, or try sytem gettext first', default_gettext_opt, allowed_values = ( 'auto', # detect gettext, if not found, use included 'included', # always use included gettext 'system', # always use system gettext, fail if can not find ) ), # EnumOption('spell', 'Choose spell checker to use.', 'auto', allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ), # BoolOption('fast_start', 'Whether or not use cached tests and keep current config.h', True), # BoolOption('load_option', 'load option from previous scons run', True), # FIXME: I do not know how pch is working. Ignore this option now. BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt), # enable assertion, (config.h has ENABLE_ASSERTIOS BoolOption('assertions', 'Use assertions', True), # enable warning, (config.h has WITH_WARNINGS) BoolOption('warnings', 'Use warnings', True), # enable glib, (config.h has _GLIBCXX_CONCEPT_CHECKS) BoolOption('concept_checks', 'Enable concept checks', True), # BoolOption('nls', 'Whether or not use native language support', True), # FIXME: not implemented BoolOption('profile', '(NA) Whether or not enable profiling', False), # FIXME: not implemented BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False), # using x11? BoolOption('X11', 'Use x11 windows system', default_with_x), # use MS VC++ to build lyx BoolOption('use_vc', 'Use MS VC++ to build lyx', False), # PathOption('qt_dir', 'Path to qt directory', None), # PathOption('qt_include_path', 'Path to qt include directory', None), # PathOption('qt_lib_path', 'Path to qt library directory', None), # build directory, will use $mode if not set PathOption('build_dir', 'Build directory', None), # extra include and libpath PathOption('extra_inc_path', 'Extra include path', None), # PathOption('extra_lib_path', 'Extra library path', None), # PathOption('extra_inc_path1', 'Extra include path', None), # PathOption('extra_lib_path1', 'Extra library path', None), # rebuild only specifed, comma separated targets ('rebuild', 'rebuild only specifed, comma separated targets', None), # can be set to a non-existing directory ('prefix', 'install architecture-independent files in PREFIX', None), # will install to dest_dir if defined. Otherwise, prefix will be used. ('dest_dir', 'install to dest_dir', None), # version suffix ('version_suffix', 'install lyx as lyx-suffix', ''), # PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None), # log file ('logfile', 'save commands (not outputs) to logfile', default_log_file), # Path to aikasurus PathOption('aikasurus_path', 'Path to aikasurus library', None), # environment variable can be set as options. (DO NOT set defaults) ('CC', '$CC', None), ('LINK', '$LINK', None), ('CPP', '$CPP', None), ('CXX', '$CXX', None), ('CXXCPP', '$CXXCPP', None), ('CCFLAGS', '$CCFLAGS', None), ('CPPFLAGS', '$CPPFLAGS', None), ('LDFLAGS', '$LDFLAGS', None), ) # whether or not use current config.h, and cached tests if (not ARGUMENTS.has_key('fast_start') or \ ARGUMENTS['fast_start'] in ['y', 'yes', 't', 'true', '1', 'all']) \ and os.path.isfile(env_cache_file): fast_start = True cache_file = open(env_cache_file) env_cache = cPickle.load(cache_file) cache_file.close() print '------------ fast_start mode --------------------' print ' Use cached test results and current config.h' print ' use fast_start=no to override' print else: fast_start = False env_cache = {} if (not ARGUMENTS.has_key('load_option') or \ ARGUMENTS['load_option'] in ['y', 'yes', 't', 'true', '1', 'all']) \ and os.path.isfile(env_cache_file): cache_file = open(env_cache_file) opt_cache = cPickle.load(cache_file)['arg_cache'] cache_file.close() # import cached options, but we should ignore qt_dir when frontend changes if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \ and ARGUMENTS['frontend'] != opt_cache['frontend'] \ and opt_cache.has_key('qt_dir'): opt_cache.pop('qt_dir') # and we do not cache some options for arg in ['fast_start']: if opt_cache.has_key(arg): opt_cache.pop(arg) for key in opt_cache.keys(): if not ARGUMENTS.has_key(key): ARGUMENTS[key] = opt_cache[key] print "Restoring cached option %s=%s" % (key, ARGUMENTS[key]) print # save arguments env_cache['arg_cache'] = ARGUMENTS #--------------------------------------------------------- # Setting up environment #--------------------------------------------------------- # Note that I do not really like ENV=os.environ, but you may # add it here if you experience some environment related problem env = Environment(options = opts) # Determine the frontend to use, which may be loaded # from option cache frontend = env.get('frontend', default_frontend) # make sure the key exists env['frontend'] = frontend env['LYX_EXT'] = lyx_ext # use_X11 = env.get('X11', default_with_x) use_vc = env.get('use_vc', False) # use it only once for s scons-bug, will remove it later. env['USE_VC'] = use_vc # set individual variables since I do not really like ENV = os.environ env['ENV']['PATH'] = os.environ.get('PATH') env['ENV']['HOME'] = os.environ.get('HOME') # these are defined for MSVC env['ENV']['LIB'] = os.environ.get('LIB') env['ENV']['INCLUDE'] = os.environ.get('INCLUDE') if use_vc: # full path name is used to build msvs project files env['TOP_SRC_DIR'] = Dir(TOP_SRC_DIR).abspath else: env['TOP_SRC_DIR'] = TOP_SRC_DIR env['SCONS_DIR'] = SCONS_DIR # install to default_prefix by default env['PREFIX'] = env.get('prefix', default_prefix) # program suffix if env.has_key('version_suffix'): env['PROGRAM_SUFFIX'] = env['version_suffix'] else: env['PROGRAM_SUFFIX'] = '' env['ADD_SUFFIX_TO_EXECUTABLES'] = add_suffix_to_executables env['SHARE_DIR'] = os.path.join(env['PREFIX'], share_dir + env['PROGRAM_SUFFIX']) env['LOCALE_DIR'] = os.path.join(env['PREFIX'], locale_dir) # # if dest_dir is different from prefix. env['DEST_DIR'] = env.get('dest_dir', env['PREFIX']) if env.has_key('exec_prefix'): env['BIN_DEST_DIR'] = env['exec_prefix'] else: env['BIN_DEST_DIR'] = os.path.join(env['DEST_DIR'], 'bin') env['SHARE_DEST_DIR'] = os.path.join(env['DEST_DIR'], share_dir + env['PROGRAM_SUFFIX']) env['MAN_DEST_DIR'] = os.path.join(env['DEST_DIR'], man_dir) env['LOCALE_DEST_DIR'] = os.path.join(env['DEST_DIR'], locale_dir) # # this is a bit out of place (after auto-configration) but # it is required to do the tests. Since Tool('mingw') will # reset CCFLAGS etc, this should be done before getEnvVariable if platform_name == 'win32' and not use_vc: env.Tool('mingw') env.AppendUnique(CPPPATH = ['#c:/MinGW/include']) elif use_vc: env.Tool('msvc') env.Tool('mslink') # speed up source file processing #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp'] #env['CXXSUFFIX'] = ['.C'] def getEnvVariable(env, name): # first try command line argument (override environment settings) if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '': # multiple options may be passed like "-02 -g" env[name] = ARGUMENTS[name].split() # it does not seem necessary, but it is safer to change ['a'] back to 'a' if len(env[name]) == 1: env[name] = env[name][0] # then use environment default elif os.environ.has_key(name) and os.environ[name].strip() != '': print "Acquiring varaible %s from system environment: %s" % (name, env[name]) env[name] = os.environ[name].split() if len(env[name]) == 1: env[name] = env[name][0] # finally, env['CC'] etc is set to the default values of Options. # and env['CPP'] etc does not exist getEnvVariable(env, 'CC') getEnvVariable(env, 'LINK') getEnvVariable(env, 'CPP') getEnvVariable(env, 'CXX') getEnvVariable(env, 'CXXCPP') getEnvVariable(env, 'CCFLAGS') getEnvVariable(env, 'CXXFLAGS') getEnvVariable(env, 'CPPFLAGS') getEnvVariable(env, 'LDFLAGS') # # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs # env['mode'] = env.get('mode', default_build_mode) # lyx will be built to $build/build_dir so it is possible # to build multiple build_dirs using the same source # $mode can be debug or release if env.has_key('build_dir') and env['build_dir']: build_dir = env['build_dir'] env['BUILDDIR'] = build_dir else: # Determine the name of the build $mode env['BUILDDIR'] = '#' + env['mode'] # all built libraries will go to build_dir/libs # (This is different from the make file approach) env['LOCALLIBPATH'] = '$BUILDDIR/libs' # to make use of local cached parameters, this one has to be '.' env['MSVSPATH'] = '.' env.AppendUnique(LIBPATH = ['$LOCALLIBPATH']) # # QTDIR, QT_LIB_PATH, QT_INC_PATH # if env.has_key('qt_dir') and env['qt_dir']: env['QTDIR'] = env['qt_dir'] # add path to the qt tools env.AppendUnique(LIBPATH = [os.path.join(env['qt_dir'], 'lib')]) # set environment so that moc etc can be found even if its path is not set properly env.PrependENVPath('PATH', os.path.join(env['qt_dir'], 'bin')) else: env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3') if env.has_key('qt_lib_path') and env['qt_lib_path']: env['QT_LIB_PATH'] = env['qt_lib_path'] else: env['QT_LIB_PATH'] = '$QTDIR/lib' env.AppendUnique(LIBPATH = ['$QT_LIB_PATH']) # qt4 seems to be using pkg_config env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH')) if env.has_key('qt_inc_path') and env['qt_inc_path']: env['QT_INC_PATH'] = env['qt_inc_path'] elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')): env['QT_INC_PATH'] = '$QTDIR/include' else: # have to guess env['QT_INC_PATH'] = '/usr/include/$frontend/' # Note that this CPPPATH is for testing only # it will be removed before calling SConscript env['CPPPATH'] = [env['QT_INC_PATH']] # # extra_inc_path and extra_lib_path # if env.has_key('extra_inc_path') and env['extra_inc_path']: env.AppendUnique(CPPPATH = [env['extra_inc_path']]) if env.has_key('extra_lib_path') and env['extra_lib_path']: env.AppendUnique(LIBPATH = [env['extra_lib_path']]) if env.has_key('extra_inc_path1') and env['extra_inc_path1']: env.AppendUnique(CPPPATH = [env['extra_inc_path1']]) if env.has_key('extra_lib_path1') and env['extra_lib_path1']: env.AppendUnique(LIBPATH = [env['extra_lib_path1']]) if env.has_key('aikasurus_path') and env['aikasurus_path']: env.AppendUnique(LIBPATH = [env['aikasurus_path']]) # under windows, scons is confused by .C/.c and uses gcc instead of # g++. I am forcing the use of g++ here. This is expected to change # after lyx renames all .C files to .cpp # # Note that this step has to be after env.Tool('mingw') step # since env.Tool('mingw') will set env['CC'] etc. # # save the old c compiler and CCFLAGS (used by libintl) env['C_COMPILER'] = env.subst('$CC') env['C_CCFLAGS'] = env.subst('$CCFLAGS').split() # if we use ms vc, the commands are fine (cl.exe and link.exe) if not use_vc: if env.has_key('CXX') and env['CXX']: env['CC'] = env.subst('$CXX') env['LINK'] = env.subst('$CXX') else: env['CC'] = 'g++' env['LINK'] = 'g++' else: # /TP treat all source code as C++ # C4819: The file contains a character that cannot be represented # in the current code page (number) # C4996: foo was decleared deprecated env.Append(CCFLAGS=['/TP', '/EHsc', '/wd4819', '/wd4996']) env.Append(C_CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX']) #---------------------------------------------------------- # Autoconf business #---------------------------------------------------------- conf = Configure(env, custom_tests = { 'CheckPkgConfig' : utils.checkPkgConfig, 'CheckPackage' : utils.checkPackage, 'CheckMkdirOneArg' : utils.checkMkdirOneArg, 'CheckSelectArgType' : utils.checkSelectArgType, 'CheckBoostLibraries' : utils.checkBoostLibraries, 'CheckCommand' : utils.checkCommand, 'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd, } ) # pkg-config? (if not, we use hard-coded options) if not fast_start: if conf.CheckPkgConfig('0.15.0'): env['HAS_PKG_CONFIG'] = True else: print 'pkg-config >= 0.1.50 is not found' env['HAS_PKG_CONFIG'] = False env_cache['HAS_PKG_CONFIG'] = env['HAS_PKG_CONFIG'] else: env['HAS_PKG_CONFIG'] = env_cache['HAS_PKG_CONFIG'] # zlib? This is required. (fast_start assumes the existance of zlib) if not fast_start: if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \ or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')): print 'Did not find zdll.lib or zlib.h, exiting!' Exit(1) # qt libraries? if not fast_start: # # qt3 does not use pkg_config if frontend == 'qt3': if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'): print 'Did not find qt libraries, exiting!' Exit(1) elif frontend == 'qt4': succ = False # first: try pkg_config if env['HAS_PKG_CONFIG']: succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4') env['QT4_PKG_CONFIG'] = succ # second: try to link to it if not succ: # FIXME: under linux, I can test the following perfectly # However, under windows, lib names need to passed as libXXX4.a ... succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \ conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();') # third: try to look up the path if not succ: succ = True for lib in ['QtCore', 'QtGui']: # windows version has something like QtGui4 ... if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \ os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))): succ = False break # still can not find it if succ: print "Qt4 libraries are found." else: print 'Did not find qt libraries, exiting!' Exit(1) # now, if msvc2005 is used, we will need that QT_LIB_PATH/QT_LIB.manifest file if use_vc: # glob file xxx.dll.manifest (msvc 2003 may not have it) manifests = glob.glob(os.path.join(env.subst('$QT_LIB_PATH'), '*.dll.manifest')) if manifests != []: env['LINKCOM'] = [env['LINKCOM'], 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % manifests[0]] # check socket libs if not fast_start: env['SOCKET_LIBS'] = [] if conf.CheckLib('socket'): env['SOCKET_LIBS'].append('socket') # nsl is the network services library and provides a # transport-level interface to networking services. if conf.CheckLib('nsl'): env['SOCKET_LIBS'].append('nsl') env_cache['SOCKET_LIBS'] = env['SOCKET_LIBS'] else: env['SOCKET_LIBS'] = env_cache['SOCKET_LIBS'] if not fast_start: # check boost libraries boost_opt = ARGUMENTS.get('boost', default_boost_opt) # check for system boost succ = False if boost_opt in ['auto', 'system']: pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib'] sig = conf.CheckBoostLibraries('boost_signals', pathes) reg = conf.CheckBoostLibraries('boost_regex', pathes) fil = conf.CheckBoostLibraries('boost_filesystem', pathes) ios = conf.CheckBoostLibraries('boost_iostreams', pathes) # if any of them is not found if ('' in [sig[0], reg[0], fil[0], ios[0]]): if boost_opt == 'system': print "Can not find system boost libraries" print "Please supply a path through extra_lib_path and try again." print "Or use boost=included to use included boost libraries." Exit(2) else: env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]] # assume all boost libraries are in the same path... env.AppendUnique(LIBPATH = [sig[0]]) env['INCLUDED_BOOST'] = False succ = True # now, auto and succ = false, or boost=included if not succ: # we do not need to set LIBPATH now. env['BOOST_LIBRARIES'] = ['included_boost_signals', 'included_boost_regex', 'included_boost_filesystem', 'included_boost_iostreams'] env['INCLUDED_BOOST'] = True env_cache['BOOST_LIBRARIES'] = env['BOOST_LIBRARIES'] env_cache['INCLUDED_BOOST'] = env['INCLUDED_BOOST'] else: env['BOOST_LIBRARIES'] = env_cache['BOOST_LIBRARIES'] env['INCLUDED_BOOST'] = env_cache['INCLUDED_BOOST'] env['ENABLE_NLS'] = not env.has_key('nls') or env['nls'] if not fast_start: if not env['ENABLE_NLS']: env['INTL_LIBS'] = [] env['INCLUDED_GETTEXT'] = False else: # check gettext libraries gettext_opt = ARGUMENTS.get('gettext', default_gettext_opt) # check for system gettext succ = False if gettext_opt in ['auto', 'system']: if conf.CheckLib('intl'): env['INCLUDED_GETTEXT'] = False env['INTL_LIBS'] = ['intl'] succ = True else: # no found if gettext_opt == 'system': print "Can not find system gettext library" print "Please supply a path through extra_lib_path and try again." print "Or use gettext=included to use included gettext libraries." Exit(2) # now, auto and succ = false, or gettext=included if not succ: # we do not need to set LIBPATH now. env['INCLUDED_GETTEXT'] = True env['INTL_LIBS'] = ['included_intl'] if platform_name == 'win32' and not use_vc: # for functions AddFontResouceA, RemoveFontResourceA # if use_vc, gdi32 will be added anyway later env['INTL_LIBS'].append('gdi32') env_cache['INCLUDED_GETTEXT'] = env['INCLUDED_GETTEXT'] env_cache['INTL_LIBS'] = env['INTL_LIBS'] else: env['INTL_LIBS'] = env_cache['INTL_LIBS'] env['INCLUDED_GETTEXT'] = env_cache['INCLUDED_GETTEXT'] # # check for msgfmt command if not fast_start: env['MSGFMT'] = conf.CheckCommand('msgfmt') env_cache['MSGFMT'] = env['MSGFMT'] else: env['MSGFMT'] = env_cache['MSGFMT'] #---------------------------------------------------------- # Generating config.h #---------------------------------------------------------- if not fast_start: print "Generating ", utils.config_h, "..." # I do not handle all macros in src/config.h.in, rather I am following a list # of *used-by-lyx* macros compiled by Abdelrazak Younes # # Note: addToConfig etc are defined in scons_util utils.startConfigH() # HAVE_IO_H # HAVE_LIMITS_H # HAVE_LOCALE_H # HAVE_LOCALE # HAVE_PROCESS_H # HAVE_STDLIB_H # HAVE_SYS_STAT_H # HAVE_SYS_TIME_H # HAVE_SYS_TYPES_H # HAVE_SYS_UTIME_H # HAVE_UNISTD_H # HAVE_UTIME_H # HAVE_STRINGS_H # HAVE_DIRECT_H # HAVE_ISTREAM # HAVE_OSTREAM # HAVE_IOS # for libintl % grep HAVE * | grep _H | cut -d: -f2 | sort -u # # HAVE_INTTYPES_H # HAVE_STDINT_H # HAVE_ALLOCA_H # HAVE_STDLIB_H # HAVE_STRING_H # HAVE_STDDEF_H # HAVE_LIMITS_H # HAVE_ARGZ_H # HAVE_UNISTD_H # HAVE_SYS_PARAM_H # Check header files headers = [ ('io.h', 'HAVE_IO_H', 'c'), ('limits.h', 'HAVE_LIMITS_H', 'c'), ('locale.h', 'HAVE_LOCALE_H', 'c'), ('locale', 'HAVE_LOCALE', 'cxx'), ('process.h', 'HAVE_PROCESS_H', 'c'), ('stdlib.h', 'HAVE_STDLIB_H', 'c'), ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'), ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'), ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'), ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'), ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'), ('unistd.h', 'HAVE_UNISTD_H', 'c'), ('inttypes.h', 'HAVE_INTTYPES_H', 'c'), ('utime.h', 'HAVE_UTIME_H', 'c'), ('string.h', 'HAVE_STRING_H', 'c'), ('strings.h', 'HAVE_STRINGS_H', 'c'), ('direct.h', 'HAVE_DIRECT_H', 'c'), ('istream', 'HAVE_ISTREAM', 'cxx'), ('ostream', 'HAVE_OSTREAM', 'cxx'), ('ios', 'HAVE_IOS', 'cxx'), ('argz.h', 'HAVE_ARGZ_H', 'c'), ('limits.h', 'HAVE_LIMITS_H', 'c'), ('alloca.h', 'HAVE_ALLOCA_H', 'c'), ('stddef.h', 'HAVE_STDDEF_H', 'c'), ('stdint.h', 'HAVE_STDINT_H', 'c'), ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c') ] for header in headers: utils.addToConfig("/* Define to 1 if you have the <%s> header file. */" % header[0], newline=1) if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \ (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])): utils.addToConfig('#define %s 1' % header[1]) else: utils.addToConfig('/* #undef %s */' % header[1]) # HAVE_OPEN # HAVE_CLOSE # HAVE_POPEN # HAVE_PCLOSE # HAVE__OPEN # HAVE__CLOSE # HAVE__POPEN # HAVE__PCLOSE # HAVE_GETPID # HAVE__GETPID # HAVE_MKDIR # HAVE__MKDIR # HAVE_PUTENV # HAVE_MKTEMP # HAVE_MKSTEMP # HAVE_STRERROR # HAVE_STD_COUNT # HAVE_GETCWD # HAVE_STRCPY # HAVE_STRCASECMP # HAVE_STRDUP # HAVE_STRTOUL # HAVE_WCSLEN # HAVE_MMAP ? # HAVE_ALLOCA # HAVE___FSETLOCKING # HAVE_MEMPCPY # HAVE_STRCASECMP # HAVE___ARGZ_COUNT # HAVE___ARGZ_NEXT # HAVE___ARGZ_STRINGIFY # HAVE___FSETLOCKING # HAVE_GETCWD # HAVE_STRTOUL # HAVE_STRCASECMP # HAVE_STRDUP # HAVE_TSEARCH # Check functions functions = [ ('open', 'HAVE_OPEN', None), ('close', 'HAVE_CLOSE', None), ('popen', 'HAVE_POPEN', None), ('pclose', 'HAVE_PCLOSE', None), ('_open', 'HAVE__OPEN', None), ('_close', 'HAVE__CLOSE', None), ('_popen', 'HAVE__POPEN', None), ('_pclose', 'HAVE__PCLOSE', None), ('getpid', 'HAVE_GETPID', None), ('_getpid', 'HAVE__GETPID', None), ('mkdir', 'HAVE_MKDIR', None), ('_mkdir', 'HAVE__MKDIR', None), ('putenv', 'HAVE_PUTENV', None), ('mktemp', 'HAVE_MKTEMP', None), ('mkstemp', 'HAVE_MKSTEMP', None), ('strerror', 'HAVE_STRERROR', None), ('count', 'HAVE_STD_COUNT', ''' #include int count() { char a[] = "hello"; return std::count(a, a+5, 'l'); } '''), ('getcwd', 'HAVE_GETCWD', None), ('stpcpy', 'HAVE_STPCPY', None), ('strcasecmp', 'HAVE_STRCASECMP', None), ('strdup', 'HAVE_STRDUP', None), ('strtoul', 'HAVE_STRTOUL', None), ('alloca', 'HAVE_ALLOCA', None), ('__fsetlocking', 'HAVE___FSETLOCKING', None), ('mempcpy', 'HAVE_MEMPCPY', None), ('__argz_count', 'HAVE___ARGZ_COUNT', None), ('__argz_next', 'HAVE___ARGZ_NEXT', None), ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None), ('setlocale', 'HAVE_SETLOCALE', None), ('tsearch', 'HAVE_TSEARCH', None), ('getegid', 'HAVE_GETEGID', None), ('getgid', 'HAVE_GETGID', None), ('getuid', 'HAVE_GETUID', None), ('wcslen', 'HAVE_WCSLEN', None) ] # HAVE_ASPRINTF # HAVE_WPRINTF # HAVE_SNPRINTF # HAVE_POSIX_PRINTF # HAVE_FCNTL for func in functions: utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1) if conf.CheckFunc(func[0], header=func[2]): utils.addToConfig('#define %s 1' % func[1]) else: utils.addToConfig('/* #undef %s */' % func[1]) env_functions = [ ('asprintf', 'HAVE_ASPRINTF'), ('wprintf', 'HAVE_WPRINTF'), ('snprintf', 'HAVE_SNPRINTF'), ('printf', 'HAVE_POSIX_PRINTF'), ('fcntl', 'HAVE_FCNTL') ] for func in env_functions: utils.addToConfig("/* Define to 1 if you have the `%s' function. */" % func[0], newline=1) if conf.CheckFunc(func[0]): utils.addToConfig('#define %s 1' % func[1]) env[func[1]] = 1 else: utils.addToConfig('/* #undef %s */' % func[1]) env[func[1]] = 0 # HAVE_INTMAX_T # HAVE_DECL_ISTREAMBUF_ITERATOR utils.addToConfig("/* Define to 1 if you have the `intmax_t' type. */", newline=1) if conf.CheckType('intmax_t', includes='#include ') or \ conf.CheckType('intmax_t', includes='#include '): utils.addToConfig('#define HAVE_INTMAX_T 1') else: utils.addToConfig('/* #undef HAVE_INTMAX_T */') # HAVE_INTMAX_T # HAVE_LONG_DOUBLE # HAVE_LONG_LONG # HAVE_WCHAR_T # HAVE_WINT_T # HAVE_INTTYPES_H_WITH_UINTMAX # HAVE_STDINT_H_WITH_UINTMAX types = [ ('intmax_t', 'HAVE_INTMAX_T', None), ('long double', 'HAVE_LONG_DOUBLE', None), ('long long', 'HAVE_LONG_LONG', None), ('wchar_t', 'HAVE_WCHAR_T', None), ('wint_t', 'HAVE_WINT_T', None), ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include '), ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include '), ('std::istreambuf_iterator', 'HAVE_DECL_ISTREAMBUF_ITERATOR', '#include \n#include ') ] for t in types: utils.addToConfig("/* Define to 1 if you have the `%s' type. */" % t[0], newline=1) if conf.CheckType(t[0], includes=t[2]): utils.addToConfig('#define %s 1' % t[1]) else: utils.addToConfig('/* #undef %s */' % t[1]) # windows/msvc sys/types.h does not have pid_t # FIXME: #include is the right way? if not conf.CheckType('pid_t', includes='#include '): utils.addToConfig('#define pid_t int') # determine the use of std::tolower or tolower if conf.CheckCXXGlobalCstd(): utils.addToConfig('#define CXX_GLOBAL_CSTD 1') else: utils.addToConfig('/* #undef CXX_GLOBAL_CSTD */') # PACKAGE # PACKAGE_VERSION # DEVEL_VERSION utils.addToConfig('#define PACKAGE "%s%s"' % (PACKAGE, env['PROGRAM_SUFFIX'])) utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION) if DEVEL_VERSION: utils.addToConfig('#define DEVEL_VERSION 1') # ENABLE_ASSERTIONS # ENABLE_NLS # WITH_WARNINGS # _GLIBCXX_CONCEPT_CHECKS # items are (ENV, ARGUMENTS) values = [ ('ENABLE_ASSERTIONS', 'assertions'), ('ENABLE_NLS', 'nls'), ('WITH_WARNINGS', 'warnings'), ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'), ] for val in values: if (env.has_key(val[0]) and env[val[0]]) or \ (env.has_key(val[1]) and env[val[1]]): utils.addToConfig('#define %s 1' % val[0]) else: utils.addToConfig('/* #undef %s */' % val[0]) # disable automatic linking of boost libraries. # This is an interesting feature that is supposed to be useful under # windows but since I can not find a way to use it on all platforms, # I disable it for now. utils.addToConfig('#define BOOST_ALL_NO_LIB 1') env['EXTRA_LIBS'] = [] # HAVE_LIBAIKSAURUS # AIKSAURUS_H_LOCATION if conf.CheckLib('Aiksaurus'): utils.addToConfig("#define HAVE_LIBAIKSAURUS 1") if (conf.CheckCXXHeader("Aiksaurus.h")): utils.addToConfig("#define AIKSAURUS_H_LOCATION ") elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")): utils.addToConfig("#define AIKSAURUS_H_LOCATION ") else: utils.addToConfig("#define AIKSAURUS_H_LOCATION") env['EXTRA_LIBS'].append('Aiksaurus') # USE_ASPELL # USE_PSPELL # USE_ISPELL # determine headers to use spell_engine = ARGUMENTS.get('spell', 'auto') spell_detected = False if spell_engine in ['auto', 'aspell'] and \ conf.CheckLib('aspell'): utils.addToConfig('#define USE_ASPELL 1') env['USE_ASPELL'] = True env['USE_PSPELL'] = False env['USE_ISPELL'] = False env['EXTRA_LIBS'].append('aspell') spell_detected = True elif spell_engine in ['auto', 'pspell'] and \ conf.CheckLib('pspell'): utils.addToConfig('#define USE_PSPELL 1') env['USE_ASPELL'] = False env['USE_PSPELL'] = True env['USE_ISPELL'] = False env['EXTRA_LIBS'].append('pspell') spell_detected = True elif spell_engine in ['auto', 'ispell'] and \ conf.CheckLib('ispell'): utils.addToConfig('#define USE_ISPELL 1') env['USE_ASPELL'] = False env['USE_PSPELL'] = False env['USE_ISPELL'] = True env['EXTRA_LIBS'].append('ispell') spell_detected = True if not spell_detected: env['USE_ASPELL'] = False env['USE_PSPELL'] = False env['USE_ISPELL'] = False # FIXME: can lyx work without an spell engine if spell_engine == 'auto': print "Warning: Can not locate any spell checker" else: print "Warning: Can not locate specified spell checker:", spell_engine # USE_POSIX_PACKAGING # USE_MACOSX_PACKAGING # USE_WINDOWS_PACKAGING if packaging_method == 'windows': utils.addToConfig('#define USE_WINDOWS_PACKAGING 1') elif packaging_method == 'posix': utils.addToConfig('#define USE_POSIX_PACKAGING 1') elif packaging_method == 'mac': utils.addToConfig('#define USE_MACOSX_PACKAGING 1') # BOOST_POSIX if boost_posix: utils.addToConfig('#define BOOST_POSIX 1') else: utils.addToConfig('/* #undef BOOST_POSIX */') # MKDIR_TAKES_ONE_ARG if conf.CheckMkdirOneArg(): utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1') else: utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */') # SELECT_TYPE_ARG1 # SELECT_TYPE_ARG234 # SELECT_TYPE_ARG5 (arg1, arg234, arg5) = conf.CheckSelectArgType() utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1) utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234) utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5) # mkstemp # USE_BOOST_FORMAT # WANT_GETFILEATTRIBUTESEX_WRAPPER utils.endConfigH(TOP_SRC_DIR) # env['EXTRA_LIBS'] will be modified later, so a unique copy is needed # NOTE that we do *not* save qt_libs in environment. env_cache['EXTRA_LIBS'] = copy.copy(env['EXTRA_LIBS']) env_cache['USE_ASPELL'] = env['USE_ASPELL'] env_cache['USE_PSPELL'] = env['USE_PSPELL'] env_cache['USE_ISPELL'] = env['USE_ISPELL'] env_cache['HAVE_ASPRINTF'] = env['HAVE_ASPRINTF'] env_cache['HAVE_WPRINTF'] = env['HAVE_WPRINTF'] env_cache['HAVE_SNPRINTF'] = env['HAVE_SNPRINTF'] env_cache['HAVE_POSIX_PRINTF'] = env['HAVE_POSIX_PRINTF'] env_cache['HAVE_FCNTL'] = env['HAVE_FCNTL'] else: # # this comes as a big surprise, without this line # (doing nothing obvious), adding fast_start=yes # to a build with fast_start=no will result in a rebuild # Note that the exact header file to check does not matter conf.CheckCHeader('io.h') # only a few variables need to be rescanned env['EXTRA_LIBS'] = copy.copy(env_cache['EXTRA_LIBS']) env['USE_ASPELL'] = env_cache['USE_ASPELL'] env['USE_PSPELL'] = env_cache['USE_PSPELL'] env['USE_ISPELL'] = env_cache['USE_ISPELL'] env['HAVE_ASPRINTF'] = env_cache['HAVE_ASPRINTF'] env['HAVE_WPRINTF'] = env_cache['HAVE_WPRINTF'] env['HAVE_SNPRINTF'] = env_cache['HAVE_SNPRINTF'] env['HAVE_POSIX_PRINTF'] = env_cache['HAVE_POSIX_PRINTF'] env['HAVE_FCNTL'] = env_cache['HAVE_FCNTL'] # # Finish auto-configuration env = conf.Finish() #---------------------------------------------------------- # Now set up our build process accordingly #---------------------------------------------------------- # # QT_LIB etc (EXTRA_LIBS holds lib for each frontend) # # NOTE: Tool('qt') or Tool('qt4') will be loaded later # in their respective directory and specialized env. try: if frontend == 'qt3': # note: env.Tool('qt') my set QT_LIB to qt env['QT_LIB'] = 'qt-mt' env['EXTRA_LIBS'].append('qt-mt') if platform_name == 'cygwin' and use_X11: env['EXTRA_LIBS'].extend(['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv', 'pthread']) env.AppendUnique(LIBPATH = ['/usr/X11R6/lib']) elif frontend == 'qt4': if platform_name == "win32": env['QT_LIB'] = ['QtCore4', 'QtGui4'] else: env['QT_LIB'] = ['QtCore', 'QtGui'] env['EXTRA_LIBS'] += env['QT_LIB'] except: print "Can not locate qt tools" print "What I get is " print " QTDIR: ", env['QTDIR'] if platform_name in ['win32', 'cygwin']: # the final link step needs stdc++ to succeed under mingw # FIXME: shouldn't g++ automatically link to stdc++? if use_vc: env['SYSTEM_LIBS'] = ['shlwapi', 'gdi32', 'shell32', 'advapi32', 'zdll'] else: env['SYSTEM_LIBS'] = ['shlwapi', 'stdc++', 'z'] else: env['SYSTEM_LIBS'] = ['z'] # # Build parameters CPPPATH etc # # boost is always in, src is needed for config.h # # QT_INC_PATH is not needed for *every* source file env['CPPPATH'].remove(env['QT_INC_PATH']) env['CPPPATH'] += ['$TOP_SRC_DIR/boost', '$TOP_SRC_DIR/src'] # TODO: add (more) appropriate compiling options (-DNDEBUG etc) # for debug/release mode if ARGUMENTS.get('mode', default_build_mode) == 'debug': env.AppendUnique(CCFLAGS = []) else: env.AppendUnique(CCFLAGS = []) # # Customized builders # # install customized builders env['BUILDERS']['substFile'] = Builder(action = utils.env_subst) # # A Link script for cygwin see # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html # for details # if platform_name == 'cygwin': ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++' ld_script = utils.installCygwinLDScript(ld_script_path) env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc', '-Wl,--script,%s' % ld_script, '-Wl,-s']) # # Report results # # src/support/package.C.in needs the following to replace # LYX_ABS_INSTALLED_DATADIR (e.g. /usr/local/lyx/share/lyx) env['LYX_DIR'] = env['SHARE_DIR'] # LYX_ABS_INSTALLED_LOCALEDIR env['LOCALEDIR'] = env['LOCALE_DIR'] env['TOP_SRCDIR'] = env['TOP_SRC_DIR'] # needed by src/version.C.in => src/version.C env['PACKAGE_VERSION'] = PACKAGE_VERSION # fill in the version info env['VERSION_INFO'] = '''Configuration Host type: %s Special build flags: %s C Compiler: %s C Compiler flags: %s %s C++ Compiler: %s C++ Compiler LyX flags: %s C++ Compiler flags: %s %s Linker flags: %s Linker user flags: %s Build info: Builing directory: %s Local library directory: %s Libraries pathes: %s Boost libraries: %s Extra libraries: %s System libraries: %s include search path: %s Frontend: Frontend: %s Packaging: %s LyX dir: %s LyX binary dir: %s LyX files dir: %s ''' % (platform_name, env.subst('$CCFLAGS'), env.subst('$CC'), env.subst('$CPPFLAGS'), env.subst('$CFLAGS'), env.subst('$CXX'), env.subst('$CXXFLAGS'), env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'), env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'), env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'), str(env['LIBPATH']), str(env['BOOST_LIBRARIES']), str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']), str(env['CPPPATH']), env['frontend'], packaging_method, env['PREFIX'], env['BIN_DEST_DIR'], env['SHARE_DIR']) if env['frontend'] in ['qt3', 'qt4']: env['VERSION_INFO'] += ''' include dir: %s library dir: %s X11: %s ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11) if not fast_start: print env['VERSION_INFO'] # # Mingw command line may be too short for our link usage, # Here we use a trick from scons wiki # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32 # # I also would like to add logging (commands only) capacity to the # spawn system. logfile = env.get('logfile', default_log_file) if logfile != '' or platform_name == 'win32': import time utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'), info = '''# This is a log of commands used by scons to build lyx # Time: %s # Command: %s # Info: %s ''' % (time.asctime(), ' '.join(sys.argv), env['VERSION_INFO'].replace('\n','\n# ')) ) # # Cleanup stuff # # -h will print out help info Help(opts.GenerateHelpText(env)) # save environment settings (for fast_start option) cache_file = open(env_cache_file, 'w') cPickle.dump(env_cache, cache_file) cache_file.close() #---------------------------------------------------------- # Start building #---------------------------------------------------------- Export('env') # this has been the source of problems on some platforms... # I find that I need to supply it with full path name env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign')) # this usage needs further investigation. #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend)) env['BUILD_TARGETS'] = BUILD_TARGETS if env.has_key('rebuild'): env['REBUILD_TARGETS'] = env['rebuild'].split(',') else: env['REBUILD_TARGETS'] = None print "Building all targets recursively" env.SConscript('$SCONS_DIR/SConscript', duplicate = 0)