+RELEASE XXX - XXX
+
+ From Greg Noel:
+
+ - Fix use of $CXXFLAGS when building C++ shared object files.
+
+ From Steven Knight:
+
+ - Fix a regression when a Builder's source_scanner doesn't select
+ a more specific scanner for the suffix of a specified source file.
+
+ - Fix the Options object backwards compatibility so people can still
+ "import SCons.Options.{Bool,Enum,List,Package,Path}Option" submodules.
+
+ - Fix searching for implicit dependencies when an Entry Node shows up
+ in the search path list.
+
+ From Stefano:
+
+ - Fix expansion of $FORTRANMODDIR in the default Fortran command line(s)
+ when it's set to something like ${TARGET.dir}.
+
+
+
RELEASE 0.98.2 - Sun, 20 Apr 2008 23:38:56 -0700
From Steven Knight:
SCons/Node/Alias.py
SCons/Node/FS.py
SCons/Node/Python.py
-SCons/Options.py
+SCons/Options/__init__.py
+SCons/Options/BoolOption.py
+SCons/Options/EnumOption.py
+SCons/Options/ListOption.py
+SCons/Options/PackageOption.py
+SCons/Options/PathOption.py
SCons/PathList.py
SCons/Platform/__init__.py
SCons/Platform/aix.py
if scanner:
for node in node_list:
node.disambiguate()
- scanner = scanner.select(node)
- if not scanner:
+ s = scanner.select(node)
+ if not s:
continue
- path = self.get_build_scanner_path(scanner)
- deps.extend(node.get_implicit_deps(env, scanner, path))
+ path = self.get_build_scanner_path(s)
+ deps.extend(node.get_implicit_deps(env, s, path))
else:
kw = self.get_kw()
for node in node_list:
interrupt_msg = 'Build interrupted.'
+
+class InterruptState:
+ def __init__(self):
+ self.interrupted = False
+
+ def set(self):
+ self.interrupted = True
+
+ def __call__(self):
+ return self.interrupted
+
+
class Jobs:
"""An instance of this class initializes N jobs, and provides
methods for starting, stopping, and waiting on all N jobs.
self.job = Serial(taskmaster)
self.num_jobs = 1
- self.job.interrupted = False
-
def run(self, postfunc=lambda: None):
"""Run the jobs.
def were_interrupted(self):
"""Returns whether the jobs were interrupted by a signal."""
- return self.job.interrupted
+ return self.job.interrupted()
def _setup_sig_handler(self):
"""Setup an interrupt handler so that SCons can shutdown cleanly in
SCons forks before executing another process. In that case, we
want the child to exit immediately.
"""
- def handler(signum, stack, parentpid=os.getpid()):
+ def handler(signum, stack, self=self, parentpid=os.getpid()):
if os.getpid() == parentpid:
self.job.taskmaster.stop()
- self.job.interrupted = True
+ self.job.interrupted.set()
else:
os._exit(2)
execute (e.g. execute() raised an exception)."""
self.taskmaster = taskmaster
+ self.interrupted = InterruptState()
def start(self):
"""Start the job. This will begin pulling tasks from the taskmaster
if task.needs_execute():
task.execute()
except:
- if self.interrupted:
+ if self.interrupted():
try:
raise SCons.Errors.BuildError(
task.targets[0], errstr=interrupt_msg)
dequeues the task, executes it, and posts a tuple including the task
and a boolean indicating whether the task executed successfully. """
- def __init__(self, requestQueue, resultsQueue):
+ def __init__(self, requestQueue, resultsQueue, interrupted):
threading.Thread.__init__(self)
self.setDaemon(1)
self.requestQueue = requestQueue
self.resultsQueue = resultsQueue
+ self.interrupted = interrupted
self.start()
def run(self):
break
try:
+ if self.interrupted():
+ raise SCons.Errors.BuildError(
+ task.targets[0], errstr=interrupt_msg)
task.execute()
except:
task.exception_set()
class ThreadPool:
"""This class is responsible for spawning and managing worker threads."""
- def __init__(self, num, stack_size):
+ def __init__(self, num, stack_size, interrupted):
"""Create the request and reply queues, and 'num' worker threads.
One must specify the stack size of the worker threads. The
# Create worker threads
self.workers = []
for _ in range(num):
- worker = Worker(self.requestQueue, self.resultsQueue)
+ worker = Worker(self.requestQueue, self.resultsQueue, interrupted)
self.workers.append(worker)
# Once we drop Python 1.5 we can change the following to:
multiple tasks simultaneously. """
self.taskmaster = taskmaster
- self.tp = ThreadPool(num, stack_size)
+ self.interrupted = InterruptState()
+ self.tp = ThreadPool(num, stack_size, self.interrupted)
self.maxjobs = num
if ok:
task.executed()
else:
- if self.interrupted:
+ if self.interrupted():
try:
raise SCons.Errors.BuildError(
task.targets[0], errstr=interrupt_msg)
node = p.entries[norm_name]
except KeyError:
return p.dir_on_disk(name)
- # Once we move to Python 2.2 we can do:
- #if isinstance(node, (Dir, Entry)):
- if isinstance(node, Dir) or isinstance(node, Entry):
+ if isinstance(node, Dir):
+ return node
+ if isinstance(node, Entry):
+ node.must_be_same(Dir)
return node
return None
# node = p.entries[norm_name]
# except KeyError:
# return p.dir_on_disk(name)
- # # Once we move to Python 2.2 we can do:
- # #if isinstance(node, (Dir, Entry)):
+ # if isinstance(node, Dir):
+ # return node
+ # if isinstance(node, Entry):
+ # node.must_be_same(Dir)
+ # return node
# if isinstance(node, Dir) or isinstance(node, Entry):
# return node
# return None
--- /dev/null
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Place-holder for the old SCons.Options module hierarchy
+
+This is for backwards compatibility. The new equivalent is the Variables/
+class hierarchy. These will have deprecation warnings added (some day),
+and will then be removed entirely (some day).
+"""
+
+import SCons.Variables
+
+BoolOption = SCons.Variables.BoolVariable
--- /dev/null
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Place-holder for the old SCons.Options module hierarchy
+
+This is for backwards compatibility. The new equivalent is the Variables/
+class hierarchy. These will have deprecation warnings added (some day),
+and will then be removed entirely (some day).
+"""
+
+import SCons.Variables
+
+EnumOption = SCons.Variables.EnumVariable
--- /dev/null
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Place-holder for the old SCons.Options module hierarchy
+
+This is for backwards compatibility. The new equivalent is the Variables/
+class hierarchy. These will have deprecation warnings added (some day),
+and will then be removed entirely (some day).
+"""
+
+import SCons.Variables
+
+ListOption = SCons.Variables.ListVariable
--- /dev/null
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Place-holder for the old SCons.Options module hierarchy
+
+This is for backwards compatibility. The new equivalent is the Variables/
+class hierarchy. These will have deprecation warnings added (some day),
+and will then be removed entirely (some day).
+"""
+
+import SCons.Variables
+
+PackageOption = SCons.Variables.PackageVariable
--- /dev/null
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Place-holder for the old SCons.Options module hierarchy
+
+This is for backwards compatibility. The new equivalent is the Variables/
+class hierarchy. These will have deprecation warnings added (some day),
+and will then be removed entirely (some day).
+"""
+
+import SCons.Variables
+
+PathOption = SCons.Variables.PathVariable
import SCons.Variables
+from BoolOption import BoolOption # okay
+from EnumOption import EnumOption # okay
+from ListOption import ListOption # naja
+from PackageOption import PackageOption # naja
+from PathOption import PathOption # okay
+
class Options(SCons.Variables.Variables):
def AddOptions(self, *args, **kw):
return apply(SCons.Variables.Variables.FormatVariableHelpText,
(self,) + args,
kw)
-
-BoolOption = SCons.Variables.BoolVariable
-EnumOption = SCons.Variables.EnumVariable
-ListOption = SCons.Variables.ListVariable
-PackageOption = SCons.Variables.PackageVariable
-PathOption = SCons.Variables.PathVariable
Explicit stop-the-build failure.
"""
- # Invoke fail_continue() to clean-up the pending children
+ # Invoke will_not_build() to clean-up the pending children
# list.
- self.fail_continue()
+ self.tm.will_not_build(self.targets)
# Tell the taskmaster to not start any new tasks
self.tm.stop()
This sets failure status on the target nodes and all of
their dependent parent nodes.
"""
+ self.tm.will_not_build(self.targets)
- pending_children = self.tm.pending_children
-
- to_visit = set()
- for t in self.targets:
- # Set failure state on all of the parents that were dependent
- # on this failed build.
- if t.state != NODE_FAILED:
- t.state = NODE_FAILED
- parents = t.waiting_parents
- to_visit = to_visit | parents
- pending_children = pending_children - parents
-
- try:
- while 1:
- try:
- node = to_visit.pop()
- except AttributeError:
- # Python 1.5.2
- if len(to_visit):
- node = to_visit[0]
- to_visit.remove(node)
- else:
- break
- if node.state != NODE_FAILED:
- node.state = NODE_FAILED
- parents = node.waiting_parents
- to_visit = to_visit | parents
- pending_children = pending_children - parents
- except KeyError:
- # The container to_visit has been emptied.
- pass
-
- # We have the stick back the pending_children list into the
- # task master because the python 1.5.2 compatibility does not
- # allow us to use in-place updates
- self.tm.pending_children = pending_children
-
def make_ready_all(self):
"""
Marks all targets in a task ready for execution.
def no_next_candidate(self):
"""
Stops Taskmaster processing by not returning a next candidate.
- """
+
+ Note that we have to clean-up the Taskmaster candidate list
+ because the cycle detection depends on the fact all nodes have
+ been processed somehow.
+ """
+ while self.candidates:
+ candidates = self.candidates
+ self.candidates = []
+ self.will_not_build(candidates)
return None
def _find_next_ready_node(self):
S.considered = S.considered + 1
else:
S = None
-
- if T: T.write('Taskmaster: Considering node <%-10s %s> and its children:\n' %
- (StateString[node.get_state()], repr(str(node))))
+
+ if T: T.write('Taskmaster: Considering node <%-10s %-3s %s> and its children:\n' %
+ (StateString[node.get_state()], node.ref_count, repr(str(node))))
if state == NODE_NO_STATE:
# Mark this node as being on the execution stack:
for child in chain(children,node.prerequisites):
childstate = child.get_state()
- if T: T.write('Taskmaster: <%-10s %s>\n' %
- (StateString[childstate], repr(str(child))))
+ if T: T.write('Taskmaster: <%-10s %-3s %s>\n' %
+ (StateString[childstate], child.ref_count, repr(str(child))))
if childstate == NODE_NO_STATE:
children_not_visited.append(child)
node.set_state(NODE_FAILED)
if S: S.child_failed = S.child_failed + 1
- if T: T.write('Taskmaster:****** <%-10s %s>\n' %
- (StateString[node.get_state()], repr(str(node))))
+ if T: T.write('Taskmaster:****** <%-10s %-3s %s>\n' %
+ (StateString[node.get_state()], node.ref_count, repr(str(node))))
continue
if children_not_ready:
# count so we can be put back on the list for
# re-evaluation when they've all finished.
node.ref_count = node.ref_count + child.add_to_waiting_parents(node)
+ if T: T.write('Taskmaster: adjusting ref count: <%-10s %-3s %s>\n' %
+ (StateString[node.get_state()], node.ref_count, repr(str(node))))
self.pending_children = self.pending_children | children_pending
# The default when we've gotten through all of the checks above:
# this node is ready to be built.
if S: S.build = S.build + 1
- if T: T.write('Taskmaster: Evaluating <%-10s %s>\n' %
- (StateString[node.get_state()], repr(str(node))))
+ if T: T.write('Taskmaster: Evaluating <%-10s %-3s %s>\n' %
+ (StateString[node.get_state()], node.ref_count, repr(str(node))))
return node
return None
return task
+ def will_not_build(self, nodes):
+ """
+ Perform clean-up about nodes that will never be built.
+ """
+
+ pending_children = self.pending_children
+
+ to_visit = set()
+ for node in nodes:
+ # Set failure state on all of the parents that were dependent
+ # on this failed build.
+ if node.state != NODE_FAILED:
+ node.state = NODE_FAILED
+ parents = node.waiting_parents
+ to_visit = to_visit | parents
+ pending_children = pending_children - parents
+
+ try:
+ while 1:
+ try:
+ node = to_visit.pop()
+ except AttributeError:
+ # Python 1.5.2
+ if len(to_visit):
+ node = to_visit[0]
+ to_visit.remove(node)
+ else:
+ break
+ if node.state != NODE_FAILED:
+ node.state = NODE_FAILED
+ parents = node.waiting_parents
+ to_visit = to_visit | parents
+ pending_children = pending_children - parents
+ except KeyError:
+ # The container to_visit has been emptied.
+ pass
+
+ # We have the stick back the pending_children list into the
+ # task master because the python 1.5.2 compatibility does not
+ # allow us to use in-place updates
+ self.pending_children = pending_children
+
def stop(self):
"""
Stops the current build completely.
if cycle:
desc = desc + " " + string.join(map(str, cycle), " -> ") + "\n"
else:
- desc = desc + " Internal Error: no cycle found for node %s (%s)\n" % \
- (node, repr(node))
+ desc = desc + \
+ " Internal Error: no cycle found for node %s (%s) in state %s\n" % \
+ (node, repr(node), StateString[node.get_state()])
+
raise SCons.Errors.UserError, desc
expect = """\
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'n1'> and its children:
-Taskmaster: Evaluating <pending 'n1'>
+Taskmaster: Considering node <no_state 0 'n1'> and its children:
+Taskmaster: Evaluating <pending 0 'n1'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <executed 'n1'> and its children:
+Taskmaster: Considering node <executed 0 'n1'> and its children:
Taskmaster: already handled (executed)
-Taskmaster: Considering node <no_state 'n3'> and its children:
-Taskmaster: <executed 'n1'>
-Taskmaster: <no_state 'n2'>
-Taskmaster: Considering node <no_state 'n2'> and its children:
-Taskmaster: Evaluating <pending 'n2'>
+Taskmaster: Considering node <no_state 0 'n3'> and its children:
+Taskmaster: <executed 0 'n1'>
+Taskmaster: <no_state 0 'n2'>
+Taskmaster: adjusting ref count: <pending 1 'n3'>
+Taskmaster: Considering node <no_state 0 'n2'> and its children:
+Taskmaster: Evaluating <pending 0 'n2'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <pending 'n3'> and its children:
-Taskmaster: <executed 'n1'>
-Taskmaster: <executed 'n2'>
-Taskmaster: Evaluating <pending 'n3'>
+Taskmaster: Considering node <pending 0 'n3'> and its children:
+Taskmaster: <executed 0 'n1'>
+Taskmaster: <executed 0 'n2'>
+Taskmaster: Evaluating <pending 0 'n3'>
Taskmaster: Looking for a node to evaluate
Taskmaster: No candidate anymore.
env['FORTRANMODDIR'] = '' # where the compiler should place .mod files
env['FORTRANMODDIRPREFIX'] = '' # some prefix to $FORTRANMODDIR - similar to $INCPREFIX
env['FORTRANMODDIRSUFFIX'] = '' # some suffix to $FORTRANMODDIR - similar to $INCSUFFIX
- env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs)} $)'
+ env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
def add_f77_to_env(env):
"""Add Builders and construction variables for f77 to an Environment."""
env['CXXFLAGS'] = SCons.Util.CLVar('')
env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['SHCXX'] = '$CXX'
- env['SHCXXFLAGS'] = SCons.Util.CLVar('')
+ env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CXX'] = env.Detect(compilers)
# platform specific settings
- if env['PLATFORM'] == 'cygwin':
- env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
- elif env['PLATFORM'] == 'aix':
- # Original line from Christian Engel added -DPIC:
- #env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -DPIC -mminimal-toc')
+ if env['PLATFORM'] == 'aix':
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
elif env['PLATFORM'] == 'hpux':
- # Original line from Christian Engel added -DPIC:
- #env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -DPIC')
env['SHOBJSUFFIX'] = '.pic.o'
elif env['PLATFORM'] == 'sunos':
- # Original line from Christian Engel added -DPIC:
- #env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -DPIC')
env['SHOBJSUFFIX'] = '.pic.o'
- else:
- # Original line from Christian Engel added -DPIC:
- #env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -DPIC')
- pass
# determine compiler version
if env['CXX']:
line = os.popen(env['CXX'] + ' --version').readline()
'packages' : ["SCons",
"SCons.compat",
"SCons.Node",
+ "SCons.Options",
"SCons.Platform",
"SCons.Scanner",
"SCons.Script",
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that $CXXFLAGS settings are used to build both static
+and shared object files.
+"""
+
+import os
+import string
+import sys
+
+import TestSCons
+
+_obj = TestSCons._obj
+
+if os.name == 'posix':
+ os.environ['LD_LIBRARY_PATH'] = '.'
+if string.find(sys.platform, 'irix') > -1:
+ os.environ['LD_LIBRARYN32_PATH'] = '.'
+
+test = TestSCons.TestSCons()
+
+e = test.Environment()
+
+test.write('SConstruct', """
+foo = Environment(WINDOWS_INSERT_DEF=1)
+foo.Append(CXXFLAGS = '-DFOO')
+bar = Environment(WINDOWS_INSERT_DEF=1)
+bar.Append(CXXFLAGS = '-DBAR')
+foo_obj = foo.SharedObject(target = 'fooshared%(_obj)s', source = 'doIt.cpp')
+bar_obj = bar.SharedObject(target = 'barshared%(_obj)s', source = 'doIt.cpp')
+foo.SharedLibrary(target = 'foo', source = foo_obj)
+bar.SharedLibrary(target = 'bar', source = bar_obj)
+
+fooMain = foo.Clone(LIBS='foo', LIBPATH='.')
+foo_obj = fooMain.Object(target='foomain', source='main.c')
+fooMain.Program(target='fooprog', source=foo_obj)
+
+barMain = bar.Clone(LIBS='bar', LIBPATH='.')
+bar_obj = barMain.Object(target='barmain', source='main.c')
+barMain.Program(target='barprog', source=bar_obj)
+
+foo_obj = foo.Object(target = 'foostatic', source = 'prog.cpp')
+bar_obj = bar.Object(target = 'barstatic', source = 'prog.cpp')
+foo.Program(target = 'foo', source = foo_obj)
+bar.Program(target = 'bar', source = bar_obj)
+""" % locals())
+
+test.write('foo.def', r"""
+LIBRARY "foo"
+DESCRIPTION "Foo Shared Library"
+
+EXPORTS
+ doIt
+""")
+
+test.write('bar.def', r"""
+LIBRARY "bar"
+DESCRIPTION "Bar Shared Library"
+
+EXPORTS
+ doIt
+""")
+
+test.write('doIt.cpp', r"""
+#include <stdio.h>
+
+extern "C" void
+doIt()
+{
+#ifdef FOO
+ printf("doIt.cpp: FOO\n");
+#endif
+#ifdef BAR
+ printf("doIt.cpp: BAR\n");
+#endif
+}
+""")
+
+test.write('main.c', r"""
+
+void doIt();
+
+int
+main(int argc, char* argv[])
+{
+ doIt();
+ return 0;
+}
+""")
+
+test.write('prog.cpp', r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+#ifdef FOO
+ printf("prog.c: FOO\n");
+#endif
+#ifdef BAR
+ printf("prog.c: BAR\n");
+#endif
+ exit (0);
+}
+""")
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('fooprog'), stdout = "doIt.cpp: FOO\n")
+test.run(program = test.workpath('barprog'), stdout = "doIt.cpp: BAR\n")
+test.run(program = test.workpath('foo'), stdout = "prog.c: FOO\n")
+test.run(program = test.workpath('bar'), stdout = "prog.c: BAR\n")
+
+
+
+test.write('SConstruct', """
+bar = Environment(WINDOWS_INSERT_DEF=1)
+bar.Append(CXXFLAGS = '-DBAR')
+foo_obj = bar.SharedObject(target = 'foo%(_obj)s', source = 'doIt.cpp')
+bar_obj = bar.SharedObject(target = 'bar%(_obj)s', source = 'doIt.cpp')
+bar.SharedLibrary(target = 'foo', source = foo_obj)
+bar.SharedLibrary(target = 'bar', source = bar_obj)
+
+barMain = bar.Clone(LIBS='bar', LIBPATH='.')
+foo_obj = barMain.Object(target='foomain', source='main.c')
+bar_obj = barMain.Object(target='barmain', source='main.c')
+barMain.Program(target='barprog', source=foo_obj)
+barMain.Program(target='fooprog', source=bar_obj)
+""" % locals())
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('fooprog'), stdout = "doIt.cpp: BAR\n")
+test.run(program = test.workpath('barprog'), stdout = "doIt.cpp: BAR\n")
+
+
+
+test.pass_test()
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import sys
-import TestSCons
+"""
+Verify that $SHCXXFLAGS settings are used to build shared object files.
+"""
+
import os
import string
+import sys
+
+import TestSCons
_obj = TestSCons._obj
test = TestSCons.TestSCons()
e = test.Environment()
-fooflags = e['SHCXXFLAGS'] + ' -DFOO'
-barflags = e['SHCXXFLAGS'] + ' -DBAR'
test.write('SConstruct', """
-foo = Environment(SHCXXFLAGS = '%s', WINDOWS_INSERT_DEF=1)
-bar = Environment(SHCXXFLAGS = '%s', WINDOWS_INSERT_DEF=1)
-foo.SharedObject(target = 'foo%s', source = 'prog.cpp')
-bar.SharedObject(target = 'bar%s', source = 'prog.cpp')
-foo.SharedLibrary(target = 'foo', source = 'foo%s')
-bar.SharedLibrary(target = 'bar', source = 'bar%s')
+foo = Environment(WINDOWS_INSERT_DEF=1)
+foo.Append(SHCXXFLAGS = '-DFOO')
+bar = Environment(WINDOWS_INSERT_DEF=1)
+bar.Append(SHCXXFLAGS = '-DBAR')
+foo_obj = foo.SharedObject(target = 'foo%(_obj)s', source = 'prog.cpp')
+bar_obj = bar.SharedObject(target = 'bar%(_obj)s', source = 'prog.cpp')
+foo.SharedLibrary(target = 'foo', source = foo_obj)
+bar.SharedLibrary(target = 'bar', source = bar_obj)
fooMain = foo.Clone(LIBS='foo', LIBPATH='.')
foo_obj = fooMain.Object(target='foomain', source='main.c')
barMain = bar.Clone(LIBS='bar', LIBPATH='.')
bar_obj = barMain.Object(target='barmain', source='main.c')
barMain.Program(target='barprog', source=bar_obj)
-""" % (fooflags, barflags, _obj, _obj, _obj, _obj))
+""" % locals())
test.write('foo.def', r"""
LIBRARY "foo"
test.run(program = test.workpath('barprog'), stdout = "prog.cpp: BAR\n")
test.write('SConstruct', """
-bar = Environment(SHCXXFLAGS = '%s', WINDOWS_INSERT_DEF=1)
-bar.SharedObject(target = 'foo%s', source = 'prog.cpp')
-bar.SharedObject(target = 'bar%s', source = 'prog.cpp')
-bar.SharedLibrary(target = 'foo', source = 'foo%s')
-bar.SharedLibrary(target = 'bar', source = 'bar%s')
+bar = Environment(WINDOWS_INSERT_DEF=1)
+bar.Append(SHCXXFLAGS = '-DBAR')
+foo_obj = bar.SharedObject(target = 'foo%(_obj)s', source = 'prog.cpp')
+bar_obj = bar.SharedObject(target = 'bar%(_obj)s', source = 'prog.cpp')
+bar.SharedLibrary(target = 'foo', source = foo_obj)
+bar.SharedLibrary(target = 'bar', source = bar_obj)
barMain = bar.Clone(LIBS='bar', LIBPATH='.')
foo_obj = barMain.Object(target='foomain', source='main.c')
bar_obj = barMain.Object(target='barmain', source='main.c')
barMain.Program(target='barprog', source=foo_obj)
barMain.Program(target='fooprog', source=bar_obj)
-""" % (barflags, _obj, _obj, _obj, _obj))
+""" % locals())
test.run(arguments = '.')
test.write(SConstruct_path, """\
+from SCons.Options.BoolOption import BoolOption
+BO = BoolOption
+
from SCons.Options import BoolOption
opts = Options(args=ARGUMENTS)
opts.AddOptions(
BoolOption('warnings', 'compilation with -Wall and similiar', 1),
- BoolOption('profile', 'create profiling informations', 0),
+ BO('profile', 'create profiling informations', 0),
)
env = Environment(options=opts)
expect_stderr = """
scons: *** Error converting option: warnings
Invalid value for boolean option: irgendwas
-""" + test.python_file_line(SConstruct_path, 9)
+""" + test.python_file_line(SConstruct_path, 12)
test.run(arguments='warnings=irgendwas', stderr = expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Options.EnumOption import EnumOption
+EO = EnumOption
+
from SCons.Options import EnumOption
list_of_libs = Split('x11 gl qt ical')
EnumOption('guilib', 'gui lib to use', 'gtk',
allowed_values=('motif', 'gtk', 'kde'),
map={}, ignorecase=1), # case insensitive
- EnumOption('some', 'some option', 'xaver',
- allowed_values=('xaver', 'eins'),
- map={}, ignorecase=2), # make lowercase
+ EO('some', 'some option', 'xaver',
+ allowed_values=('xaver', 'eins'),
+ map={}, ignorecase=2), # make lowercase
)
env = Environment(options=opts)
expect_stderr = """
scons: *** Invalid value for option debug: FULL
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='debug=FULL', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Invalid value for option guilib: irgendwas
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='guilib=IrGeNdwas', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Invalid value for option some: irgendwas
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='some=IrGeNdwas', stderr=expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Options.ListOption import ListOption
+LO = ListOption
+
from SCons.Options import ListOption
list_of_libs = Split('x11 gl qt ical')
'all',
names = list_of_libs,
map = {'GL':'gl', 'QT':'qt'}),
+ LO('listvariable', 'listvariable help', 'all', names=['l1', 'l2', 'l3'])
)
env = Environment(options=opts)
check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
"['gl ical qt x11']"])
-test.must_match(test.workpath('scons.options'), "shared = 'all'"+os.linesep)
+expect = "shared = 'all'"+os.linesep+"listvariable = 'all'"+os.linesep
+test.must_match(test.workpath('scons.options'), expect)
check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
"['gl ical qt x11']"])
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo,ical', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=ical,foo', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=ical,foo,x11', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo,bar
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo,x11,,,bar', stderr=expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Options.PackageOption import PackageOption
+PO = PackageOption
+
from SCons.Options import PackageOption
opts = Options(args=ARGUMENTS)
PackageOption('x11',
'use X11 installed here (yes = search some places',
'yes'),
+ PO('package', 'help for package', 'yes'),
)
env = Environment(options=opts)
expect_stderr = """
scons: *** Path does not exist for option x11: /non/existing/path/
-""" + test.python_file_line(SConstruct_path, 10)
+""" + test.python_file_line(SConstruct_path, 14)
test.run(arguments='x11=/non/existing/path/', stderr=expect_stderr, status=2)
libpath = os.path.join(workpath, 'lib')
test.write(SConstruct_path, """\
+from SCons.Options.PathOption import PathOption
+PO = PathOption
+
from SCons.Options import PathOption
qtdir = r'%s'
opts = Options(args=ARGUMENTS)
opts.AddOptions(
PathOption('qtdir', 'where the root of Qt is installed', qtdir),
- PathOption('qt_libraries', 'where the Qt library is installed', r'%s'),
+ PO('qt_libraries', 'where the Qt library is installed', r'%s'),
)
env = Environment(options=opts)
check([qtpath, libpath, libpath])
qtpath = os.path.join(workpath, 'non', 'existing', 'path')
-SConstruct_file_line = test.python_file_line(test.workpath('SConstruct'), 11)[:-1]
+SConstruct_file_line = test.python_file_line(test.workpath('SConstruct'), 14)[:-1]
expect_stderr = """
scons: *** Path for option qtdir does not exist: %(qtpath)s
env = Environment(FORTRANCOM = r'%(_python_)s myfortran.py $FORTRANMODDIR $SOURCE $TARGET',
FORTRANMODDIR = 'modules')
env.Object(target = 'test1.obj', source = 'test1.f')
-env.Object(target = 'sub/test2.obj', source = 'test1.f',
+env.Object(target = 'sub2/test2.obj', source = 'test1.f',
+ FORTRANMODDIR='${TARGET.dir}')
+env.Object(target = 'sub3/test3.obj', source = 'test1.f',
+ FORTRANCOM = r'%(_python_)s myfortran.py $_FORTRANMODFLAG $SOURCE $TARGET',
FORTRANMODDIR='${TARGET.dir}')
""" % locals())
test.must_match(['modules', 'mod_foo.mod'], "myfortran.py wrote mod_foo.mod\n")
test.must_not_exist(['modules', 'mod_bar.mod'])
-test.must_match(['sub', 'test2.obj'], "myfortran.py wrote test2.obj\n")
-test.must_match(['sub', 'mod_foo.mod'], "myfortran.py wrote mod_foo.mod\n")
+test.must_match(['sub2', 'test2.obj'], "myfortran.py wrote test2.obj\n")
+test.must_match(['sub2', 'mod_foo.mod'], "myfortran.py wrote mod_foo.mod\n")
+
+test.must_match(['sub3', 'test3.obj'], "myfortran.py wrote test3.obj\n")
+test.must_match(['sub3', 'mod_foo.mod'], "myfortran.py wrote mod_foo.mod\n")
test.up_to_date(arguments = '.')
scons.send("build --taskmastertrace=- foo.out\n")
+test.wait_for(test.workpath('foo.out'))
+
scons.send("build 2\n")
test.wait_for(test.workpath('2'))
Touch("1")
scons>>>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'foo.out'> and its children:
-Taskmaster: <no_state 'foo.in'>
-Taskmaster: Considering node <no_state 'foo.in'> and its children:
-Taskmaster: Evaluating <pending 'foo.in'>
+Taskmaster: Considering node <no_state 0 'foo.out'> and its children:
+Taskmaster: <no_state 0 'foo.in'>
+Taskmaster: adjusting ref count: <pending 1 'foo.out'>
+Taskmaster: Considering node <no_state 0 'foo.in'> and its children:
+Taskmaster: Evaluating <pending 0 'foo.in'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <pending 'foo.out'> and its children:
-Taskmaster: <up_to_date 'foo.in'>
-Taskmaster: Evaluating <pending 'foo.out'>
+Taskmaster: Considering node <pending 0 'foo.out'> and its children:
+Taskmaster: <up_to_date 0 'foo.in'>
+Taskmaster: Evaluating <pending 0 'foo.out'>
Copy("foo.out", "foo.in")
Taskmaster: Looking for a node to evaluate
# c) Some targets succeed building
# d) Some children are ignored
# e) Some children are pre-requesites
-# f) Some sources are missing
+# f) Some children have side-effects
+# g) Some sources are missing
+# h) Builds that are interrupted
test.write('SConstruct', """
+opts = Options()
+opts.Add( BoolOption('interrupt', 'Interrupt the build.', 0 ) )
+optEnv = Environment(options=opts)
+
def fail_action(target = None, source = None, env = None):
return 2
+def simulate_keyboard_interrupt(target = None, source = None, env = None):
+ # Directly invoked the SIGINT handler to simulate a
+ # KeyboardInterrupt. This hack is necessary because there is no
+ # easy way to get access to the current Job/Taskmaster object.
+ import signal
+ handler = signal.getsignal(signal.SIGINT)
+ handler(signal.SIGINT, None)
+ return 0
+
+interrupt = Command(target='interrupt', source='', action=simulate_keyboard_interrupt)
+
+
failed0 = Command(target='failed00', source='', action=fail_action)
-ok0 = Command(target='ok00', source='', action=Touch('${TARGET}'))
+ok0 = Command(target=['ok00a', 'ok00b', 'ok00c'],
+ source='',
+ action=[Touch('${TARGETS[0]}'), Touch('${TARGETS[1]}'), Touch('${TARGETS[2]}')])
prereq0 = Command(target='prereq00', source='', action=Touch('${TARGET}'))
ignore0 = Command(target='ignore00', source='', action=Touch('${TARGET}'))
igreq0 = Command(target='igreq00', source='', action=Touch('${TARGET}'))
missing0 = Command(target='missing00', source='MissingSrc', action=Touch('${TARGET}'))
+withSE0 = Command(target=['withSE00a', 'withSE00b', 'withSE00c'],
+ source='',
+ action=[Touch('${TARGETS[0]}'), Touch('${TARGETS[1]}'), Touch('${TARGETS[2]}'),
+ Touch('side_effect')])
+SideEffect('side_effect', withSE0)
-prev_level = failed0 + ok0 + ignore0
+prev_level = failed0 + ok0 + ignore0 + missing0 + withSE0
prev_prereq = prereq0
prev_ignore = ignore0
prev_igreq = igreq0
+if optEnv['interrupt']:
+ prev_level = prev_level + interrupt
+
for i in range(1,20):
failed = Command(target='failed%02d' % i, source='', action=fail_action)
- ok = Command(target='ok%02d' % i, source='', action=Touch('${TARGET}'))
+ ok = Command(target=['ok%02da' % i, 'ok%02db' % i, 'ok%02dc' % i],
+ source='',
+ action=[Touch('${TARGETS[0]}'), Touch('${TARGETS[1]}'), Touch('${TARGETS[2]}')])
prereq = Command(target='prereq%02d' % i, source='', action=Touch('${TARGET}'))
ignore = Command(target='ignore%02d' % i, source='', action=Touch('${TARGET}'))
igreq = Command(target='igreq%02d' % i, source='', action=Touch('${TARGET}'))
missing = Command(target='missing%02d' %i, source='MissingSrc', action=Touch('${TARGET}'))
+ withSE = Command(target=['withSE%02da' % i, 'withSE%02db' % i, 'withSE%02dc' % i],
+ source='',
+ action=[Touch('${TARGETS[0]}'), Touch('${TARGETS[1]}'), Touch('${TARGETS[2]}'),
+ Touch('side_effect')])
+ SideEffect('side_effect', withSE)
- next_level = failed + ok + ignore + igreq + missing
+ next_level = failed + ok + ignore + igreq + missing + withSE
for j in range(1,10):
a = Alias('a%02d%02d' % (i,j), prev_level)
re_error = """\
(scons: \\*\\*\\* \\[failed\\d+] Error 2\\n)|\
-(scons: \\*\\*\\* Source `MissingSrc' not found, needed by target `missing\\d+'\\.( Stop\\.)?\\n)\
+(scons: \\*\\*\\* Source `MissingSrc' not found, needed by target `missing\\d+'\\.( Stop\\.)?\\n)|\
+(scons: \\*\\*\\* \\[\\w+] Build interrupted\.\\n)\
"""
re_errors = "(" + re_error + ")+"
test.run(arguments = 'all',
status = 2,
stderr = "scons: *** [failed19] Error 2\n")
-test.must_not_exist(test.workpath('ok'))
+test.must_not_exist(test.workpath('side_effect'))
+for i in range(20):
+ test.must_not_exist(test.workpath('ok%02da' % i))
+ test.must_not_exist(test.workpath('ok%02db' % i))
+ test.must_not_exist(test.workpath('ok%02dc' % i))
+ test.must_not_exist(test.workpath('prereq%02d' % i))
+ test.must_not_exist(test.workpath('ignore%02d' % i))
+ test.must_not_exist(test.workpath('igreq%02d' % i))
+ test.must_not_exist(test.workpath('withSE%02da' % i))
+ test.must_not_exist(test.workpath('withSE%02db' % i))
+ test.must_not_exist(test.workpath('withSE%02dc' % i))
for i in range(5):
status = 2,
stderr = re_errors,
match=TestSCons.match_re_dotall)
+ test.must_exist(test.workpath('side_effect'))
for i in range(20):
- test.must_exist(test.workpath('ok%02d' % i))
+ test.must_exist(test.workpath('ok%02da' % i))
+ test.must_exist(test.workpath('ok%02db' % i))
+ test.must_exist(test.workpath('ok%02dc' % i))
test.must_exist(test.workpath('prereq%02d' % i))
test.must_not_exist(test.workpath('ignore%02d' % i))
test.must_exist(test.workpath('igreq%02d' % i))
+ test.must_exist(test.workpath('withSE%02da' % i))
+ test.must_exist(test.workpath('withSE%02db' % i))
+ test.must_exist(test.workpath('withSE%02dc' % i))
for i in range(5):
status = 2,
stderr = re_errors,
match=TestSCons.match_re_dotall)
- test.must_not_exist(test.workpath('ok'))
+
for i in range(5):
test.run(arguments = '-c all')
stderr = re_errors,
match=TestSCons.match_re_dotall)
+
for i in range(5):
test.run(arguments = '-c all')
status = 2,
stderr = re_errors,
match=TestSCons.match_re_dotall)
+ test.must_exist(test.workpath('side_effect'))
for i in range(20):
- test.must_exist(test.workpath('ok%02d' % i))
+ test.must_exist(test.workpath('ok%02da' % i))
+ test.must_exist(test.workpath('ok%02db' % i))
+ test.must_exist(test.workpath('ok%02dc' % i))
test.must_exist(test.workpath('prereq%02d' % i))
test.must_not_exist(test.workpath('ignore%02d' % i))
test.must_exist(test.workpath('igreq%02d' % i))
+ test.must_exist(test.workpath('withSE%02da' % i))
+ test.must_exist(test.workpath('withSE%02db' % i))
+ test.must_exist(test.workpath('withSE%02dc' % i))
+
+
+for i in range(5):
+ test.run(arguments = '-c all')
+
+ test.run(arguments = '-j 8 -k --random interrupt=yes all',
+ status = 2,
+ stderr = re_errors,
+ match=TestSCons.match_re_dotall)
+
test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that an implicit dependency search for a directory for which
+we have an Entry Node works as expected, converting the Entry into a
+Dir Node.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env = Environment()
+tc = env.Program('testcase', 'testcase.cpp')
+foo = env.Entry('foo')
+tc[0].all_children()[0].all_children()
+""")
+
+test.write('testcase.cpp', """\
+#if 0
+#include "foo/bar/widget.h"
+#endif
+int main(int argc, char *argv[])
+{
+ return 0;
+}
+""")
+
+test.run(arguments = '.')
+
+# In 0.98.2, re-running failed with a stack trace.
+test.run(arguments = '.')
+
+test.pass_test()
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that a source_scanner that uses a dictionary to select more
+specific scanners for source file suffixes works correctly, even
+when it's handed a file suffix that it doesn't know how to scan
+(i.e., for which it doesn't have a specific scanner in its dictionary).
+"""
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+test.write('build.py', r"""
+import sys
+output = open(sys.argv[1], 'wb')
+for infile in sys.argv[2:]:
+ input = open(infile, 'rb')
+
+ include_prefix = 'include%s ' % infile[-1]
+
+ def process(infp, outfp, include_prefix=include_prefix):
+ for line in infp.readlines():
+ if line[:len(include_prefix)] == include_prefix:
+ file = line[len(include_prefix):-1]
+ process(open(file, 'rb'), outfp)
+ else:
+ outfp.write(line)
+
+ process(input, output)
+
+sys.exit(0)
+""")
+
+# Execute a subsidiary SConscript just to make sure we can
+# get at the Scanner keyword from there.
+
+test.write('SConstruct', """
+SConscript('SConscript')
+""")
+
+test.write('SConscript', """
+import re
+
+include1_re = re.compile(r'^include1\s+(\S+)$', re.M)
+include2_re = re.compile(r'^include2\s+(\S+)$', re.M)
+include3_re = re.compile(r'^include3\s+(\S+)$', re.M)
+
+def k1_scan(node, env, scanpaths, arg=None):
+ contents = node.get_contents()
+ includes = include1_re.findall(contents)
+ return includes
+
+def k2_scan(node, env, scanpaths, arg=None):
+ contents = node.get_contents()
+ includes = include2_re.findall(contents)
+ return includes
+
+def k3_scan(node, env, scanpaths, arg=None):
+ contents = node.get_contents()
+ includes = include3_re.findall(contents)
+ return includes
+
+kscanner = Scanner({'.k1' : Scanner(k1_scan), '.k2': Scanner(k2_scan)})
+
+b = Builder(action=r'%(_python_)s build.py $TARGET $SOURCES',
+ source_scanner=kscanner)
+env = Environment(BUILDERS={'Build':b})
+
+kscanner.add_scanner('.k3', Scanner(k3_scan))
+
+env.Build('aaa', 'aaa.k1')
+env.Build('bbb', 'bbb.k2')
+env.Build('ccc', 'ccc.k3')
+env.Build('ddd', ['ddd.k4', 'aaa.k1', 'bbb.k2', 'ccc.k3'])
+""" % locals())
+
+test.write('aaa.k1',
+"""aaa.k1 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('bbb.k2',
+"""bbb.k2 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('ccc.k3',
+"""ccc.k3 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('ddd.k4',
+"""ddd.k4 1
+line 2
+line 3
+""")
+
+test.write('xxx', "xxx 1\n")
+test.write('yyy', "yyy 1\n")
+test.write('zzz', "zzz 1\n")
+
+
+
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py aaa aaa.k1
+%(_python_)s build.py bbb bbb.k2
+%(_python_)s build.py ccc ccc.k3
+%(_python_)s build.py ddd ddd.k4 aaa.k1 bbb.k2 ccc.k3
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_aaa = 'aaa.k1 1\nline 2\nxxx 1\ninclude2 yyy\ninclude3 zzz\nline 6\n'
+expect_bbb = 'bbb.k2 1\nline 2\ninclude1 xxx\nyyy 1\ninclude3 zzz\nline 6\n'
+expect_ccc = 'ccc.k3 1\nline 2\ninclude1 xxx\ninclude2 yyy\nzzz 1\nline 6\n'
+expect_ddd = 'ddd.k4 1\nline 2\nline 3\n' + expect_aaa + expect_bbb + expect_ccc
+
+test.must_match('aaa', expect_aaa)
+test.must_match('bbb', expect_bbb)
+test.must_match('ccc', expect_ccc)
+test.must_match('ddd', expect_ddd)
+
+test.up_to_date(arguments = '.')
+
+
+
+test.write('zzz', "zzz 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py ccc ccc.k3
+%(_python_)s build.py ddd ddd.k4 aaa.k1 bbb.k2 ccc.k3
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_ccc = 'ccc.k3 1\nline 2\ninclude1 xxx\ninclude2 yyy\nzzz 2\nline 6\n'
+expect_ddd = 'ddd.k4 1\nline 2\nline 3\n' + expect_aaa + expect_bbb + expect_ccc
+
+test.must_match('bbb', expect_bbb)
+test.must_match('ddd', expect_ddd)
+
+
+
+test.write('yyy', "yyy 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py bbb bbb.k2
+%(_python_)s build.py ddd ddd.k4 aaa.k1 bbb.k2 ccc.k3
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_bbb = 'bbb.k2 1\nline 2\ninclude1 xxx\nyyy 2\ninclude3 zzz\nline 6\n'
+expect_ddd = 'ddd.k4 1\nline 2\nline 3\n' + expect_aaa + expect_bbb + expect_ccc
+
+test.must_match('bbb', expect_bbb)
+test.must_match('ddd', expect_ddd)
+
+
+
+test.write('xxx', "xxx 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py aaa aaa.k1
+%(_python_)s build.py ddd ddd.k4 aaa.k1 bbb.k2 ccc.k3
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_aaa = 'aaa.k1 1\nline 2\nxxx 2\ninclude2 yyy\ninclude3 zzz\nline 6\n'
+expect_ddd = 'ddd.k4 1\nline 2\nline 3\n' + expect_aaa + expect_bbb + expect_ccc
+
+test.must_match('aaa', expect_aaa)
+test.must_match('ddd', expect_ddd)
+
+
+
+test.pass_test()
test.write(SConstruct_path, """\
+from SCons.Variables.BoolVariable import BoolVariable
+BV = BoolVariable
+
from SCons.Variables import BoolVariable
opts = Variables(args=ARGUMENTS)
opts.AddVariables(
BoolVariable('warnings', 'compilation with -Wall and similiar', 1),
- BoolVariable('profile', 'create profiling informations', 0),
+ BV('profile', 'create profiling informations', 0),
)
env = Environment(variables=opts)
expect_stderr = """
scons: *** Error converting option: warnings
Invalid value for boolean option: irgendwas
-""" + test.python_file_line(SConstruct_path, 9)
+""" + test.python_file_line(SConstruct_path, 12)
test.run(arguments='warnings=irgendwas', stderr = expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Variables.EnumVariable import EnumVariable
+EV = EnumVariable
+
from SCons.Variables import EnumVariable
list_of_libs = Split('x11 gl qt ical')
EnumVariable('guilib', 'gui lib to use', 'gtk',
allowed_values=('motif', 'gtk', 'kde'),
map={}, ignorecase=1), # case insensitive
- EnumVariable('some', 'some option', 'xaver',
- allowed_values=('xaver', 'eins'),
- map={}, ignorecase=2), # make lowercase
+ EV('some', 'some option', 'xaver',
+ allowed_values=('xaver', 'eins'),
+ map={}, ignorecase=2), # make lowercase
)
env = Environment(variables=opts)
expect_stderr = """
scons: *** Invalid value for option debug: FULL
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='debug=FULL', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Invalid value for option guilib: irgendwas
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='guilib=IrGeNdwas', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Invalid value for option some: irgendwas
-""" + test.python_file_line(SConstruct_path, 18)
+""" + test.python_file_line(SConstruct_path, 21)
test.run(arguments='some=IrGeNdwas', stderr=expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Variables.ListVariable import ListVariable
+LV = ListVariable
+
from SCons.Variables import ListVariable
list_of_libs = Split('x11 gl qt ical')
'all',
names = list_of_libs,
map = {'GL':'gl', 'QT':'qt'}),
+ LV('listvariable', 'listvariable help', 'all', names=['l1', 'l2', 'l3'])
)
env = Environment(variables=opts)
check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
"['gl ical qt x11']"])
-test.must_match(test.workpath('scons.variables'), "shared = 'all'"+os.linesep)
+expect = "shared = 'all'"+os.linesep+"listvariable = 'all'"+os.linesep
+test.must_match(test.workpath('scons.variables'), expect)
check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
"['gl ical qt x11']"])
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo,ical', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=ical,foo', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=ical,foo,x11', stderr=expect_stderr, status=2)
expect_stderr = """
scons: *** Error converting option: shared
Invalid value(s) for option: foo,bar
-""" + test.python_file_line(SConstruct_path, 15)
+""" + test.python_file_line(SConstruct_path, 19)
test.run(arguments='shared=foo,x11,,,bar', stderr=expect_stderr, status=2)
test.write(SConstruct_path, """\
+from SCons.Variables.PackageVariable import PackageVariable
+PV = PackageVariable
+
from SCons.Variables import PackageVariable
opts = Variables(args=ARGUMENTS)
PackageVariable('x11',
'use X11 installed here (yes = search some places',
'yes'),
+ PV('package', 'help for package', 'yes'),
)
env = Environment(variables=opts)
expect_stderr = """
scons: *** Path does not exist for option x11: /non/existing/path/
-""" + test.python_file_line(SConstruct_path, 10)
+""" + test.python_file_line(SConstruct_path, 14)
test.run(arguments='x11=/non/existing/path/', stderr=expect_stderr, status=2)
libpath = os.path.join(workpath, 'lib')
test.write(SConstruct_path, """\
+from SCons.Variables.PathVariable import PathVariable
+PV = PathVariable
+
from SCons.Variables import PathVariable
qtdir = r'%s'
opts = Variables(args=ARGUMENTS)
opts.AddVariables(
PathVariable('qtdir', 'where the root of Qt is installed', qtdir),
- PathVariable('qt_libraries', 'where the Qt library is installed', r'%s'),
+ PV('qt_libraries', 'where the Qt library is installed', r'%s'),
)
env = Environment(variables=opts)
check([qtpath, libpath, libpath])
qtpath = os.path.join(workpath, 'non', 'existing', 'path')
-SConstruct_file_line = test.python_file_line(test.workpath('SConstruct'), 11)[:-1]
+SConstruct_file_line = test.python_file_line(test.workpath('SConstruct'), 14)[:-1]
expect_stderr = """
scons: *** Path for option qtdir does not exist: %(qtpath)s
expect_stdout = test.wrap_stdout("""\
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state '.'> and its children:
-Taskmaster: <no_state 'SConstruct'>
-Taskmaster: <no_state 'Tfile.in'>
-Taskmaster: <no_state 'Tfile.mid'>
-Taskmaster: <no_state 'Tfile.out'>
-Taskmaster: Considering node <no_state 'SConstruct'> and its children:
-Taskmaster: Evaluating <pending 'SConstruct'>
+Taskmaster: Considering node <no_state 0 '.'> and its children:
+Taskmaster: <no_state 0 'SConstruct'>
+Taskmaster: <no_state 0 'Tfile.in'>
+Taskmaster: <no_state 0 'Tfile.mid'>
+Taskmaster: <no_state 0 'Tfile.out'>
+Taskmaster: adjusting ref count: <pending 1 '.'>
+Taskmaster: adjusting ref count: <pending 2 '.'>
+Taskmaster: adjusting ref count: <pending 3 '.'>
+Taskmaster: adjusting ref count: <pending 4 '.'>
+Taskmaster: Considering node <no_state 0 'SConstruct'> and its children:
+Taskmaster: Evaluating <pending 0 'SConstruct'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.in'> and its children:
-Taskmaster: Evaluating <pending 'Tfile.in'>
+Taskmaster: Considering node <no_state 0 'Tfile.in'> and its children:
+Taskmaster: Evaluating <pending 0 'Tfile.in'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.mid'> and its children:
-Taskmaster: <up_to_date 'Tfile.in'>
-Taskmaster: Evaluating <pending 'Tfile.mid'>
+Taskmaster: Considering node <no_state 0 'Tfile.mid'> and its children:
+Taskmaster: <up_to_date 0 'Tfile.in'>
+Taskmaster: Evaluating <pending 0 'Tfile.mid'>
Copy("Tfile.mid", "Tfile.in")
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.out'> and its children:
-Taskmaster: <executed 'Tfile.mid'>
-Taskmaster: Evaluating <pending 'Tfile.out'>
+Taskmaster: Considering node <no_state 0 'Tfile.out'> and its children:
+Taskmaster: <executed 0 'Tfile.mid'>
+Taskmaster: Evaluating <pending 0 'Tfile.out'>
Copy("Tfile.out", "Tfile.mid")
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <pending '.'> and its children:
-Taskmaster: <up_to_date 'SConstruct'>
-Taskmaster: <up_to_date 'Tfile.in'>
-Taskmaster: <executed 'Tfile.mid'>
-Taskmaster: <executed 'Tfile.out'>
-Taskmaster: Evaluating <pending '.'>
+Taskmaster: Considering node <pending 0 '.'> and its children:
+Taskmaster: <up_to_date 0 'SConstruct'>
+Taskmaster: <up_to_date 0 'Tfile.in'>
+Taskmaster: <executed 0 'Tfile.mid'>
+Taskmaster: <executed 0 'Tfile.out'>
+Taskmaster: Evaluating <pending 0 '.'>
Taskmaster: Looking for a node to evaluate
Taskmaster: No candidate anymore.
expect_trace = """\
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state '.'> and its children:
-Taskmaster: <no_state 'SConstruct'>
-Taskmaster: <no_state 'Tfile.in'>
-Taskmaster: <no_state 'Tfile.mid'>
-Taskmaster: <no_state 'Tfile.out'>
-Taskmaster: Considering node <no_state 'SConstruct'> and its children:
-Taskmaster: Evaluating <pending 'SConstruct'>
+Taskmaster: Considering node <no_state 0 '.'> and its children:
+Taskmaster: <no_state 0 'SConstruct'>
+Taskmaster: <no_state 0 'Tfile.in'>
+Taskmaster: <no_state 0 'Tfile.mid'>
+Taskmaster: <no_state 0 'Tfile.out'>
+Taskmaster: adjusting ref count: <pending 1 '.'>
+Taskmaster: adjusting ref count: <pending 2 '.'>
+Taskmaster: adjusting ref count: <pending 3 '.'>
+Taskmaster: adjusting ref count: <pending 4 '.'>
+Taskmaster: Considering node <no_state 0 'SConstruct'> and its children:
+Taskmaster: Evaluating <pending 0 'SConstruct'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.in'> and its children:
-Taskmaster: Evaluating <pending 'Tfile.in'>
+Taskmaster: Considering node <no_state 0 'Tfile.in'> and its children:
+Taskmaster: Evaluating <pending 0 'Tfile.in'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.mid'> and its children:
-Taskmaster: <up_to_date 'Tfile.in'>
-Taskmaster: Evaluating <pending 'Tfile.mid'>
+Taskmaster: Considering node <no_state 0 'Tfile.mid'> and its children:
+Taskmaster: <up_to_date 0 'Tfile.in'>
+Taskmaster: Evaluating <pending 0 'Tfile.mid'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <no_state 'Tfile.out'> and its children:
-Taskmaster: <executed 'Tfile.mid'>
-Taskmaster: Evaluating <pending 'Tfile.out'>
+Taskmaster: Considering node <no_state 0 'Tfile.out'> and its children:
+Taskmaster: <executed 0 'Tfile.mid'>
+Taskmaster: Evaluating <pending 0 'Tfile.out'>
Taskmaster: Looking for a node to evaluate
-Taskmaster: Considering node <pending '.'> and its children:
-Taskmaster: <up_to_date 'SConstruct'>
-Taskmaster: <up_to_date 'Tfile.in'>
-Taskmaster: <executed 'Tfile.mid'>
-Taskmaster: <executed 'Tfile.out'>
-Taskmaster: Evaluating <pending '.'>
+Taskmaster: Considering node <pending 0 '.'> and its children:
+Taskmaster: <up_to_date 0 'SConstruct'>
+Taskmaster: <up_to_date 0 'Tfile.in'>
+Taskmaster: <executed 0 'Tfile.mid'>
+Taskmaster: <executed 0 'Tfile.out'>
+Taskmaster: Evaluating <pending 0 '.'>
Taskmaster: Looking for a node to evaluate
Taskmaster: No candidate anymore.