summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rpm/scons.spec2
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/engine/SCons/EnvironmentTests.py50
-rw-r--r--src/engine/SCons/Node/FS.py548
-rw-r--r--src/engine/SCons/Node/FSTests.py213
-rw-r--r--src/engine/SCons/Scanner/C.py6
-rw-r--r--src/engine/SCons/Scanner/Fortran.py6
-rw-r--r--src/engine/SCons/Script/__init__.py5
-rw-r--r--src/engine/SCons/Util.py34
-rw-r--r--test/BuildDir.py88
-rw-r--r--test/CPPPATH.py4
-rw-r--r--test/Repository/BuildDir.py42
-rw-r--r--test/Repository/LIBPATH.py121
-rw-r--r--test/Repository/variants.py186
-rw-r--r--test/option--U.py2
-rw-r--r--test/option--implicit-cache.py2
16 files changed, 890 insertions, 425 deletions
diff --git a/rpm/scons.spec b/rpm/scons.spec
index a4635d9..8c1cf73 100644
--- a/rpm/scons.spec
+++ b/rpm/scons.spec
@@ -68,6 +68,8 @@ rm -rf $RPM_BUILD_ROOT
/usr/lib/scons/SCons/Node/FS.pyc
/usr/lib/scons/SCons/Node/__init__.py
/usr/lib/scons/SCons/Node/__init__.pyc
+/usr/lib/scons/SCons/Options.py
+/usr/lib/scons/SCons/Options.pyc
/usr/lib/scons/SCons/Platform/cygwin.py
/usr/lib/scons/SCons/Platform/cygwin.pyc
/usr/lib/scons/SCons/Platform/os2.py
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 42ce7e8..d542c0d 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -15,9 +15,11 @@ RELEASE 0.09 -
- Add a Prepend() method to Environments, to append values to
the beginning of construction variables.
- From Steven Knight:
+ From Charles Crain and Steven Knight:
+
+ - Add Repository() functionality.
- - Add Repository() functionality.
+ From Steven Knight:
- Fix auto-deduction of target names so that deduced targets end
up in the same subdirectory as the source.
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 45b6901..2211bf8 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -485,26 +485,16 @@ class EnvironmentTestCase(unittest.TestCase):
def test_autogenerate(dict):
"""Test autogenerating variables in a dictionary."""
- def Dir(name):
- dir = SCons.Node.FS.default_fs.Dir('/xx')
- return SCons.Node.FS.default_fs.Dir(name, dir)
-
- def File(name):
- dir = SCons.Node.FS.default_fs.Dir('/xx')
- return SCons.Node.FS.default_fs.File(name, dir)
-
- def RDirs(pathlist, Dir=Dir):
- def path_dirs(rep, path, Dir=Dir):
- if rep:
- path = os.path.join(rep, path)
- return Dir(path)
-
- return SCons.Node.FS.default_fs.Rsearchall(pathlist, path_dirs)
+ def RDirs(pathlist):
+ return SCons.Node.FS.default_fs.Rsearchall(pathlist,
+ clazz=SCons.Node.FS.Dir,
+ must_exist=0,
+ cwd=SCons.Node.FS.default_fs.Dir('xx'))
env = Environment(LIBS = [ 'foo', 'bar', 'baz' ],
LIBLINKPREFIX = 'foo',
LIBLINKSUFFIX = 'bar',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_LIBFLAGS', 1)[0]
assert len(flags) == 3, flags
assert flags[0] == 'foofoobar', \
@@ -520,18 +510,18 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = 'foo ',
INCSUFFIX = 'bar',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
assert len(flags) == 8, flags
assert flags[0] == '$(', \
flags[0]
assert flags[1] == os.path.normpath('foo'), \
flags[1]
- assert flags[2] == os.path.normpath('/xx/foobar'), \
+ assert flags[2] == os.path.normpath('xx/foobar'), \
flags[2]
assert flags[3] == os.path.normpath('foo'), \
flags[3]
- assert flags[4] == os.path.normpath('/xx/baz/barbar'), \
+ assert flags[4] == os.path.normpath('xx/baz/barbar'), \
flags[4]
assert flags[5] == os.path.normpath('foo'), \
flags[5]
@@ -544,18 +534,18 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = 'foo ',
INCSUFFIX = 'bar',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_F77INCFLAGS', 1)[0]
assert len(flags) == 8, flags
assert flags[0] == '$(', \
flags[0]
assert flags[1] == os.path.normpath('foo'), \
flags[1]
- assert flags[2] == os.path.normpath('/xx/foobar'), \
+ assert flags[2] == os.path.normpath('xx/foobar'), \
flags[2]
assert flags[3] == os.path.normpath('foo'), \
flags[3]
- assert flags[4] == os.path.normpath('/xx/baz/barbar'), \
+ assert flags[4] == os.path.normpath('xx/baz/barbar'), \
flags[4]
assert flags[5] == os.path.normpath('foo'), \
flags[5]
@@ -565,7 +555,7 @@ class EnvironmentTestCase(unittest.TestCase):
flags[7]
env = Environment(CPPPATH = '', F77PATH = '', LIBPATH = '',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
assert len(env.subst_list('$_CPPINCFLAGS')[0]) == 0
assert len(env.subst_list('$_F77INCFLAGS')[0]) == 0
assert len(env.subst_list('$_LIBDIRFLAGS')[0]) == 0
@@ -576,21 +566,21 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = '-I ',
INCSUFFIX = 'XXX',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
assert flags[0] == '$(', \
flags[0]
assert flags[1] == '-I', \
flags[1]
- assert flags[2] == os.path.normpath('/xx/fooXXX'), \
+ assert flags[2] == os.path.normpath('xx/fooXXX'), \
flags[2]
assert flags[3] == '-I', \
flags[3]
- assert flags[4] == os.path.normpath('/rep1/fooXXX'), \
+ assert flags[4] == os.path.normpath('/rep1/xx/fooXXX'), \
flags[4]
assert flags[5] == '-I', \
flags[5]
- assert flags[6] == os.path.normpath('/rep2/fooXXX'), \
+ assert flags[6] == os.path.normpath('/rep2/xx/fooXXX'), \
flags[6]
assert flags[7] == '-I', \
flags[7]
@@ -598,15 +588,15 @@ class EnvironmentTestCase(unittest.TestCase):
flags[8]
assert flags[9] == '-I', \
flags[9]
- assert flags[10] == os.path.normpath('/xx/baz/barXXX'), \
+ assert flags[10] == os.path.normpath('xx/baz/barXXX'), \
flags[10]
assert flags[11] == '-I', \
flags[11]
- assert flags[12] == os.path.normpath('/rep1/baz/barXXX'), \
+ assert flags[12] == os.path.normpath('/rep1/xx/baz/barXXX'), \
flags[12]
assert flags[13] == '-I', \
flags[13]
- assert flags[14] == os.path.normpath('/rep2/baz/barXXX'), \
+ assert flags[14] == os.path.normpath('/rep2/xx/baz/barXXX'), \
flags[14]
assert flags[15] == '-I', \
flags[15]
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 1ac7566..aa6482d 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -41,6 +41,7 @@ import SCons.Node
from UserDict import UserDict
import sys
from SCons.Errors import UserError
+import SCons.Warnings
try:
import os
@@ -62,20 +63,26 @@ class ParentOfRoot:
This class is an instance of the Null object pattern.
"""
def __init__(self):
- self.duplicate = 1
self.abspath = ''
self.path = ''
- self.srcpath = ''
self.abspath_ = ''
self.path_ = ''
- self.srcpath_ = ''
-
+ self.name=''
+ self.duplicate=0
+ self.srcdir=None
+
def is_under(self, dir):
return 0
def up(self):
return None
+ def getRepositories(self):
+ return []
+
+ def get_dir(self):
+ return None
+
if os.path.normcase("TeSt") == os.path.normpath("TeSt"):
def _my_normcase(x):
return x
@@ -83,15 +90,128 @@ else:
def _my_normcase(x):
return string.upper(x)
+class Entry(SCons.Node.Node):
+ """A generic class for file system entries. This class is for
+ when we don't know yet whether the entry being looked up is a file
+ or a directory. Instances of this class can morph into either
+ Dir or File objects by a later, more precise lookup.
+
+ Note: this class does not define __cmp__ and __hash__ for efficiency
+ reasons. SCons does a lot of comparing of Entry objects, and so that
+ operation must be as fast as possible, which means we want to use
+ Python's built-in object identity comparison.
+ """
+
+ def __init__(self, name, directory, fs):
+ """Initialize a generic file system Entry.
+
+ Call the superclass initialization, take care of setting up
+ our relative and absolute paths, identify our parent
+ directory, and indicate that this node should use
+ signatures."""
+ SCons.Node.Node.__init__(self)
+
+ self.name = name
+ self.fs = fs
+
+ assert directory, "A directory must be provided"
+
+ self.abspath = directory.abspath_ + name
+ if directory.path == '.':
+ self.path = name
+ else:
+ self.path = directory.path_ + name
+
+ self.path_ = self.path
+ self.abspath_ = self.abspath
+ self.dir = directory
+ self.cwd = None # will hold the SConscript directory for target nodes
+ self.duplicate = directory.duplicate
+
+ def get_dir(self):
+ return self.dir
+
+ def __str__(self):
+ """A FS node's string representation is its path name."""
+ if self.duplicate or self.builder:
+ return self.path
+ return self.srcnode().path
+
+ def get_contents(self):
+ """Fetch the contents of the entry.
+
+ Since this should return the real contents from the file
+ system, we check to see into what sort of subclass we should
+ morph this Entry."""
+ if os.path.isfile(self.abspath):
+ self.__class__ = File
+ self._morph()
+ return File.get_contents(self)
+ if os.path.isdir(self.abspath):
+ self.__class__ = Dir
+ self._morph()
+ return Dir.get_contents(self)
+ raise AttributeError
+
+ def exists(self):
+ try:
+ return self._exists
+ except AttributeError:
+ self._exists = os.path.exists(self.abspath)
+ return self._exists
-def exists_path(rep, path):
- """Return a path if it's already a Node or it exists in the
- real filesystem."""
- if rep:
- path = os.path.join(rep, path)
- if os.path.exists(path):
- return path
- return None
+ def rexists(self):
+ if not hasattr(self, '_rexists'):
+ 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 current(self, calc):
+ """If the underlying path doesn't exist, we know the node is
+ not current without even checking the signature, so return 0.
+ Otherwise, return None to indicate that signature calculation
+ should proceed as normal to find out if the node is current."""
+ bsig = calc.bsig(self)
+ if not self.exists():
+ return 0
+ return calc.current(self, bsig)
+
+ def is_under(self, dir):
+ if self is dir:
+ return 1
+ else:
+ return self.dir.is_under(dir)
+
+ def set_local(self):
+ self._local = 1
+
+ def srcnode(self):
+ """If this node is in a build path, return the node
+ corresponding to its source file. Otherwise, return
+ ourself."""
+ try:
+ return self._srcnode
+ except AttributeError:
+ dir=self.dir
+ name=self.name
+ while dir:
+ if dir.srcdir:
+ self._srcnode = self.fs.Entry(name, dir.srcdir,
+ klass=self.__class__)
+ return self._srcnode
+ name = dir.name + os.sep + name
+ dir=dir.get_dir()
+ self._srcnode = self
+ return self._srcnode
+
+# This is for later so we can differentiate between Entry the class and Entry
+# the method of the FS class.
+_classEntry = Entry
class FS:
@@ -110,7 +230,6 @@ class FS:
self.pathTop = path
self.Root = {}
self.Top = None
- self.Repositories = []
def set_toplevel_dir(self, path):
assert not self.Top, "You can only set the top-level path on an FS object that has not had its File, Dir, or Entry methods called yet."
@@ -120,7 +239,6 @@ class FS:
if not self.Top:
self.Top = self.__doLookup(Dir, os.path.normpath(self.pathTop))
self.Top.path = '.'
- self.Top.srcpath = '.'
self.Top.path_ = '.' + os.sep
self._cwd = self.Top
@@ -137,7 +255,7 @@ class FS:
return node
if not isinstance(node, klass):
raise TypeError, "Tried to lookup %s '%s' as a %s." % \
- (node.__class__.__name__, str(node), klass.__name__)
+ (node.__class__.__name__, node.path, klass.__name__)
return node
def __doLookup(self, fsclass, name, directory = None, create = 1):
@@ -173,7 +291,6 @@ class FS:
dir = Dir(drive, ParentOfRoot(), self)
dir.path = dir.path + os.sep
dir.abspath = dir.abspath + os.sep
- dir.srcpath = dir.srcpath + os.sep
self.Root[drive] = dir
directory = dir
path_comp = path_comp[1:]
@@ -192,7 +309,7 @@ class FS:
# look at the actual filesystem and make sure there isn't
# a file already there
- path = os.path.join(str(directory), path_name)
+ path = directory.path_ + path_name
if os.path.isfile(path):
raise TypeError, \
"File %s found where directory expected." % path
@@ -210,7 +327,7 @@ class FS:
# make sure we don't create File nodes when there is actually
# a directory at that path on the disk, and vice versa
- path = os.path.join(str(directory), path_comp[-1])
+ path = directory.path_ + path_comp[-1]
if fsclass == File:
if os.path.isdir(path):
raise TypeError, \
@@ -301,12 +418,12 @@ class FS:
def BuildDir(self, build_dir, src_dir, duplicate=1):
"""Link the supplied build directory to the source directory
for purposes of building files."""
+
self.__setTopLevelDir()
if not isinstance(src_dir, SCons.Node.Node):
src_dir = self.Dir(src_dir)
if not isinstance(build_dir, SCons.Node.Node):
build_dir = self.Dir(build_dir)
- build_dir.duplicate = duplicate
if not src_dir.is_under(self.Top):
raise UserError, "Source directory must be under top of build tree."
if src_dir.is_under(build_dir):
@@ -316,24 +433,47 @@ class FS:
def Repository(self, *dirs):
"""Specify Repository directories to search."""
for d in dirs:
- self.Repositories.append(self.Dir(d))
+ if not isinstance(d, SCons.Node.Node):
+ d = self.Dir(d)
+ self.__setTopLevelDir()
+ self.Top.addRepository(d)
- def Rsearch(self, path, func = exists_path):
+ def Rsearch(self, path, clazz=_classEntry, cwd=None):
"""Search for something in a Repository. Returns the first
one found in the list, or None if there isn't one."""
if isinstance(path, SCons.Node.Node):
return path
else:
- n = func(None, path)
- if n:
+ name, d = self.__transformPath(path, cwd)
+ n = self.__doLookup(clazz, name, d)
+ if n.exists():
return n
- for rep in self.Repositories:
- n = func(rep.path, path)
- if n:
- return n
+ d = n.get_dir()
+ name = n.name
+ # Search repositories of all directories that this file is under.
+ while d:
+ for rep in d.getRepositories():
+ try:
+ rnode = self.__doLookup(clazz, name, rep)
+ # Only find the node if it exists and it is not
+ # a derived file. If for some reason, we are
+ # explicitly building a file IN a Repository, we
+ # don't want it to show up in the build tree.
+ # This is usually the case with BuildDir().
+ # We only want to find pre-existing files.
+ if rnode.exists() and \
+ (isinstance(rnode, Dir) or not rnode.builder):
+ return rnode
+ except TypeError:
+ pass # Wrong type of node.
+ # Prepend directory name
+ name = d.name + os.sep + name
+ # Go up one directory
+ d = d.get_dir()
return None
+
- def Rsearchall(self, pathlist, func = exists_path):
+ def Rsearchall(self, pathlist, must_exist=1, clazz=_classEntry, cwd=None):
"""Search for a list of somethings in the Repository list."""
ret = []
if SCons.Util.is_String(pathlist):
@@ -344,133 +484,39 @@ class FS:
if isinstance(path, SCons.Node.Node):
ret.append(path)
else:
- n = func(None, path)
- if n:
+ name, d = self.__transformPath(path, cwd)
+ n = self.__doLookup(clazz, name, d)
+ if not must_exist or n.exists():
ret.append(n)
- if not os.path.isabs(path):
- if path[0] == '#':
- path = path[1:]
- for rep in self.Repositories:
- n = func(rep.path, path)
- if n:
- ret.append(n)
+ if isinstance(n, Dir):
+ # If this node is a directory, then any repositories
+ # attached to this node can be repository paths.
+ ret.extend(filter(lambda x, me=must_exist, clazz=clazz: isinstance(x, clazz) and (not me or x.exists()),
+ n.getRepositories()))
+
+ d = n.get_dir()
+ name = n.name
+ # Search repositories of all directories that this file is under.
+ while d:
+ for rep in d.getRepositories():
+ try:
+ rnode = self.__doLookup(clazz, name, rep)
+ # Only find the node if it exists (or must_exist is zero)
+ # and it is not a derived file. If for some reason, we
+ # are explicitly building a file IN a Repository, we don't
+ # want it to show up in the build tree. This is usually the
+ # case with BuildDir(). We only want to find pre-existing files.
+ if (not must_exist or rnode.exists()) and \
+ (not rnode.builder or isinstance(rnode, Dir)):
+ ret.append(rnode)
+ except TypeError:
+ pass # Wrong type of node.
+ # Prepend directory name
+ name = d.name + os.sep + name
+ # Go up one directory
+ d = d.get_dir()
return ret
-
-class Entry(SCons.Node.Node):
- """A generic class for file system entries. This class if for
- when we don't know yet whether the entry being looked up is a file
- or a directory. Instances of this class can morph into either
- Dir or File objects by a later, more precise lookup.
-
- Note: this class does not define __cmp__ and __hash__ for efficiency
- reasons. SCons does a lot of comparing of Entry objects, and so that
- operation must be as fast as possible, which means we want to use
- Python's built-in object identity comparison.
- """
-
- def __init__(self, name, directory, fs):
- """Initialize a generic file system Entry.
-
- Call the superclass initialization, take care of setting up
- our relative and absolute paths, identify our parent
- directory, and indicate that this node should use
- signatures."""
- SCons.Node.Node.__init__(self)
-
- self.name = name
-
- assert directory, "A directory must be provided"
-
- self.duplicate = directory.duplicate
- self.abspath = directory.abspath_ + name
- if str(directory.path) == '.':
- self.path = name
- else:
- self.path = directory.path_ + name
-
- self.path_ = self.path
- self.abspath_ = self.abspath
- self.dir = directory
- self.__doSrcpath(self.duplicate)
- self.srcpath_ = self.srcpath
- self.cwd = None # will hold the SConscript directory for target nodes
- self._local = None
- self.fs = fs # The filesystem that this entry is part of
-
- def get_dir(self):
- return self.dir
-
- def adjust_srcpath(self, duplicate):
- self.__doSrcpath(duplicate)
-
- def __doSrcpath(self, duplicate):
- self.duplicate = duplicate
- if str(self.dir.srcpath) == '.':
- self.srcpath = self.name
- else:
- self.srcpath = self.dir.srcpath_ + self.name
-
- def __str__(self):
- """A FS node's string representation is its path name."""
- if self.duplicate or self.builder:
- return self.path
- else:
- return self.srcpath
-
- def get_contents(self):
- """Fetch the contents of the entry.
-
- Since this should return the real contents from the file
- system, we check to see into what sort of subclass we should
- morph this Entry."""
- if os.path.isfile(self.abspath):
- self.__class__ = File
- self._morph()
- return File.get_contents(self)
- if os.path.isdir(self.abspath):
- self.__class__ = Dir
- self._morph()
- return Dir.get_contents(self)
- raise AttributeError
-
- def exists(self):
- if not hasattr(self, '_exists'):
- self._exists = os.path.exists(str(self))
- return self._exists
-
- def rexists(self):
- if not hasattr(self, '_rexists'):
- self._rexists = os.path.exists(self.rstr())
- 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 current(self, calc):
- """If the underlying path doesn't exist, we know the node is
- not current without even checking the signature, so return 0.
- Otherwise, return None to indicate that signature calculation
- should proceed as normal to find out if the node is current."""
- bsig = calc.bsig(self)
- if not self.exists():
- return 0
- return calc.current(self, bsig)
-
- def is_under(self, dir):
- if self is dir:
- return 1
- else:
- return self.dir.is_under(dir)
-
- def set_local(self):
- self._local = 1
-
-
-
# XXX TODO?
# Annotate with the creator
# rel_path
@@ -497,15 +543,53 @@ class Dir(Entry):
self.path_ = self.path + os.sep
self.abspath_ = self.abspath + os.sep
- self.srcpath_ = self.srcpath + os.sep
-
+ self.repositories = []
+ self.srcdir = None
+
self.entries = {}
self.entries['.'] = self
self.entries['..'] = self.dir
self.cwd = self
self.builder = 1
self._sconsign = None
-
+
+ def __clearRepositoryCache(self, duplicate=None):
+ """Called when we change the repository(ies) for a directory.
+ This clears any cached information that is invalidated by changing
+ the repository."""
+
+ for node in self.entries.values():
+ if node != self.dir:
+ if node != self and isinstance(node, Dir):
+ node.__clearRepositoryCache(duplicate)
+ else:
+ try:
+ del node._srcreps
+ except AttributeError:
+ pass
+ try:
+ del node._rfile
+ except AttributeError:
+ pass
+ try:
+ del node._rexists
+ except AttributeError:
+ pass
+ try:
+ del node._exists
+ except AttributeError:
+ pass
+ try:
+ del node._srcnode
+ except AttributeError:
+ pass
+ if duplicate != None:
+ node.duplicate=duplicate
+
+ def __resetDuplicate(self, node):
+ if node != self:
+ node.duplicate = node.get_dir().duplicate
+
def Dir(self, name):
"""Create a directory node named 'name' relative to this directory."""
return self.fs.Dir(name, self)
@@ -513,23 +597,32 @@ class Dir(Entry):
def File(self, name):
"""Create file node named 'name' relatove to this directory."""
return self.fs.File(name, self)
-
- def __doReparent(self, duplicate):
- for ent in self.entries.values():
- if not ent is self and not ent is self.dir:
- ent.adjust_srcpath(duplicate)
-
- def adjust_srcpath(self, duplicate):
- Entry.adjust_srcpath(self, duplicate)
- self.srcpath_ = self.srcpath + os.sep
- self.__doReparent(duplicate)
def link(self, srcdir, duplicate):
"""Set this directory as the build directory for the
supplied source directory."""
- self.srcpath = srcdir.path
- self.srcpath_ = srcdir.path_
- self.__doReparent(duplicate)
+ self.srcdir = srcdir
+ self.duplicate = duplicate
+ self.__clearRepositoryCache(duplicate)
+
+ def getRepositories(self):
+ """Returns a list of repositories for this directory."""
+ if self.srcdir and not self.duplicate:
+ try:
+ return self._srcreps
+ except AttributeError:
+ self._srcreps = self.fs.Rsearchall(self.srcdir.path,
+ clazz=Dir,
+ must_exist=0,
+ cwd=self.fs.Top) \
+ + self.repositories
+ return self._srcreps
+ return self.repositories
+
+ def addRepository(self, dir):
+ if not dir in self.repositories and dir != self:
+ self.repositories.append(dir)
+ self.__clearRepositoryCache()
def up(self):
return self.entries['..']
@@ -595,32 +688,6 @@ class Dir(Entry):
self._sconsign = SCons.Sig.SConsignFile(self)
return self._sconsign
- def __str__(self):
- # Reimplemented from Entry since, unlike for
- # Entry and File, we want to return the source
- # path *even if* the builder is non-zero
- # (which it always is for a directory)
- if self.duplicate:
- return self.path
- else:
- return self.srcpath
-
- def exists(self):
- # Again, directories are special...we don't care if their
- # source path exists, we only care about the path.
- if not hasattr(self, '_exists'):
- self._exists = os.path.exists(self.path)
- return self._exists
-
- def rexists(self):
- # Again, directories are special...we don't care if their
- # source path exists, we only care about the path.
- if not hasattr(self, '_rexists'):
- self._rexists = os.path.exists(self.rstr())
- return self._rexists
-
-
-
# XXX TODO?
# base_suf
# suffix
@@ -648,12 +715,8 @@ class File(Entry):
def RDirs(self, pathlist):
"""Search for a list of directories in the Repository list."""
- def path_dirs(rep, path, Dir=self.Dir):
- if rep:
- path = os.path.join(rep, path)
- return Dir(path)
-
- return self.fs.Rsearchall(pathlist, path_dirs)
+ return self.fs.Rsearchall(pathlist, clazz=Dir, must_exist=0,
+ cwd=self.cwd)
def generate_build_env(self):
env = SCons.Node.Node.generate_build_env(self)
@@ -665,6 +728,7 @@ class File(Entry):
def _morph(self):
"""Turn a file system node into a File object."""
self.created = 0
+ self._local = 0
def root(self):
return self.dir.root()
@@ -733,56 +797,7 @@ class File(Entry):
return scanner.scan(self, env, target)
else:
return []
-
- def exists(self):
- if not hasattr(self, '_exists'):
- if self.duplicate and not self.created:
- self.created = 1
- if self.srcpath != self.path and \
- os.path.exists(self.srcpath):
- if os.path.exists(self.path):
- os.unlink(self.path)
- self.__createDir()
- file_link(self.srcpath, self.path)
- self._exists = os.path.exists(str(self))
- return self._exists
-
- def rexists(self):
- if not hasattr(self, '_rexists'):
- if self.path != self.srcpath:
- if os.path.exists(self.srcpath):
- if self.duplicate and not self.created:
- self.created = 1
- if os.path.exists(self.path):
- os.unlink(self.path)
- self.__createDir()
- file_link(self.srcpath, self.path)
- self._rexists = 1
- return self._rexists
- for rep in self.fs.Repositories:
- if not os.path.isabs(self.path):
- f = os.path.join(rep.path, self.path)
- if os.path.exists(f):
- self._rexists = 1
- return self._rexists
- f = os.path.join(rep.path, self.srcpath)
- if os.path.exists(f):
- if self.duplicate and not self.created:
- self.created = 1
- if os.path.exists(self.path):
- os.unlink(self.path)
- self.__createDir()
- file_link(f, self.path)
- else:
- self.srcpath = f
- self.srcpath_ = f + os.sep
- self._rexists = 1
- return self._rexists
- self._rexists = None
- else:
- self._rexists = Entry.rexists(self)
- return self._rexists
-
+
def scanner_key(self):
return os.path.splitext(self.name)[1]
@@ -829,6 +844,26 @@ class File(Entry):
return 1
return None
+ def exists(self):
+ # Duplicate from source path if we are set up to do this.
+ if self.duplicate and not self.builder and not self.created:
+ src=self.srcnode().rfile()
+ if src.exists() and src.abspath != self.abspath:
+ try:
+ os.unlink(self.abspath)
+ except OSError:
+ pass
+ self.__createDir()
+ file_link(src.abspath,
+ self.abspath)
+ self.created = 1
+
+ # Set our exists cache accordingly
+ self._exists=1
+ self._rexists=1
+ return 1
+ return Entry.exists(self)
+
def current(self, calc):
bsig = calc.bsig(self)
if not self.exists():
@@ -853,20 +888,15 @@ class File(Entry):
def rfile(self):
if not hasattr(self, '_rfile'):
self._rfile = self
- if not os.path.isabs(self.path) and not os.path.isfile(self.path):
- def file_node(dir, path, fs=self.fs):
- if dir:
- path = os.path.join(dir, path)
- if os.path.isfile(path):
- return fs.File(path)
- return None
- n = self.fs.Rsearch(self.path, file_node)
+ if not self.exists():
+ n = self.fs.Rsearch(self.path, clazz=File,
+ cwd=self.fs.Top)
if n:
self._rfile = n
return self._rfile
def rstr(self):
- return os.path.normpath(str(self.rfile()))
+ return str(self.rfile())
default_fs = FS()
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 51d4a6f..0c7bd69 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -82,23 +82,23 @@ class BuildDirTestCase(unittest.TestCase):
f1 = fs.File('build/test1')
fs.BuildDir('build', 'src')
f2 = fs.File('build/test2')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test2'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test2'), f2.srcnode().path
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
fs.BuildDir('build', '.')
f2 = fs.File('build/test2')
- assert f1.srcpath == 'test1', f1.srcpath
- assert f2.srcpath == 'test2', f2.srcpath
+ assert f1.srcnode().path == 'test1', f1.srcnode().path
+ assert f2.srcnode().path == 'test2', f2.srcnode().path
fs = SCons.Node.FS.FS()
fs.BuildDir('build/var1', 'src')
fs.BuildDir('build/var2', 'src')
f1 = fs.File('build/var1/test1')
f2 = fs.File('build/var2/test1')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
fs = SCons.Node.FS.FS()
fs.BuildDir('../var1', 'src')
@@ -106,56 +106,136 @@ class BuildDirTestCase(unittest.TestCase):
f1 = fs.File('../var1/test1')
f2 = fs.File('../var2/test1')
assert hasattr(f1, 'overrides')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
+
+ # Set up some files
+ test.subdir('work', ['work', 'src'])
+ test.subdir(['work', 'build'], ['work', 'build', 'var1'])
+ test.subdir(['work', 'build', 'var2'])
+ test.subdir('rep1', ['rep1', 'src'])
+ test.subdir(['rep1', 'build'], ['rep1', 'build', 'var1'])
+ test.subdir(['rep1', 'build', 'var2'])
+
+ # A source file in the source directory
+ test.write([ 'work', 'src', 'test.in' ], 'test.in')
+
+ # A source file in the repository
+ test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
+
+ # Some source files in the build directory
+ test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
+ test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
- fs = SCons.Node.FS.FS()
+ # An old derived file in the build directories
+ test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
+ test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
+
+ # And just in case we are weird, a derived file in the source
+ # dir.
+ test.write([ 'work', 'src', 'test.out' ], 'test.out.src')
+
+ # A derived file in the repository
+ test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
+ test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
+
+ fs = SCons.Node.FS.FS(test.workpath('work'))
fs.BuildDir('build/var1', 'src', duplicate=0)
fs.BuildDir('build/var2', 'src')
- f1 = fs.File('build/var1/test')
+ f1 = fs.File('build/var1/test.in')
f1out = fs.File('build/var1/test.out')
f1out.builder = 1
- f2 = fs.File('build/var2/test')
+ f1out_2 = fs.File('build/var1/test2.out')
+ f1out_2.builder = 1
+ f2 = fs.File('build/var2/test.in')
f2out = fs.File('build/var2/test.out')
f2out.builder = 1
-
- assert f1.srcpath == os.path.normpath('src/test'), f1.srcpath
- assert f1out.srcpath == os.path.normpath('src/test.out'), f1out.srcpath
- assert str(f1) == os.path.normpath('src/test'), str(f1)
- assert str(f1out) == os.path.normpath('build/var1/test.out'), str(f1out)
- assert f2.srcpath == os.path.normpath('src/test'), f2.srcpath
- assert f2out.srcpath == os.path.normpath('src/test.out'), f2out.srcpath
- assert str(f2) == os.path.normpath('build/var2/test'), str(f2)
- assert str(f2out) == os.path.normpath('build/var2/test.out'), str(f2out)
-
- assert not f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- test.subdir('src')
- test.write(['src', 'test'], "src/test\n")
- test.write(['src', 'test'], "src/test.out\n")
-
+ f2out_2 = fs.File('build/var2/test2.out')
+ f2out_2.builder = 1
+ fs.Repository(test.workpath('rep1'))
+
+ assert f1.srcnode().path == os.path.normpath('src/test.in'),\
+ f1.srcnode().path
+ # str(node) returns source path for duplicate = 0
+ assert str(f1) == os.path.normpath('src/test.in'), str(f1)
+ # Build path does not exist
assert not f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- f1.built()
- f2.built()
-
- assert f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- d1 = fs.Dir('build/var1')
- d2 = fs.Dir('build/var2')
-
- assert str(d1) == 'src', str(d1)
- assert str(d2) == os.path.normpath('build/var2'), str(d2)
+ # But source path does
+ assert f1.srcnode().exists()
+ # And duplicate=0 should also work just like a Repository
+ assert f1.rexists()
+ # rfile() should point to the source path
+ assert f1.rfile().path == os.path.normpath('src/test.in'),\
+ f1.rfile().path
+
+ assert f2.srcnode().path == os.path.normpath('src/test.in'),\
+ f2.srcnode().path
+ # str(node) returns build path for duplicate = 1
+ assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
+ # Build path exists
+ assert f2.exists()
+ # ...and should copy the file from src to build path
+ assert test.read(['work', 'build', 'var2', 'test.in']) == 'test.in',\
+ test.read(['work', 'build', 'var2', 'test.in'])
+ # Since exists() is true, so should rexists() be
+ assert f2.rexists()
+ f3 = fs.File('build/var1/test2.in')
+ f4 = fs.File('build/var2/test2.in')
+
+ assert f3.srcnode().path == os.path.normpath('src/test2.in'),\
+ f3.srcnode().path
+ # str(node) returns source path for duplicate = 0
+ assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
+ # Build path does not exist
+ assert not f3.exists()
+ # Source path does not either
+ assert not f3.srcnode().exists()
+ # But we do have a file in the Repository
+ assert f3.rexists()
+ # rfile() should point to the source path
+ assert f3.rfile().path == test.workpath('rep1/src/test2.in'),\
+ f3.rfile().path
+
+ assert f4.srcnode().path == os.path.normpath('src/test2.in'),\
+ f4.srcnode().path
+ # str(node) returns build path for duplicate = 1
+ assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
+ # Build path should exist
+ assert f4.exists()
+ # ...and copy over the file into the local build path
+ assert test.read(['work', 'build', 'var2', 'test2.in']) == 'test2.in'
+ # should exist in repository, since exists() is true
+ assert f4.rexists()
+ # rfile() should point to ourselves
+ assert f4.rfile().path == os.path.normpath('build/var2/test2.in'),\
+ f4.rfile().path
+
+ f5 = fs.File('build/var1/test.out')
+ f6 = fs.File('build/var2/test.out')
+
+ assert f5.exists()
+ # We should not copy the file from the source dir, since this is
+ # a derived file.
+ assert test.read(['work', 'build', 'var1', 'test.out']) == 'test.old'
+
+ assert f6.exists()
+ # We should not copy the file from the source dir, since this is
+ # a derived file.
+ assert test.read(['work', 'build', 'var2', 'test.out']) == 'test.old'
+ f7 = fs.File('build/var1/test2.out')
+ f8 = fs.File('build/var2/test2.out')
+
+ assert not f7.exists()
+ assert f7.rexists()
+ assert f7.rfile().path == test.workpath('rep1/build/var1/test2.out'),\
+ f7.rfile().path
+
+ assert not f8.exists()
+ assert f8.rexists()
+ assert f8.rfile().path == test.workpath('rep1/build/var2/test2.out'),\
+ f8.rfile().path
+
# Test to see if file_link() works...
test.subdir('src','build')
test.write('src/foo', 'foo\n')
@@ -664,8 +744,9 @@ class RepositoryTestCase(unittest.TestCase):
fs.Repository(os.path.join('bar', 'foo'))
fs.Repository('bar')
- assert len(fs.Repositories) == 4, fs.Repositories
- r = map(lambda x, np=os.path.normpath: np(str(x)), fs.Repositories)
+ rep = fs.Dir('#').getRepositories()
+ assert len(rep) == 4, map(str, rep)
+ r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
assert r == ['foo',
os.path.join('foo', 'bar'),
os.path.join('bar', 'foo'),
@@ -703,15 +784,6 @@ class RepositoryTestCase(unittest.TestCase):
assert fs.Rsearch('f2')
assert fs.Rsearch(f3) is f3
- def my_exists(rep, path):
- if rep:
- path = os.path.join(rep, path)
- return os.path.exists(path)
-
- assert not fs.Rsearch('f1', my_exists)
- assert fs.Rsearch('f2', my_exists)
- assert fs.Rsearch('f3', my_exists)
-
list = fs.Rsearchall(fs.Dir('d1'))
assert len(list) == 1, list
assert list[0].path == 'd1', list[0].path
@@ -727,36 +799,41 @@ class RepositoryTestCase(unittest.TestCase):
assert list == [], list
test.subdir(['work', 'd2'])
+ fs.File('d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2'], list
+ assert map(str, list) == ['d2'], list
test.subdir(['rep2', 'd2'])
+ fs.File('../rep2/d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2', test.workpath('rep2', 'd2')], list
+ assert map(str, list) == ['d2', test.workpath('rep2', 'd2')], list
test.subdir(['rep1', 'd2'])
+ fs.File('../rep1/d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2',
- test.workpath('rep1', 'd2'),
- test.workpath('rep2', 'd2')], list
+ assert map(str, list) == ['d2',
+ test.workpath('rep1', 'd2'),
+ test.workpath('rep2', 'd2')], list
list = fs.Rsearchall(['d3', 'd4'])
assert list == [], list
test.subdir(['work', 'd3'])
- list = fs.Rsearchall(['d3', 'd4'])
+ fs.File('d3').built() # Clear exists cache
+ list = map(str, fs.Rsearchall(['d3', 'd4']))
assert list == ['d3'], list
test.subdir(['rep3', 'd4'])
- list = fs.Rsearchall(['d3', 'd4'])
+ fs.File('../rep3/d4').built() # Clear exists cache
+ list = map(str, fs.Rsearchall(['d3', 'd4']))
assert list == ['d3', test.workpath('rep3', 'd4')], list
- list = fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep))
+ list = map(str, fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep)))
assert list == ['d3', test.workpath('rep3', 'd4')], list
work_d4 = fs.File(os.path.join('work', 'd4'))
- list = fs.Rsearchall(['d3', work_d4])
- assert list == ['d3', work_d4], list
+ list = map(str, fs.Rsearchall(['d3', work_d4]))
+ assert list == ['d3', str(work_d4)], list
fs.BuildDir('build', '.')
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py
index d12fd45..47b6ea7 100644
--- a/src/engine/SCons/Scanner/C.py
+++ b/src/engine/SCons/Scanner/C.py
@@ -79,12 +79,8 @@ def scan(node, env, target, fs = SCons.Node.FS.default_fs):
# node.includes - the result of include_re.findall()
if not hasattr(target, 'cpppath'):
- def Dir(rep, path, dir=target.cwd, fs=fs):
- if rep:
- path = os.path.join(rep, path)
- return fs.Dir(path, dir)
try:
- target.cpppath = tuple(fs.Rsearchall(env['CPPPATH'], Dir))
+ target.cpppath = tuple(fs.Rsearchall(SCons.Util.mapPaths(env['CPPPATH'], target.cwd), clazz=SCons.Node.FS.Dir))
except KeyError:
target.cpppath = ()
diff --git a/src/engine/SCons/Scanner/Fortran.py b/src/engine/SCons/Scanner/Fortran.py
index 5e0d6d3..fd8c971 100644
--- a/src/engine/SCons/Scanner/Fortran.py
+++ b/src/engine/SCons/Scanner/Fortran.py
@@ -77,12 +77,8 @@ def scan(node, env, target, fs = SCons.Node.FS.default_fs):
# node.includes - the result of include_re.findall()
if not hasattr(target, 'f77path'):
- def Dir(rep, path, dir=target.cwd, fs=fs):
- if rep:
- path = os.path.join(rep, path)
- return fs.Dir(path, dir)
try:
- target.f77path = tuple(fs.Rsearchall(env['F77PATH'], Dir))
+ target.f77path = tuple(fs.Rsearchall(SCons.Util.mapPaths(env['F77PATH'], target.cwd), clazz=SCons.Node.FS.Dir))
except KeyError:
target.f77path = ()
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 65d900c..a0bab35 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -997,8 +997,9 @@ def _main():
# -U with default targets
default_targets = SCons.Script.SConscript.default_targets
def check_dir(x):
- cwd = SCons.Node.FS.default_fs.Dir(x.cwd.srcpath)
- return cwd == target_top
+ reps = SCons.Node.FS.default_fs.Rsearchall(str(x.cwd), must_exist=0,
+ clazz=SCons.Node.FS.Dir)
+ return target_top in reps
default_targets = filter(check_dir, default_targets)
SCons.Script.SConscript.default_targets = default_targets
target_top = None
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 63c992e..3a39c4e 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -370,6 +370,40 @@ def Split(arg):
else:
return [arg]
+def mapPaths(paths, dir):
+ """Takes a single node or string, or a list of nodes and/or
+ strings. We leave the nodes untouched, but we put the strings
+ under the supplied directory node dir, if they are not an absolute
+ path.
+
+ For instance, the following:
+
+ n = SCons.Node.FS.default_fs.File('foo')
+ mapPaths([ n, 'foo', '/bar' ],
+ SCons.Node.FS.default_fs.Dir('baz'))
+
+ ...would return:
+
+ [ n, 'baz/foo', '/bar' ]
+ """
+
+ def mapPathFunc(path, dir=dir):
+ if dir and is_String(path):
+ if not path:
+ return str(dir)
+ if os.path.isabs(path) or path[0] == '#':
+ return path
+ return dir.path_ + path
+ return path
+
+ if not is_List(paths):
+ paths = [ paths ]
+ ret = map(mapPathFunc, paths)
+ if len(ret) == 1:
+ ret = ret[0]
+ return ret
+
+
if hasattr(types, 'UnicodeType'):
def is_String(e):
return type(e) is types.StringType \
diff --git a/test/BuildDir.py b/test/BuildDir.py
index b8e073b..349ed51 100644
--- a/test/BuildDir.py
+++ b/test/BuildDir.py
@@ -76,13 +76,15 @@ var2 = Dir('build/var2')
var3 = Dir('build/var3')
var4 = Dir('build/var4')
var5 = Dir('../build/var5')
+var6 = Dir('../build/var6')
BuildDir('build/var1', src)
-BuildDir(var2, src)
-BuildDir(var3, src, duplicate=0)
+BuildDir(var2, src, duplicate=0)
+BuildDir(var3, src)
BuildDir(var4, src, duplicate=0)
-BuildDir(var5, src, duplicate=0)
+BuildDir(var5, src)
+BuildDir(var6, src, duplicate=0)
env = Environment(CPPPATH='#src', F77PATH='#src')
SConscript('build/var1/SConscript', "env")
@@ -94,6 +96,7 @@ SConscript(File('SConscript', var4), "env")
env = Environment(CPPPATH='.', F77PATH='.')
SConscript('../build/var5/SConscript', "env")
+SConscript('../build/var6/SConscript', "env")
""")
test.subdir(['test', 'src'])
@@ -114,6 +117,13 @@ Import("env")
env.Command(target='f2.c', source='f2.in', action=buildIt)
env.Program(target='foo2', source='f2.c')
env.Program(target='foo1', source='f1.c')
+env.Command(target='f3.h', source='f3h.in', action=buildIt)
+env.Command(target='f4.h', source='f4h.in', action=buildIt)
+env.Command(target='f4.c', source='f4.in', action=buildIt)
+
+env2=env.Copy(CPPPATH='.')
+env2.Program(target='foo3', source='f3.c')
+env2.Program(target='foo4', source='f4.c')
try:
f77 = env['F77']
@@ -122,8 +132,8 @@ except:
if f77 and WhereIs(env['F77']):
env.Command(target='b2.f', source='b2.in', action=buildIt)
- env.Copy(LIBS = 'g2c').Program(target='bar2', source='b2.f')
- env.Copy(LIBS = 'g2c').Program(target='bar1', source='b1.f')
+ env.Copy(LIBS = ['g2c']).Program(target='bar2', source='b2.f')
+ env.Copy(LIBS = ['g2c']).Program(target='bar1', source='b1.f')
""")
test.write('test/src/f1.c', r"""
@@ -150,6 +160,30 @@ main(int argc, char *argv[])
}
""")
+test.write('test/src/f3.c', r"""
+#include "f3.h"
+
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf(F3_STR);
+ exit (0);
+}
+""")
+
+test.write('test/src/f4.in', r"""
+#include "f4.h"
+
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf(F4_STR);
+ exit (0);
+}
+""")
+
test.write('test/src/f1.h', r"""
#define F1_STR "f1.c\n"
""")
@@ -158,6 +192,14 @@ test.write('test/src/f2.h', r"""
#define F2_STR "f2.c\n"
""")
+test.write('test/src/f3h.in', r"""
+#define F3_STR "f3.c\n"
+""")
+
+test.write('test/src/f4h.in', r"""
+#define F4_STR "f4.c\n"
+""")
+
test.write(['test', 'src', 'b1.f'], r"""
PROGRAM FOO
INCLUDE 'b1.for'
@@ -214,37 +256,25 @@ def equal_stats(x,y):
return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and
x[stat.ST_MTIME] == y[stat.ST_MTIME])
-# Make sure we did duplicate the source files in build/var2, and that their stats are the same:
-test.fail_test(not os.path.exists(test.workpath('test', 'build', 'var2', 'f1.c')))
-test.fail_test(not os.path.exists(test.workpath('test', 'build', 'var2', 'f2.in')))
-test.fail_test(not equal_stats(test.workpath('test', 'build', 'var2', 'f1.c'), test.workpath('test', 'src', 'f1.c')))
-test.fail_test(not equal_stats(test.workpath('test', 'build', 'var2', 'f2.in'), test.workpath('test', 'src', 'f2.in')))
-
-# Make sure we didn't duplicate the source files in build/var3.
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'f1.c')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'f2.in')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'b1.f')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'b2.in')))
-
-# Make sure we didn't duplicate the source files in build/var4.
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'f1.c')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'f2.in')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'b1.f')))
-test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'b2.in')))
-
-# Make sure we didn't duplicate the source files in build/var5.
-test.fail_test(os.path.exists(test.workpath('build', 'var5', 'f1.c')))
-test.fail_test(os.path.exists(test.workpath('build', 'var5', 'f2.in')))
-test.fail_test(os.path.exists(test.workpath('build', 'var5', 'b1.f')))
-test.fail_test(os.path.exists(test.workpath('build', 'var5', 'b2.in')))
-
# verify that header files in the source directory are scanned properly:
test.write(['test', 'src', 'f1.h'], r"""
#define F1_STR "f1.c 2\n"
""")
+test.write(['test', 'src', 'f3h.in'], r"""
+#define F3_STR "f3.c 2\n"
+""")
+
+test.write(['test', 'src', 'f4h.in'], r"""
+#define F4_STR "f4.c 2\n"
+""")
+
test.run(chdir='test', arguments = '../build/var5')
test.run(program = foo51, stdout = "f1.c 2\n")
+test.run(program = test.workpath('build', 'var5', 'foo3' + _exe),
+ stdout = "f3.c 2\n")
+test.run(program = test.workpath('build', 'var5', 'foo4' + _exe),
+ stdout = "f4.c 2\n")
test.pass_test()
diff --git a/test/CPPPATH.py b/test/CPPPATH.py
index a2cae10..45216c8 100644
--- a/test/CPPPATH.py
+++ b/test/CPPPATH.py
@@ -49,7 +49,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.c')
env.Program(target='prog', source=obj)
SConscript('subdir/SConscript', "env")
-BuildDir('variant', 'subdir', 0)
+BuildDir('variant', 'subdir', duplicate=0)
include = Dir('include')
env = Environment(CPPPATH=[include])
SConscript('variant/SConscript', "env")
@@ -168,7 +168,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.c')
env.Program(target='prog', source=obj)
SConscript('subdir/SConscript', "env")
-BuildDir('variant', 'subdir', 0)
+BuildDir('variant', 'subdir')
include = Dir('include')
env = Environment(CPPPATH=['inc2', include])
SConscript('variant/SConscript', "env")
diff --git a/test/Repository/BuildDir.py b/test/Repository/BuildDir.py
index 2d75590..905c618 100644
--- a/test/Repository/BuildDir.py
+++ b/test/Repository/BuildDir.py
@@ -38,8 +38,8 @@ opts = "-Y " + test.workpath('repository')
#
test.write(['repository', 'SConstruct'], r"""
-BuildDir('build0', 'src', duplicate=0)
-BuildDir('build1', 'src', duplicate=1)
+BuildDir('build0', 'src')
+BuildDir('build1', 'src', duplicate=0)
SConscript('build0/SConscript')
SConscript('build1/SConscript')
""")
@@ -78,9 +78,9 @@ repository/src/bbb.in
repository/src/ccc.in
""")
-test.fail_test(os.path.exists('work1/build0/aaa.in'))
-test.fail_test(os.path.exists('work1/build0/bbb.in'))
-test.fail_test(os.path.exists('work1/build0/ccc.in'))
+test.fail_test(not os.path.exists('work1/build0/aaa.in'))
+test.fail_test(not os.path.exists('work1/build0/bbb.in'))
+test.fail_test(not os.path.exists('work1/build0/ccc.in'))
test.fail_test(not os.path.exists('work1/build0/aaa.mid'))
test.fail_test(not os.path.exists('work1/build0/bbb.mid'))
test.fail_test(not os.path.exists('work1/build0/ccc.mid'))
@@ -91,9 +91,9 @@ repository/src/bbb.in
repository/src/ccc.in
""")
-test.fail_test(not os.path.exists('work1/build1/aaa.in'))
-test.fail_test(not os.path.exists('work1/build1/bbb.in'))
-test.fail_test(not os.path.exists('work1/build1/ccc.in'))
+test.fail_test(os.path.exists('work1/build1/aaa.in'))
+test.fail_test(os.path.exists('work1/build1/bbb.in'))
+test.fail_test(os.path.exists('work1/build1/ccc.in'))
test.fail_test(not os.path.exists('work1/build1/aaa.mid'))
test.fail_test(not os.path.exists('work1/build1/bbb.mid'))
test.fail_test(not os.path.exists('work1/build1/ccc.mid'))
@@ -111,9 +111,9 @@ work1/src/bbb.in
repository/src/ccc.in
""")
-test.fail_test(os.path.exists('work1/build0/aaa.in'))
-test.fail_test(os.path.exists('work1/build0/bbb.in'))
-test.fail_test(os.path.exists('work1/build0/ccc.in'))
+test.fail_test(not os.path.exists('work1/build0/aaa.in'))
+test.fail_test(not os.path.exists('work1/build0/bbb.in'))
+test.fail_test(not os.path.exists('work1/build0/ccc.in'))
test.fail_test(not os.path.exists('work1/build0/aaa.mid'))
test.fail_test(not os.path.exists('work1/build0/bbb.mid'))
test.fail_test(not os.path.exists('work1/build0/ccc.mid'))
@@ -124,9 +124,9 @@ work1/src/bbb.in
repository/src/ccc.in
""")
-test.fail_test(not os.path.exists('work1/build1/aaa.in'))
-test.fail_test(not os.path.exists('work1/build1/bbb.in'))
-test.fail_test(not os.path.exists('work1/build1/ccc.in'))
+test.fail_test(os.path.exists('work1/build1/aaa.in'))
+test.fail_test(os.path.exists('work1/build1/bbb.in'))
+test.fail_test(os.path.exists('work1/build1/ccc.in'))
test.fail_test(not os.path.exists('work1/build1/aaa.mid'))
test.fail_test(not os.path.exists('work1/build1/bbb.mid'))
test.fail_test(not os.path.exists('work1/build1/ccc.mid'))
@@ -144,9 +144,9 @@ test.writable('repository', 0)
#
test.run(chdir = 'work2', options = opts, arguments = '.')
-test.fail_test(os.path.exists('work2/build0/aaa.in'))
-test.fail_test(os.path.exists('work2/build0/bbb.in'))
-test.fail_test(os.path.exists('work2/build0/ccc.in'))
+test.fail_test(not os.path.exists('work2/build0/aaa.in'))
+test.fail_test(not os.path.exists('work2/build0/bbb.in'))
+test.fail_test(not os.path.exists('work2/build0/ccc.in'))
test.fail_test(os.path.exists('work2/build0/aaa.mid'))
test.fail_test(os.path.exists('work2/build0/bbb.mid'))
test.fail_test(os.path.exists('work2/build0/ccc.mid'))
@@ -173,9 +173,9 @@ work2/src/bbb.in
repository/src/ccc.in
""")
-test.fail_test(os.path.exists('work2/build0/aaa.in'))
-test.fail_test(os.path.exists('work2/build0/bbb.in'))
-test.fail_test(os.path.exists('work2/build0/ccc.in'))
+test.fail_test(not os.path.exists('work2/build0/aaa.in'))
+test.fail_test(not os.path.exists('work2/build0/bbb.in'))
+test.fail_test(not os.path.exists('work2/build0/ccc.in'))
test.fail_test(os.path.exists('work2/build0/aaa.mid'))
test.fail_test(not os.path.exists('work2/build0/bbb.mid'))
test.fail_test(os.path.exists('work2/build0/ccc.mid'))
@@ -187,7 +187,7 @@ repository/src/ccc.in
""")
test.fail_test(os.path.exists('work2/build1/aaa.in'))
-test.fail_test(not os.path.exists('work2/build1/bbb.in'))
+test.fail_test(os.path.exists('work2/build1/bbb.in'))
test.fail_test(os.path.exists('work2/build1/ccc.in'))
test.fail_test(os.path.exists('work2/build1/aaa.mid'))
test.fail_test(not os.path.exists('work2/build1/bbb.mid'))
diff --git a/test/Repository/LIBPATH.py b/test/Repository/LIBPATH.py
new file mode 100644
index 0000000..a385410
--- /dev/null
+++ b/test/Repository/LIBPATH.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2001, 2002 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 string
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('foo', ['foo', 'zzz'], 'bar', ['bar', 'yyy'], 'work')
+
+workpath_foo = test.workpath('foo')
+workpath_foo_yyy = test.workpath('foo', 'yyy')
+workpath_foo_zzz = test.workpath('foo', 'zzz')
+workpath_bar = test.workpath('bar')
+workpath_bar_yyy = test.workpath('bar', 'yyy')
+workpath_bar_zzz = test.workpath('bar', 'zzz')
+workpath_work = test.workpath('work')
+
+test.write(['work', 'SConstruct'], r"""
+import string
+env_zzz = Environment(LIBPATH = ['.', 'zzz'])
+env_yyy = Environment(LIBPATH = ['yyy', '.'])
+aaa_exe = env_zzz.Program('aaa', 'aaa.c')
+bbb_exe = env_yyy.Program('bbb', 'bbb.c')
+def write_LIBDIRFLAGS(env, target, source):
+ pre = env.subst('$LIBDIRPREFIX')
+ suf = env.subst('$LIBDIRSUFFIX')
+ f = open(str(target[0]), 'wb')
+ for arg in string.split(env.subst('$_LIBDIRFLAGS')):
+ if arg[:len(pre)] == pre:
+ arg = arg[len(pre):]
+ if arg[-len(suf):] == suf:
+ arg = arg[:-len(pre)]
+ f.write(arg + '\n')
+ f.close()
+ return 0
+env_zzz.Command('zzz.out', aaa_exe, write_LIBDIRFLAGS)
+env_yyy.Command('yyy.out', bbb_exe, write_LIBDIRFLAGS)
+""")
+
+test.write(['work', 'aaa.c'], r"""
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf("work/aaa.c\n");
+ exit (0);
+}
+""")
+
+test.write(['work', 'bbb.c'], r"""
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf("work/bbb.c\n");
+ exit (0);
+}
+""")
+
+#
+opts = "-Y %s -Y %s -Y %s" % (workpath_foo, workpath_work, workpath_bar)
+test.run(chdir = 'work', options = opts, arguments = ".")
+
+#dirs = ['.', workpath_foo, workpath_bar, workpath_foo_zzz]
+dirs = ['.', workpath_foo, workpath_bar,
+ 'zzz', workpath_foo_zzz, workpath_bar_zzz]
+test.fail_test(test.read(['work', 'zzz.out']) !=
+ string.join(dirs, '\n') + '\n')
+
+#dirs = [workpath_bar_yyy, '.', workpath_foo, workpath_bar]
+dirs = ['yyy', workpath_foo_yyy, workpath_bar_yyy,
+ '.', workpath_foo, workpath_bar]
+test.fail_test(test.read(['work', 'yyy.out']) !=
+ string.join(dirs, '\n') + '\n')
+
+#
+test.run(chdir = 'work', options = '-c', arguments = ".")
+
+test.subdir(['work', 'zzz'], ['work', 'yyy'])
+
+#
+test.run(chdir = 'work', options = opts, arguments = ".")
+
+#dirs = ['.', workpath_foo, workpath_bar, 'zzz', workpath_foo_zzz]
+dirs = ['.', workpath_foo, workpath_bar,
+ 'zzz', workpath_foo_zzz, workpath_bar_zzz]
+test.fail_test(test.read(['work', 'zzz.out']) !=
+ string.join(dirs, '\n') + '\n')
+
+#dirs = ['yyy', workpath_bar_yyy, '.', workpath_foo, workpath_bar]
+dirs = ['yyy', workpath_foo_yyy, workpath_bar_yyy,
+ '.', workpath_foo, workpath_bar]
+test.fail_test(test.read(['work', 'yyy.out']) !=
+ string.join(dirs, '\n') + '\n')
+
+#
+test.pass_test()
diff --git a/test/Repository/variants.py b/test/Repository/variants.py
new file mode 100644
index 0000000..d91235f
--- /dev/null
+++ b/test/Repository/variants.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2001, 2002 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 os.path
+import time
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('repository', ['repository', 'src'],
+ 'work1', ['work1', 'src'],
+ 'work2', ['work2', 'src'])
+
+repository_build_foo_xxx = test.workpath('repository', 'build', 'foo', 'xxx')
+work1_build_foo_xxx = test.workpath('work1', 'build', 'foo', 'xxx')
+work1_build_bar_xxx = test.workpath('work1', 'build', 'bar', 'xxx')
+
+opts = "-Y " + test.workpath('repository')
+
+#
+test.write(['repository', 'SConstruct'], r"""
+OS = ARGUMENTS['OS']
+build_os = "#build/" + OS
+ccflags = {
+ 'foo' : '-DFOO',
+ 'bar' : '-DBAR',
+}
+env = Environment(CCFLAGS = ccflags[OS],
+ CPPPATH = build_os)
+BuildDir(build_os, 'src')
+SConscript(build_os + '/SConscript', "env")
+""")
+
+test.write(['repository', 'src', 'SConscript'], r"""
+Import("env")
+env.Program('xxx', ['aaa.c', 'bbb.c', 'main.c'])
+""")
+
+test.write(['repository', 'src', 'iii.h'], r"""
+#ifdef FOO
+#define STRING "REPOSITORY_FOO"
+#endif
+#ifdef BAR
+#define STRING "REPOSITORY_BAR"
+#endif
+""")
+
+test.write(['repository', 'src', 'aaa.c'], r"""
+#include <iii.h>
+void
+aaa(void)
+{
+ printf("repository/src/aaa.c: %s\n", STRING);
+}
+""")
+
+test.write(['repository', 'src', 'bbb.c'], r"""
+#include <iii.h>
+void
+bbb(void)
+{
+ printf("repository/src/bbb.c: %s\n", STRING);
+}
+""")
+
+test.write(['repository', 'src', 'main.c'], r"""
+#include <iii.h>
+extern void aaa(void);
+extern void bbb(void);
+int
+main(int argc, char *argv[])
+{
+#ifdef BAR
+ printf("Only when -DBAR.\n");
+#endif
+ aaa();
+ bbb();
+ printf("repository/src/main.c: %s\n", STRING);
+ exit (0);
+}
+""")
+
+#
+test.run(chdir = 'repository', options = opts + " OS=foo", arguments = '.')
+
+test.run(program = repository_build_foo_xxx, stdout =
+"""repository/src/aaa.c: REPOSITORY_FOO
+repository/src/bbb.c: REPOSITORY_FOO
+repository/src/main.c: REPOSITORY_FOO
+""")
+
+test.fail_test(os.path.exists(test.workpath('repository', 'src', '.sconsign')))
+test.fail_test(os.path.exists(test.workpath('src', '.sconsign')))
+
+# Make the entire repository non-writable, so we'll detect
+# if we try to write into it accidentally.
+test.writable('repository', 0)
+
+#
+test.up_to_date(chdir = 'work1', options = opts + " OS=foo", arguments = '.')
+
+test.fail_test(os.path.exists(test.workpath('work1', 'build', 'foo', 'aaa.o')))
+test.fail_test(os.path.exists(test.workpath('work1', 'build', 'foo', 'bbb.o')))
+test.fail_test(os.path.exists(test.workpath('work1', 'build', 'foo', 'main.o')))
+test.fail_test(os.path.exists(test.workpath('work1', 'build', 'foo', 'xxx')))
+
+#
+test.run(chdir = 'work1', options = opts, arguments = 'OS=bar .')
+
+test.run(program = work1_build_bar_xxx, stdout =
+"""Only when -DBAR.
+repository/src/aaa.c: REPOSITORY_BAR
+repository/src/bbb.c: REPOSITORY_BAR
+repository/src/main.c: REPOSITORY_BAR
+""")
+
+test.fail_test(os.path.exists(test.workpath('repository', 'src', '.sconsign')))
+test.fail_test(os.path.exists(test.workpath('src', '.sconsign')))
+
+test.up_to_date(chdir = 'work1', options = opts + " OS=bar", arguments = '.')
+
+#
+time.sleep(2)
+test.write(['work1', 'src', 'iii.h'], r"""
+#ifdef FOO
+#define STRING "WORK_FOO"
+#endif
+#ifdef BAR
+#define STRING "WORK_BAR"
+#endif
+""")
+
+#
+test.run(chdir = 'work1', options = opts + " OS=bar", arguments = '.')
+
+test.run(program = work1_build_bar_xxx, stdout =
+"""Only when -DBAR.
+repository/src/aaa.c: WORK_BAR
+repository/src/bbb.c: WORK_BAR
+repository/src/main.c: WORK_BAR
+""")
+
+test.fail_test(os.path.exists(test.workpath('repository', 'src', '.sconsign')))
+test.fail_test(os.path.exists(test.workpath('src', '.sconsign')))
+
+test.up_to_date(chdir = 'work1', options = opts + " OS=bar", arguments = '.')
+
+#
+test.run(chdir = 'work1', options = opts + " OS=foo", arguments = '.')
+
+test.run(program = work1_build_foo_xxx, stdout =
+"""repository/src/aaa.c: WORK_FOO
+repository/src/bbb.c: WORK_FOO
+repository/src/main.c: WORK_FOO
+""")
+
+test.fail_test(os.path.exists(test.workpath('repository', 'src', '.sconsign')))
+test.fail_test(os.path.exists(test.workpath('src', '.sconsign')))
+
+test.up_to_date(chdir = 'work1', options = opts + " OS=foo", arguments = '.')
+
+#
+test.pass_test()
diff --git a/test/option--U.py b/test/option--U.py
index 23e82b1..0160015 100644
--- a/test/option--U.py
+++ b/test/option--U.py
@@ -52,7 +52,7 @@ Default(env.B(target = 'sub1/foo.out', source = 'sub1/foo.in'))
Export('env')
SConscript('sub2/SConscript')
Default(env.B(target = 'sub3/baz.out', source = 'sub3/baz.in'))
-BuildDir('sub2b', 'sub2')
+BuildDir('sub2b', 'sub2', duplicate=0)
SConscript('sub2b/SConscript')
Default(env.B(target = 'sub2/xxx.out', source = 'xxx.in'))
SConscript('SConscript')
diff --git a/test/option--implicit-cache.py b/test/option--implicit-cache.py
index 4e5cf1e..186b637 100644
--- a/test/option--implicit-cache.py
+++ b/test/option--implicit-cache.py
@@ -52,7 +52,7 @@ obj = env.Object(target='prog', source='subdir/prog.c')
env.Program(target='prog', source=obj)
SConscript('subdir/SConscript', "env")
-BuildDir('variant', 'subdir', 0)
+BuildDir('variant', 'subdir')
include = Dir('include')
env = Environment(CPPPATH=['inc2', include])
SConscript('variant/SConscript', "env")