From 1cfd65999774eea436c7f69aae211f1a06dc9b0d Mon Sep 17 00:00:00 2001 From: stevenknight Date: Wed, 3 Jul 2002 15:23:57 +0000 Subject: [PATCH] Deduce the target if it's not supplied. git-svn-id: http://scons.tigris.org/svn/scons/trunk@400 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- doc/man/scons.1 | 298 +++++++++++++++++++++------ src/CHANGES.txt | 4 + src/engine/SCons/Builder.py | 31 ++- src/engine/SCons/BuilderTests.py | 73 ++++++- src/engine/SCons/Environment.py | 24 ++- src/engine/SCons/EnvironmentTests.py | 53 ++++- 6 files changed, 395 insertions(+), 88 deletions(-) diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 0241c9b2..f606adb7 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -33,7 +33,7 @@ .RE .fi .. -.TH SCONS 1 "May 2002" +.TH SCONS 1 "July 2002" .SH NAME scons \- a software construction tool .SH SYNOPSIS @@ -542,16 +542,6 @@ Ignored for compatibility with GNU appear up-to-date is unnecessary when using .BR scons .) -.TP --T -Works exactly the same way as the -.B -u -option except for the way default targets are handled. -When this option is used and no targets are specified on the command line, -all default targets that are defined in the SConscript files in the current -directory are built, regardless of what directory the resulant targets end -up in. - .TP -u, --up, --search-up Walks up the directory structure until an @@ -757,34 +747,64 @@ yacc Build rules are specified by calling a construction environment's builder methods. -The arguments to the builder methods are target (a list of -target files) and source (a list of source files). -If a string is given -for target or source, then -.B scons -.I currently -interprets it as a space-delimited list of files. -NOTE: Splitting a string into a list of files this -way will be -.I removed -as of the next version of SCons. -If you currently use space-delimited file lists, -you must change them by next release. -See the discussion of the Split() function -for more information. - -The following are examples of calling the Program builder: - -.ES -# The recommended ways to call a builder -# with multiple source input files: +The arguments to the builder methods are +.B target +(a list of target files) +and +.B source +(a list of source files). + +Because long lists of file names +can lead to a lot of quoting, +.B scons +supplies a +.B Split() +function that splits a single string +into a list, separated on +strings of white-space characters. +(This is similar to the +string.split() method +from the standard Python library.) + +Like all Python arguments, +the target and source arguments to a builder +can be specified either with or without +the "target" and "source" keywords. +When the keywords are omitted, +the target is first, +followed by the source. +The following are equivalent examples of calling the Program builder: + +.ES env.Program('bar', ['bar.c', 'foo.c']) env.Program('bar', Split('bar.c foo.c')) +env.Program(source = ['bar.c', 'foo.c'], target = 'bar') +env.Program(target = 'bar', Split('bar.c foo.c')) +env.Program('bar', source = string.split('bar.c foo.c')) +.EE -# Space-delimited lists. -# The following will NOT work in version 0.08 of SCons! -env.Program(target = 'bar', source = 'bar.c foo.c') -env.Program('bar', 'bar.c foo.c') +When the target shares the same base name +as the source and only the suffix varies, +and if the builder has a suffix defined for the target file type, +then the target argument may be omitted completely, +and +.B scons +will deduce the target file name from +the source file name. +The following examples all build the +executable program +.B bar +(on POSIX systems) +or +.B bar.exe +(on Windows sytems) +from the bar.c source file: + +.ES +env.Program(target = 'bar', source = 'bar.c') +env.Program('bar', source = 'bar.c') +env.Program(source = 'bar.c') +env.Program('bar.c') .EE .B scons @@ -820,8 +840,13 @@ Source files must have one of the following extensions: .SPP assembly language file + C pre-processor .EE .IP -The target object file prefix and suffix (if any) are automatically -added. Examples: +The target object file prefix +(specified by the $OBJPREFIX construction variable; nothing by default) +and suffix +(specified by the $OBJSUFFIX construction variable; +\.obj on Windows systems, .o on POSIX systems) +are automatically added to the target if not already present. +Examples: .ES env.StaticObject(target = 'aaa', source = 'aaa.c') @@ -836,8 +861,13 @@ Source files must have one of the same set of extensions specified above for the .B StaticObject builder. -The target object file prefix and suffix (if any) are automatically -added. Examples: +The target object file prefix +(specified by the $OBJPREFIX construction variable; nothing by default) +and suffix +(specified by the $OBJSUFFIX construction variable; +\.obj on Windows systems, .o on POSIX systems) +are automatically added to the target if not already present. +Examples: .ES env.SharedObject(target = 'ddd', source = 'ddd.c') @@ -861,11 +891,16 @@ builder; see that builder's description for a list of legal source file suffixes and how they are interpreted. -The executable prefix and suffix (if any) are -automatically added to the target. Example: +The target executable file prefix +(specified by the $PROGPREFIX construction variable; nothing by default) +and suffix +(specified by the $PROGSUFFIX construction variable; +by default, .exe on Windows systems, nothing on POSIX systems) +are automatically added to the target if not already present. +Example: .ES -env.Program(target = 'foo', source = 'foo.o bar.c baz.f') +env.Program(target = 'foo', source = ['foo.o', 'bar.c', 'baz.f']) .EE .IP StaticLibrary @@ -874,14 +909,22 @@ or C, C++ or Fortran source files. If any source files are given, then they will be automatically compiled to object files. -The library prefix and suffix (if any) +The static library prefix and suffix (if any) are automatically added to the target. +The target library file prefix +(specified by the $LIBPREFIX construction variable; +by default, lib on POSIX systems, nothing on Windows systems) +and suffix +(specified by the $LIBSUFFIX construction variable; +by default, .lib on Windows systems, .a on POSIX systems) +are automatically added to the target if not already present. Example: .ES -env.StaticLibrary(target = 'bar', source = 'bar.c foo.o') +env.StaticLibrary(target = 'bar', source = ['bar.c', 'foo.o']) .EE +.IP Any object files listed in the .B source must have been built for a static library @@ -899,12 +942,19 @@ or C, C++ or Fortran source files. If any source files are given, then they will be automatically compiled to object files. -The library prefix and suffix (if any) +The static library prefix and suffix (if any) are automatically added to the target. +The target library file prefix +(specified by the $SHLIBPREFIX construction variable; +by default, lib on POSIX systems, nothing on Windows systems) +and suffix +(specified by the $SHLIBSUFFIX construction variable; +by default, .dll on Windows systems, .so on POSIX systems) +are automatically added to the target if not already present. Example: .ES -env.SharedLibrary(target = 'bar', source = 'bar.c foo.o') +env.SharedLibrary(target = 'bar', source = ['bar.c', 'foo.o']) .EE .IP On WIN32 systems, the @@ -984,7 +1034,7 @@ if it is not already present. Example: .ES # builds from aaa.tex env.PDF(target = 'aaa.pdf', source = 'aaa.tex') -# builds bbb.dvi +# builds bbb.pdf from bbb.dvi env.PDF(target = 'bbb', source = 'bbb.dvi') .EE @@ -999,7 +1049,7 @@ if it is not already present. Example: .ES # builds from aaa.tex env.PostScript(target = 'aaa.ps', source = 'aaa.tex') -# builds bbb.dvi +# builds bbb.ps from bbb.dvi env.PostScript(target = 'bbb', source = 'bbb.dvi') .EE .LP @@ -1309,6 +1359,15 @@ and the $ASPPCOM command line used to assemble an assembly language source file, after first running each file through the C preprocessor. +.IP _CPPINCFLAGS +An automatically-generated construction variable +containing the C preprocessor command-line options +for specifying directories to be searched for include files. +The value of $_CPPINCFLAGS is created +by appending $INCPREFIX and $INCSUFFIX +to the beginning and end +of each directory in $CPPPATH. + .IP CPPPATH The list of directories that the C preprocessor will search for include directories. The C/C++ implicit dependency scanner will search these @@ -1334,6 +1393,25 @@ include = Dir('include') env = Environment(CPPPATH=include) .EE +.IP +The directory list will be added to command lines +through the automatically-generated +$_CPPINCFLAGS +construction variable, +which is constructed by +appending the values of the +$INCPREFIX and $INCSUFFIX +construction variables +to the beginning and end +of each directory in $CPPPATH. +Any command lines you define that need +the CPPPATH directory list should +include $_CPPINCFLAGS: + +.ES +env = Environment(CCCOM="my_compiler $_CPPINCFLAGS -c -o $TARGET $SOURCE") +.EE + .IP CXX The C++ compiler. @@ -1429,6 +1507,15 @@ The command line used to compile a Fortran source file to an object file. .IP F77FLAGS General options that are passed to the Fortran compiler. +.IP _F77INCFLAGS +An automatically-generated construction variable +containing the Fortran compiler command-line options +for specifying directories to be searched for include files. +The value of $_F77INCFLAGS is created +by appending $INCPREFIX and $INCSUFFIX +to the beginning and end +of each directory in $F77PATH. + .IP F77PATH The list of directories that the Fortran compiler will search for include directories. The Fortran implicit dependency scanner will search these @@ -1454,6 +1541,25 @@ include = Dir('include') env = Environment(F77PATH=include) .EE +.IP +The directory list will be added to command lines +through the automatically-generated +$_F77INCFLAGS +construction variable, +which is constructed by +appending the values of the +$INCPREFIX and $INCSUFFIX +construction variables +to the beginning and end +of each directory in $F77PATH. +Any command lines you define that need +the F77PATH directory list should +include $_F77INCFLAGS: + +.ES +env = Environment(F77COM="my_compiler $_F77INCFLAGS -c -o $TARGET $SOURCE") +.EE + .IP F77PPCOM The command line used to compile a Fortran source file to an object file after first running the file through the C preprocessor. @@ -1463,10 +1569,18 @@ are included on this command line. .IP INCPREFIX The prefix used to specify an include directory on the C compiler command line. +This will be appended to the beginning of each directory +in the $CPPPATH and $F77PATH construction variables +when the $_CPPINCFLAGS and $_F77INCFLAGS +variables are automatically generated. .IP INCSUFFIX The suffix used to specify an include directory on the C compiler command line. +This will be appended to the end of each directory +in the $CPPPATH and $F77PATH construction variables +when the $_CPPINCFLAGS and $_F77INCFLAGS +variables are automatically generated. .IP LATEX The LaTeX structured formatter and typesetter. @@ -1487,17 +1601,47 @@ General options passed to the lexical analyzer generator. The command line used to call the lexical analyzer generator to generate a source file. +.IP _LIBDIRFLAGS +An automatically-generated construction variable +containing the linker command-line options +for specifying directories to be searched for library. +The value of $_LIBDIRFLAGS is created +by appending $LIBDIRPREFIX and $LIBDIRSUFFIX +to the beginning and end +of each directory in $LIBPATH. + .IP LIBDIRPREFIX The prefix used to specify a library directory on the linker command line. +This will be appended to the beginning of each directory +in the $LIBPATH construction variable +when the $_LIBDIRFLAGS variable is automatically generated. .IP LIBDIRSUFFIX The suffix used to specify a library directory on the linker command line. +This will be appended to the end of each directory +in the $LIBPATH construction variable +when the $_LIBDIRFLAGS variable is automatically generated. + +.IP _LIBFLAGS +An automatically-generated construction variable +containing the linker command-line options +for specifying libraries to be linked with the resulting target. +The value of $_LIBFLAGS is created +by appending $LIBLINKPREFIX and $LIBLINKSUFFIX +to the beginning and end +of each directory in $LIBS. .IP LIBLINKPREFIX The prefix used to specify a library to link on the linker command line. +This will be appended to the beginning of each library +in the $LIBS construction variable +when the $_LIBFLAGS variable is automatically generated. .IP LIBLINKSUFFIX The suffix used to specify a library to link on the linker command line. +This will be appended to the end of each library +in the $LIBS construction variable +when the $_LIBFLAGS variable is automatically generated. .IP LIBPATH The list of directories that will be searched for libraries. @@ -1524,6 +1668,25 @@ libs = Dir('libs') env = Environment(LIBPATH=libs) .EE +.IP +The directory list will be added to command lines +through the automatically-generated +$_LIBDIRFLAGS +construction variable, +which is constructed by +appending the values of the +$LIBDIRPREFIX and $LIBDIRSUFFIX +construction variables +to the beginning and end +of each directory in $LIBPATH. +Any command lines you define that need +the LIBPATH directory list should +include $_LIBDIRFLAGS: + +.ES +env = Environment(LINKCOM="my_linker $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET $SOURCE") +.EE + .IP LIBPREFIX The prefix used for (static) library file names. @@ -1536,6 +1699,25 @@ that will be linked with any executable programs created by this environment. +.IP +The library list will be added to command lines +through the automatically-generated +$_LIBFLAGS +construction variable, +which is constructed by +appending the values of the +$LIBLINKPREFIX and $LIBLINKSUFFIX +construction variables +to the beginning and end +of each directory in $LIBS. +Any command lines you define that need +the LIBS library list should +include $_LIBFLAGS: + +.ES +env = Environment(LINKCOM="my_linker $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET $SOURCE") +.EE + .IP LIBSUFFIX The suffix used for (static) library file names. @@ -1953,17 +2135,6 @@ files = Split(""" f6.c """) .EE -.IP -NOTE: Currently, all builders perform this white-space split -automatically on their target and source file arguments. -As of the next version of SCons, -Builder objects will no longer perform this split. -If you use white-space separated strings of file names, -you will need to convert them to lists -by the next release of SCons by hand, -or by using the Split() function provided here, -or by using a similar function such as the -string.split() function in the Python library. .TP .RI Tool( string ) @@ -2608,12 +2779,7 @@ env.Program(target = 'prog', source = 'p1.c p2.c') .SS Defining Your Own Builder Object -You -.I must -specify a "name" keyword argument for the builder, -as that becomes the Environment method name -you use to call the builder. -Notice also that you can leave off the target file suffix, +Notice that you can leave off the target file suffix, and the builder will add it automatically. .ES diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 8146a261..0054f35a 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -71,6 +71,10 @@ RELEASE 0.08 - - Add support for the GNU as, Microsoft masm, and nasm assemblers. + - Allow the "target" argument to a Builder call to be omitted, in + which case the target(s) are deduced from the source file(s) and the + Builder's specified suffix. + From Jeff Petkau: - Fix --implicit-cache if the scanner returns an empty list. diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 0b54303b..c4e86430 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -56,6 +56,11 @@ import SCons.Node.FS import SCons.Util import SCons.Warnings +class _Null: + pass + +_null = _Null + class DictCmdGenerator: """This is a callable class that can be used as a command generator function. It holds on to a dictionary @@ -142,6 +147,8 @@ def _init_nodes(builder, env, args, tlist, slist): s.source_scanner = scanner for t in tlist: + if t.side_effect: + raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t) if t.builder is not None: if t.env != env: raise UserError, "Two different environments were specified for the same target: %s"%str(t) @@ -267,11 +274,11 @@ class BuilderBase: path, fn = os.path.split(os.path.normpath(f)) f = os.path.join(path, pre + fn) # Only append a suffix if the file does not have one. - if suf and not os.path.splitext(f)[1]: - if f[-len(suf):] != suf: - f = f + suf - ret.append(f) - return ret + if suf and not os.path.splitext(f)[1]: + if f[-len(suf):] != suf: + f = f + suf + ret.append(f) + return ret pre = self.get_prefix(env) suf = self.get_suffix(env) @@ -290,14 +297,20 @@ class BuilderBase: emit_args.update(args) target, source = apply(self.emitter, (), emit_args) - tlist = SCons.Node.arg2nodes(adjustixes(target, pre, suf), - self.target_factory) slist = SCons.Node.arg2nodes(adjustixes(source, None, src_suf), self.source_factory) + if target is None: + target = map(lambda x, s=suf: os.path.splitext(str(x))[0] + s, + slist) + tlist = SCons.Node.arg2nodes(adjustixes(target, pre, suf), + self.target_factory) return tlist, slist - def __call__(self, env, target = None, source = None, **kw): + def __call__(self, env, target = None, source = _null, **kw): + if source is _null: + source = target + target = None tlist, slist = self._create_nodes(env, kw, target, source) if len(tlist) == 1: @@ -456,7 +469,7 @@ class MultiStepBuilder(BuilderBase): src_bld = sdict[ext] dictArgs = copy.copy(kw) - dictArgs['target'] = [ path + src_bld.get_suffix(env) ] + dictArgs['target'] = [path] dictArgs['source'] = snode dictArgs['env'] = env tgt = apply(src_bld, (), dictArgs) diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index c0ed108e..8451d995 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -107,6 +107,7 @@ class BuilderTestCase(unittest.TestCase): self.name = name self.sources = [] self.builder = None + self.side_effect = 0 def __str__(self): return self.name def builder_set(self, builder): @@ -474,7 +475,7 @@ class BuilderTestCase(unittest.TestCase): "Source has unexpected name: %s" % tgt.sources[0].path tgt = b1(env, target = 'tgt3', source = 'src3a src3b') - assert len(tgt.sources) == 1 + assert len(tgt.sources) == 1 assert tgt.sources[0].path == 'src3a src3b.c', \ "Unexpected tgt.sources[0] name: %s" % tgt.sources[0].path @@ -578,9 +579,9 @@ class BuilderTestCase(unittest.TestCase): action='bar', src_builder = builder1, src_suffix = '.foo') - tgt = builder2(env, target='baz', source=['test.bleh.bar', 'test2.foo', 'test3.txt']) - assert str(tgt.sources[0]) == 'test.bleh.foo', str(tgt.sources[0]) - assert str(tgt.sources[0].sources[0]) == 'test.bleh.bar', \ + tgt = builder2(env, target='baz', source=['test.bar', 'test2.foo', 'test3.txt']) + assert str(tgt.sources[0]) == 'test.foo', str(tgt.sources[0]) + assert str(tgt.sources[0].sources[0]) == 'test.bar', \ str(tgt.sources[0].sources[0]) assert str(tgt.sources[1]) == 'test2.foo', str(tgt.sources[1]) assert str(tgt.sources[2]) == 'test3.txt', str(tgt.sources[2]) @@ -654,7 +655,7 @@ class BuilderTestCase(unittest.TestCase): assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder) flag = 0 - tgt = builder(env, target='t5', source=[ 'test5a.foo', 'test5b.inb' ]) + tgt = builder(env, target='t5', source='test5a.foo test5b.inb') try: tgt.build() except SCons.Errors.UserError: @@ -662,7 +663,7 @@ class BuilderTestCase(unittest.TestCase): assert flag, "UserError should be thrown when we build targets with files of different suffixes." flag = 0 - tgt = builder(env, target='t6', source=[ 'test6a.bar', 'test6b.ina' ]) + tgt = builder(env, target='t6', source='test6a.bar test6b.ina') try: tgt.build() except SCons.Errors.UserError: @@ -670,7 +671,7 @@ class BuilderTestCase(unittest.TestCase): assert flag, "UserError should be thrown when we build targets with files of different suffixes." flag = 0 - tgt = builder(env, target='t4', source=[ 'test4a.ina', 'test4b.inb' ]) + tgt = builder(env, target='t4', source='test4a.ina test4b.inb') try: tgt.build() except SCons.Errors.UserError: @@ -775,6 +776,64 @@ class BuilderTestCase(unittest.TestCase): emitter="$FOO") assert builder2 == builder2a, repr(builder2.__dict__) + "\n" + repr(builder2a.__dict__) + def test_no_target(self): + """Test deducing the target from the source.""" + + b = SCons.Builder.Builder(action='foo', suffix='.o') + + tgt = b(env, 'aaa') + assert str(tgt) == 'aaa.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'aaa', map(str, tgt.sources) + + tgt = b(env, 'bbb.c') + assert str(tgt) == 'bbb.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'bbb.c', map(str, tgt.sources) + + tgt = b(env, 'ccc.x.c') + assert str(tgt) == 'ccc.x.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'ccc.x.c', map(str, tgt.sources) + + tgt = b(env, ['d0.c', 'd1.c']) + assert len(tgt) == 2, map(str, tgt) + assert str(tgt[0]) == 'd0.o', map(str, tgt) + assert str(tgt[1]) == 'd1.o', map(str, tgt) + assert len(tgt[0].sources) == 2, map(str, tgt[0].sources) + assert str(tgt[0].sources[0]) == 'd0.c', map(str, tgt[0].sources) + assert str(tgt[0].sources[1]) == 'd1.c', map(str, tgt[0].sources) + assert len(tgt[1].sources) == 2, map(str, tgt[1].sources) + assert str(tgt[1].sources[0]) == 'd0.c', map(str, tgt[1].sources) + assert str(tgt[1].sources[1]) == 'd1.c', map(str, tgt[1].sources) + + tgt = b(env, source='eee') + assert str(tgt) == 'eee.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'eee', map(str, tgt.sources) + + tgt = b(env, source='fff.c') + assert str(tgt) == 'fff.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'fff.c', map(str, tgt.sources) + + tgt = b(env, source='ggg.x.c') + assert str(tgt) == 'ggg.x.o', str(tgt) + assert len(tgt.sources) == 1, map(str, tgt.sources) + assert str(tgt.sources[0]) == 'ggg.x.c', map(str, tgt.sources) + + tgt = b(env, source=['h0.c', 'h1.c']) + assert len(tgt) == 2, map(str, tgt) + assert str(tgt[0]) == 'h0.o', map(str, tgt) + assert str(tgt[1]) == 'h1.o', map(str, tgt) + assert len(tgt[0].sources) == 2, map(str, tgt[0].sources) + assert str(tgt[0].sources[0]) == 'h0.c', map(str, tgt[0].sources) + assert str(tgt[0].sources[1]) == 'h1.c', map(str, tgt[0].sources) + assert len(tgt[1].sources) == 2, map(str, tgt[1].sources) + assert str(tgt[1].sources[0]) == 'h0.c', map(str, tgt[1].sources) + assert str(tgt[1].sources[1]) == 'h1.c', map(str, tgt[1].sources) + + if __name__ == "__main__": suite = unittest.makeSuite(BuilderTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 30e0a536..42aa326f 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -212,9 +212,8 @@ class Environment: self.env = env self.builder = builder - def __call__(self, target = None, source = None, **kw): - return apply(self.builder, (self.env, target, source), - kw) + def __call__(self, *args, **kw): + return apply(self.builder, (self.env,) + args, kw) # This allows a Builder to be executed directly # through the Environment to which it's attached. @@ -356,6 +355,25 @@ class Environment: if len(ret) == 1: ret = ret[0] return ret + + def SideEffect(self, side_effect, target): + """Tell scons that side_effects are built as side + effects of building targets.""" + side_effects = SCons.Node.arg2nodes(side_effect, self.fs.File) + targets = SCons.Node.arg2nodes(target, self.fs.File) + + for side_effect in side_effects: + if side_effect.builder is not None: + raise UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect) + side_effect.add_source(targets) + side_effect.side_effect = 1 + self.Precious(side_effect) + for target in targets: + target.side_effects.append(side_effect) + if len(side_effects) == 1: + return side_effects[0] + else: + return side_effects def subst(self, string): """Recursively interpolates construction variables from the diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 2e7003ac..75e5e83c 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -52,6 +52,7 @@ def diff_env(env1, env2): s2 = s2 + "}\n" return s1 + s2 +called_it = {} built_it = {} class Builder: @@ -59,10 +60,15 @@ class Builder: a target is simply setting a value in the dictionary. """ def __init__(self, name = None): - self.name = name + self.name = name + + def __call__(self, env, **kw): + global called_it + called_it.update(kw) def execute(self, target = None, **kw): - built_it[target] = 1 + global built_it + built_it[target] = 1 @@ -86,7 +92,36 @@ class Scanner: class EnvironmentTestCase(unittest.TestCase): - def test_Builders(self): + def test_Builder_calls(self): + """Test Builder calls through different environments + """ + global called_it + + b1 = Builder() + b2 = Builder() + + env = Environment() + env.Replace(BUILDERS = { 'builder1' : b1, + 'builder2' : b2 }) + called_it = {} + env.builder1(target = 'out1') + assert called_it['target'] == 'out1', called_it + assert not called_it.has_key('source') + + called_it = {} + env.builder2(target = 'out2', xyzzy = 1) + assert called_it['target'] == 'out2', called_it + assert called_it['xyzzy'] == 1, called_it + assert not called_it.has_key('source') + + called_it = {} + env.builder1(foo = 'bar') + assert called_it['foo'] == 'bar', called_it + assert not called_it.has_key('target') + assert not called_it.has_key('source') + + + def test_Builder_execs(self): """Test Builder execution through different environments One environment is initialized with a single @@ -372,6 +407,18 @@ class EnvironmentTestCase(unittest.TestCase): assert 'foo1.in' in map(lambda x: x.path, t.sources) assert 'foo2.in' in map(lambda x: x.path, t.sources) + def test_SideEffect(self): + """Test the SideEffect() method""" + env = Environment() + foo = env.Object('foo.obj', 'foo.cpp') + bar = env.Object('bar.obj', 'bar.cpp') + s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj']) + assert s.side_effect + assert foo.side_effects == [s] + assert bar.side_effects == [s] + assert s.depends_on([bar]) + assert s.depends_on([foo]) + def test_subst(self): """Test substituting construction variables within strings -- 2.26.2