.TP
.RI CheckContext.TryBuild( self ", " builder ", [" text ", " extension ])
Low level implementation for testing specific builds;
-the methods above are based on this metho.
+the methods above are based on this method.
Given the Builder instance
.I builder
and the optional
QApplication qapp(argc, argv);
return 0;
}
-"""
+""")
if not ret:
context.env.Replace(LIBS = lastLIBS, LIBPATH=lastLIBPATH, CPPPATH=lastCPPPATH)
context.Result( ret )
return ret
env = Environment()
-conf = Configure( env, custom_tests = 'CheckQt' : CheckQt )
+conf = Configure( env, custom_tests = { 'CheckQt' : CheckQt } )
if not conf.CheckQt('/usr/lib/qt'):
print 'We really need qt!'
Exit(1)
.\"XXX
.TP
-.RI GetJobs()
-Get the number of jobs (commands) that will be run simultaneously. See also
-.I -j
-and
-.IR SetJobs() .
+.RI GetOption( name )
+This function provides a way to query a select subset of the scons command line
+options from a SConscript file. See
+.IR SetOption ()
+for a description of the options available.
.TP
.RI Help( text )
Return(["foo", "bar"])
.EE
+.TP
+.RI SetOption( name , value )
+This function provides a way to set a select subset of the scons command
+line options from a SConscript file. The options supported are: clean which
+cooresponds to -c, --clean, and --remove; implicit_cache which corresponds
+to --implicit-cache; max_drift which corresponds to --max-drift; and
+num_jobs which corresponds to -j and --jobs. See the documentation for the
+corresponding command line object for information about each specific
+option. Example:
+
+.EE
+SetOption('max_drift', 1)
+.ES
+
.TP
.RI SConscript( script ", [" exports ", " build_dir ", " src_dir ", " duplicate ])
This tells
SConscript('bar/SConscript') # will chdir to bar
.EE
-.TP
-.RI SetBuildSignatureType( type )
-
-This function tells SCons what type of build signature to use: "build" or
-"content". "build" means to concatenate the signatures of all source files
-of a derived file to make its signature, and "content" means to use
-the derived files content signature as its signature. "build" signatures
-are usually faster to compute, but "content" signatures can prevent
-redundant rebuilds. The default is "build".
-
.TP
-.RI SetContentSignatureType( type )
+.RI TargetSignatures( type )
-This function tells SCons what type of content signature to use: "MD5" or
-"timestamp". "MD5" means to use the MD5 checksum of a files contents as
-its signature, and "timestamp" means to use a files timestamp as its
-signature. When using "timestamp" signatures, changes in the
-command line will not cause files to be rebuilt. "MD5" signatures take
-longer to compute, but "timestamp" signatures are less accurate. The
-default is "MD5".
+This function tells SCons what type of signatures to use
+for target files:
+.B "build"
+or
+.BR "content" .
+"build" means the signature of a target file
+is made by concatenating all of the
+signatures of all its source files.
+"content" means the signature of a target
+file is an MD5 checksum of its contents.
+"build" signatures are usually faster to compute,
+but "content" signatures can prevent unnecessary rebuilds
+when a target file is rebuilt to the exact same contents as last time.
+The default is "build".
.TP
-.RI SetJobs( num )
-Specifies the number of jobs (commands) to run simultaneously.
-.I -j
-overrides this function. See also
-.I -j
-and
-.IR GetJobs() .
+.RI SourceSignatures( type )
+
+This function tells SCons what type of signature to use for source files:
+.B "MD5"
+or
+.BR "timestamp" .
+"MD5" means the signature of a source file
+is the MD5 checksum of its contents.
+"timestamp" means the signature of a source file
+is its timestamp (modification time).
+When using "timestamp" signatures,
+changes in the command line will not cause files to be rebuilt.
+"MD5" signatures take longer to compute,
+but are more accurate than "timestamp" signatures.
+The default is "MD5".
.TP
.RI Split( arg )
- Fix an undefined exitvalmap on Win32 systems.
+ - Support new SetOption() and GetOption() functions for setting
+ various command-line options from with an SConscript file.
+
+ - Deprecate the old SetJobs() and GetJobs() functions in favor of
+ using the new generic {Set,Get}Option() functions.
+
From David Snopek:
- Contribute the "Autoscons" code for Autoconf-like checking for
file, you may need to modify the module to make the previously
global variables available to your Export() or SConscript() call.
+ - The SetJobs() and GetJobs() functions have been deprecated.
+ Their new equivalents are:
+
+ SetOption('num_jobs', num)
+ GetOption('num_jobs')
+
Please note the following important changes since release 0.11:
- The default behavior of SCons is now to change to the directory in
sys.exit(2)
def GetJobs():
- return SCons.Script.get_num_jobs(SCons.Script.options)
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
+ "The GetJobs() function has been deprecated;\n" +\
+ "\tuse GetOption('num_jobs') instead.")
+ return GetOption('num_jobs')
+
def SetJobs(num):
- try:
- tmp = int(num)
- if tmp < 1:
- raise ValueError
- SCons.Script.num_jobs = tmp
- except ValueError, x:
- raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(num)
-
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
+ "The SetJobs() function has been deprecated;\n" +\
+ "\tuse SetOption('num_jobs', num) instead.")
+ SetOption('num_jobs', num)
+
def Clean(target, files):
if not isinstance(target, SCons.Node.Node):
target = SCons.Node.FS.default_fs.Entry(target, create=1)
alias = SCons.Node.Alias.default_ans.Alias(name)
return alias
+def SetOption(name, value):
+ SCons.Script.ssoptions.set(name, value)
+
+def GetOption(name):
+ return SCons.Script.ssoptions.get(name)
+
def BuildDefaultGlobals():
"""
Create a dictionary containing all the default globals for
globals['Action'] = SCons.Action.Action
globals['AddPostAction'] = AddPostAction
globals['AddPreAction'] = AddPreAction
+ globals['Alias'] = Alias
globals['ARGUMENTS'] = arguments
globals['BuildDir'] = BuildDir
globals['Builder'] = SCons.Builder.Builder
globals['GetCommandHandler'] = SCons.Action.GetCommandHandler
globals['GetJobs'] = GetJobs
globals['GetLaunchDir'] = GetLaunchDir
+ globals['GetOption'] = GetOption
globals['Help'] = Help
globals['Import'] = Import
globals['Library'] = SCons.Defaults.StaticLibrary
globals['SetCommandHandler'] = SCons.Action.SetCommandHandler
globals['SetContentSignatureType'] = SetContentSignatureType
globals['SetJobs'] = SetJobs
+ globals['SetOption'] = SetOption
globals['SharedLibrary'] = SCons.Defaults.SharedLibrary
globals['SharedObject'] = SCons.Defaults.SharedObject
globals['SourceSignatures'] = SourceSignatures
globals['TargetSignatures'] = TargetSignatures
globals['Tool'] = SCons.Tool.Tool
globals['WhereIs'] = SCons.Util.WhereIs
- globals['Alias'] = Alias
return globals
exit_status = 0 # exit status, assume success by default
profiling = 0
repositories = []
-sig_module = None
+sig_module = SCons.Sig.default_module
num_jobs = 1 # this is modifed by SConscript.SetJobs()
# Exceptions for this module
# utility functions
-def get_num_jobs(options):
- if hasattr(options, 'num_jobs'):
- return options.num_jobs
- else:
- return num_jobs
-
def get_all_children(node): return node.all_children(None)
def get_derived_children(node):
help="Ignored for compatibility.")
self.add_option('-c', '--clean', '--remove', action="store_true",
- default=0, dest="clean",
+ dest="clean",
help="Remove specified targets and dependencies.")
self.add_option('-C', '--directory', type="string", action = "append",
dest='include_dir', metavar="DIRECTORY",
help="Search DIRECTORY for imported Python modules.")
- self.add_option('--implicit-cache', action="store_true", default=0,
+ self.add_option('--implicit-cache', action="store_true",
dest='implicit_cache',
help="Cache implicit dependencies")
opt.implicit_cache = 1
return opt, arglist
+class SConscriptSettableOptions:
+ """This class wraps an OptParser instance and provides
+ uniform access to options that can be either set on the command
+ line or from a SConscript file. A value specified on the command
+ line always overrides a value set in a SConscript file.
+ Not all command line options are SConscript settable, and the ones
+ that are must be explicitly added to settable dictionary and optionally
+ validated and coerced in the set() method."""
+
+ def __init__(self, options):
+ self.options = options
+
+ # 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.Sig.default_max_drift,
+ 'implicit_cache':0,
+ 'clean':0}
+
+ def get(self, name):
+ if not self.settable.has_key(name):
+ raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
+ if hasattr(self.options, name) and getattr(self.options, name) is not None:
+ return getattr(self.options, name)
+ else:
+ return self.settable[name]
+
+ def set(self, name, value):
+ if not self.settable.has_key(name):
+ raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
+
+ if name == 'num_jobs':
+ try:
+ value = int(value)
+ if value < 1:
+ raise ValueError
+ except ValueError, x:
+ raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value)
+ elif name == 'max_drift':
+ try:
+ value = int(value)
+ except ValueError, x:
+ raise SCons.Errors.UserError, "An integer is required: %s"%repr(value)
+
+ self.settable[name] = value
+
def _main():
targets = []
# it's OK if there's no SCONSFLAGS
pass
parser = OptParser()
- global options
+ global options, ssoptions
options, args = parser.parse_args(all_args)
+ ssoptions = SConscriptSettableOptions(options)
if options.help_msg:
def raisePrintHelp(text):
parser.print_help(sys.stdout)
sys.exit(0)
+ # Now that we've read the SConscripts we can set the options
+ # that are SConscript settable:
+ SCons.Node.implicit_cache = ssoptions.get('implicit_cache')
+
if target_top:
target_top = SCons.Node.FS.default_fs.Dir(target_top)
if options.question:
task_class = QuestionTask
try:
- if options.clean:
+ if ssoptions.get('clean'):
task_class = CleanTask
class CleanCalculator:
def bsig(self, node):
pass
if not calc:
- if options.max_drift is not None:
- if sig_module is not None:
- SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module,
- max_drift=options.max_drift)
- else:
- SCons.Sig.default_calc = SCons.Sig.Calculator(max_drift=options.max_drift)
- elif sig_module is not None:
- SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module)
-
+ SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module,
+ max_drift=ssoptions.get('max_drift'))
calc = SCons.Sig.default_calc
if options.random:
display("scons: Building targets ...")
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc, order)
- jobs = SCons.Job.Jobs(get_num_jobs(options), taskmaster)
+ jobs = SCons.Job.Jobs(ssoptions.get('num_jobs'), taskmaster)
try:
jobs.run()
import TimeStamp
default_module = TimeStamp
+default_max_drift = 2*24*60*60
+
#XXX Get rid of the global array so this becomes re-entrant.
sig_files = []
for the build engine.
"""
- def __init__(self, module=default_module, max_drift=2*24*60*60):
+ def __init__(self, module=default_module, max_drift=default_max_drift):
"""
Initialize the calculator.
test.run(arguments = "--implicit-deps-changed " + variant_prog)
assert string.find(test.stdout(), 'is up to date') == -1, test.stdout()
+# Test that Set/GetOption('implicit_cache') works:
+test.write('SConstruct', """
+assert not GetOption('implicit_cache')
+SetOption('implicit_cache', 1)
+assert GetOption('implicit_cache')
+""")
+
+test.run()
+
+test.write('SConstruct', """
+assert GetOption('implicit_cache')
+SetOption('implicit_cache', 0)
+assert GetOption('implicit_cache')
+""")
+
+test.run(arguments='--implicit-cache')
+
+# Test to make sure SetOption('implicit_cache', 1) actually enables implicit caching
+# by detecting the one case where implicit caching causes inaccurate builds:
+test.write('SConstruct', """
+SetOption('implicit_cache', 1)
+env=Environment(CPPPATH=['i1', 'i2'])
+env.Object('foo.c')
+""")
+
+test.subdir('i1')
+test.subdir('i2')
+
+test.write('foo.c', """
+#include <foo.h>
+
+int foo(void)
+{
+ FOO_H_DEFINED
+}
+""")
+
+test.write('i2/foo.h', """
+#define FOO_H_DEFINED int x = 1;
+""")
+
+test.run()
+
+test.write('i1/foo.h', """
+""");
+
+test.run()
test.pass_test()
scons: "f2.out" is up to date.
""" % python))
+# Test that Set/GetOption('max_drift') works:
+test.write('SConstruct', """
+assert GetOption('max_drift') == 2*24*60*60
+SetOption('max_drift', 1)
+assert GetOption('max_drift') == 1
+""")
+
+test.run()
+
+test.write('SConstruct', """
+assert GetOption('max_drift') == 1
+SetOption('max_drift', 10)
+assert GetOption('max_drift') == 1
+""")
+
+test.run(arguments='--max-drift=1')
+
+# Test that SetOption('max_drift') actually sets max_drift
+# by mucking with the file timestamps to make SCons not realize the source has changed
+test.write('SConstruct', """
+SetOption('max_drift', 0)
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo.out', source = 'foo.in')
+""" % python)
+
+test.write('foo.in', 'foo.in\n')
+
+atime = os.path.getatime(test.workpath('foo.in'))
+mtime = os.path.getmtime(test.workpath('foo.in'))
+
+test.run()
+test.fail_test(test.read('foo.out') != 'foo.in\n')
+
+test.write('foo.in', 'foo.in delta\n')
+os.utime(test.workpath('foo.in'), (atime,mtime))
+
+test.run()
+
+test.fail_test(test.read('foo.out') != 'foo.in\n')
+
test.pass_test()
Removed %s
Removed %s
Removed directory subd
-""" % (os.path.join('subd', 'SConscript'), os.path.join('subd','foon.in')))
+""" % (os.path.join('subd','SConscript'), os.path.join('subd', 'foon.in')))
test.run(arguments = '-c -n .', stdout=expect)
expect = test.wrap_stdout("""Removed foo1.out
test.fail_test(os.path.exists(test.workpath('subdir', 'foon.in')))
test.fail_test(os.path.exists(test.workpath('subdir')))
+
+# Ensure that Set/GetOption('clean') works correctly:
+test.write('SConstruct', """
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo.out', source = 'foo.in')
+
+assert not GetOption('clean')
+"""%python)
+
+test.write('foo.in', '"Foo", I say!\n')
+
+test.run(arguments='foo.out')
+test.fail_test(test.read(test.workpath('foo.out')) != '"Foo", I say!\n')
+
+test.write('SConstruct', """
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo.out', source = 'foo.in')
+
+assert GetOption('clean')
+SetOption('clean', 0)
+assert GetOption('clean')
+"""%python)
+
+test.run(arguments='-c foo.out')
+test.fail_test(os.path.exists(test.workpath('foo.out')))
+
+test.write('SConstruct', """
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo.out', source = 'foo.in')
+"""%python)
+
+test.run(arguments='foo.out')
+test.fail_test(test.read(test.workpath('foo.out')) != '"Foo", I say!\n')
+
+test.write('SConstruct', """
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo.out', source = 'foo.in')
+
+assert not GetOption('clean')
+SetOption('clean', 1)
+assert GetOption('clean')
+"""%python)
+
+test.run(arguments='foo.out')
+test.fail_test(os.path.exists(test.workpath('foo.out')))
+
test.pass_test()
+
+
#
"""
-This tests the -j command line option, and the SetJobs() and GetJobs()
-SConscript functions.
+This tests the -j command line option, and the num_jobs
+SConscript settable option.
"""
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
env.Install('out', t)
-assert GetJobs() == 1
-SetJobs(2)
-assert GetJobs() == 2
+assert GetOption('num_jobs') == 1
+SetOption('num_jobs', 2)
+assert GetOption('num_jobs') == 2
""" % python)
-# This should be a prallel build because the SConscript sets jobs to 2.
+# This should be a parallel build because the SConscript sets jobs to 2.
# fail if the second file was not started
# before the first one was finished
start2, finish1 = RunTest('f1 f2', "third")
t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
env.Install('out', t)
-assert GetJobs() == 1
-SetJobs(2)
-assert GetJobs() == 1
+assert GetOption('num_jobs') == 1
+SetOption('num_jobs', 2)
+assert GetOption('num_jobs') == 1
""" % python)
# This should be a serial build since -j 1 overrides the call to SetJobs().