1 import SCons.Node, SCons.Node.FS, SCons.Util
3 #####################################################################
4 # This IS a hack .. but a very useful one: The hack will remove the
5 # 'senf' library from the unit-tests and instead add all the object
6 # files needed explicitly.
8 # This works by building a list of all children (recursively) of the
9 # test sources. For each child we check, wether a file with the same
10 # name but an $OBJSUFFIX extension exists as a build target. In that
11 # case, we add it to the list of needed objects (AND recursively scan
12 # that objects children).
14 # Additionally, of the variable 'only_tests' is set, it contains a
15 # list of test source files to be built exclusively: All other test
16 # sources will NOT be compiled (and their children will therefore not
19 # There is one restriction: CompileCheck tests are not run when this
21 #####################################################################
23 # Build a list of all object file targets which are needed by 'nodes'
24 def neededObjects(env,nodes):
25 if not SCons.Util.is_List(nodes) : nodes = [nodes]
29 walker = SCons.Node.Walker(node)
38 def check(nodes, env=env, seen=seen, rv=rv):
40 if isinstance(c,SCons.Node.FS.File) and not seen.get(c):
42 ob = c.File(env.subst("${SOURCE.dir.abspath}/${OBJPREFIX}${SOURCE.filebase}${OBJSUFFIX}", source=c))
53 rv = [ (str(x),x) for x in rv.iterkeys() ]
55 return (x[1] for x in rv)
57 # Return a map witch has all sources (recursively) of 'nodes' as keys
58 def recursiveSourcesMap(nodes):
61 def check(node, rv=rv):
62 for src in node.sources:
72 # Replacement BoostUnitTest builder. This build just defers the real
73 # builder call until later
74 def AutoObjectBoostUnitTest(env, target, tests, **kw):
75 target = env.arg2nodes(target)[0]
76 tests = env.arg2nodes(tests)
77 env.Append(_UNIT_TEST_LIST = (target, tests, kw))
80 env['BUILDERS']['RealBoostUnitTest'] = env['BUILDERS']['BoostUnitTest']
81 env['BUILDERS']['BoostUnitTest'] = AutoObjectBoostUnitTest
82 env['_UNIT_TEST_LIST'] = []
84 # This needs to be called after all build targets have been set
85 # up. This is important since the list of object targets needs to be
88 env = env.Clone(LIBS = [ '$EXTRA_LIBS' ])
89 if env.has_key("only_tests"):
90 only_tests = [ env.Dir(env.GetLaunchDir()).File(test)
91 for test in env.Split(env['only_tests']) ]
94 for target, tests, kw in env['_UNIT_TEST_LIST']:
98 if test.suffix == env['OBJSUFFIX']:
101 if not only_tests or test in only_tests:
102 objects.extend(env.Object(test))
104 elif test.name == 'main.test.cc':
105 objects.extend(env.Object(test))
106 if not build : continue
108 # First step: Get all objects which are needed by any of 'objects'
109 objects = list(neededObjects(env,objects))
110 # Get all the source files needed by those objects
111 sources = recursiveSourcesMap(objects)
112 # Now remove any objects which are also sources: When an
113 # object is a source for another object this means, the target
114 # object has been built by CombinedObject. Since the target
115 # object includes all it's source objects, we need to remove
116 # all those source objects from the object list (if any).
117 objects = [ ob for ob in objects if not sources.get(ob) ]
119 env.RealBoostUnitTest(target, objects, **kw)