Merged revisions 1907-1940,1942-1967 via svnmerge from
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 1 Jun 2007 21:14:13 +0000 (21:14 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 1 Jun 2007 21:14:13 +0000 (21:14 +0000)
http://scons.tigris.org/svn/scons/branches/core

........
  r1914 | stevenknight | 2007-05-19 20:18:45 -0700 (Sat, 19 May 2007) | 4 lines

  Use the dict() builtin, not a by-hand function, to assemble --debug=explain
  info.  Update our backwards-compatibility dict() function so its calling
  signature matches the later SCons dict() builtin, and so it actually works.
........
  r1920 | stevenknight | 2007-05-21 19:59:00 -0700 (Mon, 21 May 2007) | 4 lines

  Issue 1652:  only add the {base}_p.c and {base}_data.c files if the
  /proxy or /dlldata arguments are present (respectively).
  (Allan Erskine)
........
  r1921 | stevenknight | 2007-05-21 20:09:54 -0700 (Mon, 21 May 2007) | 2 lines

  Add initial .svnt/conf file for experimental use.
........
  r1924 | stevenknight | 2007-05-22 17:51:34 -0700 (Tue, 22 May 2007) | 3 lines

  Don't let tool initialization overwrite ${C,CXX}FILESUFFIX if they're
  already set.
........
  r1925 | stevenknight | 2007-05-22 19:14:27 -0700 (Tue, 22 May 2007) | 3 lines

  Change the --debug=explain message when AlwaysBuild() is set from
  the default "unknown reasons" to "because AlwaysBuild() is specified."
........
  r1927 | stevenknight | 2007-05-23 05:20:32 -0700 (Wed, 23 May 2007) | 3 lines

  Issue 1658:  Find Java anonymous classes when the next token after
  the name is an open parenthesis.  (Jan Nijtmans)
........
  r1928 | stevenknight | 2007-05-23 11:50:20 -0700 (Wed, 23 May 2007) | 3 lines

  Issue 1313:  add support for {Get,Set}Option('help') and
  {Get,Set}Option('random') .
........
  r1929 | stevenknight | 2007-05-23 11:56:18 -0700 (Wed, 23 May 2007) | 3 lines

  Issue 1362:  Push/retrieve built symlinks to/from a CacheDir() as symlinks,
  not by copying file contents.
........
  r1930 | stevenknight | 2007-05-23 12:55:12 -0700 (Wed, 23 May 2007) | 3 lines

  Issue 1638:  add LaTeX scanner support for finding dependencies from
  \usepackage{} directives.  (Sohail Somani)
........
  r1932 | stevenknight | 2007-05-24 05:06:45 -0700 (Thu, 24 May 2007) | 3 lines

  Add a section mentioning that libraries can be built from mixed lists
  of source code and object files.  (Follow-up from IRC chat.)
........
  r1933 | stevenknight | 2007-05-24 11:18:30 -0700 (Thu, 24 May 2007) | 2 lines

  Issue 1467:  add /opt/SUNWspro/bin to the default execution $PATH on Solaris.
........
  r1934 | stevenknight | 2007-05-24 13:10:01 -0700 (Thu, 24 May 2007) | 3 lines

  Support running tests when Python is in a path that contains
  spaces (like "C:\Program Files\Python...").
........
  r1935 | stevenknight | 2007-05-24 13:11:52 -0700 (Thu, 24 May 2007) | 4 lines

  Issue 1479:  print multiple projects in a Visual Studio 7.[01] solution
  file, generating a separate GUID for each instead of re-using the
  solution GUID.  (Mark Bertoglio)
........
  r1937 | stevenknight | 2007-05-26 14:35:17 -0700 (Sat, 26 May 2007) | 4 lines

  Issue 1659:  when stringifying a generator action, fall back to using
  the default construction environment, not an empty dictionary, if not
  environment was supplied.
........
  r1938 | stevenknight | 2007-05-29 05:14:37 -0700 (Tue, 29 May 2007) | 2 lines

  Re-run tests if any of the test infrastructure changed, too.
........
  r1940 | stevenknight | 2007-05-29 06:58:42 -0700 (Tue, 29 May 2007) | 2 lines

  Issue 1634:  "define HAVE_FEATURE 1" lines in generated config.h files.
........
  r1943 | stevenknight | 2007-05-29 13:24:34 -0700 (Tue, 29 May 2007) | 2 lines

  Issue 1426:  Generalize AlwaysBuild() to non-File Nodes.
........
  r1945 | stevenknight | 2007-05-30 08:15:25 -0700 (Wed, 30 May 2007) | 3 lines

  Clean up emitter unit tests:  subdivide one large test case into
  separate tests, code renaming and reorganizing for readability.
........
  r1947 | stevenknight | 2007-05-30 10:22:49 -0700 (Wed, 30 May 2007) | 4 lines

  Issue 1656:  two PDB fixes:
  1)  support expansion of $TARGET, etc. in emitted file names
  2)  put the output PDB file in the target's build_dir
........
  r1951 | stevenknight | 2007-05-31 12:51:42 -0700 (Thu, 31 May 2007) | 3 lines

  Refactor the checkLogAndStdout() function into a TestSCons method
  so we can split the sub-tests into their own scripts.
........
  r1952 | stevenknight | 2007-05-31 13:00:56 -0700 (Thu, 31 May 2007) | 3 lines

  Also move the definition of what system library we need to use for
  Configure tests into the TestSCons class.
........
  r1953 | stevenknight | 2007-05-31 14:12:16 -0700 (Thu, 31 May 2007) | 2 lines

  Refactor the Configure context subtests into separate scripts.
........
  r1954 | stevenknight | 2007-05-31 14:18:11 -0700 (Thu, 31 May 2007) | 3 lines

  Get rid of the work_dir argument to checkLogAndStdout(), since we're
  no longer executing sub-tests from separate subdirectories.
........
  r1955 | stevenknight | 2007-05-31 14:35:20 -0700 (Thu, 31 May 2007) | 2 lines

  Move the test to its correct subdirectory.  Oops.
........
  r1958 | stevenknight | 2007-06-01 08:35:50 -0700 (Fri, 01 Jun 2007) | 2 lines

  Skip the Visual C/C++ PDB + BuildDir test when not run on Windows.
........
  r1959 | stevenknight | 2007-06-01 09:35:09 -0700 (Fri, 01 Jun 2007) | 2 lines

  Support an AddMethod() global function and construction environment method.
........
  r1960 | stevenknight | 2007-06-01 09:52:59 -0700 (Fri, 01 Jun 2007) | 3 lines

  Python 1.5 compatibility in the test infrastructure added to support
  the refactored Configure tests.
........
  r1963 | stevenknight | 2007-06-01 12:29:48 -0700 (Fri, 01 Jun 2007) | 2 lines

  Python 1.5 compatibility fix for AddMethod().
........

git-svn-id: http://scons.tigris.org/svn/scons/trunk@1968 fdb21ef1-2011-0410-befe-b5e4ea1792b1

60 files changed:
.svnt/conf [new file with mode: 0644]
QMTest/TestSCons.py
doc/man/scons.1
doc/user/caching.in
doc/user/libraries.in
doc/user/libraries.sgml
doc/user/main.in
src/CHANGES.txt
src/RELEASE.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Conftest.py
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Platform/sunos.py
src/engine/SCons/Scanner/LaTeX.py
src/engine/SCons/Script/Main.py
src/engine/SCons/Script/__init__.py
src/engine/SCons/Taskmaster.py
src/engine/SCons/TaskmasterTests.py
src/engine/SCons/Tool/JavaCommon.py
src/engine/SCons/Tool/JavaCommonTests.py
src/engine/SCons/Tool/__init__.py
src/engine/SCons/Tool/midl.py
src/engine/SCons/Tool/mslink.py
src/engine/SCons/Tool/msvs.py
src/engine/SCons/Util.py
src/engine/SCons/compat/builtins.py
test/AddMethod.py [new file with mode: 0644]
test/AlwaysBuild.py
test/CFILESUFFIX.py
test/CXX/CXXFILESUFFIX.py
test/CacheDir/symlink.py [new file with mode: 0644]
test/Configure/Action-error.py [new file with mode: 0644]
test/Configure/BuildDir-SConscript.py [new file with mode: 0644]
test/Configure/BuildDir.py [new file with mode: 0644]
test/Configure/Builder-call.py [new file with mode: 0644]
test/Configure/Configure.py [deleted file]
test/Configure/ConfigureDryRunError.py [new file with mode: 0644]
test/Configure/SConscript.py [new file with mode: 0644]
test/Configure/basic.py [new file with mode: 0644]
test/Configure/cache-not-ok.py [new file with mode: 0644]
test/Configure/cache-ok.py [new file with mode: 0644]
test/Configure/config-h.py [new file with mode: 0644]
test/Configure/custom-tests.py [new file with mode: 0644]
test/Configure/option--Q.py [new file with mode: 0644]
test/Configure/option--config.py [new file with mode: 0644]
test/GetOption/help.py [new file with mode: 0644]
test/IDL/MIDLCOM.py
test/MSVC/multiple-pdb.py [new file with mode: 0644]
test/MSVC/pdb-BuildDir-path.py [new file with mode: 0644]
test/MSVS/vs-7.0-files.py
test/MSVS/vs-7.1-files.py
test/TEX/usepackage.py [new file with mode: 0644]
test/explain.py
test/option--random.py

diff --git a/.svnt/conf b/.svnt/conf
new file mode 100644 (file)
index 0000000..255a4ac
--- /dev/null
@@ -0,0 +1,18 @@
+import os
+import sys
+
+python = os.environ.get('PYTHON', sys.executable)
+
+cmd = '"%(python)s" runtest.py -q --noqmtest %%s' % locals()
+
+test_inputs = [
+    'src/*.py',
+    'QMTest/*.py',
+]
+
+tests = (
+    ('src/*Tests.py', cmd),
+    ('test/*.py', cmd),
+)
+
+valid_regression_results = [0, 2]
index 196c24ef847fd5c8ecf6cf2def074d85fceb4536..8d820b60446e8335efb27e000eda1e15867448cf 100644 (file)
@@ -18,9 +18,21 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import os
 import os.path
+import re
 import string
 import sys
 
+import __builtin__
+try:
+    __builtin__.zip
+except AttributeError:
+    def zip(*lists):
+        result = []
+        for i in xrange(len(lists[0])):
+            result.append(tuple(map(lambda l, i=i: l[i], lists)))
+        return result
+    __builtin__.zip = zip
+
 from TestCommon import *
 from TestCommon import __all__
 
@@ -576,6 +588,131 @@ print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
                 return p
         return apply(os.path.join, [vs_path] + sub_paths[version][0])
 
+
+    NCR = 0 # non-cached rebuild
+    CR  = 1 # cached rebuild (up to date)
+    NCF = 2 # non-cached build failure
+    CF  = 3 # cached build failure
+
+    if sys.platform == 'win32':
+        Configure_lib = 'msvcrt'
+    else:
+        Configure_lib = 'm'
+
+    # to use cygwin compilers on cmd.exe -> uncomment following line
+    #Configure_lib = 'm'
+
+    def checkLogAndStdout(self, checks, results, cached,
+                          logfile, sconf_dir, sconstruct,
+                          doCheckLog=1, doCheckStdout=1):
+
+        class NoMatch:
+            def __init__(self, p):
+                self.pos = p
+
+        def matchPart(log, logfile, lastEnd):
+            m = re.match(log, logfile[lastEnd:])
+            if not m:
+                raise NoMatch, lastEnd
+            return m.end() + lastEnd
+        try:
+            #print len(os.linesep)
+            ls = os.linesep
+            nols = "("
+            for i in range(len(ls)):
+                nols = nols + "("
+                for j in range(i):
+                    nols = nols + ls[j]
+                nols = nols + "[^" + ls[i] + "])"
+                if i < len(ls)-1:
+                    nols = nols + "|"
+            nols = nols + ")"
+            lastEnd = 0
+            logfile = self.read(self.workpath(logfile))
+            if (doCheckLog and
+                string.find( logfile, "scons: warning: The stored build "
+                             "information has an unexpected class." ) >= 0):
+                self.fail_test()
+            sconf_dir = sconf_dir
+            sconstruct = sconstruct
+
+            log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls
+            if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
+            log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
+            if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
+            rdstr = ""
+            cnt = 0
+            for check,result,cache_desc in zip(checks, results, cached):
+                log   = re.escape("scons: Configure: " + check) + ls
+                if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
+                log = ""
+                result_cached = 1
+                for bld_desc in cache_desc: # each TryXXX
+                    for ext, flag in bld_desc: # each file in TryBuild
+                        file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
+                        if flag == self.NCR:
+                            # rebuild will pass
+                            if ext in ['.c', '.cpp']:
+                                log=log + re.escape(file + " <-") + ls
+                                log=log + r"(  \|" + nols + "*" + ls + ")+?"
+                            else:
+                                log=log + "(" + nols + "*" + ls +")*?"
+                            result_cached = 0
+                        if flag == self.CR:
+                            # up to date
+                            log=log + \
+                                 re.escape("scons: Configure: \"%s\" is up to date." 
+                                           % file) + ls
+                            log=log+re.escape("scons: Configure: The original builder "
+                                              "output was:") + ls
+                            log=log+r"(  \|.*"+ls+")+"
+                        if flag == self.NCF:
+                            # non-cached rebuild failure
+                            log=log + "(" + nols + "*" + ls + ")*?"
+                            result_cached = 0
+                        if flag == self.CF:
+                            # cached rebuild failure
+                            log=log + \
+                                 re.escape("scons: Configure: Building \"%s\" failed "
+                                           "in a previous run and all its sources are"
+                                           " up to date." % file) + ls
+                            log=log+re.escape("scons: Configure: The original builder "
+                                              "output was:") + ls
+                            log=log+r"(  \|.*"+ls+")+"
+                    cnt = cnt + 1
+                if result_cached:
+                    result = "(cached) " + result
+                rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
+                log=log + re.escape("scons: Configure: " + result) + ls + ls
+                if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
+                log = ""
+            if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
+            if doCheckLog and lastEnd != len(logfile):
+                raise NoMatch, lastEnd
+            
+        except NoMatch, m:
+            print "Cannot match log file against log regexp."
+            print "log file: "
+            print "------------------------------------------------------"
+            print logfile[m.pos:]
+            print "------------------------------------------------------"
+            print "log regexp: "
+            print "------------------------------------------------------"
+            print log
+            print "------------------------------------------------------"
+            self.fail_test()
+
+        if doCheckStdout:
+            exp_stdout = self.wrap_stdout(".*", rdstr)
+            if not self.match_re_dotall(self.stdout(), exp_stdout):
+                print "Unexpected stdout: "
+                print "-----------------------------------------------------"
+                print repr(self.stdout())
+                print "-----------------------------------------------------"
+                print repr(exp_stdout)
+                print "-----------------------------------------------------"
+                self.fail_test()
+
 # In some environments, $AR will generate a warning message to stderr
 # if the library doesn't previously exist and is being created.  One
 # way to fix this is to tell AR to be quiet (sometimes the 'c' flag),
index 73e3df93fd9bdb1d9d566c28bb8b243bb338e916..c0b91ecd070c4deeb7cac48ea1eafc06d9be0ccf 100644 (file)
@@ -1973,6 +1973,59 @@ The
 form delays all variable expansion
 until the Action object is actually used.
 
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP 
+.RI AddMethod( object, function ", [" name ])
+.TP
+.RI env.AddMethod( function ", [" name ])
+When called with the
+.BR AddMethod ()
+form,
+adds the specified
+.I function
+to the specified
+.I object
+as the specified method
+.IR name .
+When called with the
+.BR env.AddMethod ()
+form,
+adds the specified
+.I function
+to the construction environment
+.I env
+as the specified method
+.IR name .
+In both cases, if
+.I name
+is omitted or
+.BR None ,
+the name of the
+specified
+.I function
+itself is used for the method name.
+
+.ES
+# Note that the first argument to the function to
+# be attached as a method must be the object through
+# which the method will be called; the Python
+# convention is to call it 'self'.
+def my_method(self, arg):
+    print "my_method() got", arg
+
+# Use the global AddMethod() function to add a method
+# to the Environment class.  This
+AddMethod(Environment, my_method)
+env = Environment()
+env.my_method('arg')
+
+# Add the function as a method, using the function
+# name for the method call.
+env = Environment()
+env.AddMethod(my_method, 'other_method_name')
+env.other_method_name('another arg')
+.EE
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP 
 .RI AddPostAction( target ", " action )
@@ -4048,16 +4101,19 @@ if not env.has_key('FOO'): env['FOO'] = 'foo'
 This function provides a way to set a select subset of the scons command
 line options from a SConscript file. The options supported are:
 .B clean
-which corresponds to -c, --clean, and --remove;
+which corresponds to -c, --clean and --remove;
 .B duplicate
-which 
-corresponds to --duplicate;
+which corresponds to --duplicate;
+.B help
+which corresponds to -h and --help;
 .B implicit_cache
 which corresponds to --implicit-cache;
 .B max_drift
 which corresponds to --max-drift;
 .B num_jobs
 which corresponds to -j and --jobs.
+.B random
+which corresponds to --random.
 See the documentation for the
 corresponding command line object for information about each specific
 option. Example:
index 015407bed62e5338296a5c260f94957d9242abff..8dfa731c56bf2e4ce51557eef9cd8b55b5525e06 100644 (file)
 
     </para>
 
+    <para>
+
+    If you want to make sure dependencies will be built
+    in a random order without having to specify
+    the <literal>--random</literal> on very command line,
+    you can use the &SetOption; function to
+    set the <literal>random</litera> option
+    within any &SConscript; file:
+
+    </para>
+
+    <scons_example name="ex-random">
+       <file name="SConstruct" printme="1">
+       SetOption('random', 1)
+       Program('prog',
+               ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c'])
+       </file>
+       <file name="f1.c">f1.c</file>
+       <file name="f2.c">f2.c</file>
+       <file name="f3.c">f3.c</file>
+       <file name="f4.c">f4.c</file>
+       <file name="f5.c">f5.c</file>
+       <file name="f6.c">f6.c</file>
+    </scons_example>
+
   </section>
 
   <!--
index e5368d17b9e723e710e3b753bd26ee5ce6a5cdaa..9a120622444fe480e6bda2eee7dcd074e51e2a4e 100644 (file)
 
     </para>
 
+    <section>
+    <title>Building Libraries From Source Code or Object Files</title>
+
+      <para>
+
+      The previous example shows building a library from a
+      list of source files.
+      You can, however, also give the &b-link-Library; call
+      object files,
+      and it will correctly realize
+      In fact, you can arbitrarily mix source code files
+      and object files in the source list:
+
+      </para>
+
+      <para>
+
+      <scons_example name="objects" printme="1">
+        <file name="SConstruct" printme="1">
+        Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])
+        </file>
+        <file name="f1.c">
+        void f1() { printf("f1.c\n"); }
+        </file>
+        <file name="f2.o">
+        object file
+        </file>
+        <file name="f3.c">
+        void f3() { printf("f3.c\n"); }
+        </file>
+        <file name="f4.o">
+        object file
+        </file>
+      </scons_example>
+
+      <para>
+
+      And SCons realizes that only the source code files
+      must be compiled into object files
+      before creating the final library:
+
+      </para>
+
+      <scons_output example="objects" os="posix">
+        <scons_output_command>scons -Q</scons_output_command>
+      </scons_output>
+
+      <para>
+
+      Of course, in this example, the object files
+      must already exist for the build to succeed.
+      See <xref linkend="chap-nodes">, below,
+      for information about how you can
+      build object files explicitly
+      and include the built files in a library.
+
+      </para>
+
+    </section>
+
     <section>
     <title>Building Static Libraries Explicitly:  the &b-StaticLibrary; Builder</title>
 
index ca2cb9734e5f74ca92ef58e4f0e4c372edf70732..96814a70964899c814bf13b31eb4823e0bbc0bfa 100644 (file)
 
     </para>
 
+    <section>
+    <title>Building Libraries From Source Code or Object Files</title>
+
+      <para>
+
+      The previous example shows building a library from a
+      list of source files.
+      You can, however, also give the &b-link-Library; call
+      object files,
+      and it will correctly realize
+      In fact, you can arbitrarily mix source code files
+      and object files in the source list:
+
+      </para>
+
+      <para>
+
+      <programlisting>
+        Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])
+      </programlisting>
+
+      <para>
+
+      And SCons realizes that only the source code files
+      must be compiled into object files
+      before creating the final library:
+
+      </para>
+
+      <screen>
+        % <userinput>scons -Q</userinput>
+        cc -o f1.o -c f1.c
+        cc -o f3.o -c f3.c
+        ar rc libfoo.a f1.o f2.o f3.o f4.o
+        ranlib libfoo.a
+      </screen>
+
+      <para>
+
+      Of course, in this example, the object files
+      must already exist for the build to succeed.
+      See <xref linkend="chap-nodes">, below,
+      for information about how you can
+      build object files explicitly
+      and include the built files in a library.
+
+      </para>
+
+    </section>
+
     <section>
     <title>Building Static Libraries Explicitly:  the &b-StaticLibrary; Builder</title>
 
index d8643504d67692fd51cbd7d9ccdc187707c2b411..aaddb2a5d3593eecc1f3f0eff45643740714ac2d 100644 (file)
   XXX SetOption('duplicate')
   XXX - - duplicate=
 
+  XXX GetOption('help')
+  XXX SetOption('help')
+
   XXX GetOption('num_jobs')
   XXX SetOption('num_jobs')
 
index a47992a70d26b9d95a69bb18ccdd38370b445813..9cf69e9073ba0d87d3632d5de8bff304ce2af9f5 100644 (file)
@@ -8,6 +8,71 @@
 
 
 
+RELEASE 0.97.X - XXX
+
+  From Mark Bertoglio:
+
+  - Fix listing multiple projects in Visual Studio 7.[01] solution files,
+    including generating individual project GUIDs instead of re-using
+    the solution GUID.
+
+  From Jean Brouwers:
+
+  - Add /opt/SUNWspro/bin to the default execution PATH on Solaris.
+
+  From Allan Erskine:
+
+  - Only expect the Microsoft IDL compiler to emit *_p.c and *_data.c
+    files if the /proxy and /dlldata switches are used (respectively).
+
+  From Steven Knight:
+
+  - Have --debug=explain report if a target is being rebuilt because
+    AlwaysBuild() is specified (instead of "unknown reasons").
+
+  - Support {Get,Set}Option('help') to make it easier for SConscript
+    files to tell if a help option (-h, --help, etc.) has been specified.
+
+  - Support {Get,Set}Option('random') so random-dependency interaction
+    with CacheDir() is controllable from SConscript files.
+
+  - Push and retrieve built symlinks to/from a CacheDir() as actual
+    symlinks, not by copying the file contents.
+
+  - Fix how the Action module handles stringifying the shared library
+    generator in the Tool/mingw.py module.
+
+  - When generating a config.h file, print "#define HAVE_{FEATURE} 1"
+    instad of just "#define HAVE_{FEATURE}", for more compatibility
+    with Autoconf-style projects.
+
+  - Fix expansion of $TARGET, $TARGETS, $SOURCE and $SOURCES keywords in
+    Visual C/C++ PDB file names.
+    
+  - Fix locating Visual C/C++ PDB files in build directories.
+
+  - Support an env.AddMethod() method and an AddMethod() global function
+    for adding a new method, respectively, to a construction environment
+    or an arbitrary object (such as a class).
+
+  From Leanid Nazdrynau:
+
+  - When applying Tool modules after a construction environment has
+    already been created, don't overwrite existing $CFILESUFFIX and
+    $CXXFILESUFFIX value.
+
+  From Jan Nijtmans:
+
+  - Find Java anonymous classes when the next token after the name is
+    an open parenthesis.
+
+  From Sohail Somani:
+
+  - Add LaTeX scanner support for finding dependencies specified with
+    the \usepackage{} directive.
+
+
+
 RELEASE 0.97 - Thu, 17 May 2007 08:59:41 -0500
 
   From Steven Knight:
index b19a39cd77bea9e49f704394d4fb39c2f5da61b7..6dd66aaf51912e8b3eb52620d6d68d700463842b 100644 (file)
@@ -25,6 +25,33 @@ RELEASE 0.97 - Thu, 12 Apr 2007 12:36:25 -0500
   This is the eighth beta release of SCons.  Please consult the
   CHANGES.txt file for a list of specific changes since last release.
 
+  Please note the following important changes since release 0.97:
+
+    --  THE DEFAULT EXECUTION PATH FOR Solaris HAS CHANGED
+
+        On Solaris systems, SCons now adds the "/opt/SUNWspro/bin"
+        directory to the default execution $PATH variable before the
+        "/usr/ccs/bin" directory.  This was done to reflect the fact
+        that /opt/SUNWspro/ is the default for SUN tools, but it may
+        cause a different compiler to be used if you have compilers
+        installed in both directories.
+
+    --  GENERATED config.h FILES NOW SAY "#define HAVE_{FEATURE} 1"
+
+        When generating a "config.h" file, SCons now defines values that
+        record the existence of a feature with a "1" value:
+
+            #define HAVE_FEATURE 1
+
+        Instead of printing the line without a "1", as it used to:
+
+            #define HAVE_FEATURE
+
+        This should not cause any problems in the normal use of "#ifdef
+        HAVE_{FEATURE}" statements interpreted by a C preprocessor, but
+        might cause a compatibility issue if a script or other utility
+        was looking for an exact match of the previous text.
+
   Please note the following important changes since release 0.96.93:
 
     --  THE --debug=memoizer OPTION NOW REQUIRES PYTHON 2.2 OR LATER
index 438588ba88e280d44f5ec3cb3cd93e29664c5e2e..a010c4a7772580958edfe476eb5180837c989405 100644 (file)
@@ -515,9 +515,11 @@ class CommandGeneratorAction(ActionBase):
 
     def __str__(self):
         try:
-            env = self.presub_env or {}
+            env = self.presub_env
         except AttributeError:
-            env = {}
+            env = None
+        if env is None:
+            env = SCons.Defaults.DefaultEnvironment()
         act = self._generate([], [], env, 1)
         return str(act)
 
index 08373c3fb5cb96d916bc9770b6917bfc8e55dd4c..87fb4b0810046e155d87c9c25c971d2a14c88dec 100644 (file)
@@ -1261,6 +1261,14 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
         """Test the pre-substitution strings for command generator Actions
         """
         def f(target, source, env, for_signature, self=self):
+
+            # See if "env" is really a construction environment (or
+            # looks like one) by accessing the FindIxes attribute.
+            # (The Tool/mingw.py module has a generator that uses this,
+            # and the __str__() method used to cause problems by passing
+            # us a regular dictionary as a fallback.)
+
+            env.FindIxes
             return "FOO"
         a = SCons.Action.CommandGeneratorAction(f)
         s = str(a)
index ecc93c076af6c5a666e5a42e91fd69898ee746a0..c4b1d1dc641e0029241d5f95c652dcb57dde0c95 100644 (file)
@@ -520,6 +520,9 @@ class BuilderBase:
                     t.builder_set(self)
                     new_targets.append(t)
 
+            orig_tlist = tlist[:]
+            orig_slist = slist[:]
+
             target, source = self.emitter(target=tlist, source=slist, env=env)
 
             # Now delete the temporary builders that we attached to any
@@ -533,8 +536,10 @@ class BuilderBase:
 
             # Have to call arg2nodes yet again, since it is legal for
             # emitters to spit out strings as well as Node instances.
-            tlist = env.arg2nodes(target, target_factory)
-            slist = env.arg2nodes(source, source_factory)
+            tlist = env.arg2nodes(target, target_factory,
+                                  target=orig_tlist, source=orig_slist)
+            slist = env.arg2nodes(source, source_factory,
+                                  target=orig_tlist, source=orig_slist)
 
         return tlist, slist
 
index bb5a69a417c6872ff5c1e058ceca870fc9442bb7..3996d5c6142c6507dfb4e846857fb6ff23ce454d 100644 (file)
@@ -33,6 +33,7 @@ def Func():
 import os.path
 import sys
 import types
+import StringIO
 import unittest
 import UserList
 
@@ -43,6 +44,8 @@ import SCons.Builder
 import SCons.Environment
 import SCons.Errors
 
+sys.stdout = StringIO.StringIO()
+
 # Initial setup of the common environment for all tests,
 # a temporary working directory containing a
 # script for writing arguments to an output file.
@@ -95,7 +98,7 @@ class Environment:
                    source=None, dict=None, conv=None):
         return SCons.Util.scons_subst_list(string, self, raw, target,
                                            source, dict, conv)
-    def arg2nodes(self, args, factory):
+    def arg2nodes(self, args, factory, **kw):
         global env_arg2nodes_called
         env_arg2nodes_called = 1
         if not SCons.Util.is_List(args):
@@ -1210,28 +1213,32 @@ class BuilderTestCase(unittest.TestCase):
         assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
         assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
 
-        # Test that, if an emitter sets a builder on the passed-in
-        # targets and passes back new targets, the new builder doesn't
-        # get overwritten.
+    def test_emitter_preserve_builder(self):
+        """Test an emitter not overwriting a newly-set builder"""
+        env = Environment()
+
         new_builder = SCons.Builder.Builder(action='new')
         node = MyNode('foo8')
         new_node = MyNode('foo8.new')
-        def emit3(target, source, env, nb=new_builder, nn=new_node):
+
+        def emit(target, source, env, nb=new_builder, nn=new_node):
             for t in target:
                 t.builder = nb
             return [nn], source
             
-        builder3=SCons.Builder.Builder(action='foo',
-                                       emitter=emit3,
-                                       target_factory=MyNode,
-                                       source_factory=MyNode)
-        tgt = builder3(env, target=node, source='bar')[0]
+        builder=SCons.Builder.Builder(action='foo',
+                                      emitter=emit,
+                                      target_factory=MyNode,
+                                      source_factory=MyNode)
+        tgt = builder(env, target=node, source='bar')[0]
         assert tgt is new_node, tgt
-        assert tgt.builder is builder3, tgt.builder
+        assert tgt.builder is builder, tgt.builder
         assert node.builder is new_builder, node.builder
 
-        # Test use of a dictionary mapping file suffixes to
-        # emitter functions
+    def test_emitter_suffix_map(self):
+        """Test mapping file suffixes to emitter functions"""
+        env = Environment()
+
         def emit4a(target, source, env):
             source = map(str, source)
             target = map(lambda x: 'emit4a-' + x[:-3], source)
@@ -1240,61 +1247,86 @@ class BuilderTestCase(unittest.TestCase):
             source = map(str, source)
             target = map(lambda x: 'emit4b-' + x[:-3], source)
             return (target, source)
-        builder4 = SCons.Builder.Builder(action='foo',
-                                         emitter={'.4a':emit4a,
-                                                  '.4b':emit4b},
-                                         target_factory=MyNode,
-                                         source_factory=MyNode)
-        tgt = builder4(env, None, source='aaa.4a')[0]
+
+        builder = SCons.Builder.Builder(action='foo',
+                                        emitter={'.4a':emit4a,
+                                                 '.4b':emit4b},
+                                        target_factory=MyNode,
+                                        source_factory=MyNode)
+        tgt = builder(env, None, source='aaa.4a')[0]
         assert str(tgt) == 'emit4a-aaa', str(tgt)
-        tgt = builder4(env, None, source='bbb.4b')[0]
+        tgt = builder(env, None, source='bbb.4b')[0]
         assert str(tgt) == 'emit4b-bbb', str(tgt)
-        tgt = builder4(env, None, source='ccc.4c')[0]
+        tgt = builder(env, None, source='ccc.4c')[0]
         assert str(tgt) == 'ccc', str(tgt)
 
         def emit4c(target, source, env):
             source = map(str, source)
             target = map(lambda x: 'emit4c-' + x[:-3], source)
             return (target, source)
-        builder4.add_emitter('.4c', emit4c)
-        tgt = builder4(env, None, source='ccc.4c')[0]
+
+        builder.add_emitter('.4c', emit4c)
+        tgt = builder(env, None, source='ccc.4c')[0]
         assert str(tgt) == 'emit4c-ccc', str(tgt)
 
-        # Test a list of emitter functions.
-        def emit5a(target, source, env):
+    def test_emitter_function_list(self):
+        """Test lists of emitter functions"""
+        env = Environment()
+
+        def emit1a(target, source, env):
             source = map(str, source)
-            target = target + map(lambda x: 'emit5a-' + x[:-2], source)
+            target = target + map(lambda x: 'emit1a-' + x[:-2], source)
             return (target, source)
-        def emit5b(target, source, env):
+        def emit1b(target, source, env):
             source = map(str, source)
-            target = target + map(lambda x: 'emit5b-' + x[:-2], source)
+            target = target + map(lambda x: 'emit1b-' + x[:-2], source)
             return (target, source)
-        builder5 = SCons.Builder.Builder(action='foo',
-                                         emitter=[emit5a, emit5b],
+        builder1 = SCons.Builder.Builder(action='foo',
+                                         emitter=[emit1a, emit1b],
                                          node_factory=MyNode)
 
-        tgts = builder5(env, target='target-5', source='aaa.5')
+        tgts = builder1(env, target='target-1', source='aaa.1')
         tgts = map(str, tgts)
-        assert tgts == ['target-5', 'emit5a-aaa', 'emit5b-aaa'], tgts
+        assert tgts == ['target-1', 'emit1a-aaa', 'emit1b-aaa'], tgts
 
         # Test a list of emitter functions through the environment.
-        def emit6a(target, source, env):
+        def emit2a(target, source, env):
             source = map(str, source)
-            target = target + map(lambda x: 'emit6a-' + x[:-2], source)
+            target = target + map(lambda x: 'emit2a-' + x[:-2], source)
             return (target, source)
-        def emit6b(target, source, env):
+        def emit2b(target, source, env):
             source = map(str, source)
-            target = target + map(lambda x: 'emit6b-' + x[:-2], source)
+            target = target + map(lambda x: 'emit2b-' + x[:-2], source)
             return (target, source)
-        builder6 = SCons.Builder.Builder(action='foo',
+        builder2 = SCons.Builder.Builder(action='foo',
                                          emitter='$EMITTERLIST',
                                          node_factory=MyNode)
                                          
-        env = Environment(EMITTERLIST = [emit6a, emit6b])
+        env = Environment(EMITTERLIST = [emit2a, emit2b])
 
-        tgts = builder6(env, target='target-6', source='aaa.6')
+        tgts = builder2(env, target='target-2', source='aaa.2')
         tgts = map(str, tgts)
-        assert tgts == ['target-6', 'emit6a-aaa', 'emit6b-aaa'], tgts
+        assert tgts == ['target-2', 'emit2a-aaa', 'emit2b-aaa'], tgts
+
+    def test_emitter_TARGET_SOURCE(self):
+        """Test use of $TARGET and $SOURCE in emitter results"""
+
+        env = SCons.Environment.Environment()
+
+        def emit(target, source, env):
+            return (target + ['${SOURCE}.s1', '${TARGET}.t1'],
+                    source + ['${TARGET}.t2', '${SOURCE}.s2'])
+
+        builder = SCons.Builder.Builder(action='foo',
+                                        emitter = emit,
+                                        node_factory = MyNode)
+
+        targets = builder(env, target = 'TTT', source ='SSS')
+        sources = targets[0].sources
+        targets = map(str, targets)
+        sources = map(str, sources)
+        assert targets == ['TTT', 'SSS.s1', 'TTT.t1'], targets
+        assert sources == ['SSS', 'TTT.t2', 'SSS.s2'], targets
 
     def test_no_target(self):
         """Test deducing the target from the source."""
index 81a8ee4d12d448b7c4cf1b5ac020bf46e02d1921..bb3be56263522d425018d0e1ae7ef0f47ac46daf 100644 (file)
@@ -462,7 +462,7 @@ def _Have(context, key, have):
     key_up = re.sub('[^A-Z0-9_]', '_', key_up)
     context.havedict[key_up] = have
     if have == 1:
-        line = "#define %s\n" % key_up
+        line = "#define %s 1\n" % key_up
     elif have == 0:
         line = "/* #undef %s */\n" % key_up
     elif type(have) == IntType:
index e5eb40c9d6286ab4385c974f5df330045eed731b..94cdf74004668d722fed2a44aede47e0c65ac1c3 100644 (file)
@@ -327,7 +327,7 @@ class SubstitutionEnvironment:
     def items(self):
         return self._dict.items()
 
-    def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
+    def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
         if node_factory is _null:
             node_factory = self.fs.File
         if lookup_list is _null:
@@ -351,7 +351,9 @@ class SubstitutionEnvironment:
                         break
                 if not n is None:
                     if SCons.Util.is_String(n):
-                        n = self.subst(n, raw=1)
+                        # n = self.subst(n, raw=1, **kw)
+                        kw['raw'] = 1
+                        n = apply(self.subst, (n,), kw)
                         if node_factory:
                             n = node_factory(n)
                     if SCons.Util.is_List(n):
@@ -359,7 +361,9 @@ class SubstitutionEnvironment:
                     else:
                         nodes.append(n)
                 elif node_factory:
-                    v = node_factory(self.subst(v, raw=1))
+                    # v = node_factory(self.subst(v, raw=1, **kw))
+                    kw['raw'] = 1
+                    v = node_factory(apply(self.subst, (v,), kw))
                     if SCons.Util.is_List(v):
                         nodes.extend(v)
                     else:
@@ -473,6 +477,14 @@ class SubstitutionEnvironment:
             raise OSError("'%s' exited %d" % (command, status))
         return out
 
+    def AddMethod(self, function, name=None):
+        """
+        Adds the specified function as a method of this construction
+        environment with the specified name.  If the name is omitted,
+        the default name is the name of the function itself.
+        """
+        SCons.Util.AddMethod(self, function, name)
+
     def Override(self, overrides):
         """
         Produce a modified environment whose variables are overriden by
@@ -1453,7 +1465,7 @@ class Base(SubstitutionEnvironment):
     def AlwaysBuild(self, *targets):
         tlist = []
         for t in targets:
-            tlist.extend(self.arg2nodes(t, self.fs.File))
+            tlist.extend(self.arg2nodes(t, self.fs.Entry))
         for t in tlist:
             t.set_always_build()
         return tlist
index 70f90264c15bce9122959dda34386613194f8d83..a8b718dacb00ac5679c700b0b27f5184c2bc27c2 100644 (file)
@@ -357,6 +357,22 @@ class SubstitutionTestCase(unittest.TestCase):
         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
         assert nodes[1].c == 1, nodes[1]
 
+    def test_arg2nodes_target_source(self):
+        """Test the arg2nodes method with target= and source= keywords
+        """
+        targets = [DummyNode('t1'), DummyNode('t2')]
+        sources = [DummyNode('s1'), DummyNode('s2')]
+        env = SubstitutionEnvironment()
+        nodes = env.arg2nodes(['${TARGET}-a',
+                               '${SOURCE}-b',
+                               '${TARGETS[1]}-c',
+                               '${SOURCES[1]}-d'],
+                              DummyNode,
+                              target=targets,
+                              source=sources)
+        names = map(lambda n: n.name, nodes)
+        assert names == ['t1-a', 's1-b', 't2-c', 's2-d'], names
+
     def test_gvars(self):
         """Test the base class gvars() method"""
         env = SubstitutionEnvironment()
@@ -626,6 +642,38 @@ sys.exit(1)
         finally:
             sys.stderr = save_stderr
 
+    def test_AddMethod(self):
+        """Test the AddMethod() method"""
+        env = SubstitutionEnvironment(FOO = 'foo')
+
+        def func(self):
+            return 'func-' + self['FOO']
+
+        assert not hasattr(env, 'func')
+        env.AddMethod(func)
+        r = env.func()
+        assert r == 'func-foo', r
+
+        assert not hasattr(env, 'bar')
+        env.AddMethod(func, 'bar')
+        r = env.bar()
+        assert r == 'func-foo', r
+
+        def func2(self, arg=''):
+            return 'func2-' + self['FOO'] + arg
+
+        env.AddMethod(func2)
+        r = env.func2()
+        assert r == 'func2-foo', r
+        r = env.func2('-xxx')
+        assert r == 'func2-foo-xxx', r
+
+        env.AddMethod(func2, 'func')
+        r = env.func()
+        assert r == 'func2-foo', r
+        r = env.func('-yyy')
+        assert r == 'func2-foo-yyy', r
+
     def test_Override(self):
         "Test overriding construction variables"
         env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4)
@@ -2390,22 +2438,29 @@ def generate(env):
     def test_AlwaysBuild(self):
         """Test the AlwaysBuild() method"""
         env = self.TestEnvironment(FOO='fff', BAR='bbb')
-        t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR')
-        assert t[0].__class__.__name__ == 'File'
+        t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
+                            env.fs.Dir('dir'), env.fs.File('file'))
+        assert t[0].__class__.__name__ == 'Entry'
         assert t[0].path == 'a'
         assert t[0].always_build
-        assert t[1].__class__.__name__ == 'File'
+        assert t[1].__class__.__name__ == 'Entry'
         assert t[1].path == 'bfff'
         assert t[1].always_build
-        assert t[2].__class__.__name__ == 'File'
+        assert t[2].__class__.__name__ == 'Entry'
         assert t[2].path == 'c'
         assert t[2].always_build
-        assert t[3].__class__.__name__ == 'File'
+        assert t[3].__class__.__name__ == 'Entry'
         assert t[3].path == 'd'
         assert t[3].always_build
-        assert t[4].__class__.__name__ == 'File'
+        assert t[4].__class__.__name__ == 'Entry'
         assert t[4].path == 'bbb'
         assert t[4].always_build
+        assert t[5].__class__.__name__ == 'Dir'
+        assert t[5].path == 'dir'
+        assert t[5].always_build
+        assert t[6].__class__.__name__ == 'File'
+        assert t[6].path == 'file'
+        assert t[6].always_build
 
     def test_BuildDir(self):
         """Test the BuildDir() method"""
index a16fee4c9f4e0e561b35535d4deb7aa6d998ba4d..c9a1443f026586e1e3a1c08c287a648141652bd3 100644 (file)
@@ -232,7 +232,10 @@ def CacheRetrieveFunc(target, source, env):
         return 1
     fs.CacheDebug('CacheRetrieve(%s):  retrieving from %s\n', t, cachefile)
     if SCons.Action.execute_actions:
-        fs.copy2(cachefile, t.path)
+        if fs.islink(cachefile):
+            fs.symlink(fs.readlink(cachefile), t.path)
+        else:
+            fs.copy2(cachefile, t.path)
         st = fs.stat(cachefile)
         fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
     return 0
@@ -272,7 +275,10 @@ def CachePushFunc(target, source, env):
 
     tempfile = cachefile+'.tmp'
     try:
-        fs.copy2(t.path, tempfile)
+        if fs.islink(t.path):
+            fs.symlink(fs.readlink(t.path), tempfile)
+        else:
+            fs.copy2(t.path, tempfile)
         fs.rename(tempfile, cachefile)
         st = fs.stat(t.path)
         fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
@@ -2269,8 +2275,6 @@ class File(Base):
         self.binfo = self.gen_binfo(calc)
         return self._cur2()
     def _cur2(self):
-        if self.always_build:
-            return None
         if not self.exists():
             # The file doesn't exist locally...
             r = self.rfile()
index 6644d7a5b706269bb259cf9c86f55045cea54f7a..f550b5b7cebbc29c8c8c957722aabc5e40bb02e8 100644 (file)
@@ -1046,32 +1046,27 @@ class Node:
         if not self.exists():
             return "building `%s' because it doesn't exist\n" % self
 
+        if self.always_build:
+            return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
+
         old = self.get_stored_info()
         if old is None:
             return None
         old.prepare_dependencies()
 
-        def dictify(result, kids, sigs):
-            for k, s in zip(kids, sigs):
-                result[k] = s
-
         try:
-            osig = {}
-            dictify(osig, old.bsources, old.bsourcesigs)
-            dictify(osig, old.bdepends, old.bdependsigs)
-            dictify(osig, old.bimplicit, old.bimplicitsigs)
+            old_bkids    = old.bsources    + old.bdepends    + old.bimplicit
+            old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
         except AttributeError:
             return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
 
         new = self.get_binfo()
 
-        nsig = {}
-        dictify(nsig, new.bsources, new.bsourcesigs)
-        dictify(nsig, new.bdepends, new.bdependsigs)
-        dictify(nsig, new.bimplicit, new.bimplicitsigs)
+        new_bkids    = new.bsources    + new.bdepends    + new.bimplicit
+        new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
 
-        old_bkids = old.bsources + old.bdepends + old.bimplicit
-        new_bkids = new.bsources + new.bdepends + new.bimplicit
+        osig = dict(zip(old_bkids, old_bkidsigs))
+        nsig = dict(zip(new_bkids, new_bkidsigs))
 
         # The sources and dependencies we'll want to report are all stored
         # as relative paths to this target's directory, but we want to
index ed9521e419284805ebcb5cfefb68b0e6a70c9db9..502986088f3d840ba017f90419aebd5aa8cefcee 100644 (file)
@@ -41,4 +41,4 @@ def generate(env):
     env['MAXLINELENGTH']  = 1045320
     env['PKGINFO'] = 'pkginfo'
     env['PKGCHK'] = '/usr/sbin/pkgchk'
-    env['ENV']['PATH'] = env['ENV']['PATH'] + ':/usr/ccs/bin'
+    env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin'
index d875e6e8e6ce074943d8745ecf0cca0b19216bbe..645a894d12d96d8dac567ad23502d68025f6cdff 100644 (file)
@@ -39,7 +39,7 @@ def LaTeXScanner(fs = SCons.Node.FS.default_fs):
     ds = LaTeX(name = "LaTeXScanner",
                suffixes =  '$LATEXSUFFIXES',
                path_variable = 'TEXINPUTS',
-               regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography){([^}]*)}',
+               regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}',
                recursive = 0)
     return ds
 
@@ -72,6 +72,10 @@ class LaTeX(SCons.Scanner.Classic):
             base, ext = os.path.splitext( filename )
             if ext == "":
                 filename = filename + '.bib'
+        if include[0] == 'usepackage':
+            base, ext = os.path.splitext( filename )
+            if ext == "":
+                filename = filename + '.sty'
         return filename
     def sort_key(self, include):
         return SCons.Node.FS._my_normcase(self.latex_name(include))
index ca7f68cfc2910a002c2abe8908d91ad4ef77ddcc..d80050d0e4b822d68935bf8c87559f52612be3eb 100644 (file)
@@ -40,7 +40,6 @@ import SCons.compat
 
 import os
 import os.path
-import random
 import string
 import sys
 import time
@@ -789,7 +788,7 @@ class OptParser(OptionParser):
                         help="Read FILE as the top-level SConstruct file.")
 
         self.add_option('-h', '--help', action="store_true", default=0,
-                        dest="help_msg",
+                        dest="help",
                         help="Print defined help message, or this one.")
 
         self.add_option("-H", "--help-options",
@@ -988,13 +987,18 @@ class SConscriptSettableOptions:
 
         # This dictionary stores the defaults for all the SConscript
         # settable options, as well as indicating which options
-        # are SConscript settable. 
-        self.settable = {'num_jobs':1,
-                         'max_drift':SCons.Node.FS.default_max_drift,
-                         'implicit_cache':0,
-                         'clean':0,
-                         'duplicate':'hard-soft-copy',
-                         'diskcheck':diskcheck_all}
+        # are SConscript settable (and gettable, which for options
+        # like 'help' is far more important than being settable). 
+        self.settable = {
+            'clean'             : 0,
+            'diskcheck'         : diskcheck_all,
+            'duplicate'         : 'hard-soft-copy',
+            'help'              : 0,
+            'implicit_cache'    : 0,
+            'max_drift'         : SCons.Node.FS.default_max_drift,
+            'num_jobs'          : 1,
+            'random'            : 0,
+        }
 
     def get(self, name):
         if not self.settable.has_key(name):
@@ -1118,7 +1122,7 @@ def _main(args, parser):
             scripts.append(sfile)
 
     if not scripts:
-        if options.help_msg:
+        if options.help:
             # There's no SConstruct, but they specified -h.
             # Give them the options usage now, before we fail
             # trying to read a non-existent SConstruct file.
@@ -1225,7 +1229,7 @@ def _main(args, parser):
 
     fs.chdir(fs.Top)
 
-    if options.help_msg:
+    if ssoptions.get('help'):
         help_text = SCons.Script.help_text
         if help_text is None:
             # They specified -h, but there was no Help() inside the
@@ -1341,6 +1345,7 @@ def _main(args, parser):
     if options.random:
         def order(dependencies):
             """Randomize the dependencies."""
+            import random
             # This is cribbed from the implementation of
             # random.shuffle() in Python 2.X.
             d = dependencies
index fde49974e700d2863d92e69e22c2579ba1525c7f..e9709895fa5452ae8087619492f799671643fda9 100644 (file)
@@ -131,6 +131,7 @@ call_stack              = _SConscript.call_stack
 
 #
 Action                  = SCons.Action.Action
+AddMethod               = SCons.Util.AddMethod
 AllowSubstExceptions    = SCons.Subst.SetAllowableExceptions
 BoolOption              = SCons.Options.BoolOption
 Builder                 = SCons.Builder.Builder
index 9a5011b3307c5913eaa8f0d5983cbdae454aa783..acb8c9b5844847ef50bc48f60418fb45bc2c94f1 100644 (file)
@@ -275,8 +275,9 @@ class Task:
         """
         self.out_of_date = []
         for t in self.targets:
+            t.disambiguate()
             try:
-                is_up_to_date = t.disambiguate().current()
+                is_up_to_date = not t.always_build and t.current()
             except EnvironmentError, e:
                 raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename)
             if is_up_to_date:
index 757306fc9a79fc557c91d5c56ef963a36a68f1e5..718851d79212aa8da1ef9d17027651f44f831327 100644 (file)
@@ -63,6 +63,7 @@ class Node:
         self.postprocessed = None
         self._bsig_val = None
         self._current_val = 0
+        self.always_build = None
 
     def disambiguate(self):
         return self
@@ -495,7 +496,10 @@ class TaskmasterTestCase(unittest.TestCase):
         n3 = Node("n3")
         c4 = Node("c4")
         c4._current_val = 1
-        tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4],
+        a5 = Node("a5")
+        a5._current_val = 1
+        a5.always_build = 1
+        tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4, a5],
                                          tasker = TaskGen)
 
         del ood[:]
@@ -514,6 +518,9 @@ class TaskmasterTestCase(unittest.TestCase):
         t = tm.next_task()
         assert ood == [], ood
 
+        del ood[:]
+        t = tm.next_task()
+        assert ood == [a5], ood
 
     def test_make_ready_exception(self):
         """Test handling exceptions from Task.make_ready()
index 177d579dc25d7a63612eb2e97f898dc229cdcb73..d340d5b1d336051b3c3e91ccbb0744324c72c864 100644 (file)
@@ -53,7 +53,7 @@ if java_parsing:
     #     array declarations "[]";
     #     semi-colons;
     #     periods.
-    _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.]|' +
+    _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
                           r'[A-Za-z_][\w\.]*|/\*|\*/|\[\])')
 
     class OuterState:
@@ -90,6 +90,7 @@ if java_parsing:
             try:
                 return self.anonState
             except AttributeError:
+                self.outer_state = self
                 ret = SkipState(1, AnonClassState(self))
                 self.anonState = ret
                 return ret
@@ -154,23 +155,36 @@ if java_parsing:
 
     class AnonClassState:
         """A state that looks for anonymous inner classes."""
-        def __init__(self, outer_state):
+        def __init__(self, old_state):
             # outer_state is always an instance of OuterState
-            self.outer_state = outer_state
-            self.tokens_to_find = 2
+            self.outer_state = old_state.outer_state
+            self.old_state = old_state
+            self.brace_level = 0
         def parseToken(self, token):
-            # This is an anonymous class if and only if the next  
-            # non-whitespace token is a bracket            
-            if token == '\n':
+            # This is an anonymous class if and only if the next
+            # non-whitespace token is a bracket. Everything between
+            # braces should be parsed as normal java code.
+            if token[:2] == '//':
+                return IgnoreState('\n', self)
+            elif token == '/*':
+                return IgnoreState('*/', self)
+            elif token == '\n':
+                return self
+            elif token == '(':
+                self.brace_level = self.brace_level + 1
+                return self
+            if self.brace_level > 0:
+                if token == 'new':
+                    # look further for anonymous inner class
+                    return SkipState(1, AnonClassState(self))
+                elif token in [ '"', "'" ]:
+                    return IgnoreState(token, self)
+                elif token == ')':
+                    self.brace_level = self.brace_level - 1
                 return self
             if token == '{':
-                self.outer_state.openBracket()
                 self.outer_state.addAnonClass()
-            elif token == '}':
-                self.outer_state.closeBracket()
-            elif token in ['"', "'"]:
-                return IgnoreState(token, self)
-            return self.outer_state
+            return self.old_state.parseToken(token)
 
     class SkipState:
         """A state that will skip a specified number of tokens before
index 853afd4de067d9319a3b768cf0e69f1d07c4ac65..e848bf9b42e555fe179299e7746c18e0992bd058 100644 (file)
@@ -329,6 +329,30 @@ public class A {
         assert pkg_dir == None, pkg_dir
         assert classes == ['A$B', 'A'], classes
 
+    def test_anonymous_classes_with_parentheses(self):
+        """Test finding anonymous classes marked by parentheses"""
+        pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\
+import java.io.File;
+
+public class Foo {
+    public static void main(String[] args) {
+        File f = new File(
+            new File("a") {
+                public String toString() {
+                    return "b";
+                }
+            } to String()
+        ) {
+            public String toString() {
+                return "c";
+            }
+        };
+    }
+}
+""")
+        assert classes == ['Foo$1', 'Foo$2', 'Foo'], classes
+
+
 
 
 if __name__ == "__main__":
index b2e2eff95b1306887c2e8ab35c3abe0357511346..dea77fd909235351783357559051daeda9076976 100644 (file)
@@ -316,7 +316,8 @@ def createCFileBuilders(env):
                                        emitter = {},
                                        suffix = {None:'$CFILESUFFIX'})
         env['BUILDERS']['CFile'] = c_file
-        env['CFILESUFFIX'] = '.c'
+
+        env.SetDefault(CFILESUFFIX = '.c')
 
     try:
         cxx_file = env['BUILDERS']['CXXFile']
@@ -325,7 +326,7 @@ def createCFileBuilders(env):
                                          emitter = {},
                                          suffix = {None:'$CXXFILESUFFIX'})
         env['BUILDERS']['CXXFile'] = cxx_file
-        env['CXXFILESUFFIX'] = '.cc'
+        env.SetDefault(CXXFILESUFFIX = '.cc')
 
     return (c_file, cxx_file)
 
index 67579e9af882eea64872471137374a49256a6e27..811d573215234b491f334ebefeee5d2d779e1458 100644 (file)
@@ -33,6 +33,8 @@ selection method.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import string
+
 import SCons.Action
 import SCons.Builder
 import SCons.Defaults
@@ -46,11 +48,17 @@ def midl_emitter(target, source, env):
     tlb = target[0]
     incl = base + '.h'
     interface = base + '_i.c'
-    proxy = base + '_p.c'
-    dlldata = base + '_data.c'
+    t = [tlb, incl, interface]
 
-    t = [tlb, incl, interface, proxy, dlldata]
+    midlcom = env['MIDLCOM']
 
+    if string.find(midlcom, '/proxy') != -1:
+        proxy = base + '_p.c'
+        t.append(proxy)
+    if string.find(midlcom, '/dlldata') != -1:
+        dlldata = base + '_data.c'
+        t.append(dlldata)
+    
     return (t,source)
 
 idl_scanner = SCons.Scanner.IDL.IDLScan()
index 4b90e3dcb47e21138926c3d33ce4b1dc21a01b54..c071aa7eed2652c4c88844a8ce490d87fd567758 100644 (file)
@@ -45,10 +45,10 @@ import SCons.Tool.msvs
 import SCons.Util
 
 def pdbGenerator(env, target, source, for_signature):
-    if target and env.has_key('PDB') and env['PDB']:
-        return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
-                '/DEBUG']
-    return None
+    try:
+        return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG']
+    except (AttributeError, IndexError):
+        return None
 
 def windowsShlinkTargets(target, source, env, for_signature):
     listCmd = []
@@ -99,7 +99,9 @@ def windowsLibEmitter(target, source, env):
                                       "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX"))
 
     if env.has_key('PDB') and env['PDB']:
-        target.append(env['PDB'])
+        pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
+        target.append(pdb)
+        target[0].attributes.pdb = pdb
 
     if not no_import_lib and \
        not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
@@ -129,7 +131,9 @@ def prog_emitter(target, source, env):
                                       "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX"))
 
     if env.has_key('PDB') and env['PDB']:
-        target.append(env['PDB'])
+        pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
+        target.append(pdb)
+        target[0].attributes.pdb = pdb
 
     return (target,source)
 
index db8e8fd7be96300c82efad715cc4c6d09c9f40e4..138f920c72085463a3472bf90dd4fb45955bd8b9 100644 (file)
@@ -1018,8 +1018,10 @@ class _GenerateV7DSW(_DSWGenerator):
                     self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
                                     '\t\t%s.%s|%s.Build.0 = %s|%s\n'  % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
             else:
-                self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
-                                '\t\t%s.%s.Build.0 = %s|%s\n'  %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform))
+                for p in self.dspfiles:
+                    guid = _generateGUID(p, '')
+                    self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
+                                    '\t\t%s.%s.Build.0 = %s|%s\n'  %(guid,variant,variant,platform,guid,variant,variant,platform))
 
         self.file.write('\tEndGlobalSection\n')
 
index f1e856b320dce188d3bbc271e0360b6ed9791676..a5ea859fcd3478c7063a74b510fa16076d315b6b 100644 (file)
@@ -950,3 +950,79 @@ class Unbuffered:
         self.file.flush()
     def __getattr__(self, attr):
         return getattr(self.file, attr)
+
+# The original idea for AddMethod() and RenameFunction() come from the
+# following post to the ActiveState Python Cookbook:
+#
+#      ASPN: Python Cookbook : Install bound methods in an instance
+#      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613
+#
+# That code was a little fragile, though, so the following changes
+# have been wrung on it:
+#
+# * Switched the installmethod() "object" and "function" arguments,
+#   so the order reflects that the left-hand side is the thing being
+#   "assigned to" and the right-hand side is the value being assigned.
+#
+# * Changed explicit type-checking to the "try: klass = object.__class__"
+#   block in installmethod() below so that it still works with the
+#   old-style classes that SCons uses.
+#
+# * Replaced the by-hand creation of methods and functions with use of
+#   the "new" module, as alluded to in Alex Martelli's response to the
+#   following Cookbook post:
+#
+#      ASPN: Python Cookbook : Dynamically added methods to a class
+#      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
+
+def AddMethod(object, function, name = None):
+    """
+    Adds either a bound method to an instance or an unbound method to
+    a class. If name is ommited the name of the specified function
+    is used by default.
+    Example:
+      a = A()
+      def f(self, x, y):
+        self.z = x + y
+      AddMethod(f, A, "add")
+      a.add(2, 4)
+      print a.z
+      AddMethod(lambda self, i: self.l[i], a, "listIndex")
+      print a.listIndex(5)
+    """
+    import new
+
+    if name is None:
+        name = function.func_name
+    else:
+        function = RenameFunction(function, name)
+
+    try:
+        klass = object.__class__
+    except AttributeError:
+        # "object" is really a class, so it gets an unbound method.
+        object.__dict__[name] = new.instancemethod(function, None, object)
+    else:
+        # "object" is really an instance, so it gets a bound method.
+        object.__dict__[name] = new.instancemethod(function, object, klass)
+
+def RenameFunction(function, name):
+    """
+    Returns a function identical to the specified function, but with
+    the specified name.
+    """
+    import new
+
+    # Compatibility for Python 1.5 and 2.1.  Can be removed in favor of
+    # passing function.func_defaults directly to new.function() once
+    # we base on Python 2.2 or later.
+    func_defaults = function.func_defaults
+    if func_defaults is None:
+        func_defaults = ()
+
+    return new.function(function.func_code,
+                        function.func_globals,
+                        name,
+                        func_defaults)
+
+del __revision__
index a477a482a70d52dc7629e8b7e38d9610ea4653a1..1124cf0ff2a8bf4a84963d5618b9916d8971c945 100644 (file)
@@ -76,11 +76,13 @@ try:
     dict
 except NameError:
     # Pre-2.2 Python has no dict() keyword.
-    def dict(*arg, **kwargs):
+    def dict(seq=[], **kwargs):
         """
         New dictionary initialization.
         """
-        d = apply(types.DictType, arg)
+        d = {}
+        for k, v in seq:
+            d[k] = v
         d.update(kwargs)
         return d
     __builtin__.dict = dict
diff --git a/test/AddMethod.py b/test/AddMethod.py
new file mode 100644 (file)
index 0000000..ef4a8d0
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 use of the AddMethod() global function (specifically, to add
+an unbound method to the Environment class) and its counterpart
+construction environment method.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+def foo(self):
+    return 'foo-' + env['FOO']
+
+AddMethod(Environment, foo)
+env = Environment(FOO = '111')
+print env.foo()
+
+env = Environment(FOO = '222')
+print env.foo()
+
+env.AddMethod(foo, 'bar')
+print env.bar()
+
+""")
+
+expect = """\
+foo-111
+foo-222
+foo-222
+"""
+
+test.run(arguments = '-Q -q', stdout = expect)
+
+test.pass_test()
index a10730237ffc12fa6c2d5d6510fb5ad1e4dc3bde..d1f07fd53145e10c162d9aa86b7884a3e1e3ccbe 100644 (file)
@@ -33,6 +33,9 @@ test = TestSCons.TestSCons()
 
 test.subdir('sub')
 
+sub_f3_out = os.path.join('sub', 'f3.out')
+_SUBDIR_f3_out = os.path.join('$SUBDIR', 'f3.out')
+
 test.write('SConstruct', """\
 def bfunc(target, source, env):
     import shutil
@@ -43,30 +46,37 @@ env = Environment(BUILDERS = { 'B' : B }, SUBDIR='sub')
 env.B('f1.out', source='f1.in')
 AlwaysBuild('f1.out')
 
-env.B(r'%s', source='f3.in')
-env.AlwaysBuild(r'%s')
+env.B(r'%(sub_f3_out)s', source='f3.in')
+env.AlwaysBuild(r'%(_SUBDIR_f3_out)s')
 
 env.Alias('clean1', [], Delete('clean1-target'))
 env.AlwaysBuild('clean1')
 c2 = env.Alias('clean2', [], [Delete('clean2-t1'), Delete('clean2-t2')])
 env.AlwaysBuild(c2)
-""" % (os.path.join('sub', 'f3.out'),
-       os.path.join('$SUBDIR', 'f3.out')
-      ))
+
+def dir_build(target, source, env):
+    open('dir_build.txt', 'ab').write('dir_build()\\n')
+env.Command(Dir('dir'), None, dir_build)
+env.AlwaysBuild('dir')
+""" % locals())
 
 test.write('f1.in', "f1.in\n")
 test.write('f2.in', "1")
 test.write('f3.in', "f3.in\n")
 
+test.subdir('dir')
+
 test.run(arguments = ".")
-test.fail_test(test.read('f1.out') != '1')
-test.fail_test(test.read(['sub', 'f3.out']) != '1')
+test.must_match('f1.out', '1')
+test.must_match(['sub', 'f3.out'], '1')
+test.must_match('dir_build.txt', "dir_build()\n")
 
 test.write('f2.in', "2")
 
 test.run(arguments = ".")
-test.fail_test(test.read('f1.out') != '2')
-test.fail_test(test.read(['sub', 'f3.out']) != '2')
+test.must_match('f1.out', '2')
+test.must_match(['sub', 'f3.out'], '2')
+test.must_match('dir_build.txt', "dir_build()\ndir_build()\n")
 
 test.run(arguments = 'clean1', stdout=test.wrap_stdout("""\
 Delete("clean1-target")
@@ -77,4 +87,8 @@ Delete("clean2-t1")
 Delete("clean2-t2")
 """))
 
+test.not_up_to_date(arguments = 'dir')
+
+test.must_match('dir_build.txt', "dir_build()\ndir_build()\ndir_build()\n")
+
 test.pass_test()
index 1fa615aff62221b62300505f07a813a842fb6846..08c40c29a73bb3aeb7d27b3c67de11d579c32ec6 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+"""
+Verify that we can set CFILESUFFIX to arbitrary values.
+"""
+
 import os
 import os.path
 import string
@@ -49,6 +53,13 @@ test.write('SConstruct', """
 env = Environment(LEX = r'%(_python_)s mylex.py', tools = ['lex'])
 env.CFile(target = 'foo', source = 'foo.l')
 env.Clone(CFILESUFFIX = '.xyz').CFile(target = 'bar', source = 'bar.l')
+
+# Make sure that calling a Tool on a construction environment *after*
+# we've set CFILESUFFIX doesn't overwrite the value.
+env2 = Environment(tools = [], CFILESUFFIX = '.env2')
+env2.Tool('lex')
+env2['LEX'] = r'%(_python_)s mylex.py'
+env2.CFile(target = 'f3', source = 'f3.l')
 """ % locals())
 
 input = r"""
@@ -66,10 +77,14 @@ test.write('foo.l', input % 'foo.l')
 
 test.write('bar.l', input % 'bar.l')
 
+test.write('f3.l', input % 'f3.l')
+
 test.run(arguments = '.')
 
-test.fail_test(not os.path.exists(test.workpath('foo.c')))
+test.must_exist(test.workpath('foo.c'))
+
+test.must_exist(test.workpath('bar.xyz'))
 
-test.fail_test(not os.path.exists(test.workpath('bar.xyz')))
+test.must_exist(test.workpath('f3.env2'))
 
 test.pass_test()
index b156f748bc58648a4b83869da6e81c7bdbcfa906..fbc34ffb25e8344d74901787a691025efe867c8f 100644 (file)
@@ -49,6 +49,13 @@ test.write('SConstruct', """
 env = Environment(LEX = r'%(_python_)s mylex.py', tools = ['lex'])
 env.CXXFile(target = 'foo', source = 'foo.ll')
 env.Clone(CXXFILESUFFIX = '.xyz').CXXFile(target = 'bar', source = 'bar.ll')
+
+# Make sure that calling a Tool on a construction environment *after*
+# we've set CXXFILESUFFIX doesn't overwrite the value.
+env2 = Environment(tools = [], CXXFILESUFFIX = '.env2')
+env2.Tool('lex')
+env2['LEX'] = r'%(_python_)s mylex.py'
+env2.CXXFile(target = 'f3', source = 'f3.ll')
 """ % locals())
 
 input = r"""
@@ -66,10 +73,14 @@ test.write('foo.ll', input % 'foo.ll')
 
 test.write('bar.ll', input % 'bar.ll')
 
+test.write('f3.ll', input % 'f3.ll')
+
 test.run(arguments = '.')
 
-test.fail_test(not os.path.exists(test.workpath('foo.cc')))
+test.must_exist(test.workpath('foo.cc'))
+
+test.must_exist(test.workpath('bar.xyz'))
 
-test.fail_test(not os.path.exists(test.workpath('bar.xyz')))
+test.must_exist(test.workpath('f3.env2'))
 
 test.pass_test()
diff --git a/test/CacheDir/symlink.py b/test/CacheDir/symlink.py
new file mode 100644 (file)
index 0000000..6dd1f94
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 we push and retrieve a built symlink to/from a CacheDir()
+as an actualy symlink, not by copying the file contents.
+"""
+
+import os
+import os.path
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+if not hasattr(os, 'symlink'):
+    import sys
+    test.skip_test('%s has no os.symlink() method; skipping test\n' % sys.executable)
+
+test.write('SConstruct', """\
+CacheDir('cache')
+import os
+Symlink = Action(lambda target, source, env:
+                        os.symlink(str(source[0]), str(target[0])),
+                 "os.symlink($SOURCE, $TARGET)")
+Command('file.symlink', 'file.txt', Symlink)
+""")
+
+test.write('file.txt', "file.txt\n")
+
+test.run(arguments = '.')
+
+test.fail_test(not os.path.islink('file.symlink'))
+test.must_match('file.symlink', "file.txt\n")
+
+test.run(arguments = '-c .')
+
+test.must_not_exist('file.symlink')
+
+test.run(arguments = '.')
+
+test.fail_test(not os.path.islink('file.symlink'))
+test.must_match('file.symlink', "file.txt\n")
+
+test.pass_test()
diff --git a/test/Configure/Action-error.py b/test/Configure/Action-error.py
new file mode 100644 (file)
index 0000000..0abcc7c
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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 calling Configure from an Action results in a readable error.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+def ConfigureAction(target, source, env):
+    env.Configure()
+    return 0
+env = Environment(BUILDERS = {'MyAction' :
+                          Builder(action=Action(ConfigureAction))})
+env.MyAction('target', [])
+""")
+
+expect = "scons: *** Calling Configure from Builders is not supported.\n"
+
+test.run(status=2, stderr=expect)
+
+test.pass_test()
diff --git a/test/Configure/BuildDir-SConscript.py b/test/Configure/BuildDir-SConscript.py
new file mode 100644 (file)
index 0000000..47b7d82
--- /dev/null
@@ -0,0 +1,159 @@
+#!/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 Configure calls in SConscript files work when used
+with BuildDir.
+"""
+
+import os.path
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+test.subdir( 'sub', ['sub', 'local'] )
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+test.write('SConstruct', """\
+opts = Options()
+opts.Add('chdir')
+env = Environment(options=opts)
+if env['chdir'] == 'yes':
+  SConscriptChdir(1)
+else:
+  SConscriptChdir(0)
+BuildDir( 'build', '.' )
+SConscript( 'build/SConscript' )
+""")
+
+test.write(['sub', 'local', 'local_header.h'], "/* Hello World */" )
+
+test.write('SConscript', """\
+SConscript( 'sub/SConscript' )
+""")
+
+test.write(['sub', 'SConscript'], """\
+def CustomTest(context):
+  context.Message('Executing Custom Test ... ')
+  ret = context.TryCompile('#include "local_header.h"', '.c')
+  context.Result(ret)
+  return ret
+
+env = Environment(FOO='fff')
+env.Append( CPPPATH='local' )
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure( env, custom_tests = {'CustomTest' : CustomTest,
+                                       '$FOO' : CustomTest} )
+if hasattr(conf, 'fff'):
+  conf.Message('$FOO should not have been expanded!')
+  Exit(1)
+if not conf.CheckCHeader( 'math.h' ):
+  Exit(1)
+if conf.CheckCHeader( 'no_std_c_header.h' ):
+  Exit(1)
+if not conf.CustomTest():
+  Exit(1)
+env = conf.Finish()
+env.Program( 'TestProgram', 'TestProgram.c' )
+""")
+
+test.write(['sub', 'TestProgram.h'], """\
+/* Just a test header */
+""")
+
+test.write(['sub', 'TestProgram.c'], """\
+#include "TestProgram.h"
+#include <stdio.h>
+
+int main() {
+  printf( "Hello\\n" );
+}
+""")
+
+# first with SConscriptChdir(0)
+test.run(arguments='chdir=no')
+test.checkLogAndStdout( ["Checking for C header file math.h... ",
+                        "Checking for C header file no_std_c_header.h... ",
+                        "Executing Custom Test ... "],
+                        ["yes", "no", "yes"],
+                        [[((".c", NCR), (_obj, NCR))],
+                         [((".c", NCR), (_obj, NCF))],
+                         [((".c", NCR), (_obj, NCR))]],
+                        "config.log",
+                        ".sconf_temp",
+                        os.path.join("build", "sub", "SConscript"))
+
+test.run(arguments='chdir=no')
+test.checkLogAndStdout( ["Checking for C header file math.h... ",
+                        "Checking for C header file no_std_c_header.h... ",
+                        "Executing Custom Test ... "],
+                        ["yes", "no", "yes"],
+                        [[((".c", CR), (_obj, CR))],
+                         [((".c", CR), (_obj, CF))],
+                         [((".c", CR), (_obj, CR))]],
+                        "config.log",
+                        ".sconf_temp",
+                        os.path.join("build", "sub", "SConscript"))
+
+import shutil
+shutil.rmtree(test.workpath(".sconf_temp"))
+test.unlink(".sconsign.dblite")
+
+# now with SConscriptChdir(1)
+test.run(arguments='chdir=yes')
+test.checkLogAndStdout( ["Checking for C header file math.h... ",
+                        "Checking for C header file no_std_c_header.h... ",
+                        "Executing Custom Test ... "],
+                        ["yes", "no", "yes"],
+                        [[((".c", NCR), (_obj, NCR))],
+                         [((".c", NCR), (_obj, NCF))],
+                         [((".c", NCR), (_obj, NCR))]],
+                        "config.log",
+                        ".sconf_temp",
+                        os.path.join("build", "sub", "SConscript"))
+
+test.run(arguments='chdir=yes')
+test.checkLogAndStdout( ["Checking for C header file math.h... ",
+                        "Checking for C header file no_std_c_header.h... ",
+                        "Executing Custom Test ... "],
+                        ["yes", "no", "yes"],
+                        [[((".c", CR), (_obj, CR))],
+                         [((".c", CR), (_obj, CF))],
+                         [((".c", CR), (_obj, CR))]],
+                        "config.log",
+                        ".sconf_temp",
+                        os.path.join("build", "sub", "SConscript"))
+
+
+test.pass_test()
diff --git a/test/Configure/BuildDir.py b/test/Configure/BuildDir.py
new file mode 100644 (file)
index 0000000..ca3c147
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 Configure contexts work with basic use of BuildDir.
+"""
+
+import os.path
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+test.write('SConstruct', """\
+env = Environment(LOGFILE='build/config.log')
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+BuildDir( 'build', '.' )
+conf = env.Configure(conf_dir='build/config.tests', log_file='$LOGFILE')
+r1 = conf.CheckCHeader( 'math.h' )
+r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
+env = conf.Finish()
+Export( 'env' )
+# print open( 'build/config.log' ).readlines()
+SConscript( 'build/SConscript' )
+""")
+
+test.write('SConscript', """\
+Import( 'env' )
+env.Program( 'TestProgram', 'TestProgram.c' )
+""")
+
+test.write('TestProgram.c', """\
+#include <stdio.h>
+
+int main() {
+  printf( "Hello\\n" );
+}
+""")
+
+test.run()
+test.checkLogAndStdout(["Checking for C header file math.h... ",
+                       "Checking for C header file no_std_c_header.h... "],
+                      ["yes", "no"],
+                      [[((".c", NCR), (_obj, NCR))],
+                       [((".c", NCR), (_obj, NCF))]],
+                      os.path.join("build", "config.log"),
+                      os.path.join("build", "config.tests"),
+                      "SConstruct")
+    
+test.run()
+test.checkLogAndStdout(["Checking for C header file math.h... ",
+                       "Checking for C header file no_std_c_header.h... "],
+                      ["yes", "no"],
+                      [[((".c", CR), (_obj, CR))],
+                       [((".c", CR), (_obj, CF))]],
+                      os.path.join("build", "config.log"),
+                      os.path.join("build", "config.tests"),
+                      "SConstruct")
+
+test.pass_test()
diff --git a/test/Configure/Builder-call.py b/test/Configure/Builder-call.py
new file mode 100644 (file)
index 0000000..a6f2fa5
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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 calling normal Builders from an actual Configure
+context environment works correctly.
+"""
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+test.write('cmd.py', r"""
+import sys
+sys.stderr.write( 'Hello World on stderr\n' )
+sys.stdout.write( 'Hello World on stdout\n' )
+open(sys.argv[1], 'w').write( 'Hello World\n' )
+""")
+
+test.write('SConstruct', """\
+env = Environment()
+def CustomTest(*args):
+    return 0
+conf = env.Configure(custom_tests = {'MyTest' : CustomTest})
+if not conf.MyTest():
+    env.Command("hello", [], '%(_python_)s cmd.py $TARGET')
+env = conf.Finish()
+""" % locals())
+
+test.run(stderr="Hello World on stderr\n")
+
+test.pass_test()
diff --git a/test/Configure/Configure.py b/test/Configure/Configure.py
deleted file mode 100644 (file)
index 4063699..0000000
+++ /dev/null
@@ -1,939 +0,0 @@
-#!/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 os
-import re
-import shutil
-import string
-import sys
-
-import __builtin__
-try:
-    __builtin__.zip
-except AttributeError:
-    def zip(*lists):
-        result = []
-        for i in xrange(len(lists[0])):
-            result.append(tuple(map(lambda l, i=i: l[i], lists)))
-        return result
-    __builtin__.zip = zip
-
-import TestCmd
-import TestSCons
-
-if sys.platform == 'win32':
-    lib = 'msvcrt'
-else:
-    lib = 'm'
-
-# to use cygwin compilers on cmd.exe -> uncomment following line
-#lib = 'm'
-
-work_cnt = 0
-work_dir = None
-python = TestSCons.python
-_python_ = TestSCons._python_
-test = TestSCons.TestSCons()
-_obj = TestSCons._obj
-_exe = TestSCons._exe
-
-RE = 0
-RE_DOTALL = 1
-EXACT = 2
-def reset(match):
-    global test, work_dir, work_cnt
-    work_cnt = work_cnt + 1
-    work_dir='test%d' % work_cnt
-    test.subdir(work_dir)
-    if match == RE:
-        test.match_func = TestCmd.match_re
-    elif match == RE_DOTALL:
-        test.match_func = TestCmd.match_re_dotall
-    elif match == EXACT:
-        test.match_func = TestCmd.match_exact
-
-def checkFiles(test, files):
-    global work_dir
-    for f in files:
-        test.fail_test( not os.path.isfile( test.workpath(work_dir,f) ) )
-
-def checklib(lang, name, up_to_date):
-    if lang == 'C':
-        return (".c", _obj, _exe)
-    elif lang == 'C++':
-        return (".cc", _obj, _exe)
-
-class NoMatch:
-    def __init__(self, p):
-        self.pos = p
-
-NCR = 0 # non-cached rebuild
-CR  = 1 # cached rebuild (up to date)
-NCF = 2 # non-cached build failure
-CF  = 3 # cached build failure
-
-def checkLogAndStdout(checks, results, cached,
-                      test, logfile, sconf_dir, sconstruct,
-                      doCheckLog=1, doCheckStdout=1):
-    def matchPart(log, logfile, lastEnd):
-        m = re.match(log, logfile[lastEnd:])
-        if not m:
-            raise NoMatch, lastEnd
-        return m.end() + lastEnd
-    try:
-        #print len(os.linesep)
-        ls = os.linesep
-        nols = "("
-        for i in range(len(ls)):
-            nols = nols + "("
-            for j in range(i):
-                nols = nols + ls[j]
-            nols = nols + "[^" + ls[i] + "])"
-            if i < len(ls)-1:
-                nols = nols + "|"
-        nols = nols + ")"
-        lastEnd = 0
-        logfile = test.read(test.workpath(work_dir, logfile))
-        if (doCheckLog and
-            string.find( logfile, "scons: warning: The stored build "
-                         "information has an unexpected class." ) >= 0):
-            test.fail_test()
-        sconf_dir = sconf_dir
-        sconstruct = sconstruct
-
-        log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls
-        if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
-        log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
-        if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
-        rdstr = ""
-        cnt = 0
-        for check,result,cache_desc in zip(checks, results, cached):
-            log   = re.escape("scons: Configure: " + check) + ls
-            if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
-            log = ""
-            result_cached = 1
-            for bld_desc in cache_desc: # each TryXXX
-                for ext, flag in bld_desc: # each file in TryBuild
-                    file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
-                    if flag == NCR:
-                        # rebuild will pass
-                        if ext in ['.c', '.cpp']:
-                            log=log + re.escape(file + " <-") + ls
-                            log=log + r"(  \|" + nols + "*" + ls + ")+?"
-                        else:
-                            log=log + "(" + nols + "*" + ls +")*?"
-                        result_cached = 0
-                    if flag == CR:
-                        # up to date
-                        log=log + \
-                             re.escape("scons: Configure: \"%s\" is up to date." 
-                                       % file) + ls
-                        log=log+re.escape("scons: Configure: The original builder "
-                                          "output was:") + ls
-                        log=log+r"(  \|.*"+ls+")+"
-                    if flag == NCF:
-                        # non-cached rebuild failure
-                        log=log + "(" + nols + "*" + ls + ")*?"
-                        result_cached = 0
-                    if flag == CF:
-                        # cached rebuild failure
-                        log=log + \
-                             re.escape("scons: Configure: Building \"%s\" failed "
-                                       "in a previous run and all its sources are"
-                                       " up to date." % file) + ls
-                        log=log+re.escape("scons: Configure: The original builder "
-                                          "output was:") + ls
-                        log=log+r"(  \|.*"+ls+")+"
-                cnt = cnt + 1
-            if result_cached:
-                result = "(cached) " + result
-            rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
-            log=log + re.escape("scons: Configure: " + result) + ls + ls
-            if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
-            log = ""
-        if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
-        if doCheckLog and lastEnd != len(logfile):
-            raise NoMatch, lastEnd
-        
-    except NoMatch, m:
-        print "Cannot match log file against log regexp."
-        print "log file: "
-        print "------------------------------------------------------"
-        print logfile[m.pos:]
-        print "------------------------------------------------------"
-        print "log regexp: "
-        print "------------------------------------------------------"
-        print log
-        print "------------------------------------------------------"
-        test.fail_test()
-
-    if doCheckStdout:
-        exp_stdout = test.wrap_stdout(".*", rdstr)
-        if not test.match_re_dotall(test.stdout(), exp_stdout):
-            print "Unexpected stdout: "
-            print "-----------------------------------------------------"
-            print repr(test.stdout())
-            print "-----------------------------------------------------"
-            print repr(exp_stdout)
-            print "-----------------------------------------------------"
-            test.fail_test()
-        
-try:
-    # 1.1 if checks are ok, the cache mechanism should work
-
-    reset(RE)
-
-    test.write([work_dir,  'SConstruct'], """
-if int(ARGUMENTS.get('target_signatures_content', 0)):
-    TargetSignatures('content')
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
-r1 = conf.CheckLibWithHeader( '%s', 'math.h', 'c' )
-r2 = conf.CheckLibWithHeader( None, 'math.h', 'c' )
-r3 = conf.CheckLib( '%s', autoadd=0 )
-r4 = conf.CheckLib( None, autoadd=0 )
-r5 = conf.CheckCHeader( 'math.h' )
-r6 = conf.CheckCXXHeader( 'vector' )
-env = conf.Finish()
-if not (r1 and r2 and r3 and r4 and r5 and r6):
-     Exit(1)
-""" % (lib,lib))
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C header file math.h... ",
-                       "Checking for C++ header file vector... "],
-                      ["yes"]*6,
-                      [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
-                        [[((".c", NCR), (_obj, NCR))]] +
-                        [[((".cpp", NCR), (_obj, NCR))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")    
-    
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C header file math.h... ",
-                       "Checking for C++ header file vector... "],
-                      ["yes"]*6,
-                      [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
-                       [[((".c", CR), (_obj, CR))]] +
-                       [[((".cpp", CR), (_obj, CR))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    # same should be true for TargetSignatures('content')
-
-    test.run(chdir=work_dir, arguments='target_signatures_content=1 --config=force')
-    checkLogAndStdout(["Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C header file math.h... ",
-                       "Checking for C++ header file vector... "],
-                      ["yes"]*6,
-                      [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
-                        [[((".c", NCR), (_obj, NCR))]] +
-                        [[((".cpp", NCR), (_obj, NCR))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")    
-
-    test.run(chdir=work_dir, arguments='target_signatures_content=1')
-    checkLogAndStdout(["Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C library %s... " % lib,
-                       "Checking for C library None... ",
-                       "Checking for C header file math.h... ",
-                       "Checking for C++ header file vector... "],
-                      ["yes"]*6,
-                      [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
-                       [[((".c", CR), (_obj, CR))]] +
-                       [[((".cpp", CR), (_obj, CR))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")    
-
-    # 1.2 if checks are not ok, the cache mechanism should work as well
-    #     (via explicit cache)
-    reset(EXACT)              # match exactly, "()" is a regexp thing
-
-    test.write([work_dir,  'SConstruct'], """
-if int(ARGUMENTS.get('target_signatures_content', 0)):
-    TargetSignatures('content')
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = env.Configure()
-r1 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
-r2 = conf.CheckLib( 'no_c_library_SAFFDG' )   # leads to link error
-env = conf.Finish()
-if not (not r1 and not r2):
-     print "FAIL: ", r1, r2
-     Exit(1)
-""")
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
-                       "Checking for C library no_c_library_SAFFDG... "],
-                      ["no"]*2,
-                      [[((".c", NCR), (_obj, NCF))],
-                       [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
-                       "Checking for C library no_c_library_SAFFDG... "],
-                      ["no"]*2,
-                      [[((".c", CR), (_obj, CF))],
-                       [((".c", CR), (_obj, CR), (_exe, CF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    # 1.3 same should be true for TargetSignatures('content')
-    test.run(chdir=work_dir, arguments='--config=force target_signatures_content=1')
-    checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
-                       "Checking for C library no_c_library_SAFFDG... "],
-                      ["no"]*2,
-                      [[((".c", NCR), (_obj, NCF))],
-                       [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.run(chdir=work_dir, arguments='target_signatures_content=1')
-    checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
-                       "Checking for C library no_c_library_SAFFDG... "],
-                      ["no"]*2,
-                      [[((".c", CR), (_obj, CF))],
-                       [((".c", CR), (_obj, CR), (_exe, CF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    
-
-    # 2.1 test that normal builds work together with Sconf
-    reset(RE_DOTALL)
-
-
-    test.write([work_dir,  'SConstruct'], """
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
-r1 = conf.CheckCHeader( 'math.h' )
-r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
-env = conf.Finish()
-Export( 'env' )
-SConscript( 'SConscript' )
-""")
-    test.write([work_dir,  'SConscript'], """
-Import( 'env' )
-env.Program( 'TestProgram', 'TestProgram.c' )
-""")
-    test.write([work_dir,  'TestProgram.c'], """
-#include <stdio.h>
-
-int main() {
-  printf( "Hello\\n" );
-}
-""")
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file math.h... ",
-                       "Checking for C header file no_std_c_header.h... "],
-                      ["yes", "no"],
-                      [[((".c", NCR), (_obj, NCR))],
-                       [((".c", NCR), (_obj, NCF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file math.h... ",
-                       "Checking for C header file no_std_c_header.h... "],
-                      ["yes", "no"],
-                      [[((".c", CR), (_obj, CR))],
-                       [((".c", CR), (_obj, CF))]],
-                      test, "config.log", ".sconf_temp", "SConstruct")
-
-    # 2.2 test that BuildDir builds work together with Sconf
-    reset(RE_DOTALL)
-
-
-    test.write([work_dir,  'SConstruct'], """
-env = Environment(LOGFILE='build/config.log')
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-BuildDir( 'build', '.' )
-conf = env.Configure(conf_dir='build/config.tests', log_file='$LOGFILE')
-r1 = conf.CheckCHeader( 'math.h' )
-r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
-env = conf.Finish()
-Export( 'env' )
-# print open( 'build/config.log' ).readlines()
-SConscript( 'build/SConscript' )
-""")
-    test.write([work_dir,  'SConscript'], """
-Import( 'env' )
-env.Program( 'TestProgram', 'TestProgram.c' )
-""")
-    test.write([work_dir,  'TestProgram.c'], """
-#include <stdio.h>
-
-int main() {
-  printf( "Hello\\n" );
-}
-""")
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file math.h... ",
-                       "Checking for C header file no_std_c_header.h... "],
-                      ["yes", "no"],
-                      [[((".c", NCR), (_obj, NCR))],
-                       [((".c", NCR), (_obj, NCF))]],
-                      test,
-                      os.path.join("build", "config.log"),
-                      os.path.join("build", "config.tests"),
-                      "SConstruct")
-    
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Checking for C header file math.h... ",
-                       "Checking for C header file no_std_c_header.h... "],
-                      ["yes", "no"],
-                      [[((".c", CR), (_obj, CR))],
-                       [((".c", CR), (_obj, CF))]],
-                      test,
-                      os.path.join("build", "config.log"),
-                      os.path.join("build", "config.tests"),
-                      "SConstruct")
-
-    # 2.3 test that Configure calls in SConscript files work
-    #     even if BuildDir is set
-    reset(RE_DOTALL)
-
-    test.subdir( [work_dir, 'sub'], [work_dir, 'sub', 'local'] )
-    test.write([work_dir,  'SConstruct'], """
-opts = Options()
-opts.Add('chdir')
-env = Environment(options=opts)
-if env['chdir'] == 'yes':
-  SConscriptChdir(1)
-else:
-  SConscriptChdir(0)
-BuildDir( 'build', '.' )
-SConscript( 'build/SConscript' )
-""")
-    test.write([work_dir,  'sub', 'local', 'local_header.h'],
-               "/* Hello World */" )
-    test.write([work_dir,  'SConscript'], """
-SConscript( 'sub/SConscript' )
-""")
-    test.write([work_dir,  'sub', 'SConscript'], """
-def CustomTest(context):
-  context.Message('Executing Custom Test ... ')
-  ret = context.TryCompile('#include "local_header.h"', '.c')
-  context.Result(ret)
-  return ret
-
-env = Environment(FOO='fff')
-env.Append( CPPPATH='local' )
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure( env, custom_tests = {'CustomTest' : CustomTest,
-                                       '$FOO' : CustomTest} )
-if hasattr(conf, 'fff'):
-  conf.Message('$FOO should not have been expanded!')
-  Exit(1)
-if not conf.CheckCHeader( 'math.h' ):
-  Exit(1)
-if conf.CheckCHeader( 'no_std_c_header.h' ):
-  Exit(1)
-if not conf.CustomTest():
-  Exit(1)
-env = conf.Finish()
-env.Program( 'TestProgram', 'TestProgram.c' )
-""")
-    test.write([work_dir, 'sub', 'TestProgram.h'], """
-/* Just a test header */
-""")
-    test.write([work_dir, 'sub', 'TestProgram.c'], """
-#include "TestProgram.h"
-#include <stdio.h>
-
-int main() {
-  printf( "Hello\\n" );
-}
-""")
-
-    # first with SConscriptChdir(0)
-    test.run(chdir=work_dir, arguments='chdir=no')
-    checkLogAndStdout( ["Checking for C header file math.h... ",
-                        "Checking for C header file no_std_c_header.h... ",
-                        "Executing Custom Test ... "],
-                        ["yes", "no", "yes"],
-                        [[((".c", NCR), (_obj, NCR))],
-                         [((".c", NCR), (_obj, NCF))],
-                         [((".c", NCR), (_obj, NCR))]],
-                        test, "config.log",
-                        ".sconf_temp",
-                        os.path.join("build", "sub", "SConscript"))
-
-    test.run(chdir=work_dir, arguments='chdir=no')
-    checkLogAndStdout( ["Checking for C header file math.h... ",
-                        "Checking for C header file no_std_c_header.h... ",
-                        "Executing Custom Test ... "],
-                        ["yes", "no", "yes"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))],
-                         [((".c", CR), (_obj, CR))]],
-                        test, "config.log",
-                        ".sconf_temp",
-                        os.path.join("build", "sub", "SConscript"))
-
-    shutil.rmtree(test.workpath(work_dir, ".sconf_temp"))
-    os.unlink(test.workpath(work_dir, ".sconsign.dblite"))
-
-    # now with SConscriptChdir(1)
-    test.run(chdir=work_dir, arguments='chdir=yes')
-    checkLogAndStdout( ["Checking for C header file math.h... ",
-                        "Checking for C header file no_std_c_header.h... ",
-                        "Executing Custom Test ... "],
-                        ["yes", "no", "yes"],
-                        [[((".c", NCR), (_obj, NCR))],
-                         [((".c", NCR), (_obj, NCF))],
-                         [((".c", NCR), (_obj, NCR))]],
-                        test, "config.log",
-                        ".sconf_temp",
-                        os.path.join("build", "sub", "SConscript"))
-
-    test.run(chdir=work_dir, arguments='chdir=yes')
-    checkLogAndStdout( ["Checking for C header file math.h... ",
-                        "Checking for C header file no_std_c_header.h... ",
-                        "Executing Custom Test ... "],
-                        ["yes", "no", "yes"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))],
-                         [((".c", CR), (_obj, CR))]],
-                        test, "config.log",
-                        ".sconf_temp",
-                        os.path.join("build", "sub", "SConscript"))
-
-    # 3.1 test custom tests
-    reset(RE_DOTALL)
-
-    compileOK = '#include <stdio.h>\\nint main() {printf("Hello");return 0;}'
-    compileFAIL = "syntax error"
-    linkOK = compileOK
-    linkFAIL = "void myFunc(); int main() { myFunc(); }"
-    runOK = compileOK
-    runFAIL = "int main() { return 1; }"
-    test.write([work_dir, 'pyAct.py'], 'import sys\nprint sys.argv[1]\nsys.exit(int(sys.argv[1]))\n')
-    test.write([work_dir, 'SConstruct'], """
-def CheckCustom(test):
-    test.Message( 'Executing MyTest ... ' )
-    retCompileOK = test.TryCompile( '%s', '.c' )
-    retCompileFAIL = test.TryCompile( '%s', '.c' )
-    retLinkOK = test.TryLink( '%s', '.c' )
-    retLinkFAIL = test.TryLink( '%s', '.c' )
-    (retRunOK, outputRunOK) = test.TryRun( '%s', '.c' )
-    (retRunFAIL, outputRunFAIL) = test.TryRun( '%s', '.c' )
-    (retActOK, outputActOK) = test.TryAction( '%s pyAct.py 0 > $TARGET' )
-    (retActFAIL, outputActFAIL) = test.TryAction( '%s pyAct.py 1 > $TARGET' )
-    resOK = retCompileOK and retLinkOK and retRunOK and outputRunOK=="Hello"
-    resOK = resOK and retActOK and int(outputActOK)==0
-    resFAIL = retCompileFAIL or retLinkFAIL or retRunFAIL or outputRunFAIL!=""
-    resFAIL = resFAIL or retActFAIL or outputActFAIL!=""
-    test.Result( int(resOK and not resFAIL) )
-    return resOK and not resFAIL
-
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure( env, custom_tests={'CheckCustom' : CheckCustom} )
-conf.CheckCustom()
-env = conf.Finish()
-""" % (compileOK, compileFAIL, linkOK, linkFAIL, runOK, runFAIL,
-       python, python ) )
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Executing MyTest ... "],
-                      ["yes"],
-                      [[(('.c', NCR), (_obj, NCR)),
-                        (('.c', NCR), (_obj, NCF)),
-                        (('.c', NCR), (_obj, NCR), (_exe, NCR)),
-                        (('.c', NCR), (_obj, NCR), (_exe, NCF)),
-                        (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCR)),
-                        (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCF)),
-                        (('', NCR),),
-                        (('', NCF),)]],
-                       test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout(["Executing MyTest ... "],
-                      ["yes"],
-                      [[(('.c', CR), (_obj, CR)),
-                        (('.c', CR), (_obj, CF)),
-                        (('.c', CR), (_obj, CR), (_exe, CR)),
-                        (('.c', CR), (_obj, CR), (_exe, CF)),
-                        (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CR)),
-                        (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CF)),
-                        (('', CR),),
-                        (('', CF),)]],
-                       test, "config.log", ".sconf_temp", "SConstruct")
-
-    # 4.1 test that calling normal builders from an actual configuring
-    # environment works
-    reset(RE_DOTALL)
-
-    test.write([work_dir, 'cmd.py'], r"""
-import sys
-sys.stderr.write( 'Hello World on stderr\n' )
-sys.stdout.write( 'Hello World on stdout\n' )
-open(sys.argv[1], 'w').write( 'Hello World\n' )
-""")
-
-    test.write([work_dir, 'SConstruct'], """
-env = Environment()
-def CustomTest(*args):
-    return 0
-conf = env.Configure(custom_tests = {'MyTest' : CustomTest})
-if not conf.MyTest():
-    env.Command("hello", [], '%(_python_)s cmd.py $TARGET')
-env = conf.Finish()
-""" % locals())
-    test.run(chdir=work_dir, stderr="Hello World on stderr\n")
-
-    # 4.2 test that calling Configure from a builder results in a
-    # readable Error
-    reset(EXACT)
-
-    test.write([work_dir, 'SConstruct'], """
-def ConfigureAction(target, source, env):
-    env.Configure()
-    return 0
-env = Environment(BUILDERS = {'MyAction' :
-                              Builder(action=Action(ConfigureAction))})
-env.MyAction('target', [])
-""")
-    test.run(chdir=work_dir, status=2,
-             stderr="scons: *** Calling Configure from Builders is not supported.\n")
-
-    # 4.3 test the calling Configure from multiple subsidiary,
-    # nested SConscript files does *not* result in an error.
-
-    test.subdir([work_dir, 'dir1'],
-                [work_dir, 'dir2'],
-                [work_dir, 'dir2', 'sub1'],
-                [work_dir, 'dir2', 'sub1', 'sub2'])
-    test.write([work_dir, 'SConstruct'], """
-env = Environment()
-SConscript(dirs=['dir1', 'dir2'], exports="env")
-""")
-    test.write([work_dir, 'dir1', 'SConscript'], """
-Import("env")
-conf = env.Configure()
-conf.Finish()
-""")
-    test.write([work_dir, 'dir2', 'SConscript'], """
-Import("env")
-conf = env.Configure()
-conf.Finish()
-SConscript(dirs=['sub1'], exports="env")
-""")
-    test.write([work_dir, 'dir2', 'sub1', 'SConscript'], """
-Import("env")
-conf = env.Configure()
-conf.Finish()
-SConscript(dirs=['sub2'], exports="env")
-""")
-    test.write([work_dir, 'dir2', 'sub1', 'sub2', 'SConscript'], """
-Import("env")
-conf = env.Configure()
-conf.Finish()
-""")
-    test.run(chdir=work_dir)
-
-    # 5.1 test the ConfigureDryRunError
-    
-    reset(EXACT) # exact match
-
-    SConstruct_path = test.workpath(work_dir, 'SConstruct')
-
-    test.write(SConstruct_path, """
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
-r1 = conf.CheckLib('%s') # will pass
-r2 = conf.CheckLib('hopefullynolib') # will fail
-env = conf.Finish()
-if not (r1 and not r2):
-     Exit(1)
-""" % (lib))
-
-    test.run(chdir=work_dir, arguments='-n', status=2, stderr="""
-scons: *** Cannot create configure directory ".sconf_temp" within a dry-run.
-File "%(SConstruct_path)s", line 5, in ?
-""" % locals())
-    test.must_not_exist([work_dir, 'config.log'])
-    test.subdir([work_dir, '.sconf_temp'])
-
-    conftest_0_c = os.path.join(".sconf_temp", "conftest_0.c")
-    
-    test.run(chdir=work_dir, arguments='-n', status=2, stderr="""
-scons: *** Cannot update configure test "%(conftest_0_c)s" within a dry-run.
-File "%(SConstruct_path)s", line 6, in ?
-""" % locals())
-
-    test.run(chdir=work_dir)
-    checkLogAndStdout( ["Checking for C library %s... " % lib,
-                        "Checking for C library hopefullynolib... "],
-                        ["yes", "no"],
-                        [[((".c", NCR), (_obj, NCR))],
-                         [((".c", NCR), (_obj, NCF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-    oldLog = test.read(test.workpath(work_dir, 'config.log'))
-
-    test.run(chdir=work_dir, arguments='-n')
-    checkLogAndStdout( ["Checking for C library %s... " % lib,
-                        "Checking for C library hopefullynolib... "],
-                        ["yes", "no"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct",
-                        doCheckLog=0)
-    newLog = test.read(test.workpath(work_dir, 'config.log'))
-    if newLog != oldLog:
-        print "Unexpected update of log file within a dry run"
-        test.fail_test()
-
-    # 5.2 test the --config=<auto|force|cache> option
-    reset(EXACT) # exact match
-
-    SConstruct_path = test.workpath(work_dir, 'SConstruct')
-
-    test.write(SConstruct_path, """
-env = Environment(CPPPATH='#/include')
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
-r1 = conf.CheckCHeader('non_system_header1.h')
-r2 = conf.CheckCHeader('non_system_header2.h')
-env = conf.Finish()
-""")
-    test.subdir([work_dir, 'include'])
-    test.write([work_dir, 'include', 'non_system_header1.h'], """
-/* A header */
-""")
-
-    conftest_0_c = os.path.join(".sconf_temp", "conftest_0.c")
-
-    test.run(chdir=work_dir, arguments='--config=cache', status=2, stderr="""
-scons: *** "%(conftest_0_c)s" is not yet built and cache is forced.
-File "%(SConstruct_path)s", line 6, in ?
-""" % locals())
-
-    test.run(chdir=work_dir, arguments='--config=auto')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["yes", "no"],
-                        [[((".c", NCR), (_obj, NCR))],
-                         [((".c", NCR), (_obj, NCF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-    test.run(chdir=work_dir, arguments='--config=auto')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["yes", "no"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-    
-    test.run(chdir=work_dir, arguments='--config=force')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["yes", "no"],
-                        [[((".c", NCR), (_obj, NCR))],
-                         [((".c", NCR), (_obj, NCF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.run(chdir=work_dir, arguments='--config=cache')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["yes", "no"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-
-    test.write([work_dir, 'include', 'non_system_header2.h'], """
-/* Another header */
-""")
-    test.unlink([work_dir, 'include', 'non_system_header1.h'])
-    test.run(chdir=work_dir, arguments='--config=cache')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["yes", "no"],
-                        [[((".c", CR), (_obj, CR))],
-                         [((".c", CR), (_obj, CF))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-    
-    test.run(chdir=work_dir, arguments='--config=auto')
-    checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
-                        "Checking for C header file non_system_header2.h... "],
-                        ["no", "yes"],
-                        [[((".c", CR), (_obj, NCF))],
-                         [((".c", CR), (_obj, NCR))]],
-                        test, "config.log", ".sconf_temp", "SConstruct")
-
-    # 5.3 test -Q option
-    reset(EXACT)
-    test.write([work_dir,  'SConstruct'], """
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
-r1 = conf.CheckCHeader('stdio.h')
-env = conf.Finish()
-""")
-    test.run(chdir=work_dir, arguments='-Q',
-             stdout="scons: `.' is up to date.\n", stderr="")
-
-
-    # 6. check config.h support
-    reset(EXACT)
-    test.write([work_dir, 'SConstruct'], """
-env = Environment()
-import os
-env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env, config_h = 'config.h')
-r1 = conf.CheckFunc('printf')
-r2 = conf.CheckFunc('noFunctionCall')
-r3 = conf.CheckType('int')
-r4 = conf.CheckType('noType')
-r5 = conf.CheckCHeader('stdio.h', '<>')
-r6 = conf.CheckCHeader('hopefullynoc-header.h')
-r7 = conf.CheckCXXHeader('vector', '<>')
-r8 = conf.CheckCXXHeader('hopefullynocxx-header.h')
-env = conf.Finish()
-conf = Configure(env, config_h = 'config.h')
-r9 = conf.CheckLib('%s', 'sin')
-r10 = conf.CheckLib('hopefullynolib', 'sin')
-r11 = conf.CheckLibWithHeader('%s', 'math.h', 'c')
-r12 = conf.CheckLibWithHeader('%s', 'hopefullynoheader2.h', 'c')
-r13 = conf.CheckLibWithHeader('hopefullynolib2', 'math.h', 'c')
-env = conf.Finish()
-""" % (lib, lib, lib))
-
-    expected_read_str = """\
-Checking for C function printf()... yes
-Checking for C function noFunctionCall()... no
-Checking for C type int... yes
-Checking for C type noType... no
-Checking for C header file stdio.h... yes
-Checking for C header file hopefullynoc-header.h... no
-Checking for C++ header file vector... yes
-Checking for C++ header file hopefullynocxx-header.h... no
-Checking for sin() in C library %(lib)s... yes
-Checking for sin() in C library hopefullynolib... no
-Checking for C library %(lib)s... yes
-Checking for C library %(lib)s... no
-Checking for C library hopefullynolib2... no
-""" % {'lib' : lib}
-
-    expected_build_str = """\
-scons: Configure: creating config.h
-"""
-    
-    expected_stdout = test.wrap_stdout(build_str=expected_build_str,
-                                       read_str=expected_read_str)
-
-    expected_config_h = string.replace("""#ifndef CONFIG_H_SEEN
-#define CONFIG_H_SEEN
-
-#define HAVE_PRINTF
-/* #undef HAVE_NOFUNCTIONCALL */
-#define HAVE_INT
-/* #undef HAVE_NOTYPE */
-#define HAVE_STDIO_H
-/* #undef HAVE_HOPEFULLYNOC_HEADER_H */
-#define HAVE_VECTOR
-/* #undef HAVE_HOPEFULLYNOCXX_HEADER_H */
-#define HAVE_%(LIB)s
-/* #undef HAVE_LIBHOPEFULLYNOLIB */
-#define HAVE_%(LIB)s
-/* #undef HAVE_%(LIB)s */
-/* #undef HAVE_LIBHOPEFULLYNOLIB2 */
-
-#endif /* CONFIG_H_SEEN */
-""" % {'LIB' : "LIB" + string.upper(lib) }, "\n", os.linesep)
-
-    test.run(chdir=work_dir, stdout=expected_stdout)
-    config_h = test.read(test.workpath(work_dir, 'config.h'))
-    if expected_config_h != config_h:
-        print "Unexpected config.h"
-        print "Expected: "
-        print "---------------------------------------------------------"
-        print repr(expected_config_h)
-        print "---------------------------------------------------------"
-        print "Found: "
-        print "---------------------------------------------------------"
-        print repr(config_h)
-        print "---------------------------------------------------------"
-        print "Stdio: "
-        print "---------------------------------------------------------"
-        print test.stdout()
-        print "---------------------------------------------------------"
-        test.fail_test()
-
-    expected_read_str = re.sub(r'\b((yes)|(no))\b',
-                               r'(cached) \1',
-                               expected_read_str)
-    expected_build_str = "scons: `.' is up to date.\n"
-    expected_stdout = test.wrap_stdout(build_str=expected_build_str,
-                                       read_str=expected_read_str)
-    #expected_stdout = string.replace(expected_stdout, "\n", os.linesep)
-    test.run(chdir=work_dir, stdout=expected_stdout)    
-    config_h = test.read(test.workpath(work_dir, 'config.h'))    
-    if expected_config_h != config_h:
-        print "Unexpected config.h"
-        print "Expected: "
-        print "---------------------------------------------------------"
-        print repr(expected_config_h)
-        print "---------------------------------------------------------"
-        print "Found: "
-        print "---------------------------------------------------------"
-        print repr(config_h)
-        print "---------------------------------------------------------"
-        print "Stdio: "
-        print "---------------------------------------------------------"
-        print test.stdout()
-        print "---------------------------------------------------------"
-        test.fail_test()
-
-finally:
-    pass
-    #os.system( 'find . -type f -exec ls -l {} \;' )
-    #print "-------------config.log------------------"
-    #print test.read( test.workpath(work_dir, 'config.log'))
-    #print "-------------build/config.log------------"
-    #print test.read( test.workpath('build/config.log' ))
-
-
-test.pass_test()
diff --git a/test/Configure/ConfigureDryRunError.py b/test/Configure/ConfigureDryRunError.py
new file mode 100644 (file)
index 0000000..04fbc75
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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 the ConfigureDryRunError.
+"""
+
+import os.path
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons()
+
+lib = test.Configure_lib
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+SConstruct_path = test.workpath('SConstruct')
+
+test.write(SConstruct_path, """
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env)
+r1 = conf.CheckLib('%s') # will pass
+r2 = conf.CheckLib('hopefullynolib') # will fail
+env = conf.Finish()
+if not (r1 and not r2):
+ Exit(1)
+""" % (lib))
+
+test.run(arguments='-n', status=2, stderr="""
+scons: *** Cannot create configure directory ".sconf_temp" within a dry-run.
+File "%(SConstruct_path)s", line 5, in ?
+""" % locals())
+
+test.must_not_exist('config.log')
+test.subdir('.sconf_temp')
+
+conftest_0_c = os.path.join(".sconf_temp", "conftest_0.c")
+
+test.run(arguments='-n', status=2, stderr="""
+scons: *** Cannot update configure test "%(conftest_0_c)s" within a dry-run.
+File "%(SConstruct_path)s", line 6, in ?
+""" % locals())
+
+test.run()
+test.checkLogAndStdout( ["Checking for C library %s... " % lib,
+                    "Checking for C library hopefullynolib... "],
+                    ["yes", "no"],
+                    [[((".c", NCR), (_obj, NCR))],
+                     [((".c", NCR), (_obj, NCF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+oldLog = test.read(test.workpath('config.log'))
+
+test.run(arguments='-n')
+test.checkLogAndStdout( ["Checking for C library %s... " % lib,
+                    "Checking for C library hopefullynolib... "],
+                    ["yes", "no"],
+                    [[((".c", CR), (_obj, CR))],
+                     [((".c", CR), (_obj, CF))]],
+                    "config.log", ".sconf_temp", "SConstruct",
+                    doCheckLog=0)
+
+newLog = test.read(test.workpath('config.log'))
+if newLog != oldLog:
+    print "Unexpected update of log file within a dry run"
+    test.fail_test()
+
+test.pass_test()
diff --git a/test/Configure/SConscript.py b/test/Configure/SConscript.py
new file mode 100644 (file)
index 0000000..2bfe2f7
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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 Configure contexts from multiple subsidiary SConscript
+files work without error.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir(['dir1'],
+            ['dir2'],
+            ['dir2', 'sub1'],
+            ['dir2', 'sub1', 'sub2'])
+
+test.write('SConstruct', """\
+env = Environment()
+SConscript(dirs=['dir1', 'dir2'], exports="env")
+""")
+
+test.write(['dir1', 'SConscript'], """
+Import("env")
+conf = env.Configure()
+conf.Finish()
+""")
+
+test.write(['dir2', 'SConscript'], """
+Import("env")
+conf = env.Configure()
+conf.Finish()
+SConscript(dirs=['sub1'], exports="env")
+""")
+
+test.write(['dir2', 'sub1', 'SConscript'], """
+Import("env")
+conf = env.Configure()
+conf.Finish()
+SConscript(dirs=['sub2'], exports="env")
+""")
+
+test.write(['dir2', 'sub1', 'sub2', 'SConscript'], """
+Import("env")
+conf = env.Configure()
+conf.Finish()
+""")
+
+test.run()
+
+test.pass_test()
diff --git a/test/Configure/basic.py b/test/Configure/basic.py
new file mode 100644 (file)
index 0000000..677f40f
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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 basic builds work with Configure contexts.
+"""
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+test.write('SConstruct', """\
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env)
+r1 = conf.CheckCHeader( 'math.h' )
+r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
+env = conf.Finish()
+Export( 'env' )
+SConscript( 'SConscript' )
+""")
+
+test.write('SConscript', """\
+Import( 'env' )
+env.Program( 'TestProgram', 'TestProgram.c' )
+""")
+
+test.write('TestProgram.c', """\
+#include <stdio.h>
+
+int main() {
+  printf( "Hello\\n" );
+}
+""")
+
+test.run()
+test.checkLogAndStdout(["Checking for C header file math.h... ",
+                       "Checking for C header file no_std_c_header.h... "],
+                      ["yes", "no"],
+                      [[((".c", NCR), (_obj, NCR))],
+                       [((".c", NCR), (_obj, NCF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+test.run()
+test.checkLogAndStdout(["Checking for C header file math.h... ",
+                       "Checking for C header file no_std_c_header.h... "],
+                      ["yes", "no"],
+                      [[((".c", CR), (_obj, CR))],
+                       [((".c", CR), (_obj, CF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+test.pass_test()
diff --git a/test/Configure/cache-not-ok.py b/test/Configure/cache-not-ok.py
new file mode 100644 (file)
index 0000000..82e32f6
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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 the cache mechanism works when checks are not ok.
+"""
+
+import os.path
+
+import TestSCons
+
+_exe = TestSCons._exe
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons()
+
+lib = test.Configure_lib
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+test.write('SConstruct', """\
+if int(ARGUMENTS.get('target_signatures_content', 0)):
+    TargetSignatures('content')
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = env.Configure()
+r1 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
+r2 = conf.CheckLib( 'no_c_library_SAFFDG' )   # leads to link error
+env = conf.Finish()
+if not (not r1 and not r2):
+     print "FAIL: ", r1, r2
+     Exit(1)
+""")
+
+test.run()
+test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+                       "Checking for C library no_c_library_SAFFDG... "],
+                      ["no"]*2,
+                      [[((".c", NCR), (_obj, NCF))],
+                       [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+test.run()
+test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+                       "Checking for C library no_c_library_SAFFDG... "],
+                      ["no"]*2,
+                      [[((".c", CR), (_obj, CF))],
+                       [((".c", CR), (_obj, CR), (_exe, CF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+# same should be true for TargetSignatures('content')
+
+test.run(arguments='--config=force target_signatures_content=1')
+test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+                       "Checking for C library no_c_library_SAFFDG... "],
+                      ["no"]*2,
+                      [[((".c", NCR), (_obj, NCF))],
+                       [((".c", NCR), (_obj, NCR), (_exe, NCF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+test.run(arguments='target_signatures_content=1')
+test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+                       "Checking for C library no_c_library_SAFFDG... "],
+                      ["no"]*2,
+                      [[((".c", CR), (_obj, CF))],
+                       [((".c", CR), (_obj, CR), (_exe, CF))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+test.pass_test()
diff --git a/test/Configure/cache-ok.py b/test/Configure/cache-ok.py
new file mode 100644 (file)
index 0000000..d8eac77
--- /dev/null
@@ -0,0 +1,118 @@
+#!/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 the cache mechanism works when checks are ok.
+"""
+
+import TestSCons
+
+_exe = TestSCons._exe
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons(match = TestSCons.match_re)
+
+lib = test.Configure_lib
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+test.write('SConstruct', """\
+if int(ARGUMENTS.get('target_signatures_content', 0)):
+    TargetSignatures('content')
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env)
+r1 = conf.CheckLibWithHeader( '%(lib)s', 'math.h', 'c' )
+r2 = conf.CheckLibWithHeader( None, 'math.h', 'c' )
+r3 = conf.CheckLib( '%(lib)s', autoadd=0 )
+r4 = conf.CheckLib( None, autoadd=0 )
+r5 = conf.CheckCHeader( 'math.h' )
+r6 = conf.CheckCXXHeader( 'vector' )
+env = conf.Finish()
+if not (r1 and r2 and r3 and r4 and r5 and r6):
+     Exit(1)
+""" % locals())
+
+test.run()
+test.checkLogAndStdout(["Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C header file math.h... ",
+                       "Checking for C++ header file vector... "],
+                      ["yes"]*6,
+                      [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
+                        [[((".c", NCR), (_obj, NCR))]] +
+                        [[((".cpp", NCR), (_obj, NCR))]],
+                      "config.log", ".sconf_temp", "SConstruct")    
+    
+
+test.run()
+test.checkLogAndStdout(["Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C header file math.h... ",
+                       "Checking for C++ header file vector... "],
+                      ["yes"]*6,
+                      [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
+                       [[((".c", CR), (_obj, CR))]] +
+                       [[((".cpp", CR), (_obj, CR))]],
+                      "config.log", ".sconf_temp", "SConstruct")
+
+# same should be true for TargetSignatures('content')
+
+test.run(arguments='target_signatures_content=1 --config=force')
+test.checkLogAndStdout(["Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C header file math.h... ",
+                       "Checking for C++ header file vector... "],
+                      ["yes"]*6,
+                      [[((".c", NCR), (_obj, NCR), (_exe, NCR))]]*4 +
+                        [[((".c", NCR), (_obj, NCR))]] +
+                        [[((".cpp", NCR), (_obj, NCR))]],
+                      "config.log", ".sconf_temp", "SConstruct")    
+
+test.run(arguments='target_signatures_content=1')
+test.checkLogAndStdout(["Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C library %s... " % lib,
+                       "Checking for C library None... ",
+                       "Checking for C header file math.h... ",
+                       "Checking for C++ header file vector... "],
+                      ["yes"]*6,
+                      [[((".c", CR), (_obj, CR), (_exe, CR))]]*4 +
+                       [[((".c", CR), (_obj, CR))]] +
+                       [[((".cpp", CR), (_obj, CR))]],
+                      "config.log", ".sconf_temp", "SConstruct")    
+
+test.pass_test()
diff --git a/test/Configure/config-h.py b/test/Configure/config-h.py
new file mode 100644 (file)
index 0000000..7bc8645
--- /dev/null
@@ -0,0 +1,155 @@
+#!/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 creation of a config.h file from a Configure context.
+"""
+
+import os
+import re
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_exact)
+
+lib = test.Configure_lib
+LIB = "LIB" + string.upper(lib)
+
+test.write('SConstruct', """\
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env, config_h = 'config.h')
+r1 = conf.CheckFunc('printf')
+r2 = conf.CheckFunc('noFunctionCall')
+r3 = conf.CheckType('int')
+r4 = conf.CheckType('noType')
+r5 = conf.CheckCHeader('stdio.h', '<>')
+r6 = conf.CheckCHeader('hopefullynoc-header.h')
+r7 = conf.CheckCXXHeader('vector', '<>')
+r8 = conf.CheckCXXHeader('hopefullynocxx-header.h')
+env = conf.Finish()
+conf = Configure(env, config_h = 'config.h')
+r9 = conf.CheckLib('%(lib)s', 'sin')
+r10 = conf.CheckLib('hopefullynolib', 'sin')
+r11 = conf.CheckLibWithHeader('%(lib)s', 'math.h', 'c')
+r12 = conf.CheckLibWithHeader('%(lib)s', 'hopefullynoheader2.h', 'c')
+r13 = conf.CheckLibWithHeader('hopefullynolib2', 'math.h', 'c')
+env = conf.Finish()
+""" % locals())
+
+expected_read_str = """\
+Checking for C function printf()... yes
+Checking for C function noFunctionCall()... no
+Checking for C type int... yes
+Checking for C type noType... no
+Checking for C header file stdio.h... yes
+Checking for C header file hopefullynoc-header.h... no
+Checking for C++ header file vector... yes
+Checking for C++ header file hopefullynocxx-header.h... no
+Checking for sin() in C library %(lib)s... yes
+Checking for sin() in C library hopefullynolib... no
+Checking for C library %(lib)s... yes
+Checking for C library %(lib)s... no
+Checking for C library hopefullynolib2... no
+""" % locals()
+
+expected_build_str = """\
+scons: Configure: creating config.h
+"""
+    
+expected_stdout = test.wrap_stdout(build_str=expected_build_str,
+                                       read_str=expected_read_str)
+
+expected_config_h = string.replace("""\
+#ifndef CONFIG_H_SEEN
+#define CONFIG_H_SEEN
+
+#define HAVE_PRINTF 1
+/* #undef HAVE_NOFUNCTIONCALL */
+#define HAVE_INT 1
+/* #undef HAVE_NOTYPE */
+#define HAVE_STDIO_H 1
+/* #undef HAVE_HOPEFULLYNOC_HEADER_H */
+#define HAVE_VECTOR 1
+/* #undef HAVE_HOPEFULLYNOCXX_HEADER_H */
+#define HAVE_%(LIB)s 1
+/* #undef HAVE_LIBHOPEFULLYNOLIB */
+#define HAVE_%(LIB)s 1
+/* #undef HAVE_%(LIB)s */
+/* #undef HAVE_LIBHOPEFULLYNOLIB2 */
+
+#endif /* CONFIG_H_SEEN */
+""" % locals(), "\n", os.linesep)
+
+test.run(stdout=expected_stdout)
+
+config_h = test.read(test.workpath('config.h'))
+if expected_config_h != config_h:
+    print "Unexpected config.h"
+    print "Expected: "
+    print "---------------------------------------------------------"
+    print repr(expected_config_h)
+    print "---------------------------------------------------------"
+    print "Found: "
+    print "---------------------------------------------------------"
+    print repr(config_h)
+    print "---------------------------------------------------------"
+    print "Stdio: "
+    print "---------------------------------------------------------"
+    print test.stdout()
+    print "---------------------------------------------------------"
+    test.fail_test()
+
+expected_read_str = re.sub(r'\b((yes)|(no))\b',
+                           r'(cached) \1',
+                           expected_read_str)
+expected_build_str = "scons: `.' is up to date.\n"
+expected_stdout = test.wrap_stdout(build_str=expected_build_str,
+                                   read_str=expected_read_str)
+#expected_stdout = string.replace(expected_stdout, "\n", os.linesep)
+
+test.run(stdout=expected_stdout)    
+
+config_h = test.read(test.workpath('config.h'))    
+if expected_config_h != config_h:
+    print "Unexpected config.h"
+    print "Expected: "
+    print "---------------------------------------------------------"
+    print repr(expected_config_h)
+    print "---------------------------------------------------------"
+    print "Found: "
+    print "---------------------------------------------------------"
+    print repr(config_h)
+    print "---------------------------------------------------------"
+    print "Stdio: "
+    print "---------------------------------------------------------"
+    print test.stdout()
+    print "---------------------------------------------------------"
+    test.fail_test()
+
+test.pass_test()
diff --git a/test/Configure/custom-tests.py b/test/Configure/custom-tests.py
new file mode 100644 (file)
index 0000000..7fb0ab7
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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 execution of custom test cases.
+"""
+
+import TestSCons
+
+_exe = TestSCons._exe
+_obj = TestSCons._obj
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+compileOK = '#include <stdio.h>\\nint main() {printf("Hello");return 0;}'
+compileFAIL = "syntax error"
+linkOK = compileOK
+linkFAIL = "void myFunc(); int main() { myFunc(); }"
+runOK = compileOK
+runFAIL = "int main() { return 1; }"
+
+test.write('pyAct.py', """\
+import sys
+print sys.argv[1]
+sys.exit(int(sys.argv[1]))
+""")
+
+test.write('SConstruct', """\
+def CheckCustom(test):
+    test.Message( 'Executing MyTest ... ' )
+    retCompileOK                = test.TryCompile( '%(compileOK)s', '.c' )
+    retCompileFAIL              = test.TryCompile( '%(compileFAIL)s', '.c' )
+    retLinkOK                   = test.TryLink( '%(linkOK)s', '.c' )
+    retLinkFAIL                 = test.TryLink( '%(linkFAIL)s', '.c' )
+    (retRunOK, outputRunOK)     = test.TryRun( '%(runOK)s', '.c' )
+    (retRunFAIL, outputRunFAIL) = test.TryRun( '%(runFAIL)s', '.c' )
+    (retActOK, outputActOK) = test.TryAction( '%(_python_)s pyAct.py 0 > $TARGET' )
+    (retActFAIL, outputActFAIL) = test.TryAction( '%(_python_)s pyAct.py 1 > $TARGET' )
+    resOK = retCompileOK and retLinkOK and retRunOK and outputRunOK=="Hello"
+    resOK = resOK and retActOK and int(outputActOK)==0
+    resFAIL = retCompileFAIL or retLinkFAIL or retRunFAIL or outputRunFAIL!=""
+    resFAIL = resFAIL or retActFAIL or outputActFAIL!=""
+    test.Result( int(resOK and not resFAIL) )
+    return resOK and not resFAIL
+
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure( env, custom_tests={'CheckCustom' : CheckCustom} )
+conf.CheckCustom()
+env = conf.Finish()
+""" % locals())
+
+test.run()
+
+test.checkLogAndStdout(["Executing MyTest ... "],
+                      ["yes"],
+                      [[(('.c', NCR), (_obj, NCR)),
+                        (('.c', NCR), (_obj, NCF)),
+                        (('.c', NCR), (_obj, NCR), (_exe, NCR)),
+                        (('.c', NCR), (_obj, NCR), (_exe, NCF)),
+                        (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCR)),
+                        (('.c', NCR), (_obj, NCR), (_exe, NCR), (_exe + '.out', NCF)),
+                        (('', NCR),),
+                        (('', NCF),)]],
+                       "config.log", ".sconf_temp", "SConstruct")
+
+test.run()
+
+test.checkLogAndStdout(["Executing MyTest ... "],
+                      ["yes"],
+                      [[(('.c', CR), (_obj, CR)),
+                        (('.c', CR), (_obj, CF)),
+                        (('.c', CR), (_obj, CR), (_exe, CR)),
+                        (('.c', CR), (_obj, CR), (_exe, CF)),
+                        (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CR)),
+                        (('.c', CR), (_obj, CR), (_exe, CR), (_exe + '.out', CF)),
+                        (('', CR),),
+                        (('', CF),)]],
+                       "config.log", ".sconf_temp", "SConstruct")
+
+test.pass_test()
diff --git a/test/Configure/option--Q.py b/test/Configure/option--Q.py
new file mode 100644 (file)
index 0000000..ab9d488
--- /dev/null
@@ -0,0 +1,46 @@
+#!/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 the -Q option suppresses Configure context output.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+env = Environment()
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env)
+r1 = conf.CheckCHeader('stdio.h')
+env = conf.Finish()
+""")
+
+test.run(arguments='-Q', stdout="scons: `.' is up to date.\n", stderr="")
+
+test.pass_test()
diff --git a/test/Configure/option--config.py b/test/Configure/option--config.py
new file mode 100644 (file)
index 0000000..95a0d3b
--- /dev/null
@@ -0,0 +1,122 @@
+#!/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 use of the --config=<auto|force|cache> option.
+"""
+
+import os.path
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+test = TestSCons.TestSCons()
+
+test.subdir('include')
+
+NCR = test.NCR  # non-cached rebuild
+CR  = test.CR   # cached rebuild (up to date)
+NCF = test.NCF  # non-cached build failure
+CF  = test.CF   # cached build failure
+
+SConstruct_path = test.workpath('SConstruct')
+
+test.write(SConstruct_path, """
+env = Environment(CPPPATH='#/include')
+import os
+env.AppendENVPath('PATH', os.environ['PATH'])
+conf = Configure(env)
+r1 = conf.CheckCHeader('non_system_header1.h')
+r2 = conf.CheckCHeader('non_system_header2.h')
+env = conf.Finish()
+""")
+
+test.write(['include', 'non_system_header1.h'], """
+/* A header */
+""")
+
+conftest_0_c = os.path.join(".sconf_temp", "conftest_0.c")
+
+test.run(arguments='--config=cache', status=2, stderr="""
+scons: *** "%(conftest_0_c)s" is not yet built and cache is forced.
+File "%(SConstruct_path)s", line 6, in ?
+""" % locals())
+
+test.run(arguments='--config=auto')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["yes", "no"],
+                    [[((".c", NCR), (_obj, NCR))],
+                     [((".c", NCR), (_obj, NCF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.run(arguments='--config=auto')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["yes", "no"],
+                    [[((".c", CR), (_obj, CR))],
+                     [((".c", CR), (_obj, CF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.run(arguments='--config=force')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["yes", "no"],
+                    [[((".c", NCR), (_obj, NCR))],
+                     [((".c", NCR), (_obj, NCF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.run(arguments='--config=cache')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["yes", "no"],
+                    [[((".c", CR), (_obj, CR))],
+                     [((".c", CR), (_obj, CF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.write(['include', 'non_system_header2.h'], """
+/* Another header */
+""")
+test.unlink(['include', 'non_system_header1.h'])
+
+test.run(arguments='--config=cache')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["yes", "no"],
+                    [[((".c", CR), (_obj, CR))],
+                     [((".c", CR), (_obj, CF))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.run(arguments='--config=auto')
+test.checkLogAndStdout( ["Checking for C header file non_system_header1.h... ",
+                    "Checking for C header file non_system_header2.h... "],
+                    ["no", "yes"],
+                    [[((".c", CR), (_obj, NCF))],
+                     [((".c", CR), (_obj, NCR))]],
+                    "config.log", ".sconf_temp", "SConstruct")
+
+test.pass_test()
diff --git a/test/GetOption/help.py b/test/GetOption/help.py
new file mode 100644 (file)
index 0000000..37f9555
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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 use of GetOption('help') to short-circuit work.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+if GetOption('help'):
+   print "GetOption('help') set"
+else:
+    print "no help for you"
+""")
+
+test.run(arguments = '-q -Q', stdout = "no help for you\n")
+
+expect = "GetOption('help') set"
+
+test.run(arguments = '-q -Q -h')
+test.fail_test(string.split(test.stdout(), '\n')[0] != expect)
+
+test.run(arguments = '-q -Q --help')
+test.fail_test(string.split(test.stdout(), '\n')[0] != expect)
+
+test.pass_test()
index 79857d060796b434e6d09219f93a8c1c3436288e..b28556829384f81d44e3bd0cb716fa0c99be5c6a 100644 (file)
@@ -37,12 +37,18 @@ test = TestSCons.TestSCons()
 
 
 test.write('mymidl.py', """
+import os.path
 import sys
-outfile = open(sys.argv[1], 'wb')
+out_tlb = open(sys.argv[1], 'wb')
+base = os.path.splitext(sys.argv[1])[0]
+out_h = open(base + '.h', 'wb')
+out_c = open(base + '_i.c', 'wb')
 for f in sys.argv[2:]:
     infile = open(f, 'rb')
     for l in filter(lambda l: l != '/*midl*/\\n', infile.readlines()):
-        outfile.write(l)
+        out_tlb.write(l)
+        out_h.write(l)
+        out_c.write(l)
 sys.exit(0)
 """)
 
@@ -57,6 +63,10 @@ test.write('aaa.idl', "aaa.idl\n/*midl*/\n")
 test.run(arguments = '.')
 
 test.must_match('aaa.tlb', "aaa.idl\n")
+test.must_match('aaa.h', "aaa.idl\n")
+test.must_match('aaa_i.c', "aaa.idl\n")
+
+test.up_to_date(options = '--debug=explain', arguments = 'aaa.tlb')
 
 
 
diff --git a/test/MSVC/multiple-pdb.py b/test/MSVC/multiple-pdb.py
new file mode 100644 (file)
index 0000000..f359fb9
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/env python\r
+#\r
+# __COPYRIGHT__\r
+#\r
+# Permission is hereby granted, free of charge, to any person obtaining\r
+# a copy of this software and associated documentation files (the\r
+# "Software"), to deal in the Software without restriction, including\r
+# without limitation the rights to use, copy, modify, merge, publish,\r
+# distribute, sublicense, and/or sell copies of the Software, and to\r
+# permit persons to whom the Software is furnished to do so, subject to\r
+# the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be included\r
+# in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY\r
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+#\r
+\r
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"\r
+\r
+"""\r
+Verify that setting $PDB to '${TARGET}.pdb allows us to build multiple\r
+programs with separate .pdb files from the same environment.\r
+\r
+Under the covers, this verifies that emitters support expansion of the\r
+$TARGET variable (and implicitly $SOURCE), using the original specified\r
+list(s).\r
+"""\r
+\r
+import sys\r
+\r
+import TestSCons\r
+\r
+_exe = TestSCons._exe\r
+\r
+test = TestSCons.TestSCons()\r
+\r
+if sys.platform != 'win32':\r
+    msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform\r
+    test.skip_test(msg)\r
+\r
+test.write('SConstruct', """\\r
+env = Environment(PDB = '${TARGET}.pdb')\r
+env.Program('test1.cpp')\r
+env.Program('test2.cpp')\r
+""")\r
+\r
+test.write('test1.cpp', """\\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+int\r
+main(int argc, char *argv)\r
+{\r
+    printf("test1.cpp\\n");\r
+    exit (0);\r
+}\r
+""")\r
+\r
+test.write('test2.cpp', """\\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+int\r
+main(int argc, char *argv)\r
+{\r
+    printf("test2.cpp\\n");\r
+    exit (0);\r
+}\r
+""")\r
+\r
+test.run(arguments = '.')\r
+\r
+test.must_exist('test1%s'     % _exe)\r
+test.must_exist('test1%s.pdb' % _exe)\r
+test.must_exist('test2%s'     % _exe)\r
+test.must_exist('test2%s.pdb' % _exe)\r
+\r
+test.pass_test()\r
diff --git a/test/MSVC/pdb-BuildDir-path.py b/test/MSVC/pdb-BuildDir-path.py
new file mode 100644 (file)
index 0000000..223e535
--- /dev/null
@@ -0,0 +1,76 @@
+#!/usr/bin/env python\r
+#\r
+# __COPYRIGHT__\r
+#\r
+# Permission is hereby granted, free of charge, to any person obtaining\r
+# a copy of this software and associated documentation files (the\r
+# "Software"), to deal in the Software without restriction, including\r
+# without limitation the rights to use, copy, modify, merge, publish,\r
+# distribute, sublicense, and/or sell copies of the Software, and to\r
+# permit persons to whom the Software is furnished to do so, subject to\r
+# the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be included\r
+# in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY\r
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+#\r
+\r
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"\r
+\r
+"""\r
+Verify that .pdb files get put in a build_dir correctly.\r
+"""\r
+\r
+import sys\r
+\r
+import TestSCons\r
+\r
+_exe = TestSCons._exe\r
+\r
+test = TestSCons.TestSCons()\r
+\r
+if sys.platform != 'win32':\r
+    msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform\r
+    test.skip_test(msg)\r
+\r
+test.subdir('src')\r
+\r
+test.write('SConstruct', """\\r
+env = Environment()\r
+env.Append(BINDIR = '#bin')\r
+\r
+Export('env')\r
+SConscript('#src/SConscript', duplicate = 0, build_dir = '#.build')\r
+""")\r
+\r
+test.write(['src', 'SConscript'], """\\r
+Import('env')\r
+env['PDB'] = '${TARGET}.pdb'\r
+p = env.Program('test.exe', 'test.cpp')\r
+env.Install(env['BINDIR'], p)\r
+""")\r
+\r
+test.write(['src', 'test.cpp'], """\\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+int\r
+main(int argc, char *argv)\r
+{\r
+    printf("test.cpp\\n");\r
+    exit (0);\r
+}\r
+""")\r
+\r
+test.run(arguments = '.')\r
+\r
+test.must_exist(['.build', 'test%s'     % _exe])\r
+test.must_exist(['.build', 'test%s.pdb' % _exe])\r
+\r
+test.pass_test()\r
index b9827e7cc8fc2d3ae0329c68bde2087bdb98b5b7..aaffd7d880115c6c360e92c33e87883c02158ffa 100644 (file)
@@ -53,8 +53,8 @@ Global
 \tGlobalSection(ProjectDependencies) = postSolution
 \tEndGlobalSection
 \tGlobalSection(ProjectConfiguration) = postSolution
-\t\t{SLNGUID}.Release.ActiveCfg = Release|Win32
-\t\t{SLNGUID}.Release.Build.0 = Release|Win32
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release.ActiveCfg = Release|Win32
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release.Build.0 = Release|Win32
 \tEndGlobalSection
 \tGlobalSection(ExtensibilityGlobals) = postSolution
 \tEndGlobalSection
index 057f34fe9b7bacfe5e0f6f90e33e1a18bcb58ea9..98bd9da19f7feb0d02cf6d7c5ebf996c9b9cca34 100644 (file)
@@ -53,8 +53,8 @@ Global
 \t\tConfigName.0 = Release
 \tEndGlobalSection
 \tGlobalSection(ProjectConfiguration) = postSolution
-\t\t{SLNGUID}.Release.ActiveCfg = Release|Win32
-\t\t{SLNGUID}.Release.Build.0 = Release|Win32
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release.ActiveCfg = Release|Win32
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release.Build.0 = Release|Win32
 \tEndGlobalSection
 \tGlobalSection(ExtensibilityGlobals) = postSolution
 \tEndGlobalSection
diff --git a/test/TEX/usepackage.py b/test/TEX/usepackage.py
new file mode 100644 (file)
index 0000000..4be7f58
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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__"
+
+"""
+Validate that we can set the LATEX string to our own utility, that
+the produced .dvi, .aux and .log files get removed by the -c option,
+and that we can use this to wrap calls to the real latex utility.
+"""
+
+import os
+import os.path
+import string
+import sys
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('latex')
+
+if not latex:
+    test.skip_test('could not find latex; skipping test\n')
+
+test.write('SConstruct', """
+import os
+ENV = { 'PATH' : os.environ['PATH'],
+        'TEXINPUTS' : [ 'subdir', os.environ.get('TEXINPUTS', '') ] }
+foo = Environment(ENV = ENV)
+foo.DVI(target = 'foo.dvi', source = 'foo.ltx')
+""" % locals())
+
+test.write('foo.ltx', r"""
+\documentclass{letter}
+\usepackage{bar}
+\begin{document}
+This is the foo.ltx file.
+\end{document}
+""")
+
+test.write('bar.sty', "\n")
+
+test.run(arguments = 'foo.dvi', stderr = None)
+
+test.write('bar.sty', "\n\n\n")
+
+test.not_up_to_date(arguments = 'foo.dvi', stderr = None)
+
+
+
+test.pass_test()
index f69b00f1154610d5e939d05091abcf9f513f46d5..9b721d2b559a7989365db4fe65fa0c241272244e 100644 (file)
@@ -41,8 +41,8 @@ test.subdir('work1', ['work1', 'src'], ['work1', 'src', 'subdir'],
             'work4', ['work4', 'src'], ['work4', 'src', 'subdir'],
             'work5')
 
-subdir_file6 = os.path.join('subdir', 'file6')
-subdir_file6_in = os.path.join('subdir', 'file6.in')
+subdir_file7 = os.path.join('subdir', 'file7')
+subdir_file7_in = os.path.join('subdir', 'file7.in')
 cat_py = test.workpath('cat.py')
 
 test.write(cat_py, r"""
@@ -113,7 +113,9 @@ env.Command('file4', 'file4.in',
              r'%(_python_)s %(cat_py)s $TARGET $FILE4FLAG $SOURCES',
              FILE4FLAG='-')
 env.Cat('file5', 'file5.k')
-env.Cat('subdir/file6', 'subdir/file6.in')
+file6 = env.Cat('file6', 'file6.in')
+AlwaysBuild(file6)
+env.Cat('subdir/file7', 'subdir/file7.in')
 """ % locals())
 
 test.write(['work1', 'src', 'aaa'], "aaa 1\n")
@@ -149,7 +151,9 @@ include ../inc/bbb.k
 file5.k 1 line 4
 """)
 
-test.write(['work1', 'src', 'subdir', 'file6.in'], "subdir/file6.in 1\n")
+test.write(['work1', 'src', 'file6.in'], "file6.in 1\n")
+
+test.write(['work1', 'src', 'subdir', 'file7.in'], "subdir/file7.in 1\n")
 
 work1_inc_aaa = test.workpath('work1', 'inc', 'aaa')
 work1_inc_ddd = test.workpath('work1', 'inc', 'ddd')
@@ -176,8 +180,10 @@ scons: building `%(work1_inc_bbb_k)s' because it doesn't exist
 Install file: "bbb.k" as "%(work1_inc_bbb_k)s"
 scons: building `file5' because it doesn't exist
 %(_python_)s %(cat_py)s file5 file5.k
-scons: building `%(subdir_file6)s' because it doesn't exist
-%(_python_)s %(cat_py)s %(subdir_file6)s %(subdir_file6_in)s
+scons: building `file6' because it doesn't exist
+%(_python_)s %(cat_py)s file6 file6.in
+scons: building `%(subdir_file7)s' because it doesn't exist
+%(_python_)s %(cat_py)s %(subdir_file7)s %(subdir_file7_in)s
 """ % locals())
 
 test.run(chdir='work1/src', arguments=args, stdout=expect)
@@ -200,6 +206,7 @@ ddd 1
 eee.in 1
 file5.k 1 line 4
 """)
+test.must_match(['work1', 'src', 'file6'], "file6.in 1\n")
 
 #
 test.write(['work1', 'src', 'file1.in'], "file1.in 2\n")
@@ -223,6 +230,8 @@ scons: rebuilding `%(work1_inc_bbb_k)s' because:
 Install file: "bbb.k" as "%(work1_inc_bbb_k)s"
 scons: rebuilding `file5' because `%(work1_inc_bbb_k)s' changed
 %(_python_)s %(cat_py)s file5 file5.k
+scons: rebuilding `file6' because AlwaysBuild() is specified
+%(_python_)s %(cat_py)s file6 file6.in
 """ % locals())
 
 test.run(chdir='work1/src', arguments=args, stdout=expect)
index f806bbee1d132f9abe1c3824290c840dc5de1e85..8c7ef1e073faeb445596447435ba546985ec2722 100644 (file)
@@ -34,7 +34,7 @@ import TestSCons
 
 test = TestSCons.TestSCons()
 
-test.write('SConstruct', """
+test.write('SConscript', """\
 def cat(env, source, target):
     target = str(target[0])
     source = map(str, source)
@@ -53,23 +53,66 @@ test.write('aaa.in', "aaa.in\n")
 test.write('bbb.in', "bbb.in\n")
 test.write('ccc.in', "ccc.in\n")
 
-test.run(arguments = '--random .')
 
-test.fail_test(test.read('all') != "aaa.in\nbbb.in\nccc.in\n")
+
+test.write('SConstruct', """\
+SetOption('random', 1)
+SConscript('SConscript')
+""")
+
+test.run(arguments = '-n -Q')
+non_random_output = test.stdout()
+
+tries = 0
+max_tries = 3
+while test.stdout() == non_random_output:
+    if tries >= max_tries:
+        print "--random generated the non-random output %s times!" % max_tries
+        test.fail_test()
+    tries = tries + 1
+    test.run(arguments = '-n -Q --random')
+
+
+
+test.write('SConstruct', """\
+SConscript('SConscript')
+""")
+
+test.run(arguments = '-n -Q')
+non_random_output = test.stdout()
+
+tries = 0
+max_tries = 3
+while test.stdout() == non_random_output:
+    if tries >= max_tries:
+        print "--random generated the non-random output %s times!" % max_tries
+        test.fail_test()
+    tries = tries + 1
+    test.run(arguments = '-n -Q --random')
+
+
+
+test.run(arguments = '-Q --random')
+
+test.must_match('all', "aaa.in\nbbb.in\nccc.in\n")
 
 test.run(arguments = '-q --random .')
 
 test.run(arguments = '-c --random .')
 
-test.fail_test(os.path.exists(test.workpath('aaa.out')))
-test.fail_test(os.path.exists(test.workpath('bbb.out')))
-test.fail_test(os.path.exists(test.workpath('ccc.out')))
-test.fail_test(os.path.exists(test.workpath('all')))
+test.must_not_exist(test.workpath('aaa.out'))
+test.must_not_exist(test.workpath('bbb.out'))
+test.must_not_exist(test.workpath('ccc.out'))
+test.must_not_exist(test.workpath('all'))
 
 test.run(arguments = '-q --random .', status = 1)
 
 test.run(arguments = '--random .')
 
-test.fail_test(test.read('all') != "aaa.in\nbbb.in\nccc.in\n")
+test.must_match('all', "aaa.in\nbbb.in\nccc.in\n")
+
+test.run(arguments = '-c --random .')
+
+
 
 test.pass_test()