SCons/Node/FS.py
SCons/Scanner/__init__.py
SCons/Scanner/C.py
+SCons/Scanner/Prog.py
SCons/Sig/__init__.py
SCons/Sig/MD5.py
SCons/Sig/TimeStamp.py
prefix = '',
suffix = '',
src_suffix = '',
- node_factory = SCons.Node.FS.default_fs.File):
+ node_factory = SCons.Node.FS.default_fs.File,
+ scanner = None):
self.name = name
self.action = Action(action)
self.suffix = suffix
self.src_suffix = src_suffix
self.node_factory = node_factory
+ self.scanner = scanner
if self.suffix and self.suffix[0] not in '.$':
self.suffix = '.' + self.suffix
if self.src_suffix and self.src_suffix[0] not in '.$':
if not type(files) is type([]):
files = [files]
for f in files:
- if type(f) == type(""):
+ if type(f) is types.StringType or isinstance(f, UserString):
if pre and f[:len(pre)] != pre:
- f = pre + f
+ path, fn = os.path.split(os.path.normpath(f))
+ f = os.path.join(path, pre + fn)
if suf:
if f[-len(suf):] != suf:
f = f + suf
t.builder_set(self)
t.env_set(env)
t.add_source(slist)
+ if self.scanner:
+ t.scanner_set(self.scanner)
for s in slist:
s.env_set(env, 1)
prefix = '',
suffix = '',
src_suffix = '',
- node_factory = SCons.Node.FS.default_fs.File):
+ node_factory = SCons.Node.FS.default_fs.File,
+ scanner=None):
BuilderBase.__init__(self, name, action, prefix, suffix, src_suffix,
- node_factory)
+ node_factory, scanner)
self.src_builder = src_builder
def __call__(self, env, target = None, source = None):
import TestCmd
import SCons.Builder
-
# Initial setup of the common environment for all tests,
# a temporary working directory containing a
# script for writing arguments to an output file.
class Foo:
pass
def FooFactory(target):
+ global Foo
return Foo(target)
builder = SCons.Builder.Builder(node_factory = FooFactory)
assert builder.node_factory is FooFactory
flag = 1
assert flag, "UserError should be thrown when we build targets with files of different suffixes."
+ def test_build_scanner(self):
+ """Testing ability to set a target scanner through a builder."""
+ class TestScanner:
+ pass
+ scn = TestScanner()
+ builder=SCons.Builder.Builder(scanner=scn)
+ tgt = builder(env, target='foo', source='bar')
+ assert tgt.scanner == scn, tgt.scanner
+
+ builder1 = SCons.Builder.Builder(action='foo',
+ src_suffix='.bar',
+ suffix='.foo')
+ builder2 = SCons.Builder.Builder(action='foo',
+ src_builder = builder1,
+ scanner = scn)
+ tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt')
+ assert tgt.scanner == scn, tgt.scanner
if __name__ == "__main__":
suite = unittest.makeSuite(BuilderTestCase, 'test_')
import os
import SCons.Builder
import SCons.Scanner.C
-
+import SCons.Scanner.Prog
Object = SCons.Builder.Builder(name = 'Object',
action = { '.c' : '$CCCOM',
prefix = '$PROGPREFIX',
suffix = '$PROGSUFFIX',
src_suffix = '$OBJSUFFIX',
- src_builder = Object)
+ src_builder = Object,
+ scanner = SCons.Scanner.Prog.ProgScan())
Library = SCons.Builder.Builder(name = 'Library',
action = '$ARCOM',
ConstructionEnvironment = {
'CC' : 'cc',
'CCFLAGS' : '',
- 'CCCOM' : '$CC $CCFLAGS -c -o $TARGET $SOURCES',
+ 'CCCOM' : '$CC $CCFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
'CXX' : 'c++',
'CXXFLAGS' : '$CCFLAGS',
- 'CXXCOM' : '$CXX $CXXFLAGS -c -o $TARGET $SOURCES',
+ 'CXXCOM' : '$CXX $CXXFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
'LINK' : '$CXX',
'LINKFLAGS' : '',
- 'LINKCOM' : '$LINK $LINKFLAGS -o $TARGET $SOURCES',
+ 'LINKCOM' : '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
'AR' : 'ar',
'ARFLAGS' : 'r',
'ARCOM' : '$AR $ARFLAGS $TARGET $SOURCES\nranlib $TARGET',
'LIBDIRSUFFIX' : '',
'LIBLINKPREFIX' : '-l',
'LIBLINKSUFFIX' : '',
+ 'INCPREFIX' : '-I',
+ 'INCSUFFIX' : '',
'ENV' : { 'PATH' : '/usr/local/bin:/bin:/usr/bin' },
}
ConstructionEnvironment = {
'CC' : 'cl',
'CCFLAGS' : '/nologo',
- 'CCCOM' : '$CC $CCFLAGS /c $SOURCES /Fo$TARGET',
+ 'CCCOM' : '$CC $CCFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
'CXX' : '$CC',
'CXXFLAGS' : '$CCFLAGS',
- 'CXXCOM' : '$CXX $CXXFLAGS /c $SOURCES /Fo$TARGET',
+ 'CXXCOM' : '$CXX $CXXFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
'LINK' : 'link',
'LINKFLAGS' : '',
- 'LINKCOM' : '$LINK $LINKFLAGS /out:$TARGET $SOURCES',
+ 'LINKCOM' : '$LINK $LINKFLAGS /out:$TARGET $_LIBDIRFLAGS $_LIBFLAGS $SOURCES',
'AR' : 'lib',
'ARFLAGS' : '/nologo',
'ARCOM' : '$AR $ARFLAGS /out:$TARGET $SOURCES',
'LIBDIRSUFFIX' : '',
'LIBLINKPREFIX' : '',
'LIBLINKSUFFIX' : '$LIBSUFFIX',
+ 'INCPREFIX' : '/I',
+ 'INCSUFFIX' : '',
'ENV' : {
'PATH' : r'C:\Python20;C:\WINNT\system32;C:\WINNT;C:\Program Files\Microsoft Visual Studio\VC98\Bin\;',
'PATHEXT' : '.COM;.EXE;.BAT;.CMD',
( '_LIBDIRFLAGS',
'LIBPATH',
'LIBDIRPREFIX',
- 'LIBDIRSUFFIX' ) )
+ 'LIBDIRSUFFIX' ),
+ ( '_INCFLAGS',
+ 'CPPPATH',
+ 'INCPREFIX',
+ 'INCSUFFIX' ) )
def __init__(self, **kw):
import SCons.Defaults
assert env.Dictionary('_LIBFLAGS')[2] == 'foobazbar', \
env.Dictionary('_LIBFLAGS')[2]
+ env = Environment(CPPPATH = [ 'foo', 'bar', 'baz' ],
+ INCPREFIX = 'foo',
+ INCSUFFIX = 'bar')
+ assert len(env.Dictionary('_INCFLAGS')) == 3, env.Dictionary('_INCFLAGS')
+ assert env.Dictionary('_INCFLAGS')[0] == 'foofoobar', \
+ env.Dictionary('_INCFLAGS')[0]
+ assert env.Dictionary('_INCFLAGS')[1] == 'foobarbar', \
+ env.Dictionary('_INCFLAGS')[1]
+ assert env.Dictionary('_INCFLAGS')[2] == 'foobazbar', \
+ env.Dictionary('_INCFLAGS')[2]
+
+
if __name__ == "__main__":
suite = unittest.makeSuite(EnvironmentTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
return self.path
def exists(self):
- return os.path.exists(self.path)
+ return os.path.exists(self.abspath)
def current(self):
"""If the underlying path doesn't exist, we know the node is
kids = map(lambda x, s=self: s.entries[x],
filter(lambda k: k != '.' and k != '..',
self.entries.keys()))
- kids.sort()
+ def c(one, two):
+ if one.abspath < two.abspath:
+ return -1
+ if one.abspath > two.abspath:
+ return 1
+ return 0
+ kids.sort(c)
return kids
def build(self):
self.add_dependency(scanner.scan(self.path_, self.env))
self.scanned = 1
+ def __createDir(self):
+ # ensure that the directories for this node are
+ # created.
+
+ listPaths = []
+ strPath = self.abspath
+ while 1:
+ strPath, strFile = os.path.split(strPath)
+ if os.path.exists(strPath):
+ break
+ listPaths.append(strPath)
+ if not strFile:
+ break
+ listPaths.reverse()
+ for strPath in listPaths:
+ try:
+ os.mkdir(strPath)
+ except OSError:
+ pass
+
+ def build(self):
+ self.__createDir()
+ Entry.build(self)
default_fs = FS()
f1.scan()
assert f1.depends[0].path_ == "d1/f1"
+ # Test building a file whose directory is not there yet...
+ f1 = fs.File(test.workpath("foo/bar/baz/ack"))
+ assert not f1.dir.exists()
+ f1.build()
+ assert f1.dir.exists()
+
#XXX test exists()
#XXX test current() for directories
nw = SCons.Node.Walker(n1)
assert nw.next().name == "n4"
assert nw.next().name == "n5"
+ assert nw.history.has_key(n2)
assert nw.next().name == "n2"
assert nw.next().name == "n6"
assert nw.next().name == "n7"
+ assert nw.history.has_key(n3)
assert nw.next().name == "n3"
+ assert nw.history.has_key(n1)
assert nw.next().name == "n1"
assert nw.next() == None
returns the next node on the descent with each next() call.
'kids_func' is an optional function that will be called to
get the children of a node instead of calling 'children'.
+
+ This class does not get caught in node cycles caused, for example,
+ by C header file include loops.
"""
def __init__(self, node, kids_func=get_children):
self.kids_func = kids_func
self.stack = [Wrapper(node, self.kids_func)]
+ self.history = {} # used to efficiently detect and avoid cycles
+ self.history[node] = None
def next(self):
"""Return the next node for this walk of the tree.
while self.stack:
if self.stack[-1].kids:
- self.stack.append(Wrapper(self.stack[-1].kids.pop(0),
- self.kids_func))
+ node = self.stack[-1].kids.pop(0)
+ if not self.history.has_key(node):
+ self.stack.append(Wrapper(node, self.kids_func))
+ self.history[node] = None
else:
- return self.stack.pop().node
+ node = self.stack.pop().node
+ del self.history[node]
+ return node
def is_done(self):
return not self.stack
import SCons.Scanner
import re
import os.path
+import SCons.Util
angle_re = re.compile('^[ \t]*#[ \t]*include[ \t]+<([\\w./\\\\]+)>', re.M)
quote_re = re.compile('^[ \t]*#[ \t]*include[ \t]+"([\\w./\\\\]+)"', re.M)
s.name = "CScan"
return s
-def find_files(filenames, paths):
- """
- find_files([str], [str]) -> [str]
-
- filenames - a list of filenames to find
- paths - a list of paths to search in
-
- returns - the fullnames of the files
-
- Only the first fullname found is returned for each filename, and any
- file that aren't found are ignored.
- """
- fullnames = []
- for filename in filenames:
- for path in paths:
- fullname = os.path.join(path, filename)
- if os.path.exists(fullname):
- fullnames.append(fullname)
- break
-
- return fullnames
-
def scan(filename, env, node_factory):
"""
scan(str, Environment) -> [str]
dependencies.
"""
- if hasattr(env, "CPPPATH"):
- paths = env.CPPPATH
- else:
+ try:
+ paths = env.Dictionary("CPPPATH")
+ except KeyError:
paths = []
-
- file = open(filename)
- contents = file.read()
- file.close()
- angle_includes = angle_re.findall(contents)
- quote_includes = quote_re.findall(contents)
+ try:
+ file = open(filename)
+ contents = file.read()
+ file.close()
- source_dir = os.path.dirname(filename)
-
- deps = (find_files(angle_includes, paths + [source_dir])
- + find_files(quote_includes, [source_dir] + paths))
+ angle_includes = angle_re.findall(contents)
+ quote_includes = quote_re.findall(contents)
- deps = map(node_factory, deps)
- return deps
+ source_dir = os.path.dirname(filename)
+
+ return (SCons.Util.find_files(angle_includes, paths + [source_dir],
+ node_factory)
+ + SCons.Util.find_files(quote_includes, [source_dir] + paths,
+ node_factory))
+ except OSError:
+ return []
import SCons.Scanner.C
import unittest
import sys
+import os.path
test = TestCmd.TestCmd(workdir = '')
# define some helpers:
class DummyEnvironment:
- pass
+ def __init__(self, listCppPath):
+ self.path = listCppPath
+
+ def Dictionary(self, *args):
+ if not args:
+ return { 'CPPPATH': self.path }
+ elif len(args) == 1 and args[0] == 'CPPPATH':
+ return self.path
+ else:
+ raise KeyError, "Dummy environment only has CPPPATH attribute."
def deps_match(deps, headers):
- return deps.sort() == map(test.workpath, headers).sort()
+ deps = map(str, deps)
+ headers = map(test.workpath, headers)
+ deps.sort()
+ headers.sort()
+ return map(os.path.normpath, deps) == \
+ map(os.path.normpath, headers)
# define some tests:
class CScannerTestCase1(unittest.TestCase):
def runTest(self):
- env = DummyEnvironment
+ env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
deps = s.scan(test.workpath('f1.cpp'), env)
- self.failUnless(deps_match(deps, ['f1.h', 'f2.h']))
+ self.failUnless(deps_match(deps, ['f1.h', 'f2.h']), map(str, deps))
class CScannerTestCase2(unittest.TestCase):
def runTest(self):
- env = DummyEnvironment
- env.CPPPATH = [test.workpath("d1")]
+ env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
deps = s.scan(test.workpath('f1.cpp'), env)
headers = ['f1.h', 'd1/f2.h']
- self.failUnless(deps_match(deps, headers))
+ self.failUnless(deps_match(deps, headers), map(str, deps))
class CScannerTestCase3(unittest.TestCase):
def runTest(self):
- env = DummyEnvironment
- env.CPPPATH = [test.workpath("d1")]
+ env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
deps = s.scan(test.workpath('f2.cpp'), env)
- headers = ['f1.h', 'd1/f2.h', 'd1/d2/f1.h']
- self.failUnless(deps_match(deps, headers))
-
+ headers = ['f1.h', 'd1/f1.h', 'd1/d2/f1.h']
+ self.failUnless(deps_match(deps, headers), map(str, deps))
class CScannerTestCase4(unittest.TestCase):
def runTest(self):
- env = DummyEnvironment
- env.CPPPATH = [test.workpath("d1"), test.workpath("d1/d2")]
+ env = DummyEnvironment([test.workpath("d1"), test.workpath("d1/d2")])
s = SCons.Scanner.C.CScan()
deps = s.scan(test.workpath('f2.cpp'), env)
- headers = ['f1.h', 'd1/f2.h', 'd1/d2/f1.h', 'd1/d2/f4.h']
- self.failUnless(deps_match(deps, headers))
+ headers = ['f1.h', 'd1/f1.h', 'd1/d2/f1.h', 'd1/d2/f4.h']
+ self.failUnless(deps_match(deps, headers), map(str, deps))
class CScannerTestCase5(unittest.TestCase):
def runTest(self):
- env = DummyEnvironment
+ env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
deps = s.scan(test.workpath('f3.cpp'), env)
headers = ['f1.h', 'f2.h', 'f3.h', 'd1/f1.h', 'd1/f2.h', 'd1/f3.h']
- self.failUnless(deps_match(deps, headers))
+ self.failUnless(deps_match(deps, headers), map(str, deps))
def suite():
suite = unittest.TestSuite()
--- /dev/null
+#
+# Copyright (c) 2001 Steven Knight
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Scanner
+import SCons.Node.FS
+import SCons.Util
+
+def ProgScan():
+ """Return a Scanner instance for scanning executable files
+ for static-lib dependencies"""
+ s = SCons.Scanner.Scanner(scan, SCons.Node.FS.default_fs.File)
+ s.name = "ProgScan"
+ return s
+
+def scan(filename, env, node_factory):
+ """
+ This scanner scans program files for static-library
+ dependencies. It will search the LIBPATH environment variable
+ for libraries specified in the LIBS variable, returning any
+ files it finds as dependencies.
+ """
+
+ try:
+ paths = env.Dictionary("LIBPATH")
+ except KeyError:
+ paths = []
+
+ try:
+ libs = env.Dictionary("LIBS")
+ except KeyError:
+ libs = []
+
+ try:
+ prefix = env.Dictionary("LIBPREFIX")
+ except KeyError:
+ prefix=''
+
+ try:
+ suffix = env.Dictionary("LIBSUFFIX")
+ except KeyError:
+ suffix=''
+
+ libs = map(lambda x, s=suffix, p=prefix: p + x + s, libs)
+ return SCons.Util.find_files(libs, paths, node_factory)
--- /dev/null
+#
+# Copyright (c) 2001 Steven Knight
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestCmd
+import SCons.Scanner.Prog
+import unittest
+import sys
+import os.path
+
+test = TestCmd.TestCmd(workdir = '')
+
+test.subdir('d1', ['d1', 'd2'])
+
+libs = [ 'l1.lib', 'd1/l2.lib', 'd1/d2/l3.lib' ]
+
+for h in libs:
+ test.write(h, " ")
+
+# define some helpers:
+
+class DummyEnvironment:
+ def __init__(self, **kw):
+ self._dict = kw
+ self._dict['LIBSUFFIX'] = '.lib'
+
+ def Dictionary(self, *args):
+ if not args:
+ return self._dict
+ elif len(args) == 1:
+ return self._dict[args[0]]
+ else:
+ return map(lambda x, s=self: s._dict[x], args)
+
+def deps_match(deps, libs):
+ deps=map(str, deps)
+ deps.sort()
+ libs.sort()
+ return map(os.path.normpath, deps) == \
+ map(os.path.normpath,
+ map(test.workpath, libs))
+
+# define some tests:
+
+class ProgScanTestCase1(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment(LIBPATH=[ test.workpath("") ],
+ LIBS=[ 'l1', 'l2', 'l3' ])
+ s = SCons.Scanner.Prog.ProgScan()
+ deps = s.scan('dummy', env)
+ assert deps_match(deps, ['l1.lib']), map(str, deps)
+
+class ProgScanTestCase2(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment(LIBPATH=map(test.workpath,
+ ["", "d1", "d1/d2" ]),
+ LIBS=[ 'l1', 'l2', 'l3' ])
+ s = SCons.Scanner.Prog.ProgScan()
+ deps = s.scan('dummy', env)
+ assert deps_match(deps, ['l1.lib', 'd1/l2.lib', 'd1/d2/l3.lib' ]), map(str, deps)
+
+def suite():
+ suite = unittest.TestSuite()
+ suite.addTest(ProgScanTestCase1())
+ suite.addTest(ProgScanTestCase2())
+ return suite
+
+if __name__ == "__main__":
+ runner = unittest.TextTestRunner()
+ result = runner.run(suite())
+ if not result.wasSuccessful():
+ sys.exit(1)
import sys
import unittest
+import string
from SCons.Sig.MD5 import current, collect, signature, to_string, from_string
try:
signature('string')
except AttributeError, e:
- assert str(e) == "unable to fetch contents of 'string': 'string' object has no attribute 'get_contents'", e
+ # the error string should begin with "unable to fetch contents of 'string': "
+ assert string.find(str(e), "unable to fetch contents of 'string':") == 0
else:
raise AttributeError, "unexpected get_contents() attribute"
self.failUnless(current(calc, nodes[4]))
self.failUnless(current(calc, nodes[5]))
self.failUnless(not current(calc, nodes[6]), "modified directly")
- self.failUnless(current(calc, nodes[7]), "indirect source modified")
+ self.failUnless(not current(calc, nodes[7]), "indirect source modified")
self.failUnless(not current(calc, nodes[8]), "modified directory")
self.failUnless(not current(calc, nodes[9]), "direct source modified")
self.failUnless(not current(calc, nodes[10]), "indirect source modified")
import os.path
import string
-
+import SCons.Node
#XXX Get rid of the global array so this becomes re-entrant.
sig_files = []
return None
#XXX If configured, use the content signatures from the
#XXX .sconsign file if the timestamps match.
- sigs = map(lambda n,s=self: s.get_signature(n), node.children())
+
+ # Collect the signatures for ALL the nodes that this
+ # node depends on. Just collecting the direct
+ # dependants is not good enough, because
+ # the signature of a non-derived file does
+ # not include the signatures of its psuedo-sources
+ # (e.g. the signature for a .c file does not include
+ # the signatures of the .h files that it includes).
+ walker = SCons.Node.Walker(node)
+ sigs = []
+ while 1:
+ child = walker.next()
+ if child is None: break
+ if child is node: continue # skip the node itself
+ sigs.append(self.get_signature(child))
+
if node.builder:
sigs.append(self.module.signature(node.builder_sig_adapter()))
return self.module.collect(filter(lambda x: not x is None, sigs))
"""
cmd_list = scons_subst_list(strSubst, locals, globals)
return string.join(map(string.join, cmd_list), '\n')
+
+def find_files(filenames, paths,
+ node_factory = SCons.Node.FS.default_fs.File):
+ """
+ find_files([str], [str]) -> [nodes]
+
+ filenames - a list of filenames to find
+ paths - a list of paths to search in
+
+ returns - the nodes created from the found files.
+
+ Finds nodes corresponding to either derived files or files
+ that exist already.
+
+ Only the first fullname found is returned for each filename, and any
+ file that aren't found are ignored.
+ """
+ nodes = []
+ for filename in filenames:
+ for path in paths:
+ fullname = os.path.join(path, filename)
+ try:
+ node = node_factory(fullname)
+ # Return true of the node exists or is a derived node.
+ if node.builder or \
+ (isinstance(node, SCons.Node.FS.Entry) and node.exists()):
+ nodes.append(node)
+ break
+ except TypeError:
+ # If we find a directory instead of a file, we
+ # don't care
+ pass
+
+ return nodes
import unittest
import SCons.Node
import SCons.Node.FS
-from SCons.Util import scons_str2nodes, scons_subst, PathList, scons_subst_list
-
+from SCons.Util import *
+import TestCmd
class UtilTestCase(unittest.TestCase):
def test_str2nodes(self):
assert len(cmd_list) == 2, cmd_list
assert cmd_list[1][0] == 'after', cmd_list[1][0]
assert cmd_list[0][2] == cvt('../foo/ack.cbefore'), cmd_list[0][2]
+
+ def test_find_files(self):
+ """Testing find_files function."""
+ test = TestCmd.TestCmd(workdir = '')
+ test.write('./foo', 'Some file\n')
+ fs = SCons.Node.FS.FS(test.workpath(""))
+ node_derived = fs.File(test.workpath('./bar/baz'))
+ node_derived.builder_set(1) # Any non-zero value.
+ nodes = find_files(['foo', 'baz'],
+ map(test.workpath, ['./', './bar' ]), fs.File)
+ file_names = map(str, nodes)
+ file_names = map(os.path.normpath, file_names)
+ assert os.path.normpath('./foo') in file_names, file_names
+ assert os.path.normpath('./bar/baz') in file_names, file_names
+
if __name__ == "__main__":
suite = unittest.makeSuite(UtilTestCase, 'test_')
test = TestSCons.TestSCons()
-test.pass_test() #XXX Short-circuit until this is implemented.
+test.write('foo.c',
+"""#include "include/foo.h"
+#include <stdio.h>
+
+int main(void)
+{
+ printf(TEST_STRING);
+ return 0;
+}
+""")
+
+test.subdir('include')
+
+test.write('include/foo.h',
+"""
+#define TEST_STRING "Bad news\n"
+""")
test.write('SConstruct', """
+env = Environment()
+env.Program(target='prog', source='foo.c')
+#env.Depends(target='foo.c', dependency='include/foo.h')
""")
-test.run(arguments = '.')
+test.run(arguments = 'prog')
+
+test.run(program = test.workpath('prog'),
+ stdout = "Bad news\n")
+
+test.unlink('include/foo.h')
+test.write('include/foo.h',
+"""
+#define TEST_STRING "Good news\n"
+""")
+
+test.run(arguments = 'prog')
+
+test.run(program = test.workpath('prog'),
+ stdout = "Good news\n")
test.pass_test()
test = TestSCons.TestSCons()
-test.pass_test() #XXX Short-circuit until this is implemented.
-
test.write('SConstruct', """
+env = Environment(LIBS = [ 'foo1' ],
+ LIBPATH = [ './libs' ])
+env.Program(target = 'prog', source = 'prog.c')
+env.Library(target = './libs/foo1', source = 'f1.c')
+""")
+
+test.write('f1.c', """
+void
+f1(void)
+{
+ printf("f1.c\n");
+}
""")
-test.run(arguments = '.')
+test.write('prog.c', """
+void f1(void);
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ f1();
+ printf("prog.c\n");
+ return 0;
+}
+""")
+
+test.run(arguments = 'prog')
+
+test.run(program = test.workpath('prog'),
+ stdout = "f1.c\nprog.c\n")
test.pass_test()
test = TestSCons.TestSCons()
-#XXX Need to switch TestBld to Program() when LIBS variable is working.
test.write('SConstruct', """
-TestBld = Builder(name='TestBld',
- action='cc -o $TARGET $SOURCES -L./ -lfoo1 -lfoo2 -lfoo3')
-env = Environment(BUILDERS=[ TestBld, Library ])
+env = Environment(LIBS = [ 'foo1', 'foo2', 'foo3' ],
+ LIBPATH = [ './' ])
env.Library(target = 'foo1', source = 'f1.c')
env.Library(target = 'foo2', source = 'f2a.c f2b.c f2c.c')
env.Library(target = 'foo3', source = ['f3a.c', 'f3b.c', 'f3c.c'])
-env.TestBld(target = 'prog', source = 'prog.c')
-env.Depends(target = 'prog', dependency = 'libfoo1.a libfoo2.a libfoo3.a')
+env.Program(target = 'prog', source = 'prog.c')
""")
test.write('f1.c', """
}
""")
-test.run(arguments = 'libfoo1.a libfoo2.a libfoo3.a prog')
+test.run(arguments = 'prog')
test.run(program = test.workpath('prog'),
stdout = "f1.c\nf2a.c\nf2b.c\nf2c.c\nf3a.c\nf3b.c\nf3c.c\nprog.c\n")