attributes defined in this subclass.
"""
-# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
+# __COPYRIGHT__
-__revision__ = "QMTest/TestSCons_time.py 0.96.C629 2006/11/19 06:39:17 knight"
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
$ scons build/scons
-If you don't have SCons version 0.96 or later already installed on your
-system, you can use SCons itself to populate the build/scons/ directory
-with a little more typing. You must first set the SCONS_LIB_DIR
-environment variable to the local src/engine subdirectory, and then
-execute the local src/script/scons.py script to populate the build/scons/
-subdirectory. You would do this as follows on a Linux or UNIX system
-(using sh or a derivative like bash or ksh):
+You can also use this version of SCons to populate its own build directory
+by using a supplied bootstrap.py script:
+
+ $ python bootstrap.py build/scons
+
+The bootstrap.py keeps the src/ subdirectory free of compiled Python
+(*.pyc or *.pyo) files by copying the necessary SCons files to a local
+bootstrap/ subdirectory and executing it from there.
+
+You can also execute the local SCons directly from the src/ subdirectory
+by first setting the SCONS_LIB_DIR environment variable to the local
+src/engine subdirectory, and then execute the local src/script/scons.py
+script to populate the build/scons/ subdirectory. You would do this as
+follows on a Linux or UNIX system (using sh or a derivative like bash
+or ksh):
$ export SCONS_LIB_DIR=`pwd`/src/engine
$ python src/script/scons.py build/scons
Or as follows on Windows:
C:\scons\>set SCONS_LIB_DIR=%cd%\src\engine
- C:\scons\>python src/script/scons.py build/scons
+ C:\scons\>python src\script\scons.py build/scons
-Either command will populate the build/scons/ directory with the necessary
-files and directory structure to use the Python-standard setup script
-as follows on Linux or UNIX:
+Any of the above commands will populate the build/scons/ directory with
+the necessary files and directory structure to use the Python-standard
+setup script as follows on Linux or UNIX:
# cd build/scons
# python setup.py install
mainly to find the appropriate build engine library and then execute it.
In order to make your own change locally and test them by hand, simply
-edit modules in the local src/engine/SCons and set the SCONS_LIB_DIR
-to point to that directory. Here is one way you can set up environment
-variables to do this on a UNIX or Linux system:
+edit modules in the local src/engine/SCons subdirectory tree and
+either use the local bootstrap.py script:
+
+ $ python bootstrap.py [arguments]
+
+Or set the SCONS_LIB_DIR to point to the src/engine/SCons directory and
+then execute the src/script/scons.py script. Here is one way you can
+set up environment variables to do this on a UNIX or Linux system:
$ setenv MYSCONS=`pwd`/src
$ setenv SCONS_LIB_DIR=$MYSCONS
an SCons bug, and you want to see if a patch you make actually fixes
that bug):
- $ python $MYSCONS/script/scons.py -C /some/other/location [arguments]
+ $ python bootstrap.py -C /some/other/location [arguments]
Lastly, if you want to be able to just execute your modified version
of SCons from the command line, you can make it executable and add its
# When this gets changed, you also need to change test/option-v.py
# so it looks for the right string.
-copyright_years = '2001, 2002, 2003, 2004, 2005, 2006'
+copyright_years = '2001, 2002, 2003, 2004, 2005, 2006, 2007'
+
+# This gets inserted into the man pages to reflect the month of release.
+month_year = 'January 2007'
#
# __COPYRIGHT__
contents = string.replace(contents, '__DATE' + '__', env['DATE'])
contents = string.replace(contents, '__DEVELOPER' + '__', env['DEVELOPER'])
contents = string.replace(contents, '__FILE' + '__', str(source[0]))
+ contents = string.replace(contents, '__MONTH_YEAR'+ '__', env['MONTH_YEAR'])
contents = string.replace(contents, '__REVISION' + '__', env['REVISION'])
contents = string.replace(contents, '__VERSION' + '__', env['VERSION'])
contents = string.replace(contents, '__NULL' + '__', '')
COPYRIGHT = copyright,
DATE = date,
DEVELOPER = developer,
+ MONTH_YEAR = month_year,
REVISION = revision,
VERSION = version,
DH_COMPAT = 2,
-"""bootstrap.py
-
-This is an Aegis-to-SCons build script that collects a copy of the
-current SCons into a bootstrap/ subdirectory and then executes it with
-the supplied command-line options.
-
-Right now, it only understands the SCons -Y option, which is the only
-one currently used. It collects the repositories specified by -Y and
-searches them, in order, for the pieces of SCons to copy into the local
-bootstrap/ subdirectory.
-
-This is essentially a minimal build of SCons to bootstrap ourselves into
-executing it for the full build of all the packages, as specified in our
-local SConstruct file.
-
-"""
-
#
# __COPYRIGHT__
#
import string
import sys
+__doc__ = """bootstrap.py
+
+This script supports "bootstrap" execution of the current SCons in
+this local source tree by copying of all necessary Python scripts and
+modules from underneath the src/ subdirectory into a subdirectory (named
+"bootstrap/" by default), and then executing the copied SCons with the
+supplied command-line arguments.
+
+There are a handful of options that are specific to this bootstrap.py
+script and which are *not* passed on to the underlying SCons script.
+All of these begin with the string "bootstrap_":
+
+ --bootstrap_dir=DIR
+
+ Sets the name of the directory into which the SCons files will
+ be copied. The default is "bootstrap" in the local subdirectory.
+
+ --bootstrap_force
+
+ Forces a copy of all necessary files. By default, the
+ bootstrap.py script only updates the bootstrap copy if the
+ content of the source copy is different.
+
+ --bootstrap_update
+
+ Only updates the bootstrap subdirectory, and then exits.
+
+In addition to the above options, the bootstrap.py script understands
+the -Y and --repository= options, which are used under Aegis to specify
+a search path for the source files that may not have been copied in to
+the Aegis change.
+
+This is essentially a minimal build of SCons to bootstrap ourselves into
+executing it for the full build of all the packages, as specified in our
+local SConstruct file.
+"""
+
+bootstrap_dir = 'bootstrap'
+pass_through_args = []
search = ['.']
+update_only = None
+
+requires_an_argument = 'bootstrap.py: %s requires an argument\n'
+
+command_line_args = sys.argv[1:]
+
+def must_copy(dst, src):
+ if not os.path.exists(dst):
+ return 1
+ return open(dst, 'rb').read() != open(src, 'rb').read()
-opts, args = getopt.getopt(sys.argv[1:], "Y:", [])
+while command_line_args:
+ arg = command_line_args.pop(0)
-for o, a in opts:
- if o == '-Y':
- search.append(a)
+ if arg == '--bootstrap_dir':
+ try:
+ bootstrap_dir = command_line_args.pop(0)
+ except IndexError:
+ sys.stderr.write(requires_an_argument % arg)
+ sys.exit(1)
+
+ elif arg[:16] == '--bootstrap_dir=':
+ bootstrap_dir = arg[16:]
+
+ elif arg == '--bootstrap_force':
+ def must_copy(dst, src):
+ return 1
+
+ elif arg == '--bootstrap_update':
+ update_only = 1
+
+ elif arg in ('-Y', '--repository'):
+ try:
+ dir = command_line_args.pop(0)
+ except IndexError:
+ sys.stderr.write(requires_an_argument % arg)
+ sys.exit(1)
+ else:
+ search.append(dir)
+ pass_through_args.extend([arg, dir])
+
+ elif arg[:2] == '-Y':
+ search.append(arg[2:])
+ pass_through_args.append(arg)
+
+ elif arg[:13] == '--repository=':
+ search.append(arg[13:])
+ pass_through_args.append(arg)
+
+ else:
+ pass_through_args.append(arg)
def find(file, search=search):
for dir in search:
files = [ scons_py ] + map(lambda x: os.path.join(src_engine, x[:-1]),
open(MANIFEST_in).readlines())
-subdir = 'bootstrap'
-
for file in files:
src = find(file)
- dst = os.path.join(subdir, file)
- dir, _ = os.path.split(dst)
- if not os.path.isdir(dir):
- os.makedirs(dir)
- contents = open(src, 'rb').read()
- try: os.unlink(dst)
- except: pass
- open(dst, 'wb').write(contents)
-
-args = [ sys.executable, os.path.join(subdir, scons_py) ] + sys.argv[1:]
+ dst = os.path.join(bootstrap_dir, file)
+ if must_copy(dst, src):
+ dir = os.path.split(dst)[0]
+ if not os.path.isdir(dir):
+ os.makedirs(dir)
+ try: os.unlink(dst)
+ except: pass
+ open(dst, 'wb').write( open(src, 'rb').read() )
+
+if update_only:
+ sys.exit(0)
+
+args = [
+ os.path.split(sys.executable)[1],
+ os.path.join(bootstrap_dir, scons_py)
+ ] + pass_through_args
sys.stdout.write(string.join(args, " ") + '\n')
sys.stdout.flush()
-os.environ['SCONS_LIB_DIR'] = os.path.join(subdir, src_engine)
+os.environ['SCONS_LIB_DIR'] = os.path.join(bootstrap_dir, src_engine)
os.execve(sys.executable, args, os.environ)
.\" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
.\" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.\"
-.\" doc/man/scons-time.1 0.96.C629 2006/11/18 11:50:43 knight
+.\" __FILE__ __REVISION__ __DATE__ __DEVELOPER__
.\"
.\" ES - Example Start - indents and turns off line fill
.de ES
[\fB--which=\fIWHICH\fR]
[\fIARGUMENTS\fR]
..
-.TH SCONS-TIME 1 "November 2006"
+.TH SCONS-TIME 1 "__MONTH_YEAR__"
.SH NAME
scons-time \- generate and display SCons timing information
'\"==========================================================================
.fi
.RE
..
-.TH SCONS 1 "December 2006"
+.TH SCONS 1 "__MONTH_YEAR__"
.SH NAME
scons \- a software construction tool
.SH SYNOPSIS
.ES
$ scons --debug=presub
Building myprog.o with action(s):
- $SHCC $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
+ $SHCC $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
...
.EE
-mno-cygwin CCFLAGS, LINKFLAGS
-mwindows LINKFLAGS
-pthread CCFLAGS, LINKFLAGS
+-std= CFLAGS
-Wa, ASFLAGS, CCFLAGS
-Wl,-rpath= RPATH
-Wl,-R, RPATH
.RE
.fi
..
-.TH SCONSIGN 1 "August 2004"
+.TH SCONSIGN 1 "__MONTH_YEAR__"
.SH NAME
sconsign \- print SCons .sconsign file information
.SH SYNOPSIS
<blockquote>
<para>
- SCons User's Guide Copyright (c) 2004 Steven Knight
+ SCons User's Guide Copyright (c) 2004, 2005, 2006, 2007 Steven Knight
</para>
</blockquote>
<blockquote>
<para>
- SCons User's Guide Copyright (c) 2004 Steven Knight
+ SCons User's Guide Copyright (c) 2004, 2005, 2006, 2007 Steven Knight
</para>
</blockquote>
<edition>Revision &buildrevision; (&builddate;)</edition>
- <pubdate>2004</pubdate>
+ <pubdate>2004, 2005, 2006, 2007</pubdate>
<copyright>
- <year>2004</year>
+ <year>2004, 2005, 2006, 2007</year>
<holder>Steven Knight</holder>
</copyright>
<edition>Revision &buildrevision; (&builddate;)</edition>
- <pubdate>2004</pubdate>
+ <pubdate>2004, 2005, 2006, 2007</pubdate>
<copyright>
- <year>2004</year>
+ <year>2004, 2005, 2006, 2007</year>
<holder>Steven Knight</holder>
</copyright>
import os.path
program_list = Program('hello.c')
program_name = str(program_list[0])
- if not os.path.exists(program_name)
+ if not os.path.exists(program_name):
print program_name, "does not exist!"
</file>
<file name="hello.c">
import os.path
program_list = Program('hello.c')
program_name = str(program_list[0])
- if not os.path.exists(program_name)
+ if not os.path.exists(program_name):
print program_name, "does not exist!"
</programlisting>
- Allow arbitrary white space after a SWIG %module declaration.
+ From Paul:
+
+ - When compiling resources under MinGW, make sure there's a space
+ between the --include-dir option and its argument.
+
From Jay Kint:
- Alleviate long command line issues on Windows by executing command
files control over what exceptions cause a string to expand to ''
vs. terminating processing with an error.
+ - Allow the f90.py and f95.py Tool modules to compile earlier source
+ source files of earlier Fortran version.
+
+ - Fix storing signatures of files retrieved from CacheDir() so they're
+ correctly identified as up-to-date next invocation.
+
+ - Make sure lists of computed source suffixes cached by Builder objects
+ don't persist across changes to the list of source Builders (so the
+ addition of suffixes like .ui by the qt.py Tool module take effect).
+
+ - Enhance the bootstrap.py script to allow it to be used to execute
+ SCons more easily from a checked-out source tree.
+
From Ben Leslie:
- Fix post-Memoizer value caching misspellings in Node.FS._doLookup().
- Eliminate some unnecessary os.path.normpath() calls.
+ - Add a $CFLAGS variable for C-specific options, leaving $CCFLAGS
+ for options common to C and C++.
+
From Tom Parker:
- Have the error message print the missing file that Qt can't find.
specified on the command line (and not intuited from the old way of
calling it with just ".sconsign").
+ From Jose Pablo Ezequiel "Pupeno" Fernandez Silva:
+
+ - Give the 'lex' tool knowledge of the additional target files produced
+ by the flex "--header-file=" and "--tables-file=" options.
+
+ - Give the 'yacc' tool knowledge of the additional target files produced
+ by the bison "-g", "--defines=" and "--graph=" options.
+
+ - Generate intermediate files with Objective C file suffixes (.m) when
+ the lex and yacc source files have appropriate suffixes (.lm and .ym).
+
From Sohail Somain:
- Have the mslink.py Tool only look for a 'link' executable on Windows
dive any deeper into this subsystem.
The base class here is BuilderBase. This is a concrete base class which
-does, in fact, represent most Builder objects that we (or users) create.
+does, in fact, represent the Builder objects that we (or users) create.
-There is (at present) one subclasses:
-
- MultiStepBuilder
-
- This is a Builder that knows how to "chain" Builders so that
- users can specify a source file that requires multiple steps
- to turn into a target file. A canonical example is building a
- program from yacc input file, which requires invoking a builder
- to turn the .y into a .c, the .c into a .o, and the .o into an
- executable program.
-
-There is also two proxies that look like Builders:
+There is also a proxy that looks like a Builder:
CompositeBuilder
(compilers, compile options) for different flavors of source
files.
- ListBuilder
-
- This proxies for a Builder *invocation* where the target
- is a list of files, not a single file.
-
Builders and their proxies have the following public interface methods
used by other modules:
"""A class for warning about keyword arguments that we use as
overrides in a Builder call.
- This class exists to handle the fact that a single MultiStepBuilder
- call can actually invoke multiple builders as a result of a single
- user-level Builder call. This class only emits the warnings once,
- no matter how many Builders are invoked.
+ This class exists to handle the fact that a single Builder call
+ can actually invoke multiple builders. This class only emits the
+ warnings once, no matter how many Builders are invoked.
"""
def __init__(self, dict):
UserDict.UserDict.__init__(self, dict)
if self.already_warned:
return
for k in self.keys():
- try:
+ if misleading_keywords.has_key(k):
alt = misleading_keywords[k]
- except KeyError:
- pass
- else:
- SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning,
- "Did you mean to use `%s' instead of `%s'?" % (alt, k))
+ msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
+ SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
self.already_warned = 1
def Builder(**kw):
elif SCons.Util.is_List(emitter):
kw['emitter'] = ListEmitter(emitter)
- if kw.has_key('src_builder'):
- ret = apply(MultiStepBuilder, (), kw)
- else:
- ret = apply(BuilderBase, (), kw)
+ result = apply(BuilderBase, (), kw)
if not composite is None:
- ret = CompositeBuilder(ret, composite)
+ result = CompositeBuilder(result, composite)
- return ret
+ return result
def _node_errors(builder, env, tlist, slist):
"""Validate that the lists of target and source nodes are
# were specified.
for t in tlist:
if t.side_effect:
- raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
+ raise UserError, "Multiple ways to build the same target were specified for: %s" % t
if t.has_explicit_builder():
if not t.env is None and not t.env is env:
action = t.builder.action
contents = action.get_contents(tlist, slist, env)
if t_contents == contents:
- SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning,
- "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s"%(str(t), action.genstring(tlist, slist, t.env)))
-
+ msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
+ SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
else:
- raise UserError, "Two environments with different actions were specified for the same target: %s"%str(t)
-
+ msg = "Two environments with different actions were specified for the same target: %s" % t
+ raise UserError, msg
if builder.multi:
if t.builder != builder:
- if isinstance(t.builder, ListBuilder) and isinstance(builder, ListBuilder) and t.builder.builder == builder.builder:
- raise UserError, "Two different target sets have a target in common: %s"%str(t)
- else:
- raise UserError, "Two different builders (%s and %s) were specified for the same target: %s"%(t.builder.get_name(env), builder.get_name(env), str(t))
- elif isinstance(t.builder, ListBuilder) ^ isinstance(builder, ListBuilder):
- raise UserError, "Cannot build same target `%s' as singular and list"%str(t)
+ msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
+ raise UserError, msg
+ if t.get_executor().targets != tlist:
+ msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, map(str, t.get_executor().targets), map(str, tlist))
+ raise UserError, msg
elif t.sources != slist:
- raise UserError, "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (str(t), map(str,t.sources), map(str,slist))
+ msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, map(str, t.sources), map(str, slist))
+ raise UserError, msg
if builder.single_source:
if len(slist) > 1:
name = None,
chdir = _null,
is_explicit = 1,
+ src_builder = [],
**overrides):
if __debug__: logInstanceCreation(self, 'Builder.BuilderBase')
self._memo = {}
self.executor_kw['chdir'] = chdir
self.is_explicit = is_explicit
+ if not SCons.Util.is_List(src_builder):
+ src_builder = [ src_builder ]
+ self.src_builder = src_builder
+
def __nonzero__(self):
raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead"
def _execute(self, env, target, source, overwarn={}, executor_kw={}):
# We now assume that target and source are lists or None.
+ if self.src_builder:
+ source = self.src_builder_sources(env, source, overwarn)
+
if self.single_source and len(source) > 1 and target is None:
result = []
if target is None: target = [None]*len(source)
tlist, slist = self._create_nodes(env, target, source)
- if len(tlist) == 1:
- builder = self
- else:
- builder = ListBuilder(self, env, tlist)
-
# Check for errors with the specified target/source lists.
- _node_errors(builder, env, tlist, slist)
+ _node_errors(self, env, tlist, slist)
# The targets are fine, so find or make the appropriate Executor to
# build this particular list of targets from this particular list of
# sources.
- if builder.multi:
- get_executor = builder.get_multi_executor
+ if self.multi:
+ get_executor = self.get_multi_executor
else:
- get_executor = builder.get_single_executor
+ get_executor = self.get_single_executor
executor = get_executor(env, tlist, slist, executor_kw)
# Now set up the relevant information in the target Nodes themselves.
for t in tlist:
t.cwd = env.fs.getcwd()
- t.builder_set(builder)
+ t.builder_set(self)
t.env_set(env)
t.add_source(slist)
t.set_executor(executor)
- t.set_explicit(builder.is_explicit)
+ t.set_explicit(self.is_explicit)
return SCons.Node.NodeList(tlist)
suffix = suffix(env, sources)
return env.subst(suffix)
- def _src_suffixes_key(self, env):
- return id(env)
-
- memoizer_counters.append(SCons.Memoize.CountDict('src_suffixes', _src_suffixes_key))
-
- def src_suffixes(self, env):
- """
- Returns the list of source suffixes for this Builder.
-
- The suffix list may contain construction variable expansions,
- so we have to evaluate the individual strings. To avoid doing
- this over and over, we memoize the results for each construction
- environment.
- """
- memo_key = id(env)
- try:
- memo_dict = self._memo['src_suffixes']
- except KeyError:
- memo_dict = {}
- self._memo['src_suffixes'] = memo_dict
- else:
- try:
- return memo_dict[memo_key]
- except KeyError:
- pass
- result = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
- memo_dict[memo_key] = result
- return result
-
def set_src_suffix(self, src_suffix):
if not src_suffix:
src_suffix = []
"""
self.emitter[suffix] = emitter
-
-
-class ListBuilder(SCons.Util.Proxy):
- """A Proxy to support building an array of targets (for example,
- foo.o and foo.h from foo.y) from a single Action execution.
- """
-
- def __init__(self, builder, env, tlist):
- if __debug__: logInstanceCreation(self, 'Builder.ListBuilder')
- SCons.Util.Proxy.__init__(self, builder)
- self.builder = builder
- self.target_scanner = builder.target_scanner
- self.source_scanner = builder.source_scanner
- self.env = env
- self.tlist = tlist
- self.multi = builder.multi
- self.single_source = builder.single_source
-
- def targets(self, node):
- """Return the list of targets for this builder instance.
+ def add_src_builder(self, builder):
"""
- return self.tlist
-
- def get_name(self, env):
- """Attempts to get the name of the Builder."""
-
- return "ListBuilder(%s)" % self.builder.get_name(env)
-
-class MultiStepBuilder(BuilderBase):
- """This is a builder subclass that can build targets in
- multiple steps. The src_builder parameter to the constructor
- accepts a builder that is called to build sources supplied to
- this builder. The targets of that first build then become
- the sources of this builder.
-
- If this builder has a src_suffix supplied, then the src_builder
- builder is NOT invoked if the suffix of a source file matches
- src_suffix.
- """
-
- memoizer_counters = []
-
- def __init__(self, src_builder,
- action = None,
- prefix = '',
- suffix = '',
- src_suffix = '',
- target_factory = None,
- source_factory = None,
- target_scanner = None,
- source_scanner = None,
- emitter=None,
- single_source=0):
- if __debug__: logInstanceCreation(self, 'Builder.MultiStepBuilder')
- BuilderBase.__init__(self, action, prefix, suffix, src_suffix,
- target_factory, source_factory,
- target_scanner, source_scanner, emitter,
- single_source = single_source)
- if not SCons.Util.is_List(src_builder):
- src_builder = [ src_builder ]
- self.src_builder = src_builder
-
- def _get_sdict_key(self, env):
- return id(env)
+ Add a new Builder to the list of src_builders.
- memoizer_counters.append(SCons.Memoize.CountDict('_get_sdict', _get_sdict_key))
+ This requires wiping out cached values so that the computed
+ lists of source suffixes get re-calculated.
+ """
+ self._memo = {}
+ self.src_builder.append(builder)
def _get_sdict(self, env):
"""
This dictionary is used for each target specified, so we save a
lot of extra computation by memoizing it for each construction
environment.
+
+ Note that this is re-computed each time, not cached, because there
+ might be changes to one of our source Builders (or one of their
+ source Builders, and so on, and so on...) that we can't "see."
+
+ The underlying methods we call cache their computed values,
+ though, so we hope repeatedly aggregating them into a dictionary
+ like this won't be too big a hit. We may need to look for a
+ better way to do this if performance data show this has turned
+ into a significant bottleneck.
"""
- memo_key = id(env)
- try:
- memo_dict = self._memo['_get_sdict']
- except KeyError:
- memo_dict = {}
- self._memo['_get_sdict'] = memo_dict
- else:
- try:
- return memo_dict[memo_key]
- except KeyError:
- pass
sdict = {}
- for bld in self.src_builder:
- if SCons.Util.is_String(bld):
- try:
- bld = env['BUILDERS'][bld]
- except KeyError:
- continue
+ for bld in self.get_src_builders(env):
for suf in bld.src_suffixes(env):
sdict[suf] = bld
- memo_dict[memo_key] = sdict
return sdict
- def _execute(self, env, target, source, overwarn={}, executor_kw={}):
- # We now assume that target and source are lists or None.
+ def src_builder_sources(self, env, source, overwarn={}):
source_factory = env.get_factory(self.source_factory)
slist = env.arg2nodes(source, source_factory)
- final_sources = []
sdict = self._get_sdict(env)
return suf
return None
+ result = []
+
for snode in slist:
match_suffix = match_src_suffix(snode)
if match_suffix:
try:
bld = sdict[match_suffix]
except KeyError:
- final_sources.append(snode)
+ result.append(snode)
else:
tlist = bld._execute(env, None, [snode], overwarn)
# If the subsidiary Builder returned more than one
# Builder isn't capable of building.
if len(tlist) > 1:
tlist = filter(match_src_suffix, tlist)
- final_sources.extend(tlist)
+ result.extend(tlist)
else:
- final_sources.append(snode)
+ result.append(snode)
- return BuilderBase._execute(self, env, target, final_sources, overwarn)
+ return result
+
+ def _get_src_builders_key(self, env):
+ return id(env)
+
+ memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key))
def get_src_builders(self, env):
- """Return all the src_builders for this Builder.
+ """
+ Returns the list of source Builders for this Builder.
- This is essentially a recursive descent of the src_builder "tree."
+ This exists mainly to look up Builders referenced as
+ strings in the 'BUILDER' variable of the construction
+ environment and cache the result.
"""
- ret = []
+ memo_key = id(env)
+ try:
+ memo_dict = self._memo['get_src_builders']
+ except KeyError:
+ memo_dict = {}
+ self._memo['get_src_builders'] = memo_dict
+ else:
+ try:
+ return memo_dict[memo_key]
+ except KeyError:
+ pass
+
+ builders = []
for bld in self.src_builder:
if SCons.Util.is_String(bld):
- # All Environments should have a BUILDERS
- # variable, so no need to check for it.
try:
bld = env['BUILDERS'][bld]
except KeyError:
continue
- ret.append(bld)
- return ret
+ builders.append(bld)
+
+ memo_dict[memo_key] = builders
+ return builders
- def _src_suffixes_key(self, env):
+ def _subst_src_suffixes_key(self, env):
return id(env)
- memoizer_counters.append(SCons.Memoize.CountDict('src_suffixes', _src_suffixes_key))
+ memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key))
- def src_suffixes(self, env):
+ def subst_src_suffixes(self, env):
"""
- Returns the list of source suffixes for all src_builders of this
- Builder.
-
The suffix list may contain construction variable expansions,
so we have to evaluate the individual strings. To avoid doing
this over and over, we memoize the results for each construction
"""
memo_key = id(env)
try:
- memo_dict = self._memo['src_suffixes']
+ memo_dict = self._memo['subst_src_suffixes']
except KeyError:
memo_dict = {}
- self._memo['src_suffixes'] = memo_dict
+ self._memo['subst_src_suffixes'] = memo_dict
else:
try:
return memo_dict[memo_key]
except KeyError:
pass
- suffixes = BuilderBase.src_suffixes(self, env)
+ suffixes = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
+ memo_dict[memo_key] = suffixes
+ return suffixes
+
+ def src_suffixes(self, env):
+ """
+ Returns the list of source suffixes for all src_builders of this
+ Builder.
+
+ This is essentially a recursive descent of the src_builder "tree."
+ (This value isn't cached because there may be changes in a
+ src_builder many levels deep that we can't see.)
+ """
+ suffixes = self.subst_src_suffixes(env)
for builder in self.get_src_builders(env):
suffixes.extend(builder.src_suffixes(env))
- memo_dict[memo_key] = suffixes
return suffixes
class CompositeBuilder(SCons.Util.Proxy):
class MyAction:
def __init__(self, action):
self.action = action
+ def __call__(self, *args, **kw):
+ pass
def get_executor(self, env, overrides, tlist, slist, executor_kw):
return ['executor'] + [self.action]
assert 0
- def test_ListBuilder(self):
- """Testing ListBuilder class."""
+ def test_lists(self):
+ """Testing handling lists of targets and source"""
def function2(target, source, env, tlist = [outfile, outfile2], **kw):
for t in target:
open(str(t), 'w').write("function2\n")
assert os.path.exists(test.workpath('sub1'))
assert os.path.exists(test.workpath('sub2'))
- def test_MultiStepBuilder(self):
- """Testing MultiStepBuilder class."""
+ def test_src_builder(self):
+ """Testing Builders with src_builder"""
+ # These used to be MultiStepBuilder objects until we
+ # eliminated it as a separate class
env = Environment()
builder1 = SCons.Builder.Builder(action='foo',
src_suffix='.bar',
suffix='.foo')
- builder2 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
- src_builder = builder1,
- src_suffix = '.foo')
+ builder2 = SCons.Builder.Builder(action=MyAction('act'),
+ src_builder = builder1,
+ src_suffix = '.foo')
tgt = builder2(env, source=[])
assert tgt == [], tgt
s = map(str, tgt.sources[0].sources)
assert s == ['aaa.bar'], s
- builder3 = SCons.Builder.MultiStepBuilder(action = 'foo',
- src_builder = 'xyzzy',
- src_suffix = '.xyzzy')
+ builder3 = SCons.Builder.Builder(action = 'foo',
+ src_builder = 'xyzzy',
+ src_suffix = '.xyzzy')
assert builder3.get_src_builders(Environment()) == []
builder4 = SCons.Builder.Builder(action='bld4',
src_suffix='.i',
suffix='_wrap.c')
- builder5 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
- src_builder=builder4,
- suffix='.obj',
- src_suffix='.c')
- builder6 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
- src_builder=builder5,
- suffix='.exe',
- src_suffix='.obj')
+ builder5 = SCons.Builder.Builder(action=MyAction('act'),
+ src_builder=builder4,
+ suffix='.obj',
+ src_suffix='.c')
+ builder6 = SCons.Builder.Builder(action=MyAction('act'),
+ src_builder=builder5,
+ suffix='.exe',
+ src_suffix='.obj')
tgt = builder6(env, 'test', 'test.i')[0]
s = str(tgt)
assert s == 'test.exe', s
b1 = SCons.Builder.Builder(action='foo', suffix='.o')
b2 = SCons.Builder.Builder(action='foo', suffix='.c')
- b3 = SCons.Builder.MultiStepBuilder(action='bar',
- src_suffix = '.foo',
- src_builder = b1)
+ b3 = SCons.Builder.Builder(action='bar', src_suffix = '.foo',
+ src_builder = b1)
b4 = SCons.Builder.Builder(action={})
b5 = SCons.Builder.Builder(action='foo', name='builder5')
b6 = SCons.Builder.Builder(action='foo')
for B in b3.get_src_builders(env2):
assert B.get_name(env2) == 'B1'
- tgts = b1(env, target = [outfile, outfile2], source='moo')
- for t in tgts:
- name = t.builder.get_name(env)
- assert name == 'ListBuilder(bldr1)', name
- # The following are not symbolically correct, because the
- # ListBuilder was only created on behalf of env, so it
- # would probably be OK if better correctness
- # env-to-builder mappings caused this to fail in the
- # future.
- assert t.builder.get_name(env2) == 'ListBuilder(B1)'
-
tgt = b4(env, target = 'moo', source='cow')
assert tgt[0].builder.get_name(env) == 'bldr4'
assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
tgt = builder(env, target='t2', source='t2a.foo t2b.ina')[0]
- assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder), tgt.builder.__dict__
+ assert isinstance(tgt.builder, SCons.Builder.BuilderBase), tgt.builder.__dict__
bar_bld = SCons.Builder.Builder(action = 'a-bar',
src_suffix = '.inb',
builder.add_action('.bar', 'bar')
tgt = builder(env, target='t3-foo', source='t3a.foo t3b.ina')[0]
- assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
+ assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
tgt = builder(env, target='t3-bar', source='t3a.bar t3b.inb')[0]
- assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
+ assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
flag = 0
tgt = builder(env, target='t5', source=['test5a.foo', 'test5b.inb'])[0]
import SCons.Platform
import SCons.SConsign
import SCons.Sig
-import SCons.Sig.MD5
import SCons.Sig.TimeStamp
import SCons.Subst
import SCons.Tool
"""
dict = {
'ASFLAGS' : [],
+ 'CFLAGS' : [],
'CCFLAGS' : [],
'CPPDEFINES' : [],
'CPPFLAGS' : [],
elif arg == '-pthread':
dict['CCFLAGS'].append(arg)
dict['LINKFLAGS'].append(arg)
+ elif arg[:5] == '-std=':
+ dict['CFLAGS'].append(arg) # C only
elif arg[0] == '+':
dict['CCFLAGS'].append(arg)
dict['LINKFLAGS'].append(arg)
def SourceSignatures(self, type):
type = self.subst(type)
if type == 'MD5':
- import SCons.Sig.MD5
- self._calc_module = SCons.Sig.MD5
+ try:
+ import SCons.Sig.MD5
+ except ImportError:
+ msg = "No MD5 module available, using time stamps"
+ SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
+ import SCons.Sig.TimeStamp
+ self._calc_module = SCons.Sig.TimeStamp
+ else:
+ self._calc_module = SCons.Sig.MD5
elif type == 'timestamp':
import SCons.Sig.TimeStamp
self._calc_module = SCons.Sig.TimeStamp
empty = {
'ASFLAGS' : [],
+ 'CFLAGS' : [],
'CCFLAGS' : [],
'CPPDEFINES' : [],
'CPPFLAGS' : [],
"-Wl,-R,rpath2 " + \
"-Wl,-Rrpath3 " + \
"-Wp,-cpp " + \
+ "-std=c99 " + \
"-framework Carbon " + \
"-frameworkdir=fwd1 " + \
"-Ffwd2 " + \
d = env.ParseFlags(s)
assert d['ASFLAGS'] == ['-as'], d['ASFLAGS']
+ assert d['CFLAGS'] == ['-std=c99']
assert d['CCFLAGS'] == ['-X', '-Wa,-as',
'-pthread', '-mno-cygwin',
('-arch', 'i386'), ('-isysroot', '/tmp'),
from SCons.Debug import logInstanceCreation
import SCons.Errors
import SCons.Node
-import SCons.Sig.MD5
import SCons.Subst
import SCons.Util
import SCons.Warnings
def diskcheck_match(self):
pass
- def disambiguate(self):
+ def disambiguate(self, must_exist=None):
"""
"""
if self.isdir():
self.srcnode().isdir():
self.__class__ = Dir
self._morph()
+ elif must_exist:
+ msg = "No such file or directory: '%s'" % self.abspath
+ raise SCons.Errors.UserError, msg
else:
self.__class__ = File
self._morph()
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 self.isfile():
- self.__class__ = File
- self._morph()
- return self.get_contents()
- if self.isdir():
- self.__class__ = Dir
- self._morph()
+ try:
+ self = self.disambiguate(must_exist=1)
+ except SCons.Errors.UserError, e:
+ # There was nothing on disk with which to disambiguate
+ # this entry. Leave it as an Entry, but return a null
+ # string so calls to get_contents() in emitters and the
+ # like (e.g. in qt.py) don't have to disambiguate by hand
+ # or catch the exception.
+ return ''
+ else:
return self.get_contents()
- if self.islink():
- return '' # avoid errors for dangling symlinks
- msg = "No such file or directory: '%s'" % self.abspath
- raise SCons.Errors.UserError, msg
def must_be_a_Dir(self):
"""Called to make sure a Node is a Dir. Since we're an
self.CacheDebug = self.CacheDebugWrite
def CacheDir(self, path):
- self.CachePath = path
+ try:
+ import SCons.Sig.MD5
+ except ImportError:
+ msg = "No MD5 module available, CacheDir() not supported"
+ SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
+ else:
+ self.CachePath = path
def build_dir_target_climb(self, orig, dir, tail):
"""Create targets in corresponding build directories
b = self.is_derived()
if not b and not self.has_src_builder():
return None
+
+ retrieved = None
if b and self.fs.CachePath:
if self.fs.cache_show:
if CacheRetrieveSilent(self, [], None, execute=1) == 0:
self.build(presub=0, execute=0)
- self.set_state(SCons.Node.executed)
- return 1
- elif CacheRetrieve(self, [], None, execute=1) == 0:
+ retrieved = 1
+ else:
+ if CacheRetrieve(self, [], None, execute=1) == 0:
+ retrieved = 1
+ if retrieved:
+ # Record build signature information, but don't
+ # push it out to cache. (We just got it from there!)
self.set_state(SCons.Node.executed)
- return 1
- return None
+ SCons.Node.Node.built(self)
+
+ return retrieved
def built(self):
return None, None
ninfo = self.get_binfo().ninfo
if not hasattr(ninfo, 'bsig'):
+ import SCons.Errors
raise SCons.Errors.InternalError, "cachepath(%s) found no bsig" % self.path
elif ninfo.bsig is None:
+ import SCons.Errors
raise SCons.Errors.InternalError, "cachepath(%s) found a bsig of None" % self.path
# Add the path to the cache signature, because multiple
# targets built by the same action will all have the same
# build signature, and we have to differentiate them somehow.
+ import SCons.Sig.MD5
cache_sig = SCons.Sig.MD5.collect([ninfo.bsig, self.path])
subdir = string.upper(cache_sig[0])
dir = os.path.join(self.fs.CachePath, subdir)
# test Entry.get_contents()
e = fs.Entry('does_not_exist')
- exc_caught = 0
- try:
- e.get_contents()
- except SCons.Errors.UserError:
- exc_caught = 1
- assert exc_caught, "Should have caught an IOError"
+ c = e.get_contents()
+ assert c == "", c
+ assert e.__class__ == SCons.Node.FS.Entry
test.write("file", "file\n")
try:
os.symlink('nonexistent', test.workpath('dangling_symlink'))
e = fs.Entry('dangling_symlink')
c = e.get_contents()
- assert e.__class__ == SCons.Node.FS.Entry
+ assert e.__class__ == SCons.Node.FS.Entry, e.__class__
assert c == "", c
test.write("tstamp", "tstamp\n")
assert e3f.__class__ is SCons.Node.FS.File, e3f.__class__
e3n = fs.Entry('e3n')
- exc_caught = None
- try:
- e3n.get_contents()
- except SCons.Errors.UserError:
- exc_caught = 1
- assert exc_caught, "did not catch expected SCons.Errors.UserError"
+ e3n.get_contents()
+ assert e3n.__class__ is SCons.Node.FS.Entry, e3n.__class__
test.subdir('e4d')
test.write('e4f', "e4f\n")
# what line in what file created the node, for example).
Annotate(self)
- def disambiguate(self):
+ def disambiguate(self, must_exist=None):
return self
def get_suffix(self):
pass
def calc_signature(self, calc):
pass
+ def get_executor(self):
+ class Executor:
+ pass
+ e = Executor()
+ e.targets = [self]
+ return e
return [MyNode('n1'), MyNode('n2')]
try:
self.scons_env.Append(BUILDERS = {'SConfActionBuilder' : MyBuilder()})
SCons.Warnings.DeprecatedWarning,
SCons.Warnings.DuplicateEnvironmentWarning,
SCons.Warnings.MissingSConscriptWarning,
+ SCons.Warnings.NoMD5ModuleWarning,
SCons.Warnings.NoMetaclassSupportWarning,
SCons.Warnings.NoParallelSupportWarning,
SCons.Warnings.MisleadingKeywordsWarning, ]
if node is None:
return None
- try:
- tlist = node.builder.targets(node)
- except AttributeError:
- tlist = [node]
+ tlist = node.get_executor().targets
task = self.tasker(self, tlist, node is self.current_top, node)
try:
pass
def executed(self, node):
- try:
- tlist = node.builder.targets(node)
- except AttributeError:
- tlist = [node]
+ pass
def exception_raise(self, exception):
exc = exception[:]
def postprocess(self):
self.postprocessed = 1
+ def get_executor(self):
+ class Executor:
+ pass
+ e = Executor()
+ e.targets = self.targets
+ return e
+
class OtherError(Exception):
pass
env['CC'] = 'bcc32'
env['CCFLAGS'] = SCons.Util.CLVar('')
- env['CCCOM'] = '$CC -q $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
+ env['CFLAGS'] = SCons.Util.CLVar('')
+ env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
- env['SHCCCOM'] = '$SHCC -WD $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
+ env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
+ env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CPPDEFSUFFIX'] = ''
env['INCPREFIX'] = '-I'
env['CC'] = 'cc'
env['CCFLAGS'] = SCons.Util.CLVar('')
- env['CCCOM'] = '$CC -o $TARGET -c $CCFLAGS $_CCCOMCOM $SOURCES'
+ env['CFLAGS'] = SCons.Util.CLVar('')
+ env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
- env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCCFLAGS $_CCCOMCOM $SOURCES'
+ env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
+ env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CPPDEFSUFFIX'] = ''
<cvar name="CCCOM">
<summary>
-The command line used to compile a C source file to a (static) object file.
-Any options specified in the &cv-CCFLAGS; and &cv-CPPFLAGS; construction variables
-are included on this command line.
+The command line used to compile a C source file to a (static) object
+file. Any options specified in the &cv-CFLAGS;, &cv-CCFLAGS; and
+&cv-CPPFLAGS; construction variables are included on this command
+line.
</summary>
</cvar>
<cvar name="CCFLAGS">
<summary>
-General options that are passed to the C compiler.
+General options that are passed to the C and C++ compilers.
+</summary>
+</cvar>
+
+<cvar name="CFLAGS">
+<summary>
+General options that are passed to the C compiler (C only; not C++).
</summary>
</cvar>
<summary>
The command line used to compile a C source file
to a shared-library object file.
-Any options specified in the &cv-SHCCFLAGS; and &cv-CPPFLAGS; construction variables
+Any options specified in the &cv-SHCFLAGS;, &cv-SHCCFLAGS; and &cv-CPPFLAGS; construction variables
are included on this command line.
</summary>
</cvar>
<cvar name="SHCCFLAGS">
<summary>
-Options that are passed to the C compiler
+Options that are passed to the C and C++ compilers
+to generate shared-library objects.
+</summary>
+</cvar>
+
+<cvar name="SHCFLAGS">
+<summary>
+Options that are passed to the C compiler (only; not C++)
to generate shared-library objects.
</summary>
</cvar>
def generate(env):
fortran.add_to_env(env)
+
+ import f77
+ f77.add_to_env(env)
+
add_to_env(env)
env['_FORTRAND'] = env.Detect(compilers) or 'f90'
def generate(env):
fortran.add_to_env(env)
+
+ import f77
+ f77.add_to_env(env)
+
+ import f90
+ f90.add_to_env(env)
+
add_to_env(env)
env['_FORTRAND'] = env.Detect(compilers) or 'f95'
cc.generate(env)
env['CC'] = 'icc'
- env['CCCOM'] = '$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
+ env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
env['CPPDEFPREFIX'] = '/D'
env['CPPDEFSUFFIX'] = ''
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os.path
+
+import string
+
import SCons.Action
import SCons.Tool
import SCons.Util
LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR")
+def lexEmitter(target, source, env):
+ sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0]))
+
+ if sourceExt == ".lm": # If using Objective-C
+ target = [sourceBase + ".m"] # the extension is ".m".
+
+ # This emitter essentially tries to add to the target all extra
+ # files generated by flex.
+
+ # Different options that are used to trigger the creation of extra files.
+ fileGenOptions = ["--header-file=", "--tables-file="]
+
+ for option in SCons.Util.CLVar(env.subst("$LEXFLAGS")):
+ for fileGenOption in fileGenOptions:
+ l = len(fileGenOption)
+ if option[:l] == fileGenOption:
+ # A file generating option is present, so add the
+ # file name to the target list.
+ fileName = string.strip(option[l:])
+ target.append(fileName)
+ return (target, source)
+
def generate(env):
"""Add Builders and construction variables for lex to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
- c_file.add_action('.l', LexAction)
- c_file.add_action('.lex', LexAction)
- cxx_file.add_action('.ll', LexAction)
+ # C
+ c_file.add_action(".l", LexAction)
+ c_file.add_emitter(".l", lexEmitter)
+
+ c_file.add_action(".lex", LexAction)
+ c_file.add_emitter(".lex", lexEmitter)
+
+ # Objective-C
+ cxx_file.add_action(".lm", LexAction)
+ cxx_file.add_emitter(".lm", lexEmitter)
+
+ # C++
+ cxx_file.add_action(".ll", LexAction)
+ cxx_file.add_emitter(".ll", lexEmitter)
+
+ env["LEX"] = env.Detect("flex") or "lex"
+ env["LEXFLAGS"] = SCons.Util.CLVar("")
+ env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
- env['LEX'] = env.Detect('flex') or 'lex'
- env['LEXFLAGS'] = SCons.Util.CLVar('')
- env['LEXCOM'] = '$LEX $LEXFLAGS -t $SOURCES > $TARGET'
-
def exists(env):
- return env.Detect(['flex', 'lex'])
+ return env.Detect(["flex", "lex"])
env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['RCINCPREFIX'] = '--include-dir '
env['RCINCSUFFIX'] = ''
- env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX}${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
+ env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
env['BUILDERS']['RES'] = res_builder
# Some setting from the platform also have to be overridden:
env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
env['CC'] = 'cl'
env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
- env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
+ env['CFLAGS'] = SCons.Util.CLVar('')
+ env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CCCOMFLAGS'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
- env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
+ env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
+ env['SHCCCOM'] = '$SHCC $SHCFLAGS $SHCCFLAGS $CCCOMFLAGS'
env['CXX'] = '$CC'
env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS $( /TP $)')
env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -nolink -o $TARGET $SOURCES'
env['CC'] = 'mwcc'
- env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
+ env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CCCOMFLAGS'
env['CXX'] = 'mwcc'
env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = '$CCFLAGS'
- env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
+ env['SHCFLAGS'] = '$CFLAGS'
+ env['SHCCCOM'] = '$SHCC $SHCFLAGS $SHCCFLAGS $CCCOMFLAGS'
env['SHCXX'] = '$CXX'
env['SHCXXFLAGS'] = '$CXXFLAGS'
env['BUILDERS']['Uic'] = uicBld
env['BUILDERS']['Moc'] = mocBld
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
- static_obj.src_builder.append('Uic')
- shared_obj.src_builder.append('Uic')
+ static_obj.add_src_builder('Uic')
+ shared_obj.add_src_builder('Uic')
# We use the emitters of Program / StaticLibrary / SharedLibrary
# to scan for moc'able files
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os.path
+import string
import SCons.Defaults
import SCons.Tool
YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR")
def _yaccEmitter(target, source, env, ysuf, hsuf):
+ flags = SCons.Util.CLVar(env.subst("$YACCFLAGS"))
+ targetBase, targetExt = os.path.splitext(SCons.Util.to_String(target[0]))
+
+ if '.ym' in ysuf: # If using Objective-C
+ target = [targetBase + ".m"] # the extension is ".m".
+
+
# If -d is specified on the command line, yacc will emit a .h
- # or .hpp file as well as a .c or .cpp file, depending on whether
- # the input file is a .y or .yy, respectively.
- if len(source) and '-d' in SCons.Util.CLVar(env.subst("$YACCFLAGS")):
+ # or .hpp file with the same name as the .c or .cpp output file.
+ if '-d' in flags:
+ target.append(targetBase + env.subst(hsuf))
+
+ # If -g is specified on the command line, yacc will emit a .vcg
+ # file with the same base name as the .y, .yacc, .ym or .yy file.
+ if "-g" in flags:
base, ext = os.path.splitext(SCons.Util.to_String(source[0]))
- if ext in ysuf:
- base, ext = os.path.splitext(SCons.Util.to_String(target[0]))
- target.append(base + env.subst(hsuf))
+ target.append(base + env.subst("$YACCVCGFILESUFFIX"))
+
+ # With --defines and --graph, the name of the file is totally defined
+ # in the options.
+ fileGenOptions = ["--defines=", "--graph="]
+ for option in flags:
+ for fileGenOption in fileGenOptions:
+ l = len(fileGenOption)
+ if option[:l] == fileGenOption:
+ # A file generating option is present, so add the file
+ # name to the list of targets.
+ fileName = string.strip(option[l:])
+ target.append(fileName)
+
return (target, source)
def yEmitter(target, source, env):
return _yaccEmitter(target, source, env, ['.y', '.yacc'], '$YACCHFILESUFFIX')
+def ymEmitter(target, source, env):
+ return _yaccEmitter(target, source, env, ['.ym'], '$YACCHFILESUFFIX')
+
def yyEmitter(target, source, env):
return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX')
def generate(env):
"""Add Builders and construction variables for yacc to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
-
+
+ # C
c_file.add_action('.y', YaccAction)
- c_file.add_action('.yacc', YaccAction)
- cxx_file.add_action('.yy', YaccAction)
c_file.add_emitter('.y', yEmitter)
+
+ c_file.add_action('.yacc', YaccAction)
c_file.add_emitter('.yacc', yEmitter)
+
+ # Objective-C
+ c_file.add_action('.ym', YaccAction)
+ c_file.add_emitter('.ym', ymEmitter)
+
+ # C++
+ cxx_file.add_action('.yy', YaccAction)
cxx_file.add_emitter('.yy', yyEmitter)
env['YACC'] = env.Detect('bison') or 'yacc'
env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES'
env['YACCHFILESUFFIX'] = '.h'
env['YACCHXXFILESUFFIX'] = '.hpp'
+ env['YACCVCGFILESUFFIX'] = '.vcg'
def exists(env):
return env.Detect(['bison', 'yacc'])
<filename>.hpp</filename>.
</summary>
</cvar>
+
+<cvar name="YACCVCGFILESUFFIX">
+<summary>
+The suffix of the file
+containing the VCG grammar automaton definition
+when the
+<option>--graph=</option>
+option is used.
+Note that setting this variable does not cause
+the parser generator to generate a VCG
+file with the specified suffix,
+it exists to allow you to specify
+what suffix the parser generator will use of its own accord.
+The default value is
+<filename>.vcg</filename>.
+</summary>
+</cvar>
class MissingSConscriptWarning(Warning):
pass
+class NoMD5ModuleWarning(Warning):
+ pass
+
class NoMetaclassSupportWarning(Warning):
pass
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
import getopt
import glob
import os
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Verify that we have proper Copyright notices on all the right files
-in our distributions.
+Verify that we have proper strings like Copyright notices on all the
+right files in our distributions.
-Note that this is a packaging test, not a functional test, so the
-name of this script doesn't end in *Tests.py.
+Note that this is a source file and packaging test, not a functional test,
+so the name of this script doesn't end in *Tests.py.
"""
+import fnmatch
import os
import os.path
import re
import string
+import TestCmd
import TestSCons
-test = TestSCons.TestSCons()
+# Use TestCmd, not TestSCons, so we don't chdir to a temporary directory.
+test = TestCmd.TestCmd()
-try:
- cwd = os.environ['SCONS_CWD']
-except KeyError:
- cwd = os.getcwd()
+scons_version = TestSCons.SConsVersion
def build_path(*args):
- return apply(os.path.join, (cwd, 'build',)+args)
+ return apply(os.path.join, ('build',)+args)
build_scons = build_path('scons')
-build_local = build_path('scons-local', 'scons-local-'+test.scons_version)
+build_local = build_path('scons-local', 'scons-local-'+scons_version)
build_src = build_path('scons-src')
-class Collect:
- expression = re.compile('Copyright.*The SCons Foundation')
- def __init__(self, directory, remove_list):
- self.copyright = []
- self.no_copyright = []
- self.remove = {}
+class Checker:
+ def __init__(self, directory, search_list = [], remove_list=[]):
+ self.directory = directory
+ self.search_list = search_list
+ self.remove_dict = {}
for r in remove_list:
- self.remove[os.path.join(directory, r)] = 1
-
-def visit(collect, dirname, names):
- make_path_tuple = lambda n, d=dirname: (n, os.path.join(d, n))
- for name, path in map(make_path_tuple, names):
- if collect.remove.get(path):
- names.remove(name)
- elif os.path.isfile(path):
- if collect.expression.search(open(path, 'r').read()):
- collect.copyright.append(path)
- else:
- collect.no_copyright.append(path)
-
-# Map each directory to search (dictionary keys) to a list of its
-# subsidiary files and directories to exclude from copyright checks.
-check = {
- build_scons : [
- 'build',
- 'build-stamp',
- 'configure-stamp',
- 'debian',
- 'dist',
- 'engine/SCons/Conftest.py',
- 'engine/SCons/dblite.py',
- 'engine/SCons/Optik',
- 'MANIFEST',
- 'os_spawnv_fix.diff',
- 'setup.cfg',
- ],
- build_local : [
- 'SCons/Conftest.py',
- 'SCons/dblite.py',
- 'SCons/Optik',
- ],
- build_src : [
- 'bin',
- 'config',
- 'debian',
- 'doc/design',
- 'doc/MANIFEST',
- 'doc/python10',
- 'doc/reference',
- 'doc/man/MANIFEST',
- 'doc/user/cons.pl',
- 'doc/user/MANIFEST',
- 'doc/user/SCons-win32-install-1.jpg',
- 'doc/user/SCons-win32-install-2.jpg',
- 'doc/user/SCons-win32-install-3.jpg',
- 'doc/user/SCons-win32-install-4.jpg',
- 'gentoo',
- 'QMTest/classes.qmc',
- 'QMTest/configuration',
- 'QMTest/TestCmd.py',
- 'QMTest/TestCommon.py',
- 'QMTest/unittest.py',
- 'src/os_spawnv_fix.diff',
- 'src/MANIFEST.in',
- 'src/setup.cfg',
- 'src/engine/MANIFEST.in',
- 'src/engine/MANIFEST-xml.in',
- 'src/engine/setup.cfg',
- 'src/engine/SCons/Conftest.py',
- 'src/engine/SCons/dblite.py',
- 'src/engine/SCons/Optik',
- 'src/script/MANIFEST.in',
- 'src/script/setup.cfg',
- ],
-}
-
-no_copyright = []
-no_result = []
-
-for directory, remove_list in check.items():
- if os.path.exists(directory):
- c = Collect(directory, remove_list)
- os.path.walk(directory, visit, c)
- no_copyright.extend(c.no_copyright)
- else:
- no_result.append(directory)
-
-if no_copyright:
- print "Found the following files with no copyrights:"
- print "\t" + string.join(no_copyright, "\n\t")
+ self.remove_dict[os.path.join(directory, r)] = 1
+
+ def directory_exists(self):
+ return os.path.exists(self.directory)
+
+ def remove_path(self, path):
+ return self.remove_dict.get(path)
+
+ def search_this(self, path):
+ if self.search_list:
+ for pattern in self.search_list:
+ if fnmatch.fnmatch(path, pattern):
+ return 1
+ return None
+ else:
+ return os.path.isfile(path)
+
+ def visit(self, result, dirname, names):
+ make_path_tuple = lambda n, d=dirname: (n, os.path.join(d, n))
+ for name, path in map(make_path_tuple, names):
+ if self.remove_path(path):
+ names.remove(name)
+ elif self.search_this(path):
+ body = open(path, 'r').read()
+ for expr in self.expressions:
+ if not expr.search(body):
+ msg = '%s: missing %s' % (path, repr(expr.pattern))
+ result.append(msg)
+
+ def find_missing(self):
+ result = []
+ os.path.walk(self.directory, self.visit, result)
+ return result
+
+class CheckUnexpandedStrings(Checker):
+ expressions = [
+ re.compile('__COPYRIGHT__'),
+ re.compile('__FILE__ __REVISION__ __DATE__ __DEVELOPER__'),
+ ]
+ def must_be_built(self):
+ return None
+
+class CheckExpandedCopyright(Checker):
+ expressions = [
+ re.compile('Copyright.*The SCons Foundation'),
+ ]
+ def must_be_built(self):
+ return 1
+
+check_list = [
+
+ CheckUnexpandedStrings(
+ 'src',
+ search_list = [ '*.py' ],
+ remove_list = [
+ 'engine/SCons/Conftest.py',
+ 'engine/SCons/dblite.py',
+ 'engine/SCons/Optik',
+ ],
+ ),
+
+ CheckUnexpandedStrings(
+ 'test',
+ search_list = [ '*.py' ],
+ ),
+
+ CheckExpandedCopyright(
+ build_scons,
+ remove_list = [
+ 'build',
+ 'build-stamp',
+ 'configure-stamp',
+ 'debian',
+ 'dist',
+ 'engine/SCons/Conftest.py',
+ 'engine/SCons/dblite.py',
+ 'engine/SCons/Optik',
+ 'MANIFEST',
+ 'os_spawnv_fix.diff',
+ 'setup.cfg',
+ ],
+ ),
+
+ CheckExpandedCopyright(
+ build_local,
+ remove_list = [
+ 'SCons/Conftest.py',
+ 'SCons/dblite.py',
+ 'SCons/Optik',
+ ],
+ ),
+
+ CheckExpandedCopyright(
+ build_src,
+ remove_list = [
+ 'bin',
+ 'config',
+ 'debian',
+ 'doc/design',
+ 'doc/MANIFEST',
+ 'doc/python10',
+ 'doc/reference',
+ 'doc/man/MANIFEST',
+ 'doc/user/cons.pl',
+ 'doc/user/MANIFEST',
+ 'doc/user/SCons-win32-install-1.jpg',
+ 'doc/user/SCons-win32-install-2.jpg',
+ 'doc/user/SCons-win32-install-3.jpg',
+ 'doc/user/SCons-win32-install-4.jpg',
+ 'gentoo',
+ 'QMTest/classes.qmc',
+ 'QMTest/configuration',
+ 'QMTest/TestCmd.py',
+ 'QMTest/TestCommon.py',
+ 'QMTest/unittest.py',
+ 'src/os_spawnv_fix.diff',
+ 'src/MANIFEST.in',
+ 'src/setup.cfg',
+ 'src/engine/MANIFEST.in',
+ 'src/engine/MANIFEST-xml.in',
+ 'src/engine/setup.cfg',
+ 'src/engine/SCons/Conftest.py',
+ 'src/engine/SCons/dblite.py',
+ 'src/engine/SCons/Optik',
+ 'src/script/MANIFEST.in',
+ 'src/script/setup.cfg',
+ ],
+ ),
+
+]
+
+missing_strings = []
+not_built = []
+
+for collector in check_list:
+ if collector.directory_exists():
+ missing_strings.extend(collector.find_missing())
+ elif collector.must_be_built():
+ not_built.append(collector.directory)
+
+if missing_strings:
+ print "Found the following files with missing strings:"
+ print "\t" + string.join(missing_strings, "\n\t")
test.fail_test(1)
-if no_result:
- print "Cannot check copyrights, the following have apparently not been built:"
- print "\t" + string.join(no_result, "\n\t")
+if not_built:
+ print "Cannot check all strings, the following have apparently not been built:"
+ print "\t" + string.join(not_built, "\n\t")
test.no_result(1)
test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that environments with actions that have different signatures
+generate an error.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=Action(build, varlist=['XXX']), multi=1)
+env = Environment(BUILDERS = { 'B' : B }, XXX = 'foo')
+env2 = env.Clone(XXX = 'var')
+env.B(target = 'file6.out', source = 'file6a.in')
+env2.B(target = 'file6.out', source = 'file6b.in')
+""")
+
+test.write('file6a.in', 'file6a.in\n')
+test.write('file6b.in', 'file6b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two environments with different actions were specified for the same target: file6.out
+""") + TestSCons.file_expr
+
+test.pass_test()
+
+test.run(arguments='file6.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a warning is generated if the calls have different overrides
+but the overrides don't appear to affect the build operation.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+_python_ = TestSCons._python_
+
+test.write('build.py', r"""#!/usr/bin/env python
+import sys
+def build(num, target, source):
+ file = open(str(target), 'wb')
+ file.write('%s\n'%num)
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+build(sys.argv[1],sys.argv[2],sys.argv[3:])
+""")
+
+test.write('SConstruct', """\
+B = Builder(action='%(_python_)s build.py $foo $TARGET $SOURCES', multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file03.out', source = 'file03a.in', foo=1)
+env.B(target = 'file03.out', source = 'file03b.in', foo=2)
+""" % locals())
+
+test.write('file03a.in', 'file03a.in\n')
+test.write('file03b.in', 'file03b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two environments with different actions were specified for the same target: file03.out
+""") + TestSCons.file_expr
+
+test.run(arguments='file03.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that trying to call a target with two different "multi" builders
+generates an error.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+def build2(env, target, source):
+ build(env, target, source)
+
+# Put the names on the Builder objects and in the environment so
+# the error output should be consistent regardless of Python version
+# or how we mess with the Builder internals.
+B = Builder(action=build, multi=1, name='B')
+C = Builder(action=build2, multi=1, name='C')
+env = Environment(BUILDERS = { 'B' : B, 'C' : C })
+env.B(target = 'file8.out', source = 'file8.in')
+env.C(target = 'file8.out', source = 'file8.in')
+""")
+
+test.write('file8a.in', 'file8a.in\n')
+test.write('file8b.in', 'file8b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two different builders (B and C) were specified for the same target: file8.out
+""") + TestSCons.file_expr
+
+test.run(arguments='file8.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a "multi" builder can NOT be called multiple times with
+target lists that have different orders. This is intentional; the
+order of the targets matter to the builder because the build command
+can contain things like ${TARGET[0]}.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ for t in target:
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = ['file10a.out', 'file10b.out'], source = 'file10.in')
+env.B(target = ['file10b.out', 'file10a.out'], source = 'file10.in')
+""")
+
+test.write('file10.in', 'file10.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two different target lists have a target in common: file10b.out (from ['file10a.out', 'file10b.out'] and from ['file10b.out', 'file10a.out'])
+""") + TestSCons.file_expr
+
+test.run(arguments='file10.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a warning is generated if the calls have different overrides
+but the overrides don't appear to affect the build operation.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file3.out', source = 'file3a.in', foo=1)
+env.B(target = 'file3.out', source = 'file3b.in', foo=2)
+""")
+
+test.write('file3a.in', 'file3a.in\n')
+test.write('file3b.in', 'file3b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: warning: Two different environments were specified for target file3.out,
+\tbut they appear to have the same action: build(target, source, env)
+""") + TestSCons.file_expr
+
+test.run(arguments='file3.out', stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a target file can't be in two different target lists.
+"""
+
+# XXX It would be nice if the following two tests could be made to work
+# by executing the action once for each unique set of targets. This
+# would make it simple to deal with PDB files on Windows like so:
+#
+# env.Object(['foo.obj', 'vc60.pdb'], 'foo.c')
+# env.Object(['bar.obj', 'vc60.pdb'], 'bar.c')
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ for t in target:
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = ['file11a.out', 'file11b.out'], source = 'file11a.in')
+env.B(target = ['file11b.out', 'file11c.out'], source = 'file11b.in')
+""")
+
+test.write('file11a.in', 'file11a.in\n')
+test.write('file11b.in', 'file11b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two different target lists have a target in common: file11b.out (from ['file11a.out', 'file11b.out'] and from ['file11b.out', 'file11c.out'])
+""") + TestSCons.file_expr
+
+test.run(arguments='file11.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a builder with "multi" not set generates an error on the
+second call.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=0)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file2.out', source = 'file2a.in')
+env.B(target = 'file2.out', source = 'file2b.in')
+""")
+
+test.write('file2a.in', 'file2a.in\n')
+test.write('file2b.in', 'file2b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Multiple ways to build the same target were specified for: file2.out (from ['file2a.in'] and from ['file2b.in'])
+""") + TestSCons.file_expr
+
+test.run(arguments='file2.out', status=2, stderr=expect)
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a target file can't be a lone target and in a list.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ for t in target:
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = ['file12a.out', 'file12b.out'], source = 'file12a.in')
+env.B(target = 'file12a.out', source = 'file12b.in')
+""")
+
+test.write('file12a.in', 'file12a.in\n')
+test.write('file12b.in', 'file12b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: *** Two different target lists have a target in common: file12a.out (from ['file12a.out', 'file12b.out'] and from ['file12a.out'])
+""") + TestSCons.file_expr
+
+test.run(arguments='file12.out', status=2, stderr=expect)
+
+
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a builder with "multi" set can be called multiple times
+and the source files are added to the list.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file1.out', source = 'file1a.in')
+env.B(target = 'file1.out', source = 'file1b.in')
+""")
+
+test.write('file1a.in', 'file1a.in\n')
+test.write('file1b.in', 'file1b.in\n')
+
+test.run(arguments='file1.out')
+
+test.must_match('file1.out', "file1a.in\nfile1b.in\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that two different environments can be used for the same target,
+so long as the actions have the same signature; a warning is generated.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env2 = env.Clone(DIFFERENT_VARIABLE = 'true')
+env.B(target = 'file5.out', source = 'file5a.in')
+env2.B(target = 'file5.out', source = 'file5b.in')
+""")
+
+test.write('file5a.in', 'file5a.in\n')
+test.write('file5b.in', 'file5b.in\n')
+
+expect = TestSCons.re_escape("""
+scons: warning: Two different environments were specified for target file5.out,
+\tbut they appear to have the same action: build(target, source, env)
+""") + TestSCons.file_expr
+
+test.run(arguments='file5.out', stderr=expect)
+
+test.must_match('file5.out', "file5a.in\nfile5b.in\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that everything works if two multi calls have the same overrides.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+_python_ = TestSCons._python_
+
+test.write('build.py', r"""#!/usr/bin/env python
+import sys
+def build(num, target, source):
+ file = open(str(target), 'wb')
+ file.write('%s\n'%num)
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+build(sys.argv[1],sys.argv[2],sys.argv[3:])
+""")
+
+test.write('SConstruct', """\
+B = Builder(action='%(_python_)s build.py $foo $TARGET $SOURCES', multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file4.out', source = 'file4a.in', foo=3)
+env.B(target = 'file4.out', source = 'file4b.in', foo=3)
+""" % locals())
+
+test.write('file4a.in', 'file4a.in\n')
+test.write('file4b.in', 'file4b.in\n')
+
+python_expr = string.replace(TestSCons.python, '\\', '\\\\')
+act = TestSCons.re_escape('"%s" build.py \$foo \$TARGET \$SOURCES' % python_expr)
+
+expect = ("""
+scons: warning: Two different environments were specified for target file4.out,
+\tbut they appear to have the same action: %s
+""" % act) + TestSCons.file_expr
+
+test.run(arguments='file4.out', stderr=expect)
+
+test.must_match('file4.out', "3\nfile4a.in\nfile4b.in\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a "multi" builder can be called multiple times with the same
+target list if everything is identical.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """\
+def build(env, target, source):
+ for t in target:
+ file = open(str(t), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = ['file9a.out', 'file9b.out'], source = 'file9a.in')
+env.B(target = ['file9a.out', 'file9b.out'], source = 'file9b.in')
+""")
+
+test.write('file9a.in', 'file9a.in\n')
+test.write('file9b.in', 'file9b.in\n')
+
+test.run(arguments='file9b.out')
+
+test.must_match('file9a.out', "file9a.in\nfile9b.in\n")
+test.must_match('file9b.out', "file9a.in\nfile9b.in\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that a builder without "multi" set can still be called multiple
+times if the calls are the same.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match=TestSCons.match_re)
+
+test.write('SConstruct', """
+def build(env, target, source):
+ file = open(str(target[0]), 'wb')
+ for s in source:
+ file.write(open(str(s), 'rb').read())
+
+B = Builder(action=build, multi=0)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'file7.out', source = 'file7.in')
+env.B(target = 'file7.out', source = 'file7.in')
+""")
+
+test.write('file7.in', 'file7.in\n')
+
+test.run(arguments='file7.out')
+
+test.must_match('file7.out', "file7.in\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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 sys, string
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+# Make sure CFLAGS is not passed to CXX by just expanding CXXCOM
+test.write('SConstruct', """
+env = Environment(CFLAGS='-xyz', CCFLAGS='-abc')
+print env.subst('$CXXCOM')
+print env.subst('$CXXCOMSTR')
+print env.subst('$SHCXXCOM')
+print env.subst('$SHCXXCOMSTR')
+""")
+test.run(arguments = '.')
+test.fail_test(string.find(test.stdout(), "-xyz") != -1)
+test.fail_test(string.find(test.stdout(), "-abc") == -1)
+
+
+# Test passing CFLAGS to C compiler by actually compiling programs
+if sys.platform == 'win32':
+ _obj = '.obj'
+ fooflags = '/nologo -DFOO'
+ barflags = '/nologo -DBAR'
+else:
+ _obj = '.o'
+ fooflags = '-DFOO'
+ barflags = '-DBAR'
+
+
+test.write('SConstruct', """
+foo = Environment(CFLAGS = '%s')
+bar = Environment(CFLAGS = '%s')
+foo.Object(target = 'foo%s', source = 'prog.c')
+bar.Object(target = 'bar%s', source = 'prog.c')
+foo.Program(target = 'foo', source = 'foo%s')
+bar.Program(target = 'bar', source = 'bar%s')
+foo.Program(target = 'prog', source = 'prog.c',
+ CFLAGS = '$CFLAGS -DBAR $BAZ', BAZ = '-DBAZ')
+""" % (fooflags, barflags, _obj, _obj, _obj, _obj))
+
+test.write('prog.c', r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+#ifdef FOO
+ printf("prog.c: FOO\n");
+#endif
+#ifdef BAR
+ printf("prog.c: BAR\n");
+#endif
+#ifdef BAZ
+ printf("prog.c: BAZ\n");
+#endif
+ exit (0);
+}
+""")
+
+
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('foo'), stdout = "prog.c: FOO\n")
+test.run(program = test.workpath('bar'), stdout = "prog.c: BAR\n")
+test.run(program = test.workpath('prog'), stdout = """\
+prog.c: FOO
+prog.c: BAR
+prog.c: BAZ
+""")
+
+test.write('SConstruct', """
+bar = Environment(CFLAGS = '%s')
+bar.Object(target = 'foo%s', source = 'prog.c')
+bar.Object(target = 'bar%s', source = 'prog.c')
+bar.Program(target = 'foo', source = 'foo%s')
+bar.Program(target = 'bar', source = 'bar%s')
+""" % (barflags, _obj, _obj, _obj, _obj))
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('foo'), stdout = "prog.c: BAR\n")
+test.run(program = test.workpath('bar'), stdout = "prog.c: BAR\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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 sys
+import TestSCons
+import os
+import string
+
+test = TestSCons.TestSCons()
+
+e = test.Environment()
+fooflags = e['SHCFLAGS'] + ' -DFOO'
+barflags = e['SHCFLAGS'] + ' -DBAR'
+
+if os.name == 'posix':
+ os.environ['LD_LIBRARY_PATH'] = '.'
+if string.find(sys.platform, 'irix') > -1:
+ os.environ['LD_LIBRARYN32_PATH'] = '.'
+
+test.write('SConstruct', """
+foo = Environment(SHCFLAGS = '%s', WINDOWS_INSERT_DEF=1)
+bar = Environment(SHCFLAGS = '%s', WINDOWS_INSERT_DEF=1)
+
+foo_obj = foo.SharedObject(target = 'foo', source = 'prog.c')
+foo.SharedLibrary(target = 'foo', source = foo_obj)
+
+bar_obj = bar.SharedObject(target = 'bar', source = 'prog.c')
+bar.SharedLibrary(target = 'bar', source = bar_obj)
+
+fooMain = foo.Clone(LIBS='foo', LIBPATH='.')
+foomain_obj = fooMain.Object(target='foomain', source='main.c')
+fooMain.Program(target='fooprog', source=foomain_obj)
+
+barMain = bar.Clone(LIBS='bar', LIBPATH='.')
+barmain_obj = barMain.Object(target='barmain', source='main.c')
+barMain.Program(target='barprog', source=barmain_obj)
+""" % (fooflags, barflags))
+
+test.write('foo.def', r"""
+LIBRARY "foo"
+DESCRIPTION "Foo Shared Library"
+
+EXPORTS
+ doIt
+""")
+
+test.write('bar.def', r"""
+LIBRARY "bar"
+DESCRIPTION "Bar Shared Library"
+
+EXPORTS
+ doIt
+""")
+
+test.write('prog.c', r"""
+#include <stdio.h>
+
+void
+doIt()
+{
+#ifdef FOO
+ printf("prog.c: FOO\n");
+#endif
+#ifdef BAR
+ printf("prog.c: BAR\n");
+#endif
+}
+""")
+
+test.write('main.c', r"""
+
+void doIt();
+
+int
+main(int argc, char* argv[])
+{
+ doIt();
+ return 0;
+}
+""")
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('fooprog'), stdout = "prog.c: FOO\n")
+test.run(program = test.workpath('barprog'), stdout = "prog.c: BAR\n")
+
+test.write('SConstruct', """
+bar = Environment(SHCFLAGS = '%s', WINDOWS_INSERT_DEF=1)
+
+foo_obj = bar.SharedObject(target = 'foo', source = 'prog.c')
+bar.SharedLibrary(target = 'foo', source = foo_obj)
+
+bar_obj = bar.SharedObject(target = 'bar', source = 'prog.c')
+bar.SharedLibrary(target = 'bar', source = bar_obj)
+
+barMain = bar.Clone(LIBS='bar', LIBPATH='.')
+foomain_obj = barMain.Object(target='foomain', source='main.c')
+barmain_obj = barMain.Object(target='barmain', source='main.c')
+barMain.Program(target='barprog', source=foomain_obj)
+barMain.Program(target='fooprog', source=barmain_obj)
+""" % (barflags))
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('fooprog'), stdout = "prog.c: BAR\n")
+test.run(program = test.workpath('barprog'), stdout = "prog.c: BAR\n")
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Verify that targets retrieved from CacheDir() are reported as
+up-to-date by the -q option.
+
+Thanks to dvitek for the test case.
+"""
+
+# Demonstrate a regression between 0.96.1 and 0.96.93.
+#
+# SCons would incorrectly believe files are stale if they were retrieved
+# from the cache in a previous invocation.
+#
+# What this script does:
+# 1. Set up two identical C project directories called 'alpha' and
+# 'beta', which use the same cache
+# 2. Invoke scons on 'alpha'
+# 3. Invoke scons on 'beta', which successfully draws output
+# files from the cache
+# 4. Invoke scons again, asserting (with -q) that 'beta' is up to date
+#
+# Step 4 failed in 0.96.93. In practice, this problem would lead to
+# lots of unecessary fetches from the cache during incremental
+# builds (because they behaved like non-incremental builds).
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('cache', 'alpha', 'beta')
+
+foo_c = """
+int main(){ return 0; }
+"""
+
+sconstruct = """
+import os
+CacheDir('%s')
+Program('foo', 'foo.c')
+""" % test.workpath('cache')
+
+test.write('alpha/foo.c', foo_c)
+test.write('alpha/SConstruct', sconstruct)
+
+test.write('beta/foo.c', foo_c)
+test.write('beta/SConstruct', sconstruct)
+
+# First build, populates the cache
+test.run(chdir = 'alpha', arguments = '.')
+
+# Second build, everything is a cache hit
+test.run(chdir = 'beta', arguments = '.')
+
+# Since we just built 'beta', it ought to be up to date.
+test.run(chdir = 'beta', arguments = '. -q')
+
+test.pass_test()
test.write('SConstruct', """
env = Environment(LEX = r'%(_python_)s mylex.py', tools=['default', 'lex'])
-env.Program(target = 'aaa', source = 'aaa.l')
-env.Program(target = 'bbb', source = 'bbb.lex')
+env.CFile(target = 'aaa', source = 'aaa.l')
+env.CFile(target = 'bbb', source = 'bbb.lex')
+env.CXXFile(target = 'ccc', source = 'ccc.ll')
+env.CXXFile(target = 'ddd', source = 'ddd.lm')
""" % locals())
-test.write('aaa.l', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("LEX\n");
- printf("aaa.l\n");
- exit (0);
-}
-""")
-
-test.write('bbb.lex', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("LEX\n");
- printf("bbb.lex\n");
- exit (0);
-}
-""")
+test.write('aaa.l', "aaa.l\nLEX\n")
+test.write('bbb.lex', "bbb.lex\nLEX\n")
+test.write('ccc.ll', "ccc.ll\nLEX\n")
+test.write('ddd.lm', "ddd.lm\nLEX\n")
test.run(arguments = '.', stderr = None)
-test.run(program = test.workpath('aaa' + _exe), stdout = "mylex.py\naaa.l\n")
-test.run(program = test.workpath('bbb' + _exe), stdout = "mylex.py\nbbb.lex\n")
-
-
-
-lex = test.where_is('lex')
-
-if lex:
-
- test.write("wrapper.py", """import os
-import string
-import sys
-open('%s', 'wb').write("wrapper.py\\n")
-os.system(string.join(sys.argv[1:], " "))
-""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
-
- test.write('SConstruct', """
-foo = Environment()
-lex = foo.Dictionary('LEX')
-bar = Environment(LEX = r'%(_python_)s wrapper.py ' + lex)
-foo.Program(target = 'foo', source = 'foo.l')
-bar.Program(target = 'bar', source = 'bar.l')
-""" % locals())
-
- lex = r"""
-%%%%
-a printf("A%sA");
-b printf("B%sB");
-%%%%
-int
-yywrap()
-{
- return 1;
-}
-
-main()
-{
- yylex();
-}
-"""
-
- test.write('foo.l', lex % ('foo.l', 'foo.l'))
-
- test.write('bar.l', lex % ('bar.l', 'bar.l'))
-
- test.run(arguments = 'foo' + _exe, stderr = None)
-
- test.fail_test(os.path.exists(test.workpath('wrapper.out')))
-
- test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "Afoo.lA\n")
-
- test.run(arguments = 'bar' + _exe)
+# Read in with mode='r' because mylex.py implicitley wrote to stdout
+# with mode='w'.
+test.must_match('aaa.c', "aaa.l\nmylex.py\n", mode='r')
+test.must_match('bbb.c', "bbb.lex\nmylex.py\n", mode='r')
+test.must_match('ccc.cc', "ccc.ll\nmylex.py\n", mode='r')
+test.must_match('ddd.m', "ddd.lm\nmylex.py\n", mode='r')
- test.fail_test(test.read('wrapper.out') != "wrapper.py\n")
- test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "Bbar.lB\n")
test.pass_test()
env = Environment(LEX = r'%(_python_)s mylex.py',
LEXFLAGS = '-x',
tools=['default', 'lex'])
-env.Program(target = 'aaa', source = 'aaa.l')
+env.CFile(target = 'aaa', source = 'aaa.l')
""" % locals())
-test.write('aaa.l', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("LEXFLAGS\n");
- printf("aaa.l\n");
- exit (0);
-}
-""")
-
-test.run(arguments = 'aaa' + _exe, stderr = None)
-
-test.run(program = test.workpath('aaa' + _exe), stdout = " -x -t\naaa.l\n")
-
-
-
-lex = test.where_is('lex')
-
-if lex:
-
- test.write('SConstruct', """
-foo = Environment()
-bar = Environment(LEXFLAGS = '-b')
-foo.Program(target = 'foo', source = 'foo.l')
-bar.Program(target = 'bar', source = 'bar.l')
-""")
-
- lex = r"""
-%%%%
-a printf("A%sA");
-b printf("B%sB");
-%%%%
-int
-yywrap()
-{
- return 1;
-}
-
-main()
-{
- yylex();
-}
-"""
-
- test.write('foo.l', lex % ('foo.l', 'foo.l'))
-
- test.write('bar.l', lex % ('bar.l', 'bar.l'))
-
- test.run(arguments = 'foo' + _exe, stderr = None)
-
- test.fail_test(os.path.exists(test.workpath('lex.backup')))
+test.write('aaa.l', "aaa.l\nLEXFLAGS\n")
- test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "Afoo.lA\n")
+test.run('.', stderr = None)
- test.run(arguments = 'bar' + _exe)
+# Read in with mode='r' because mylex.py implicitley wrote to stdout
+# with mode='w'.
+test.must_match('aaa.c', "aaa.l\n -x -t\n", mode='r')
- test.fail_test(not os.path.exists(test.workpath('lex.backup')))
- test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "Bbar.lB\n")
test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test LEX and LEXFLAGS with a live lex.
+"""
+
+import string
+
+import TestSCons
+
+_exe = TestSCons._exe
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+lex = test.where_is('lex') or test.where_is('flex')
+
+if not lex:
+ test.skip_test('No lex or flex found; skipping test.\n')
+
+
+
+test.write("wrapper.py", """import os
+import string
+import sys
+open('%s', 'wb').write("wrapper.py\\n")
+os.system(string.join(sys.argv[1:], " "))
+""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
+
+test.write('SConstruct', """
+foo = Environment()
+lex = foo.Dictionary('LEX')
+bar = Environment(LEX = r'%(_python_)s wrapper.py ' + lex,
+ LEXFLAGS = '-b')
+foo.Program(target = 'foo', source = 'foo.l')
+bar.Program(target = 'bar', source = 'bar.l')
+""" % locals())
+
+lex = r"""
+%%%%
+a printf("A%sA");
+b printf("B%sB");
+%%%%
+int
+yywrap()
+{
+ return 1;
+}
+
+main()
+{
+ yylex();
+}
+"""
+
+test.write('foo.l', lex % ('foo.l', 'foo.l'))
+
+test.write('bar.l', lex % ('bar.l', 'bar.l'))
+
+test.run(arguments = 'foo' + _exe, stderr = None)
+
+test.must_not_exist(test.workpath('wrapper.out'))
+test.must_not_exist(test.workpath('lex.backup'))
+
+test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "Afoo.lA\n")
+
+
+
+
+test.run(arguments = 'bar' + _exe)
+
+test.must_match(test.workpath('wrapper.out'), "wrapper.py\n")
+test.must_exist(test.workpath('lex.backup'))
+
+test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "Bbar.lB\n")
+
+
+
+test.pass_test()
test = TestSCons.TestSCons()
+latex = test.where_is('latex')
+if not latex:
+ test.skip_test("Could not find 'latex'; skipping test.\n")
+
test.subdir(['docs'])
test.write(['SConstruct'], """\
import os
-env = Environment(ENV = { 'PATH' : os.environ['PATH'] })
+env = Environment(ENV = { 'PATH' : os.environ['PATH'] },
+ TOOLS = ['tex', 'latex', 'dvipdf'])
Export(['env'])
SConscript(os.path.join('docs', 'SConscript'),
test = TestSCons.TestSCons()
+latex = test.where_is('latex')
+if not latex:
+ test.skip_test("Could not find 'latex'; skipping test.\n")
+
+pdflatex = test.where_is('pdflatex')
+if not pdflatex:
+ test.skip_test("Could not find 'pdflatex'; skipping test.\n")
+
test.subdir('sub')
test.write('SConstruct', """\
-PDF( 'sub/x.tex' )
-DVI( 'sub/x.tex' )
+env = Environment(TOOLS = ['tex', 'pdftex'])
+env.PDF( 'sub/x.tex' )
+env.DVI( 'sub/x.tex' )
""")
test.write(['sub', 'x.tex'],
test.write('SConstruct', """
env = Environment(YACC = r'%(_python_)s myyacc.py', tools=['default', 'yacc'])
-env.Program(target = 'aaa', source = 'aaa.y')
-env.Program(target = 'bbb', source = 'bbb.yacc')
+env.CFile(target = 'aaa', source = 'aaa.y')
+env.CFile(target = 'bbb', source = 'bbb.yacc')
+env.CXXFile(target = 'ccc', source = 'ccc.yy')
+env.CFile(target = 'ddd', source = 'ddd.ym')
""" % locals())
-test.write('aaa.y', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("YACC\n");
- printf("aaa.y\n");
- exit (0);
-}
-""")
-
-test.write('bbb.yacc', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("YACC\n");
- printf("bbb.yacc\n");
- exit (0);
-}
-""")
+test.write('aaa.y', "aaa.y\nYACC\n")
+test.write('bbb.yacc', "bbb.yacc\nYACC\n")
+test.write('ccc.yy', "ccc.yacc\nYACC\n")
+test.write('ddd.ym', "ddd.yacc\nYACC\n")
test.run(arguments = '.', stderr = None)
-test.run(program = test.workpath('aaa' + _exe), stdout = "myyacc.py\naaa.y\n")
-test.run(program = test.workpath('bbb' + _exe), stdout = "myyacc.py\nbbb.yacc\n")
-
-
-
-yacc = test.where_is('yacc')
-
-if yacc:
-
- test.write("wrapper.py",
-"""import os
-import string
-import sys
-open('%s', 'wb').write("wrapper.py\\n")
-os.system(string.join(sys.argv[1:], " "))
-""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
-
- test.write('SConstruct', """
-foo = Environment(YACCFLAGS='-d')
-yacc = foo.Dictionary('YACC')
-bar = Environment(YACC = r'%(_python_)s wrapper.py ' + yacc)
-foo.Program(target = 'foo', source = 'foo.y')
-bar.Program(target = 'bar', source = 'bar.y')
-foo.Program(target = 'hello', source = ['hello.cpp'])
-foo.CXXFile(target = 'file.cpp', source = ['file.yy'], YACCFLAGS='-d')
-foo.CFile(target = 'not_foo', source = 'foo.y')
-""" % locals())
-
- yacc = r"""
-%%{
-#include <stdio.h>
-
-main()
-{
- yyparse();
-}
-
-yyerror(s)
-char *s;
-{
- fprintf(stderr, "%%s\n", s);
- return 0;
-}
-
-yylex()
-{
- int c;
-
- c = fgetc(stdin);
- return (c == EOF) ? 0 : c;
-}
-%%}
-%%%%
-input: letter newline { printf("%s\n"); };
-letter: 'a' | 'b';
-newline: '\n';
-"""
-
- test.write("file.yy", """\
-%token GRAPH_T NODE_T EDGE_T DIGRAPH_T EDGEOP_T SUBGRAPH_T
-
-%pure_parser
-
-%%
-graph: GRAPH_T
- ;
-
-%%
-""")
-
- test.write("hello.cpp", """\
-#include "file.hpp"
-
-int main()
-{
-}
-""")
-
- test.write('foo.y', yacc % 'foo.y')
-
- test.write('bar.y', yacc % 'bar.y')
-
- # Build the foo program
- test.run(arguments = 'foo' + _exe, stderr = None)
-
- test.up_to_date(arguments = 'foo' + _exe)
-
- test.fail_test(os.path.exists(test.workpath('wrapper.out')))
-
- test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "foo.y\n")
-
- test.fail_test(not os.path.exists(test.workpath('foo.h')))
-
- test.run(arguments = '-c .')
-
- test.fail_test(os.path.exists(test.workpath('foo.h')))
-
- #
- test.run(arguments = 'not_foo.c')
-
- test.up_to_date(arguments = 'not_foo.c')
-
- test.fail_test(os.path.exists(test.workpath('foo.h')))
- test.fail_test(not os.path.exists(test.workpath('not_foo.h')))
-
- test.run(arguments = '-c .')
-
- test.fail_test(os.path.exists(test.workpath('not_foo.h')))
-
- #
- test.run(arguments = 'bar' + _exe)
-
- test.up_to_date(arguments = 'bar' + _exe)
-
- test.fail_test(test.read('wrapper.out') != "wrapper.py\n")
+test.must_match('aaa.c', "aaa.y\nmyyacc.py\n")
+test.must_match('bbb.c', "bbb.yacc\nmyyacc.py\n")
+test.must_match('ccc.cc', "ccc.yacc\nmyyacc.py\n")
+test.must_match('ddd.m', "ddd.yacc\nmyyacc.py\n")
- test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "bar.y\n")
- #
- test.run(arguments = '.')
- test.up_to_date(arguments = '.')
test.pass_test()
env = Environment(YACC = r'%(_python_)s myyacc.py',
YACCFLAGS = '-x',
tools=['yacc', '%(linker)s', '%(compiler)s'])
-env.Program(target = 'aaa', source = 'aaa.y')
+env.CFile(target = 'aaa', source = 'aaa.y')
""" % locals())
-test.write('aaa.y', r"""
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("YACCFLAGS\n");
- printf("aaa.y\n");
- exit (0);
-}
-""")
-
-test.run(arguments = 'aaa' + _exe, stderr = None)
-
-test.run(program = test.workpath('aaa' + _exe), stdout = " -x\naaa.y\n")
-
-
-
-yacc = test.where_is('yacc')
-
-if yacc:
-
- test.write('SConstruct', """
-foo = Environment()
-bar = Environment(YACCFLAGS = '-v')
-foo.Program(target = 'foo', source = 'foo.y')
-bar.Program(target = 'bar', source = 'bar.y')
-""")
-
- yacc = r"""
-%%{
-#include <stdio.h>
-
-main()
-{
- yyparse();
-}
-
-yyerror(s)
-char *s;
-{
- fprintf(stderr, "%%s\n", s);
- return 0;
-}
-
-yylex()
-{
- int c;
-
- c = fgetc(stdin);
- return (c == EOF) ? 0 : c;
-}
-%%}
-%%%%
-input: letter newline { printf("%s\n"); };
-letter: 'a' | 'b';
-newline: '\n';
-"""
-
- test.write('foo.y', yacc % 'foo.y')
-
- test.write('bar.y', yacc % 'bar.y')
-
- test.run(arguments = 'foo' + _exe, stderr = None)
-
- test.fail_test(os.path.exists(test.workpath('foo.output'))
- or os.path.exists(test.workpath('y.output')))
+test.write('aaa.y', "aaa.y\nYACCFLAGS\n")
- test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "foo.y\n")
+test.run('.', stderr = None)
- test.run(arguments = 'bar' + _exe)
+test.must_match('aaa.c', "aaa.y\n -x\n")
- test.fail_test(not os.path.exists(test.workpath('bar.output'))
- and not os.path.exists(test.workpath('y.output')))
- test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "bar.y\n")
test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test setting the YACCVCGFILESUFFIX variable.
+"""
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+
+
+test.write('myyacc.py', """\
+import getopt
+import os.path
+import string
+import sys
+vcg = None
+opts, args = getopt.getopt(sys.argv[1:], 'go:')
+for o, a in opts:
+ if o == '-g':
+ vcg = 1
+ elif o == '-o':
+ outfile = open(a, 'wb')
+for f in args:
+ infile = open(f, 'rb')
+ for l in filter(lambda l: l != '/*yacc*/\\n', infile.readlines()):
+ outfile.write(l)
+outfile.close()
+if vcg:
+ base, ext = os.path.splitext(args[0])
+ open(base+'.vcgsuffix', 'wb').write(string.join(sys.argv)+'\\n')
+sys.exit(0)
+""")
+
+test.write('SConstruct', """
+env = Environment(tools=['default', 'yacc'],
+ YACC = r'%(_python_)s myyacc.py',
+ YACCVCGFILESUFFIX = '.vcgsuffix')
+env.CXXFile(target = 'aaa', source = 'aaa.yy')
+env.CXXFile(target = 'bbb', source = 'bbb.yy', YACCFLAGS = '-g')
+""" % locals())
+
+test.write('aaa.yy', "aaa.yy\n/*yacc*/\n")
+test.write('bbb.yy', "bbb.yy\n/*yacc*/\n")
+
+test.run(arguments = '.')
+
+test.must_match('aaa.cc', "aaa.yy\n")
+test.must_not_exist('aaa.vcg')
+test.must_not_exist('aaa.vcgsuffix')
+
+test.must_match('bbb.cc', "bbb.yy\n")
+test.must_not_exist('bbb.vcg')
+test.must_match('bbb.vcgsuffix', "myyacc.py -g -o bbb.cc bbb.yy\n")
+
+test.up_to_date(arguments = '.')
+
+
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test YACC and YACCFLAGS with a live yacc compiler.
+"""
+
+import string
+
+import TestSCons
+
+_exe = TestSCons._exe
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+yacc = test.where_is('yacc') or test.where_is('bison')
+
+if not yacc:
+ test.skip_test('No yacc or bison found; skipping test.\n')
+
+test.write("wrapper.py",
+"""import os
+import string
+import sys
+open('%s', 'wb').write("wrapper.py\\n")
+os.system(string.join(sys.argv[1:], " "))
+""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
+
+test.write('SConstruct', """
+foo = Environment(YACCFLAGS='-d')
+yacc = foo.Dictionary('YACC')
+bar = Environment(YACC = r'%(_python_)s wrapper.py ' + yacc)
+foo.Program(target = 'foo', source = 'foo.y')
+bar.Program(target = 'bar', source = 'bar.y')
+foo.Program(target = 'hello', source = ['hello.cpp'])
+foo.CXXFile(target = 'file.cpp', source = ['file.yy'], YACCFLAGS='-d')
+foo.CFile(target = 'not_foo', source = 'foo.y')
+""" % locals())
+
+yacc = r"""
+%%{
+#include <stdio.h>
+
+main()
+{
+ yyparse();
+}
+
+yyerror(s)
+char *s;
+{
+ fprintf(stderr, "%%s\n", s);
+ return 0;
+}
+
+yylex()
+{
+ int c;
+
+ c = fgetc(stdin);
+ return (c == EOF) ? 0 : c;
+}
+%%}
+%%%%
+input: letter newline { printf("%s\n"); };
+letter: 'a' | 'b';
+newline: '\n';
+"""
+
+test.write("file.yy", """\
+%token GRAPH_T NODE_T EDGE_T DIGRAPH_T EDGEOP_T SUBGRAPH_T
+
+%pure_parser
+
+%%
+graph: GRAPH_T
+ ;
+
+%%
+""")
+
+test.write("hello.cpp", """\
+#include "file.hpp"
+
+int main()
+{
+}
+""")
+
+test.write('foo.y', yacc % 'foo.y')
+
+test.write('bar.y', yacc % 'bar.y')
+
+
+
+test.run(arguments = 'foo' + _exe, stderr = None)
+
+test.up_to_date(arguments = 'foo' + _exe)
+
+test.must_not_exist(test.workpath('wrapper.out'))
+
+test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "foo.y\n")
+
+test.must_exist(test.workpath('foo.h'))
+
+test.run(arguments = '-c .')
+
+test.must_not_exist(test.workpath('foo.h'))
+
+
+
+test.run(arguments = 'not_foo.c')
+
+test.up_to_date(arguments = 'not_foo.c')
+
+test.must_not_exist(test.workpath('foo.h'))
+test.must_exist(test.workpath('not_foo.h'))
+
+test.run(arguments = '-c .')
+
+test.must_not_exist(test.workpath('not_foo.h'))
+
+
+
+test.run(arguments = 'bar' + _exe)
+
+test.up_to_date(arguments = 'bar' + _exe)
+
+test.must_match(test.workpath('wrapper.out'), "wrapper.py\n")
+
+test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "bar.y\n")
+
+
+
+test.run(arguments = '.')
+
+test.up_to_date(arguments = '.')
+
+
+
+test.pass_test()
#!/usr/bin/env python
#
-# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
+# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
Test use of a preceding - to ignore the return value from a command.
"""
-__revision__ = "/home/scons/scons/branch.0/branch.96/baseline/test/option-n.py 0.96.C352 2005/03/26 00:09:23 knight"
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
+++ /dev/null
-#!/usr/bin/env python
-#
-# __COPYRIGHT__
-#
-# 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__"
-
-"""
-Test various cases where a target is "built" by multiple builder calls.
-"""
-
-import os.path
-import string
-
-import TestCmd
-import TestSCons
-
-test = TestSCons.TestSCons(match=TestCmd.match_re)
-
-_python_ = TestSCons._python_
-
-#
-# A builder with "multi" set can be called multiple times and
-# the source files are added to the list.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file1.out', source = 'file1a.in')
-env.B(target = 'file1.out', source = 'file1b.in')
-""")
-
-test.write('file1a.in', 'file1a.in\n')
-test.write('file1b.in', 'file1b.in\n')
-
-test.run(arguments='file1.out')
-
-test.must_match('file1.out', "file1a.in\nfile1b.in\n")
-
-
-#
-# A builder with "multi" not set generates an error on the second call.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=0)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file2.out', source = 'file2a.in')
-env.B(target = 'file2.out', source = 'file2b.in')
-""")
-
-test.write('file2a.in', 'file2a.in\n')
-test.write('file2b.in', 'file2b.in\n')
-
-test.run(arguments='file2.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Multiple ways to build the same target were specified for: file2.out (from ['file2a.in'] and from ['file2b.in'])
-""") + TestSCons.file_expr)
-
-
-#
-# A warning is generated if the calls have different overrides but the
-# overrides don't appear to affect the build operation.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file3.out', source = 'file3a.in', foo=1)
-env.B(target = 'file3.out', source = 'file3b.in', foo=2)
-""")
-
-test.write('file3a.in', 'file3a.in\n')
-test.write('file3b.in', 'file3b.in\n')
-
-test.run(arguments='file3.out',
- stderr=TestSCons.re_escape("""
-scons: warning: Two different environments were specified for target file3.out,
-\tbut they appear to have the same action: build(target, source, env)
-""") + TestSCons.file_expr)
-
-#
-# A warning is generated if the calls have different overrides but the
-# overrides don't appear to affect the build operation.
-#
-
-test.write('build.py',r"""#!/usr/bin/env python
-import sys
-def build(num, target, source):
- file = open(str(target), 'wb')
- file.write('%s\n'%num)
- for s in source:
- file.write(open(str(s), 'rb').read())
-build(sys.argv[1],sys.argv[2],sys.argv[3:])
-""")
-
-test.write('SConstruct', """
-
-B = Builder(action='%(_python_)s build.py $foo $TARGET $SOURCES', multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file03.out', source = 'file03a.in', foo=1)
-env.B(target = 'file03.out', source = 'file03b.in', foo=2)
-""" % locals())
-
-test.write('file03a.in', 'file03a.in\n')
-test.write('file03b.in', 'file03b.in\n')
-
-test.run(arguments='file03.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Two environments with different actions were specified for the same target: file03.out
-""") + TestSCons.file_expr)
-
-#
-# Everything works if the two calls have the same overrides.
-#
-
-test.write('build.py',r"""#!/usr/bin/env python
-import sys
-def build(num, target, source):
- file = open(str(target), 'wb')
- file.write('%s\n'%num)
- for s in source:
- file.write(open(str(s), 'rb').read())
-build(sys.argv[1],sys.argv[2],sys.argv[3:])
-""")
-
-test.write('SConstruct', """
-
-B = Builder(action='%(_python_)s build.py $foo $TARGET $SOURCES', multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file4.out', source = 'file4a.in', foo=3)
-env.B(target = 'file4.out', source = 'file4b.in', foo=3)
-""" % locals())
-
-test.write('file4a.in', 'file4a.in\n')
-test.write('file4b.in', 'file4b.in\n')
-
-python_expr = string.replace(TestSCons.python, '\\', '\\\\')
-act = TestSCons.re_escape('"%s" build.py \$foo \$TARGET \$SOURCES' % python_expr)
-
-test.run(arguments='file4.out',
- stderr=("""
-scons: warning: Two different environments were specified for target file4.out,
-\tbut they appear to have the same action: %s
-""" % act) + TestSCons.file_expr)
-
-test.must_match('file4.out', "3\nfile4a.in\nfile4b.in\n")
-
-
-#
-# Two different environments can be used for the same target, so long
-# as the actions have the same signature; a warning is generated.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env2 = env.Clone(DIFFERENT_VARIABLE = 'true')
-env.B(target = 'file5.out', source = 'file5a.in')
-env2.B(target = 'file5.out', source = 'file5b.in')
-""")
-
-test.write('file5a.in', 'file5a.in\n')
-test.write('file5b.in', 'file5b.in\n')
-
-test.run(arguments='file5.out',
- stderr=TestSCons.re_escape("""
-scons: warning: Two different environments were specified for target file5.out,
-\tbut they appear to have the same action: build(target, source, env)
-""") + TestSCons.file_expr)
-
-test.must_match('file5.out', "file5a.in\nfile5b.in\n")
-
-
-#
-# Environments with actions that have different signatures generate
-# an error.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=Action(build, varlist=['XXX']), multi=1)
-env = Environment(BUILDERS = { 'B' : B }, XXX = 'foo')
-env2 = env.Clone(XXX = 'var')
-env.B(target = 'file6.out', source = 'file6a.in')
-env2.B(target = 'file6.out', source = 'file6b.in')
-""")
-
-test.write('file6a.in', 'file6a.in\n')
-test.write('file6b.in', 'file6b.in\n')
-
-test.run(arguments='file6.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Two environments with different actions were specified for the same target: file6.out
-""") + TestSCons.file_expr)
-
-
-#
-# A builder without "multi" set can still be called multiple times
-# if the calls are the same.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=0)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = 'file7.out', source = 'file7.in')
-env.B(target = 'file7.out', source = 'file7.in')
-""")
-
-test.write('file7.in', 'file7.in\n')
-
-test.run(arguments='file7.out')
-
-test.must_match('file7.out', "file7.in\n")
-
-
-#
-# Trying to call a target with two different "multi" builders
-# generates an error.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-def build2(env, target, source):
- build(env, target, source)
-
-B = Builder(action=build, multi=1)
-C = Builder(action=build2, multi=1)
-env = Environment(BUILDERS = { 'B' : B, 'C' : C })
-env.B(target = 'file8.out', source = 'file8.in')
-env.C(target = 'file8.out', source = 'file8.in')
-""")
-
-test.write('file8a.in', 'file8a.in\n')
-test.write('file8b.in', 'file8b.in\n')
-
-test.run(arguments='file8.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Two different builders (B and C) were specified for the same target: file8.out
-""") + TestSCons.file_expr)
-
-
-#
-# A "multi" builder can be called multiple times with the same target list
-# if everything is identical.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- for t in target:
- file = open(str(t), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = ['file9a.out', 'file9b.out'], source = 'file9a.in')
-env.B(target = ['file9a.out', 'file9b.out'], source = 'file9b.in')
-""")
-
-test.write('file9a.in', 'file9a.in\n')
-test.write('file9b.in', 'file9b.in\n')
-
-test.run(arguments='file9b.out')
-
-test.must_match('file9a.out', "file9a.in\nfile9b.in\n")
-test.must_match('file9b.out', "file9a.in\nfile9b.in\n")
-
-
-#
-# A "multi" builder can NOT be called multiple times with target lists
-# that have different orders. This is intentional; the order of the
-# targets matter to the builder because the build command can contain
-# things like ${TARGET[0]}.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- for t in target:
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = ['file10a.out', 'file10b.out'], source = 'file10.in')
-env.B(target = ['file10b.out', 'file10a.out'], source = 'file10.in')
-""")
-
-test.write('file10.in', 'file10.in\n')
-
-test.run(arguments='file10.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Two different target sets have a target in common: file10b.out
-""") + TestSCons.file_expr)
-
-
-#
-# A target file can't be in two different target lists.
-#
-
-# XXX It would be nice if the following two tests could be made to work
-# by executing the action once for each unique set of targets. This
-# would make it simple to deal with PDB files on Windows like so:
-#
-# env.Object(['foo.obj', 'vc60.pdb'], 'foo.c')
-# env.Object(['bar.obj', 'vc60.pdb'], 'bar.c')
-
-test.write('SConstruct', """
-def build(env, target, source):
- for t in target:
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = ['file11a.out', 'file11b.out'], source = 'file11a.in')
-env.B(target = ['file11b.out', 'file11c.out'], source = 'file11b.in')
-""")
-
-test.write('file11a.in', 'file11a.in\n')
-test.write('file11b.in', 'file11b.in\n')
-
-test.run(arguments='file11.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Two different target sets have a target in common: file11b.out
-""") + TestSCons.file_expr)
-
-
-#
-# A target file can't be a lone target and in a list.
-#
-
-test.write('SConstruct', """
-def build(env, target, source):
- for t in target:
- file = open(str(target[0]), 'wb')
- for s in source:
- file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(target = ['file12a.out', 'file12b.out'], source = 'file12a.in')
-env.B(target = 'file12a.out', source = 'file12b.in')
-""")
-
-test.write('file12a.in', 'file12a.in\n')
-test.write('file12b.in', 'file12b.in\n')
-
-test.run(arguments='file12.out',
- status=2,
- stderr=TestSCons.re_escape("""
-scons: *** Cannot build same target `file12a.out' as singular and list
-""") + TestSCons.file_expr)
-
-
-
-test.pass_test()
# by the packaging build.
copyright_marker = '__' + 'COPYRIGHT' + '__'
-copyright_years = '2001, 2002, 2003, 2004, 2005, 2006'
+copyright_years = '2001, 2002, 2003, 2004, 2005, 2006, 2007'
fmt = '(%s|Copyright \\(c\\) %s The SCons Foundation)\n'
#!/usr/bin/env python
#
-# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
+# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
Test the use of a preceding @ to suppress printing a command.
"""
-__revision__ = "/home/scons/scons/branch.0/branch.96/baseline/test/option-n.py 0.96.C352 2005/03/26 00:09:23 knight"
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
os.environ['PYTHONPATH'] = test.workpath('.')
test.write('SConstruct', """
+DefaultEnvironment(tools=[])
def build(env, target, source):
open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
B = Builder(action = build)
-env = Environment(BUILDERS = { 'B' : B })
+env = Environment(tools = [], BUILDERS = { 'B' : B })
env.B(target = 'f1.out', source = 'f1.in')
env.B(target = 'f2.out', source = 'f2.in')
env.B(target = 'f3.out', source = 'f3.in')