# -*- python -*- ## ## SConstruct - SCons based build-sytem for Lumiera ## # Copyright (C) Lumiera.org # 2008, Hermann Vosseler # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ##################################################################### #-----------------------------------Configuration OPTIONSCACHEFILE = 'optcache' CUSTOPTIONSFILE = 'custom-options' SRCDIR = 'src' TARDIR = 'target' LIBDIR = 'target/modules' MODULES = 'modules' TESTDIR = 'tests' ICONDIR = 'icons' VERSION = '0.1+pre.01' TOOLDIR = './admin/scons' SCRIPTDIR = './admin' #-----------------------------------Configuration # NOTE: scons -h for help. # Read more about the SCons build system at: http://www.scons.org # Basically, this script just /defines/ the components and how they # fit together. SCons will derive the necessary build steps. import os import sys sys.path.append(TOOLDIR) sys.path.append(SCRIPTDIR) from Buildhelper import * from LumieraEnvironment import * ##################################################################### def setupBasicEnvironment(): """ define cmdline options, build type decisions """ EnsurePythonVersion(2,3) EnsureSConsVersion(1,0) Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5 vars = defineCmdlineVariables() env = LumieraEnvironment(variables=vars ,toolpath = [TOOLDIR] ,tools = ["default", "BuilderGCH", "BuilderDoxygen"] ) env.Tool("ToolDistCC") env.Tool("ToolCCache") handleVerboseMessages(env) env.Append ( CCCOM=' -std=gnu99') env.Append ( SHCCCOM=' -std=gnu99') # workaround for a bug: CCCOM currently doesn't honour CFLAGS, only CCFLAGS env.Replace( VERSION=VERSION , SRCDIR=SRCDIR , TARDIR=TARDIR , LIBDIR=LIBDIR , MODULES=MODULES , ICONDIR=ICONDIR , DESTDIR=env.subst('$INSTALLDIR/$PREFIX') , CPPPATH=["#"+SRCDIR] # used to find includes, "#" means always absolute to build-root , CPPDEFINES=['-DLUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines , CCFLAGS='-Wall -Wextra ' , CFLAGS='-std=gnu99' ) handleNoBugSwitches(env) env.Append(CPPDEFINES = '_GNU_SOURCE') appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG') # appendCppDefine(env,'OPENGL','USE_OPENGL') appendVal(env,'ARCHFLAGS','CCFLAGS') # for both C and C++ appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3') appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb') # setup search path for Lumiera plugins appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:./$MODULES\\"' ,'LUMIERA_PLUGIN_PATH=\\"$DESTDIR/lib/lumiera/:./$MODULES\\"') appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"' ,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"') prepareOptionsHelp(vars,env) vars.Save(OPTIONSCACHEFILE, env) return env def appendCppDefine(env,var,cppVar, elseVal=''): if env[var]: env.Append(CPPDEFINES = env.subst(cppVar) ) elif elseVal: env.Append(CPPDEFINES = env.subst(elseVal)) def appendVal(env,var,targetVar,val=None): if env[var]: env.Append( **{targetVar: env.subst(val) or env[var]}) def handleNoBugSwitches(env): """ set the build level for NoBug. Release builds imply no DEBUG whereas ALPHA and BETA require DEBUG """ level = env['BUILDLEVEL'] if level in ['ALPHA', 'BETA']: if not env['DEBUG']: print 'Warning: NoBug ALPHA or BETA builds requires DEBUG=yes, switching DEBUG on!' env.Replace( DEBUG = 1 ) env.Append(CPPDEFINES = 'EBUG_'+level) elif level == 'RELEASE': env.Replace( DEBUG = 0 ) def handleVerboseMessages(env): """ toggle verbose build output """ if not env['VERBOSE']: # SetOption('silent', True) env['CCCOMSTR'] = env['SHCCCOMSTR'] = " Compiling $SOURCE" env['CXXCOMSTR'] = env['SHCXXCOMSTR'] = " Compiling++ $SOURCE" env['LINKCOMSTR'] = " Linking --> $TARGET" env['LDMODULECOMSTR'] = " creating module [ $TARGET ]" def defineCmdlineVariables(): """ several toggles and configuration variables can be set on the commandline, current settings will be persisted in a options cache file. you may define custom variable settings in a separate file. Commandline will override both. """ vars = Variables([OPTIONSCACHEFILE, CUSTOPTIONSFILE]) vars.AddVariables( ('ARCHFLAGS', 'Set architecture-specific compilation flags (passed literally to gcc)','') ,('CC', 'Set the C compiler to use.', 'gcc') ,('CXX', 'Set the C++ compiler to use.', 'g++') ,PathVariable('CCACHE', 'Integrate with CCache', '', PathVariable.PathAccept) ,PathVariable('DISTCC', 'Invoke C/C++ compiler commands through DistCC', '', PathVariable.PathAccept) ,EnumVariable('BUILDLEVEL', 'NoBug build level for debugging', 'ALPHA', allowed_values=('ALPHA', 'BETA', 'RELEASE')) ,BoolVariable('DEBUG', 'Build with debugging information and no optimisations', False) ,BoolVariable('OPTIMIZE', 'Build with strong optimisation (-O3)', False) ,BoolVariable('VALGRIND', 'Run Testsuite under valgrind control', True) ,BoolVariable('VERBOSE', 'Print full build commands', False) ,('TESTSUITES', 'Run only Testsuites matching the given pattern', '') # ,BoolVariable('OPENGL', 'Include support for OpenGL preview rendering', False) # ,EnumVariable('DIST_TARGET', 'Build target architecture', 'auto', # allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2) ,PathVariable('PREFIX', 'Installation dir prefix', 'usr/local', PathVariable.PathAccept) ,PathVariable('INSTALLDIR', 'Root output directory for install. Final installation will happen in INSTALLDIR/PREFIX/... ', '/', PathVariable.PathIsDir) ,PathVariable('PKGLIBDIR', 'Installation dir for plugins, defaults to PREFIX/lib/lumiera/modules', '',PathVariable.PathAccept) ,PathVariable('PKGDATADIR', 'Installation dir for default config, usually PREFIX/share/lumiera', '',PathVariable.PathAccept) ) return vars def prepareOptionsHelp(vars,env): prelude = """ USAGE: scons [-c] [OPTS] [key=val [key=val...]] [TARGETS] Build and optionally install Lumiera. Without specifying any target, just the (re)build target will run. Add -c to the commandline to clean up anything a given target would produce Special Targets: build : just compile and link testcode: additionally compile the Testsuite check : build and run the Testsuite doc : generate documentation (Doxygen) install : install created artifacts at PREFIX src.tar : create source tarball doc.tar : create developer doc tarball tar : create all tarballs Configuration Options: """ Help(prelude + vars.GenerateHelpText(env)) def configurePlatform(env): """ locate required libs. setup platform specific options. Abort build in case of failure. """ conf = env.Configure() # run all configuration checks in the given env # Perform checks for prerequisites -------------------------------------------- problems = [] if not conf.TryAction('pkg-config --version > $TARGET')[0]: problems.append('We need pkg-config for including library configurations, exiting.') if not conf.CheckLibWithHeader('m', 'math.h','C'): problems.append('Did not find math.h / libm.') if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'): problems.append('Functions for runtime dynamic loading not available.') if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'): problems.append('Did not find the pthread lib or pthread.h.') else: conf.env.Append(CPPFLAGS = ' -DHAVE_PTHREAD') conf.env.Append(CCFLAGS = ' -pthread') if conf.CheckCHeader('execinfo.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_EXECINFO_H') if conf.CheckCHeader('valgrind/valgrind.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_VALGRIND_H') else: print 'Valgrind not found. The use of Valgrind is optional; building without.' if not conf.CheckPkgConfig('nobugmt', 201006.1): problems.append('Did not find NoBug [http://www.lumiera.org/nobug_manual.html].') else: conf.env.mergeConf('nobugmt') if not conf.CheckCXXHeader('tr1/memory'): problems.append('We rely on the std::tr1 proposed standard extension for shared_ptr.') if not conf.CheckCXXHeader('boost/config.hpp'): problems.append('We need the C++ boost-lib.') else: if not conf.CheckCXXHeader('boost/shared_ptr.hpp'): problems.append('We need boost::shared_ptr (shared_ptr.hpp).') if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'): problems.append('We need boost::program_options (including binary lib for linking).') if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'): problems.append('We need the boost regular expression lib (incl. binary lib for linking).') if conf.CheckLib(symbol='clock_gettime'): print 'Using function clock_gettime() as defined in the C-lib...' else: if not conf.CheckLib(symbol='clock_gettime', library='rt'): problems.append('No library known to provide the clock_gettime() function.') if not conf.CheckPkgConfig('gavl', 1.0): problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].') else: conf.env.mergeConf('gavl') if not conf.CheckPkgConfig('gtkmm-2.4', 2.8): problems.append('Unable to configure GTK--, exiting.') if not conf.CheckPkgConfig('glibmm-2.4', '2.16'): problems.append('Unable to configure Lib glib--, exiting.') if not conf.CheckPkgConfig('gthread-2.0', '2.12.4'): problems.append('Need gthread support lib for glib-- based thread handling.') if not conf.CheckPkgConfig('cairomm-1.0', 0.6): problems.append('Unable to configure Cairo--, exiting.') verGDL = '2.27.1' if not conf.CheckPkgConfig('gdl-lum', verGDL, alias='gdl'): print 'Custom package "gdl-lum" not found. Trying official GDL release >=%s...' % verGDL if not conf.CheckPkgConfig('gdl-1.0', verGDL, alias='gdl'): problems.append('GNOME Docking Library not found. We either need a very recent GDL ' 'version (>=%s), or the custom package "gdl-lum".' % verGDL) if not conf.CheckPkgConfig('librsvg-2.0', '2.18.1'): problems.append('Need rsvg Library for rendering icons.') if not conf.CheckCHeader(['X11/Xutil.h', 'X11/Xlib.h'],'<>'): problems.append('Xlib.h and Xutil.h required. Please install libx11-dev.') if not conf.CheckPkgConfig('xv') : problems.append('Need libXv...') if not conf.CheckPkgConfig('xext'): problems.append('Need libXext.') # report missing dependencies if problems: print "*** unable to build due to the following problems:" for isue in problems: print " * %s" % isue print print "build aborted." Exit(1) print "** Gathered Library Info: %s" % conf.env.libInfo.keys() # create new env containing the finished configuration return conf.Finish() def definePackagingTargets(env, artifacts): """ build operations and targets to be done /before/ compiling. things like creating a source tarball or preparing a version header. """ pass def defineBuildTargets(env, artifacts): """ define the source file/dirs comprising each artifact to be built. setup sub-environments with special build options if necessary. We use a custom function to declare a whole tree of srcfiles. """ # use PCH to speed up building // disabled for now due to strange failures # env['GCH'] = ( env.PrecompiledHeader('$SRCDIR/pre.hpp') # + env.PrecompiledHeader('$SRCDIR/pre_a.hpp') # ) lLib = env.LumieraLibrary('$LIBDIR/lumiera', srcSubtree(env,'$SRCDIR/lib')) lApp = env.LumieraLibrary('$LIBDIR/lumieracommon', srcSubtree(env,'$SRCDIR/common'), LIBS=lLib) lBack = env.LumieraLibrary('$LIBDIR/lumierabackend', srcSubtree(env,'$SRCDIR/backend')) lProc = env.LumieraLibrary('$LIBDIR/lumieraproc', srcSubtree(env,'$SRCDIR/proc')) core = lLib+lApp+lBack+lProc artifacts['corelib'] = core artifacts['support'] = lLib artifacts['lumiera'] = env.LumieraExe('$TARDIR/lumiera', ['$SRCDIR/lumiera/main.cpp'], LIBS=core) # building Lumiera Plugins envPlu = env.Clone() envPlu.Append(CPPDEFINES='LUMIERA_PLUGIN') artifacts['plugins'] = [] # currently none # render and install Icons vector_icon_dir = env.subst('$ICONDIR/svg') prerendered_icon_dir = env.subst('$ICONDIR/prerendered') artifacts['icons'] = ( [env.IconRender(f) for f in scanSubtree(vector_icon_dir, ['*.svg'])] + [env.IconCopy(f) for f in scanSubtree(prerendered_icon_dir, ['*.png'])] ) ##TODO make that into a resource builder # the Lumiera GTK GUI envGtk = env.Clone() envGtk.mergeConf(['gtkmm-2.4','gthread-2.0','cairomm-1.0','gdl','xv','xext','sm']) envGtk.Append(CPPDEFINES='LUMIERA_PLUGIN', LIBS=core) objgui = srcSubtree(envGtk,'$SRCDIR/gui') guimodule = envGtk.LoadableModule('$LIBDIR/gtk_gui', objgui, SHLIBPREFIX='', SHLIBSUFFIX='.lum') artifacts['gui'] = ( guimodule + env.Install('$TARDIR', env.Glob('$SRCDIR/gui/*.rc')) + artifacts['icons'] ) artifacts['guimodule'] = guimodule ###TODO better organisation of GUI components # call subdir SConscript(s) for independent components SConscript(dirs=[SRCDIR+'/tool'], exports='env artifacts core') SConscript(dirs=[TESTDIR], exports='env envPlu artifacts core') def definePostBuildTargets(env, artifacts): """ define further actions after the core build (e.g. Documentaion). define alias targets to trigger the installing. """ ib = env.Alias('install-bin', '$DESTDIR/bin') il = env.Alias('install-lib', '$DESTDIR/lib') id = env.Alias('install-dat', '$DESTDIR/share') env.Alias('install', [ib, il, id]) build = env.Alias('build', artifacts['lumiera']+artifacts['gui']+artifacts['plugins']+artifacts['tools']) env.Default('build') # additional files to be cleaned when cleaning 'build' env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ]) env.Clean ('build', [ '$SRCDIR/pre.gch' ]) doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile') env.Alias ('doc', doxydoc) env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt']) allbu = env.Alias('allbuild', build+artifacts['testsuite']+doxydoc) def defineInstallTargets(env, artifacts): """ define artifacts to be installed into target locations. """ binDir = '$DESTDIR/bin/' lumDir = '$DESTDIR/lib/lumiera/' modDir = '$DESTDIR/lib/lumiera/$MODULES/' shaDir = '$DESTDIR/share/lumiera/' env.Install(dir = modDir, source=artifacts['corelib']) env.Install(dir = modDir, source=artifacts['plugins']) env.Install(dir = modDir, source=artifacts['guimodule']) lumi = env.Install(dir = lumDir, source=artifacts['lumiera']) tool = env.Install(dir = lumDir, source=artifacts['tools']) print "Aufruf LINK DESTDIR=" + env.get('DESTDIR') env.SymLink(binDir+"lumiera",lumi,"../lib/lumiera/lumiera") env.Install(dir = shaDir, source="data/config/dummy_lumiera.ini") ### TODO should become a resource builder # env.Install(dir = '$DESTDIR/share/doc/lumiera$VERSION/devel', source=artifacts['doxydoc']) ##################################################################### ### === MAIN === #################################################### env = setupBasicEnvironment() if not (isCleanupOperation(env) or isHelpRequest()): env = configurePlatform(env) artifacts = {} # the various things we build. # Each entry actually is a SCons-Node list. # Passing these entries to other builders defines dependencies. # 'lumiera' : the App # 'gui' : the GTK UI (plugin) # 'plugins' : plugin shared lib # 'tools' : small tool applications (e.g mpegtoc) # 'src,tar' : source tree as tarball (without doc) # 'doc.tar' : uml model, wiki, dev docu (no src) definePackagingTargets(env, artifacts) defineBuildTargets(env, artifacts) definePostBuildTargets(env, artifacts) defineInstallTargets(env, artifacts)