summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2007-06-01 21:14:13 (GMT)
committerSteven Knight <knight@baldmt.com>2007-06-01 21:14:13 (GMT)
commitf311f5ac8b8da71b93166bf566aa0a89c91abd50 (patch)
tree7e913c029bfbdf97ba614bb07f639af5d45ae2ae
parent3978c6205c89626792ff84de70e863967a912aba (diff)
downloadSCons-f311f5ac8b8da71b93166bf566aa0a89c91abd50.zip
SCons-f311f5ac8b8da71b93166bf566aa0a89c91abd50.tar.gz
SCons-f311f5ac8b8da71b93166bf566aa0a89c91abd50.tar.bz2
Merged revisions 1907-1940,1942-1967 via svnmerge from
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(). ........
-rw-r--r--.svnt/conf18
-rw-r--r--QMTest/TestSCons.py137
-rw-r--r--doc/man/scons.162
-rw-r--r--doc/user/caching.in25
-rw-r--r--doc/user/libraries.in60
-rw-r--r--doc/user/libraries.sgml50
-rw-r--r--doc/user/main.in3
-rw-r--r--src/CHANGES.txt65
-rw-r--r--src/RELEASE.txt27
-rw-r--r--src/engine/SCons/Action.py6
-rw-r--r--src/engine/SCons/ActionTests.py8
-rw-r--r--src/engine/SCons/Builder.py9
-rw-r--r--src/engine/SCons/BuilderTests.py112
-rw-r--r--src/engine/SCons/Conftest.py2
-rw-r--r--src/engine/SCons/Environment.py20
-rw-r--r--src/engine/SCons/EnvironmentTests.py67
-rw-r--r--src/engine/SCons/Node/FS.py12
-rw-r--r--src/engine/SCons/Node/__init__.py23
-rw-r--r--src/engine/SCons/Platform/sunos.py2
-rw-r--r--src/engine/SCons/Scanner/LaTeX.py6
-rw-r--r--src/engine/SCons/Script/Main.py27
-rw-r--r--src/engine/SCons/Script/__init__.py1
-rw-r--r--src/engine/SCons/Taskmaster.py3
-rw-r--r--src/engine/SCons/TaskmasterTests.py9
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py40
-rw-r--r--src/engine/SCons/Tool/JavaCommonTests.py24
-rw-r--r--src/engine/SCons/Tool/__init__.py5
-rw-r--r--src/engine/SCons/Tool/midl.py14
-rw-r--r--src/engine/SCons/Tool/mslink.py16
-rw-r--r--src/engine/SCons/Tool/msvs.py6
-rw-r--r--src/engine/SCons/Util.py76
-rw-r--r--src/engine/SCons/compat/builtins.py6
-rw-r--r--test/AddMethod.py61
-rw-r--r--test/AlwaysBuild.py32
-rw-r--r--test/CFILESUFFIX.py19
-rw-r--r--test/CXX/CXXFILESUFFIX.py15
-rw-r--r--test/CacheDir/symlink.py68
-rw-r--r--test/Configure/Action-error.py48
-rw-r--r--test/Configure/BuildDir-SConscript.py159
-rw-r--r--test/Configure/BuildDir.py91
-rw-r--r--test/Configure/Builder-call.py57
-rw-r--r--test/Configure/Configure.py939
-rw-r--r--test/Configure/ConfigureDryRunError.py99
-rw-r--r--test/Configure/SConscript.py74
-rw-r--r--test/Configure/basic.py83
-rw-r--r--test/Configure/cache-not-ok.py96
-rw-r--r--test/Configure/cache-ok.py118
-rw-r--r--test/Configure/config-h.py155
-rw-r--r--test/Configure/custom-tests.py111
-rw-r--r--test/Configure/option--Q.py46
-rw-r--r--test/Configure/option--config.py122
-rw-r--r--test/GetOption/help.py54
-rw-r--r--test/IDL/MIDLCOM.py14
-rw-r--r--test/MSVC/multiple-pdb.py83
-rw-r--r--test/MSVC/pdb-BuildDir-path.py76
-rw-r--r--test/MSVS/vs-7.0-files.py4
-rw-r--r--test/MSVS/vs-7.1-files.py4
-rw-r--r--test/TEX/usepackage.py74
-rw-r--r--test/explain.py21
-rw-r--r--test/option--random.py59
60 files changed, 2632 insertions, 1091 deletions
diff --git a/.svnt/conf b/.svnt/conf
new file mode 100644
index 0000000..255a4ac
--- /dev/null
+++ b/.svnt/conf
@@ -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]
diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py
index 196c24e..8d820b6 100644
--- a/QMTest/TestSCons.py
+++ b/QMTest/TestSCons.py
@@ -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),
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 73e3df9..c0b91ec 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -1975,6 +1975,59 @@ 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 )
.TP
.RI env.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:
diff --git a/doc/user/caching.in b/doc/user/caching.in
index 015407b..8dfa731 100644
--- a/doc/user/caching.in
+++ b/doc/user/caching.in
@@ -430,6 +430,31 @@
</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>
<!--
diff --git a/doc/user/libraries.in b/doc/user/libraries.in
index e5368d1..9a12062 100644
--- a/doc/user/libraries.in
+++ b/doc/user/libraries.in
@@ -94,6 +94,66 @@
</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>
<para>
diff --git a/doc/user/libraries.sgml b/doc/user/libraries.sgml
index ca2cb97..96814a7 100644
--- a/doc/user/libraries.sgml
+++ b/doc/user/libraries.sgml
@@ -92,6 +92,56 @@
</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>
<para>
diff --git a/doc/user/main.in b/doc/user/main.in
index d864350..aaddb2a 100644
--- a/doc/user/main.in
+++ b/doc/user/main.in
@@ -117,6 +117,9 @@
XXX SetOption('duplicate')
XXX - - duplicate=
+ XXX GetOption('help')
+ XXX SetOption('help')
+
XXX GetOption('num_jobs')
XXX SetOption('num_jobs')
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index a47992a..9cf69e9 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -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:
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index b19a39c..6dd66aa 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -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
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 438588b..a010c4a 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -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)
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 08373c3..87fb4b0 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -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)
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index ecc93c0..c4b1d1d 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -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
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index bb5a69a..3996d5c 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -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."""
diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py
index 81a8ee4..bb3be56 100644
--- a/src/engine/SCons/Conftest.py
+++ b/src/engine/SCons/Conftest.py
@@ -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:
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index e5eb40c..94cdf74 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -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
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 70f9026..a8b718d 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -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"""
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index a16fee4..c9a1443 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -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()
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 6644d7a..f550b5b 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -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
diff --git a/src/engine/SCons/Platform/sunos.py b/src/engine/SCons/Platform/sunos.py
index ed9521e..5029860 100644
--- a/src/engine/SCons/Platform/sunos.py
+++ b/src/engine/SCons/Platform/sunos.py
@@ -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'
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py
index d875e6e..645a894 100644
--- a/src/engine/SCons/Scanner/LaTeX.py
+++ b/src/engine/SCons/Scanner/LaTeX.py
@@ -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))
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index ca7f68c..d80050d 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -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
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index fde4997..e970989 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -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
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 9a5011b..acb8c9b 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -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:
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index 757306f..718851d 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -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()
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 177d579..d340d5b 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -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
diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py
index 853afd4..e848bf9 100644
--- a/src/engine/SCons/Tool/JavaCommonTests.py
+++ b/src/engine/SCons/Tool/JavaCommonTests.py
@@ -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__":
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index b2e2eff..dea77fd 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -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)
diff --git a/src/engine/SCons/Tool/midl.py b/src/engine/SCons/Tool/midl.py
index 67579e9..811d573 100644
--- a/src/engine/SCons/Tool/midl.py
+++ b/src/engine/SCons/Tool/midl.py
@@ -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()
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 4b90e3d..c071aa7 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -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)
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index db8e8fd..138f920 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -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')
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index f1e856b..a5ea859 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -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__
diff --git a/src/engine/SCons/compat/builtins.py b/src/engine/SCons/compat/builtins.py
index a477a48..1124cf0 100644
--- a/src/engine/SCons/compat/builtins.py
+++ b/src/engine/SCons/compat/builtins.py
@@ -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
index 0000000..ef4a8d0
--- /dev/null
+++ b/test/AddMethod.py
@@ -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()
diff --git a/test/AlwaysBuild.py b/test/AlwaysBuild.py
index a107302..d1f07fd 100644
--- a/test/AlwaysBuild.py
+++ b/test/AlwaysBuild.py
@@ -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()
diff --git a/test/CFILESUFFIX.py b/test/CFILESUFFIX.py
index 1fa615a..08c40c2 100644
--- a/test/CFILESUFFIX.py
+++ b/test/CFILESUFFIX.py
@@ -24,6 +24,10 @@
__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()
diff --git a/test/CXX/CXXFILESUFFIX.py b/test/CXX/CXXFILESUFFIX.py
index b156f74..fbc34ff 100644
--- a/test/CXX/CXXFILESUFFIX.py
+++ b/test/CXX/CXXFILESUFFIX.py
@@ -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
index 0000000..6dd1f94
--- /dev/null
+++ b/test/CacheDir/symlink.py
@@ -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
index 0000000..0abcc7c
--- /dev/null
+++ b/test/Configure/Action-error.py
@@ -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
index 0000000..47b7d82
--- /dev/null
+++ b/test/Configure/BuildDir-SConscript.py
@@ -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
index 0000000..ca3c147
--- /dev/null
+++ b/test/Configure/BuildDir.py
@@ -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
index 0000000..a6f2fa5
--- /dev/null
+++ b/test/Configure/Builder-call.py
@@ -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
index 4063699..0000000
--- a/test/Configure/Configure.py
+++ /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
index 0000000..04fbc75
--- /dev/null
+++ b/test/Configure/ConfigureDryRunError.py
@@ -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
index 0000000..2bfe2f7
--- /dev/null
+++ b/test/Configure/SConscript.py
@@ -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
index 0000000..677f40f
--- /dev/null
+++ b/test/Configure/basic.py
@@ -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
index 0000000..82e32f6
--- /dev/null
+++ b/test/Configure/cache-not-ok.py
@@ -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
index 0000000..d8eac77
--- /dev/null
+++ b/test/Configure/cache-ok.py
@@ -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
index 0000000..7bc8645
--- /dev/null
+++ b/test/Configure/config-h.py
@@ -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
index 0000000..7fb0ab7
--- /dev/null
+++ b/test/Configure/custom-tests.py
@@ -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
index 0000000..ab9d488
--- /dev/null
+++ b/test/Configure/option--Q.py
@@ -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
index 0000000..95a0d3b
--- /dev/null
+++ b/test/Configure/option--config.py
@@ -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
index 0000000..37f9555
--- /dev/null
+++ b/test/GetOption/help.py
@@ -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()
diff --git a/test/IDL/MIDLCOM.py b/test/IDL/MIDLCOM.py
index 79857d0..b285568 100644
--- a/test/IDL/MIDLCOM.py
+++ b/test/IDL/MIDLCOM.py
@@ -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
index 0000000..f359fb9
--- /dev/null
+++ b/test/MSVC/multiple-pdb.py
@@ -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 setting $PDB to '${TARGET}.pdb allows us to build multiple
+programs with separate .pdb files from the same environment.
+
+Under the covers, this verifies that emitters support expansion of the
+$TARGET variable (and implicitly $SOURCE), using the original specified
+list(s).
+"""
+
+import sys
+
+import TestSCons
+
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+ msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform
+ test.skip_test(msg)
+
+test.write('SConstruct', """\
+env = Environment(PDB = '${TARGET}.pdb')
+env.Program('test1.cpp')
+env.Program('test2.cpp')
+""")
+
+test.write('test1.cpp', """\
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *argv)
+{
+ printf("test1.cpp\\n");
+ exit (0);
+}
+""")
+
+test.write('test2.cpp', """\
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *argv)
+{
+ printf("test2.cpp\\n");
+ exit (0);
+}
+""")
+
+test.run(arguments = '.')
+
+test.must_exist('test1%s' % _exe)
+test.must_exist('test1%s.pdb' % _exe)
+test.must_exist('test2%s' % _exe)
+test.must_exist('test2%s.pdb' % _exe)
+
+test.pass_test()
diff --git a/test/MSVC/pdb-BuildDir-path.py b/test/MSVC/pdb-BuildDir-path.py
new file mode 100644
index 0000000..223e535
--- /dev/null
+++ b/test/MSVC/pdb-BuildDir-path.py
@@ -0,0 +1,76 @@
+#!/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 .pdb files get put in a build_dir correctly.
+"""
+
+import sys
+
+import TestSCons
+
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+ msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform
+ test.skip_test(msg)
+
+test.subdir('src')
+
+test.write('SConstruct', """\
+env = Environment()
+env.Append(BINDIR = '#bin')
+
+Export('env')
+SConscript('#src/SConscript', duplicate = 0, build_dir = '#.build')
+""")
+
+test.write(['src', 'SConscript'], """\
+Import('env')
+env['PDB'] = '${TARGET}.pdb'
+p = env.Program('test.exe', 'test.cpp')
+env.Install(env['BINDIR'], p)
+""")
+
+test.write(['src', 'test.cpp'], """\
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *argv)
+{
+ printf("test.cpp\\n");
+ exit (0);
+}
+""")
+
+test.run(arguments = '.')
+
+test.must_exist(['.build', 'test%s' % _exe])
+test.must_exist(['.build', 'test%s.pdb' % _exe])
+
+test.pass_test()
diff --git a/test/MSVS/vs-7.0-files.py b/test/MSVS/vs-7.0-files.py
index b9827e7..aaffd7d 100644
--- a/test/MSVS/vs-7.0-files.py
+++ b/test/MSVS/vs-7.0-files.py
@@ -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
diff --git a/test/MSVS/vs-7.1-files.py b/test/MSVS/vs-7.1-files.py
index 057f34f..98bd9da 100644
--- a/test/MSVS/vs-7.1-files.py
+++ b/test/MSVS/vs-7.1-files.py
@@ -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
index 0000000..4be7f58
--- /dev/null
+++ b/test/TEX/usepackage.py
@@ -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()
diff --git a/test/explain.py b/test/explain.py
index f69b00f..9b721d2 100644
--- a/test/explain.py
+++ b/test/explain.py
@@ -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)
diff --git a/test/option--random.py b/test/option--random.py
index f806bbe..8c7ef1e 100644
--- a/test/option--random.py
+++ b/test/option--random.py
@@ -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()