diff options
author | Steven Knight <knight@baldmt.com> | 2007-01-07 07:23:05 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2007-01-07 07:23:05 (GMT) |
commit | 8e31352a5b5a500263a8d0d3aee7288970a67b4c (patch) | |
tree | 05e6aee9b46b530443e01bbb762b68775a6bb0ff /src | |
parent | a4fa510f9025ccb4ffeddefe26ce17e01c6a2b8f (diff) | |
download | SCons-8e31352a5b5a500263a8d0d3aee7288970a67b4c.zip SCons-8e31352a5b5a500263a8d0d3aee7288970a67b4c.tar.gz SCons-8e31352a5b5a500263a8d0d3aee7288970a67b4c.tar.bz2 |
Merged revisions 1738-1754,1756 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core
........
r1741 | stevenknight | 2006-12-16 22:51:07 -0600 (Sat, 16 Dec 2006) | 1 line
0.96.D527 - Give the f90 and f95 Tool modules knowledge of how to build source files of earlier Fortran versions.
........
r1742 | stevenknight | 2006-12-16 23:22:54 -0600 (Sat, 16 Dec 2006) | 1 line
0.96.D528 - Better handling of timestamp fallback if there's no md5 module.
........
r1743 | stevenknight | 2006-12-17 00:21:31 -0600 (Sun, 17 Dec 2006) | 1 line
0.96.D529 - Fix portability of new tests on systems that don't have TeX installed.
........
r1744 | stevenknight | 2006-12-19 15:30:16 -0600 (Tue, 19 Dec 2006) | 1 line
0.96.D530 - Eliminate the ListBuilder subclass in favor of using the Executor's target lists.
........
r1745 | stevenknight | 2006-12-19 18:54:26 -0600 (Tue, 19 Dec 2006) | 1 line
0.96.D531 - Eliminate of MultiStepBuilder as a separate Builder subclass.
........
r1746 | garyo | 2006-12-21 13:21:08 -0600 (Thu, 21 Dec 2006) | 1 line
Minor doc fix, thanks to Douglas Landgraf.
........
r1747 | stevenknight | 2006-12-21 17:13:55 -0600 (Thu, 21 Dec 2006) | 1 line
0.96.D533 - Add CFLAGS for options common to C/C++. (Gary Oberbrunner)
........
r1748 | stevenknight | 2007-01-03 19:48:05 -0600 (Wed, 03 Jan 2007) | 1 line
0.96.D534 - Fix signature storage when targets are retrieved from CacheDir().
........
r1749 | stevenknight | 2007-01-04 16:48:47 -0600 (Thu, 04 Jan 2007) | 1 line
0.96.D535 - Teach the lex and yacc tools about target files generated by different flex/bison options, and about Objective C suffixes. (Pupeno)
........
r1750 | stevenknight | 2007-01-04 17:14:38 -0600 (Thu, 04 Jan 2007) | 1 line
0.96.D536 - Refactor duplicate disambiguation logic in Entry.get_contents().
........
r1751 | stevenknight | 2007-01-05 13:00:54 -0600 (Fri, 05 Jan 2007) | 1 line
0.96.D537 - Fix lprof regression from 0.96.92.
........
r1752 | stevenknight | 2007-01-05 20:43:48 -0600 (Fri, 05 Jan 2007) | 1 line
0.96.D538 - Fix caching of Builder suffix matching (to fix lprof regression).
........
r1753 | stevenknight | 2007-01-06 00:03:16 -0600 (Sat, 06 Jan 2007) | 1 line
0.96.D539 - Fix --include-dir when using MinGW. (Paul)
........
r1754 | stevenknight | 2007-01-06 00:24:53 -0600 (Sat, 06 Jan 2007) | 1 line
0.96.D540 - Make bootstrap.py something useful to execute SCons out of a source directory.
........
r1756 | stevenknight | 2007-01-06 21:32:11 -0600 (Sat, 06 Jan 2007) | 1 line
0.96.D541 - Update the Copyright year string to include 2007. Automate updating the month+year string in man page title headers. Fix hard-coded __revision__ strings that crept into some older tests.
........
Diffstat (limited to 'src')
28 files changed, 564 insertions, 410 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index e7f4937..3678dd1 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -14,6 +14,11 @@ RELEASE 0.97 - XXX - 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 @@ -65,6 +70,19 @@ RELEASE 0.97 - XXX 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(). @@ -93,6 +111,9 @@ RELEASE 0.97 - XXX - 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. @@ -107,6 +128,17 @@ RELEASE 0.97 - XXX 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 diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index d5f566a..d625ed7 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -16,20 +16,9 @@ building new types of files in their configurations, without having to 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 @@ -39,11 +28,6 @@ There is also two proxies that look like Builders: (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: @@ -227,10 +211,9 @@ class OverrideWarner(UserDict.UserDict): """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) @@ -240,13 +223,10 @@ class OverrideWarner(UserDict.UserDict): 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): @@ -284,15 +264,12 @@ 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 @@ -304,7 +281,7 @@ def _node_errors(builder, env, tlist, slist): # 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 @@ -312,22 +289,21 @@ def _node_errors(builder, env, tlist, slist): 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: @@ -388,6 +364,7 @@ class BuilderBase: name = None, chdir = _null, is_explicit = 1, + src_builder = [], **overrides): if __debug__: logInstanceCreation(self, 'Builder.BuilderBase') self._memo = {} @@ -432,6 +409,10 @@ class BuilderBase: 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" @@ -557,6 +538,9 @@ class BuilderBase: 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) @@ -570,31 +554,26 @@ class BuilderBase: 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) @@ -650,35 +629,6 @@ class BuilderBase: 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 = [] @@ -712,72 +662,15 @@ class BuilderBase: """ 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): """ @@ -788,35 +681,26 @@ class MultiStepBuilder(BuilderBase): 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) @@ -834,13 +718,15 @@ class MultiStepBuilder(BuilderBase): 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 @@ -848,39 +734,56 @@ class MultiStepBuilder(BuilderBase): # 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 @@ -888,19 +791,31 @@ class MultiStepBuilder(BuilderBase): """ 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): diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 4e196e2..acf0722 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -147,6 +147,8 @@ class Environment: 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] @@ -716,8 +718,8 @@ class BuilderTestCase(unittest.TestCase): 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") @@ -770,15 +772,17 @@ class BuilderTestCase(unittest.TestCase): 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 @@ -800,22 +804,22 @@ class BuilderTestCase(unittest.TestCase): 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 @@ -1359,9 +1363,8 @@ class BuilderTestCase(unittest.TestCase): 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') @@ -1407,17 +1410,6 @@ class BuilderTestCase(unittest.TestCase): 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' @@ -1529,7 +1521,7 @@ class CompositeBuilderTestCase(unittest.TestCase): 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', @@ -1543,10 +1535,10 @@ class CompositeBuilderTestCase(unittest.TestCase): 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] diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 4761ea0..e2883f4 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -54,7 +54,6 @@ import SCons.Node.Python import SCons.Platform import SCons.SConsign import SCons.Sig -import SCons.Sig.MD5 import SCons.Sig.TimeStamp import SCons.Subst import SCons.Tool @@ -513,6 +512,7 @@ class SubstitutionEnvironment: """ dict = { 'ASFLAGS' : [], + 'CFLAGS' : [], 'CCFLAGS' : [], 'CPPDEFINES' : [], 'CPPFLAGS' : [], @@ -641,6 +641,8 @@ class SubstitutionEnvironment: 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) @@ -1667,8 +1669,15 @@ class Base(SubstitutionEnvironment): 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 diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index f0f73da..c015bc1 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -658,6 +658,7 @@ sys.exit(1) empty = { 'ASFLAGS' : [], + 'CFLAGS' : [], 'CCFLAGS' : [], 'CPPDEFINES' : [], 'CPPFLAGS' : [], @@ -686,6 +687,7 @@ sys.exit(1) "-Wl,-R,rpath2 " + \ "-Wl,-Rrpath3 " + \ "-Wp,-cpp " + \ + "-std=c99 " + \ "-framework Carbon " + \ "-frameworkdir=fwd1 " + \ "-Ffwd2 " + \ @@ -698,6 +700,7 @@ sys.exit(1) 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'), diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 08b8d7d..8db2928 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -48,7 +48,6 @@ import SCons.Action from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Node -import SCons.Sig.MD5 import SCons.Subst import SCons.Util import SCons.Warnings @@ -776,7 +775,7 @@ class Entry(Base): def diskcheck_match(self): pass - def disambiguate(self): + def disambiguate(self, must_exist=None): """ """ if self.isdir(): @@ -802,6 +801,9 @@ class Entry(Base): 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() @@ -825,18 +827,17 @@ class Entry(Base): 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 @@ -1259,7 +1260,13 @@ class FS(LocalFS): 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 @@ -2026,16 +2033,23 @@ class File(Base): 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): @@ -2285,12 +2299,15 @@ class File(Base): 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) diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 434709c..ec3c322 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1224,12 +1224,9 @@ class FSTestCase(_tempdirTestCase): # 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: @@ -1250,7 +1247,7 @@ class FSTestCase(_tempdirTestCase): 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") @@ -1866,12 +1863,8 @@ class EntryTestCase(_tempdirTestCase): 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") diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index e5d064e..e17666b 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -219,7 +219,7 @@ class Node: # 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): diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 3ad4cc7..22ec188 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -201,6 +201,12 @@ class SConfTestCase(unittest.TestCase): 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()}) diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 6eedbab..96f1526 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -961,6 +961,7 @@ def _main(args, parser): SCons.Warnings.DeprecatedWarning, SCons.Warnings.DuplicateEnvironmentWarning, SCons.Warnings.MissingSConscriptWarning, + SCons.Warnings.NoMD5ModuleWarning, SCons.Warnings.NoMetaclassSupportWarning, SCons.Warnings.NoParallelSupportWarning, SCons.Warnings.MisleadingKeywordsWarning, ] diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 2ea3f0d..04ed19a 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -546,10 +546,7 @@ class Taskmaster: 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: @@ -580,10 +577,7 @@ class Taskmaster: pass def executed(self, node): - try: - tlist = node.builder.targets(node) - except AttributeError: - tlist = [node] + pass def exception_raise(self, exception): exc = exception[:] diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index 4fefb9d..1803eee 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -162,6 +162,13 @@ class Node: 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 diff --git a/src/engine/SCons/Tool/bcc32.py b/src/engine/SCons/Tool/bcc32.py index 826373f..86ca076 100644 --- a/src/engine/SCons/Tool/bcc32.py +++ b/src/engine/SCons/Tool/bcc32.py @@ -63,10 +63,12 @@ def generate(env): 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' diff --git a/src/engine/SCons/Tool/cc.py b/src/engine/SCons/Tool/cc.py index c4114b7..62b945f 100644 --- a/src/engine/SCons/Tool/cc.py +++ b/src/engine/SCons/Tool/cc.py @@ -63,10 +63,12 @@ def generate(env): 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'] = '' diff --git a/src/engine/SCons/Tool/cc.xml b/src/engine/SCons/Tool/cc.xml index 84980db..0ebaf14 100644 --- a/src/engine/SCons/Tool/cc.xml +++ b/src/engine/SCons/Tool/cc.xml @@ -18,9 +18,10 @@ The C compiler. <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> @@ -38,7 +39,13 @@ env = Environment(CCCOMSTR = "Compiling static object $TARGET") <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> @@ -92,7 +99,7 @@ The C compiler used for generating shared-library objects. <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> @@ -111,7 +118,14 @@ env = Environment(SHCCCOMSTR = "Compiling shared object $TARGET") <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> diff --git a/src/engine/SCons/Tool/f90.py b/src/engine/SCons/Tool/f90.py index 2e2b5b1..cb450b6 100644 --- a/src/engine/SCons/Tool/f90.py +++ b/src/engine/SCons/Tool/f90.py @@ -119,6 +119,10 @@ def add_to_env(env): 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' diff --git a/src/engine/SCons/Tool/f95.py b/src/engine/SCons/Tool/f95.py index 9cd2664..7adc80b 100644 --- a/src/engine/SCons/Tool/f95.py +++ b/src/engine/SCons/Tool/f95.py @@ -119,6 +119,13 @@ def add_to_env(env): 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' diff --git a/src/engine/SCons/Tool/icc.py b/src/engine/SCons/Tool/icc.py index 20bf17c..90dece7 100644 --- a/src/engine/SCons/Tool/icc.py +++ b/src/engine/SCons/Tool/icc.py @@ -40,7 +40,7 @@ def generate(env): 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'] = '' diff --git a/src/engine/SCons/Tool/lex.py b/src/engine/SCons/Tool/lex.py index 3331f6c..31f21a9 100644 --- a/src/engine/SCons/Tool/lex.py +++ b/src/engine/SCons/Tool/lex.py @@ -33,23 +33,60 @@ selection method. __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"]) diff --git a/src/engine/SCons/Tool/mingw.py b/src/engine/SCons/Tool/mingw.py index d679b53..0639535 100644 --- a/src/engine/SCons/Tool/mingw.py +++ b/src/engine/SCons/Tool/mingw.py @@ -145,7 +145,7 @@ def generate(env): 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: diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py index 80b5926..7e476f5 100644 --- a/src/engine/SCons/Tool/msvc.py +++ b/src/engine/SCons/Tool/msvc.py @@ -687,10 +687,12 @@ def generate(env): 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' diff --git a/src/engine/SCons/Tool/mwcc.py b/src/engine/SCons/Tool/mwcc.py index 52f55ee..a1ede44 100644 --- a/src/engine/SCons/Tool/mwcc.py +++ b/src/engine/SCons/Tool/mwcc.py @@ -171,14 +171,15 @@ def generate(env): 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' diff --git a/src/engine/SCons/Tool/qt.py b/src/engine/SCons/Tool/qt.py index 5077901..4d290c7 100644 --- a/src/engine/SCons/Tool/qt.py +++ b/src/engine/SCons/Tool/qt.py @@ -313,8 +313,8 @@ def generate(env): 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 diff --git a/src/engine/SCons/Tool/yacc.py b/src/engine/SCons/Tool/yacc.py index b8916ae..cbccb29 100644 --- a/src/engine/SCons/Tool/yacc.py +++ b/src/engine/SCons/Tool/yacc.py @@ -34,6 +34,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path +import string import SCons.Defaults import SCons.Tool @@ -42,31 +43,64 @@ import SCons.Util 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' @@ -74,6 +108,7 @@ def generate(env): env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' + env['YACCVCGFILESUFFIX'] = '.vcg' def exists(env): return env.Detect(['bison', 'yacc']) diff --git a/src/engine/SCons/Tool/yacc.xml b/src/engine/SCons/Tool/yacc.xml index 48bb323..8a23d0b 100644 --- a/src/engine/SCons/Tool/yacc.xml +++ b/src/engine/SCons/Tool/yacc.xml @@ -79,3 +79,20 @@ The default value is <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> diff --git a/src/engine/SCons/Warnings.py b/src/engine/SCons/Warnings.py index 27614bf..1b13c96 100644 --- a/src/engine/SCons/Warnings.py +++ b/src/engine/SCons/Warnings.py @@ -54,6 +54,9 @@ class DuplicateEnvironmentWarning(Warning): class MissingSConscriptWarning(Warning): pass +class NoMD5ModuleWarning(Warning): + pass + class NoMetaclassSupportWarning(Warning): pass diff --git a/src/script/scons-time.py b/src/script/scons-time.py index 1867d44..b0feaab 100644 --- a/src/script/scons-time.py +++ b/src/script/scons-time.py @@ -31,6 +31,8 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + import getopt import glob import os diff --git a/src/test_copyrights.py b/src/test_copyrights.py index ce78a8b..2bc951e 100644 --- a/src/test_copyrights.py +++ b/src/test_copyrights.py @@ -25,129 +25,188 @@ __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() |