X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=site_scons%2Fsenfutil.py;h=f32325444dc96b97aa6f13530d28b84101475eee;hb=84f14a42f9993e186c7897ce0db021300e0a2d48;hp=1ac5680e08cba67899718f84e15629ae483d1cc8;hpb=269adf2f5cc1141c91750f8041a8bc170c8f070a;p=senf.git diff --git a/site_scons/senfutil.py b/site_scons/senfutil.py index 1ac5680..f323254 100644 --- a/site_scons/senfutil.py +++ b/site_scons/senfutil.py @@ -1,5 +1,8 @@ import os.path, glob, site_tools.Yaptu from SCons.Script import * +import SCons.Defaults, SCons.Util +import senfconf +import types, re senfutildir = os.path.dirname(__file__) @@ -31,6 +34,69 @@ class BuildTypeOptions: 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') + for tool in os.listdir(tooldir): + name, ext = os.path.splitext(tool) + if ext == '.py' and name != "__init__" : env.Tool(name, [ tooldir ]) + def parseArguments(env, *defs): vars = Variables(args=ARGUMENTS) for d in defs : vars.Add(d) @@ -48,40 +114,33 @@ Special command line parameters: env.Help(vars.GenerateHelpText(env)) try : unknv = vars.UnknownVariables() except AttributeError: unknv = vars.UnknownOptions() + env.SetDefault(ARGUMENT_VARIABLES = {}) for k,v in unknv.iteritems(): 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}) ########################################################################### # 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 and update that SENF if needed +# c) check for a local SENF, set options accordingly +# d) check, wether the boost extensions are needed def SetupForSENF(env, senf_path = []): global senfutildir senf_path.extend(('senf', os.path.dirname(senfutildir), '/usr/local', '/usr')) - tooldir = os.path.join(senfutildir, 'site_tools') - env.Tool('Boost', [ tooldir ]) - env.Tool('PhonyTarget', [ tooldir ]) - env.Tool('Yaptu', [ tooldir ]) - env.Tool('CopyToDir', [ tooldir ]) - env.Tool('Doxygen', [ tooldir ]) + loadTools(env) env.Append( - LIBS = [ 'senf', 'rt', '$BOOSTREGEXLIB', - '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', - '$BOOSTFSLIB' ], - BOOSTREGEXLIB = 'boost_regex', - BOOSTIOSTREAMSLIB = 'boost_iostreams', - BOOSTSIGNALSLIB = 'boost_signals', - BOOSTFSLIB = 'boost_filesystem', + LIBS = [ 'rt' ], - CXXFLAGS = [ '-Wno-long-long', '$CXXFLAGS_' ], + CXXFLAGS = [ '-Wno-long-long', '$CXXFLAGS_', '-fno-strict-aliasing' ], CXXFLAGS_ = BuildTypeOptions('CXXFLAGS'), CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ], @@ -119,6 +178,8 @@ def SetupForSENF(env, senf_path = []): REVISION = "unknown", ) + env.Replace( _defines = expandDefines ) + # Interpret command line options parseArguments( env, @@ -139,6 +200,7 @@ def SetupForSENF(env, senf_path = []): CPPPATH = [ sconspath ], BUNDLEDIR = sconspath, SENFDIR = sconspath, + SENFINCDIR = sconspath, SENFSYSLAYOUT = False) try: env.MergeFlags(file(os.path.join(path,"senf.conf")).read()) @@ -152,40 +214,133 @@ def SetupForSENF(env, senf_path = []): print "\nUsing system SENF in '%s/'\n" % sconspath env.Append(BUNDLEDIR = os.path.join(sconspath,"lib/senf"), SENFDIR = sconspath, + SENFINCDIR = '%s/include' % 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 + env.Append( + CPPPATH = '${NEED_BOOST_EXT and "$SENFINCDIR/boost_ext" or None}', + LIBS = [ 'senf', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', + '$BOOSTFSLIB' ], + ) + env.Alias('all', '#') def DefaultOptions(env): env.Append( CXXFLAGS = [ '-Wall', '-Woverloaded-virtual' ], - CXXFLAGS_final = [ '-O2' ], - CXXFLAGS_normal = [ '-O0', '-g' ], - CXXFLAGS_debug = [ '$CXXFLAGS_normal' ], + CXXFLAGS_final = [ '-O3' ], + CXXFLAGS_normal = [ '-O2', '-g' ], + CXXFLAGS_debug = [ '-O0', '-g' ], LINKFLAGS_normal = [ '-Wl,-S' ], LINKFLAGS_debug = [ '-g' ], ) + def Glob(env, exclude=[], subdirs=[]): testSources = env.Glob("*.test.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)) + testSources += env.Glob(os.path.join(subdir,"*.test.cc"), strings=True) sources += [ x - for x in env.Glob(os.path.join(subdir,"*.cc", strings=True)) + 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() + tagfiles = None def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=False, senfdoc_path=[], @@ -260,7 +415,8 @@ def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=Fals 'tagfiles' : '$TAGFILES', 'output_dir' : 'doc', 'html_dir' : 'html', - 'html' : 'YES' }, + 'html' : 'YES', + 'DOXYGEN' : '$DOXYGEN' }, TAGFILES = tagfiles, DOCLIBDIR = libdir, DOXYGENCOM = "$DOCLIBDIR/doxygen.sh $DOXYOPTS $SOURCE")