'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
-.RI Builder( action ", [" multi ", " prefix ", " suffix ", " src_suffix ", " src_builder ", " emitter ])
+.RI Builder( action ", [" arguments ])
.TP
-.RI env.Builder( action ", [" multi ", " prefix ", " suffix ", " src_suffix ", " src_builder ", " emitter ])
+.RI env.Builder( action ", [" arguments ])
Creates a Builder object for
the specified
.IR action .
.IP SCANNERS
A list of the available implicit dependency scanners.
+New file scanners may be added by
+appending to this list,
+although the more flexible approach
+is to associate scanners
+with a specific Builder.
+See the sections "Builder Objects"
+and "Scanner Objects,"
+below, for more information.
.IP SCCS
The SCCS executable.
.I env
- the construction environment.
-.IP multi
-Specifies whether this builder is allowed to be called multiple times for
-the same target file(s). The default is 0, which means the builder
-can not be called multiple times for the same target file(s). Calling a
-builder multiple times for the same target simply adds additional source
-files to the target; it is not allowed to change the environment associated
-with the target, specify addition environment overrides, or associate a different
-builder with the target.
-
.IP prefix
The prefix that will be prepended to the target file name.
This may be a simple string, or a callable object that takes
.IP src_suffix
The expected source file name suffix.
-.IP src_builder
-Specifies a builder to use when a source file name suffix does not match
-any of the suffixes of the builder. Using this argument produces a
-multi-stage builder.
+.IP target_scanner
+A Scanner object that
+will be invoked to find
+implicit dependencies for this target file.
+This keyword argument should be used
+for Scanner objects that find
+implicit dependencies
+based only on the target file
+and the construction environment,
+.I not
+for implicit
+(See the section "Scanner Objects," below,
+for information about creating Scanner objects.)
+
+.IP source_scanner
+A Scanner object that
+will be invoked to
+find implicit dependences in
+any source files
+used to build this target file.
+This is where you would
+specify a scanner to
+find things like
+.B #include
+lines in source files.
+(See the section "Scanner Objects," below,
+for information about creating Scanner objects.)
.IP emitter
A function or list of functions to manipulate the target and source
'.suf2' : e_suf2})
.EE
+.IP multi
+Specifies whether this builder is allowed to be called multiple times for
+the same target file(s). The default is 0, which means the builder
+can not be called multiple times for the same target file(s). Calling a
+builder multiple times for the same target simply adds additional source
+files to the target; it is not allowed to change the environment associated
+with the target, specify addition environment overrides, or associate a different
+builder with the target.
+
+.IP env
+A construction environment that can be used
+to fetch source code using this Builder.
+(Note that this environment is
+.I not
+used for normal builds of normal target files,
+which use the environment that was
+used to call the Builder for the target file.)
+
.IP generator
A function that returns a list of actions that will be executed to build
the target(s) from the source(s).
b = Builder(generator=g)
.EE
+.IP src_builder
+Specifies a builder to use when a source file name suffix does not match
+any of the suffixes of the builder. Using this argument produces a
+multi-stage builder.
+
+.RE
The
.I generator
and
.I action
arguments must not both be used for the same Builder.
-.IP env
-A construction environment that can be used
-to fetch source code using this Builder.
-(Note that this environment is
-.I not
-used for normal builds of normal target files,
-which use the environment that was
-used to call the Builder for the target file.)
-
Any additional keyword arguments supplied
when a Builder object is created
(that is, when the Builder() function is called)
the parents's implicit dependencies, let returning up the normal
Taskmaster descent take care of it for us.
+ - Add documented support for separate target_scanner and source_scanner
+ arguments to Builder creation, which allows different scanners to
+ be applied to source files
+
+ - Don't re-install or (re-generate) .h files when a subsidiary #included
+ .h file changes. This eliminates incorrect circular dependencies
+ with .h files generated from other source files.
+
From Gary Oberbrunner:
- Add a --debug=presub option to print actions prior to substitution.
elif t.overrides != overrides:
raise UserError, "Two different sets of overrides were specified for the same target: %s"%str(t)
- elif builder.scanner and t.target_scanner and builder.scanner != t.target_scanner:
+ elif builder.target_scanner and t.target_scanner and builder.target_scanner != t.target_scanner:
raise UserError, "Two different scanners were specified for the same target: %s"%str(t)
if builder.multi:
t.env_set(env)
t.add_source(slist)
t.set_executor(executor)
- if builder.scanner:
- t.target_scanner = builder.scanner
- if not t.source_scanner:
- t.source_scanner = env.get_scanner(t.scanner_key())
-
- # Last, add scanners from the Environment to the source Nodes.
+ if builder.target_scanner:
+ t.target_scanner = builder.target_scanner
+ if t.source_scanner is None:
+ t.source_scanner = builder.source_scanner
+
+ # Add backup source scanners from the environment to the source
+ # nodes. This may not be necessary if the node will have a real
+ # source scanner added later (which is why these are the "backup"
+ # source scanners, not the real ones), but because source nodes may
+ # be used multiple times for different targets, it ends up being
+ # more efficient to do this calculation once here, as opposed to
+ # delaying it until later when we potentially have to calculate it
+ # over and over and over.
for s in slist:
- if not s.source_scanner:
- s.source_scanner = env.get_scanner(s.scanner_key())
+ if s.source_scanner is None and s.backup_source_scanner is None:
+ s.backup_source_scanner = env.get_scanner(s.scanner_key())
class EmitterProxy:
"""This is a callable class that can act as a
src_suffix = '',
target_factory = SCons.Node.FS.default_fs.File,
source_factory = SCons.Node.FS.default_fs.File,
- scanner = None,
+ target_scanner = None,
+ source_scanner = None,
emitter = None,
multi = 0,
env = None,
self.target_factory = target_factory
self.source_factory = source_factory
- self.scanner = scanner
+ self.target_scanner = target_scanner
+ self.source_scanner = source_scanner
self.emitter = emitter
if __debug__: logInstanceCreation(self)
SCons.Util.Proxy.__init__(self, builder)
self.builder = builder
- self.scanner = builder.scanner
+ self.target_scanner = builder.target_scanner
+ self.source_scanner = builder.source_scanner
self.env = env
self.tlist = tlist
self.multi = builder.multi
src_suffix = '',
target_factory = SCons.Node.FS.default_fs.File,
source_factory = SCons.Node.FS.default_fs.File,
- scanner=None,
+ target_scanner = None,
+ source_scanner = None,
emitter=None):
if __debug__: logInstanceCreation(self)
BuilderBase.__init__(self, action, prefix, suffix, src_suffix,
target_factory, source_factory,
- scanner, emitter)
+ target_scanner, source_scanner, emitter)
if not SCons.Util.is_List(src_builder):
src_builder = [ src_builder ]
self.src_builder = src_builder
self.builder = None
self.side_effect = 0
self.source_scanner = None
+ self.backup_source_scanner = None
def __str__(self):
return self.name
def builder_set(self, builder):
match = str(e) == "While building `['t8']': Don't know how to build a file with suffix `.unknown'."
assert match, e
- def test_build_scanner(self):
- """Testing ability to set a target scanner through a builder."""
+ def test_target_scanner(self):
+ """Testing ability to set target and source scanners through a builder."""
global instanced
class TestScanner:
pass
- scn = TestScanner()
+ tscan = TestScanner()
+ sscan = TestScanner()
env = Environment()
- builder = SCons.Builder.Builder(scanner=scn)
+ builder = SCons.Builder.Builder(target_scanner=tscan,
+ source_scanner=sscan)
tgt = builder(env, target='foo2', source='bar')
- assert tgt.target_scanner == scn, tgt.target_scanner
+ assert tgt.target_scanner == tscan, tgt.target_scanner
+ assert tgt.source_scanner == sscan, tgt.source_scanner
builder1 = SCons.Builder.Builder(action='foo',
src_suffix='.bar',
suffix='.foo')
builder2 = SCons.Builder.Builder(action='foo',
src_builder = builder1,
- scanner = scn)
+ target_scanner = tscan,
+ source_scanner = tscan)
tgt = builder2(env, target='baz2', source='test.bar test2.foo test3.txt')
- assert tgt.target_scanner == scn, tgt.target_scanner
+ assert tgt.target_scanner == tscan, tgt.target_scanner
+ assert tgt.source_scanner == tscan, tgt.source_scanner
def test_src_scanner(slf):
"""Testing ability to set a source file scanner through a builder."""
scanner = TestScanner()
builder = SCons.Builder.Builder(action='action')
- # With no scanner specified, source_scanner is None.
+ # With no scanner specified, source_scanner and
+ # backup_source_scanner are None.
env1 = Environment()
tgt = builder(env1, target='foo1.x', source='bar.y')
src = tgt.sources[0]
assert tgt.target_scanner != scanner, tgt.target_scanner
assert src.source_scanner is None, src.source_scanner
+ assert src.backup_source_scanner is None, src.backup_source_scanner
# Later use of the same source file with an environment that
# has a scanner must still set the scanner.
tgt = builder(env2, target='foo2.x', source='bar.y')
src = tgt.sources[0]
assert tgt.target_scanner != scanner, tgt.target_scanner
- assert src.source_scanner == scanner, src.source_scanner
+ assert src.source_scanner is None, src.source_scanner
+ assert src.backup_source_scanner == scanner, src.backup_source_scanner
def test_Builder_Args(self):
"""Testing passing extra args to a builder."""
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
# Scanners and suffixes for common languages.
+ObjSourceScan = SCons.Scanner.Scanner({})
+
CScan = SCons.Scanner.C.CScan()
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
".F", ".fpp", ".FPP",
".S", ".spp", ".SPP"]
+for suffix in CSuffixes:
+ ObjSourceScan.add_scanner(suffix, CScan)
+
DScan = SCons.Scanner.D.DScan()
DSuffixes = ['.d']
+for suffix in DSuffixes:
+ ObjSourceScan.add_scanner(suffix, DScan)
+
FortranScan = SCons.Scanner.Fortran.FortranScan()
FortranSuffixes = [".f", ".F", ".for", ".FOR"]
+for suffix in FortranSuffixes:
+ ObjSourceScan.add_scanner(suffix, FortranScan)
+
IDLSuffixes = [".idl", ".IDL"]
# Actions for common languages.
ConstructionEnvironment = {
'BUILDERS' : {},
- 'SCANNERS' : [CScan, FortranScan, DScan],
+ 'SCANNERS' : [],
'CPPSUFFIXES': CSuffixes,
'DSUFFIXES' : DSuffixes,
'FORTRANSUFFIXES': FortranSuffixes,
try:
scanners = self._dict['SCANNERS']
except KeyError:
+ self.scanner_map = {}
return None
else:
self.scanner_map = sm = {}
# claim they can scan the same suffix, earlier scanners
# in the list will overwrite later scanners, so that
# the result looks like a "first match" to the user.
+ if not SCons.Util.is_List(scanners):
+ scanners = [scanners]
scanners.reverse()
for scanner in scanners:
for k in scanner.get_skeys(self):
arg = self.subst(arg)
nargs.append(arg)
nkw = self.subst_kw(kw)
- return apply(SCons.Scanner.Base, nargs, nkw)
+ return apply(SCons.Scanner.Scanner, nargs, nkw)
def SConsignFile(self, name=".sconsign", dbm_module=None):
name = self.subst(name)
self._rexists = self.rfile().exists()
return self._rexists
- def get_parents(self):
- parents = SCons.Node.Node.get_parents(self)
- if self.dir and not isinstance(self.dir, ParentOfRoot):
- parents.append(self.dir)
- return parents
-
def is_under(self, dir):
if self is dir:
return 1
self.abspath_ = self.abspath + os.sep
self.repositories = []
self.srcdir = None
- self.source_scanner = None
-
+
self.entries = {}
self.entries['.'] = self
self.entries['..'] = self.dir
return [self.node]
def __hash__(self):
return self.hash
+ def select(self, node):
+ return self
class Environment:
def __init__(self):
skey = fs.Dir('ddd.x').scanner_key()
assert skey is None, skey
- d1 = fs.Dir('dir')
- f1 = fs.File('dir/file')
- assert f1.dir == d1, f1.dir
- parents = f1.get_parents()
- assert parents == [ d1 ], parents
-
test.write("i_am_not_a_directory", "\n")
try:
exc_caught = 0
def __call__(self, node):
self.called = 1
return node.found_includes
+ def select(self, node):
+ return self
class MyNode(SCons.Node.Node):
"""The base Node class contains a number of do-nothing methods that
node.add_dependency([three, four, one])
assert node.depends == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_depends([[five, six]])
except:
else:
raise "did not catch expected exception"
assert node.depends == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_add_source(self):
node.add_source([three, four, one])
assert node.sources == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_source([[five, six]])
except:
else:
raise "did not catch expected exception"
assert node.sources == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_add_ignore(self):
"""Test adding files whose dependencies should be ignored.
node.add_ignore([three, four, one])
assert node.ignore == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_ignore([[five, six]])
except:
else:
raise "did not catch expected exception"
assert node.ignore == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_get_found_includes(self):
"""Test the default get_found_includes() method
deps = node.get_implicit_deps(env, s, target)
assert deps == [d, e, f], map(str, deps)
+ def test_get_source_scanner(self):
+ """Test fetching the source scanner for a Node
+ """
+ class Builder:
+ pass
+ target = SCons.Node.Node()
+ source = SCons.Node.Node()
+ s = target.get_source_scanner(source)
+ assert s is None, s
+
+ ts1 = Scanner()
+ ts2 = Scanner()
+ ts3 = Scanner()
+
+ source.backup_source_scanner = ts1
+ s = target.get_source_scanner(source)
+ assert s is ts1, s
+
+ source.builder = Builder()
+ source.builder.source_scanner = ts2
+ s = target.get_source_scanner(source)
+ assert s is ts2, s
+
+ target.source_scanner = ts3
+ s = target.get_source_scanner(source)
+ assert s is ts3, s
+
def test_scan(self):
"""Test Scanner functionality
"""
n.includes = 'testincludes'
n.found_include = {'testkey':'testvalue'}
n.implicit = 'testimplicit'
+ n.waiting_parents = ['foo', 'bar']
n.clear()
assert n.includes is None, n.includes
assert n.found_includes == {}, n.found_includes
assert n.implicit is None, n.implicit
+ assert n.waiting_parents == [], n.waiting_parents
def test_get_subst_proxy(self):
"""Test the get_subst_proxy method."""
n = SCons.Node.Node()
n.postprocess()
+ def test_add_to_waiting_parents(self):
+ """Test the add_to_waiting_parents() method"""
+ n1 = SCons.Node.Node()
+ n2 = SCons.Node.Node()
+ assert n1.waiting_parents == [], n1.waiting_parents
+ n1.add_to_waiting_parents(n2)
+ assert n1.waiting_parents == [n2], n1.waiting_parents
+
+ def test_call_for_all_waiting_parents(self):
+ """Test the call_for_all_waiting_parents() method"""
+ n1 = SCons.Node.Node()
+ n2 = SCons.Node.Node()
+ n1.add_to_waiting_parents(n2)
+ result = []
+ def func(node, result=result):
+ result.append(node)
+ n1.call_for_all_waiting_parents(func)
+ assert result == [n1, n2], result
+
if __name__ == "__main__":
self.ignore = [] # dependencies to ignore
self.ignore_dict = {}
self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
- self.parents = {}
+ self.waiting_parents = []
self.wkids = None # Kids yet to walk, when it's an array
self.target_scanner = None # explicit scanner from this node's Builder
- self.source_scanner = None # source scanner
+ self.source_scanner = None
+ self.backup_source_scanner = None
self.env = None
self.state = None
else:
self.store_info(new_binfo)
- # Clear out the implicit dependency caches:
- # XXX this really should somehow be made more general and put
- # under the control of the scanners.
- if self.source_scanner:
- self.found_includes = {}
- self.includes = None
- for parent in self.get_parents():
- parent.implicit = None
- parent.del_binfo()
+ # Clear our scanned included files.
+ self.found_includes = {}
+ self.includes = None
+
+ # Clear the implicit dependency caches of any Nodes
+ # waiting for this Node to be built.
+ for parent in self.waiting_parents:
+ parent.implicit = None
+ parent.del_binfo()
+ self.waiting_parents = []
# The content just changed, delete any cached info
# so it will get recalculated.
self.del_cinfo()
+ def add_to_waiting_parents(self, node):
+ self.waiting_parents.append(node)
+
+ def call_for_all_waiting_parents(self, func):
+ func(self)
+ for parent in self.waiting_parents:
+ parent.call_for_all_waiting_parents(func)
+
def postprocess(self):
"""Clean up anything we don't need to hang onto after we've
been built."""
self.found_includes = {}
self.implicit = None
+ self.waiting_parents = []
+
def visited(self):
"""Called just after this node has been visited
without requiring a build.."""
if not scanner:
return []
+ # Give the scanner a chance to select a more specific scanner
+ # for this Node.
+ scanner = scanner.select(self)
+
try:
recurse = scanner.recursive
except AttributeError:
self.implicit_factory_cache[path] = n
return n
+ def get_source_scanner(self, node):
+ """Fetch the source scanner for the specified node
+
+ NOTE: "self" is the target being built, "node" is
+ the source file for which we want to fetch the scanner.
+ """
+ if self.source_scanner:
+ return self.source_scanner
+ try:
+ scanner = node.builder.source_scanner
+ if scanner:
+ return scanner
+ except AttributeError:
+ pass
+ return node.backup_source_scanner or None
+
def scan(self):
"""Scan this node's dependents for implicit dependencies."""
# Don't bother scanning non-derived files, because we don't
# self.del_binfo()
for child in self.children(scan=0):
- scanner = child.source_scanner
+ scanner = self.get_source_scanner(child)
if scanner:
- self._add_child(self.implicit,
- self.implicit_dict,
- child.get_implicit_deps(build_env,
- scanner,
- self))
+ deps = child.get_implicit_deps(build_env, scanner, self)
+ self._add_child(self.implicit, self.implicit_dict, deps)
# scan this node itself for implicit dependencies
- self._add_child(self.implicit,
- self.implicit_dict,
- self.get_implicit_deps(build_env,
- self.target_scanner,
- self))
+ deps = self.get_implicit_deps(build_env, self.target_scanner, self)
+ self._add_child(self.implicit, self.implicit_dict, deps)
# XXX See note above re: --implicit-cache.
#if implicit_cache:
collection.append(c)
dict[c] = 1
added = 1
- c.parents[self] = 1
if added:
self._children_reset()
else:
return self.sources + self.depends + self.implicit
- def get_parents(self):
- return self.parents.keys()
-
def set_state(self, state):
self.state = state
if self.is_derived() and self.env:
env = self.get_build_env()
for s in self.sources:
- def f(node, env=env, scanner=s.source_scanner, target=self):
+ scanner = s.get_source_scanner(self)
+ def f(node, env=env, scanner=scanner, target=self):
return node.get_found_includes(env, scanner, target)
return SCons.Util.render_tree(s, f, 1)
else:
already_done.append( n )
self._setCache(n.children())
+ # Calling children() has set up the implicit cache (and
+ # other state), but we're not really building things yet,
+ # so generated files won't have been generated. Clear the
+ # state so we will, in fact, build everything that's necessary
+ # when we do the build.
+ #
+ # XXX - it would be good to find a better way to do this,
+ # maybe by doing something with the actions in the actual
+ # Taskmaster...?
+ n.clear()
+
def BuildNodes(self, nodes):
"""
Tries to build the given nodes immediately. Returns 1 on success,
return None
def postprocess(self):
pass
+ def clear(self):
+ pass
return [MyNode('n1'), MyNode('n2')]
self.scons_env.Append(BUILDERS = {'SConfActionBuilder' : MyBuilder()})
sconf.TryBuild(self.scons_env.SConfActionBuilder)
path = [path]
return map(self.subst, path)
+ def get_calculator(self):
+ return None
+
if os.path.normcase('foo') == os.path.normcase('FOO'):
my_normpath = os.path.normcase
else:
path = [path]
return map(self.subst, path)
+ def get_calculator(self):
+ return None
+
def deps_match(self, deps, headers):
scanned = map(os.path.normpath, map(str, deps))
expect = map(os.path.normpath, headers)
def __delitem__(self,key):
del self.Dictionary()[key]
+ def get_calculator(self):
+ return None
+
global my_normpath
my_normpath = os.path.normpath
class ScannerTestCase(unittest.TestCase):
+ def test_creation(self):
+ """Test creation of Scanner objects through the Scanner() function"""
+ def func(self):
+ pass
+ s = SCons.Scanner.Scanner(func)
+ assert isinstance(s, SCons.Scanner.Base), s
+ s = SCons.Scanner.Scanner({})
+ assert isinstance(s, SCons.Scanner.Selector), s
+
+class BaseTestCase(unittest.TestCase):
+
def func(self, filename, env, target, *args):
self.filename = filename
self.env = env
self.failUnless(sk == ['.3', '.4'],
"sk was %s, not ['.3', '.4']")
+ def test_select(self):
+ """Test the Scanner.Base select() method"""
+ scanner = SCons.Scanner.Base(function = self.func)
+ s = scanner.select('.x')
+ assert s is scanner, s
+
+class SelectorTestCase(unittest.TestCase):
+ class skey:
+ def __init__(self, key):
+ self.key = key
+ def scanner_key(self):
+ return self.key
+
+ def test___init__(self):
+ """Test creation of Scanner.Selector object"""
+ s = SCons.Scanner.Selector({})
+ assert isinstance(s, SCons.Scanner.Selector), s
+ assert s.dict == {}, s.dict
+
+ def test___call__(self):
+ """Test calling Scanner.Selector objects"""
+ called = []
+ def s1func(node, env, path, called=called):
+ called.append('s1func')
+ called.append(node)
+ return []
+ def s2func(node, env, path, called=called):
+ called.append('s2func')
+ called.append(node)
+ return []
+ s1 = SCons.Scanner.Base(s1func)
+ s2 = SCons.Scanner.Base(s2func)
+ selector = SCons.Scanner.Selector({'.x' : s1, '.y' : s2})
+ nx = self.skey('.x')
+ selector(nx, None, [])
+ assert called == ['s1func', nx], called
+ del called[:]
+ ny = self.skey('.y')
+ selector(ny, None, [])
+ assert called == ['s2func', ny], called
+
+ def test_select(self):
+ """Test the Scanner.Selector select() method"""
+ selector = SCons.Scanner.Selector({'.x' : 1, '.y' : 2})
+ s = selector.select(self.skey('.x'))
+ assert s == 1, s
+ s = selector.select(self.skey('.y'))
+ assert s == 2, s
+ s = selector.select(self.skey('.z'))
+ assert s is None, s
+
+ def test_add_scanner(self):
+ """Test the Scanner.Selector add_scanner() method"""
+ selector = SCons.Scanner.Selector({'.x' : 1, '.y' : 2})
+ s = selector.select(self.skey('.z'))
+ assert s is None, s
+ selector.add_scanner('.z', 3)
+ s = selector.select(self.skey('.z'))
+ assert s == 3, s
+
class CurrentTestCase(unittest.TestCase):
def test_class(self):
"""Test the Scanner.Current class"""
tclasses = [
FindPathDirsTestCase,
ScannerTestCase,
+ BaseTestCase,
+ SelectorTestCase,
CurrentTestCase,
ClassicTestCase,
ClassicCPPTestCase,
# used as an actual argument value.
_null = _Null
+def Scanner(function, *args, **kw):
+ """Public interface factory function for creating different types
+ of Scanners based on the different types of "functions" that may
+ be supplied."""
+ if SCons.Util.is_Dict(function):
+ return apply(Selector, (function,) + args, kw)
+ else:
+ return apply(Base, (function,) + args, kw)
+
class FindPathDirs:
"""A class to bind a specific *PATH variable name and the fs object
to a function that will return all of the *path directories."""
return env.subst_list(self.skeys)[0]
return self.skeys
+ def select(self, node):
+ return self
+
+
+class Selector(Base):
+ """
+ A class for selecting a more specific scanner based on the
+ scanner_key() (suffix) for a specific Node.
+ """
+ def __init__(self, dict, *args, **kw):
+ Base.__init__(self, (None,)+args, kw)
+ self.dict = dict
+
+ def __call__(self, node, env, path = ()):
+ return self.select(node)(node, env, path)
+
+ def select(self, node):
+ try:
+ return self.dict[node.scanner_key()]
+ except KeyError:
+ return None
+
+ def add_scanner(self, skey, scanner):
+ self.dict[skey] = scanner
+
class Current(Base):
"""
def __init__(self, *args, **kw):
def current_check(node, env):
+ calc = env.get_calculator()
c = not node.has_builder() or node.current(env.get_calculator())
return c
kw['scan_check'] = current_check
their dependent parent nodes.
"""
for t in self.targets:
- def get_parents(node, parent): return node.get_parents()
- def set_state(node, parent): node.set_state(SCons.Node.failed)
- walker = SCons.Node.Walker(t, get_parents, eval_func=set_state)
- n = walker.next()
- while n:
- n = walker.next()
+ # Set failure state on all of the parents that were dependent
+ # on this failed build.
+ def set_state(node): node.set_state(SCons.Node.failed)
+ t.call_for_all_waiting_parents(set_state)
self.tm.executed(self.node)
def unbuilt_nodes(node): return node.get_state() == None
not_built = filter(unbuilt_nodes, derived)
if not_built:
+ # We're waiting on one more derived files that have not
+ # yet been built. Add this node to the waiting_parents
+ # list of each of those derived files.
+ def add_to_waiting_parents(child, parent=node):
+ child.add_to_waiting_parents(parent)
+ map(add_to_waiting_parents, not_built)
not_built.reverse()
self.candidates.extend(self.order(not_built))
continue
self.csig = None
self.state = None
self.prepared = None
- self.parents = []
+ self.waiting_parents = []
self.side_effect = 0
self.side_effects = []
self.alttargets = []
self.postprocessed = None
- for kid in kids:
- kid.parents.append(self)
-
def retrieve_from_cache(self):
global cache_text
if self.cached:
global scan_called
scan_called = scan_called + 1
self.kids = self.kids + self.scans
- for scan in self.scans:
- scan.parents.append(self)
self.scans = []
def scanner_key(self):
return self.name
- def get_parents(self):
- return self.parents
+ def add_to_waiting_parents(self, node):
+ self.waiting_parents.append(node)
+
+ def call_for_all_waiting_parents(self, func):
+ func(self)
+ for parent in self.waiting_parents:
+ parent.call_for_all_waiting_parents(func)
def get_state(self):
return self.state
n2 = Node("n2", [n1])
n3 = Node("n3", [n2])
n1.kids = [n3]
- n3.parents.append(n1)
try:
tm = SCons.Taskmaster.Taskmaster([n3])
suffix = '$PROGSUFFIX',
src_suffix = '$OBJSUFFIX',
src_builder = 'Object',
- scanner = SCons.Defaults.ProgScan)
+ target_scanner = SCons.Defaults.ProgScan)
env['BUILDERS']['Program'] = program
return program
emitter = "$SHLIBEMITTER",
prefix = '$SHLIBPREFIX',
suffix = '$SHLIBSUFFIX',
- scanner = SCons.Defaults.ProgScan,
+ target_scanner = SCons.Defaults.ProgScan,
src_suffix = '$SHOBJSUFFIX',
src_builder = 'SharedObject')
env['BUILDERS']['SharedLibrary'] = shared_lib
emitter = "$OBJEMITTER",
prefix = '$OBJPREFIX',
suffix = '$OBJSUFFIX',
- src_builder = ['CFile', 'CXXFile'])
+ src_builder = ['CFile', 'CXXFile'],
+ source_scanner = SCons.Defaults.ObjSourceScan)
env['BUILDERS']['StaticObject'] = static_obj
env['BUILDERS']['Object'] = static_obj
env['OBJEMITTER'] = SCons.Defaults.StaticObjectEmitter
emitter = "$SHOBJEMITTER",
prefix = '$SHOBJPREFIX',
suffix = '$SHOBJSUFFIX',
- src_builder = ['CFile', 'CXXFile'])
+ src_builder = ['CFile', 'CXXFile'],
+ source_scanner = SCons.Defaults.ObjSourceScan)
env['BUILDERS']['SharedObject'] = shared_obj
env['SHOBJEMITTER'] = SCons.Defaults.SharedObjectEmitter
env['RCINCPREFIX'] = '--include-dir '
env['RCINCSUFFIX'] = ''
env['RCCOM'] = '$RC $RCINCFLAGS $RCFLAGS -i $SOURCE -o $TARGET'
- env.Append(CPPSUFFIXES = ['.rc'])
+ SCons.Defaults.ObjSourceScan.add_scanner('.rc', SCons.Defaults.CScan)
env['BUILDERS']['RES'] = res_builder
# Some setting from the platform also have to be overridden:
env['RC'] = 'rc'
env['RCFLAGS'] = SCons.Util.CLVar('')
env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
- env.Append(CPPSUFFIXES = ['.rc'])
+ SCons.Defaults.ObjSourceScan.add_scanner('.rc', SCons.Defaults.CScan)
env['BUILDERS']['RES'] = res_builder
try:
out_sources.append(moc_o)
objBuilder(moc_o, moc_cpp)
self.mocFromHBld(env, moc_cpp, h)
- moc_cpp.target_scanner = SCons.Defaults.CScan
+ #moc_cpp.target_scanner = SCons.Defaults.CScan
if cpp and q_object_search.search(cpp.get_contents()):
# cpp file with Q_OBJECT macro found -> add moc
# (to be included in cpp)
env['QT_MOCNAMEGENERATOR'](base, src_ext, env)))
self.mocFromCppBld(env, moc, cpp)
env.Ignore(moc, moc)
- moc.source_scanner = SCons.Defaults.CScan
+ #moc.source_scanner = SCons.Defaults.CScan
os.chdir(old_os_cwd)
FS.chdir(old_fs_cwd)
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Test that we can add filesuffixes to $CPPSUFFIXES.
+Test the ability to scan additional filesuffixes added to $CPPSUFFIXES.
"""
import TestSCons
+python = TestSCons.python
+
test = TestSCons.TestSCons()
+test.write('mycc.py', r"""
+import string
+import sys
+def do_file(outf, inf):
+ for line in open(inf, 'rb').readlines():
+ if line[:10] == '#include <':
+ do_file(outf, line[10:-2])
+ else:
+ outf.write(line)
+outf = open(sys.argv[1], 'wb')
+for f in sys.argv[2:]:
+ do_file(outf, f)
+sys.exit(0)
+""")
+
test.write('SConstruct', """
-env = Environment(CPPPATH = ['.'])
+env = Environment(CPPPATH = ['.'],
+ CC = r'%s mycc.py',
+ CCFLAGS = [],
+ CCCOM = '$CC $TARGET $SOURCES',
+ OBJSUFFIX = '.o')
env.Append(CPPSUFFIXES = ['.x'])
-env.InstallAs('foo_c', 'foo.c')
-env.InstallAs('foo_x', 'foo.x')
+env.Object(target = 'test1', source = 'test1.c')
+env.InstallAs('test1_c', 'test1.c')
+env.InstallAs('test1_h', 'test1.h')
+env.InstallAs('test1_x', 'test1.x')
+""" % (python,))
+
+test.write('test1.c', """\
+test1.c 1
+#include <test1.h>
+#include <test1.x>
""")
-test.write('foo.c', """\
+test.write('test1.h', """\
+test1.h 1
#include <foo.h>
""")
-test.write('foo.x', """\
+test.write('test1.x', """\
+test1.x 1
#include <foo.h>
""")
test.write('foo.h', "foo.h 1\n")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.c" as "foo_c"
-Install file: "foo.x" as "foo_x"
-"""))
+%s mycc.py test1.o test1.c
+Install file: "test1.c" as "test1_c"
+Install file: "test1.h" as "test1_h"
+Install file: "test1.x" as "test1_x"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.c 1
+test1.h 1
+foo.h 1
+test1.x 1
+foo.h 1
+""")
test.up_to_date(arguments='.')
test.write('foo.h', "foo.h 2\n")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.c" as "foo_c"
-Install file: "foo.x" as "foo_x"
-"""))
+%s mycc.py test1.o test1.c
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.c 1
+test1.h 1
+foo.h 2
+test1.x 1
+foo.h 2
+""")
+
+test.up_to_date(arguments='.')
+
+test.write('test1.x', """\
+test1.x 2
+#include <foo.h>
+""")
+
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s mycc.py test1.o test1.c
+Install file: "test1.x" as "test1_x"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.c 1
+test1.h 1
+foo.h 2
+test1.x 2
+foo.h 2
+""")
+
+test.up_to_date(arguments='.')
+
+test.write('test1.h', """\
+test1.h 2
+#include <foo.h>
+""")
+
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s mycc.py test1.o test1.c
+Install file: "test1.h" as "test1_h"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.c 1
+test1.h 2
+foo.h 2
+test1.x 2
+foo.h 2
+""")
test.up_to_date(arguments='.')
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Test that we can add filesuffixes to $DSUFFIXES.
+Test the ability to scan additional filesuffixes added to $DSUFFIXES.
"""
import TestSCons
+python = TestSCons.python
+
test = TestSCons.TestSCons()
+test.write('mydc.py', r"""
+import string
+import sys
+def do_file(outf, inf):
+ for line in open(inf, 'rb').readlines():
+ if line[:7] == 'import ':
+ do_file(outf, line[7:-2]+'.d')
+ else:
+ outf.write(line)
+outf = open(sys.argv[1], 'wb')
+for f in sys.argv[2:]:
+ do_file(outf, f)
+sys.exit(0)
+""")
+
test.write('SConstruct', """
-env = Environment(DPATH=['.'])
-env.Append(DSUFFIXES = ['.x'])
-env.InstallAs('foo_d', 'foo.d')
-env.InstallAs('foo_x', 'foo.x')
+env = Environment(DPATH = ['.'],
+ DC = r'%s mydc.py',
+ DFLAGS = [],
+ DCOM = '$DC $TARGET $SOURCES',
+ OBJSUFFIX = '.o')
+env.Append(CPPSUFFIXES = ['.x'])
+env.Object(target = 'test1', source = 'test1.d')
+env.InstallAs('test1_d', 'test1.d')
+env.InstallAs('test2_d', 'test2.d')
+env.InstallAs('test3_d', 'test3.d')
+""" % (python,))
+
+test.write('test1.d', """\
+test1.d 1
+import test2;
+import test3;
+""")
+
+test.write('test2.d', """\
+test2.d 1
+import foo;
""")
-test.write('foo.d', """\
-import inc;
+test.write('test3.d', """\
+test3.d 1
+import foo;
""")
-test.write('foo.x', """\
-import inc;
+test.write('foo.d', "foo.d 1\n")
+
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s mydc.py test1.o test1.d
+Install file: "test1.d" as "test1_d"
+Install file: "test2.d" as "test2_d"
+Install file: "test3.d" as "test3_d"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.d 1
+test2.d 1
+foo.d 1
+test3.d 1
+foo.d 1
+""")
+
+test.up_to_date(arguments='.')
+
+test.write('foo.d', "foo.d 2\n")
+
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s mydc.py test1.o test1.d
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.d 1
+test2.d 1
+foo.d 2
+test3.d 1
+foo.d 2
""")
-test.write('inc.d', "inc.d 1\n")
+test.up_to_date(arguments='.')
+
+test.write('test3.d', """\
+test3.d 2
+import foo;
+""")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.d" as "foo_d"
-Install file: "foo.x" as "foo_x"
-"""))
+%s mydc.py test1.o test1.d
+Install file: "test3.d" as "test3_d"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.d 1
+test2.d 1
+foo.d 2
+test3.d 2
+foo.d 2
+""")
test.up_to_date(arguments='.')
-test.write('inc.d', "inc 2\n")
+test.write('test2.d', """\
+test2.d 2
+import foo;
+""")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.d" as "foo_d"
-Install file: "foo.x" as "foo_x"
-"""))
+%s mydc.py test1.o test1.d
+Install file: "test2.d" as "test2_d"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+test1.d 1
+test2.d 2
+foo.d 2
+test3.d 2
+foo.d 2
+""")
test.up_to_date(arguments='.')
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Test that we can add filesuffixes to $FORTRANSUFFIXES.
+Test the ability to scan additional filesuffixes added to $FORTRANSUFFIXES.
"""
import TestSCons
+python = TestSCons.python
+
test = TestSCons.TestSCons()
+test.write('myfc.py', r"""
+import string
+import sys
+def do_file(outf, inf):
+ for line in open(inf, 'rb').readlines():
+ if line[:15] == " INCLUDE '":
+ do_file(outf, line[15:-2])
+ else:
+ outf.write(line)
+outf = open(sys.argv[1], 'wb')
+for f in sys.argv[2:]:
+ do_file(outf, f)
+sys.exit(0)
+""")
+
test.write('SConstruct', """
-env = Environment()
+env = Environment(F77PATH = ['.'],
+ F77 = r'%s myfc.py',
+ F77FLAGS = [],
+ F77COM = '$F77 $TARGET $SOURCES',
+ OBJSUFFIX = '.o')
env.Append(FORTRANSUFFIXES = ['.x'])
-env.InstallAs('foo_f', 'foo.f')
-env.InstallAs('foo_x', 'foo.x')
+env.Object(target = 'test1', source = 'test1.f')
+env.InstallAs('test1_f', 'test1.f')
+env.InstallAs('test1_h', 'test1.h')
+env.InstallAs('test1_x', 'test1.x')
+""" % (python,))
+
+test.write('test1.f', """\
+ test1.f 1
+ INCLUDE 'test1.h'
+ INCLUDE 'test1.x'
+""")
+
+test.write('test1.h', """\
+ test1.h 1
+ INCLUDE 'foo.h'
+""")
+
+test.write('test1.x', """\
+ test1.x 1
+ INCLUDE 'foo.h'
+""")
+
+test.write('foo.h', """\
+ foo.h 1
+""")
+
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s myfc.py test1.o test1.f
+Install file: "test1.f" as "test1_f"
+Install file: "test1.h" as "test1_h"
+Install file: "test1.x" as "test1_x"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+ test1.f 1
+ test1.h 1
+ foo.h 1
+ test1.x 1
+ foo.h 1
""")
-test.write('foo.f', """\
-INCLUDE 'foo.h'
+test.up_to_date(arguments='.')
+
+test.write('foo.h', """\
+ foo.h 2
""")
-test.write('foo.x', """\
-INCLUDE 'foo.h'
+test.run(arguments='.', stdout=test.wrap_stdout("""\
+%s myfc.py test1.o test1.f
+""" % (python,)))
+
+test.must_match('test1.o', """\
+ test1.f 1
+ test1.h 1
+ foo.h 2
+ test1.x 1
+ foo.h 2
""")
-test.write('foo.h', "foo.h 1\n")
+test.up_to_date(arguments='.')
+
+test.write('test1.x', """\
+ test1.x 2
+ INCLUDE 'foo.h'
+""")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.f" as "foo_f"
-Install file: "foo.x" as "foo_x"
-"""))
+%s myfc.py test1.o test1.f
+Install file: "test1.x" as "test1_x"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+ test1.f 1
+ test1.h 1
+ foo.h 2
+ test1.x 2
+ foo.h 2
+""")
test.up_to_date(arguments='.')
-test.write('foo.h', "foo.h 2\n")
+test.write('test1.h', """\
+ test1.h 2
+ INCLUDE 'foo.h'
+""")
test.run(arguments='.', stdout=test.wrap_stdout("""\
-Install file: "foo.f" as "foo_f"
-Install file: "foo.x" as "foo_x"
-"""))
+%s myfc.py test1.o test1.f
+Install file: "test1.h" as "test1_h"
+""" % (python,)))
+
+test.must_match('test1.o', """\
+ test1.f 1
+ test1.h 2
+ foo.h 2
+ test1.x 2
+ foo.h 2
+""")
test.up_to_date(arguments='.')
Test that dependencies in installed header files get re-scanned correctly.
"""
+import os.path
+
import TestSCons
test = TestSCons.TestSCons()
-test.write('SConstruct', """
+test.subdir('work1', ['work1', 'dist'])
+
+test.write(['work1', 'SConstruct'], """
env = Environment(CPPPATH=['#include'])
Export('env')
SConscript('dist/SConscript')
Default(libfoo)
""")
-test.write('foo.c', """
+test.write(['work1', 'foo.c'], """
#include <h1.h>
""")
-test.subdir('dist')
-
-test.write(['dist', 'SConscript'], """\
+test.write(['work1', 'dist', 'SConscript'], """\
Import('env')
env.Install('#include', ['h1.h', 'h2.h', 'h3.h'])
""")
-test.write(['dist', 'h1.h'], """\
+test.write(['work1', 'dist', 'h1.h'], """\
#include "h2.h"
""")
-test.write(['dist', 'h2.h'], """\
+test.write(['work1', 'dist', 'h2.h'], """\
#include "h3.h"
""")
-test.write(['dist', 'h3.h'], """\
+test.write(['work1', 'dist', 'h3.h'], """\
int foo = 3;
""")
-test.run(arguments = ".")
+test.run(chdir = 'work1', arguments = ".")
+
+test.up_to_date(chdir = 'work1', arguments = ".")
+
+#
+test.subdir('ref', 'work2', ['work2', 'src'])
+
+test.write(['work2', 'SConstruct'], """
+env = Environment(CPPPATH=['build', r'%s'])
+env.Install('build', 'src/in1.h')
+env.Install('build', 'src/in2.h')
+env.Install('build', 'src/in3.h')
+""" % test.workpath('ref'))
+
+test.write(['ref', 'in1.h'], '#define FILE "ref/in1.h"\n#include <in2.h>\n')
+test.write(['ref', 'in2.h'], '#define FILE "ref/in2.h"\n#include <in3.h>\n')
+test.write(['ref', 'in3.h'], '#define FILE "ref/in3.h"\n#define FOO 0\n')
+
+src_in1_h = '#define FILE "src/in1.h"\n#include <in2.h>\n'
+src_in2_h = '#define FILE "src/in2.h"\n#include <in3.h>\n'
+src_in3_h = '#define FILE "src/in3.h"\n#define FOO 0\n'
+test.write(['work2', 'src', 'in1.h'], src_in1_h)
+test.write(['work2', 'src', 'in2.h'], src_in2_h)
+test.write(['work2', 'src', 'in3.h'], src_in3_h)
+
+test.run(chdir = 'work2', arguments = 'build')
+
+test.must_match(['work2', 'build', 'in1.h'], src_in1_h)
+test.must_match(['work2', 'build', 'in2.h'], src_in2_h)
+test.must_match(['work2', 'build', 'in3.h'], src_in3_h)
+
+test.up_to_date(chdir = 'work2', arguments = 'build')
+
+src_in3_h = '#define FILE "src/in3.h"\n#define FOO 1\n'
+test.write(['work2', 'src', 'in3.h'], src_in3_h)
+
+test.run(chdir = 'work2', arguments = 'build', stdout=test.wrap_stdout("""\
+Install file: "%s" as "%s"
+""" % (os.path.join('src', 'in3.h'),
+ os.path.join('build', 'in3.h'))))
+
+test.must_match(['work2', 'build', 'in1.h'], src_in1_h)
+test.must_match(['work2', 'build', 'in2.h'], src_in2_h)
+test.must_match(['work2', 'build', 'in3.h'], src_in3_h)
-test.up_to_date(arguments = ".")
+test.up_to_date(chdir = 'work2', arguments = 'build')
test.pass_test()
env2.Append(SCANNERS = [k2scan])
env2.Command('junk', 'junk.k2', r'%s build.py $SOURCES $TARGET')
-bar_in = File('bar.in')
-env.Command('bar', bar_in, r'%s build.py $SOURCES $TARGET')
-bar_in.source_scanner = kscan
+bar = env.Command('bar', 'bar.in', r'%s build.py $SOURCES $TARGET')
+bar.source_scanner = kscan
""" % (python, python, python))
test.write('foo.k',
-test.write("SConstruct","""
+test.write("SConstruct", """\
+import SCons.Defaults
+
def build(target, source, env):
pass
env=Environment()
-env['BUILDERS']['test'] = Builder(action=build)
+env['BUILDERS']['test'] = Builder(action=build,
+ source_scanner=SCons.Defaults.ObjSourceScan)
env.test(target='foo', source='foo.c')
""")
env = Environment(BUILDERS = builders)
e = env.Dictionary() # Slightly easier to type
-Scanned = {}
-
-def write_out(file, dict):
- keys = dict.keys()
- keys.sort()
- f = open(file, 'wb')
- for k in keys:
- file = os.path.split(k)[1]
- f.write(file + ": " + str(dict[k]) + "\\n")
- f.close()
-
-import SCons.Scanner.C
-c_scanner = SCons.Scanner.C.CScan()
-def MyCScan(node, env, target):
- deps = c_scanner(node, env, target)
-
- global Scanned
- n = str(node)
- try:
- Scanned[n] = Scanned[n] + 1
- except KeyError:
- Scanned[n] = 1
- write_out('MyCScan.out', Scanned)
-
- return deps
-S_MyCScan = SCons.Scanner.Current(skeys = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
- ".h", ".H", ".hxx", ".hpp", ".h++", ".hh"],
- function = MyCScan,
- recursive = 1)
-# QQQ Yes, this is manner of fixing the SCANNERS list is fragile.
-env["SCANNERS"] = [S_MyCScan] + env["SCANNERS"][1:]
-
global_env = env
e["GlobalEnv"] = global_env
import os
import string
import re
-import SCons.Environment
def Subdirs(env, dirlist):
for file in _subconf_list(dirlist):
""")
test.write(['SLF', 'src', 'lib_geng', 'SConstruct'], """\
+import os
+
+Scanned = {}
+
+def write_out(file, dict):
+ keys = dict.keys()
+ keys.sort()
+ f = open(file, 'wb')
+ for k in keys:
+ file = os.path.split(k)[1]
+ f.write(file + ": " + str(dict[k]) + "\\n")
+ f.close()
+
+orig_function = CScan.function
+
+def MyCScan(node, env, target, orig_function=orig_function):
+ deps = orig_function(node, env, target)
+
+ global Scanned
+ n = str(node)
+ try:
+ Scanned[n] = Scanned[n] + 1
+ except KeyError:
+ Scanned[n] = 1
+ write_out(r'%s', Scanned)
+
+ return deps
+
+CScan.function = MyCScan
+
env = Environment(CPPPATH = ".")
l = env.StaticLibrary("g", Split("libg_1.c libg_2.c libg_3.c"))
Default(l)
-""")
+""" % test.workpath('MyCScan.out'))
# These were the original shell script and Makefile from SLF's original
# bug report. We're not using them--in order to make this script as