<!ENTITY install SYSTEM "install.sgml">
<!ENTITY intro SYSTEM "intro.sgml">
<!ENTITY process SYSTEM "process.sgml">
- <!ENTITY references SYSTEM "references.sgml">
]>
- Add separate $SHOBJPREFIX and $SHOBJSUFFIX construction variables
(by default, the same as $OBJPREFIX and $OBJSUFFIX).
- - Add a Make-like message when asked to build a source file.
+ - Add Make-like error messages when asked to build a source file,
+ and before trying to build a file that doesn't have all its source
+ files (including when an invalid drive letter is used on WIN32).
From Steven Knight and Anthony Roach:
-RELEASE 0.08 - Mon, 15 Jul 2002 12:08:51 -0500
+RELEASE 0.09 - XXX
- This is the eighth alpha release of SCons. Please consult the
+ This is the ninth alpha release of SCons. Please consult the
CHANGES.txt file for a list of specific changes since last release.
Please note the following important changes since release 0.08:
- The SetCommandHandler() function has been superceded
by the SPAWN, SHELL and ESCAPE construction variables.
- XXX
+ - SCons now exits with an error message if any source files or
+ implicit dependency files for a target do not exist and have
+ no Builder. SCons used to ignore these files, so builds that
+ formally succeeded despite the absence of a scanned file will now
+ fail unless the -k (keep going on error) flag is used.
Please note the following important changes since release 0.07:
class UserError(Exception):
def __init__(self, args=None):
self.args = args
+
+class StopError(Exception):
+ def __init__(self, args=None):
+ self.args = args
import SCons.Node
from UserDict import UserDict
import sys
-from SCons.Errors import UserError
+import SCons.Errors
import SCons.Warnings
try:
directory = self.Root[drive]
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
dir = Dir(drive, ParentOfRoot(), self)
dir.path = dir.path + os.sep
dir.abspath = dir.abspath + os.sep
Dir)
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
# look at the actual filesystem and make sure there isn't
# a file already there
ret = self.__checkClass(directory.entries[file_name], fsclass)
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
# make sure we don't create File nodes when there is actually
# a directory at that path on the disk, and vice versa
if not isinstance(build_dir, SCons.Node.Node):
build_dir = self.Dir(build_dir)
if not src_dir.is_under(self.Top):
- raise UserError, "Source directory must be under top of build tree."
+ raise SCons.Errors.UserError, "Source directory must be under top of build tree."
if src_dir.is_under(build_dir):
- raise UserError, "Source directory cannot be under build directory."
+ raise SCons.Errors.UserError, "Source directory cannot be under build directory."
build_dir.link(src_dir, duplicate)
def Repository(self, *dirs):
def prepare(self):
"""Prepare for this file to be created."""
+
+ def missing(node):
+ return not node.builder and not node.rexists()
+ missing_sources = filter(missing, self.children())
+ if missing_sources:
+ desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
+ raise SCons.Errors.StopError, desc
+
if self.exists():
if self.builder and not self.precious:
os.unlink(self.path)
assert os.path.exists(test.workpath("remove_me"))
f1 = fs.File(test.workpath("remove_me"))
f1.builder = 1
+ f1.env_set(Environment())
f1.prepare()
assert not os.path.exists(test.workpath("remove_me"))
# don't try to walk the stack, just print the error.
sys.stderr.write("\nSCons error: %s\n" % e)
raise
+ except StopError, e:
+ s = str(e)
+ if not keep_going_on_error:
+ s = s + ' Stop.'
+ sys.stderr.write("scons: *** %s\n" % s)
+ raise
except:
sys.stderr.write("scons: *** %s\n" % sys.exc_value)
raise
assert sys.argv[4] == 'blat blat', sys.argv[4]
""")
+test.write('foo.in', "foo.in\n")
+
test.run(arguments='foo.out')
test.pass_test()
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
+"""
+This test verifies that we fail gracefully and provide informative
+messages if someone tries to build a target that hasn't been defined
+or uses a nonexistent source file. On Windows systems, it checks
+to make sure that this applies to invalid drive letters as well.
+"""
+
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
+import os.path
+import string
import sys
+
import TestSCons
test = TestSCons.TestSCons()
-test.write('SConstruct', "")
+test.write('SConstruct', """
+env = Environment()
+env.Command("aaa.out", "aaa.in", "should never get executed")
+env.Command("bbb.out", "bbb.in", "should never get executed")
+""")
test.run(arguments = 'foo',
stderr = "scons: *** Do not know how to make target `foo'. Stop.\n",
""",
status = 2)
+test.run(arguments = "aaa.out",
+ stderr = "scons: *** No Builder for target `aaa.in', needed by `aaa.out'. Stop.\n",
+ status = 2)
+
+test.run(arguments = "-k bbb.out aaa.out",
+ stderr = """scons: *** No Builder for target `bbb.in', needed by `bbb.out'.
+scons: *** No Builder for target `aaa.in', needed by `aaa.out'.
+""",
+ status = 2)
+
+if sys.platform == 'win32':
+ bad_drive = None
+ for i in range(len(string.uppercase)-1, -1, -1):
+ d = string.uppercase[i]
+ if not os.path.isdir(d + ':' + os.sep):
+ bad_drive = d + ':' + '\\' + os.sep
+ break
+
+ if bad_drive is None:
+ print "All drive letters appear to be in use."
+ print "Cannot test SCons handling of invalid Win32 drive letters."
+ test.no_result(1);
+
+ test.write('SConstruct', """
+def cat(env, source, target):
+ target = str(target[0])
+ source = map(str, source)
+ print 'cat(%%s) > %%s' %% (source, target)
+ f = open(target, "wb")
+ for src in source:
+ f.write(open(src, "rb").read())
+ f.close()
+
+bad_drive = '%s'
+env = Environment(BUILDERS={'Build':Builder(action=cat)})
+env.Build('aaa.out', 'aaa.in')
+env.Build(bad_drive + 'no_target', 'bbb.in')
+env.Build('ccc.out', bad_drive + 'no_source')
+""" % bad_drive)
+
+ test.write("aaa.in", "aaa.in\n")
+
+ test.write("no_target", "no_target\n")
+
+ test.write("no_source", "no_source\n")
+
+ test.run(arguments = 'aaa.out')
+
+ test.fail_test(test.read('aaa.out') != "aaa.in\n")
+
+ test.run(arguments = bad_drive + 'no_target',
+ stderr = "scons: *** Do not know how to make target `%sno_target'. Stop.\n" % bad_drive,
+ status = 2)
+
+ test.run(arguments = 'ccc.out',
+ stderr = "scons: *** No Builder for target `%sno_source', needed by `ccc.out'. Stop.\n" % bad_drive,
+ status = 2)
+
test.pass_test()
Default(env.Build('foo', 'bar', CC='mycc', LIBS = env['LIBS']+['b']))
""")
+test.write('bar', "bar\n")
+
test.run()
test.write('SConstruct', """
Default(f3)
""")
-test.run(arguments = '.',
- stdout = test.wrap_stdout("""create file2.s from file1.s
-create file3.s from file2.s
-create file4.s from file3.s
-"""))
-
test.write('file1.s', 'file1.s\n')
test.run(arguments = '.',