Refactor Repository and BuildDir. (Charles Crain)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 16 Oct 2002 04:13:14 +0000 (04:13 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 16 Oct 2002 04:13:14 +0000 (04:13 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@483 fdb21ef1-2011-0410-befe-b5e4ea1792b1

16 files changed:
rpm/scons.spec
src/CHANGES.txt
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Scanner/C.py
src/engine/SCons/Scanner/Fortran.py
src/engine/SCons/Script/__init__.py
src/engine/SCons/Util.py
test/BuildDir.py
test/CPPPATH.py
test/Repository/BuildDir.py
test/Repository/LIBPATH.py [new file with mode: 0644]
test/Repository/variants.py [new file with mode: 0644]
test/option--U.py
test/option--implicit-cache.py

index a4635d9947bd0d29927b3b7ab9edc9dadd66c28e..8c1cf73c501a90f547e64c2c59568527a189e5e3 100644 (file)
@@ -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
index 42ce7e80045dc9315b8e0f050c8236f6d68f9d5c..d542c0d463a01a82f9217a050e9f3db731efb2dd 100644 (file)
@@ -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.
index 45b69019923f33c80d1e5df87fad77edce75cd55..2211bf8fdcfbb2ab5488d58f5ba765e8aa94f012 100644 (file)
@@ -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]
index 1ac7566a032103054f4686d4824480ff81961e43..aa6482dfe50dc3945e9990acba6d1d224f8c7109 100644 (file)
@@ -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()
index 51d4a6f85e5044946e18909828cac51d5f3b98b2..0c7bd696cdcda8e5245fa069ab74ff2786eac6c2 100644 (file)
@@ -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', '.')
         
index d12fd4559dacc57df6f3f3eaf37d3e106e2f3ae5..47b6ea7085a9d00e413121b78ce11733c64df229 100644 (file)
@@ -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 = ()
 
index 5e0d6d38a68b0e39af1eeea01ad14760d37e9b59..fd8c971675601a372487a3c9d6917b70eddadcb6 100644 (file)
@@ -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 = ()
 
index 65d900c0dd31e42ea6862c405561d5c1e173b990..a0bab35d7218eaac3b5e67aff7003793355b1436 100644 (file)
@@ -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
index 63c992e33d3d8874e3168e61e9748547e52e1ff5..3a39c4ecafb945bf6e152d5d0f2a8492bdd11661 100644 (file)
@@ -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 \
index b8e073ba60eafdfd433eaff68c78943f6e67921b..349ed51c534af364c2eee85d02d0b44e5b25428f 100644 (file)
@@ -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()
index a2cae10bec747b8766723a6329e8f39ba5e5be58..45216c86146edfcf523fd78908d00b470a4da9a4 100644 (file)
@@ -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")
index 2d755903b9dfe06c0c9dff40f54fb2cb69bb3266..905c61898dc6767222cb5d1bdf03131c70fc20f8 100644 (file)
@@ -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 (file)
index 0000000..a385410
--- /dev/null
@@ -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 (file)
index 0000000..d91235f
--- /dev/null
@@ -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()
index 23e82b18c30c2f78684fd92e94d7ba5401782d8b..016001577ebad117550a3f510c6cad784e426f73 100644 (file)
@@ -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')
index 4e5cf1e5a6f067102798036d46175c06ce157ba5..186b63757f278b99b8f263e1bc321d70ec197b53 100644 (file)
@@ -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")