From d9f90c2c0419cc6ff01f38c8652d58d83ab38eab Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 30 Jan 2011 22:12:55 +0100 Subject: [PATCH] SCons: finish reworking buildsystem to rely on custom builders. All target paths and install targets now defined automatically, most of the buildscript just using plain sourcefile names --- SConstruct | 67 ++++++++++++----------- admin/scons/Buildhelper.py | 15 ++++-- admin/scons/LumieraEnvironment.py | 90 ++++++++++++++++++++----------- tests/SConscript | 6 +-- 4 files changed, 108 insertions(+), 70 deletions(-) diff --git a/SConstruct b/SConstruct index 95797748d..6eadc765b 100644 --- a/SConstruct +++ b/SConstruct @@ -22,35 +22,39 @@ ##################################################################### +# 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. + + #-----------------------------------Configuration TARGDIR = 'target' VERSION = '0.1+pre.01' -TOOLDIR = './admin/scons' +TOOLDIR = './admin/scons' # SCons plugins SCRIPTDIR = './admin' OPTCACHE = 'optcache' CUSTOPTFILE = 'custom-options' +# these are accessible via env.path.xxxx srcIcon = 'icons' srcConf = 'data/config' buildExe = '#$TARGDIR' buildLib = '#$TARGDIR/modules' buildPlug = '#$TARGDIR/modules' buildIcon = '#$TARGDIR/icons' +buildUIRes = '#$TARGDIR/' buildConf = '#$TARGDIR/config' installExe = '#$DESTDIR/lib/lumiera' installLib = '#$DESTDIR/lib/lumiera/modules' installPlug = '#$DESTDIR/lib/lumiera/modules' installIcon = '#$DESTDIR/share/lumiera/icons' -installConf = '#$DESTDIR/share/lumiera/config' +installUIRes = '#$DESTDIR/share/lumiera/' +installConf = '#$DESTDIR/lib/lumiera/config' localDefinitions = locals() #-----------------------------------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 @@ -76,7 +80,7 @@ def setupBasicEnvironment(localDefinitions): vars = defineCmdlineVariables() env = LumieraEnvironment(variables=vars ,toolpath = [TOOLDIR] - ,pathConfig = extract_localPathDefs(localDefinitions) + ,pathConfig = extract_localPathDefs(localDefinitions) # e.g. buildExe -> env.path.buildExe ,TARGDIR = TARGDIR ,DESTDIR = '$INSTALLDIR/$PREFIX' ,VERSION = VERSION @@ -239,10 +243,10 @@ def configurePlatform(env): conf.env.mergeConf('nobugmt') if not conf.CheckCXXHeader('tr1/memory'): - problems.append('We rely on the std::tr1 proposed standard extension for shared_ptr.') + problems.append('We rely on the std::tr1 standard C++ extension for shared_ptr.') if not conf.CheckCXXHeader('boost/config.hpp'): - problems.append('We need the C++ boost-lib.') + problems.append('We need the C++ boost-libraries.') else: if not conf.CheckCXXHeader('boost/shared_ptr.hpp'): problems.append('We need boost::shared_ptr (shared_ptr.hpp).') @@ -264,16 +268,16 @@ def configurePlatform(env): conf.env.mergeConf('gavl') if not conf.CheckPkgConfig('gtkmm-2.4', 2.8): - problems.append('Unable to configure GTK--, exiting.') + problems.append('Unable to configure GTK--') if not conf.CheckPkgConfig('glibmm-2.4', '2.16'): - problems.append('Unable to configure Lib glib--, exiting.') + problems.append('Unable to configure Lib glib--') 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.') + problems.append('Unable to configure Cairo--') verGDL = '2.27.1' if not conf.CheckPkgConfig('gdl-lum', verGDL, alias='gdl'): @@ -309,7 +313,7 @@ def configurePlatform(env): -def definePackagingTargets(env, artifacts): +def defineSetupTargets(env, artifacts): """ build operations and targets to be done /before/ compiling. things like creating a source tarball or preparing a version header. """ @@ -339,20 +343,19 @@ def defineBuildTargets(env, artifacts): artifacts['corelib'] = core artifacts['support'] = lLib - artifacts['lumiera'] = env.Program('lumiera', ['src/lumiera/main.cpp'], LIBS=core, install=True) + artifacts['lumiera'] = ( env.Program('lumiera', ['src/lumiera/main.cpp'], LIBS=core, install=True) + + env.ConfigData(env.path.srcConf+'dummy_lumiera.ini') + ) # building Lumiera Plugins - envPlu = env.Clone() - envPlu.Append(CPPDEFINES='LUMIERA_PLUGIN') artifacts['plugins'] = [] # currently none # render and install Icons vector_icon_dir = env.path.srcIcon+'svg' prerendered_icon_dir = env.path.srcIcon+'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'])] + artifacts['icons'] = ( [env.IconRender(f) for f in scanSubtree(vector_icon_dir, ['*.svg'])] + + [env.IconResource(f) for f in scanSubtree(prerendered_icon_dir, ['*.png'])] ) - ##TODO make that into a resource builder # the Lumiera GTK GUI envGtk = env.Clone() @@ -362,14 +365,13 @@ def defineBuildTargets(env, artifacts): objgui = srcSubtree(envGtk,'src/gui') guimodule = envGtk.LumieraPlugin('gtk_gui', objgui, install=True) artifacts['gui'] = ( guimodule - + env.Install('$TARGDIR', env.Glob('src/gui/*.rc')) + + [env.GuiResource(f) for f in env.Glob('src/gui/*.rc')] + artifacts['icons'] ) - artifacts['guimodule'] = guimodule ###TODO better organisation of GUI components - + # call subdir SConscript(s) for independent components - SConscript(dirs=['src/tool'], exports='env artifacts core') - SConscript(dirs=['tests'], exports='env envPlu artifacts core') + SConscript(dirs=['src/tool'], exports='env artifacts core') + SConscript(dirs=['tests'], exports='env artifacts core') @@ -377,8 +379,11 @@ def definePostBuildTargets(env, artifacts): """ define further actions after the core build (e.g. Documentaion). define alias targets to trigger the installing. """ - build = env.Alias('build', artifacts['lumiera']+artifacts['gui']+artifacts['plugins']+artifacts['tools']) - env.Default('build') + build = env.Alias('build', ( artifacts['lumiera'] + + artifacts['plugins'] + + artifacts['tools'] + + artifacts['gui'] + )) # additional files to be cleaned when cleaning 'build' env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ]) env.Clean ('build', [ 'src/pre.gch' ]) @@ -387,7 +392,9 @@ def definePostBuildTargets(env, artifacts): env.Alias ('doc', doxydoc) env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt']) - allbu = env.Alias('all', build+artifacts['testsuite']+doxydoc) + env.Alias ('all', build+artifacts['testsuite']+doxydoc) + env.Default('build') + # SCons default target def defineInstallTargets(env, artifacts): @@ -396,8 +403,6 @@ def defineInstallTargets(env, artifacts): for all executables automatically. see LumieraEnvironment.py """ env.SymLink('$DESTDIR/bin/lumiera',env.path.installExe+'lumiera','../lib/lumiera/lumiera') - - env.Install(dir = env.path.installConf, source=env.path.srcConf+'dummy_lumiera.ini') ### TODO should become a resource builder # env.Install(dir = '$DESTDIR/share/doc/lumiera$VERSION/devel', source=artifacts['doxydoc']) env.Alias('install', '$DESTDIR') @@ -424,7 +429,7 @@ artifacts = {} # 'plugins' : plugin shared lib # 'tools' : small tool applications (e.g mpegtoc) -definePackagingTargets(env, artifacts) +defineSetupTargets(env, artifacts) defineBuildTargets(env, artifacts) definePostBuildTargets(env, artifacts) defineInstallTargets(env, artifacts) diff --git a/admin/scons/Buildhelper.py b/admin/scons/Buildhelper.py index 2c5156863..aed9c07da 100644 --- a/admin/scons/Buildhelper.py +++ b/admin/scons/Buildhelper.py @@ -99,7 +99,7 @@ def findSrcTrees(location, patterns=SRCPATTERNS): After having initially expanded the given location with #globRootdirs, each directory is examined depth first, until encountering a directory containing source files, which then yields a result. Especially, this can be used to traverse - an organisational directory structure and find out all possible source trees of + an organisational directory structure and find out all possible source trees to be built into packages, plugins, individual tool executables etc. @return: the relative path names of all source root dirs found (generator function). """ @@ -138,12 +138,19 @@ def filterNodes(nlist, removeName=None): -def getDirname(dir): - """ extract directory name without leading path """ +def getDirname(dir, basePrefix=None): + """ extract directory name without leading path, + or without the explicitly given basePrefix + """ dir = os.path.realpath(dir) if not os.path.isdir(dir): dir,_ = os.path.split(dir) - _, name = os.path.split(dir) + if basePrefix: + basePrefix = os.path.realpath(basePrefix) + if str(dir).startswith(basePrefix): + name = str(dir)[len(basePrefix):] + else: + _, name = os.path.split(dir) return name diff --git a/admin/scons/LumieraEnvironment.py b/admin/scons/LumieraEnvironment.py index 12f5dbcc7..82a89b6ae 100644 --- a/admin/scons/LumieraEnvironment.py +++ b/admin/scons/LumieraEnvironment.py @@ -46,7 +46,7 @@ class LumieraEnvironment(Environment): self.Tool("BuilderDoxygen") self.Tool("ToolDistCC") self.Tool("ToolCCache") - RegisterIcon_Builder(self) + register_LumieraResourceBuilder(self) register_LumieraCustomBuilders(self) def Configure (self, *args, **kw): @@ -89,25 +89,6 @@ class LumieraEnvironment(Environment): if alias: self.libInfo[alias] = libInfo return libInfo - - - def SymLink(self, target, source, linktext=None): - """ use python to create a symlink - """ - def makeLink(target,source,env): - if linktext: - dest = linktext - else: - dest = str(source[0]) - link = str(target[0]) - os.symlink(dest, link) - def reportLink(target,source,env): - dest = str(source[0]) - link = str(target[0]) - return "Install link %s -> %s" % (link,dest) - - action = Action(makeLink,reportLink) - self.Command (target,source, action) @@ -136,7 +117,7 @@ class LumieraConfigContext(ConfigBase): ####### Lumiera custom tools and builders ##################################### -def RegisterIcon_Builder(env): +def register_LumieraResourceBuilder(env): """ Registers Custom Builders for generating and installing Icons. Additionally you need to build the tool (rsvg-convert.c) used to generate png from the svg source using librsvg. @@ -147,21 +128,39 @@ def RegisterIcon_Builder(env): def invokeRenderer(target, source, env): source = str(source[0]) - targetdir = env.subst("$TARGDIR") + targetdir = env.subst(env.path.buildIcon) + if targetdir.startswith('#'): targetdir = targetdir[1:] renderer.main([source,targetdir]) return 0 def createIconTargets(target,source,env): """ parse the SVG to get the target file names """ source = str(source[0]) - targetdir = os.path.basename(str(target[0])) + targetdir = env.path.buildIcon targetfiles = renderer.getTargetNames(source) # parse SVG - return (["$TARGDIR/%s" % name for name in targetfiles], source) + return ([targetdir+name for name in targetfiles], source) - def IconCopy(env, source): - """Copy icon to corresponding icon dir. """ - subdir = getDirname(source) - return env.Install("$TARGDIR/%s" % subdir, source) + def IconResource(env, source): + """Copy icon pixmap to corresponding icon dir. """ + subdir = getDirname(str(source)) + toBuild = env.path.buildIcon+subdir + toInstall = env.path.installIcon+subdir + env.Install (toInstall, source) + return env.Install(toBuild, source) + + def GuiResource(env, source): + subdir = getDirname(str(source)) + toBuild = env.path.buildUIRes+subdir + toInstall = env.path.installUIRes+subdir + env.Install (toInstall, source) + return env.Install(toBuild, source) + + def ConfigData(env, source): + subdir = getDirname(str(source), env.path.srcConf) # removes source location path prefix + toBuild = env.path.buildConf+subdir + toInstall = env.path.installConf+subdir + env.Install (toInstall, source) + return env.Install(toBuild, source) buildIcon = env.Builder( action = Action(invokeRenderer, "rendering Icon: $SOURCE --> $TARGETS") @@ -169,7 +168,9 @@ def RegisterIcon_Builder(env): , emitter = createIconTargets ) env.Append(BUILDERS = {'IconRender' : buildIcon}) - env.AddMethod(IconCopy) + env.AddMethod(IconResource) + env.AddMethod(GuiResource) + env.AddMethod(ConfigData) @@ -191,9 +192,9 @@ class WrappedStandardExeBuilder(SCons.Util.Proxy): Automatically define installation targets for build results. @note only returning the build targets, not the install targets """ - customisedEnv = self.getCustomEnvironment(env, target=target, **kw) # defined in subclasses + customisedEnv = self.getCustomEnvironment(env, target=target, **kw) # defined in subclasses buildTarget = self.buildLocation(customisedEnv, target) - buildTarget = self.invokeOriginalBuilder (customisedEnv, buildTarget, source, **kw) + buildTarget = self.invokeOriginalBuilder(customisedEnv, buildTarget, source, **kw) self.installTarget(customisedEnv, buildTarget, **kw) return buildTarget @@ -297,6 +298,9 @@ class LumieraPluginBuilder(LumieraModuleBuilder): + + + def register_LumieraCustomBuilders (lumiEnv): """ install the customised builder versions tightly integrated with our buildsystem. Especially, these builders automatically add the build and installation locations @@ -311,3 +315,27 @@ def register_LumieraCustomBuilders (lumiEnv): lumiEnv['BUILDERS']['SharedLibrary'] = libraryBuilder lumiEnv['BUILDERS']['LoadableModule'] = smoduleBuilder lumiEnv['BUILDERS']['LumieraPlugin'] = lpluginBuilder + + + def SymLink(env, target, source, linktext=None): + """ use python to create a symlink + """ + def makeLink(target,source,env): + if linktext: + dest = linktext + else: + dest = str(source[0]) + link = str(target[0]) + os.symlink(dest, link) + + if linktext: srcSpec=linktext + else: srcSpec='$SOURCE' + action = Action(makeLink, "Install link: $TARGET -> "+srcSpec) + env.Command (target,source, action) + + # adding SymLink direclty as method on the environment object + # Probably that should better be a real builder, but I couldn't figure out + # how to get the linktext through literally, which is necessary for relative links. + # Judging from the sourcecode of SCons.Builder.BuilderBase, there seems to be no way + # to set the executor_kw, which are passed through to the action object. + lumiEnv.AddMethod(SymLink) diff --git a/tests/SConscript b/tests/SConscript index cc6078878..2e7980c68 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -12,13 +12,11 @@ from Buildhelper import scanSubtree from Buildhelper import globRootdirs from Buildhelper import createPlugins -Import('env','envPlu','artifacts','core') +Import('env','artifacts','core') # temp fix to add test.h -- wouldn't it be better to put this header be into src/lib ? env = env.Clone() env.Append(CPPPATH='#/.') # add Rootdir to Includepath, so test/test.h is found -envPlu = envPlu.Clone() -envPlu.Append(CPPPATH='#/.') # temp fix------------- def testExecutable(env,tree, exeName=None, obj=None): @@ -59,7 +57,7 @@ moduledirs = globRootdirs('*') artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in ['bugs'] ] # was: ['lib','components'] + [ testCollection(env, dir) for dir in moduledirs if not dir in specials] - + createPlugins(envPlu, 'plugin') + + createPlugins(env, 'plugin') + env.File(glob('*.tests')) # depending on the test definition files for test.sh )