summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-04-30 15:35:30 (GMT)
committerSteven Knight <knight@baldmt.com>2003-04-30 15:35:30 (GMT)
commit212d77d88aa4374ef13f2e6bc7edf3395ac9736c (patch)
tree464ca9fd18866613629e2381dfb6b93190a5e2e6
parent7ff542f3fb5b361087ef2738a82b5d849e005d45 (diff)
downloadSCons-212d77d88aa4374ef13f2e6bc7edf3395ac9736c.zip
SCons-212d77d88aa4374ef13f2e6bc7edf3395ac9736c.tar.gz
SCons-212d77d88aa4374ef13f2e6bc7edf3395ac9736c.tar.bz2
Provide uniform access to (some) command-line options. (Anthony Roach)
-rw-r--r--doc/man/scons.185
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/RELEASE.txt6
-rw-r--r--src/engine/SCons/Script/SConscript.py29
-rw-r--r--src/engine/SCons/Script/__init__.py81
-rw-r--r--src/engine/SCons/Sig/__init__.py4
-rw-r--r--test/option--implicit-cache.py47
-rw-r--r--test/option--max-drift.py41
-rw-r--r--test/option-c.py54
-rw-r--r--test/option-j.py18
10 files changed, 296 insertions, 75 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 5c9db8c..c96c8b8 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -3136,7 +3136,7 @@ is returned.
.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
@@ -3163,14 +3163,14 @@ int main(int argc, char **argv) {
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)
@@ -3694,11 +3694,11 @@ foo = FindFile('foo', ['dir1', 'dir2'])
.\"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 )
@@ -3866,6 +3866,20 @@ 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
.B scons
@@ -3981,35 +3995,40 @@ SConscriptChdir(1)
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 )
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 04afab8..f6bdee0 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -90,6 +90,12 @@ RELEASE 0.14 - XXX
- 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
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index db275b7..e8d4b37 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -45,6 +45,12 @@ RELEASE 0.14 - XXX
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
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index e3da64f..6b28b92 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -443,17 +443,18 @@ def EnsurePythonVersion(major, minor):
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)
@@ -493,6 +494,12 @@ def Alias(name):
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
@@ -504,6 +511,7 @@ def BuildDefaultGlobals():
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
@@ -524,6 +532,7 @@ def BuildDefaultGlobals():
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
@@ -543,6 +552,7 @@ def BuildDefaultGlobals():
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
@@ -552,5 +562,4 @@ def BuildDefaultGlobals():
globals['TargetSignatures'] = TargetSignatures
globals['Tool'] = SCons.Tool.Tool
globals['WhereIs'] = SCons.Util.WhereIs
- globals['Alias'] = Alias
return globals
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index d67b949..a1a54e6 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -216,7 +216,7 @@ command_time = 0
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
@@ -225,12 +225,6 @@ class PrintHelp(Exception):
# 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):
@@ -433,7 +427,7 @@ class OptParser(OptionParser):
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",
@@ -507,7 +501,7 @@ class OptParser(OptionParser):
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")
@@ -650,6 +644,53 @@ class OptParser(OptionParser):
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 = []
@@ -666,8 +707,9 @@ def _main():
# 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):
@@ -808,6 +850,10 @@ def _main():
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)
@@ -865,7 +911,7 @@ def _main():
if options.question:
task_class = QuestionTask
try:
- if options.clean:
+ if ssoptions.get('clean'):
task_class = CleanTask
class CleanCalculator:
def bsig(self, node):
@@ -881,15 +927,8 @@ def _main():
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:
@@ -910,7 +949,7 @@ def _main():
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()
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index 196d065..cd6fe7e 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -44,6 +44,8 @@ except ImportError:
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 = []
@@ -237,7 +239,7 @@ class Calculator:
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.
diff --git a/test/option--implicit-cache.py b/test/option--implicit-cache.py
index 0e5bf24..e959856 100644
--- a/test/option--implicit-cache.py
+++ b/test/option--implicit-cache.py
@@ -327,5 +327,52 @@ assert string.find(test.stdout(), 'is up to date') != -1, test.stdout()
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()
diff --git a/test/option--max-drift.py b/test/option--max-drift.py
index 4dacb4d..3b90b68 100644
--- a/test/option--max-drift.py
+++ b/test/option--max-drift.py
@@ -88,5 +88,46 @@ test.run(arguments = '--max-drift=-1 f1.out f2.out',
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()
diff --git a/test/option-c.py b/test/option-c.py
index d545b10..482525d 100644
--- a/test/option-c.py
+++ b/test/option-c.py
@@ -193,7 +193,7 @@ Removed foo3.out
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
@@ -207,4 +207,56 @@ test.run(arguments = '-c .', stdout=expect)
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()
+
+
diff --git a/test/option-j.py b/test/option-j.py
index bf80f02..cf41930 100644
--- a/test/option-j.py
+++ b/test/option-j.py
@@ -23,8 +23,8 @@
#
"""
-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__"
@@ -134,12 +134,12 @@ def copyn(env, target, source):
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")
@@ -162,9 +162,9 @@ def copyn(env, target, source):
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().