CPPPATH = [ '$BUILDDIR', '#' ],
LOCALLIBDIR = '$BUILDDIR',
LIBPATH = [ '$LOCALLIBDIR' ],
- LIBS = [ '$LIBSENF$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB',
- '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ],
+ LIBS = [ '$LIBSENF$LIBADDSUFFIX', '$EXTRA_LIBS' ],
+ EXTRA_LIBS = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
+ '$BOOSTFSLIB' ],
TEST_EXTRA_LIBS = [ ],
VALGRINDARGS = [ '--num-callers=50' ],
BoolVariable('final', 'Build final (optimized) build', False),
BoolVariable('debug', 'Link in debug symbols', False),
BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
+ BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
)
+if env.has_key('only_tests') : env['sparse_tests'] = True
Export('env')
# Create Doxyfile.local otherwise doxygen will barf on this non-existent file
SConscript("debian/SConscript")
SConscriptChdir(1)
if os.path.exists('SConscript.local') : SConscript('SConscript.local')
+if env['sparse_tests']:
+ import SparseTestHack
+ SparseTestHack.setup(env)
if env.subst('$BUILDDIR') == '#':
SConscript("SConscript")
else:
SConscript("Examples/SConscript")
SConscript("HowTos/SConscript")
SConscript("doclib/SConscript")
+if env['sparse_tests']:
+ SparseTestHack.build(env)
###########################################################################
# Define build targets
--- /dev/null
+import SCons.Node, SCons.Node.FS, SCons.Util
+
+#####################################################################
+# This IS a hack .. but a very useful one: The hack will remove the
+# 'senf' library from the unit-tests and instead add all the object
+# files needed explicitly.
+#
+# This works by building a list of all children (recursively) of the
+# test sources. For each child we check, wether a file with the same
+# name but an $OBJSUFFIX extension exists as a build target. In that
+# case, we add it to the list of needed objects (AND recursively scan
+# that objects children).
+#
+# Additionally, of the variable 'only_tests' is set, it contains a
+# list of test source files to be built exclusively: All other test
+# sources will NOT be compiled (and their children will therefore not
+# be scanned).
+#
+# There is one restriction: CompileCheck tests are not run when this
+# hack is enabled.
+#####################################################################
+
+# Build a list of all object file targets which are needed by 'nodes'
+def neededObjects(env,nodes):
+ if not SCons.Util.is_List(nodes) : nodes = [nodes]
+
+ def walk(nodes):
+ for node in nodes:
+ walker = SCons.Node.Walker(node)
+ while True:
+ n = walker.next()
+ if n is None : break
+ yield n
+
+ seen = {}
+ rv = {}
+
+ def check(nodes, env=env, seen=seen, rv=rv):
+ for c in walk(nodes):
+ if isinstance(c,SCons.Node.FS.File) and not seen.get(c):
+ seen[c] = True
+ ob = c.File(env.subst("${SOURCE.dir.abspath}/${OBJPREFIX}${SOURCE.filebase}${OBJSUFFIX}", source=c))
+ if ob.is_derived():
+ rv[ob] = True
+ if not seen.get(ob):
+ seen[ob] = True
+ check([ob])
+
+ check(nodes)
+
+ for node in nodes:
+ rv[node] = True
+ rv = [ (str(x),x) for x in rv.iterkeys() ]
+ rv.sort()
+ return (x[1] for x in rv)
+
+# Return a map witch has all sources (recursively) of 'nodes' as keys
+def recursiveSourcesMap(nodes):
+ rv = {}
+
+ def check(node, rv=rv):
+ for src in node.sources:
+ if not rv.get(src):
+ rv[src] = True
+ check(src)
+
+ for node in nodes:
+ check(node)
+
+ return rv
+
+# Replacement BoostUnitTest builder. This build just defers the real
+# builder call until later
+def AutoObjectBoostUnitTest(env, target, tests, **kw):
+ target = env.arg2nodes(target)[0]
+ tests = env.arg2nodes(tests)
+ env.Append(_UNIT_TEST_LIST = (target, tests, kw))
+
+def setup(env):
+ env['BUILDERS']['RealBoostUnitTest'] = env['BUILDERS']['BoostUnitTest']
+ env['BUILDERS']['BoostUnitTest'] = AutoObjectBoostUnitTest
+ env['_UNIT_TEST_LIST'] = []
+
+# This needs to be called after all build targets have been set
+# up. This is important since the list of object targets needs to be
+# complete.
+def build(env):
+ env = env.Clone(LIBS = [ '$EXTRA_LIBS' ])
+ if env.has_key("only_tests"):
+ only_tests = [ env.Dir(env.GetLaunchDir()).File(test)
+ for test in env.Split(env['only_tests']) ]
+ else:
+ only_tests = []
+ for target, tests, kw in env['_UNIT_TEST_LIST']:
+ objects = []
+ build = False
+ for test in tests:
+ if test.suffix == env['OBJSUFFIX']:
+ objects.append(test)
+ else:
+ if not only_tests or test in only_tests:
+ objects.extend(env.Object(test))
+ build = True
+ elif test.name == 'main.test.cc':
+ objects.extend(env.Object(test))
+ if not build : continue
+
+ # First step: Get all objects which are needed by any of 'objects'
+ objects = list(neededObjects(env,objects))
+ # Get all the source files needed by those objects
+ sources = recursiveSourcesMap(objects)
+ # Now remove any objects which are also sources: When an
+ # object is a source for another object this means, the target
+ # object has been built by CombinedObject. Since the target
+ # object includes all it's source objects, we need to remove
+ # all those source objects from the object list (if any).
+ objects = [ ob for ob in objects if not sources.get(ob) ]
+
+ env.RealBoostUnitTest(target, objects, **kw)