regardless of whether a target
file was rebuilt or retrieved from the cache.
+.TP
+.RI --config= mode
+This specifies how the
+.B Configure
+call should use or generate the
+results of configuration tests.
+The option should be specified from
+among the following choices:
+
+.TP
+--config=auto
+scons will use its normal dependency mechanisms
+to decide if a test must be rebuilt or not.
+This saves time by not running the same configuration tests
+every time you invoke scons,
+but will overlook changes in system header files
+or external commands (such as compilers)
+if you don't specify those dependecies explicitly.
+This is the default behavior.
+
+.TP
+--config=force
+If this option is specified,
+all configuration tests will be re-run
+regardless of whether the
+cached results are out of date.
+This can be used to explicitly
+force the configuration tests to be updated
+in response to an otherwise unconfigured change
+in a system header file or compiler.
+
+.TP
+--config=cache
+If this option is specified,
+no configuration tests will be rerun
+and all results will be taken from cache.
+Note that scons will still consider it an error
+if --config=cache is specified
+and a necessary test does not
+yet have any results in the cache.
+
.TP
.RI "-C" " directory" ", --directory=" directory
Change to the specified
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
-.RI Configure( env ", [" custom_tests ", " conf_dir ", " log_file ])
+.RI Configure( env ", [" custom_tests ", " conf_dir ", " log_file ", " config_h ])
.TP
-.RI env.Configure([ custom_tests ", " conf_dir ", " log_file ])
+.RI env.Configure([ custom_tests ", " conf_dir ", " log_file ", " config_h ])
Creates a Configure object for integrated
functionality similar to GNU autoconf.
See the section "Configure Contexts,"
.B scons
does not maintain an explicit cache of the tested values,
but uses its normal dependency tracking to keep the checked values
-up to date.
+up to date. However, users may override this behaviour with the
+.B --config
+command line option.
+
The following methods can be used to perform checks:
.TP
-.RI Configure( env ", [" custom_tests ", " conf_dir ", " log_file ])
+.RI Configure( env ", [" custom_tests ", " conf_dir ", " log_file ", " config_h ])
.TP
-.RI env.Configure([ custom_tests ", " conf_dir ", " log_file ])
+.RI env.Configure([ custom_tests ", " conf_dir ", " log_file ", " config_h ])
This creates a configure context, which can be used to perform checks.
.I env
specifies the environment for building the tests.
.B BuildDir
method,
you may want to specify a subdirectory under your build directory.
+.I config_h
+specifies a C header file where the results of tests
+will be written, e.g. #define HAVE_STDIO_H, #define HAVE_LIBM, etc.
+The default is to not write a
+.B config.h
+file.
+You can specify the same
+.B config.h
+file in multiple calls to Configure,
+in which case
+.B scons
+will concatenate all results in the specified file.
+Note that SCons
+uses its normal dependency checking
+to decide if it's necessary to rebuild
+the specified
+.I config_h
+file.
+This means that the file is not necessarily re-built each
+time scons is run,
+but is only rebuilt if its contents will have changed
+and some target that depends on the
+.I config_h
+file is being built.
.EE
A created
so these can be set individually, instead of being hard-wired
relative to $QTDIR.
+ - The %TEMP% and %TMP% external environment variables are now propagated
+ automatically to the command execution environment on Windows systems.
+
+ - A new --config= command-line option allows explicit control of
+ of when the Configure() tests are run: --config=force forces all
+ checks to be run, --config=cache uses all previously cached values,
+ --config=auto (the default) runs tests only when dependency analysis
+ determines it's necessary.
+
+ - The Configure() subsystem can now write a config.h file with values
+ like HAVE_STDIO_H, HAVE_LIBM, etc.
+
+ - The Configure() subsystem now executes its checks silently when the
+ -Q option is specified.
+
+ - The Configure() subsystem now reports if a test result is being
+ taken from cache, and prints the standard output and error output
+ of tests even when cached.
+
+ - Configure() test results are now reported as "yes" or "no" instead of
+ "ok" or "failed."
+
+ - Fixed traceback printing when calling the env.Configure() method
+ instead of the Configure() global function.
+
+ - The Configure() subsystem now caches build failures in a .sconsign
+ file in the subdirectory, not a .cache file. This may cause
+ tests to be re-executed the first time after you install 0.97.
+
+ - Additional significant internal cleanups in the Configure() subsystem
+ and its tests.
+
RELEASE 0.96.1 - XXX
- The deprecated "validater" keyword to the Options.Add() method
has been removed.
+ - The %TEMP% and %TMP% external environment variables are now
+ propagated automatically to the command execution environment on
+ Windows systems.
+
+ - The Configure() subsystem now reports tests results as "yes" and
+ "no" instead of "ok" and "failed." This might interfere with any
+ scripts that automatically parse the Configure() output from SCons.
+
+ - The Configure() subsystem now stores its cached results in a
+ different file. This may cause configuration tests to be re-run
+ the first time after you install 0.97.
+
Please note the following important changes since release 0.95:
- All Builder calls (both built-in like Program(), Library(),
# The file must not exist or be empty when starting.
# Empty or None to skip this (some tests will not work!).
#
+# context.config_h (may be missing). If present, must be a string, which
+# will be filled with the contents of a config_h file.
+#
# context.vardict Dictionary holding variables used for the tests and
# stores results from the tests, used for the build
# commands.
# be a number and "SYSTEMNAME" a string.
#
+import re
import string
from types import IntType
+#
+# PUBLIC VARIABLES
+#
+
+LogInputFiles = 1 # Set that to log the input files in case of a failed test
+LogErrorMessages = 1 # Set that to log Conftest-generated error messages
+
#
# PUBLIC FUNCTIONS
#
if not text:
text = """
- int main() {
- return 0;
- }\n\n"""
+int main() {
+ return 0;
+}
+"""
context.Display("Checking if building a %s file works... " % lang)
ret = context.BuildProg(text, suffix)
includetext = ''
if not header:
header = """
- #ifdef __cplusplus
- extern "C"
- #endif
- char %s();""" % function_name
+#ifdef __cplusplus
+extern "C"
+#endif
+char %s();""" % function_name
lang, suffix, msg = _lang2suffix(language)
if msg:
return msg
text = """
- %(include)s
- #include <assert.h>
- %(hdr)s
-
- int main() {
- #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
- fail fail fail
- #else
- %(name)s();
- #endif
-
- return 0;
- }\n\n""" % { 'name': function_name,
- 'include': includetext,
- 'hdr': header }
+%(include)s
+#include <assert.h>
+%(hdr)s
+
+int main() {
+#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
+ fail fail fail
+#else
+ %(name)s();
+#endif
+
+ return 0;
+}
+""" % { 'name': function_name,
+ 'include': includetext,
+ 'hdr': header }
context.Display("Checking for %s function %s()... " % (lang, function_name))
ret = context.BuildProg(text, suffix)
# - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
# - Using the previous two together works reliably.
text = """
- %(include)s
- %(header)s
-
- int main() {
- if ((%(name)s *) 0)
- return 0;
- if (sizeof (%(name)s))
- return 0;
- }\n\n""" % { 'include': includetext,
- 'header': header,
- 'name': type_name }
+%(include)s
+%(header)s
+
+int main() {
+ if ((%(name)s *) 0)
+ return 0;
+ if (sizeof (%(name)s))
+ return 0;
+}
+""" % { 'include': includetext,
+ 'header': header,
+ 'name': type_name }
context.Display("Checking for %s type %s... " % (lang, type_name))
ret = context.BuildProg(text, suffix)
header = ""
text = """
- %s
- %s """ % (includetext, header)
+%s
+%s""" % (includetext, header)
# Add a function declaration if needed.
if func_name and func_name != "main" and not header:
text = text + """
- #ifdef __cplusplus
- extern "C"
- #endif
- char %s();""" % func_name
+#ifdef __cplusplus
+extern "C"
+#endif
+char %s();
+""" % func_name
# The actual test code.
if not call:
call = "%s();" % func_name
text = text + """
- int
- main() {
- %s
- return 0;
- }
- \n\n""" % call
+int
+main() {
+ %s
+return 0;
+}
+""" % call
i = string.find(call, "\n")
if i > 0:
if oldLIBS != -1 and (ret or not autoadd):
context.SetLIBS(oldLIBS)
- if ret == "":
+ if not ret:
return ret
return ret
def _Have(context, key, have):
"""
Store result of a test in context.havedict and context.headerfilename.
- "key" is a "HAVE_abc" name. It is turned into all CAPITALS and ":./" are
- replaced by an underscore.
+ "key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-
+ alphanumerics are replaced by an underscore.
The value of "have" can be:
1 - Feature is defined, add "#define key".
0 - Feature is not defined, add "/* #undef key */".
when desired and escape special characters!
"""
key_up = string.upper(key)
- key_up = string.replace(key_up, ':', '_')
- key_up = string.replace(key_up, '.', '_')
- key_up = string.replace(key_up, '/', '_')
- key_up = string.replace(key_up, ' ', '_')
+ key_up = re.sub('[^A-Z0-9_]', '_', key_up)
context.havedict[key_up] = have
+ if have == 1:
+ line = "#define %s\n" % key_up
+ elif have == 0:
+ line = "/* #undef %s */\n" % key_up
+ elif type(have) == IntType:
+ line = "#define %s %d\n" % (key_up, have)
+ else:
+ line = "#define %s %s\n" % (key_up,
+ re.sub('[^A-Za-z0-9_]', '_', str(have)))
+
if context.headerfilename:
f = open(context.headerfilename, "a")
- if have == 1:
- f.write("#define %s\n" % key_up)
- elif have == 0:
- f.write("/* #undef %s */\n" % key_up)
- elif type(have) == IntType:
- f.write("#define %s %d\n" % (key_up, have))
- else:
- f.write("#define %s %s\n" % (key_up, str(have)))
+ f.write(line)
f.close()
+ elif hasattr(context,'config_h'):
+ context.config_h = context.config_h + line
def _LogFailed(context, text, msg):
Write to the log about a failed program.
Add line numbers, so that error messages can be understood.
"""
- context.Log("Failed program was:\n")
- lines = string.split(text, '\n')
- if len(lines) and lines[-1] == '':
- lines = lines[:-1] # remove trailing empty line
- n = 1
- for line in lines:
- context.Log("%d: %s\n" % (n, line))
- n = n + 1
- context.Log("Error message: %s\n" % msg)
+ if LogInputFiles:
+ context.Log("Failed program was:\n")
+ lines = string.split(text, '\n')
+ if len(lines) and lines[-1] == '':
+ lines = lines[:-1] # remove trailing empty line
+ n = 1
+ for line in lines:
+ context.Log("%d: %s\n" % (n, line))
+ n = n + 1
+ if LogErrorMessages:
+ context.Log("Error message: %s\n" % msg)
def _lang2suffix(lang):
if args:
nargs = nargs + self.subst_list(args)[0]
nkw = self.subst_kw(kw)
+ nkw['called_from_env_method'] = 1
try:
nkw['custom_tests'] = self.subst_kw(nkw['custom_tests'])
except KeyError:
self.status = status
apply(Exception.__init__, (self,) + args)
-class ConfigureDryRunError(UserError):
- """Raised when a file needs to be updated during a Configure process,
- but the user requested a dry-run"""
- def __init__(self,file):
- UserError.__init__(self,"Cannot update configure test (%s) within a dry-run." % str(file))
except SCons.Errors.ExplicitExit, e:
assert e.node == "node"
- def test_ConfigureDryRunError(self):
- """Test the ConfigureDryRunError."""
- try:
- raise SCons.Errors.ConfigureDryRunError, "FileName"
- except SCons.Errors.UserError, e:
- assert e.args == ("Cannot update configure test (FileName) within a dry-run.",)
-
-
if __name__ == "__main__":
suite = unittest.makeSuite(ErrorsTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
# default. We're doing this for SYSTEMROOT, though, because it's
# needed for anything that uses sockets, and seldom changes. Weigh
# the impact carefully before adding other variables to this list.
- import_env = [ 'SYSTEMROOT' ]
+ import_env = [ 'SYSTEMROOT', 'TEMP', 'TMP' ]
for var in import_env:
v = os.environ.get(var)
if v:
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import cPickle
import os
+import re
import string
+import StringIO
import sys
import traceback
import types
import SCons.Warnings
import SCons.Conftest
-# First i thought of using a different filesystem as the default_fs,
-# but it showed up that there are too many side effects in doing that.
-SConfFS=SCons.Node.FS.default_fs
+# Turn off the Conftest error logging
+SCons.Conftest.LogInputFiles = 0
+SCons.Conftest.LogErrorMessages = 0
# to be set, if we are in dry-run mode
dryrun = 0
-_ac_build_counter = 0
-_ac_config_counter = 0
-_activeSConfObjects = {}
+AUTO=0 # use SCons dependency scanning for up-to-date checks
+FORCE=1 # force all tests to be rebuilt
+CACHE=2 # force all tests to be taken from cache (raise an error, if necessary)
+cache_mode = AUTO
+
+def SetCacheMode(mode):
+ """Set the Configure cache mode. mode must be one of "auto", "force",
+ or "cache"."""
+ global cache_mode
+ if mode == "auto":
+ cache_mode = AUTO
+ elif mode == "force":
+ cache_mode = FORCE
+ elif mode == "cache":
+ cache_mode = CACHE
+ else:
+ raise ValueError, "SCons.SConf.SetCacheMode: Unknown mode " + mode
+
+progress_display = SCons.Util.display # will be overwritten by SCons.Script
+def SetProgressDisplay(display):
+ """Set the progress display to use (called from SCons.Script)"""
+ global progress_display
+ progress_display = display
+
+SConfFS=SCons.Node.FS.default_fs
+_ac_build_counter = 0 # incremented, whenever TryBuild is called
+_ac_config_logs = {} # all config.log files created in this build
+_ac_config_hs = {} # all config.h files created in this build
+sconf_global = None # current sconf object
+
+def _createConfigH(target, source, env):
+ t = open(str(target[0]), "w")
+ defname = re.sub('[^A-Za-z0-9_]', '_', string.upper(str(target[0])))
+ t.write("""#ifndef %(DEFNAME)s_SEEN
+#define %(DEFNAME)s_SEEN
+
+""" % {'DEFNAME' : defname})
+ t.write(source[0].get_contents())
+ t.write("""
+#endif /* %(DEFNAME)s_SEEN */
+""" % {'DEFNAME' : defname})
+ t.close()
+
+def _stringConfigH(target, source, env):
+ return "scons: Configure: creating " + str(target[0])
+
+def CreateConfigHBuilder(env):
+ """Called just before the building targets phase begins."""
+ if len(_ac_config_hs) == 0:
+ return
+ action = SCons.Action.Action(_createConfigH,
+ _stringConfigH)
+ sconfigHBld = SCons.Builder.Builder(action=action)
+ env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
+ for k in _ac_config_hs.keys():
+ env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
+
class SConfWarning(SCons.Warnings.Warning):
pass
-SCons.Warnings.enableWarningClass( SConfWarning )
+SCons.Warnings.enableWarningClass(SConfWarning)
+
+# some error definitions
+class SConfError(SCons.Errors.UserError):
+ def __init__(self,msg):
+ SCons.Errors.UserError.__init__(self,msg)
+
+class ConfigureDryRunError(SConfError):
+ """Raised when a file or directory needs to be updated during a Configure
+ process, but the user requested a dry-run"""
+ def __init__(self,target):
+ if not isinstance(target, SCons.Node.FS.File):
+ msg = 'Cannot create configure directory "%s" within a dry-run.' % str(target)
+ else:
+ msg = 'Cannot update configure test "%s" within a dry-run.' % str(target)
+ SConfError.__init__(self,msg)
-# action to create the source
+class ConfigureCacheError(SConfError):
+ """Raised when a use explicitely requested the cache feature, but the test
+ is run the first time."""
+ def __init__(self,target):
+ SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
+
+# define actions for building text files
def _createSource( target, source, env ):
fd = open(str(target[0]), "w")
- fd.write(env['SCONF_TEXT'])
+ fd.write(source[0].get_contents())
fd.close()
-
def _stringSource( target, source, env ):
import string
- return (str(target[0]) + ' <- \n |' +
- string.replace( env['SCONF_TEXT'], "\n", "\n |" ) )
+ return (str(target[0]) + ' <-\n |' +
+ string.replace( source[0].get_contents(),
+ '\n', "\n |" ) )
+# python 2.2 introduces types.BooleanType
BooleanTypes = [types.IntType]
if hasattr(types, 'BooleanType'): BooleanTypes.append(types.BooleanType)
+class SConfBuildInfo(SCons.Node.FS.BuildInfo):
+ """
+ Special build info for targets of configure tests. Additional members
+ are result (did the builder succeed last time?) and string, which
+ contains messages of the original build phase.
+ """
+ result = None # -> 0/None -> no error, != 0 error
+ string = None # the stdout / stderr output when building the target
+
+ def __init__(self, result, string, sig):
+ self.result = result
+ self.string = string
+ self.bsig = sig
+
+
+class Streamer:
+ """
+ 'Sniffer' for a file-like writable object. Similar to the unix tool tee.
+ """
+ def __init__(self, orig):
+ self.orig = orig
+ self.s = StringIO.StringIO()
+
+ def write(self, str):
+ if self.orig:
+ self.orig.write(str)
+ self.s.write(str)
+
+ def writelines(self, lines):
+ for l in lines:
+ self.write(l + '\n')
+
+ def getvalue(self):
+ """
+ Return everything written to orig since the Streamer was created.
+ """
+ return self.s.getvalue()
+
+
+class SConfBuildTask(SCons.Taskmaster.Task):
+ """
+ This is almost the same as SCons.Script.BuildTask. Handles SConfErrors
+ correctly and knows about the current cache_mode.
+ """
+ def display(self, message):
+ if sconf_global.logstream:
+ sconf_global.logstream.write("scons: Configure: " + message + "\n")
+
+ def display_cached_string(self, bi):
+ """
+ Logs the original builder messages, given the SConfBuildInfo instance
+ bi.
+ """
+ if not isinstance(bi, SConfBuildInfo):
+ SCons.Warnings.warn(SConfWarning,
+ "The stored build information has an unexpected class.")
+ else:
+ self.display("The original builder output was:\n" +
+ string.replace(" |" + str(bi.string),
+ "\n", "\n |"))
+
+ def failed(self):
+ # check, if the reason was a ConfigureDryRunError or a
+ # ConfigureCacheError and if yes, reraise the exception
+ exc_type = self.exc_info()[0]
+ if issubclass(exc_type, SConfError):
+ raise
+ elif issubclass(exc_type, SCons.Errors.BuildError):
+ # we ignore Build Errors (occurs, when a test doesn't pass)
+ pass
+ else:
+ self.display('Caught exception while building "%s":\n' %
+ self.targets[0])
+ try:
+ excepthook = sys.excepthook
+ except AttributeError:
+ # Earlier versions of Python don't have sys.excepthook...
+ def excepthook(type, value, tb):
+ import traceback
+ traceback.print_tb(tb)
+ print type, value
+ apply(excepthook, self.exc_info())
+ return SCons.Taskmaster.Task.failed(self)
+
+ def collect_node_states(self):
+ # returns (is_up_to_date, cached_error, cachable)
+ # where is_up_to_date is 1, if the node(s) are up_to_date
+ # cached_error is 1, if the node(s) are up_to_date, but the
+ # build will fail
+ # cachable is 0, if some nodes are not in our cache
+ is_up_to_date = 1
+ cached_error = 0
+ cachable = 1
+ for t in self.targets:
+ bi = t.get_stored_info()
+ c_bi = isinstance(bi, SConfBuildInfo)
+ if c_bi:
+ if cache_mode == CACHE:
+ t.state = SCons.Node.up_to_date
+ else:
+ bsig = t.calc_signature(sconf_global.calc)
+ is_up_to_date = (is_up_to_date and
+ bsig == bi.bsig)
+ cached_error = cached_error or bi.result
+ else:
+ # the node hasn't been built in a SConf context or doesn't
+ # exist
+ cachable = 0
+ is_up_to_date = 0
+ return (is_up_to_date, cached_error, cachable)
+
+ def execute(self):
+ sconf = sconf_global
+
+ is_up_to_date, cached_error, cachable = self.collect_node_states()
+
+ if cache_mode == CACHE and not cachable:
+ raise ConfigureCacheError(self.targets[0])
+ elif cache_mode == FORCE:
+ is_up_to_date = 0
+
+ if cached_error and is_up_to_date:
+ self.display("Building \"%s\" failed in a previous run and all "
+ "its sources are up to date." % str(self.targets[0]))
+ self.display_cached_string(self.targets[0].get_stored_info())
+ raise SCons.Errors.BuildError # will be 'caught' in self.failed
+ elif is_up_to_date:
+ self.display("\"%s\" is up to date." % str(self.targets[0]))
+ self.display_cached_string(self.targets[0].get_stored_info())
+ elif dryrun:
+ raise ConfigureDryRunError(self.targets[0])
+ else:
+ # note stdout and stderr are the same here
+ s = sys.stdout = sys.stderr = Streamer(sys.stdout)
+ try:
+ env = self.targets[0].get_build_env()
+ env['PSTDOUT'] = env['PSTDERR'] = s
+ try:
+ sconf.cached = 0
+ self.targets[0].build()
+ finally:
+ sys.stdout = sys.stderr = env['PSTDOUT'] = \
+ env['PSTDERR'] = sconf.logstream
+ except KeyboardInterrupt:
+ raise
+ except SystemExit:
+ exc_value = sys.exc_info()[1]
+ raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code)
+ except:
+ for t in self.targets:
+ sig = t.calc_signature(sconf.calc)
+ string = s.getvalue()
+ t.dir.sconsign().set_entry(t.name,
+ SConfBuildInfo(1,string,sig))
+ raise
+ else:
+ for t in self.targets:
+ sig = t.calc_signature(sconf.calc)
+ string = s.getvalue()
+ t.dir.sconsign().set_entry(t.name,
+ SConfBuildInfo(0,string,sig))
+
class SConf:
"""This is simply a class to represent a configure context. After
creating a SConf object, you can call any tests. After finished with your
"""
def __init__(self, env, custom_tests = {}, conf_dir='#/.sconf_temp',
- log_file='#/config.log'):
+ log_file='#/config.log', config_h = None,
+ called_from_env_method = 0):
"""Constructor. Pass additional tests in the custom_tests-dictinary,
e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
defines a custom test.
global SConfFS
if not SConfFS:
SConfFS = SCons.Node.FS.FS(SCons.Node.FS.default_fs.pathTop)
- if len(_activeSConfObjects.keys()) > 0:
+ if not sconf_global is None:
raise (SCons.Errors.UserError,
"Only one SConf object may be active at one time")
self.env = env
self.logfile = None
self.logstream = None
self.lastTarget = None
+ self.called_from_env_method = called_from_env_method
+ self.cached = 0 # will be set, if all test results are cached
# add default tests
default_tests = {
self.AddTests(custom_tests)
self.confdir = SConfFS.Dir(conf_dir)
self.calc = None
- self.cache = {}
+ if not config_h is None:
+ config_h = SConfFS.File(config_h)
+ self.config_h = config_h
self._startup()
def Finish(self):
"""Call this method after finished with your tests:
env = sconf.Finish()"""
- global _lastSConfObj
- _lastSConfObj = None
self._shutdown()
return self.env
- def _setCache(self, nodes, already_done = []):
- # Set up actions used for caching errors
- # Caching positive tests should not be necessary, cause
- # the build system knows, if test objects/programs/outputs
- # are up to date.
- for n in nodes:
- # The 'n in already_done' expression is not really efficient.
- # We may do something more sophisticated in the future :-),
- # but there should not be that many dependencies in configure
- # tests
- if (n.has_builder() and
- not n in already_done):
- n.add_pre_action(SCons.Action.Action(self._preCache,
- self._stringCache))
- n.add_post_action(SCons.Action.Action(self._postCache,
- self._stringCache))
- already_done.append( n )
- self._setCache(n.children())
-
- # Calling children() has set up the implicit cache (and
- # other state), but we're not really building things yet,
- # so generated files won't have been generated. Clear the
- # state so we will, in fact, build everything that's necessary
- # when we do the build.
- #
- # XXX - it would be good to find a better way to do this,
- # maybe by doing something with the actions in the actual
- # Taskmaster...?
- n.clear()
-
def BuildNodes(self, nodes):
"""
Tries to build the given nodes immediately. Returns 1 on success,
0 on error.
"""
-
- global SCons
- import SCons.Script # really ugly, but we need BuildTask :-(
- # Is it better to provide a seperate Task for SConf builds ?
- class SConfBuildTask(SCons.Script.BuildTask):
- """Errors in SConf builds are not fatal, so we override
- the do_failed method"""
- def do_failed(self, status=2):
- pass
-
- class SConfDryRunTask(SConfBuildTask):
- """Raise ConfiugreDryRunErrors whenever a target is to
- be built. Pass these Errors to the main script."""
- def execute(self):
- target = self.targets[0]
- if (target.get_state() != SCons.Node.up_to_date and
- target.has_builder() and
- not hasattr(target.builder, 'status')):
-
- raise SCons.Errors.ConfigureDryRunError(target)
-
- def failed(self):
- exc_type, exc_value = self.exc_info()[:2]
- if exc_type == SCons.Errors.ConfigureDryRunError:
- raise exc_type, exc_value
- # Should be SConfBuildTask.failed(), really,
- # but that causes name errors in Python 1.5.2.
- SCons.Script.BuildTask.failed(self)
-
if self.logstream != None:
# override stdout / stderr to write in log file
oldStdout = sys.stdout
old_os_dir = os.getcwd()
SConfFS.chdir(SConfFS.Top, change_os_dir=1)
- self._setCache( nodes )
ret = 1
try:
# ToDo: use user options for calc
self.calc = SCons.Sig.Calculator(max_drift=0)
- if dryrun:
- buildTask = SConfDryRunTask
- else:
- buildTask = SConfBuildTask
- tm = SCons.Taskmaster.Taskmaster( nodes, buildTask )
+ tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask)
# we don't want to build tests in parallel
jobs = SCons.Job.Jobs(1, tm )
- try:
- jobs.run()
- except SCons.Errors.BuildError, e:
- sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
- if e.errstr == 'Exception':
- traceback.print_exception(e.args[0], e.args[1], e.args[2])
-
+ jobs.run()
for n in nodes:
state = n.get_state()
if (state != SCons.Node.executed and
# Slide our wrapper into the construction environment as
# the SPAWN function.
self.env['SPAWN'] = self.pspawn_wrapper
- self.env['SCONF_TEXT'] = text
+ sourcetext = self.env.Value(text)
if text != None:
- source = self.confdir.File(f + extension)
- sourceNode = self.env.SConfSourceBuilder(target=source,
- source=None)
- nodesToBeBuilt.extend(sourceNode)
+ textFile = self.confdir.File(f + extension)
+ textFileNode = self.env.SConfSourceBuilder(target=textFile,
+ source=sourcetext)
+ nodesToBeBuilt.extend(textFileNode)
+ source = textFileNode
else:
source = None
result = self.BuildNodes(nodesToBeBuilt)
finally:
- # Clean up the environment, restoring the SPAWN value.
+ # Restor the SPAWN value to the environment.
self.env['SPAWN'] = save_spawn
- del self.env['SCONF_TEXT']
_ac_build_counter = _ac_build_counter + 1
if result:
"Test called after sconf.Finish()")
context = CheckContext(self.sconf)
ret = apply(self.test, (context,) + args, kw)
+ if not self.sconf.config_h is None:
+ self.sconf.config_h_text = self.sconf.config_h_text + context.config_h
context.Result("error: no result")
return ret
for name in tests.keys():
self.AddTest(name, tests[name])
- def _preCache(self, target, source, env):
- # Action before target is actually built
- #
- # We record errors in the cache. Only non-exisiting targets may
- # have recorded errors
- needs_rebuild = target[0].exists()
- buildSig = target[0].calc_signature(self.calc)
- for node in source:
- if node.get_state() != SCons.Node.up_to_date:
- # if any of the sources has changed, we cannot use our cache
- needs_rebuild = 1
- tname = str(target[0])
- if not self.cache.has_key( tname ):
- # We have no recorded error, so we try to build the target
- needs_rebuild = 1
- else:
- lastBuildSig = self.cache[tname]['builder']
- if lastBuildSig != buildSig:
- needs_rebuild = 1
- if not needs_rebuild:
- # When we are here, we can savely pass the recorded error
- print ('(cached): Building "%s" failed in a previous run.' %
- target[0])
- return 1
- else:
- # Otherwise, we try to record an error
- self.cache[tname] = {
- 'builder' : buildSig
- }
-
- def _postCache(self, target, source, env):
- # Action after target is successfully built
- #
- # No error during build -> remove the recorded error
- del self.cache[str(target[0])]
-
- def _stringCache(self, target, source, env):
- return None
-
- def _loadCache(self):
- # try to load build-error cache
- try:
- cacheDesc = cPickle.load(open(str(self.confdir.File(".cache"))))
- if cacheDesc['scons_version'] != SCons.__version__:
- raise Exception, "version mismatch"
- self.cache = cacheDesc['data']
- except KeyboardInterrupt:
- raise
- except:
- self.cache = {}
-
- def _dumpCache(self):
- if dryrun:
- return
- # try to dump build-error cache
- try:
- cacheDesc = {'scons_version' : SCons.__version__,
- 'data' : self.cache }
- cPickle.dump(cacheDesc, open(str(self.confdir.File(".cache")),"w"))
- except Exception, e:
- # this is most likely not only an IO error, but an error
- # inside SConf ...
- SCons.Warnings.warn( SConfWarning, "Couldn't dump SConf cache" )
-
def _createDir( self, node ):
dirName = str(node)
if dryrun:
if not os.path.isdir( dirName ):
- raise SCons.Errors.ConfigureDryRunError(dirName)
+ raise ConfigureDryRunError(dirName)
else:
if not os.path.isdir( dirName ):
os.makedirs( dirName )
"""Private method. Set up logstream, and set the environment
variables necessary for a piped build
"""
- global _ac_config_counter
- global _activeSConfObjects
+ global _ac_config_logs
+ global sconf_global
global SConfFS
self.lastEnvFs = self.env.fs
if self.logfile != None and not dryrun:
# truncate logfile, if SConf.Configure is called for the first time
# in a build
- if _ac_config_counter == 0:
- log_mode = "w"
- else:
+ if _ac_config_logs.has_key(self.logfile):
log_mode = "a"
+ else:
+ _ac_config_logs[self.logfile] = None
+ log_mode = "w"
self.logstream = open(str(self.logfile), log_mode)
# logfile may stay in a build directory, so we tell
# the build system not to override it with a eventually
# existing file with the same name in the source directory
self.logfile.dir.add_ignore( [self.logfile] )
- tb = traceback.extract_stack()[-3]
-
- self.logstream.write( '\nfile %s,line %d:\n\tConfigure( confdir = %s )\n\n' %
- (tb[0], tb[1], str(self.confdir)) )
+ tb = traceback.extract_stack()[-3-self.called_from_env_method]
+ old_fs_dir = SConfFS.getcwd()
+ SConfFS.chdir(SConfFS.Top, change_os_dir=0)
+ self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' %
+ (tb[0], tb[1], str(self.confdir)) )
+ SConfFS.chdir(old_fs_dir)
else:
self.logstream = None
# we use a special builder to create source files from TEXT
action = SCons.Action.Action(_createSource,
- _stringSource,
- varlist=['SCONF_TEXT'])
+ _stringSource)
sconfSrcBld = SCons.Builder.Builder(action=action)
self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} )
+ self.config_h_text = _ac_config_hs.get(self.config_h, "")
self.active = 1
# only one SConf instance should be active at a time ...
- _activeSConfObjects[self] = None
- _ac_config_counter = _ac_config_counter + 1
- self._loadCache()
+ sconf_global = self
def _shutdown(self):
"""Private method. Reset to non-piped spawn"""
- global _activeSConfObjets
+ global sconf_global, _ac_config_hs
if not self.active:
raise SCons.Errors.UserError, "Finish may be called only once!"
- if self.logstream != None:
+ if self.logstream != None and not dryrun:
+ self.logstream.write("\n")
self.logstream.close()
self.logstream = None
# remove the SConfSourceBuilder from the environment
del blds['SConfSourceBuilder']
self.env.Replace( BUILDERS=blds )
self.active = 0
- del _activeSConfObjects[self]
- self._dumpCache()
+ sconf_global = None
+ if not self.config_h is None:
+ _ac_config_hs[self.config_h] = self.config_h_text
self.env.fs = self.lastEnvFs
class CheckContext:
def __init__(self, sconf):
"""Constructor. Pass the corresponding SConf instance."""
self.sconf = sconf
- self.cached = 0
self.did_show_result = 0
# for Conftest.py:
self.vardict = {}
self.havedict = {}
- self.headerfilename = None # XXX may cause trouble!
+ self.headerfilename = None
+ self.config_h = "" # config_h text will be stored here
+ # we don't regenerate the config.h file after each test. That means,
+ # that tests won't be able to include the config.h file, and so
+ # they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major
+ # issue, though. If it turns out, that we need to include config.h
+ # in tests, we must ensure, that the dependencies are worked out
+ # correctly. Note that we can't use Conftest.py's support for config.h,
+ # cause we will need to specify a builder for the config.h file ...
def Message(self, text):
"""Inform about what we are doing right now, e.g.
'Checking for SOMETHING ... '
"""
- # write to config.log
- if self.sconf.logstream != None:
- self.sconf.logstream.write(text + '\n')
- sys.stdout.write(text)
+ self.Display(text)
+ self.sconf.cached = 1
self.did_show_result = 0
def Result(self, res):
"""
if type(res) in BooleanTypes:
if res:
- text = "ok"
+ text = "yes"
else:
- text = "failed"
+ text = "no"
elif type(res) == types.StringType:
text = res
else:
raise TypeError, "Expected string, int or bool, got " + str(type(res))
if self.did_show_result == 0:
- if self.cached:
- text = text + " (cached)"
-
# Didn't show result yet, do it now.
- if self.sconf.logstream != None:
- self.sconf.logstream.write("Result: " + text + "\n\n")
- sys.stdout.write(text + "\n")
+ self.Display(text + "\n")
self.did_show_result = 1
-
def TryBuild(self, *args, **kw):
return apply(self.sconf.TryBuild, args, kw)
#### Stuff used by Conftest.py (look there for explanations).
def BuildProg(self, text, ext):
+ self.sconf.cached = 1
# TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
- res = self.TryBuild(self.env.Program, text, ext)
- if type(res) in BooleanTypes:
- if res:
- ret = ""
- else:
- ret = "failed to build test program"
- elif type(res) == types.StringType:
- ret = res
- else:
- raise TypeError, "Expected string or int"
- return ret
+ return not self.TryBuild(self.env.Program, text, ext)
def CompileProg(self, text, ext):
+ self.sconf.cached = 1
# TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
- res = self.TryBuild(self.env.Object, text, ext)
- if type(res) in BooleanTypes:
- if res:
- ret = ""
- else:
- ret = "failed to compile test program"
- elif type(res) == types.StringType:
- ret = res
- else:
- raise TypeError, "Expected string or int"
- return ret
+ return not self.TryBuild(self.env.Object, text, ext)
def AppendLIBS(self, lib_name_list):
oldLIBS = self.env.get( 'LIBS', [] )
return oldLIBS
def Display(self, msg):
- sys.stdout.write(msg)
- self.Log(msg)
+ if self.sconf.cached:
+ # We assume that Display is called twice for each test here
+ # once for the Checking for ... message and once for the result.
+ # The self.sconf.cached flag can only be set between those calls
+ msg = "(cached) " + msg
+ self.sconf.cached = 0
+ progress_display(msg, append_newline=0)
+ self.Log("scons: Configure: " + msg + "\n")
def Log(self, msg):
if self.sconf.logstream != None:
def CheckFunc(context, function_name, language = None):
res = SCons.Conftest.CheckFunc(context, function_name, language = language)
context.did_show_result = 1
- if not res:
- return 1 # Ok
- return 0 # Failed
-
+ return not res
def CheckType(context, type_name, includes = "", language = None):
res = SCons.Conftest.CheckType(context, type_name,
header = includes, language = language)
context.did_show_result = 1
- if not res:
- return 1 # Ok
- return 0 # Failed
+ return not res
+def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'):
+ # used by CheckHeader and CheckLibWithHeader to produce C - #include
+ # statements from the specified header (list)
+ if not SCons.Util.is_List(headers):
+ headers = [headers]
+ l = []
+ if leaveLast:
+ lastHeader = headers[-1]
+ headers = headers[:-1]
+ else:
+ lastHeader = None
+ for s in headers:
+ l.append("#include %s%s%s\n"
+ % (include_quotes[0], s, include_quotes[1]))
+ return string.join(l, ''), lastHeader
def CheckHeader(context, header, include_quotes = '<>', language = None):
"""
A test for a C or C++ header file.
"""
- if not SCons.Util.is_List(header):
- header = [header]
- l = []
- for s in header[:-1]:
- l.append("#include %s%s%s\n" % (include_quotes[0], s, include_quotes[1]))
- res = SCons.Conftest.CheckHeader(context, header[-1], string.join(l, ''),
+ prog_prefix, hdr_to_check = \
+ createIncludesFromHeaders(header, 1, include_quotes)
+ res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix,
language = language,
include_quotes = include_quotes)
context.did_show_result = 1
- if not res:
- return 1 # Ok
- return 0 # Failed
-
+ return not res
# Bram: Make this function obsolete? CheckHeader() is more generic.
def CheckLib(context, library = None, symbol = "main", autoadd = 1,
- header = None, language = None):
+ header = None, language = None):
"""
A test for a library. See also CheckLibWithHeader.
Note that library may also be None to test whether the given symbol
res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
language = language, autoadd = autoadd)
context.did_show_result = 1
- if not res:
- return 1 # Ok
- return 0 # Failed
-
+ return not res
# XXX
# Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H.
def CheckLibWithHeader(context, libs, header, language,
- call = "main();", autoadd = 1):
+ call = "main();", autoadd = 1):
# ToDo: accept path for library. Support system header files.
"""
Another (more sophisticated) test for a library.
As in CheckLib, we support library=None, to test if the call compiles
without extra link flags.
"""
-
- if not SCons.Util.is_List(header):
- header = [header]
- l = []
- for s in header:
- l.append('#include "%s"\n' % (s))
-
-
+ prog_prefix, dummy = \
+ createIncludesFromHeaders(header, 0)
if libs == []:
libs = [None]
if not SCons.Util.is_List(libs):
libs = [libs]
- res = SCons.Conftest.CheckLib(context, libs, "main", string.join(l, ''),
+ res = SCons.Conftest.CheckLib(context, libs, "main", prog_prefix,
call = call, language = language, autoadd = autoadd)
context.did_show_result = 1
- if not res:
- return 1 # Ok
- return 0 # Failed
+ return not res
sconf.Finish()
# we should have exactly one one error cached
log = self.test.read( self.test.workpath('config.log') )
- expr = re.compile( ".*(\(cached\))", re.DOTALL )
+ expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
firstOcc = expr.match( log )
assert firstOcc != None
secondOcc = expr.match( log, firstOcc.end(0) )
return
def built(self):
pass
+ def get_stored_info(self):
+ pass
+ def calc_signature(self, calc):
+ pass
return [MyNode('n1'), MyNode('n2')]
try:
self.scons_env.Append(BUILDERS = {'SConfActionBuilder' : MyBuilder()})
assert not res[1][0] and res[1][1] == ""
finally:
sconf.Finish()
- # we should have exactly one one error cached
+ # we should have exactly one error cached
log = self.test.read( self.test.workpath('config.log') )
- expr = re.compile( ".*(\(cached\))", re.DOTALL )
+ expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
firstOcc = expr.match( log )
assert firstOcc != None
secondOcc = expr.match( log, firstOcc.end(0) )
assert got == expect, "before and after LIBS were not the same"
finally:
sconf.env = env
-
finally:
sconf.Finish()
try:
__builtin__.zip
except AttributeError:
- def zip(l1, l2):
+ def zip(*lists):
result = []
- for i in xrange(len(l1)):
- result.append((l1[i], l2[i]))
+ for i in xrange(len(lists[0])):
+ result.append(tuple(map(lambda l, i=i: l[i], lists)))
return result
__builtin__.zip = zip
action="store_true", dest='cache_show', default=0,
help="Print build actions for files from CacheDir.")
+ config_options = ["auto", "force" ,"cache"]
+
+ def opt_config(option, opt, value, parser, c_options=config_options):
+ if value in c_options:
+ parser.values.config = value
+ else:
+ raise OptionValueError("Warning: %s is not a valid config type" % value)
+ self.add_option('--config', action="callback", type="string",
+ callback=opt_config, nargs=1, dest="config",
+ metavar="MODE", default="auto",
+ help="Controls Configure subsystem: "
+ "%s." % string.join(config_options, ", "))
+
def opt_not_yet(option, opt, value, parser):
sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
sys.exit(0)
CleanTask.execute = CleanTask.show
if options.question:
SCons.SConf.dryrun = 1
+ SCons.SConf.SetCacheMode(options.config)
+ SCons.SConf.SetProgressDisplay(progress_display)
if options.no_progress or options.silent:
progress_display.set_mode(0)
sys.exit(exit_status)
global sconscript_time
sconscript_time = time.time() - start_time
+ SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
progress_display("scons: done reading SConscript files.")
# Tell the Node.FS subsystem that we're all done reading the
_scons_internal_error()
except SCons.Errors.UserError, e:
_scons_user_error(e)
- except SCons.Errors.ConfigureDryRunError, e:
- _scons_configure_dryrun_error(e)
except:
# An exception here is likely a builtin Python exception Python
# code in an SConscript file. Show them precisely what the
def __init__(self):
self.__call__ = self.print_it
- def print_it(self, text):
- sys.stdout.write(text + '\n')
+ def print_it(self, text, append_newline=1):
+ if append_newline: text = text + '\n'
+ sys.stdout.write(text)
- def dont_print(self, text):
+ def dont_print(self, text, append_newline=1):
pass
def set_mode(self, mode):
display("line2")
display.set_mode(1)
display("line3")
-
- assert sys.stdout.buffer == "line1\nline3\n"
+ display("line4\n", append_newline=0)
+ display.set_mode(0)
+ display("dont print1")
+ display("dont print2\n", append_newline=0)
+ display.set_mode(1)
+ assert sys.stdout.buffer == "line1\nline3\nline4\n"
sys.stdout = old_stdout
def test_fs_delete(self):
import os
import re
-import sys
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
work_dir = None
python = TestSCons.python
test = TestSCons.TestSCons()
+_obj = TestSCons._obj
+_exe = TestSCons._exe
-
-def reset(match = 1):
+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 == 0:
+ if match == RE:
test.match_func = TestCmd.match_re
- elif match == 1:
+ elif match == RE_DOTALL:
test.match_func = TestCmd.match_re_dotall
- elif match == 2:
+ elif match == EXACT:
test.match_func = TestCmd.match_exact
def checkFiles(test, files):
for f in files:
test.fail_test( not os.path.isfile( test.workpath(work_dir,f) ) )
-
-def checkLog( test, logfile, numUpToDate, numCache ):
- test.fail_test(not os.path.exists(test.workpath(work_dir, logfile)))
- log = test.read(test.workpath(work_dir, logfile))
+def checklib(lang, name, up_to_date):
+ if lang == 'C':
+ return (".c", _obj, _exe)
+ elif lang == 'C++':
+ return (".cc", _obj, _exe)
+
+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):
+ 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:
- test.fail_test( len( re.findall( "is up to date", log ) ) != numUpToDate )
- test.fail_test( len( re.findall( "\(cached\): Building \S+ failed in a previous run.", log ) ) != numCache )
- except:
- print "contents of log ", test.workpath(work_dir, logfile), "\n", log
- raise
-
-
+ #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 = re.escape("file " + sconstruct + ",line ") + r"\d+:" + 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(match=2)
+ reset(RE)
test.write([work_dir, 'SConstruct'], """
env = Environment()
Exit(1)
""" % (lib,lib))
- required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n",
- read_str=
- """Checking for main() in C library %s... yes
-Checking for main() in C library None... yes
-Checking for main() in C library %s... yes
-Checking for main() in C library None... yes
-Checking for C header file math.h... yes
-Checking for C++ header file vector... yes
-""" % (lib, lib))
-
-
- test.run(chdir=work_dir, stdout = required_stdout)
- checkLog(test,'config.log', 0, 0 )
+ test.run(chdir=work_dir)
+ checkLogAndStdout(["Checking for main() in C library %s... " % lib,
+ "Checking for main() in C library None... ",
+ "Checking for main() in C library %s... " % lib,
+ "Checking for main() in 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, stdout = required_stdout)
- checkLog(test,'config.log',12, 0 )
+ test.run(chdir=work_dir)
+ checkLogAndStdout(["Checking for main() in C library %s... " % lib,
+ "Checking for main() in C library None... ",
+ "Checking for main() in C library %s... " % lib,
+ "Checking for main() in 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(match=2) # match exactly, "()" is a regexp thing
+ reset(EXACT) # match exactly, "()" is a regexp thing
test.write([work_dir, 'SConstruct'], """
env = Environment()
Exit(1)
""")
- required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n",
- read_str=
- """Checking for C header file no_std_c_header.h... no
-Checking for main() in C library no_c_library_SAFFDG... no
-""")
-
-
- test.run(chdir=work_dir, stdout = required_stdout)
- checkLog(test, 'config.log', 0, 0 )
+ test.run(chdir=work_dir)
+ checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+ "Checking for main() in 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, stdout = required_stdout)
- checkLog(test, 'config.log', 2, 2 )
+ test.run(chdir=work_dir)
+ checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
+ "Checking for main() in 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()
+ reset(RE_DOTALL)
test.write([work_dir, 'SConstruct'], """
printf( "Hello\\n" );
}
""")
- required_stdout = test.wrap_stdout(build_str='.*',
- read_str=
- """Checking for C header file math.h... yes
-Checking for C header file no_std_c_header.h... no
-""")
- test.run(chdir=work_dir, stdout = required_stdout )
- checkLog( test, 'config.log', 0, 0 )
-
- test.run(chdir=work_dir, stdout = required_stdout )
- checkLog( test, 'config.log', 3, 1 )
+ 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()
+ reset(RE_DOTALL)
test.write([work_dir, 'SConstruct'], """
printf( "Hello\\n" );
}
""")
- required_stdout = test.wrap_stdout(build_str='.*',
- read_str=
- """Checking for C header file math.h... yes
-Checking for C header file no_std_c_header.h... no
-""")
- test.run(chdir=work_dir, stdout = required_stdout )
- checkLog( test, 'build/config.log', 0, 0 )
- test.run(chdir=work_dir, stdout = required_stdout )
- checkLog( test, 'build/config.log', 3, 1 )
+ 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()
+ reset(RE_DOTALL)
test.subdir( [work_dir, 'sub'], [work_dir, 'sub', 'local'] )
test.write([work_dir, 'SConstruct'], """
printf( "Hello\\n" );
}
""")
- required_stdout = test.wrap_stdout(build_str='.*',
- read_str=
- """Checking for C header file math.h... yes
-Checking for C header file no_std_c_header.h... no
-Executing Custom Test ... ok
-""")
- # first with SConscriptChdir(0)
- test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no')
- checkFiles( test, [".sconf_temp/.cache", "config.log"] )
- checkLog( test, 'config.log', 0, 0 )
- test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no')
- checkFiles( test, [".sconf_temp/.cache", "config.log"] )
- checkLog( test, 'config.log', 5, 1 )
+ # 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"))
# now with SConscriptChdir(1)
- test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes')
- checkFiles( test, [".sconf_temp/.cache", "config.log"] )
- checkLog( test, 'config.log', 0, 0 )
-
- test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes')
- checkFiles( test, [".sconf_temp/.cache", "config.log"] )
- checkLog( test, 'config.log', 5, 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()
+ reset(RE_DOTALL)
compileOK = '#include <stdio.h>\\nint main() {printf("Hello");return 0;}'
compileFAIL = "syntax error"
env = conf.Finish()
""" % (compileOK, compileFAIL, linkOK, linkFAIL, runOK, runFAIL,
python, python ) )
- required_stdout = test.wrap_stdout(build_str='.*',
- read_str="Executing MyTest ... ok\n")
- test.run(chdir=work_dir, stdout = required_stdout)
- checkLog( test, 'config.log', 0, 0 )
+ 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, stdout = required_stdout)
- checkLog( test, 'config.log', 12, 4 )
+ 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()
+ reset(RE_DOTALL)
test.write([work_dir, 'cmd.py'], r"""
import sys
# 4.2 test that calling Configure from a builder results in a
# readable Error
- reset(match=2)
+ reset(EXACT)
test.write([work_dir, 'SConstruct'], """
def ConfigureAction(target, source, env):
""")
test.run(chdir=work_dir)
+ # 5.1 test the ConfigureDryRunError
+
+ reset(EXACT) # exact match
+ test.write([work_dir, 'SConstruct'], """
+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", line 5, in ?
+""")
+ test.must_not_exist([work_dir, 'config.log'])
+ test.subdir([work_dir, '.sconf_temp'])
+
+ test.run(chdir=work_dir, arguments='-n', status=2, stderr="""
+scons: *** Cannot update configure test "%s" within a dry-run.
+File "SConstruct", line 6, in ?
+""" % os.path.join(".sconf_temp", "conftest_0.c"))
+
+ test.run(chdir=work_dir)
+ checkLogAndStdout( ["Checking for main() in C library %s... " % lib,
+ "Checking for main() in 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 main() in C library %s... " % lib,
+ "Checking for main() in 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
+
+ test.write([work_dir, 'SConstruct'], """
+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 */
+""")
+
+ test.run(chdir=work_dir, arguments='--config=cache', status=2, stderr="""
+scons: *** "%s" is not yet built and cache is forced.
+File "SConstruct", line 6, in ?
+""" % os.path.join(".sconf_temp", "conftest_0.c"))
+
+ 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 main() in C library %(lib)s... yes
+Checking for main() in C library %(lib)s... no
+Checking for main() in 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()
+
+
test.pass_test()
finally:
pass
#os.system( 'find . -type f -exec ls -l {} \;' )
#print "-------------config.log------------------"
- #print test.read( test.workpath('config.log' ))
+ #print test.read( test.workpath(work_dir, 'config.log'))
#print "-------------build/config.log------------"
#print test.read( test.workpath('build/config.log' ))
import os
import os.path
+import re
import string
import sys
import TestCmd
""")
# test that conf_dir isn't created and an error is raised
stderr=r"""
-scons: \*\*\* Cannot update configure test \(config\.test\) within a dry-run\.
+scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\.
File \S+, line \S+, in \S+
"""
test.run(arguments="-n",stderr=stderr,status=2,
# verify that .cache and config.log are not created.
# an error should be raised
stderr=r"""
-scons: \*\*\* Cannot update configure test \(config\.test.conftest_0\.in\) within a dry-run\.
+scons: \*\*\* Cannot update configure test "%s" within a dry-run\.
File \S+, line \S+, in \S+
-"""
+""" % re.escape(os.path.join("config.test", "conftest_0.in"))
test.subdir(['configure','config.test'])
test.run(arguments="-n",stderr=stderr,status=2,
chdir=test.workpath("configure"))
# test that no error is raised, if all targets are up-to-date. In this
# case .cache and config.log shouldn't be created
stdout=test.wrap_stdout(build_str="scons: `.' is up to date.\n",
- read_str="""\
-Executing Custom Test ... ok
+ read_str=r"""Executing Custom Test ... \(cached\) yes
""")
test.run(status=0,chdir=test.workpath("configure"))
-cache1_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
log1_mtime = os.path.getmtime(test.workpath("configure","config.log"))
test.run(stdout=stdout,arguments="-n",status=0,
chdir=test.workpath("configure"))
-cache2_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
log2_mtime = os.path.getmtime(test.workpath("configure","config.log"))
-test.fail_test( cache1_mtime != cache2_mtime )
test.fail_test( log1_mtime != log2_mtime )
test.pass_test()
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os.path
+import re
import string
import sys
""")
# test that conf_dir isn't created and an error is raised
stderr=r"""
-scons: \*\*\* Cannot update configure test \(config\.test\) within a dry-run\.
+scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\.
File \S+, line \S+, in \S+
"""
test.run(arguments="-q aaa.out",stderr=stderr,status=2,
# verify that .cache and config.log are not created.
# an error should be raised
stderr=r"""
-scons: \*\*\* Cannot update configure test \(config\.test.conftest_0\.in\) within a dry-run\.
+scons: \*\*\* Cannot update configure test "%s" within a dry-run\.
File \S+, line \S+, in \S+
-"""
+""" % re.escape(os.path.join("config.test", "conftest_0.in"))
test.subdir(['configure','config.test'])
test.run(arguments="-q aaa.out",stderr=stderr,status=2,
chdir=test.workpath("configure"))
# test that no error is raised, if all targets are up-to-date. In this
# case .cache and config.log shouldn't be created
stdout=test.wrap_stdout(build_str='cp aaa.in aaa.out\n',
- read_str="""\
-Executing Custom Test ... ok
+ read_str="""Executing Custom Test ... yes
""")
test.run(stdout=stdout,arguments="aaa.out",status=0,chdir=test.workpath("configure"))
-cache1_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
log1_mtime = os.path.getmtime(test.workpath("configure","config.log"))
test.run(arguments="-q aaa.out",status=0,
chdir=test.workpath("configure"))
-cache2_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
log2_mtime = os.path.getmtime(test.workpath("configure","config.log"))
-test.fail_test( cache1_mtime != cache2_mtime )
test.fail_test( log1_mtime != log2_mtime )
test.pass_test()