X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=site_scons%2Fsenfutil.py;h=da24b19464c73b470af0e82a25e10bfe46849e34;hb=HEAD;hp=cca87a366a5f270a6cd0b2ff3b2d2642de3ad268;hpb=834416e1c5669c1687d63e29b8055afe3b44ad63;p=senf.git diff --git a/site_scons/senfutil.py b/site_scons/senfutil.py index cca87a3..da24b19 100644 --- a/site_scons/senfutil.py +++ b/site_scons/senfutil.py @@ -1,95 +1,31 @@ -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 SCons.Defaults, SCons.Util -import senfconf -import types, re 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) +########################################################################### +extdir = os.path.join(senfutildir, '../senf/Ext') +sys.path.append(extdir) -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 [] +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 + +########################################################################### -class BuildTypeOptions: - def __init__(self, var): - self._var = var - - 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] - -_DOLLAR_RE = re.compile(r'\$([a-zA-Z_][\.\w]*)|\${([^}]*)}') - -def _expandDefines(defs, target, source, env, for_signature): - rv = [] - if SCons.Util.is_Dict(defs): - keys = defs.keys() - keys.sort() - defs = [ (k,defs[k]) for k in keys ] - elif not SCons.Util.is_List(defs): - defs = [ defs ] - for elt in defs: - if SCons.Util.is_String(elt): - m = _DOLLAR_RE.match(elt) - if m: - match = m.group(1) or m.group(2) - try: rv.extend(_expandDefines(eval(match, env.gvars(), env.lvars()), - target, source, env, for_signature)) - except NameError: pass - except IndexError: pass - else: - rv.append(env.subst(elt)) - elif callable(elt): - rv.extend(_expandDefines(elt(target, source, env, for_signature), - target, source, env, for_signature)) - elif SCons.Util.is_Sequence(elt): - if len(elt)<2 or elt[1] is None: - rv.append(env.subst(elt[0])) - else: - rv.append(env.subst(elt[0]) + "=" + env.subst(elt[1])) - else: - rv.append(str(elt)) - return rv - -def expandDefines(prefix, defs, suffix, env): - """Expand defines in using . Calls SCons.Defaults._concat_ixes -to append prefix/suffix before/after each define. - - callable - Call the callable and replace it with the call result. If the result - is a list, the list is processed recursively. It the result is a - dictionary it is converted into a list of typles and processed - recursively. - '$' or '${}' - Replace the element with the variable expansion. If the result is a - list, the list is processed recursively. It the result is a - dictionary it is converted into a list of typles and processed - recursively. - '' - Define a symbol with that (expanded!) name - iterable - The iteratble must have two elments. The first element defines the - symbol name, the second the symbol value.""" - - defs = _expandDefines(defs, None, None, env, False) - return SCons.Defaults._concat_ixes(prefix, defs, suffix, env) - def loadTools(env): global senfutildir tooldir = os.path.join(senfutildir, 'site_tools') @@ -106,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: @@ -115,13 +51,42 @@ Special command line parameters: try : unknv = vars.UnknownVariables() except AttributeError: unknv = vars.UnknownOptions() env.SetDefault(ARGUMENT_VARIABLES = {}) - for k,v in unknv.iteritems(): + 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 [] + +########################################################################### +# client SENF detection/configuration def detect_senf(env,senf_path, try_flavors): """Detect senf with flavor in 'try_flavors' somewhere in 'senf_path'. @@ -156,18 +121,18 @@ The environment 'env' is updated in the following way: 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 not env.GetOption('no_progress'): - if res: - print env.subst("scons: Using${SENFSYSLAYOUT and ' system' or ''} 'libsenf${LIBADDSUFFIX}' in '$SENFDIR'") - else: - print "scons: SENF library not found, trying to build anyway ..." + 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) @@ -177,57 +142,62 @@ def SetupForSENF(env, senf_path = [], flavor=None): 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( - _defines = expandDefines, expandLogOption = expandLogOption, ) env.SetDefault( - FLAVOR = flavor, LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}', OBJADDSUFFIX = '${LIBADDSUFFIX}', + BUNDLEDIR = '$SENFDIR${SENFSYSLAYOUT and "/lib/senf" or ""}', + SENFINCDIR = '$SENFDIR${SENFSYSLAYOUT and "/include" or ""}', + PROJECTNAME = "Unnamed project", DOCLINKS = [], PROJECTEMAIL = "nobody@nowhere.org", COPYRIGHT = "nobody", REVISION = "unknown", - BUNDLEDIR = '$SENFDIR${SENFSYSLAYOUT and "/lib/senf" or ""}', - SENFINCDIR = '$SENFDIR${SENFSYSLAYOUT and "/include" or ""}', ) env.Append( - CPPPATH = [ '${NEED_BOOST_EXT and "$SENFINCDIR/boost_ext" or None}' ], CPPDEFINES = [ '$expandLogOption' ], CXXFLAGS = [ '-Wno-long-long', '-fno-strict-aliasing' ], - LIBS = [ 'senf$LIBADDSUFFIX', 'rt', - '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ], LINKFLAGS = [ '-rdynamic' ], + LIBS = [ 'senf$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', + '$BOOSTSIGNALSLIB', '$BOOSTFSLIB', '$BOOSTSYSTEMLIB', + '$BOOSTDATETIMELIB' ], ) - + try: - env.MergeFlags(file(env.File('$BUNDLEDIR/senf${LIBADDSUFFIX}.conf').abspath).read()) + 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 +########################################################################### +# Helpers + def DefaultOptions(env): env.Replace( - _defines = expandDefines, expandLogOption = expandLogOption, + CXXFLAGS_ = env.BuildTypeOptions('CXXFLAGS'), + CPPDEFINES_ = env.BuildTypeOptions('CPPDEFINES'), + LINKFLAGS_ = env.BuildTypeOptions('LINKFLAGS'), + LOGLEVELS_ = env.BuildTypeOptions('LOGLEVELS'), ) env.Append( CXXFLAGS = [ '$CXXFLAGS_' ], - CXXFLAGS_ = BuildTypeOptions('CXXFLAGS'), - CPPDEFINES = [ '$CPPDEFINES_' ], - CPPDEFINES_ = BuildTypeOptions('CPPDEFINES'), - LINKFLAGS = [ '$LINKFLAGS_' ], - LINKFLAGS_ = BuildTypeOptions('LINKFLAGS'), - LOGLEVELS = [ '$LOGLEVELS_' ], - LOGLEVELS_ = BuildTypeOptions('LOGLEVELS'), ) - env.SetDefault( + env.SetDefault( CXXFLAGS_final = [], CXXFLAGS_normal = [], CXXFLAGS_debug = [], @@ -247,18 +217,24 @@ def DefaultOptions(env): # 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), ) # Set nice default options 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' ], ) @@ -268,99 +244,29 @@ def DefaultOptions(env): 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) - -@senfconf.Test -def CheckSTLCopyN(context): - context.Message("Checking for 'copy_n' implementation... ") - versions = [ ('', 'std::copy_n', 'STD'), - ('', '__gnu_cxx::copy_n', 'GNUCXX') ] - for include, name, define in versions: - ret = context.TryCompile("#include %s\n" - "int main(int,char**) { int *a,*b; %s(a,0,b); }\n" - % (include, name), - ".cc") - if ret: - context.Result(name) - context.sconf.Define("HAVE_%s_COPYN" % define, - 1, - "Define one of " - + ", ".join(("HAVE_%s_COPYN" % elt[2] for elt in versions))) - return ret - - context.Result(False) - return False - - -@senfconf.Test -def CheckTempBufferStrategy(context): - context.Message("Checking for optimal temporary buffer strategy... ") - - def check(): - # locals - ret = context.TryCompile("void test(int n){int a[n];}",".cc") - if ret: return "locals" - - # alloca - ret = context.TryCompile("#include \n" - "void test(int a){void *b(alloca(a));}" - ".cc") - if ret: return "alloca" - - # fallback: new - return "new" - - ret = check() - context.Result(ret) - context.sconf.Define("SENF_BUFFER_USE_%s" % ret.upper(), - 1, - "Define one of SENF_BUFFER_USE_LOCALS, SENF_BUFFER_USE_ALLOCA, " - "SENF_BUFFER_USE_NEW") - return ret - - -def Fail(msg): - SCons.Util.display("scons: *** %s" % msg) - Exit(1) - - -def Configure(env, customChecks=None): - conf = env.Configure(clean=False, - help=False, - custom_tests=senfconf.Tests(), - config_h="#/senf/autoconf.hh") - - # Boost - if not conf.CheckBoostVersion(): - Fail("Boost includes not found") - if not conf.env['ARGUMENT_VARIABLES'].has_key('BOOST_VARIANT'): conf.CheckBoostVariants( '', 'mt' ) - conf.env.Replace(NEED_BOOST_EXT = not conf.CheckCXXHeader("boost/bimap.hpp")) - conf.CheckCXXHeader("boost/spirit/include/classic.hpp") - - # Compiler support - conf.CheckTempBufferStrategy() - - # Standard library stuff - if not conf.CheckSTLCopyN(): - Fail("No 'copy_n' implementation found") - conf.CheckFunc("timerfd_create") - - # User checks - if customChecks: - customChecks(conf) - - 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 @@ -372,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', @@ -389,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: @@ -402,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) @@ -413,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) @@ -438,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")