X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=site_scons%2Fsenfutil.py;h=da24b19464c73b470af0e82a25e10bfe46849e34;hb=HEAD;hp=246f72ed718c9156b5d60500357712a98242d3ac;hpb=42993f284009a951b77718ece3e7a2747041c566;p=senf.git diff --git a/site_scons/senfutil.py b/site_scons/senfutil.py index 246f72e..da24b19 100644 --- a/site_scons/senfutil.py +++ b/site_scons/senfutil.py @@ -1,36 +1,30 @@ -import os.path, glob, site_tools.Yaptu +import os, os.path, site_tools.Yaptu, types, re, fnmatch, sys +import SCons.Util from SCons.Script import * -import senfconf senfutildir = os.path.dirname(__file__) # Fix for SCons 0.97 compatibility try: Variables -except NameError: +except NameError: Variables = Options BoolVariable = BoolOption -def parseLogOption(value): - stream, area, level = ( x.strip() for x in value.strip().split('|') ) - stream = ''.join('(%s)' % x for x in stream.split('::') ) - if area : area = ''.join( '(%s)' % x for x in area.split('::') ) - else : area = '(_)' - return '((%s,%s,%s))' % (stream,area,level) - -def expandLogOption(target, source, env, for_signature): - if env.get('LOGLEVELS'): - return [ 'SENF_LOG_CONF="' + ''.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )+'"'] - else: - return [] - -class BuildTypeOptions: - def __init__(self, var): - self._var = var +########################################################################### +extdir = os.path.join(senfutildir, '../senf/Ext') +sys.path.append(extdir) + +for ext in os.listdir(extdir): + if not os.path.isdir( os.path.join(extdir, ext)): continue + if ext.startswith('.'): continue + try: + setattr( sys.modules[__name__], ext, + __import__('%s.site_scons' % ext, fromlist=['senfutil']).senfutil ) + except ImportError: + pass - def __call__(self, target, source, env, for_signature): - type = env['final'] and "final" or env['debug'] and "debug" or "normal" - return env[self._var + "_" + type] +########################################################################### def loadTools(env): global senfutildir @@ -48,7 +42,7 @@ Any construction environment variable may be set from the scons command line (see SConstruct file and SCons documentation for a list of variables) using - VARNAME=value Assign new value + VARNAME=value Assign new value VARNAME+=value Append value at end Special command line parameters: @@ -56,44 +50,154 @@ Special command line parameters: env.Help(vars.GenerateHelpText(env)) try : unknv = vars.UnknownVariables() except AttributeError: unknv = vars.UnknownOptions() - for k,v in unknv.iteritems(): + env.SetDefault(ARGUMENT_VARIABLES = {}) + for k,v in ARGLIST: + if not unknv.has_key(k) : continue if k.endswith('+'): env.Append(**{k[:-1]: v}) + env.Append(ARGUMENT_VARIABLES = {k[:-1]:v}) else: env.Replace(**{k: v}) + env.Append(ARGUMENT_VARIABLES = {k:v}) + if env.get('PARSEFLAGS', None): + env.MergeFlags(env['PARSEFLAGS']) + +def importProcessEnv(env): + env.Append( ENV = dict(( (k,v) + for pattern in env.get('IMPORT_ENV',[]) + for k,v in os.environ.iteritems() + if fnmatch.fnmatchcase(k,pattern) )) ) + + +###########################################################################$ +# SENF log option parsing + +def parseLogOption(value): + stream, area, level = ( x.strip() for x in value.strip().split('|') ) + stream = ''.join('(%s)' % x for x in stream.split('::') ) + if area : area = ''.join( '(%s)' % x for x in area.split('::') ) + else : area = '(_)' + return '((%s,%s,%s))' % (stream,area,level) +def expandLogOption(target, source, env, for_signature): + if env.subst('$LOGLEVELS'): + return [ 'SENF_LOG_CONF="' + ''.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )+'"'] + else: + return [] ########################################################################### -# This looks much more complicated than it is: We do three things here: -# a) switch between final or debug options -# b) parse the LOGLEVELS parameter into the correct SENF_LOG_CONF syntax -# c) check for a local SENF, set options accordingly -# d) check, wether the boost extensions are needed +# client SENF detection/configuration + +def detect_senf(env,senf_path, try_flavors): + """Detect senf with flavor in 'try_flavors' somewhere in 'senf_path'. -def SetupForSENF(env, senf_path = []): +This function returns True, if senf is found, False otherwise. +The environment 'env' is updated in the following way: + + SENFSYSLAYOUT set to True, if the install is a system installation, + False otherwise + + FLAVOR set to the detected senf flavor + + SENFDIR set to the base directory of the senf installation. +""" global senfutildir - senf_path.extend(('senf', os.path.dirname(senfutildir), '/usr/local', '/usr')) + senf_path.extend((os.path.dirname(senfutildir), '/usr/local', '/usr')) + + for path in senf_path: + if not path.startswith('/') : sconspath = '#/%s' % path + else : sconspath = path + for flavor in try_flavors: + suffix = flavor and "_"+flavor or "" + local_path = os.path.join(path,"senf%s.conf" % suffix) + sys_path = os.path.join(path, "lib", "senf", "senf%s.conf" % suffix) + if os.path.exists(local_path): + env.SetDefault( SENFSYSLAYOUT = False ) + elif os.path.exists(sys_path): + env.SetDefault( SENFSYSLAYOUT = True ) + else: + continue + env.SetDefault( FLAVOR = flavor, SENFDIR = sconspath ) + return True + return False + +def SetupForSENF(env, senf_path = [], flavor=None): + try_flavors = [ '', 'g' ] + if flavor is not None: + try_flavors[0:0] = [ flavor ] + + res = detect_senf(env, senf_path, try_flavors) + if res: + if not env.GetOption('no_progress'): + print env.subst("scons: Using${SENFSYSLAYOUT and ' system' or ''} " + "'libsenf${LIBADDSUFFIX}' in '$SENFDIR'") + else: + print "scons: SENF library not found, trying to build anyway ..." loadTools(env) - env.Append( - LIBS = [ 'rt' ], - - CXXFLAGS = [ '-Wno-long-long', '$CXXFLAGS_', '-fno-strict-aliasing' ], - CXXFLAGS_ = BuildTypeOptions('CXXFLAGS'), - - CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ], + # For a non-system installed senf, we add library and include search path here + if not env.get('SENFSYSLAYOUT', True): + env.Append( + CPPPATH = [ '$SENFINCDIR' ], + LIBPATH = [ '$SENFDIR' ], + ) + + if env['BOOST_VARIANT'] is None: + conf = env.Configure(clean=False, help=False) + conf.CheckBoostVersion(fail=True) + conf.CheckBoostVariants() + conf.Finish() + + env.Replace( expandLogOption = expandLogOption, - CPPDEFINES_ = BuildTypeOptions('CPPDEFINES'), - - LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_' ], - LINKFLAGS_ = BuildTypeOptions('LINKFLAGS'), + ) + env.SetDefault( + LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}', + OBJADDSUFFIX = '${LIBADDSUFFIX}', + BUNDLEDIR = '$SENFDIR${SENFSYSLAYOUT and "/lib/senf" or ""}', + SENFINCDIR = '$SENFDIR${SENFSYSLAYOUT and "/include" or ""}', - LOGLEVELS = [ '$LOGLEVELS_' ], - LOGLEVELS_ = BuildTypeOptions('LOGLEVELS'), + PROJECTNAME = "Unnamed project", + DOCLINKS = [], + PROJECTEMAIL = "nobody@nowhere.org", + COPYRIGHT = "nobody", + REVISION = "unknown", ) + env.Append( + CPPDEFINES = [ '$expandLogOption' ], + CXXFLAGS = [ '-Wno-long-long', '-fno-strict-aliasing' ], + LINKFLAGS = [ '-rdynamic' ], + LIBS = [ 'senf$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', + '$BOOSTSIGNALSLIB', '$BOOSTFSLIB', '$BOOSTSYSTEMLIB', + '$BOOSTDATETIMELIB' ], + ) + + try: + path = env.File('$BUNDLEDIR/senf${LIBADDSUFFIX}.conf').abspath + env.MergeFlags(file(path).read()) + except IOError: + # Really should never happen since detect_senf looks for this file ... + pass - env.SetDefault( +########################################################################### +# Helpers + +def DefaultOptions(env): + env.Replace( + expandLogOption = expandLogOption, + CXXFLAGS_ = env.BuildTypeOptions('CXXFLAGS'), + CPPDEFINES_ = env.BuildTypeOptions('CPPDEFINES'), + LINKFLAGS_ = env.BuildTypeOptions('LINKFLAGS'), + LOGLEVELS_ = env.BuildTypeOptions('LOGLEVELS'), + ) + env.Append( + CXXFLAGS = [ '$CXXFLAGS_' ], + CPPDEFINES = [ '$CPPDEFINES_' ], + LINKFLAGS = [ '$LINKFLAGS_' ], + LOGLEVELS = [ '$LOGLEVELS_' ], + ) + env.SetDefault( CXXFLAGS_final = [], CXXFLAGS_normal = [], CXXFLAGS_debug = [], @@ -109,101 +213,60 @@ def SetupForSENF(env, senf_path = []): LOGLEVELS_final = [], LOGLEVELS_normal = [], LOGLEVELS_debug = [], - - PROJECTNAME = "Unnamed project", - DOCLINKS = [], - PROJECTEMAIL = "nobody@nowhere.org", - COPYRIGHT = "nobody", - REVISION = "unknown", ) # Interpret command line options parseArguments( - env, + env, BoolVariable('final', 'Build final (optimized) build', False), BoolVariable('debug', 'Link in debug symbols', False), + BoolVariable('profile', 'compile and link with the profiling enabled option', False), ) - # If we have a symbolic link (or directory) 'senf', we use it as our - # senf repository - for path in senf_path: - if not path.startswith('/') : sconspath = '#/%s' % path - else : sconspath = path - if os.path.exists(os.path.join(path,"senf/config.hh")): - if not env.GetOption('no_progress'): - print "\nUsing SENF in '%s'\n" \ - % ('/..' in sconspath and os.path.abspath(path) or sconspath) - env.Append( LIBPATH = [ sconspath ], - CPPPATH = [ sconspath ], - BUNDLEDIR = sconspath, - SENFDIR = sconspath, - SENFSYSLAYOUT = False) - try: - env.MergeFlags(file(os.path.join(path,"senf.conf")).read()) - except IOError: - if not env.GetOption('no_progress'): - print "(SENF configuration file 'senf.conf' not found, assuming non-final SENF)" - env.Append(CPPDEFINES = [ 'SENF_DEBUG' ]) - break - elif os.path.exists(os.path.join(path,"include/senf/config.hh")): - if not env.GetOption('no_progress'): - print "\nUsing system SENF in '%s/'\n" % sconspath - env.Append(BUNDLEDIR = os.path.join(sconspath,"lib/senf"), - SENFDIR = sconspath, - SENFSYSLAYOUT = True) - break - else: - if not env.GetOption('no_progress'): - print "\nSENF library not found .. trying build anyway !!\n" - - Configure(env) - - # Only add senf after all configure checks have run + # Set nice default options env.Append( - CPPPATH = '${NEED_BOOST_EXT and "$SENFDIR/boost_ext" or None}', - LIBS = [ 'senf', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', - '$BOOSTFSLIB' ], - ) - - env.Alias('all', '#') - - -def DefaultOptions(env): - env.Append( - CXXFLAGS = [ '-Wall', '-Woverloaded-virtual' ], - CXXFLAGS_final = [ '-O3' ], + CXXFLAGS_CLANG = [ '-Wno-unneeded-internal-declaration' ], # needed for BOOST_PARAMETER_KEYWORD + CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', "${profile and '-pg' or None}", + '${str(CXX).split("/")[-1] == "clang++" and "$CXXFLAGS_CLANG" or None}' ], + CXXFLAGS_final = [ '-O3', '-fno-threadsafe-statics', '-fno-stack-protector', + "${profile and ' ' or '-ffunction-sections'}" ], CXXFLAGS_normal = [ '-O2', '-g' ], CXXFLAGS_debug = [ '-O0', '-g' ], + LINKFLAGS = [ "${profile and '-pg' or None}" ], + LINKFLAGS_final = [ "${profile and ' ' or '-Wl,--gc-sections'}" ], LINKFLAGS_normal = [ '-Wl,-S' ], LINKFLAGS_debug = [ '-g' ], ) + env.Alias('all', '#') + def Glob(env, exclude=[], subdirs=[]): testSources = env.Glob("*.test.cc", strings=True) - sources = [ x - for x in env.Glob("*.cc", strings=True) + sources = [ x + for x in env.Glob("*.cc", strings=True) if x not in testSources and x not in exclude ] for subdir in subdirs: testSources += env.Glob(os.path.join(subdir,"*.test.cc"), strings=True) - sources += [ x + sources += [ x for x in env.Glob(os.path.join(subdir,"*.cc"), strings=True) if x not in testSources and x not in exclude ] sources.sort() testSources.sort() return (sources, testSources) - -def Configure(env): - conf = env.Configure(clean=False, help=False, custom_tests = senfconf.Tests()) - env.Replace( - BOOST_VERSION = conf.CheckBoostVersion(), - BOOST_VARIANT = conf.CheckBoostVariants( '', 'mt' ), - NEED_BOOST_EXT = not conf.CheckCXXHeader("boost/bimap.hpp"), - ) - conf.Finish() - +def CleanGlob(env, targets, patterns): + if env.GetOption('clean'): + targets = SCons.Util.flatten(targets) + for target in targets: + if target in BUILD_TARGETS: + patterns = map(str,SCons.Util.flatten(env.subst_list(patterns))) + files = [ os.path.join(path,f) + for path, subdirs, files in os.walk('.') + for pattern in patterns + for f in fnmatch.filter(files,pattern) ] + return env.Clean(target, files) tagfiles = None @@ -215,7 +278,7 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals global senfutildir global tagfiles libdir=os.path.join(senfutildir, 'lib') - + if tagfiles is None: senfdocdir = None senfdoc_path.extend(('senfdoc', '$SENFDIR', '$SENFDIR/manual', @@ -232,12 +295,12 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals else: for dir, dirs, files in os.walk(senfdocdir): tagfiles.extend([ os.path.join(dir,f) for f in files if f.endswith('.tag') ]) - if dir.endswith('/doc') : + if dir.endswith('/doc') : try: dirs.remove('html') except ValueError: pass - for d in dirs: + for d in dirs: if d.startswith('.') : dirs.remove(d) - + if env.GetOption('clean'): env.Clean('doc', env.Dir('doc')) if not mydoxyfile: @@ -245,7 +308,7 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals if not mydoxyfile: # Create Doxyfile NOW - site_tools.Yaptu.yaptuAction("Doxyfile", + site_tools.Yaptu.yaptuAction("Doxyfile", os.path.join(libdir, "Doxyfile.yap"), env) @@ -256,7 +319,7 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals env.Value('$REVISION') ] # The other files are created using dependencies - if doxyheader: + if doxyheader: doxyheader = env.CopyToDir(env.Dir("doc"), doxyheader) else: doxyheader = env.Yaptu("doc/doxyheader.html", os.path.join(libdir, "doxyheader.yap"), **kw) @@ -281,7 +344,7 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals 'html_dir' : 'html', 'html' : 'YES', 'DOXYGEN' : '$DOXYGEN' }, - TAGFILES = tagfiles, + TAGFILES = tagfiles, DOCLIBDIR = libdir, DOXYGENCOM = "$DOCLIBDIR/doxygen.sh $DOXYOPTS $SOURCE")