upgrade to the latest scons (0.97)

This commit is contained in:
Artem Pavlenko 2007-08-07 15:50:34 +00:00
parent 8887b9eb99
commit 6752dda07e
165 changed files with 20697 additions and 11194 deletions

View file

@ -1,9 +1,4 @@
Copyright and license for SCons - a software construction tool
This copyright and license do not apply to any other software
with which this software may have been included.
Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,42 +1,28 @@
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
# src/README.txt 0.97.D001 2007/05/17 11:35:19 knight
SCons - a software construction tool
This is the scons-README file for a version of SCons packaged for local
execution--that is, execution out of a specific local directory, without
having to install SCons as a system-wide utility.
Version 0.97
You are likely reading this file in one of the following two situations:
1) You have unpacked an scons-local-{version} package and are
examining the contents.
This is a beta release of SCons, a tool for building software (and other
files). SCons is implemented in Python, and its "configuration files"
are actually Python scripts, allowing you to use the full power of a
real scripting language to solve build problems. You do not, however,
need to know Python to use SCons effectively.
In this case, you are presumably interested in using this
package to include a local copy of SCons with some other
software that you package, so that you can use SCons to build
your software without forcing all of your users to have it fully
installed. Instructions for this can be found below.
See the RELEASE.txt file for notes about this specific release,
including known problems. See the CHANGES.txt file for a list of
changes since the previous release.
If you are not looking to use SCons in this way, then please
use either the scons-{version} package to install SCons on your
system, or the scons-src-{version} package if you want the full
source to SCons, including its packaging code and underlying
tests and testing infrastructure.
2) This file was included in some other software package so that
the package could be built using SCons.
In this case, follow the instructions provided with the
rest of the software package for how to use SCons to build
and/or install the software. The file containing build and
installation instructions will typically be named README or
INSTALL.
LATEST VERSION
==============
Before going further, you can check for the latest version of the
scons-local package, or any SCons package, at the SCons download page:
Before going further, you can check that this package you have is
the latest version by checking the SCons download page at:
http://www.scons.org/download.html
@ -45,93 +31,149 @@ EXECUTION REQUIREMENTS
======================
Running SCons requires Python version 1.5.2 or later. There should be
no other dependencies or requirements to run SCons.
no other dependencies or requirements to run SCons. (There is, however,
an additional requirement to *install* SCons from this particular
package; see the next section.)
The default SCons configuration assumes use of the Microsoft Visual C++
compiler suite on WIN32 systems, and assumes a C compiler named 'cc',
a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such
as found in the GNU C compiler suite) on any other type of system.
You may, of course, override these default values by appropriate
By default, SCons knows how to search for available programming tools
on various systems--see the SCons man page for details. You may,
of course, override the default SCons choices made by appropriate
configuration of Environment construction variables.
INSTALLATION REQUIREMENTS
=========================
Installing SCons from this package requires the Python distutils
package. The distutils package was not shipped as a standard part of
Python until Python version 1.6, so if your system is running Python
1.5.2, you may not have distutils installed. If you are running
Python version 1.6 or later, you should be fine.
NOTE TO RED HAT USERS: Red Hat shipped Python 1.5.2 as the default all
the way up to Red Hat Linux 7.3, so you probably do *not* have distutils
installed, unless you have already done so manually or are running Red
Hat 8.0 or later.
In this case, your options are:
-- (Recommended.) Install from a pre-packaged SCons package that
does not require distutils:
Red Hat Linux scons-0.97-1.noarch.rpm
Debian GNU/Linux scons_0.97-1_all.deb
(or use apt-get)
Windows scons-0.97.win32.exe
-- (Optional.) Download the latest distutils package from the
following URL:
http://www.python.org/sigs/distutils-sig/download.html
Install the distutils according to the instructions on the page.
You can then proceed to the next section to install SCons from
this package.
INSTALLATION
============
Installation of this package should be as simple as unpacking the
archive (either .tar.gz or .zip) in any directory (top-level or a
subdirectory) within the software package with which you want to ship
SCons.
Assuming your system satisfies the installation requirements in the
previous section, install SCons from this package simply by running the
provided Python-standard setup script as follows:
Once you have installed this package, you should write an SConstruct
file at the top level of your source tree to build your software as you
see fit.
# python setup.py install
Then modify the build/install instructions for your package to instruct
your users to execute SCons as follows (if you installed this package in
your top-level directory):
By default, the above command will do the following:
$ python scons.py
-- Install the version-numbered "scons-0.97" and "sconsign-0.97"
scripts in the default system script directory (/usr/bin or
C:\Python*\Scripts, for example). This can be disabled by
specifying the "--no-version-script" option on the command
line.
Or (if, for example, you installed this package in a subdirectory named
"scons"):
-- Install scripts named "scons" and "sconsign" scripts in the
default system script directory (/usr/bin or C:\Python*\Scripts,
for example). This can be disabled by specifying the
"--no-scons-script" option on the command line, which is useful
if you want to install and experiment with a new version before
making it the default on your system.
$ python scons/scons.py
On UNIX or Linux systems, you can have the "scons" and "sconsign"
scripts be hard links or symbolic links to the "scons-0.97" and
"sconsign-0.97" scripts by specifying the "--hardlink-scons"
or "--symlink-scons" options on the command line.
That should be all you have to do. (If it isn't that simple, please let
us know!)
-- Install "scons-0.97.bat" and "scons.bat" wrapper scripts in the
Python prefix directory on Windows (C:\Python*, for example).
This can be disabled by specifying the "--no-install-bat" option
on the command line.
On UNIX or Linux systems, the "--install-bat" option may be
specified to have "scons-0.97.bat" and "scons.bat" files
installed in the default system script directory, which is useful
if you want to install SCons in a shared file system directory
that can be used to execute SCons from both UNIX/Linux and
Windows systems.
CONTENTS OF THIS PACKAGE
========================
-- Install the SCons build engine (a Python module) in an
appropriate version-numbered SCons library directory
(/usr/lib/scons-0.97 or C:\Python*\scons-0.97, for example).
See below for more options related to installing the build
engine library.
This scons-local package consists of the following:
-- Install the troff-format man pages in an appropriate directory
on UNIX or Linux systems (/usr/share/man/man1 or /usr/man/man1,
for example). This can be disabled by specifying the
"--no-install-man" option on the command line. The man pages
can be installed on Windows systems by specifying the
"--install-man" option on the command line.
scons-LICENSE
A copy of the copyright and terms under which SCons is
distributed (the Open Source Initiative-approved MIT license).
Note that, by default, SCons does not install its build engine library
in the standard Python library directories. If you want to be able to
use the SCons library modules (the build engine) in other Python
scripts, specify the "--standard-lib" option on the command line, as
follows:
A disclaimer has been added to the beginning to make clear that
this license applies only to SCons, and not to any separate
software you've written with which you're planning to package
SCons.
# python setup.py install --standard-lib
scons-README
What you're looking at right now.
This will install the build engine in the standard Python library
directory (/usr/lib/python*/site-packages or
C:\Python*\Lib\site-packages).
scons-local-{version}/
The SCons build engine. This is structured as a Python
library.
Alternatively, you can have SCons install its build engine library in a
hard-coded standalone library directory, instead of the default
version-numbered directory, by specifying the "--standalone-lib" option
on the command line, as follows:
scons.py
The SCons script itself. The script sets up the Python
sys.path variable to use the build engine found in the
scons-local-{version}/ directory in preference to any other
SCons build engine installed on your system.
# python setup.py install --standalone-lib
This is usually not recommended, however.
Note that, to install SCons in any of the above system directories,
you should have system installation privileges (that is, "root" or
"Administrator") when running the setup.py script. If you don't have
system installation privileges, you can use the --prefix option to
specify an alternate installation location, such as your home directory:
$ python setup.py install --prefix=$HOME
This will install SCons in the appropriate locations relative to
$HOME--that is, the scons script itself $HOME/bin and the associated
library in $HOME/lib/scons, for example.
DOCUMENTATION
=============
Because this package is intended to be included with other software by
experienced users, we have not included any SCons documentation in this
package (other than this scons-README file you're reading right now).
See the RELEASE.txt file for notes about this specific release,
including known problems. See the CHANGES.txt file for a list of
changes since the previous release.
If, however, you need documentation about SCons, then consult any of the
following from the corresponding scons-{version} or scons-src-{version}
package:
The RELEASE.txt file (src/RELEASE.txt file in the
scons-src-{version} package), which contains notes about this
specific release, including known problems.
The CHANGES.txt file (src/CHANGES.txt file in the
scons-src-{version} package), which contains a list of changes
since the previous release.
The scons.1 man page (doc/man/scons.1 in the scons-src-{version}
package), which contains a section of small examples for getting
started using SCons.
The scons.1 man page is included in this package, and contains a section
of small examples for getting started using SCons.
Additional documentation for SCons is available at:
@ -142,8 +184,8 @@ LICENSING
=========
SCons is distributed under the MIT license, a full copy of which is
available in the scons-LICENSE file in this package. The MIT license is
an approved Open Source license, which means:
available in the LICENSE.txt file. The MIT license is an approved Open
Source license, which means:
This software is OSI Certified Open Source Software. OSI
Certified is a certification mark of the Open Source Initiative.
@ -157,27 +199,51 @@ available at:
REPORTING BUGS
==============
You can report bugs either by following the "Tracker - Bugs" link
on the SCons project page:
Please report bugs by following the detailed instructions on our Bug
Submission page:
http://sourceforge.net/projects/scons/
http://scons.tigris.org/bug-submission.html
or by sending mail to the SCons developers mailing list:
You can also send mail to the SCons developers' mailing list:
scons-devel@lists.sourceforge.net
dev@scons.tigris.org
But even if you send email to the mailing list please make sure that you
ALSO submit a bug report to the project page bug tracker, because bug
reports in email often get overlooked in the general flood of messages.
MAILING LISTS
=============
A mailing list for users of SCons is available. You may send questions
or comments to the list at:
An active mailing list for users of SCons is available. You may send
questions or comments to the list at:
scons-users@lists.sourceforge.net
users@scons.tigris.org
You may subscribe to the scons-users mailing list at:
You may subscribe to the mailing list by sending email to:
http://lists.sourceforge.net/lists/listinfo/scons-users
users-subscribe@scons.tigris.org
There is also a low-volume mailing list available for announcements
about SCons. Subscribe by sending email to:
announce-subscribe@scons.tigris.org
There are other mailing lists available for SCons developers, for
notification of SCons code changes, and for notification of updated
bug reports and project documents. Please see our mailing lists page
for details.
DONATIONS
=========
If you find SCons helpful, please consider making a donation (of cash,
software, or hardware) to support continued work on the project.
Information is available at:
http://www.scons.org/donate.html
FOR MORE INFORMATION
@ -199,6 +265,9 @@ With plenty of help from the SCons Development team:
Chad Austin
Charles Crain
Steve Leblanc
Greg Noel
Gary Oberbrunner
Anthony Roach
Terrel Shumway
Greg Spencer
Christoph Wiedemann

View file

@ -1,642 +0,0 @@
"""SCons.Action
This encapsulates information about executing any sort of action that
can build one or more target Nodes (typically files) from one or more
source Nodes (also typically files) given a specific Environment.
The base class here is ActionBase. The base class supplies just a few
OO utility methods and some generic methods for displaying information
about an Action in response to the various commands that control printing.
The heavy lifting is handled by subclasses for the different types of
actions we might execute:
CommandAction
CommandGeneratorAction
FunctionAction
ListAction
The subclasses supply the following public interface methods used by
other modules:
__call__()
THE public interface, "calling" an Action object executes the
command or Python function. This also takes care of printing
a pre-substitution command for debugging purposes.
get_contents()
Fetches the "contents" of an Action for signature calculation.
This is what the Sig/*.py subsystem uses to decide if a target
needs to be rebuilt because its action changed.
genstring()
Returns a string representation of the Action *without* command
substitution, but allows a CommandGeneratorAction to generate
the right action based on the specified target, source and env.
This is used by the Signature subsystem (through the Executor)
to compare the actions used to build a target last time and
this time.
Subclasses also supply the following methods for internal use within
this module:
__str__()
Returns a string representation of the Action *without* command
substitution. This is used by the __call__() methods to display
the pre-substitution command whenever the --debug=presub option
is used.
strfunction()
Returns a substituted string representation of the Action.
This is used by the ActionBase.show() command to display the
command/function that will be executed to generate the target(s).
execute()
The internal method that really, truly, actually handles the
execution of a command or Python function. This is used so
that the __call__() methods can take care of displaying any
pre-substitution representations, and *then* execute an action
without worrying about the specific Actions involved.
There is a related independent ActionCaller class that looks like a
regular Action, and which serves as a wrapper for arbitrary functions
that we want to let the user specify the arguments to now, but actually
execute later (when an out-of-date check determines that it's needed to
be executed, for example). Objects of this class are returned by an
ActionFactory class that provides a __call__() method as a convenient
way for wrapping up the functions.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Action.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import os
import os.path
import re
import string
import sys
from SCons.Debug import logInstanceCreation
import SCons.Errors
import SCons.Util
class _Null:
pass
_null = _Null
print_actions = 1
execute_actions = 1
print_actions_presub = 0
default_ENV = None
def rfile(n):
try:
return n.rfile()
except AttributeError:
return n
def _actionAppend(act1, act2):
# This function knows how to slap two actions together.
# Mainly, it handles ListActions by concatenating into
# a single ListAction.
a1 = Action(act1)
a2 = Action(act2)
if a1 is None or a2 is None:
raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
if isinstance(a1, ListAction):
if isinstance(a2, ListAction):
return ListAction(a1.list + a2.list)
else:
return ListAction(a1.list + [ a2 ])
else:
if isinstance(a2, ListAction):
return ListAction([ a1 ] + a2.list)
else:
return ListAction([ a1, a2 ])
class CommandGenerator:
"""
Wraps a command generator function so the Action() factory
function can tell a generator function from a function action.
"""
def __init__(self, generator):
self.generator = generator
def __add__(self, other):
return _actionAppend(self, other)
def __radd__(self, other):
return _actionAppend(other, self)
def _do_create_action(act, *args, **kw):
"""This is the actual "implementation" for the
Action factory method, below. This handles the
fact that passing lists to Action() itself has
different semantics than passing lists as elements
of lists.
The former will create a ListAction, the latter
will create a CommandAction by converting the inner
list elements to strings."""
if isinstance(act, ActionBase):
return act
if SCons.Util.is_List(act):
return apply(CommandAction, (act,)+args, kw)
if isinstance(act, CommandGenerator):
return apply(CommandGeneratorAction, (act.generator,)+args, kw)
if callable(act):
return apply(FunctionAction, (act,)+args, kw)
if SCons.Util.is_String(act):
var=SCons.Util.get_environment_var(act)
if var:
# This looks like a string that is purely an Environment
# variable reference, like "$FOO" or "${FOO}". We do
# something special here...we lazily evaluate the contents
# of that Environment variable, so a user could put something
# like a function or a CommandGenerator in that variable
# instead of a string.
lcg = LazyCmdGenerator(var)
return apply(CommandGeneratorAction, (lcg,)+args, kw)
commands = string.split(str(act), '\n')
if len(commands) == 1:
return apply(CommandAction, (commands[0],)+args, kw)
else:
listCmdActions = map(lambda x: CommandAction(x), commands)
return apply(ListAction, (listCmdActions,)+args, kw)
return None
def Action(act, strfunction=_null, varlist=[], presub=_null):
"""A factory for action objects."""
if SCons.Util.is_List(act):
acts = map(lambda x, s=strfunction, v=varlist, ps=presub:
_do_create_action(x, strfunction=s, varlist=v, presub=ps),
act)
acts = filter(lambda x: not x is None, acts)
if len(acts) == 1:
return acts[0]
else:
return ListAction(acts, strfunction=strfunction, varlist=varlist, presub=presub)
else:
return _do_create_action(act, strfunction=strfunction, varlist=varlist, presub=presub)
class ActionBase:
"""Base class for actions that create output objects."""
def __init__(self, strfunction=_null, presub=_null, **kw):
if not strfunction is _null:
self.strfunction = strfunction
if presub is _null:
self.presub = print_actions_presub
else:
self.presub = presub
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
def __call__(self, target, source, env,
errfunc=None,
presub=_null,
show=_null,
execute=_null):
if not SCons.Util.is_List(target):
target = [target]
if not SCons.Util.is_List(source):
source = [source]
if presub is _null: presub = self.presub
if show is _null: show = print_actions
if execute is _null: execute = execute_actions
if presub:
t = string.join(map(str, target), 'and')
l = string.join(self.presub_lines(env), '\n ')
out = "Building %s with action(s):\n %s\n" % (t, l)
sys.stdout.write(out)
if show and self.strfunction:
s = self.strfunction(target, source, env)
if s:
sys.stdout.write(s + '\n')
if execute:
stat = self.execute(target, source, env)
if stat and errfunc:
errfunc(stat)
return stat
else:
return 0
def presub_lines(self, env):
# CommandGeneratorAction needs a real environment
# in order to return the proper string here, since
# it may call LazyCmdGenerator, which looks up a key
# in that env. So we temporarily remember the env here,
# and CommandGeneratorAction will use this env
# when it calls its __generate method.
self.presub_env = env
lines = string.split(str(self), '\n')
self.presub_env = None # don't need this any more
return lines
def genstring(self, target, source, env):
return str(self)
def get_actions(self):
return [self]
def __add__(self, other):
return _actionAppend(self, other)
def __radd__(self, other):
return _actionAppend(other, self)
def _string_from_cmd_list(cmd_list):
"""Takes a list of command line arguments and returns a pretty
representation for printing."""
cl = []
for arg in map(str, cmd_list):
if ' ' in arg or '\t' in arg:
arg = '"' + arg + '"'
cl.append(arg)
return string.join(cl)
class CommandAction(ActionBase):
"""Class for command-execution actions."""
def __init__(self, cmd, **kw):
# Cmd list can actually be a list or a single item...basically
# anything that we could pass in as the first arg to
# Environment.subst_list().
if __debug__: logInstanceCreation(self)
apply(ActionBase.__init__, (self,), kw)
self.cmd_list = cmd
def __str__(self):
return str(self.cmd_list)
def strfunction(self, target, source, env):
cmd_list = env.subst_list(self.cmd_list, 0, target, source)
return string.join(map(_string_from_cmd_list, cmd_list), "\n")
def execute(self, target, source, env):
"""Execute a command action.
This will handle lists of commands as well as individual commands,
because construction variable substitution may turn a single
"command" into a list. This means that this class can actually
handle lists of commands, even though that's not how we use it
externally.
"""
import SCons.Util
escape = env.get('ESCAPE', lambda x: x)
if env.has_key('SHELL'):
shell = env['SHELL']
else:
raise SCons.Errors.UserError('Missing SHELL construction variable.')
# for SConf support (by now): check, if we want to pipe the command
# output to somewhere else
if env.has_key('PIPE_BUILD'):
pipe_build = 1
if env.has_key('PSPAWN'):
pspawn = env['PSPAWN']
else:
raise SCons.Errors.UserError('Missing PSPAWN construction variable.')
if env.has_key('PSTDOUT'):
pstdout = env['PSTDOUT']
else:
raise SCons.Errors.UserError('Missing PSTDOUT construction variable.')
if env.has_key('PSTDERR'):
pstderr = env['PSTDERR']
else:
raise SCons.Errors.UserError('Missing PSTDOUT construction variable.')
else:
pipe_build = 0
if env.has_key('SPAWN'):
spawn = env['SPAWN']
else:
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
cmd_list = env.subst_list(self.cmd_list, 0, target, source)
for cmd_line in cmd_list:
if len(cmd_line):
try:
ENV = env['ENV']
except KeyError:
global default_ENV
if not default_ENV:
import SCons.Environment
default_ENV = SCons.Environment.Environment()['ENV']
ENV = default_ENV
# ensure that the ENV values are all strings:
for key, value in ENV.items():
if SCons.Util.is_List(value):
# If the value is a list, then we assume
# it is a path list, because that's a pretty
# common list like value to stick in an environment
# variable:
value = SCons.Util.flatten(value)
ENV[key] = string.join(map(str, value), os.pathsep)
elif not SCons.Util.is_String(value):
# If it isn't a string or a list, then
# we just coerce it to a string, which
# is proper way to handle Dir and File instances
# and will produce something reasonable for
# just about everything else:
ENV[key] = str(value)
# Escape the command line for the command
# interpreter we are using
cmd_line = SCons.Util.escape_list(cmd_line, escape)
if pipe_build:
ret = pspawn( shell, escape, cmd_line[0], cmd_line,
ENV, pstdout, pstderr )
else:
ret = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
if ret:
return ret
return 0
def get_contents(self, target, source, env, dict=None):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
since those parts don't affect signatures.
"""
cmd = self.cmd_list
if SCons.Util.is_List(cmd):
cmd = string.join(map(str, cmd))
else:
cmd = str(cmd)
return env.subst_target_source(cmd, SCons.Util.SUBST_SIG, target, source, dict)
class CommandGeneratorAction(ActionBase):
"""Class for command-generator actions."""
def __init__(self, generator, **kw):
if __debug__: logInstanceCreation(self)
apply(ActionBase.__init__, (self,), kw)
self.generator = generator
def __generate(self, target, source, env, for_signature):
# ensure that target is a list, to make it easier to write
# generator functions:
if not SCons.Util.is_List(target):
target = [target]
ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
gen_cmd = Action(ret)
if not gen_cmd:
raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
return gen_cmd
def strfunction(self, target, source, env):
if not SCons.Util.is_List(source):
source = [source]
rsources = map(rfile, source)
act = self.__generate(target, source, env, 0)
if act.strfunction:
return act.strfunction(target, rsources, env)
else:
return None
def __str__(self):
try:
env = self.presub_env or {}
except AttributeError:
env = {}
act = self.__generate([], [], env, 0)
return str(act)
def genstring(self, target, source, env):
return str(self.__generate(target, source, env, 0))
def execute(self, target, source, env):
rsources = map(rfile, source)
act = self.__generate(target, source, env, 0)
return act.execute(target, source, env)
def get_contents(self, target, source, env, dict=None):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
since those parts don't affect signatures.
"""
return self.__generate(target, source, env, 1).get_contents(target, source, env, dict=None)
class LazyCmdGenerator:
"""This is not really an Action, although it kind of looks like one.
This is really a simple callable class that acts as a command
generator. It holds on to a key into an Environment dictionary,
then waits until execution time to see what type it is, then tries
to create an Action out of it."""
def __init__(self, var):
if __debug__: logInstanceCreation(self)
self.var = SCons.Util.to_String(var)
def strfunction(self, target, source, env):
try:
return env[self.var]
except KeyError:
# The variable reference substitutes to nothing.
return ''
def __str__(self):
return 'LazyCmdGenerator: %s'%str(self.var)
def __call__(self, target, source, env, for_signature):
try:
return env[self.var]
except KeyError:
# The variable reference substitutes to nothing.
return ''
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
class FunctionAction(ActionBase):
"""Class for Python function actions."""
def __init__(self, execfunction, **kw):
if __debug__: logInstanceCreation(self)
self.execfunction = execfunction
apply(ActionBase.__init__, (self,), kw)
self.varlist = kw.get('varlist', [])
def function_name(self):
try:
return self.execfunction.__name__
except AttributeError:
try:
return self.execfunction.__class__.__name__
except AttributeError:
return "unknown_python_function"
def strfunction(self, target, source, env):
def array(a):
def quote(s):
return '"' + str(s) + '"'
return '[' + string.join(map(quote, a), ", ") + ']'
name = self.function_name()
tstr = array(target)
sstr = array(source)
return "%s(%s, %s)" % (name, tstr, sstr)
def __str__(self):
return "%s(env, target, source)" % self.function_name()
def execute(self, target, source, env):
rsources = map(rfile, source)
return self.execfunction(target=target, source=rsources, env=env)
def get_contents(self, target, source, env, dict=None):
"""Return the signature contents of this callable action.
By providing direct access to the code object of the
function, Python makes this extremely easy. Hooray!
"""
try:
# "self.execfunction" is a function.
contents = str(self.execfunction.func_code.co_code)
except AttributeError:
# "self.execfunction" is a callable object.
try:
contents = str(self.execfunction.__call__.im_func.func_code.co_code)
except AttributeError:
try:
# See if execfunction will do the heavy lifting for us.
gc = self.execfunction.get_contents
except AttributeError:
# This is weird, just do the best we can.
contents = str(self.execfunction)
else:
contents = gc(target, source, env, dict)
return contents + env.subst(string.join(map(lambda v: '${'+v+'}',
self.varlist)))
class ListAction(ActionBase):
"""Class for lists of other actions."""
def __init__(self, list, **kw):
if __debug__: logInstanceCreation(self)
apply(ActionBase.__init__, (self,), kw)
self.list = map(lambda x: Action(x), list)
def get_actions(self):
return self.list
def __str__(self):
s = []
for l in self.list:
s.append(str(l))
return string.join(s, "\n")
def strfunction(self, target, source, env):
s = []
for l in self.list:
if l.strfunction:
x = l.strfunction(target, source, env)
if not SCons.Util.is_List(x):
x = [x]
s.extend(x)
return string.join(s, "\n")
def execute(self, target, source, env):
for l in self.list:
r = l.execute(target, source, env)
if r:
return r
return 0
def get_contents(self, target, source, env, dict=None):
"""Return the signature contents of this action list.
Simple concatenation of the signatures of the elements.
"""
dict = SCons.Util.subst_dict(target, source)
return string.join(map(lambda x, t=target, s=source, e=env, d=dict:
x.get_contents(t, s, e, d),
self.list),
"")
class ActionCaller:
"""A class for delaying calling an Action function with specific
(positional and keyword) arguments until the Action is actually
executed.
This class looks to the rest of the world like a normal Action object,
but what it's really doing is hanging on to the arguments until we
have a target, source and env to use for the expansion.
"""
def __init__(self, parent, args, kw):
self.parent = parent
self.args = args
self.kw = kw
def get_contents(self, target, source, env, dict=None):
actfunc = self.parent.actfunc
try:
# "self.actfunc" is a function.
contents = str(actfunc.func_code.co_code)
except AttributeError:
# "self.actfunc" is a callable object.
try:
contents = str(actfunc.__call__.im_func.func_code.co_code)
except AttributeError:
# No __call__() method, so it might be a builtin
# or something like that. Do the best we can.
contents = str(actfunc)
return contents
def subst_args(self, target, source, env):
return map(lambda x, e=env, t=target, s=source:
e.subst(x, 0, t, s),
self.args)
def subst_kw(self, target, source, env):
kw = {}
for key in self.kw.keys():
kw[key] = env.subst(self.kw[key], 0, target, source)
return kw
def __call__(self, target, source, env):
args = self.subst_args(target, source, env)
kw = self.subst_kw(target, source, env)
return apply(self.parent.actfunc, args, kw)
def strfunction(self, target, source, env):
args = self.subst_args(target, source, env)
kw = self.subst_kw(target, source, env)
return apply(self.parent.strfunc, args, kw)
class ActionFactory:
"""A factory class that will wrap up an arbitrary function
as an SCons-executable Action object.
The real heavy lifting here is done by the ActionCaller class.
We just collect the (positional and keyword) arguments that we're
called with and give them to the ActionCaller object we create,
so it can hang onto them until it needs them.
"""
def __init__(self, actfunc, strfunc):
self.actfunc = actfunc
self.strfunc = strfunc
def __call__(self, *args, **kw):
ac = ActionCaller(self, args, kw)
return Action(ac, strfunction=ac.strfunction)

View file

@ -1,356 +0,0 @@
"""SCons.Defaults
Builders and other things for the local site. Here's where we'll
duplicate the functionality of autoconf until we move it into the
installation procedure or use something like qmconf.
The code that reads the registry to find MSVC components was borrowed
from distutils.msvccompiler.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/branch.96/baseline/src/engine/SCons/Defaults.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import os
import os.path
import shutil
import stat
import string
import time
import types
import SCons.Action
import SCons.Builder
import SCons.Environment
import SCons.Scanner.C
import SCons.Scanner.D
import SCons.Scanner.Prog
import SCons.Sig
# A placeholder for a default Environment (for fetching source files
# from source code management systems and the like). This must be
# initialized later, after the top-level directory is set by the calling
# interface.
_default_env = None
# Lazily instantiate the default environment so the overhead of creating
# it doesn't apply when it's not needed.
def DefaultEnvironment(*args, **kw):
global _default_env
if not _default_env:
_default_env = apply(SCons.Environment.Environment, args, kw)
_default_env._build_signature = 1
_default_env._calc_module = SCons.Sig.default_module
return _default_env
# Emitters for setting the shared attribute on object files,
# and an action for checking that all of the source files
# going into a shared library are, in fact, shared.
def StaticObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = None
return (target, source)
def SharedObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = 1
return (target, source)
def SharedFlagChecker(source, target, env):
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
if same == '0' or same == '' or same == 'False':
for src in source:
try:
shared = src.attributes.shared
except AttributeError:
shared = None
if not shared:
raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
# Scanners and suffixes for common languages.
ObjSourceScan = SCons.Scanner.Scanner({})
CScan = SCons.Scanner.C.CScan()
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
".h", ".H", ".hxx", ".hpp", ".hh",
".F", ".fpp", ".FPP",
".S", ".spp", ".SPP"]
for suffix in CSuffixes:
ObjSourceScan.add_scanner(suffix, CScan)
DScan = SCons.Scanner.D.DScan()
DSuffixes = ['.d']
for suffix in DSuffixes:
ObjSourceScan.add_scanner(suffix, DScan)
IDLSuffixes = [".idl", ".IDL"]
# cleanup
del suffix
# Actions for common languages.
CAction = SCons.Action.Action("$CCCOM")
DAction = SCons.Action.Action("$DCOM")
ShCAction = SCons.Action.Action("$SHCCCOM")
CXXAction = SCons.Action.Action("$CXXCOM")
ShCXXAction = SCons.Action.Action("$SHCXXCOM")
ASAction = SCons.Action.Action("$ASCOM")
ASPPAction = SCons.Action.Action("$ASPPCOM")
LinkAction = SCons.Action.Action("$LINKCOM")
ShLinkAction = SCons.Action.Action("$SHLINKCOM")
ArAction = SCons.Action.Action("$ARCOM")
LexAction = SCons.Action.Action("$LEXCOM")
YaccAction = SCons.Action.Action("$YACCCOM")
ProgScan = SCons.Scanner.Prog.ProgScan()
def DVI():
"""Common function to generate a DVI file Builder."""
return SCons.Builder.Builder(action = {},
# The suffix is not configurable via a
# construction variable like $DVISUFFIX
# because the output file name is
# hard-coded within TeX.
suffix = '.dvi')
def PDF():
"""A function for generating the PDF Builder."""
return SCons.Builder.Builder(action = { },
prefix = '$PDFPREFIX',
suffix = '$PDFSUFFIX')
# Common tasks that we allow users to perform in platform-independent
# ways by creating ActionFactory instances.
ActionFactory = SCons.Action.ActionFactory
Chmod = ActionFactory(os.chmod,
lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
def Copy(dest, src):
def _copy_func(target, source, env, dest=dest, src=src):
dest = str(env.arg2nodes(dest, env.fs.Entry)[0])
src = str(env.arg2nodes(src, env.fs.Entry)[0])
shutil.copytree(src, dest, 1)
def _copy_str(target, source, env, dest=dest, src=src):
dest = str(env.arg2nodes(dest, env.fs.Entry)[0])
src = str(env.arg2nodes(src, env.fs.Entry)[0])
return 'Copy("%s", "%s")' % (dest, src)
return SCons.Action.Action(_copy_func, strfunction=_copy_str)
def copy_func(dest, src):
if os.path.isfile(src):
return shutil.copy(src, dest)
else:
return shutil.copytree(src, dest, 1)
Copy = ActionFactory(copy_func,
lambda dest, src: 'Copy("%s", "%s")' % (dest, src))
def delete_func(entry, must_exist=0):
if not must_exist and not os.path.exists(entry):
return None
if os.path.isfile(entry):
return os.unlink(entry)
else:
return shutil.rmtree(entry, 1)
def delete_strfunc(entry, must_exist=0):
return 'Delete("%s")' % entry
Delete = ActionFactory(delete_func, delete_strfunc)
Mkdir = ActionFactory(os.makedirs,
lambda dir: 'Mkdir("%s")' % dir)
Move = ActionFactory(lambda dest, src: os.rename(src, dest),
lambda dest, src: 'Move("%s", "%s")' % (dest, src))
def touch_func(file):
mtime = int(time.time())
if os.path.exists(file):
atime = os.path.getatime(file)
else:
open(file, 'w')
atime = mtime
return os.utime(file, (atime, mtime))
Touch = ActionFactory(touch_func,
lambda file: 'Touch("%s")' % file)
# Internal utility functions
def copyFunc(dest, source, env):
"""Install a source file into a destination by copying it (and its
permission/mode bits)."""
shutil.copy2(source, dest)
st = os.stat(source)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
def _concat(prefix, list, suffix, env, f=lambda x: x):
"""Creates a new list from 'list' by first interpolating each
element in the list using the 'env' dictionary and then calling f
on the list, and finally concatenating 'prefix' and 'suffix' onto
each element of the list. A trailing space on 'prefix' or leading
space on 'suffix' will cause them to be put into separate list
elements rather than being concatenated."""
if not list:
return list
list = f(env.subst_path(list))
ret = []
# ensure that prefix and suffix are strings
prefix = str(env.subst(prefix, SCons.Util.SUBST_RAW))
suffix = str(env.subst(suffix, SCons.Util.SUBST_RAW))
for x in list:
x = str(x)
if x:
if prefix:
if prefix[-1] == ' ':
ret.append(prefix[:-1])
elif x[:len(prefix)] != prefix:
x = prefix + x
ret.append(x)
if suffix:
if suffix[0] == ' ':
ret.append(suffix[1:])
elif x[-len(suffix):] != suffix:
ret[-1] = ret[-1]+suffix
return ret
def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
"""This is a wrapper around _concat() that checks for the existence
of prefixes or suffixes on list elements and strips them where it
finds them. This is used by tools (like the GNU linker) that need
to turn something like 'libfoo.a' into '-lfoo'."""
if not callable(c):
if callable(env["_concat"]):
c = env["_concat"]
else:
c = _concat
def f(list, sp=stripprefix, ss=stripsuffix):
ret = []
for l in list:
if not SCons.Util.is_String(l):
l = str(l)
if l[:len(sp)] == sp:
l = l[len(sp):]
if l[-len(ss):] == ss:
l = l[:-len(ss)]
ret.append(l)
return ret
return c(prefix, list, suffix, env, f)
def _defines(prefix, defs, suffix, env, c=_concat):
"""A wrapper around _concat that turns a list or string
into a list of C preprocessor command-line definitions.
"""
if SCons.Util.is_List(defs):
l = []
for d in defs:
if SCons.Util.is_List(d) or type(d) is types.TupleType:
l.append(str(d[0]) + '=' + str(d[1]))
else:
l.append(str(d))
elif SCons.Util.is_Dict(defs):
# The items in a dictionary are stored in random order, but
# if the order of the command-line options changes from
# invocation to invocation, then the signature of the command
# line will change and we'll get random unnecessary rebuilds.
# Consequently, we have to sort the keys to ensure a
# consistent order...
l = []
keys = defs.keys()
keys.sort()
for k in keys:
v = defs[k]
if v is None:
l.append(str(k))
else:
l.append(str(k) + '=' + str(v))
else:
l = [str(defs)]
return c(prefix, l, suffix, env)
class NullCmdGenerator:
"""This is a callable class that can be used in place of other
command generators if you don't want them to do anything.
The __call__ method for this class simply returns the thing
you instantiated it with.
Example usage:
env["DO_NOTHING"] = NullCmdGenerator
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
"""
def __init__(self, cmd):
self.cmd = cmd
def __call__(self, target, source, env, for_signature=None):
return self.cmd
ConstructionEnvironment = {
'BUILDERS' : {},
'SCANNERS' : [],
'CPPSUFFIXES': CSuffixes,
'DSUFFIXES' : DSuffixes,
'IDLSUFFIXES': IDLSuffixes,
'PDFPREFIX' : '',
'PDFSUFFIX' : '.pdf',
'PSPREFIX' : '',
'PSSUFFIX' : '.ps',
'ENV' : {},
'INSTALL' : copyFunc,
'_concat' : _concat,
'_defines' : _defines,
'_stripixes' : _stripixes,
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs)} $)',
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs)} $)',
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
'TEMPFILE' : NullCmdGenerator
}

File diff suppressed because it is too large Load diff

View file

@ -1,175 +0,0 @@
"""SCons.Executor
A module for executing actions with specific lists of target and source
Nodes.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Executor.py 0.96.1.D001 2004/08/23 09:55:29 knight"
from SCons.Debug import logInstanceCreation
import SCons.Util
class Executor:
"""A class for controlling instances of executing an action.
This largely exists to hold a single association of an action,
environment, list of environment override dictionaries, targets
and sources for later processing as needed.
"""
def __init__(self, action, env=None, overridelist=[], targets=[], sources=[]):
if __debug__: logInstanceCreation(self)
self.action = action
self.env = env
self.overridelist = overridelist
self.targets = targets
self.sources = sources[:]
def get_build_env(self):
"""Fetch or create the appropriate build Environment
for this Executor.
"""
try:
return self.build_env
except AttributeError:
# Create the build environment instance with appropriate
# overrides. These get evaluated against the current
# environment's construction variables so that users can
# add to existing values by referencing the variable in
# the expansion.
overrides = {}
for odict in self.overridelist:
overrides.update(odict)
try:
generate_build_dict = self.targets[0].generate_build_dict
except (AttributeError, IndexError):
pass
else:
overrides.update(generate_build_dict())
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
self.build_env = env.Override(overrides)
# Now update the build environment with the things that we
# don't want expanded against the current construction
# variables.
self.build_env._update(SCons.Util.subst_dict(self.targets,
self.sources))
return self.build_env
def get_action_list(self, target):
"""Fetch or create the appropriate action list (for this target).
There is an architectural mistake here: we cache the action list
for the Executor and re-use it regardless of which target is
being asked for. In practice, this doesn't seem to be a problem
because executing the action list will update all of the targets
involved, so only one target's pre- and post-actions will win,
anyway. This is probably a bug we should fix...
"""
try:
al = self.action_list
except AttributeError:
al = self.action.get_actions()
self.action_list = al
try:
# XXX shouldn't reach into node attributes like this
return target.pre_actions + al + target.post_actions
except AttributeError:
return al
def __call__(self, target, errfunc, **kw):
"""Actually execute the action list."""
action_list = self.get_action_list(target)
if not action_list:
return
env = self.get_build_env()
for action in action_list:
apply(action, (self.targets, self.sources, env, errfunc), kw)
def cleanup(self):
try:
del self.build_env
except AttributeError:
pass
def add_sources(self, sources):
"""Add source files to this Executor's list. This is necessary
for "multi" Builders that can be called repeatedly to build up
a source file list for a given target."""
slist = filter(lambda x, s=self.sources: x not in s, sources)
self.sources.extend(slist)
def __str__(self):
try:
return self.string
except AttributeError:
action = self.action
self.string = action.genstring(self.targets,
self.sources,
self.get_build_env())
return self.string
def get_raw_contents(self):
"""Fetch the raw signature contents. This, along with
get_contents(), is the real reason this class exists, so we can
compute this once and cache it regardless of how many target or
source Nodes there are.
"""
try:
return self.raw_contents
except AttributeError:
action = self.action
self.raw_contents = action.get_raw_contents(self.targets,
self.sources,
self.get_build_env())
return self.raw_contents
def get_contents(self):
"""Fetch the signature contents. This, along with
get_raw_contents(), is the real reason this class exists, so we
can compute this once and cache it regardless of how many target
or source Nodes there are.
"""
try:
return self.contents
except AttributeError:
action = self.action
self.contents = action.get_contents(self.targets,
self.sources,
self.get_build_env())
return self.contents
def get_timestamp(self):
"""Fetch a time stamp for this Executor. We don't have one, of
course (only files do), but this is the interface used by the
timestamp module.
"""
return 0

File diff suppressed because it is too large Load diff

View file

@ -1,85 +0,0 @@
"""engine.SCons.Options.PathOption
This file defines an option type for SCons implementing 'package
activation'.
To be used whenever a 'package' may be enabled/disabled and the
package path may be specified.
Usage example:
Examples:
x11=no (disables X11 support)
x11=yes (will search for the package installation dir)
x11=/usr/local/X11 (will check this path for existance)
To replace autoconf's --with-xxx=yyy
opts = Options()
opts = Options()
opts.Add(PathOption('qtdir',
'where the root of Qt is installed',
qtdir))
opts.Add(PathOption('qt_includes',
'where the Qt includes are installed',
'$qtdir/includes'))
opts.Add(PathOption('qt_libraries',
'where the Qt library is installed',
'$qtdir/lib'))
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PathOption.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__all__ = ('PathOption',)
import os
import SCons.Errors
def _validator(key, val, env):
"""
"""
# todo: write validator, check for path
if not os.path.exists(val):
raise SCons.Errors.UserError(
'Path does not exist for option %s: %s' % (key, val))
def PathOption(key, help, default):
# NB: searchfunc is currenty undocumented and unsupported
"""
The input parameters describe a 'path list' option, thus they
are returned with the correct converter and validator appended. The
result is usable for input to opts.Add() .
A 'package list' option may either be 'all', 'none' or a list of
package names (seperated by space).
"""
return (key, '%s ( /path/to/%s )' % (help, key), default,
_validator, None)

View file

@ -1,126 +0,0 @@
"""SCons.Platform
SCons platform selection.
This looks for modules that define a callable object that can modify a
construction environment as appropriate for a given platform.
Note that we take a more simplistic view of "platform" than Python does.
We're looking for a single string that determines a set of
tool-independent variables with which to initialize a construction
environment. Consequently, we'll examine both sys.platform and os.name
(and anything else that might come in to play) in order to return some
specification which is unique enough for our purposes.
Note that because this subsysem just *selects* a callable that can
modify a construction environment, it's possible for people to define
their own "platform specification" in an arbitrary callable function.
No one needs to use or tie in to this subsystem in order to roll
their own platform definition.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import imp
import os
import string
import sys
import SCons.Errors
import SCons.Tool
def platform_default():
"""Return the platform string for our execution environment.
The returned value should map to one of the SCons/Platform/*.py
files. Since we're architecture independent, though, we don't
care about the machine architecture.
"""
osname = os.name
if osname == 'java':
osname = os._osType
if osname == 'posix':
if sys.platform == 'cygwin':
return 'cygwin'
elif string.find(sys.platform, 'irix') != -1:
return 'irix'
elif string.find(sys.platform, 'sunos') != -1:
return 'sunos'
elif string.find(sys.platform, 'hp-ux') != -1:
return 'hpux'
elif string.find(sys.platform, 'aix') != -1:
return 'aix'
elif string.find(sys.platform, 'darwin') != -1:
return 'darwin'
else:
return 'posix'
elif os.name == 'os2':
return 'os2'
else:
return sys.platform
def platform_module(name = platform_default()):
"""Return the imported module for the platform.
This looks for a module name that matches the specified argument.
If the name is unspecified, we fetch the appropriate default for
our execution environment.
"""
full_name = 'SCons.Platform.' + name
if not sys.modules.has_key(full_name):
if os.name == 'java':
eval(full_name)
else:
try:
file, path, desc = imp.find_module(name,
sys.modules['SCons.Platform'].__path__)
mod = imp.load_module(full_name, file, path, desc)
setattr(SCons.Platform, name, mod)
except ImportError:
raise SCons.Errors.UserError, "No platform named '%s'" % name
if file:
file.close()
return sys.modules[full_name]
def DefaultToolList(platform, env):
"""Select a default tool list for the specified platform.
"""
return SCons.Tool.tool_list(platform, env)
class PlatformSpec:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def Platform(name = platform_default()):
"""Select a canned Platform specification.
"""
module = platform_module(name)
spec = PlatformSpec(name)
spec.__call__ = module.generate
return spec

View file

@ -1,452 +0,0 @@
"""SCons.Taskmaster
Generic Taskmaster.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Taskmaster.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import string
import sys
import traceback
import SCons.Node
import SCons.Errors
class Task:
"""Default SCons build engine task.
This controls the interaction of the actual building of node
and the rest of the engine.
This is expected to handle all of the normally-customizable
aspects of controlling a build, so any given application
*should* be able to do what it wants by sub-classing this
class and overriding methods as appropriate. If an application
needs to customze something by sub-classing Taskmaster (or
some other build engine class), we should first try to migrate
that functionality into this class.
Note that it's generally a good idea for sub-classes to call
these methods explicitly to update state, etc., rather than
roll their own interaction with Taskmaster from scratch."""
def __init__(self, tm, targets, top, node):
self.tm = tm
self.targets = targets
self.top = top
self.node = node
def display(self, message):
"""Allow the calling interface to display a message
"""
pass
def prepare(self):
"""Called just before the task is executed.
This unlinks all targets and makes all directories before
building anything."""
# Now that it's the appropriate time, give the TaskMaster a
# chance to raise any exceptions it encountered while preparing
# this task.
self.tm.exception_raise()
if self.tm.message:
self.display(self.tm.message)
self.tm.message = None
for t in self.targets:
t.prepare()
for s in t.side_effects:
s.prepare()
def execute(self):
"""Called to execute the task.
This method is called from multiple threads in a parallel build,
so only do thread safe stuff here. Do thread unsafe stuff in
prepare(), executed() or failed()."""
try:
everything_was_cached = 1
for t in self.targets:
if not t.retrieve_from_cache():
everything_was_cached = 0
break
if not everything_was_cached:
self.targets[0].build()
except KeyboardInterrupt:
raise
except SystemExit:
exc_value = sys.exc_info()[1]
raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code)
except SCons.Errors.UserError:
raise
except SCons.Errors.BuildError:
raise
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
raise SCons.Errors.BuildError(self.targets[0],
"Exception",
exc_type,
exc_value,
exc_traceback)
def get_target(self):
"""Fetch the target being built or updated by this task.
"""
return self.node
def executed(self):
"""Called when the task has been successfully executed.
This may have been a do-nothing operation (to preserve
build order), so check the node's state before updating
things. Most importantly, this calls back to the
Taskmaster to put any node tasks waiting on this one
back on the pending list."""
if self.targets[0].get_state() == SCons.Node.executing:
for t in self.targets:
for side_effect in t.side_effects:
side_effect.set_state(None)
t.set_state(SCons.Node.executed)
t.built()
else:
for t in self.targets:
t.visited()
self.tm.executed(self.node)
def failed(self):
"""Default action when a task fails: stop the build."""
self.fail_stop()
def fail_stop(self):
"""Explicit stop-the-build failure."""
for t in self.targets:
t.set_state(SCons.Node.failed)
self.tm.failed(self.node)
self.tm.stop()
def fail_continue(self):
"""Explicit continue-the-build failure.
This sets failure status on the target nodes and all of
their dependent parent nodes.
"""
for t in self.targets:
# Set failure state on all of the parents that were dependent
# on this failed build.
def set_state(node): node.set_state(SCons.Node.failed)
t.call_for_all_waiting_parents(set_state)
self.tm.executed(self.node)
def mark_targets(self, state):
for t in self.targets:
t.set_state(state)
def mark_targets_and_side_effects(self, state):
for t in self.targets:
for side_effect in t.side_effects:
side_effect.set_state(state)
t.set_state(state)
def make_ready_all(self):
"""Mark all targets in a task ready for execution.
This is used when the interface needs every target Node to be
visited--the canonical example being the "scons -c" option.
"""
self.out_of_date = self.targets[:]
self.mark_targets_and_side_effects(SCons.Node.executing)
def make_ready_current(self):
"""Mark all targets in a task ready for execution if any target
is not current.
This is the default behavior for building only what's necessary.
"""
self.out_of_date = []
for t in self.targets:
if not t.current():
self.out_of_date.append(t)
if self.out_of_date:
self.mark_targets_and_side_effects(SCons.Node.executing)
else:
self.mark_targets(SCons.Node.up_to_date)
make_ready = make_ready_current
def postprocess(self):
"""Post process a task after it's been executed."""
for t in self.targets:
t.postprocess()
def exc_info(self):
return self.tm.exception
def exc_clear(self):
self.tm.exception_clear()
def exception_set(self):
self.tm.exception_set()
def order(dependencies):
"""Re-order a list of dependencies (if we need to)."""
return dependencies
class Taskmaster:
"""A generic Taskmaster for handling a bunch of targets.
Classes that override methods of this class should call
the base class method, so this class can do its thing.
"""
def __init__(self, targets=[], tasker=Task, order=order):
self.targets = targets # top level targets
self.candidates = targets[:] # nodes that might be ready to be executed
self.candidates.reverse()
self.executing = [] # nodes that are currently executing
self.pending = [] # nodes that depend on a currently executing node
self.tasker = tasker
self.ready = None # the next task that is ready to be executed
self.order = order
self.exception_clear()
self.message = None
def _find_next_ready_node(self):
"""Find the next node that is ready to be built"""
if self.ready:
return
while self.candidates:
node = self.candidates[-1]
state = node.get_state()
# Skip this node if it has already been executed:
if state != None and state != SCons.Node.stack:
self.candidates.pop()
continue
# Mark this node as being on the execution stack:
node.set_state(SCons.Node.stack)
try:
children = node.children()
except SystemExit:
exc_value = sys.exc_info()[1]
e = SCons.Errors.ExplicitExit(node, exc_value.code)
self.exception_set((SCons.Errors.ExplicitExit, e))
self.candidates.pop()
self.ready = node
break
except KeyboardInterrupt:
raise
except:
# We had a problem just trying to figure out the
# children (like a child couldn't be linked in to a
# BuildDir, or a Scanner threw something). Arrange to
# raise the exception when the Task is "executed."
self.exception_set()
self.candidates.pop()
self.ready = node
break
# Detect dependency cycles:
def in_stack(node): return node.get_state() == SCons.Node.stack
cycle = filter(in_stack, children)
if cycle:
nodes = filter(in_stack, self.candidates) + cycle
nodes.reverse()
desc = "Dependency cycle: " + string.join(map(str, nodes), " -> ")
raise SCons.Errors.UserError, desc
# Find all of the derived dependencies (that is,
# children who have builders or are side effects):
try:
def derived_nodes(node): return node.is_derived() or node.is_pseudo_derived()
derived = filter(derived_nodes, children)
except KeyboardInterrupt:
raise
except:
# We had a problem just trying to figure out if any of
# the kids are derived (like a child couldn't be linked
# from a repository). Arrange to raise the exception
# when the Task is "executed."
self.exception_set()
self.candidates.pop()
self.ready = node
break
# If there aren't any children with builders and this
# was a top-level argument, then see if we can find any
# corresponding targets in linked build directories:
if not derived and node in self.targets:
alt, message = node.alter_targets()
if alt:
self.message = message
self.candidates.pop()
self.candidates.extend(alt)
continue
# Add derived files that have not been built
# to the candidates list:
def unbuilt_nodes(node): return node.get_state() == None
not_built = filter(unbuilt_nodes, derived)
if not_built:
# We're waiting on one more derived files that have not
# yet been built. Add this node to the waiting_parents
# list of each of those derived files.
def add_to_waiting_parents(child, parent=node):
child.add_to_waiting_parents(parent)
map(add_to_waiting_parents, not_built)
not_built.reverse()
self.candidates.extend(self.order(not_built))
continue
# Skip this node if it has side-effects that are
# currently being built:
cont = 0
for side_effect in node.side_effects:
if side_effect.get_state() == SCons.Node.executing:
self.pending.append(node)
node.set_state(SCons.Node.pending)
self.candidates.pop()
cont = 1
break
if cont: continue
# Skip this node if it is pending on a currently
# executing node:
if node.depends_on(self.executing) or node.depends_on(self.pending):
self.pending.append(node)
node.set_state(SCons.Node.pending)
self.candidates.pop()
continue
# The default when we've gotten through all of the checks above:
# this node is ready to be built.
self.candidates.pop()
self.ready = node
break
def next_task(self):
"""Return the next task to be executed."""
self._find_next_ready_node()
node = self.ready
if node is None:
return None
try:
tlist = node.builder.targets(node)
except AttributeError:
tlist = [node]
self.executing.extend(tlist)
self.executing.extend(node.side_effects)
task = self.tasker(self, tlist, node in self.targets, node)
try:
task.make_ready()
except KeyboardInterrupt:
raise
except:
# We had a problem just trying to get this task ready (like
# a child couldn't be linked in to a BuildDir when deciding
# whether this node is current). Arrange to raise the
# exception when the Task is "executed."
self.exception_set()
self.ready = None
return task
def is_blocked(self):
self._find_next_ready_node()
return not self.ready and (self.pending or self.executing)
def stop(self):
"""Stop the current build completely."""
self.candidates = []
self.ready = None
self.pending = []
def failed(self, node):
try:
tlist = node.builder.targets(node)
except AttributeError:
tlist = [node]
for t in tlist:
self.executing.remove(t)
for side_effect in node.side_effects:
self.executing.remove(side_effect)
def executed(self, node):
try:
tlist = node.builder.targets(node)
except AttributeError:
tlist = [node]
for t in tlist:
self.executing.remove(t)
for side_effect in node.side_effects:
self.executing.remove(side_effect)
# move the current pending nodes to the candidates list:
# (they may not all be ready to build, but _find_next_ready_node()
# will figure out which ones are really ready)
for node in self.pending:
node.set_state(None)
self.pending.reverse()
self.candidates.extend(self.pending)
self.pending = []
def exception_set(self, exception=None):
if exception is None:
exception = sys.exc_info()
self.exception = exception
self.exception_raise = self._exception_raise
def exception_clear(self):
self.exception = (None, None, None)
self.exception_raise = self._no_exception_to_raise
def _no_exception_to_raise(self):
pass
def _exception_raise(self):
"""Raise a pending exception that was recorded while
getting a Task ready for execution."""
exc_type, exc_value = self.exception[:2]
raise exc_type, exc_value

View file

@ -1,138 +0,0 @@
"""engine.SCons.Tool.icl
Tool-specific initialization for the Intel C/C++ compiler.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/icl.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import os.path
import SCons.Tool.msvc
import SCons.Util
import SCons.Warnings
# Find Intel compiler:
# Could enumerate subkeys here to be more flexible.
def get_intel_compiler_top(version):
"""
Return the main path to the top-level dir of the Intel compiler,
using the given version or latest if 0.
The compiler will be in <top>/Bin/icl.exe,
the include dir is <top>/Include, etc.
"""
if version == 0:
version = "7.0" # XXX: should scan for latest
if not SCons.Util.can_read_reg:
raise SCons.Errors.InternalError, "No Windows registry module was found"
K = ('Software\\Intel\\' +
'Intel(R) C/C++ Compiler for 32-bit apps, Version ' + version)
# Note: v5 had slightly different key:
# HKCU\Software\Intel\Intel C/C++ Compiler for 32-bit apps, Version 5.0
# Note no (R).
try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_CURRENT_USER, K)
except SCons.Util.RegError:
return None
try:
# On my machine, this returns:
# c:\Program Files\Intel\Compiler70
top = SCons.Util.RegQueryValueEx(k, "Directory")[0]
except SCons.Util.RegError:
raise SCons.Errors.InternalError, "%s was not found in the registry."%K
if os.path.exists(os.path.join(top, "ia32")):
top = os.path.join(top, "ia32")
if not os.path.exists(os.path.join(top, "Bin", "icl.exe")):
raise SCons.Errors.InternalError, "Can't find Intel compiler in %s"%top
return top
def generate(env):
"""Add Builders and construction variables for icl to an Environment."""
SCons.Tool.msvc.generate(env)
try:
icltop = get_intel_compiler_top(0)
except (SCons.Util.RegError, SCons.Errors.InternalError):
icltop = None
if icltop:
env.PrependENVPath('INCLUDE', os.path.join(icltop, 'Include'))
env.PrependENVPath('LIB', os.path.join(icltop, 'Lib'))
env.PrependENVPath('PATH', os.path.join(icltop, 'Bin'))
env['CC'] = 'icl'
env['CXX'] = 'icl'
env['LINK'] = 'xilink'
# Look for license file dir.
envlicdir = os.environ.get("INTEL_LICENSE_FILE", '')
K = ('SOFTWARE\Intel\Licenses')
try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
reglicdir = SCons.Util.RegQueryValueEx(k, "w_cpp")[0]
except (AttributeError, SCons.Util.RegError):
reglicdir = ""
defaultlicdir = r'C:\Program Files\Common Files\Intel\Licenses'
licdir = None
for ld in [envlicdir, reglicdir]:
if ld and os.path.exists(ld):
licdir = ld
break
if not licdir:
licdir = defaultlicdir
if not os.path.exists(licdir):
class ICLLicenseDirWarning(SCons.Warnings.Warning):
pass
SCons.Warnings.enableWarningClass(ICLLicenseDirWarning)
SCons.Warnings.warn(ICLLicenseDirWarning,
"Intel license dir was not found."
" Tried using the INTEL_LICENSE_FILE environment variable (%s), the registry (%s) and the default path (%s)."
" Using the default path as a last resort."
% (envlicdir, reglicdir, defaultlicdir))
env['ENV']['INTEL_LICENSE_FILE'] = licdir
def exists(env):
try:
top = get_intel_compiler_top(0)
except (SCons.Util.RegError, SCons.Errors.InternalError):
top = None
if not top:
return env.Detect('icl')
return top is not None

File diff suppressed because it is too large Load diff

View file

@ -1,118 +0,0 @@
"""SCons.Tool.tex
Tool-specific initialization for TeX.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/tex.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import os.path
import re
import string
import SCons.Action
import SCons.Defaults
import SCons.Node
import SCons.Node.FS
import SCons.Util
# Define an action to build a generic tex file. This is sufficient for all
# tex files.
TeXAction = SCons.Action.CommandAction("$TEXCOM")
# Define an action to build a latex file. This action might be needed more
# than once if we are dealing with labels and bibtex
LaTeXAction = SCons.Action.CommandAction("$LATEXCOM")
# Define an action to run BibTeX on a file.
BibTeXAction = SCons.Action.CommandAction("$BIBTEXCOM")
def LaTeXAuxAction(target = None, source= None, env=None):
"""A builder for LaTeX files that checks the output in the aux file
and decides how many times to use LaTeXAction, and BibTeXAction."""
# Get the base name of the target
basename, ext = os.path.splitext(str(target[0]))
# Run LaTeX once to generate a new aux file.
LaTeXAction(target,source,env)
# Now if bibtex will need to be run.
content = open(basename + ".aux","rb").read()
if string.find(content, "bibdata") != -1:
bibfile = env.fs.File(basename)
BibTeXAction(None,bibfile,env)
# Now check if latex needs to be run yet again.
for trial in range(3):
content = open(basename + ".log","rb").read()
if not re.search("^LaTeX Warning:.*Rerun",content,re.MULTILINE):
break
LaTeXAction(target,source,env)
return 0
def TeXLaTeXAction(target = None, source= None, env=None):
"""A builder for TeX and LaTeX that scans the source file to
decide the "flavor" of the source and then executes the appropriate
program."""
LaTeXFile = None
for src in source:
content = src.get_contents()
if re.search("\\\\document(style|class)",content):
LaTeXFile = 1
break
if LaTeXFile:
LaTeXAuxAction(target,source,env)
else:
TeXAction(target,source,env)
return 0
def generate(env):
"""Add Builders and construction variables for TeX to an Environment."""
try:
bld = env['BUILDERS']['DVI']
except KeyError:
bld = SCons.Defaults.DVI()
env['BUILDERS']['DVI'] = bld
bld.add_action('.tex', TeXLaTeXAction)
env['TEX'] = 'tex'
env['TEXFLAGS'] = SCons.Util.CLVar('')
env['TEXCOM'] = '$TEX $TEXFLAGS $SOURCES'
# Duplicate from latex.py. If latex.py goes away, then this is still OK.
env['LATEX'] = 'latex'
env['LATEXFLAGS'] = SCons.Util.CLVar('')
env['LATEXCOM'] = '$LATEX $LATEXFLAGS $SOURCES'
env['BIBTEX'] = 'bibtex'
env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
env['BIBTEXCOM'] = '$BIBTEX $BIBTEXFLAGS $SOURCES'
def exists(env):
return env.Detect('tex')

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,830 @@
"""SCons.Action
This encapsulates information about executing any sort of action that
can build one or more target Nodes (typically files) from one or more
source Nodes (also typically files) given a specific Environment.
The base class here is ActionBase. The base class supplies just a few
OO utility methods and some generic methods for displaying information
about an Action in response to the various commands that control printing.
A second-level base class is _ActionAction. This extends ActionBase
by providing the methods that can be used to show and perform an
action. True Action objects will subclass _ActionAction; Action
factory class objects will subclass ActionBase.
The heavy lifting is handled by subclasses for the different types of
actions we might execute:
CommandAction
CommandGeneratorAction
FunctionAction
ListAction
The subclasses supply the following public interface methods used by
other modules:
__call__()
THE public interface, "calling" an Action object executes the
command or Python function. This also takes care of printing
a pre-substitution command for debugging purposes.
get_contents()
Fetches the "contents" of an Action for signature calculation.
This is what the Sig/*.py subsystem uses to decide if a target
needs to be rebuilt because its action changed.
genstring()
Returns a string representation of the Action *without*
command substitution, but allows a CommandGeneratorAction to
generate the right action based on the specified target,
source and env. This is used by the Signature subsystem
(through the Executor) to obtain an (imprecise) representation
of the Action operation for informative purposes.
Subclasses also supply the following methods for internal use within
this module:
__str__()
Returns a string approximation of the Action; no variable
substitution is performed.
execute()
The internal method that really, truly, actually handles the
execution of a command or Python function. This is used so
that the __call__() methods can take care of displaying any
pre-substitution representations, and *then* execute an action
without worrying about the specific Actions involved.
strfunction()
Returns a substituted string representation of the Action.
This is used by the _ActionAction.show() command to display the
command/function that will be executed to generate the target(s).
There is a related independent ActionCaller class that looks like a
regular Action, and which serves as a wrapper for arbitrary functions
that we want to let the user specify the arguments to now, but actually
execute later (when an out-of-date check determines that it's needed to
be executed, for example). Objects of this class are returned by an
ActionFactory class that provides a __call__() method as a convenient
way for wrapping up the functions.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Action.py 0.97.D001 2007/05/17 11:35:19 knight"
import dis
import os
import os.path
import string
import sys
from SCons.Debug import logInstanceCreation
import SCons.Errors
import SCons.Executor
import SCons.Util
class _Null:
pass
_null = _Null
print_actions = 1
execute_actions = 1
print_actions_presub = 0
default_ENV = None
def rfile(n):
try:
return n.rfile()
except AttributeError:
return n
def default_exitstatfunc(s):
return s
try:
SET_LINENO = dis.SET_LINENO
HAVE_ARGUMENT = dis.HAVE_ARGUMENT
except AttributeError:
remove_set_lineno_codes = lambda x: x
else:
def remove_set_lineno_codes(code):
result = []
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
if op >= HAVE_ARGUMENT:
if op != SET_LINENO:
result.append(code[i:i+3])
i = i+3
else:
result.append(c)
i = i+1
return string.join(result, '')
def _actionAppend(act1, act2):
# This function knows how to slap two actions together.
# Mainly, it handles ListActions by concatenating into
# a single ListAction.
a1 = Action(act1)
a2 = Action(act2)
if a1 is None or a2 is None:
raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
if isinstance(a1, ListAction):
if isinstance(a2, ListAction):
return ListAction(a1.list + a2.list)
else:
return ListAction(a1.list + [ a2 ])
else:
if isinstance(a2, ListAction):
return ListAction([ a1 ] + a2.list)
else:
return ListAction([ a1, a2 ])
def _do_create_action(act, *args, **kw):
"""This is the actual "implementation" for the
Action factory method, below. This handles the
fact that passing lists to Action() itself has
different semantics than passing lists as elements
of lists.
The former will create a ListAction, the latter
will create a CommandAction by converting the inner
list elements to strings."""
if isinstance(act, ActionBase):
return act
if SCons.Util.is_List(act):
return apply(CommandAction, (act,)+args, kw)
if callable(act):
try:
gen = kw['generator']
del kw['generator']
except KeyError:
gen = 0
if gen:
action_type = CommandGeneratorAction
else:
action_type = FunctionAction
return apply(action_type, (act,)+args, kw)
if SCons.Util.is_String(act):
var=SCons.Util.get_environment_var(act)
if var:
# This looks like a string that is purely an Environment
# variable reference, like "$FOO" or "${FOO}". We do
# something special here...we lazily evaluate the contents
# of that Environment variable, so a user could put something
# like a function or a CommandGenerator in that variable
# instead of a string.
return apply(LazyAction, (var,)+args, kw)
commands = string.split(str(act), '\n')
if len(commands) == 1:
return apply(CommandAction, (commands[0],)+args, kw)
else:
listCmdActions = map(lambda x, args=args, kw=kw:
apply(CommandAction, (x,)+args, kw),
commands)
return ListAction(listCmdActions)
return None
def Action(act, *args, **kw):
"""A factory for action objects."""
if SCons.Util.is_List(act):
acts = map(lambda a, args=args, kw=kw:
apply(_do_create_action, (a,)+args, kw),
act)
acts = filter(None, acts)
if len(acts) == 1:
return acts[0]
else:
return ListAction(acts)
else:
return apply(_do_create_action, (act,)+args, kw)
class ActionBase:
"""Base class for all types of action objects that can be held by
other objects (Builders, Executors, etc.) This provides the
common methods for manipulating and combining those actions."""
def __cmp__(self, other):
return cmp(self.__dict__, other)
def genstring(self, target, source, env):
return str(self)
def __add__(self, other):
return _actionAppend(self, other)
def __radd__(self, other):
return _actionAppend(other, self)
def presub_lines(self, env):
# CommandGeneratorAction needs a real environment
# in order to return the proper string here, since
# it may call LazyAction, which looks up a key
# in that env. So we temporarily remember the env here,
# and CommandGeneratorAction will use this env
# when it calls its _generate method.
self.presub_env = env
lines = string.split(str(self), '\n')
self.presub_env = None # don't need this any more
return lines
def get_executor(self, env, overrides, tlist, slist, executor_kw):
"""Return the Executor for this Action."""
return SCons.Executor.Executor(self, env, overrides,
tlist, slist, executor_kw)
class _ActionAction(ActionBase):
"""Base class for actions that create output objects."""
def __init__(self, strfunction=_null, presub=_null, chdir=None, exitstatfunc=None, **kw):
if not strfunction is _null:
self.strfunction = strfunction
self.presub = presub
self.chdir = chdir
if not exitstatfunc:
exitstatfunc = default_exitstatfunc
self.exitstatfunc = exitstatfunc
def print_cmd_line(self, s, target, source, env):
sys.stdout.write(s + "\n")
def __call__(self, target, source, env,
exitstatfunc=_null,
presub=_null,
show=_null,
execute=_null,
chdir=_null):
if not SCons.Util.is_List(target):
target = [target]
if not SCons.Util.is_List(source):
source = [source]
if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
if presub is _null:
presub = self.presub
if presub is _null:
presub = print_actions_presub
if show is _null: show = print_actions
if execute is _null: execute = execute_actions
if chdir is _null: chdir = self.chdir
save_cwd = None
if chdir:
save_cwd = os.getcwd()
try:
chdir = str(chdir.abspath)
except AttributeError:
if not SCons.Util.is_String(chdir):
chdir = str(target[0].dir)
if presub:
t = string.join(map(str, target), ' and ')
l = string.join(self.presub_lines(env), '\n ')
out = "Building %s with action:\n %s\n" % (t, l)
sys.stdout.write(out)
s = None
if show and self.strfunction:
s = self.strfunction(target, source, env)
if s:
if chdir:
s = ('os.chdir(%s)\n' % repr(chdir)) + s
try:
get = env.get
except AttributeError:
print_func = self.print_cmd_line
else:
print_func = get('PRINT_CMD_LINE_FUNC')
if not print_func:
print_func = self.print_cmd_line
print_func(s, target, source, env)
stat = 0
if execute:
if chdir:
os.chdir(chdir)
try:
stat = self.execute(target, source, env)
stat = exitstatfunc(stat)
finally:
if save_cwd:
os.chdir(save_cwd)
if s and save_cwd:
print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
return stat
def _string_from_cmd_list(cmd_list):
"""Takes a list of command line arguments and returns a pretty
representation for printing."""
cl = []
for arg in map(str, cmd_list):
if ' ' in arg or '\t' in arg:
arg = '"' + arg + '"'
cl.append(arg)
return string.join(cl)
class CommandAction(_ActionAction):
"""Class for command-execution actions."""
def __init__(self, cmd, cmdstr=None, *args, **kw):
# Cmd can actually be a list or a single item; if it's a
# single item it should be the command string to execute; if a
# list then it should be the words of the command string to
# execute. Only a single command should be executed by this
# object; lists of commands should be handled by embedding
# these objects in a ListAction object (which the Action()
# factory above does). cmd will be passed to
# Environment.subst_list() for substituting environment
# variables.
if __debug__: logInstanceCreation(self, 'Action.CommandAction')
if not cmdstr is None:
if callable(cmdstr):
args = (cmdstr,)+args
elif not SCons.Util.is_String(cmdstr):
raise SCons.Errors.UserError(\
'Invalid command display variable type. ' \
'You must either pass a string or a callback which ' \
'accepts (target, source, env) as parameters.')
apply(_ActionAction.__init__, (self,)+args, kw)
if SCons.Util.is_List(cmd):
if filter(SCons.Util.is_List, cmd):
raise TypeError, "CommandAction should be given only " \
"a single command"
self.cmd_list = cmd
self.cmdstr = cmdstr
def __str__(self):
if SCons.Util.is_List(self.cmd_list):
return string.join(map(str, self.cmd_list), ' ')
return str(self.cmd_list)
def process(self, target, source, env):
result = env.subst_list(self.cmd_list, 0, target, source)
silent = None
ignore = None
while 1:
try: c = result[0][0][0]
except IndexError: c = None
if c == '@': silent = 1
elif c == '-': ignore = 1
else: break
result[0][0] = result[0][0][1:]
try:
if not result[0][0]:
result[0] = result[0][1:]
except IndexError:
pass
return result, ignore, silent
def strfunction(self, target, source, env):
if not self.cmdstr is None:
from SCons.Subst import SUBST_RAW
c = env.subst(self.cmdstr, SUBST_RAW, target, source)
if c:
return c
cmd_list, ignore, silent = self.process(target, source, env)
if silent:
return ''
return _string_from_cmd_list(cmd_list[0])
def execute(self, target, source, env):
"""Execute a command action.
This will handle lists of commands as well as individual commands,
because construction variable substitution may turn a single
"command" into a list. This means that this class can actually
handle lists of commands, even though that's not how we use it
externally.
"""
from SCons.Subst import escape_list
import SCons.Util
flatten = SCons.Util.flatten
is_String = SCons.Util.is_String
is_List = SCons.Util.is_List
try:
shell = env['SHELL']
except KeyError:
raise SCons.Errors.UserError('Missing SHELL construction variable.')
try:
spawn = env['SPAWN']
except KeyError:
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
else:
if is_String(spawn):
spawn = env.subst(spawn, raw=1, conv=lambda x: x)
escape = env.get('ESCAPE', lambda x: x)
try:
ENV = env['ENV']
except KeyError:
global default_ENV
if not default_ENV:
import SCons.Environment
default_ENV = SCons.Environment.Environment()['ENV']
ENV = default_ENV
# Ensure that the ENV values are all strings:
for key, value in ENV.items():
if not is_String(value):
if is_List(value):
# If the value is a list, then we assume it is a
# path list, because that's a pretty common list-like
# value to stick in an environment variable:
value = flatten(value)
ENV[key] = string.join(map(str, value), os.pathsep)
else:
# If it isn't a string or a list, then we just coerce
# it to a string, which is the proper way to handle
# Dir and File instances and will produce something
# reasonable for just about everything else:
ENV[key] = str(value)
cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
# Use len() to filter out any "command" that's zero-length.
for cmd_line in filter(len, cmd_list):
# Escape the command line for the interpreter we are using.
cmd_line = escape_list(cmd_line, escape)
result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
if not ignore and result:
return result
return 0
def get_contents(self, target, source, env):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
since those parts don't affect signatures.
"""
from SCons.Subst import SUBST_SIG
cmd = self.cmd_list
if SCons.Util.is_List(cmd):
cmd = string.join(map(str, cmd))
else:
cmd = str(cmd)
return env.subst_target_source(cmd, SUBST_SIG, target, source)
class CommandGeneratorAction(ActionBase):
"""Class for command-generator actions."""
def __init__(self, generator, *args, **kw):
if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
self.generator = generator
self.gen_args = args
self.gen_kw = kw
def _generate(self, target, source, env, for_signature):
# ensure that target is a list, to make it easier to write
# generator functions:
if not SCons.Util.is_List(target):
target = [target]
ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
gen_cmd = apply(Action, (ret,)+self.gen_args, self.gen_kw)
if not gen_cmd:
raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
return gen_cmd
def __str__(self):
try:
env = self.presub_env or {}
except AttributeError:
env = {}
act = self._generate([], [], env, 1)
return str(act)
def genstring(self, target, source, env):
return self._generate(target, source, env, 1).genstring(target, source, env)
def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
show=_null, execute=_null, chdir=_null):
act = self._generate(target, source, env, 0)
return act(target, source, env, exitstatfunc, presub,
show, execute, chdir)
def get_contents(self, target, source, env):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
since those parts don't affect signatures.
"""
return self._generate(target, source, env, 1).get_contents(target, source, env)
# A LazyAction is a kind of hybrid generator and command action for
# strings of the form "$VAR". These strings normally expand to other
# strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
# want to be able to replace them with functions in the construction
# environment. Consequently, we want lazy evaluation and creation of
# an Action in the case of the function, but that's overkill in the more
# normal case of expansion to other strings.
#
# So we do this with a subclass that's both a generator *and*
# a command action. The overridden methods all do a quick check
# of the construction variable, and if it's a string we just call
# the corresponding CommandAction method to do the heavy lifting.
# If not, then we call the same-named CommandGeneratorAction method.
# The CommandGeneratorAction methods work by using the overridden
# _generate() method, that is, our own way of handling "generation" of
# an action based on what's in the construction variable.
class LazyAction(CommandGeneratorAction, CommandAction):
def __init__(self, var, *args, **kw):
if __debug__: logInstanceCreation(self, 'Action.LazyAction')
apply(CommandAction.__init__, (self, '$'+var)+args, kw)
self.var = SCons.Util.to_String(var)
self.gen_args = args
self.gen_kw = kw
def get_parent_class(self, env):
c = env.get(self.var)
if SCons.Util.is_String(c) and not '\n' in c:
return CommandAction
return CommandGeneratorAction
def _generate_cache(self, env):
c = env.get(self.var, '')
gen_cmd = apply(Action, (c,)+self.gen_args, self.gen_kw)
if not gen_cmd:
raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
return gen_cmd
def _generate(self, target, source, env, for_signature):
return self._generate_cache(env)
def __call__(self, target, source, env, *args, **kw):
args = (self, target, source, env) + args
c = self.get_parent_class(env)
return apply(c.__call__, args, kw)
def get_contents(self, target, source, env):
c = self.get_parent_class(env)
return c.get_contents(self, target, source, env)
class FunctionAction(_ActionAction):
"""Class for Python function actions."""
def __init__(self, execfunction, cmdstr=_null, *args, **kw):
if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
if not cmdstr is _null:
if callable(cmdstr):
args = (cmdstr,)+args
elif not (cmdstr is None or SCons.Util.is_String(cmdstr)):
raise SCons.Errors.UserError(\
'Invalid function display variable type. ' \
'You must either pass a string or a callback which ' \
'accepts (target, source, env) as parameters.')
self.execfunction = execfunction
apply(_ActionAction.__init__, (self,)+args, kw)
self.varlist = kw.get('varlist', [])
self.cmdstr = cmdstr
def function_name(self):
try:
return self.execfunction.__name__
except AttributeError:
try:
return self.execfunction.__class__.__name__
except AttributeError:
return "unknown_python_function"
def strfunction(self, target, source, env):
if self.cmdstr is None:
return None
if not self.cmdstr is _null:
from SCons.Subst import SUBST_RAW
c = env.subst(self.cmdstr, SUBST_RAW, target, source)
if c:
return c
def array(a):
def quote(s):
return '"' + str(s) + '"'
return '[' + string.join(map(quote, a), ", ") + ']'
try:
strfunc = self.execfunction.strfunction
except AttributeError:
pass
else:
if strfunc is None:
return None
if callable(strfunc):
return strfunc(target, source, env)
name = self.function_name()
tstr = array(target)
sstr = array(source)
return "%s(%s, %s)" % (name, tstr, sstr)
def __str__(self):
name = self.function_name()
if name == 'ActionCaller':
return str(self.execfunction)
return "%s(target, source, env)" % name
def execute(self, target, source, env):
rsources = map(rfile, source)
try:
result = self.execfunction(target=target, source=rsources, env=env)
except EnvironmentError, e:
# If an IOError/OSError happens, raise a BuildError.
# Report the name of the file or directory that caused the
# error, which might be different from the target being built
# (for example, failure to create the directory in which the
# target file will appear).
try: filename = e.filename
except AttributeError: filename = None
raise SCons.Errors.BuildError(node=target,
errstr=e.strerror,
filename=filename)
return result
def get_contents(self, target, source, env):
"""Return the signature contents of this callable action.
By providing direct access to the code object of the
function, Python makes this extremely easy. Hooray!
Unfortunately, older versions of Python include line
number indications in the compiled byte code. Boo!
So we remove the line number byte codes to prevent
recompilations from moving a Python function.
"""
execfunction = self.execfunction
try:
# Test if execfunction is a function.
code = execfunction.func_code.co_code
except AttributeError:
try:
# Test if execfunction is a method.
code = execfunction.im_func.func_code.co_code
except AttributeError:
try:
# Test if execfunction is a callable object.
code = execfunction.__call__.im_func.func_code.co_code
except AttributeError:
try:
# See if execfunction will do the heavy lifting for us.
gc = self.execfunction.get_contents
except AttributeError:
# This is weird, just do the best we can.
contents = str(self.execfunction)
else:
contents = gc(target, source, env)
else:
contents = str(code)
else:
contents = str(code)
else:
contents = str(code)
contents = remove_set_lineno_codes(contents)
return contents + env.subst(string.join(map(lambda v: '${'+v+'}',
self.varlist)))
class ListAction(ActionBase):
"""Class for lists of other actions."""
def __init__(self, list):
if __debug__: logInstanceCreation(self, 'Action.ListAction')
def list_of_actions(x):
if isinstance(x, ActionBase):
return x
return Action(x)
self.list = map(list_of_actions, list)
def genstring(self, target, source, env):
return string.join(map(lambda a, t=target, s=source, e=env:
a.genstring(t, s, e),
self.list),
'\n')
def __str__(self):
return string.join(map(str, self.list), '\n')
def presub_lines(self, env):
return SCons.Util.flatten(map(lambda a, env=env:
a.presub_lines(env),
self.list))
def get_contents(self, target, source, env):
"""Return the signature contents of this action list.
Simple concatenation of the signatures of the elements.
"""
return string.join(map(lambda x, t=target, s=source, e=env:
x.get_contents(t, s, e),
self.list),
"")
def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
show=_null, execute=_null, chdir=_null):
for act in self.list:
stat = act(target, source, env, exitstatfunc, presub,
show, execute, chdir)
if stat:
return stat
return 0
class ActionCaller:
"""A class for delaying calling an Action function with specific
(positional and keyword) arguments until the Action is actually
executed.
This class looks to the rest of the world like a normal Action object,
but what it's really doing is hanging on to the arguments until we
have a target, source and env to use for the expansion.
"""
def __init__(self, parent, args, kw):
self.parent = parent
self.args = args
self.kw = kw
def get_contents(self, target, source, env):
actfunc = self.parent.actfunc
try:
# "self.actfunc" is a function.
contents = str(actfunc.func_code.co_code)
except AttributeError:
# "self.actfunc" is a callable object.
try:
contents = str(actfunc.__call__.im_func.func_code.co_code)
except AttributeError:
# No __call__() method, so it might be a builtin
# or something like that. Do the best we can.
contents = str(actfunc)
contents = remove_set_lineno_codes(contents)
return contents
def subst(self, s, target, source, env):
# Special-case hack: Let a custom function wrapped in an
# ActionCaller get at the environment through which the action
# was called by using this hard-coded value as a special return.
if s == '$__env__':
return env
else:
return env.subst(s, 0, target, source)
def subst_args(self, target, source, env):
return map(lambda x, self=self, t=target, s=source, e=env:
self.subst(x, t, s, e),
self.args)
def subst_kw(self, target, source, env):
kw = {}
for key in self.kw.keys():
kw[key] = self.subst(self.kw[key], target, source, env)
return kw
def __call__(self, target, source, env):
args = self.subst_args(target, source, env)
kw = self.subst_kw(target, source, env)
return apply(self.parent.actfunc, args, kw)
def strfunction(self, target, source, env):
args = self.subst_args(target, source, env)
kw = self.subst_kw(target, source, env)
return apply(self.parent.strfunc, args, kw)
def __str__(self):
return apply(self.parent.strfunc, self.args, self.kw)
class ActionFactory:
"""A factory class that will wrap up an arbitrary function
as an SCons-executable Action object.
The real heavy lifting here is done by the ActionCaller class.
We just collect the (positional and keyword) arguments that we're
called with and give them to the ActionCaller object we create,
so it can hang onto them until it needs them.
"""
def __init__(self, actfunc, strfunc):
self.actfunc = actfunc
self.strfunc = strfunc
def __call__(self, *args, **kw):
ac = ActionCaller(self, args, kw)
action = Action(ac, strfunction=ac.strfunction)
return action

View file

@ -16,20 +16,9 @@ building new types of files in their configurations, without having to
dive any deeper into this subsystem.
The base class here is BuilderBase. This is a concrete base class which
does, in fact, represent most Builder objects that we (or users) create.
does, in fact, represent the Builder objects that we (or users) create.
There is (at present) one subclasses:
MultiStepBuilder
This is a Builder that knows how to "chain" Builders so that
users can specify a source file that requires multiple steps
to turn into a target file. A canonical example is building a
program from yacc input file, which requires invoking a builder
to turn the .y into a .c, the .c into a .o, and the .o into an
executable program.
There is also two proxies that look like Builders:
There is also a proxy that looks like a Builder:
CompositeBuilder
@ -39,11 +28,6 @@ There is also two proxies that look like Builders:
(compilers, compile options) for different flavors of source
files.
ListBuilder
This proxies for a Builder *invocation* where the target
is a list of files, not a single file.
Builders and their proxies have the following public interface methods
used by other modules:
@ -95,7 +79,7 @@ There are the following methods for internal use within this module:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -117,7 +101,9 @@ There are the following methods for internal use within this module:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Builder.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Builder.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.compat
import UserDict
import UserList
@ -126,6 +112,8 @@ import SCons.Action
from SCons.Debug import logInstanceCreation
from SCons.Errors import InternalError, UserError
import SCons.Executor
import SCons.Memoize
import SCons.Node
import SCons.Node.FS
import SCons.Util
import SCons.Warnings
@ -142,6 +130,10 @@ class DictCmdGenerator(SCons.Util.Selector):
to return the proper action based on the file suffix of
the source file."""
def __init__(self, dict=None, source_ext_match=1):
SCons.Util.Selector.__init__(self, dict)
self.source_ext_match = source_ext_match
def src_suffixes(self):
return self.keys()
@ -151,12 +143,18 @@ class DictCmdGenerator(SCons.Util.Selector):
self[suffix] = action
def __call__(self, target, source, env, for_signature):
if not source:
return []
if self.source_ext_match:
ext = None
for src in map(str, source):
my_ext = SCons.Util.splitext(src)[1]
if ext and my_ext != ext:
raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext))
ext = my_ext
else:
ext = SCons.Util.splitext(str(source[0]))[1]
if not ext:
raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
@ -166,7 +164,8 @@ class DictCmdGenerator(SCons.Util.Selector):
except KeyError, e:
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2]))
if ret is None:
raise UserError("While building `%s': Don't know how to build a file with suffix `%s'." % (repr(map(str, target)), ext))
raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \
(repr(map(str, target)), repr(map(str, source)), ext, repr(self.keys())))
return ret
class CallableSelector(SCons.Util.Selector):
@ -214,25 +213,22 @@ class OverrideWarner(UserDict.UserDict):
"""A class for warning about keyword arguments that we use as
overrides in a Builder call.
This class exists to handle the fact that a single MultiStepBuilder
call can actually invoke multiple builders as a result of a single
user-level Builder call. This class only emits the warnings once,
no matter how many Builders are invoked.
This class exists to handle the fact that a single Builder call
can actually invoke multiple builders. This class only emits the
warnings once, no matter how many Builders are invoked.
"""
def __init__(self, dict):
UserDict.UserDict.__init__(self, dict)
if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner')
self.already_warned = None
def warn(self):
if self.already_warned:
return
for k in self.keys():
try:
if misleading_keywords.has_key(k):
alt = misleading_keywords[k]
except KeyError:
pass
else:
SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning,
"Did you mean to use `%s' instead of `%s'?" % (alt, k))
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
self.already_warned = 1
def Builder(**kw):
@ -241,12 +237,18 @@ def Builder(**kw):
if kw.has_key('generator'):
if kw.has_key('action'):
raise UserError, "You must not specify both an action and a generator."
kw['action'] = SCons.Action.CommandGenerator(kw['generator'])
kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'])
del kw['generator']
elif kw.has_key('action') and SCons.Util.is_Dict(kw['action']):
composite = DictCmdGenerator(kw['action'])
kw['action'] = SCons.Action.CommandGenerator(composite)
elif kw.has_key('action'):
source_ext_match = kw.get('source_ext_match', 1)
if kw.has_key('source_ext_match'):
del kw['source_ext_match']
if SCons.Util.is_Dict(kw['action']):
composite = DictCmdGenerator(kw['action'], source_ext_match)
kw['action'] = SCons.Action.CommandGeneratorAction(composite)
kw['src_suffix'] = composite.src_suffixes()
else:
kw['action'] = SCons.Action.Action(kw['action'])
if kw.has_key('emitter'):
emitter = kw['emitter']
@ -264,100 +266,51 @@ def Builder(**kw):
elif SCons.Util.is_List(emitter):
kw['emitter'] = ListEmitter(emitter)
if kw.has_key('src_builder'):
ret = apply(MultiStepBuilder, (), kw)
else:
ret = apply(BuilderBase, (), kw)
result = apply(BuilderBase, (), kw)
if not composite is None:
ret = CompositeBuilder(ret, composite)
result = CompositeBuilder(result, composite)
return ret
return result
def _init_nodes(builder, env, overrides, tlist, slist):
"""Initialize lists of target and source nodes with all of
the proper Builder information.
def _node_errors(builder, env, tlist, slist):
"""Validate that the lists of target and source nodes are
legal for this builder and environment. Raise errors or
issue warnings as appropriate.
"""
# First, figure out if there are any errors in the way the targets
# were specified.
for t in tlist:
if t.side_effect:
raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
if t.has_builder():
raise UserError, "Multiple ways to build the same target were specified for: %s" % t
if t.has_explicit_builder():
if not t.env is None and not t.env is env:
t_contents = t.builder.action.get_contents(tlist, slist, t.env)
contents = t.builder.action.get_contents(tlist, slist, env)
action = t.builder.action
t_contents = action.get_contents(tlist, slist, t.env)
contents = action.get_contents(tlist, slist, env)
if t_contents == contents:
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning,
"Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s"%(str(t), t.builder.action.strfunction(tlist, slist, t.env)))
msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
else:
raise UserError, "Two environments with different actions were specified for the same target: %s"%str(t)
elif t.overrides != overrides:
raise UserError, "Two different sets of overrides were specified for the same target: %s"%str(t)
elif builder.target_scanner and t.target_scanner and builder.target_scanner != t.target_scanner:
raise UserError, "Two different scanners were specified for the same target: %s"%str(t)
msg = "Two environments with different actions were specified for the same target: %s" % t
raise UserError, msg
if builder.multi:
if t.builder != builder:
if isinstance(t.builder, ListBuilder) and isinstance(builder, ListBuilder) and t.builder.builder == builder.builder:
raise UserError, "Two different target sets have a target in common: %s"%str(t)
else:
raise UserError, "Two different builders (%s and %s) were specified for the same target: %s"%(t.builder.get_name(env), builder.get_name(env), str(t))
msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
raise UserError, msg
if t.get_executor().targets != tlist:
msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, map(str, t.get_executor().targets), map(str, tlist))
raise UserError, msg
elif t.sources != slist:
raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, map(str, t.sources), map(str, slist))
raise UserError, msg
if builder.single_source:
if len(slist) > 1:
raise UserError, "More than one source given for single-source builder: targets=%s sources=%s" % (map(str,tlist), map(str,slist))
# The targets are fine, so find or make the appropriate Executor to
# build this particular list of targets from this particular list of
# sources.
executor = None
if builder.multi:
try:
executor = tlist[0].get_executor(create = 0)
except AttributeError:
pass
else:
executor.add_sources(slist)
if executor is None:
executor = SCons.Executor.Executor(builder.action,
env or builder.env,
[builder.overrides, overrides],
tlist,
slist)
# Now set up the relevant information in the target Nodes themselves.
for t in tlist:
t.overrides = overrides
t.cwd = SCons.Node.FS.default_fs.getcwd()
t.builder_set(builder)
t.env_set(env)
t.add_source(slist)
t.set_executor(executor)
if builder.target_scanner:
t.target_scanner = builder.target_scanner
if t.source_scanner is None:
t.source_scanner = builder.source_scanner
# Add backup source scanners from the environment to the source
# nodes. This may not be necessary if the node will have a real
# source scanner added later (which is why these are the "backup"
# source scanners, not the real ones), but because source nodes may
# be used multiple times for different targets, it ends up being
# more efficient to do this calculation once here, as opposed to
# delaying it until later when we potentially have to calculate it
# over and over and over.
for s in slist:
if s.source_scanner is None and s.backup_source_scanner is None:
s.backup_source_scanner = env.get_scanner(s.scanner_key())
class EmitterProxy:
"""This is a callable class that can act as a
Builder emitter. It holds on to a string that
@ -393,28 +346,37 @@ class BuilderBase:
nodes (files) from input nodes (files).
"""
if SCons.Memoize.use_memoizer:
__metaclass__ = SCons.Memoize.Memoized_Metaclass
memoizer_counters = []
def __init__(self, action = None,
prefix = '',
suffix = '',
src_suffix = '',
target_factory = SCons.Node.FS.default_fs.File,
source_factory = SCons.Node.FS.default_fs.File,
target_factory = None,
source_factory = None,
target_scanner = None,
source_scanner = None,
emitter = None,
multi = 0,
env = None,
single_source = 0,
name = None,
chdir = _null,
is_explicit = 1,
src_builder = [],
**overrides):
if __debug__: logInstanceCreation(self, 'BuilderBase')
self.action = SCons.Action.Action(action)
if __debug__: logInstanceCreation(self, 'Builder.BuilderBase')
self._memo = {}
self.action = action
self.multi = multi
if SCons.Util.is_Dict(prefix):
prefix = CallableSelector(prefix)
self.prefix = prefix
if SCons.Util.is_Dict(suffix):
suffix = CallableSelector(suffix)
self.suffix = suffix
self.env = env
self.single_source = single_source
if overrides.has_key('overrides'):
@ -423,8 +385,14 @@ class BuilderBase:
"\tspecify the items as keyword arguments to the Builder() call instead.")
overrides.update(overrides['overrides'])
del overrides['overrides']
if overrides.has_key('scanner'):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The \"scanner\" keyword to Builder() creation has been deprecated;\n"
"\tuse: source_scanner or target_scanner as appropriate.")
del overrides['scanner']
self.overrides = overrides
self.set_suffix(suffix)
self.set_src_suffix(src_suffix)
self.target_factory = target_factory
@ -434,6 +402,19 @@ class BuilderBase:
self.emitter = emitter
# Optional Builder name should only be used for Builders
# that don't get attached to construction environments.
if name:
self.name = name
self.executor_kw = {}
if not chdir is _null:
self.executor_kw['chdir'] = chdir
self.is_explicit = is_explicit
if not SCons.Util.is_List(src_builder):
src_builder = [ src_builder ]
self.src_builder = src_builder
def __nonzero__(self):
raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead"
@ -442,21 +423,51 @@ class BuilderBase:
Look at the BUILDERS variable of env, expecting it to be a
dictionary containing this Builder, and return the key of the
dictionary."""
dictionary. If there's no key, then return a directly-configured
name (if there is one) or the name of the class (by default)."""
try:
index = env['BUILDERS'].values().index(self)
return env['BUILDERS'].keys()[index]
except (AttributeError, KeyError, ValueError):
except (AttributeError, KeyError, TypeError, ValueError):
try:
return self.name
except AttributeError:
return str(self.__class__)
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
def splitext(self, path):
def splitext(self, path, env=None):
if not env:
env = self.env
if env:
matchsuf = filter(lambda S,path=path: path[-len(S):] == S,
self.src_suffixes(env))
if matchsuf:
suf = max(map(None, map(len, matchsuf), matchsuf))[1]
return [path[:-len(suf)], path[-len(suf):]]
return SCons.Util.splitext(path)
def _create_nodes(self, env, overwarn, target = None, source = None):
def get_single_executor(self, env, tlist, slist, executor_kw):
if not self.action:
raise UserError, "Builder %s must have an action to build %s."%(self.get_name(env or self.env), map(str,tlist))
return self.action.get_executor(env or self.env,
[], # env already has overrides
tlist,
slist,
executor_kw)
def get_multi_executor(self, env, tlist, slist, executor_kw):
try:
executor = tlist[0].get_executor(create = 0)
except (AttributeError, IndexError):
return self.get_single_executor(env, tlist, slist, executor_kw)
else:
executor.add_sources(slist)
return executor
def _create_nodes(self, env, target = None, source = None):
"""Create and return lists of target and source nodes.
"""
def _adjustixes(files, pre, suf):
@ -472,14 +483,13 @@ class BuilderBase:
result.append(f)
return result
overwarn.warn()
env = env.Override(overwarn.data)
src_suf = self.get_src_suffix(env)
target_factory = env.get_factory(self.target_factory)
source_factory = env.get_factory(self.source_factory)
source = _adjustixes(source, None, src_suf)
slist = env.arg2nodes(source, self.source_factory)
slist = env.arg2nodes(source, source_factory)
pre = self.get_prefix(env, slist)
suf = self.get_suffix(env, slist)
@ -489,10 +499,14 @@ class BuilderBase:
t_from_s = slist[0].target_from_source
except AttributeError:
raise UserError("Do not know how to create a target from source `%s'" % slist[0])
tlist = [ t_from_s(pre, suf, self.splitext) ]
except IndexError:
tlist = []
else:
splitext = lambda S,self=self,env=env: self.splitext(S,env)
tlist = [ t_from_s(pre, suf, splitext) ]
else:
target = _adjustixes(target, pre, suf)
tlist = env.arg2nodes(target, self.target_factory)
tlist = env.arg2nodes(target, target_factory)
if self.emitter:
# The emitter is going to do str(node), but because we're
@ -503,58 +517,97 @@ class BuilderBase:
new_targets = []
for t in tlist:
if not t.is_derived():
t.builder = self
t.builder_set(self)
new_targets.append(t)
target, source = self.emitter(target=tlist, source=slist, env=env)
# Now delete the temporary builders that we attached to any
# new targets, so that _init_nodes() doesn't do weird stuff
# new targets, so that _node_errors() doesn't do weird stuff
# to them because it thinks they already have builders.
for t in new_targets:
if t.builder is self:
# Only delete the temporary builder if the emitter
# didn't change it on us.
t.builder = None
t.builder_set(None)
# Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances.
slist = env.arg2nodes(source, self.source_factory)
tlist = env.arg2nodes(target, self.target_factory)
tlist = env.arg2nodes(target, target_factory)
slist = env.arg2nodes(source, source_factory)
return tlist, slist
def _execute(self, env, target = None, source = _null, overwarn={}):
if source is _null:
source = target
target = None
def _execute(self, env, target, source, overwarn={}, executor_kw={}):
# We now assume that target and source are lists or None.
if self.src_builder:
source = self.src_builder_sources(env, source, overwarn)
if(self.single_source and
SCons.Util.is_List(source) and
len(source) > 1 and
target is None):
if self.single_source and len(source) > 1 and target is None:
result = []
if target is None: target = [None]*len(source)
for k in range(len(source)):
t = self._execute(env, target[k], source[k], overwarn)
if SCons.Util.is_List(t):
result.extend(t)
else:
result.append(t)
for tgt, src in zip(target, source):
if not tgt is None: tgt = [tgt]
if not src is None: src = [src]
result.extend(self._execute(env, tgt, src, overwarn))
return result
tlist, slist = self._create_nodes(env, overwarn, target, source)
overwarn.warn()
if len(tlist) == 1:
builder = self
tlist, slist = self._create_nodes(env, target, source)
# Check for errors with the specified target/source lists.
_node_errors(self, env, tlist, slist)
# The targets are fine, so find or make the appropriate Executor to
# build this particular list of targets from this particular list of
# sources.
if self.multi:
get_executor = self.get_multi_executor
else:
builder = ListBuilder(self, env, tlist)
_init_nodes(builder, env, overwarn.data, tlist, slist)
get_executor = self.get_single_executor
executor = get_executor(env, tlist, slist, executor_kw)
return tlist
# Now set up the relevant information in the target Nodes themselves.
for t in tlist:
t.cwd = env.fs.getcwd()
t.builder_set(self)
t.env_set(env)
t.add_source(slist)
t.set_executor(executor)
t.set_explicit(self.is_explicit)
def __call__(self, env, target = None, source = _null, **kw):
return self._execute(env, target, source, OverrideWarner(kw))
return SCons.Node.NodeList(tlist)
def __call__(self, env, target=None, source=None, chdir=_null, **kw):
# We now assume that target and source are lists or None.
# The caller (typically Environment.BuilderWrapper) is
# responsible for converting any scalar values to lists.
if chdir is _null:
ekw = self.executor_kw
else:
ekw = self.executor_kw.copy()
ekw['chdir'] = chdir
if kw:
if kw.has_key('srcdir'):
def prependDirIfRelative(f, srcdir=kw['srcdir']):
import os.path
if SCons.Util.is_String(f) and not os.path.isabs(f):
f = os.path.join(srcdir, f)
return f
if not SCons.Util.is_List(source):
source = [source]
source = map(prependDirIfRelative, source)
del kw['srcdir']
if self.overrides:
env_kw = self.overrides.copy()
env_kw.update(kw)
else:
env_kw = kw
else:
env_kw = self.overrides
env = env.Override(env_kw)
return self._execute(env, target, source, OverrideWarner(kw), ekw)
def adjust_suffix(self, suff):
if suff and not suff[0] in [ '.', '_', '$' ]:
@ -567,24 +620,25 @@ class BuilderBase:
prefix = prefix(env, sources)
return env.subst(prefix)
def set_suffix(self, suffix):
if not callable(suffix):
suffix = self.adjust_suffix(suffix)
self.suffix = suffix
def get_suffix(self, env, sources=[]):
suffix = self.suffix
if callable(suffix):
suffix = suffix(env, sources)
else:
suffix = self.adjust_suffix(suffix)
return env.subst(suffix)
def src_suffixes(self, env):
return map(lambda x, s=self, e=env: e.subst(s.adjust_suffix(x)),
self.src_suffix)
def set_src_suffix(self, src_suffix):
if not src_suffix:
src_suffix = []
elif not SCons.Util.is_List(src_suffix):
src_suffix = [ src_suffix ]
self.src_suffix = src_suffix
adjust = lambda suf, s=self: \
callable(suf) and suf or s.adjust_suffix(suf)
self.src_suffix = map(adjust, src_suffix)
def get_src_suffix(self, env):
"""Get the first src_suffix in the list of src_suffixes."""
@ -610,144 +664,166 @@ class BuilderBase:
"""
self.emitter[suffix] = emitter
class ListBuilder(SCons.Util.Proxy):
"""A Proxy to support building an array of targets (for example,
foo.o and foo.h from foo.y) from a single Action execution.
def add_src_builder(self, builder):
"""
Add a new Builder to the list of src_builders.
def __init__(self, builder, env, tlist):
if __debug__: logInstanceCreation(self)
SCons.Util.Proxy.__init__(self, builder)
self.builder = builder
self.target_scanner = builder.target_scanner
self.source_scanner = builder.source_scanner
self.env = env
self.tlist = tlist
self.multi = builder.multi
self.single_source = builder.single_source
def targets(self, node):
"""Return the list of targets for this builder instance.
This requires wiping out cached values so that the computed
lists of source suffixes get re-calculated.
"""
return self.tlist
self._memo = {}
self.src_builder.append(builder)
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
def get_name(self, env):
"""Attempts to get the name of the Builder."""
return "ListBuilder(%s)" % self.builder.get_name(env)
class MultiStepBuilder(BuilderBase):
"""This is a builder subclass that can build targets in
multiple steps. The src_builder parameter to the constructor
accepts a builder that is called to build sources supplied to
this builder. The targets of that first build then become
the sources of this builder.
If this builder has a src_suffix supplied, then the src_builder
builder is NOT invoked if the suffix of a source file matches
src_suffix.
def _get_sdict(self, env):
"""
def __init__(self, src_builder,
action = None,
prefix = '',
suffix = '',
src_suffix = '',
target_factory = SCons.Node.FS.default_fs.File,
source_factory = SCons.Node.FS.default_fs.File,
target_scanner = None,
source_scanner = None,
emitter=None,
single_source=0):
if __debug__: logInstanceCreation(self)
BuilderBase.__init__(self, action, prefix, suffix, src_suffix,
target_factory, source_factory,
target_scanner, source_scanner, emitter,
single_source = single_source)
if not SCons.Util.is_List(src_builder):
src_builder = [ src_builder ]
self.src_builder = src_builder
self.sdict = {}
self.cached_src_suffixes = {} # source suffixes keyed on id(env)
Returns a dictionary mapping all of the source suffixes of all
src_builders of this Builder to the underlying Builder that
should be called first.
def _execute(self, env, target = None, source = _null, overwarn={}):
if source is _null:
source = target
target = None
This dictionary is used for each target specified, so we save a
lot of extra computation by memoizing it for each construction
environment.
slist = env.arg2nodes(source, self.source_factory)
final_sources = []
Note that this is re-computed each time, not cached, because there
might be changes to one of our source Builders (or one of their
source Builders, and so on, and so on...) that we can't "see."
try:
sdict = self.sdict[id(env)]
except KeyError:
The underlying methods we call cache their computed values,
though, so we hope repeatedly aggregating them into a dictionary
like this won't be too big a hit. We may need to look for a
better way to do this if performance data show this has turned
into a significant bottleneck.
"""
sdict = {}
self.sdict[id(env)] = sdict
for bld in self.src_builder:
if SCons.Util.is_String(bld):
try:
bld = env['BUILDERS'][bld]
except KeyError:
continue
for bld in self.get_src_builders(env):
for suf in bld.src_suffixes(env):
sdict[suf] = bld
return sdict
def src_builder_sources(self, env, source, overwarn={}):
source_factory = env.get_factory(self.source_factory)
slist = env.arg2nodes(source, source_factory)
sdict = self._get_sdict(env)
src_suffixes = self.src_suffixes(env)
for snode in slist:
try:
get_suffix = snode.get_suffix
except AttributeError:
ext = self.splitext(str(snode))
else:
ext = get_suffix()
try:
subsidiary_builder = sdict[ext]
except KeyError:
final_sources.append(snode)
else:
tgt = subsidiary_builder._execute(env, None, snode, overwarn)
# If the subsidiary Builder returned more than one target,
# then filter out any sources that this Builder isn't
# capable of building.
if len(tgt) > 1:
tgt = filter(lambda x, self=self, suf=src_suffixes:
self.splitext(SCons.Util.to_String(x))[1] in suf,
tgt)
final_sources.extend(tgt)
lengths_dict = {}
for l in map(len, src_suffixes):
lengths_dict[l] = None
lengths = lengths_dict.keys()
return BuilderBase._execute(self, env, target, final_sources, overwarn)
def match_src_suffix(node, src_suffixes=src_suffixes, lengths=lengths):
node_suffixes = map(lambda l, n=node: n.name[-l:], lengths)
for suf in src_suffixes:
if suf in node_suffixes:
return suf
return None
result = []
for snode in slist:
match_suffix = match_src_suffix(snode)
if match_suffix:
try:
bld = sdict[match_suffix]
except KeyError:
result.append(snode)
else:
tlist = bld._execute(env, None, [snode], overwarn)
# If the subsidiary Builder returned more than one
# target, then filter out any sources that this
# Builder isn't capable of building.
if len(tlist) > 1:
tlist = filter(match_src_suffix, tlist)
result.extend(tlist)
else:
result.append(snode)
return result
def _get_src_builders_key(self, env):
return id(env)
memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key))
def get_src_builders(self, env):
"""Return all the src_builders for this Builder.
This is essentially a recursive descent of the src_builder "tree."
"""
ret = []
Returns the list of source Builders for this Builder.
This exists mainly to look up Builders referenced as
strings in the 'BUILDER' variable of the construction
environment and cache the result.
"""
memo_key = id(env)
try:
memo_dict = self._memo['get_src_builders']
except KeyError:
memo_dict = {}
self._memo['get_src_builders'] = memo_dict
else:
try:
return memo_dict[memo_key]
except KeyError:
pass
builders = []
for bld in self.src_builder:
if SCons.Util.is_String(bld):
# All Environments should have a BUILDERS
# variable, so no need to check for it.
try:
bld = env['BUILDERS'][bld]
except KeyError:
continue
ret.append(bld)
return ret
builders.append(bld)
memo_dict[memo_key] = builders
return builders
def _subst_src_suffixes_key(self, env):
return id(env)
memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key))
def subst_src_suffixes(self, env):
"""
The suffix list may contain construction variable expansions,
so we have to evaluate the individual strings. To avoid doing
this over and over, we memoize the results for each construction
environment.
"""
memo_key = id(env)
try:
memo_dict = self._memo['subst_src_suffixes']
except KeyError:
memo_dict = {}
self._memo['subst_src_suffixes'] = memo_dict
else:
try:
return memo_dict[memo_key]
except KeyError:
pass
suffixes = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
memo_dict[memo_key] = suffixes
return suffixes
def src_suffixes(self, env):
"""Return a list of the src_suffix attributes for all
src_builders of this Builder.
"""
try:
return self.cached_src_suffixes[id(env)]
except KeyError:
suffixes = BuilderBase.src_suffixes(self, env)
Returns the list of source suffixes for all src_builders of this
Builder.
This is essentially a recursive descent of the src_builder "tree."
(This value isn't cached because there may be changes in a
src_builder many levels deep that we can't see.)
"""
sdict = {}
suffixes = self.subst_src_suffixes(env)
for s in suffixes:
sdict[s] = 1
for builder in self.get_src_builders(env):
suffixes.extend(builder.src_suffixes(env))
self.cached_src_suffixes[id(env)] = suffixes
for s in builder.src_suffixes(env):
if not sdict.has_key(s):
sdict[s] = 1
suffixes.append(s)
return suffixes
class CompositeBuilder(SCons.Util.Proxy):
@ -757,7 +833,7 @@ class CompositeBuilder(SCons.Util.Proxy):
"""
def __init__(self, builder, cmdgen):
if __debug__: logInstanceCreation(self)
if __debug__: logInstanceCreation(self, 'Builder.CompositeBuilder')
SCons.Util.Proxy.__init__(self, builder)
# cmdgen should always be an instance of DictCmdGenerator.
@ -767,6 +843,3 @@ class CompositeBuilder(SCons.Util.Proxy):
def add_action(self, suffix, action):
self.cmdgen.add_action(suffix, action)
self.set_src_suffix(self.cmdgen.src_suffixes())
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)

View file

@ -78,6 +78,9 @@ Autoconf-like configuration support; low level implementation of tests.
# The file must not exist or be empty when starting.
# Empty or None to skip this (some tests will not work!).
#
# context.config_h (may be missing). If present, must be a string, which
# will be filled with the contents of a config_h file.
#
# context.vardict Dictionary holding variables used for the tests and
# stores results from the tests, used for the build
# commands.
@ -91,9 +94,17 @@ Autoconf-like configuration support; low level implementation of tests.
# be a number and "SYSTEMNAME" a string.
#
import re
import string
from types import IntType
#
# PUBLIC VARIABLES
#
LogInputFiles = 1 # Set that to log the input files in case of a failed test
LogErrorMessages = 1 # Set that to log Conftest-generated error messages
#
# PUBLIC FUNCTIONS
#
@ -121,9 +132,10 @@ def CheckBuilder(context, text = None, language = None):
if not text:
text = """
int main() {
int main() {
return 0;
}\n\n"""
}
"""
context.Display("Checking if building a %s file works... " % lang)
ret = context.BuildProg(text, suffix)
@ -164,10 +176,10 @@ def CheckFunc(context, function_name, header = None, language = None):
includetext = ''
if not header:
header = """
#ifdef __cplusplus
extern "C"
#endif
char %s();""" % function_name
#ifdef __cplusplus
extern "C"
#endif
char %s();""" % function_name
lang, suffix, msg = _lang2suffix(language)
if msg:
@ -175,19 +187,20 @@ def CheckFunc(context, function_name, header = None, language = None):
return msg
text = """
%(include)s
#include <assert.h>
%(hdr)s
%(include)s
#include <assert.h>
%(hdr)s
int main() {
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
int main() {
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
fail fail fail
#else
#else
%(name)s();
#endif
#endif
return 0;
}\n\n""" % { 'name': function_name,
}
""" % { 'name': function_name,
'include': includetext,
'hdr': header }
@ -282,15 +295,16 @@ def CheckType(context, type_name, fallback = None,
# - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
# - Using the previous two together works reliably.
text = """
%(include)s
%(header)s
%(include)s
%(header)s
int main() {
int main() {
if ((%(name)s *) 0)
return 0;
if (sizeof (%(name)s))
return 0;
}\n\n""" % { 'include': includetext,
}
""" % { 'include': includetext,
'header': header,
'name': type_name }
@ -305,7 +319,7 @@ def CheckType(context, type_name, fallback = None,
return ret
def CheckLib(context, libs, func_name, header = None,
def CheckLib(context, libs, func_name = None, header = None,
extra_libs = None, call = None, language = None, autoadd = 1):
"""
Configure check for a C or C++ libraries "libs". Searches through
@ -319,7 +333,8 @@ def CheckLib(context, libs, func_name, header = None,
depends on.
Optional "call" replaces the call to "func_name" in the test code. It must
consist of complete C statements, including a trailing ";".
There must either be a "func_name" or a "call" argument (or both).
Both "func_name" and "call" arguments are optional, and in that case, just
linking against the libs is tested.
"language" should be "C" or "C++" and is used to select the compiler.
Default is "C".
Note that this uses the current value of compiler and linker flags, make
@ -335,28 +350,33 @@ def CheckLib(context, libs, func_name, header = None,
header = ""
text = """
%s
%s """ % (includetext, header)
%s
%s""" % (includetext, header)
# Add a function declaration if needed.
if func_name and func_name != "main" and not header:
if func_name and func_name != "main":
if not header:
text = text + """
#ifdef __cplusplus
extern "C"
#endif
char %s();""" % func_name
#ifdef __cplusplus
extern "C"
#endif
char %s();
""" % func_name
# The actual test code.
if not call:
call = "%s();" % func_name
text = text + """
int
main() {
%s
return 0;
}
\n\n""" % call
# if no function to test, leave main() blank
text = text + """
int
main() {
%s
return 0;
}
""" % (call or "")
if call:
i = string.find(call, "\n")
if i > 0:
calltext = call[:i] + ".."
@ -372,8 +392,15 @@ def CheckLib(context, libs, func_name, header = None,
context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
return msg
# if a function was specified to run in main(), say it
if call:
context.Display("Checking for %s in %s library %s... "
% (calltext, lang, lib_name))
# otherwise, just say the name of library and language
else:
context.Display("Checking for %s library %s... "
% (lang, lib_name))
if lib_name:
l = [ lib_name ]
if extra_libs:
@ -390,7 +417,7 @@ def CheckLib(context, libs, func_name, header = None,
if oldLIBS != -1 and (ret or not autoadd):
context.SetLIBS(oldLIBS)
if ret == "":
if not ret:
return ret
return ret
@ -418,8 +445,8 @@ def _YesNoResult(context, ret, key, text):
def _Have(context, key, have):
"""
Store result of a test in context.havedict and context.headerfilename.
"key" is a "HAVE_abc" name. It is turned into all CAPITALS and ":./" are
replaced by an underscore.
"key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-
alphanumerics are replaced by an underscore.
The value of "have" can be:
1 - Feature is defined, add "#define key".
0 - Feature is not defined, add "/* #undef key */".
@ -432,22 +459,23 @@ def _Have(context, key, have):
when desired and escape special characters!
"""
key_up = string.upper(key)
key_up = string.replace(key_up, ':', '_')
key_up = string.replace(key_up, '.', '_')
key_up = string.replace(key_up, '/', '_')
key_up = string.replace(key_up, ' ', '_')
key_up = re.sub('[^A-Z0-9_]', '_', key_up)
context.havedict[key_up] = have
if have == 1:
line = "#define %s\n" % key_up
elif have == 0:
line = "/* #undef %s */\n" % key_up
elif type(have) == IntType:
line = "#define %s %d\n" % (key_up, have)
else:
line = "#define %s %s\n" % (key_up, str(have))
if context.headerfilename:
f = open(context.headerfilename, "a")
if have == 1:
f.write("#define %s\n" % key_up)
elif have == 0:
f.write("/* #undef %s */\n" % key_up)
elif type(have) == IntType:
f.write("#define %s %d\n" % (key_up, have))
else:
f.write("#define %s %s\n" % (key_up, str(have)))
f.write(line)
f.close()
elif hasattr(context,'config_h'):
context.config_h = context.config_h + line
def _LogFailed(context, text, msg):
@ -455,6 +483,7 @@ def _LogFailed(context, text, msg):
Write to the log about a failed program.
Add line numbers, so that error messages can be understood.
"""
if LogInputFiles:
context.Log("Failed program was:\n")
lines = string.split(text, '\n')
if len(lines) and lines[-1] == '':
@ -463,6 +492,7 @@ def _LogFailed(context, text, msg):
for line in lines:
context.Log("%d: %s\n" % (n, line))
n = n + 1
if LogErrorMessages:
context.Log("Error message: %s\n" % msg)

View file

@ -7,7 +7,7 @@ needed by most users.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -29,12 +29,13 @@ needed by most users.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Debug.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Debug.py 0.97.D001 2007/05/17 11:35:19 knight"
# Recipe 14.10 from the Python Cookbook.
import os
import string
import sys
# Recipe 14.10 from the Python Cookbook.
try:
import weakref
except ImportError:
@ -60,6 +61,10 @@ def string_to_classes(s):
else:
return string.split(s)
def fetchLoggedInstances(classes="*"):
classnames = string_to_classes(classes)
return map(lambda cn: (cn, len(tracked_classes[cn])), classnames)
def countLoggedInstances(classes, file=sys.stdout):
for classname in string_to_classes(classes):
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
@ -93,10 +98,102 @@ if sys.platform[:5] == "linux":
else:
try:
import resource
except ImportError:
try:
import win32process
import win32api
except ImportError:
def memory():
return 0
else:
def memory():
process_handle = win32api.GetCurrentProcess()
memory_info = win32process.GetProcessMemoryInfo( process_handle )
return memory_info['PeakWorkingSetSize']
else:
def memory():
res = resource.getrusage(resource.RUSAGE_SELF)
return res[4]
caller_dicts = {}
def caller(*backlist):
import traceback
if not backlist:
backlist = [0]
result = []
for back in backlist:
tb = traceback.extract_stack(limit=3+back)
key = tb[1][:3]
try:
entry = caller_dicts[key]
except KeyError:
entry = caller_dicts[key] = {}
key = tb[0][:3]
entry[key] = entry.get(key, 0) + 1
result.append('%s:%d(%s)' % func_shorten(key))
return result
def dump_caller_counts(file=sys.stdout):
keys = caller_dicts.keys()
keys.sort()
for k in keys:
file.write("Callers of %s:%d(%s):\n" % func_shorten(k))
counts = caller_dicts[k]
callers = counts.keys()
callers.sort()
for c in callers:
#file.write(" counts[%s] = %s\n" % (c, counts[c]))
t = ((counts[c],) + func_shorten(c))
file.write(" %6d %s:%d(%s)\n" % t)
shorten_list = [
( '/scons/SCons/', 1),
( '/src/engine/SCons/', 1),
( '/usr/lib/python', 0),
]
if os.sep != '/':
def platformize(t):
return (string.replace(t[0], '/', os.sep), t[1])
shorten_list = map(platformize, shorten_list)
del platformize
def func_shorten(func_tuple):
f = func_tuple[0]
for t in shorten_list:
i = string.find(f, t[0])
if i >= 0:
if t[1]:
i = i + len(t[0])
f = f[i:]
break
return (f,)+func_tuple[1:]
TraceFP = {}
if sys.platform == 'win32':
TraceDefault = 'con'
else:
TraceDefault = '/dev/tty'
def Trace(msg, file=None, mode='w'):
"""Write a trace message to a file. Whenever a file is specified,
it becomes the default for the next call to Trace()."""
global TraceDefault
if file is None:
file = TraceDefault
else:
TraceDefault = file
try:
fp = TraceFP[file]
except KeyError:
try:
fp = TraceFP[file] = open(file, mode)
except TypeError:
# Assume we were passed an open file pointer.
fp = file
fp.write(msg)

View file

@ -0,0 +1,449 @@
"""SCons.Defaults
Builders and other things for the local site. Here's where we'll
duplicate the functionality of autoconf until we move it into the
installation procedure or use something like qmconf.
The code that reads the registry to find MSVC components was borrowed
from distutils.msvccompiler.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Defaults.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
import shutil
import stat
import time
import types
import sys
import SCons.Action
import SCons.Builder
import SCons.Environment
import SCons.PathList
import SCons.Sig
import SCons.Subst
import SCons.Tool
# A placeholder for a default Environment (for fetching source files
# from source code management systems and the like). This must be
# initialized later, after the top-level directory is set by the calling
# interface.
_default_env = None
# Lazily instantiate the default environment so the overhead of creating
# it doesn't apply when it's not needed.
def DefaultEnvironment(*args, **kw):
global _default_env
if not _default_env:
_default_env = apply(SCons.Environment.Environment, args, kw)
_default_env._build_signature = 1
_default_env._calc_module = SCons.Sig.default_module
return _default_env
# Emitters for setting the shared attribute on object files,
# and an action for checking that all of the source files
# going into a shared library are, in fact, shared.
def StaticObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = None
return (target, source)
def SharedObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = 1
return (target, source)
def SharedFlagChecker(source, target, env):
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
if same == '0' or same == '' or same == 'False':
for src in source:
try:
shared = src.attributes.shared
except AttributeError:
shared = None
if not shared:
raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
# Some people were using these variable name before we made
# SourceFileScanner part of the public interface. Don't break their
# SConscript files until we've given them some fair warning and a
# transition period.
CScan = SCons.Tool.CScanner
DScan = SCons.Tool.DScanner
LaTeXScan = SCons.Tool.LaTeXScanner
ObjSourceScan = SCons.Tool.SourceFileScanner
ProgScan = SCons.Tool.ProgramScanner
# This isn't really a tool scanner, so it doesn't quite belong with
# the rest of those in Tool/__init__.py, but I'm not sure where else it
# should go. Leave it here for now.
import SCons.Scanner.Dir
DirScanner = SCons.Scanner.Dir.DirScanner()
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
# Actions for common languages.
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
# Common tasks that we allow users to perform in platform-independent
# ways by creating ActionFactory instances.
ActionFactory = SCons.Action.ActionFactory
Chmod = ActionFactory(os.chmod,
lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
def copy_func(dest, src):
if os.path.isfile(src):
return shutil.copy(src, dest)
else:
return shutil.copytree(src, dest, 1)
Copy = ActionFactory(copy_func,
lambda dest, src: 'Copy("%s", "%s")' % (dest, src))
def delete_func(entry, must_exist=0):
if not must_exist and not os.path.exists(entry):
return None
if not os.path.exists(entry) or os.path.isfile(entry):
return os.unlink(entry)
else:
return shutil.rmtree(entry, 1)
def delete_strfunc(entry, must_exist=0):
return 'Delete("%s")' % entry
Delete = ActionFactory(delete_func, delete_strfunc)
Mkdir = ActionFactory(os.makedirs,
lambda dir: 'Mkdir("%s")' % dir)
Move = ActionFactory(lambda dest, src: os.rename(src, dest),
lambda dest, src: 'Move("%s", "%s")' % (dest, src))
def touch_func(file):
mtime = int(time.time())
if os.path.exists(file):
atime = os.path.getatime(file)
else:
open(file, 'w')
atime = mtime
return os.utime(file, (atime, mtime))
Touch = ActionFactory(touch_func,
lambda file: 'Touch("%s")' % file)
# Internal utility functions
def installFunc(dest, source, env):
"""Install a source file or directory into a destination by copying,
(including copying permission/mode bits)."""
if os.path.isdir(source):
if os.path.exists(dest):
if not os.path.isdir(dest):
raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source))
else:
parent = os.path.split(dest)[0]
if not os.path.exists(parent):
os.makedirs(parent)
shutil.copytree(source, dest)
else:
shutil.copy2(source, dest)
st = os.stat(source)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
def installStr(dest, source, env):
source = str(source)
if os.path.isdir(source):
type = 'directory'
else:
type = 'file'
return 'Install %s: "%s" as "%s"' % (type, source, dest)
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
"""
Creates a new list from 'list' by first interpolating each element
in the list using the 'env' dictionary and then calling f on the
list, and finally calling _concat_ixes to concatenate 'prefix' and
'suffix' onto each element of the list.
"""
if not list:
return list
if SCons.Util.is_List(list):
list = SCons.Util.flatten(list)
l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
if not l is None:
list = l
return _concat_ixes(prefix, list, suffix, env)
def _concat_ixes(prefix, list, suffix, env):
"""
Creates a new list from 'list' by concatenating the 'prefix' and
'suffix' arguments onto each element of the list. A trailing space
on 'prefix' or leading space on 'suffix' will cause them to be put
into separate list elements rather than being concatenated.
"""
result = []
# ensure that prefix and suffix are strings
prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
for x in list:
if isinstance(x, SCons.Node.FS.File):
result.append(x)
continue
x = str(x)
if x:
if prefix:
if prefix[-1] == ' ':
result.append(prefix[:-1])
elif x[:len(prefix)] != prefix:
x = prefix + x
result.append(x)
if suffix:
if suffix[0] == ' ':
result.append(suffix[1:])
elif x[-len(suffix):] != suffix:
result[-1] = result[-1]+suffix
return result
def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
"""This is a wrapper around _concat() that checks for the existence
of prefixes or suffixes on list elements and strips them where it
finds them. This is used by tools (like the GNU linker) that need
to turn something like 'libfoo.a' into '-lfoo'."""
if not callable(c):
if callable(env["_concat"]):
c = env["_concat"]
else:
c = _concat
def f(list, sp=stripprefix, ss=stripsuffix):
result = []
for l in list:
if isinstance(l, SCons.Node.FS.File):
result.append(l)
continue
if not SCons.Util.is_String(l):
l = str(l)
if l[:len(sp)] == sp:
l = l[len(sp):]
if l[-len(ss):] == ss:
l = l[:-len(ss)]
result.append(l)
return result
return c(prefix, list, suffix, env, f)
# This is an alternate _stripixes() function that passes all of our tests
# (as of 21 February 2007), like the current version above. It's more
# straightforward because it does its manipulation directly, not using
# the funky f call-back function to _concat(). (In this respect it's
# like the updated _defines() function below.)
#
# The most convoluted thing is that it still uses a custom _concat()
# function if one was placed in the construction environment; there's
# a specific test for that functionality, but it might be worth getting
# rid of.
#
# Since this work was done while trying to get 0.97 out the door
# (just prior to 0.96.96), I decided to be cautious and leave the old
# function as is, to minimize the chance of other corner-case regressions.
# The updated version is captured here so we can uncomment it and start
# using it at a less sensitive time in the development cycle (or when
# it's clearly required to fix something).
#
#def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
# """
# This is a wrapper around _concat()/_concat_ixes() that checks for the
# existence of prefixes or suffixes on list elements and strips them
# where it finds them. This is used by tools (like the GNU linker)
# that need to turn something like 'libfoo.a' into '-lfoo'.
# """
#
# if not list:
# return list
#
# if not callable(c):
# env_c = env['_concat']
# if env_c != _concat and callable(env_c):
# # There's a custom _concat() method in the construction
# # environment, and we've allowed people to set that in
# # the past (see test/custom-concat.py), so preserve the
# # backwards compatibility.
# c = env_c
# else:
# c = _concat_ixes
#
# if SCons.Util.is_List(list):
# list = SCons.Util.flatten(list)
#
# lsp = len(stripprefix)
# lss = len(stripsuffix)
# stripped = []
# for l in SCons.PathList.PathList(list).subst_path(env, None, None):
# if isinstance(l, SCons.Node.FS.File):
# stripped.append(l)
# continue
# if not SCons.Util.is_String(l):
# l = str(l)
# if l[:lsp] == stripprefix:
# l = l[lsp:]
# if l[-lss:] == stripsuffix:
# l = l[:-lss]
# stripped.append(l)
#
# return c(prefix, stripped, suffix, env)
def _defines(prefix, defs, suffix, env, c=_concat_ixes):
"""A wrapper around _concat_ixes that turns a list or string
into a list of C preprocessor command-line definitions.
"""
if SCons.Util.is_List(defs):
l = []
for d in defs:
if SCons.Util.is_List(d) or type(d) is types.TupleType:
l.append(str(d[0]) + '=' + str(d[1]))
else:
l.append(str(d))
elif SCons.Util.is_Dict(defs):
# The items in a dictionary are stored in random order, but
# if the order of the command-line options changes from
# invocation to invocation, then the signature of the command
# line will change and we'll get random unnecessary rebuilds.
# Consequently, we have to sort the keys to ensure a
# consistent order...
l = []
keys = defs.keys()
keys.sort()
for k in keys:
v = defs[k]
if v is None:
l.append(str(k))
else:
l.append(str(k) + '=' + str(v))
else:
l = [str(defs)]
return c(prefix, env.subst_path(l), suffix, env)
class NullCmdGenerator:
"""This is a callable class that can be used in place of other
command generators if you don't want them to do anything.
The __call__ method for this class simply returns the thing
you instantiated it with.
Example usage:
env["DO_NOTHING"] = NullCmdGenerator
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
"""
def __init__(self, cmd):
self.cmd = cmd
def __call__(self, target, source, env, for_signature=None):
return self.cmd
class Variable_Method_Caller:
"""A class for finding a construction variable on the stack and
calling one of its methods.
We use this to support "construction variables" in our string
eval()s that actually stand in for methods--specifically, use
of "RDirs" in call to _concat that should actually execute the
"TARGET.RDirs" method. (We used to support this by creating a little
"build dictionary" that mapped RDirs to the method, but this got in
the way of Memoizing construction environments, because we had to
create new environment objects to hold the variables.)
"""
def __init__(self, variable, method):
self.variable = variable
self.method = method
def __call__(self, *args, **kw):
try: 1/0
except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
variable = self.variable
while frame:
if frame.f_locals.has_key(variable):
v = frame.f_locals[variable]
if v:
method = getattr(v, self.method)
return apply(method, args, kw)
frame = frame.f_back
return None
ConstructionEnvironment = {
'BUILDERS' : {},
'SCANNERS' : [],
'CONFIGUREDIR' : '#/.sconf_temp',
'CONFIGURELOG' : '#/config.log',
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
'DSUFFIXES' : SCons.Tool.DSuffixes,
'ENV' : {},
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
'INSTALL' : installFunc,
'INSTALLSTR' : installStr,
'_installStr' : installStr,
'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
'_concat' : _concat,
'_defines' : _defines,
'_stripixes' : _stripixes,
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
'TEMPFILE' : NullCmdGenerator,
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
'File' : Variable_Method_Caller('TARGET', 'File'),
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -28,14 +28,15 @@ and user errors in SCons.
"""
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Errors.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Errors.py 0.97.D001 2007/05/17 11:35:19 knight"
class BuildError(Exception):
def __init__(self, node=None, errstr="Unknown error", *args):
def __init__(self, node=None, errstr="Unknown error", filename=None, *args):
self.node = node
self.errstr = errstr
self.filename = filename
apply(Exception.__init__, (self,) + args)
class InternalError(Exception):
@ -53,8 +54,9 @@ class ExplicitExit(Exception):
self.status = status
apply(Exception.__init__, (self,) + args)
class ConfigureDryRunError(UserError):
"""Raised when a file needs to be updated during a Configure process,
but the user requested a dry-run"""
def __init__(self,file):
UserError.__init__(self,"Cannot update configure test (%s) within a dry-run." % str(file))
class TaskmasterException(Exception):
def __init__(self, node=None, exc_info=(None, None, None), *args):
self.node = node
self.errstr = "Exception"
self.exc_info = exc_info
apply(Exception.__init__, (self,) + args)

View file

@ -0,0 +1,306 @@
"""SCons.Executor
A module for executing actions with specific lists of target and source
Nodes.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Executor.py 0.97.D001 2007/05/17 11:35:19 knight"
import string
from SCons.Debug import logInstanceCreation
import SCons.Memoize
class Executor:
"""A class for controlling instances of executing an action.
This largely exists to hold a single association of an action,
environment, list of environment override dictionaries, targets
and sources for later processing as needed.
"""
if SCons.Memoize.use_memoizer:
__metaclass__ = SCons.Memoize.Memoized_Metaclass
memoizer_counters = []
def __init__(self, action, env=None, overridelist=[{}],
targets=[], sources=[], builder_kw={}):
if __debug__: logInstanceCreation(self, 'Executor.Executor')
self.set_action_list(action)
self.pre_actions = []
self.post_actions = []
self.env = env
self.overridelist = overridelist
self.targets = targets
self.sources = sources[:]
self.builder_kw = builder_kw
self._memo = {}
def set_action_list(self, action):
import SCons.Util
if not SCons.Util.is_List(action):
if not action:
import SCons.Errors
raise SCons.Errors.UserError, "Executor must have an action."
action = [action]
self.action_list = action
def get_action_list(self):
return self.pre_actions + self.action_list + self.post_actions
def get_build_env(self):
"""Fetch or create the appropriate build Environment
for this Executor.
"""
# Create the build environment instance with appropriate
# overrides. These get evaluated against the current
# environment's construction variables so that users can
# add to existing values by referencing the variable in
# the expansion.
overrides = {}
for odict in self.overridelist:
overrides.update(odict)
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
build_env = env.Override(overrides)
return build_env
def get_build_scanner_path(self, scanner):
"""Fetch the scanner path for this executor's targets
and sources.
"""
env = self.get_build_env()
try:
cwd = self.targets[0].cwd
except (IndexError, AttributeError):
cwd = None
return scanner.path(env, cwd, self.targets, self.sources)
def get_kw(self, kw={}):
result = self.builder_kw.copy()
result.update(kw)
return result
def do_nothing(self, target, exitstatfunc, kw):
pass
def do_execute(self, target, exitstatfunc, kw):
"""Actually execute the action list."""
env = self.get_build_env()
kw = self.get_kw(kw)
for act in self.get_action_list():
apply(act,
(self.targets, self.sources, env, exitstatfunc),
kw)
# use extra indirection because with new-style objects (Python 2.2
# and above) we can't override special methods, and nullify() needs
# to be able to do this.
def __call__(self, target, exitstatfunc, **kw):
self.do_execute(target, exitstatfunc, kw)
def cleanup(self):
self._memo = {}
def add_sources(self, sources):
"""Add source files to this Executor's list. This is necessary
for "multi" Builders that can be called repeatedly to build up
a source file list for a given target."""
slist = filter(lambda x, s=self.sources: x not in s, sources)
self.sources.extend(slist)
def add_pre_action(self, action):
self.pre_actions.append(action)
def add_post_action(self, action):
self.post_actions.append(action)
# another extra indirection for new-style objects and nullify...
def my_str(self):
env = self.get_build_env()
get = lambda action, t=self.targets, s=self.sources, e=env: \
action.genstring(t, s, e)
return string.join(map(get, self.get_action_list()), "\n")
def __str__(self):
return self.my_str()
def nullify(self):
self.cleanup()
self.do_execute = self.do_nothing
self.my_str = lambda S=self: ''
memoizer_counters.append(SCons.Memoize.CountValue('get_contents'))
def get_contents(self):
"""Fetch the signature contents. This is the main reason this
class exists, so we can compute this once and cache it regardless
of how many target or source Nodes there are.
"""
try:
return self._memo['get_contents']
except KeyError:
pass
env = self.get_build_env()
get = lambda action, t=self.targets, s=self.sources, e=env: \
action.get_contents(t, s, e)
result = string.join(map(get, self.get_action_list()), "")
self._memo['get_contents'] = result
return result
def get_timestamp(self):
"""Fetch a time stamp for this Executor. We don't have one, of
course (only files do), but this is the interface used by the
timestamp module.
"""
return 0
def scan_targets(self, scanner):
self.scan(scanner, self.targets)
def scan_sources(self, scanner):
if self.sources:
self.scan(scanner, self.sources)
def scan(self, scanner, node_list):
"""Scan a list of this Executor's files (targets or sources) for
implicit dependencies and update all of the targets with them.
This essentially short-circuits an N*M scan of the sources for
each individual target, which is a hell of a lot more efficient.
"""
map(lambda N: N.disambiguate(), node_list)
env = self.get_build_env()
select_specific_scanner = lambda t: (t[0], t[1].select(t[0]))
remove_null_scanners = lambda t: not t[1] is None
add_scanner_path = lambda t, s=self: \
(t[0], t[1], s.get_build_scanner_path(t[1]))
if scanner:
scanner_list = map(lambda n, s=scanner: (n, s), node_list)
else:
kw = self.get_kw()
get_initial_scanners = lambda n, e=env, kw=kw: \
(n, n.get_env_scanner(e, kw))
scanner_list = map(get_initial_scanners, node_list)
scanner_list = filter(remove_null_scanners, scanner_list)
scanner_list = map(select_specific_scanner, scanner_list)
scanner_list = filter(remove_null_scanners, scanner_list)
scanner_path_list = map(add_scanner_path, scanner_list)
deps = []
for node, scanner, path in scanner_path_list:
deps.extend(node.get_implicit_deps(env, scanner, path))
for tgt in self.targets:
tgt.add_to_implicit(deps)
def get_missing_sources(self):
"""
"""
return filter(lambda s: s.missing(), self.sources)
def _get_unignored_sources_key(self, ignore=()):
return tuple(ignore)
memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key))
def get_unignored_sources(self, ignore=()):
ignore = tuple(ignore)
try:
memo_dict = self._memo['get_unignored_sources']
except KeyError:
memo_dict = {}
self._memo['get_unignored_sources'] = memo_dict
else:
try:
return memo_dict[ignore]
except KeyError:
pass
sourcelist = self.sources
if ignore:
sourcelist = filter(lambda s, i=ignore: not s in i, sourcelist)
memo_dict[ignore] = sourcelist
return sourcelist
def _process_sources_key(self, func, ignore=()):
return (func, tuple(ignore))
memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process_sources_key))
def process_sources(self, func, ignore=()):
memo_key = (func, tuple(ignore))
try:
memo_dict = self._memo['process_sources']
except KeyError:
memo_dict = {}
self._memo['process_sources'] = memo_dict
else:
try:
return memo_dict[memo_key]
except KeyError:
pass
result = map(func, self.get_unignored_sources(ignore))
memo_dict[memo_key] = result
return result
_Executor = Executor
class Null(_Executor):
"""A null Executor, with a null build Environment, that does
nothing when the rest of the methods call it.
This might be able to disapper when we refactor things to
disassociate Builders from Nodes entirely, so we're not
going to worry about unit tests for this--at least for now.
"""
def __init__(self, *args, **kw):
if __debug__: logInstanceCreation(self, 'Executor.Null')
kw['action'] = []
apply(_Executor.__init__, (self,), kw)
def get_build_env(self):
class NullEnvironment:
def get_scanner(self, key):
return None
return NullEnvironment()
def get_build_scanner_path(self):
return None
def cleanup(self):
pass

View file

@ -7,7 +7,7 @@ stop, and wait on jobs.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -29,7 +29,9 @@ stop, and wait on jobs.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Job.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Job.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.compat
class Jobs:
"""An instance of this class initializes N jobs, and provides
@ -89,8 +91,7 @@ class Serial:
that needs to be executed, or None if there are no more tasks. The
taskmaster's executed() method will be called for each task when it
is successfully executed or failed() will be called if it failed to
execute (e.g. execute() raised an exception). The taskmaster's
is_blocked() method will not be called. """
execute (e.g. execute() raised an exception)."""
self.taskmaster = taskmaster
@ -154,9 +155,9 @@ else:
ok = False
except:
task.exception_set()
ok = 0
ok = False
else:
ok = 1
ok = True
self.resultsQueue.put((task, ok))
@ -169,21 +170,19 @@ else:
self.resultsQueue = Queue.Queue(0)
# Create worker threads
for i in range(num):
for _ in range(num):
Worker(self.requestQueue, self.resultsQueue)
def put(self, obj):
"""Put task into request queue."""
self.requestQueue.put(obj)
def get(self, block = 1):
def get(self, block = True):
"""Remove and return a result tuple from the results queue."""
return self.resultsQueue.get(block)
def get_nowait(self):
"""Remove and result a result tuple from the results queue
without blocking."""
return self.get(0)
def preparation_failed(self, obj):
self.resultsQueue.put((obj, 0))
class Parallel:
"""This class is used to execute tasks in parallel, and is somewhat
@ -195,25 +194,21 @@ else:
def __init__(self, taskmaster, num):
"""Create a new parallel job given a taskmaster.
The taskmaster's next_task() method should return the next task
that needs to be executed, or None if there are no more tasks. The
taskmaster's executed() method will be called for each task when it
is successfully executed or failed() will be called if the task
failed to execute (i.e. execute() raised an exception). The
taskmaster's is_blocked() method should return true iff there are
more tasks, but they can't be executed until one or more other
tasks have been executed. next_task() will be called iff
is_blocked() returned false.
The taskmaster's next_task() method should return the next
task that needs to be executed, or None if there are no more
tasks. The taskmaster's executed() method will be called
for each task when it is successfully executed or failed()
will be called if the task failed to execute (i.e. execute()
raised an exception).
Note: calls to taskmaster are serialized, but calls to execute() on
distinct tasks are not serialized, because that is the whole point
of parallel jobs: they can execute multiple tasks
simultaneously. """
Note: calls to taskmaster are serialized, but calls to
execute() on distinct tasks are not serialized, because
that is the whole point of parallel jobs: they can execute
multiple tasks simultaneously. """
self.taskmaster = taskmaster
self.tp = ThreadPool(num)
self.jobs = 0
self.maxjobs = num
def start(self):
@ -222,8 +217,12 @@ else:
more tasks. If a task fails to execute (i.e. execute() raises
an exception), then the job will stop."""
jobs = 0
while 1:
if self.jobs < self.maxjobs:
# Start up as many available tasks as we're
# allowed to.
while jobs < self.maxjobs:
task = self.taskmaster.next_task()
if task is None:
break
@ -234,26 +233,31 @@ else:
except KeyboardInterrupt:
raise
except:
# Let the failed() callback function arrange for the
# build to stop if that's appropriate.
task.failed()
# Let the failed() callback function arrange
# for the build to stop if that's appropriate.
task.exception_set()
self.tp.preparation_failed(task)
jobs = jobs + 1
continue
# dispatch task
self.tp.put(task)
self.jobs = self.jobs + 1
jobs = jobs + 1
if not task and not jobs: break
# Let any/all completed tasks finish up before we go
# back and put the next batch of tasks on the queue.
while 1:
try:
task, ok = self.tp.get_nowait()
except Queue.Empty:
if not (self.jobs is self.maxjobs or self.taskmaster.is_blocked()):
break
task, ok = self.tp.get()
self.jobs = self.jobs - 1
jobs = jobs - 1
if ok:
task.executed()
else:
task.failed()
task.postprocess()
if self.tp.resultsQueue.empty():
break

View file

@ -0,0 +1,272 @@
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Memoize.py 0.97.D001 2007/05/17 11:35:19 knight"
__doc__ = """Memoizer
A metaclass implementation to count hits and misses of the computed
values that various methods cache in memory.
Use of this modules assumes that wrapped methods be coded to cache their
values in a consistent way. Here is an example of wrapping a method
that returns a computed value, with no input parameters:
memoizer_counters = [] # Memoization
memoizer_counters.append(SCons.Memoize.CountValue('foo')) # Memoization
def foo(self):
try: # Memoization
return self._memo['foo'] # Memoization
except KeyError: # Memoization
pass # Memoization
result = self.compute_foo_value()
self._memo['foo'] = result # Memoization
return result
Here is an example of wrapping a method that will return different values
based on one or more input arguments:
def _bar_key(self, argument): # Memoization
return argument # Memoization
memoizer_counters.append(SCons.Memoize.CountDict('bar', _bar_key)) # Memoization
def bar(self, argument):
memo_key = argument # Memoization
try: # Memoization
memo_dict = self._memo['bar'] # Memoization
except KeyError: # Memoization
memo_dict = {} # Memoization
self._memo['dict'] = memo_dict # Memoization
else: # Memoization
try: # Memoization
return memo_dict[memo_key] # Memoization
except KeyError: # Memoization
pass # Memoization
result = self.compute_bar_value(argument)
memo_dict[memo_key] = result # Memoization
return result
At one point we avoided replicating this sort of logic in all the methods
by putting it right into this module, but we've moved away from that at
present (see the "Historical Note," below.).
Deciding what to cache is tricky, because different configurations
can have radically different performance tradeoffs, and because the
tradeoffs involved are often so non-obvious. Consequently, deciding
whether or not to cache a given method will likely be more of an art than
a science, but should still be based on available data from this module.
Here are some VERY GENERAL guidelines about deciding whether or not to
cache return values from a method that's being called a lot:
-- The first question to ask is, "Can we change the calling code
so this method isn't called so often?" Sometimes this can be
done by changing the algorithm. Sometimes the *caller* should
be memoized, not the method you're looking at.
-- The memoized function should be timed with multiple configurations
to make sure it doesn't inadvertently slow down some other
configuration.
-- When memoizing values based on a dictionary key composed of
input arguments, you don't need to use all of the arguments
if some of them don't affect the return values.
Historical Note: The initial Memoizer implementation actually handled
the caching of values for the wrapped methods, based on a set of generic
algorithms for computing hashable values based on the method's arguments.
This collected caching logic nicely, but had two drawbacks:
Running arguments through a generic key-conversion mechanism is slower
(and less flexible) than just coding these things directly. Since the
methods that need memoized values are generally performance-critical,
slowing them down in order to collect the logic isn't the right
tradeoff.
Use of the memoizer really obscured what was being called, because
all the memoized methods were wrapped with re-used generic methods.
This made it more difficult, for example, to use the Python profiler
to figure out how to optimize the underlying methods.
"""
import new
# A flag controlling whether or not we actually use memoization.
use_memoizer = None
CounterList = []
class Counter:
"""
Base class for counting memoization hits and misses.
We expect that the metaclass initialization will have filled in
the .name attribute that represents the name of the function
being counted.
"""
def __init__(self, method_name):
"""
"""
self.method_name = method_name
self.hit = 0
self.miss = 0
CounterList.append(self)
def display(self):
fmt = " %7d hits %7d misses %s()"
print fmt % (self.hit, self.miss, self.name)
def __cmp__(self, other):
try:
return cmp(self.name, other.name)
except AttributeError:
return 0
class CountValue(Counter):
"""
A counter class for simple, atomic memoized values.
A CountValue object should be instantiated in a class for each of
the class's methods that memoizes its return value by simply storing
the return value in its _memo dictionary.
We expect that the metaclass initialization will fill in the
.underlying_method attribute with the method that we're wrapping.
We then call the underlying_method method after counting whether
its memoized value has already been set (a hit) or not (a miss).
"""
def __call__(self, *args, **kw):
obj = args[0]
if obj._memo.has_key(self.method_name):
self.hit = self.hit + 1
else:
self.miss = self.miss + 1
return apply(self.underlying_method, args, kw)
class CountDict(Counter):
"""
A counter class for memoized values stored in a dictionary, with
keys based on the method's input arguments.
A CountDict object is instantiated in a class for each of the
class's methods that memoizes its return value in a dictionary,
indexed by some key that can be computed from one or more of
its input arguments.
We expect that the metaclass initialization will fill in the
.underlying_method attribute with the method that we're wrapping.
We then call the underlying_method method after counting whether the
computed key value is already present in the memoization dictionary
(a hit) or not (a miss).
"""
def __init__(self, method_name, keymaker):
"""
"""
Counter.__init__(self, method_name)
self.keymaker = keymaker
def __call__(self, *args, **kw):
obj = args[0]
try:
memo_dict = obj._memo[self.method_name]
except KeyError:
self.miss = self.miss + 1
else:
key = apply(self.keymaker, args, kw)
if memo_dict.has_key(key):
self.hit = self.hit + 1
else:
self.miss = self.miss + 1
return apply(self.underlying_method, args, kw)
class Memoizer:
"""Object which performs caching of method calls for its 'primary'
instance."""
def __init__(self):
pass
# Find out if we support metaclasses (Python 2.2 and later).
class M:
def __init__(cls, name, bases, cls_dict):
cls.has_metaclass = 1
class A:
__metaclass__ = M
try:
has_metaclass = A.has_metaclass
except AttributeError:
has_metaclass = None
del M
del A
if not has_metaclass:
def Dump(title):
pass
class Memoized_Metaclass:
# Just a place-holder so pre-metaclass Python versions don't
# have to have special code for the Memoized classes.
pass
def EnableMemoization():
import SCons.Warnings
msg = 'memoization is not supported in this version of Python (no metaclasses)'
raise SCons.Warnings.NoMetaclassSupportWarning, msg
else:
def Dump(title=None):
if title:
print title
CounterList.sort()
for counter in CounterList:
counter.display()
class Memoized_Metaclass(type):
def __init__(cls, name, bases, cls_dict):
super(Memoized_Metaclass, cls).__init__(name, bases, cls_dict)
for counter in cls_dict.get('memoizer_counters', []):
method_name = counter.method_name
counter.name = cls.__name__ + '.' + method_name
counter.underlying_method = cls_dict[method_name]
replacement_method = new.instancemethod(counter, None, cls)
setattr(cls, method_name, replacement_method)
def EnableMemoization():
global use_memoizer
use_memoizer = 1

View file

@ -8,7 +8,7 @@ This creates a hash of global Aliases (dummy targets).
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,8 +30,9 @@ This creates a hash of global Aliases (dummy targets).
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Alias.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Alias.py 0.97.D001 2007/05/17 11:35:19 knight"
import string
import UserDict
import SCons.Errors
@ -39,19 +40,33 @@ import SCons.Node
import SCons.Util
class AliasNameSpace(UserDict.UserDict):
def Alias(self, name):
if self.has_key(name):
raise SCons.Errors.UserError
self[name] = SCons.Node.Alias.Alias(name)
return self[name]
def Alias(self, name, **kw):
if isinstance(name, SCons.Node.Alias.Alias):
return name
try:
a = self[name]
except KeyError:
a = apply(SCons.Node.Alias.Alias, (name,), kw)
self[name] = a
return a
def lookup(self, name):
def lookup(self, name, **kw):
try:
return self[name]
except KeyError:
return None
class AliasNodeInfo(SCons.Node.NodeInfoBase):
pass
class AliasBuildInfo(SCons.Node.BuildInfoBase):
pass
class Alias(SCons.Node.Node):
NodeInfo = AliasNodeInfo
BuildInfo = AliasBuildInfo
def __init__(self, name):
SCons.Node.Node.__init__(self)
self.name = name
@ -59,16 +74,9 @@ class Alias(SCons.Node.Node):
def __str__(self):
return self.name
def build(self):
"""A "builder" for aliases."""
pass
really_build = SCons.Node.Node.build
current = SCons.Node.Node.children_are_up_to_date
def sconsign(self):
"""An Alias is not recorded in .sconsign files"""
pass
def is_under(self, dir):
# Make Alias nodes get built regardless of
# what directory scons was run from. Alias nodes
@ -78,10 +86,26 @@ class Alias(SCons.Node.Node):
def get_contents(self):
"""The contents of an alias is the concatenation
of all the contents of its sources"""
contents = ""
for kid in self.children(None):
contents = contents + kid.get_contents()
return contents
contents = map(lambda n: n.get_contents(), self.children())
return string.join(contents, '')
def sconsign(self):
"""An Alias is not recorded in .sconsign files"""
pass
#
#
#
def build(self):
"""A "builder" for aliases."""
pass
def convert(self):
try: del self.builder
except AttributeError: pass
self.reset_executor()
self.build = self.really_build
default_ans = AliasNameSpace()

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@ Python nodes.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,24 +27,36 @@ Python nodes.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Python.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Python.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Node
class ValueNodeInfo(SCons.Node.NodeInfoBase):
pass
class ValueBuildInfo(SCons.Node.BuildInfoBase):
pass
class Value(SCons.Node.Node):
"""A class for Python variables, typically passed on the command line
or generated by a script, but not from a file or some other source.
"""
def __init__(self, value):
NodeInfo = ValueNodeInfo
BuildInfo = ValueBuildInfo
def __init__(self, value, built_value=None):
SCons.Node.Node.__init__(self)
self.value = value
if not built_value is None:
self.built_value = built_value
def __str__(self):
return repr(self.value)
def build(self):
"""A "builder" for Values."""
pass
def build(self, **kw):
if not hasattr(self, 'built_value'):
apply (SCons.Node.Node.build, (self,), kw)
current = SCons.Node.Node.children_are_up_to_date
@ -54,25 +66,39 @@ class Value(SCons.Node.Node):
# are outside the filesystem:
return 1
def write(self, built_value):
"""Set the value of the node."""
self.built_value = built_value
def read(self):
"""Return the value. If necessary, the value is built."""
self.build()
if not hasattr(self, 'built_value'):
self.built_value = self.value
return self.built_value
def get_contents(self):
"""The contents of a Value are the concatenation
of all the contents of its sources with the node's value itself."""
"""By the assumption that the node.built_value is a
deterministic product of the sources, the contents of a Value
are the concatenation of all the contents of its sources. As
the value need not be built when get_contents() is called, we
cannot use the actual node.built_value."""
contents = str(self.value)
for kid in self.children(None):
contents = contents + kid.get_contents()
return contents
def calc_csig(self, calc=None):
def get_csig(self, calc=None):
"""Because we're a Python value node and don't have a real
timestamp, we get to ignore the calculator and just use the
value contents."""
try:
binfo = self.binfo
except:
except AttributeError:
binfo = self.binfo = self.new_binfo()
try:
return binfo.csig
return binfo.ninfo.csig
except AttributeError:
binfo.csig = self.get_contents()
binfo.ninfo.csig = self.get_contents()
self.store_info(binfo)
return binfo.csig
return binfo.ninfo.csig

View file

@ -10,7 +10,7 @@ See http://optik.sourceforge.net/
# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
# See the README.txt distributed with Optik for licensing terms.
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
# Original Optik revision this is based on:
__Optik_revision__ = "__init__.py,v 1.11 2002/04/11 19:17:34 gward Exp"

View file

@ -3,7 +3,7 @@
Exception classes used by Optik.
"""
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/errors.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/errors.py 0.97.D001 2007/05/17 11:35:19 knight"
# Original Optik revision this is based on:
__Optik_revision__ = "errors.py,v 1.5 2002/02/13 23:29:47 gward Exp"

View file

@ -3,7 +3,7 @@
Defines the Option class and some standard value-checking functions.
"""
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option.py 0.97.D001 2007/05/17 11:35:19 knight"
# Original Optik revision this is based on:
__Optik_revision__ = "option.py,v 1.19.2.1 2002/07/23 01:51:14 gward Exp"

View file

@ -3,7 +3,7 @@
Provides the OptionParser and Values classes.
"""
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option_parser.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option_parser.py 0.97.D001 2007/05/17 11:35:19 knight"
# Original Optik revision this is based on:
__Optik_revision__ = "option_parser.py,v 1.38.2.1 2002/07/23 01:51:14 gward Exp"

View file

@ -12,7 +12,7 @@ Usage example:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -34,20 +34,18 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/BoolOption.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/BoolOption.py 0.97.D001 2007/05/17 11:35:19 knight"
__all__ = ('BoolOption', 'True', 'False')
__all__ = ('BoolOption')
import string
import SCons.compat
import SCons.Errors
__true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
__false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
# we need this since SCons should work version indepentant
True, False = 1, 0
def _text2bool(val):
"""

View file

@ -15,7 +15,7 @@ Usage example:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -37,7 +37,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/EnumOption.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/EnumOption.py 0.97.D001 2007/05/17 11:35:19 knight"
__all__ = ('EnumOption',)

View file

@ -25,7 +25,7 @@ Usage example:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -47,7 +47,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/branch.96/baseline/src/engine/SCons/Options/ListOption.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/ListOption.py 0.97.D001 2007/05/17 11:35:19 knight"
# Know Bug: This should behave like a Set-Type, but does not really,
# since elements can occur twice.
@ -57,6 +57,8 @@ __all__ = ('ListOption',)
import string
import UserList
import SCons.Util
class _ListOption(UserList.UserList):
def __init__(self, initlist=[], allowedElems=[]):
@ -84,10 +86,10 @@ class _ListOption(UserList.UserList):
return 'all'
else:
return string.join(self, ',')
#def __repr__(self):
# todo: implement this
def __repr__(self):
return self.__str__()
def _converter(val, allowedElems):
def _converter(val, allowedElems, mapdict):
"""
"""
if val == 'none':
@ -96,10 +98,8 @@ def _converter(val, allowedElems):
val = allowedElems
else:
val = filter(None, string.split(val, ','))
notAllowed = []
for v in val:
if not v in allowedElems:
notAllowed.append(v)
val = map(lambda v, m=mapdict: m.get(v, v), val)
notAllowed = filter(lambda v, aE=allowedElems: not v in aE, val)
if notAllowed:
raise ValueError("Invalid value(s) for option: %s" %
string.join(notAllowed, ','))
@ -113,7 +113,7 @@ def _converter(val, allowedElems):
## return 1
def ListOption(key, help, default, names):
def ListOption(key, help, default, names, map={}):
"""
The input parameters describe a 'package list' option, thus they
are returned with the correct converter and validater appended. The
@ -123,9 +123,11 @@ def ListOption(key, help, default, names):
package names (separated by space).
"""
names_str = 'allowed names: %s' % string.join(names, ' ')
if SCons.Util.is_List(default):
default = string.join(default, ',')
help = string.join(
(help, '(all|none|comma-separated list of names)', names_str),
'\n ')
return (key, help, default,
None, #_validator,
lambda val, elems=names: _converter(val, elems))
lambda val, elems=names, m=map: _converter(val, elems, m))

View file

@ -28,7 +28,7 @@ Usage example:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -50,17 +50,17 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PackageOption.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PackageOption.py 0.97.D001 2007/05/17 11:35:19 knight"
__all__ = ('PackageOption', 'True', 'False')
__all__ = ('PackageOption')
import string
from BoolOption import True, False
import SCons.compat
import SCons.Errors
__enable_strings = (str(True), 'yes', 'true', 'on', 'enable', 'search')
__disable_strings = (str(False), 'no', 'false', 'off', 'disable')
__enable_strings = ('1', 'yes', 'true', 'on', 'enable', 'search')
__disable_strings = ('0', 'no', 'false', 'off', 'disable')
def _converter(val):
"""
@ -78,12 +78,10 @@ def _validator(key, val, env, searchfunc):
"""
# todo: write validator, check for path
import os
if env[key] == False:
pass
elif env[key] == True:
if env[key] is True:
if searchfunc:
env[key] = searchfunc(key, val)
elif not os.path.exists(val):
elif env[key] and not os.path.exists(val):
raise SCons.Errors.UserError(
'Path does not exist for option %s: %s' % (key, val))

View file

@ -0,0 +1,134 @@
"""SCons.Options.PathOption
This file defines an option type for SCons implementing path settings.
To be used whenever a a user-specified path override should be allowed.
Arguments to PathOption are:
option-name = name of this option on the command line (e.g. "prefix")
option-help = help string for option
option-dflt = default value for this option
validator = [optional] validator for option value. Predefined
validators are:
PathAccept -- accepts any path setting; no validation
PathIsDir -- path must be an existing directory
PathIsDirCreate -- path must be a dir; will create
PathIsFile -- path must be a file
PathExists -- path must exist (any type) [default]
The validator is a function that is called and which
should return True or False to indicate if the path
is valid. The arguments to the validator function
are: (key, val, env). The key is the name of the
option, the val is the path specified for the option,
and the env is the env to which the Otions have been
added.
Usage example:
Examples:
prefix=/usr/local
opts = Options()
opts = Options()
opts.Add(PathOption('qtdir',
'where the root of Qt is installed',
qtdir, PathIsDir))
opts.Add(PathOption('qt_includes',
'where the Qt includes are installed',
'$qtdir/includes', PathIsDirCreate))
opts.Add(PathOption('qt_libraries',
'where the Qt library is installed',
'$qtdir/lib'))
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PathOption.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
import SCons.Errors
class _PathOptionClass:
def PathAccept(self, key, val, env):
"""Accepts any path, no checking done."""
pass
def PathIsDir(self, key, val, env):
"""Validator to check if Path is a directory."""
if not os.path.isdir(val):
if os.path.isfile(val):
m = 'Directory path for option %s is a file: %s'
else:
m = 'Directory path for option %s does not exist: %s'
raise SCons.Errors.UserError(m % (key, val))
def PathIsDirCreate(self, key, val, env):
"""Validator to check if Path is a directory,
creating it if it does not exist."""
if os.path.isfile(val):
m = 'Path for option %s is a file, not a directory: %s'
raise SCons.Errors.UserError(m % (key, val))
if not os.path.isdir(val):
os.makedirs(val)
def PathIsFile(self, key, val, env):
"""validator to check if Path is a file"""
if not os.path.isfile(val):
if os.path.isdir(val):
m = 'File path for option %s is a directory: %s'
else:
m = 'File path for option %s does not exist: %s'
raise SCons.Errors.UserError(m % (key, val))
def PathExists(self, key, val, env):
"""validator to check if Path exists"""
if not os.path.exists(val):
m = 'Path for option %s does not exist: %s'
raise SCons.Errors.UserError(m % (key, val))
def __call__(self, key, help, default, validator=None):
# NB: searchfunc is currenty undocumented and unsupported
"""
The input parameters describe a 'path list' option, thus they
are returned with the correct converter and validator appended. The
result is usable for input to opts.Add() .
The 'default' option specifies the default path to use if the
user does not specify an override with this option.
validator is a validator, see this file for examples
"""
if validator is None:
validator = self.PathExists
return (key, '%s ( /path/to/%s )' % (help, key), default,
validator, None)
PathOption = _PathOptionClass()

View file

@ -5,7 +5,7 @@ customizable variables to an SCons build.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,15 +27,16 @@ customizable variables to an SCons build.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path
import string
import SCons.Errors
import SCons.Util
import SCons.Warnings
from BoolOption import BoolOption, True, False # okay
from BoolOption import BoolOption # okay
from EnumOption import EnumOption # okay
from ListOption import ListOption # naja
from PackageOption import PackageOption # naja
@ -75,6 +76,11 @@ class Options:
self.options.append(option)
def keys(self):
"""
Returns the keywords for the options
"""
return map(lambda o: o.key, self.options)
def Add(self, key, help="", default=None, validator=None, converter=None, **kw):
"""
@ -97,16 +103,8 @@ class Options:
not SCons.Util.is_valid_construction_var(key):
raise SCons.Errors.UserError, "Illegal Options.Add() key `%s'" % str(key)
if kw.has_key('validater'):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The 'validater' keyword of the Options.Add() method is deprecated\n" +\
"and should be changed to 'validator'.")
if validator is None:
validator = kw['validater']
self._do_add(key, help, default, validator, converter)
def AddOptions(self, *optlist):
"""
Add a list of options.
@ -164,15 +162,18 @@ class Options:
for option in self.options:
if option.converter and values.has_key(option.key):
value = env.subst('${%s}'%option.key)
try:
try:
env[option.key] = option.converter(value)
except TypeError:
env[option.key] = option.converter(value, env)
except ValueError, x:
raise SCons.Errors.UserError, 'Error converting option: %s\n%s'%(option.key, x)
# Finally validate the values:
for option in self.options:
if option.validator:
if option.validator and values.has_key(option.key):
option.validator(option.key, env.subst('${%s}'%option.key), env)
def Save(self, filename, env):
@ -203,8 +204,12 @@ class Options:
# Convert stuff that has a repr() that
# cannot be evaluated into a string
value = SCons.Util.to_String(value)
if env.subst('${%s}' % option.key) != \
env.subst(SCons.Util.to_String(option.default)):
defaultVal = env.subst(SCons.Util.to_String(option.default))
if option.converter:
defaultVal = option.converter(defaultVal)
if str(env.subst('${%s}' % option.key)) != str(defaultVal):
fh.write('%s = %s\n' % (option.key, repr(value)))
except KeyError:
pass
@ -222,19 +227,23 @@ class Options:
of the options.
"""
help_text = ""
if sort:
options = self.options[:]
options.sort(lambda x,y,func=sort: func(x.key,y.key))
else:
options = self.options
for option in options:
help_text = help_text + '\n%s: %s\n default: %s\n'%(option.key, option.help, option.default)
if env.has_key(option.key):
help_text = help_text + ' actual: %s\n'%env.subst('${%s}'%option.key)
def format(opt, self=self, env=env):
if env.has_key(opt.key):
actual = env.subst('${%s}' % opt.key)
else:
help_text = help_text + ' actual: None\n'
actual = None
return self.FormatOptionHelpText(env, opt.key, opt.help, opt.default, actual)
lines = filter(None, map(format, options))
return help_text
return string.join(lines, '')
format = '\n%s: %s\n default: %s\n actual: %s\n'
def FormatOptionHelpText(self, env, key, help, default, actual):
return self.format % (key, help, default, actual)

View file

@ -0,0 +1,226 @@
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/PathList.py 0.97.D001 2007/05/17 11:35:19 knight"
__doc__ = """SCons.PathList
A module for handling lists of directory paths (the sort of things
that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
efficiency as we can while still keeping the evaluation delayed so that we
Do the Right Thing (almost) regardless of how the variable is specified.
"""
import os
import string
import SCons.Memoize
import SCons.Node
import SCons.Util
#
# Variables to specify the different types of entries in a PathList object:
#
TYPE_STRING_NO_SUBST = 0 # string with no '$'
TYPE_STRING_SUBST = 1 # string containing '$'
TYPE_OBJECT = 2 # other object
def node_conv(obj):
"""
This is the "string conversion" routine that we have our substitutions
use to return Nodes, not strings. This relies on the fact that an
EntryProxy object has a get() method that returns the underlying
Node that it wraps, which is a bit of architectural dependence
that we might need to break or modify in the future in response to
additional requirements.
"""
try:
get = obj.get
except AttributeError:
if isinstance(obj, SCons.Node.Node):
result = obj
else:
result = str(obj)
else:
result = get()
return result
class _PathList:
"""
An actual PathList object.
"""
def __init__(self, pathlist):
"""
Initializes a PathList object, canonicalizing the input and
pre-processing it for quicker substitution later.
The stored representation of the PathList is a list of tuples
containing (type, value), where the "type" is one of the TYPE_*
variables defined above. We distinguish between:
strings that contain no '$' and therefore need no
delayed-evaluation string substitution (we expect that there
will be many of these and that we therefore get a pretty
big win from avoiding string substitution)
strings that contain '$' and therefore need substitution
(the hard case is things like '${TARGET.dir}/include',
which require re-evaluation for every target + source)
other objects (which may be something like an EntryProxy
that needs a method called to return a Node)
Pre-identifying the type of each element in the PathList up-front
and storing the type in the list of tuples is intended to reduce
the amount of calculation when we actually do the substitution
over and over for each target.
"""
if SCons.Util.is_String(pathlist):
pathlist = string.split(pathlist, os.pathsep)
elif not SCons.Util.is_Sequence(pathlist):
pathlist = [pathlist]
pl = []
for p in pathlist:
try:
index = string.find(p, '$')
except (AttributeError, TypeError):
type = TYPE_OBJECT
else:
if index == -1:
type = TYPE_STRING_NO_SUBST
else:
type = TYPE_STRING_SUBST
pl.append((type, p))
self.pathlist = tuple(pl)
def __len__(self): return len(self.pathlist)
def __getitem__(self, i): return self.pathlist[i]
def subst_path(self, env, target, source):
"""
Performs construction variable substitution on a pre-digested
PathList for a specific target and source.
"""
result = []
for type, value in self.pathlist:
if type == TYPE_STRING_SUBST:
value = env.subst(value, target=target, source=source,
conv=node_conv)
if SCons.Util.is_Sequence(value):
# It came back as a string or tuple, which in this
# case usually means some variable expanded to an
# actually Dir node. Concatenate the values.
value = string.join(map(str, value), '')
elif type == TYPE_OBJECT:
value = node_conv(value)
result.append(value)
return tuple(result)
class PathListCache:
"""
A class to handle caching of PathList lookups.
This class gets instantiated once and then deleted from the namespace,
so it's used as a Singleton (although we don't enforce that in the
usual Pythonic ways). We could have just made the cache a dictionary
in the module namespace, but putting it in this class allows us to
use the same Memoizer pattern that we use elsewhere to count cache
hits and misses, which is very valuable.
Lookup keys in the cache are computed by the _PathList_key() method.
Cache lookup should be quick, so we don't spend cycles canonicalizing
all forms of the same lookup key. For example, 'x:y' and ['x',
'y'] logically represent the same list, but we don't bother to
split string representations and treat those two equivalently.
(Note, however, that we do, treat lists and tuples the same.)
The main type of duplication we're trying to catch will come from
looking up the same path list from two different clones of the
same construction environment. That is, given
env2 = env1.Clone()
both env1 and env2 will have the same CPPPATH value, and we can
cheaply avoid re-parsing both values of CPPPATH by using the
common value from this cache.
"""
if SCons.Memoize.use_memoizer:
__metaclass__ = SCons.Memoize.Memoized_Metaclass
memoizer_counters = []
def __init__(self):
self._memo = {}
def _PathList_key(self, pathlist):
"""
Returns the key for memoization of PathLists.
Note that we want this to be pretty quick, so we don't completely
canonicalize all forms of the same list. For example,
'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically
represent the same list if you're executing from $ROOT, but
we're not going to bother splitting strings into path elements,
or massaging strings into Nodes, to identify that equivalence.
We just want to eliminate obvious redundancy from the normal
case of re-using exactly the same cloned value for a path.
"""
if SCons.Util.is_Sequence(pathlist):
pathlist = tuple(SCons.Util.flatten(pathlist))
return pathlist
memoizer_counters.append(SCons.Memoize.CountDict('PathList', _PathList_key))
def PathList(self, pathlist):
"""
Returns the cached _PathList object for the specified pathlist,
creating and caching a new object as necessary.
"""
pathlist = self._PathList_key(pathlist)
try:
memo_dict = self._memo['PathList']
except KeyError:
memo_dict = {}
self._memo['PathList'] = memo_dict
else:
try:
return memo_dict[pathlist]
except KeyError:
pass
result = _PathList(pathlist)
memo_dict[pathlist] = result
return result
PathList = PathListCache().PathList
del PathListCache

View file

@ -0,0 +1,216 @@
"""SCons.Platform
SCons platform selection.
This looks for modules that define a callable object that can modify a
construction environment as appropriate for a given platform.
Note that we take a more simplistic view of "platform" than Python does.
We're looking for a single string that determines a set of
tool-independent variables with which to initialize a construction
environment. Consequently, we'll examine both sys.platform and os.name
(and anything else that might come in to play) in order to return some
specification which is unique enough for our purposes.
Note that because this subsysem just *selects* a callable that can
modify a construction environment, it's possible for people to define
their own "platform specification" in an arbitrary callable function.
No one needs to use or tie in to this subsystem in order to roll
their own platform definition.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
import imp
import os
import string
import sys
import tempfile
import SCons.Errors
import SCons.Tool
def platform_default():
"""Return the platform string for our execution environment.
The returned value should map to one of the SCons/Platform/*.py
files. Since we're architecture independent, though, we don't
care about the machine architecture.
"""
osname = os.name
if osname == 'java':
osname = os._osType
if osname == 'posix':
if sys.platform == 'cygwin':
return 'cygwin'
elif string.find(sys.platform, 'irix') != -1:
return 'irix'
elif string.find(sys.platform, 'sunos') != -1:
return 'sunos'
elif string.find(sys.platform, 'hp-ux') != -1:
return 'hpux'
elif string.find(sys.platform, 'aix') != -1:
return 'aix'
elif string.find(sys.platform, 'darwin') != -1:
return 'darwin'
else:
return 'posix'
elif os.name == 'os2':
return 'os2'
else:
return sys.platform
def platform_module(name = platform_default()):
"""Return the imported module for the platform.
This looks for a module name that matches the specified argument.
If the name is unspecified, we fetch the appropriate default for
our execution environment.
"""
full_name = 'SCons.Platform.' + name
if not sys.modules.has_key(full_name):
if os.name == 'java':
eval(full_name)
else:
try:
file, path, desc = imp.find_module(name,
sys.modules['SCons.Platform'].__path__)
try:
mod = imp.load_module(full_name, file, path, desc)
finally:
if file:
file.close()
except ImportError:
try:
import zipimport
importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] )
mod = importer.load_module(full_name)
except ImportError:
raise SCons.Errors.UserError, "No platform named '%s'" % name
setattr(SCons.Platform, name, mod)
return sys.modules[full_name]
def DefaultToolList(platform, env):
"""Select a default tool list for the specified platform.
"""
return SCons.Tool.tool_list(platform, env)
class PlatformSpec:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class TempFileMunge:
"""A callable class. You can set an Environment variable to this,
then call it with a string argument, then it will perform temporary
file substitution on it. This is used to circumvent the long command
line limitation.
Example usage:
env["TEMPFILE"] = TempFileMunge
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES')}"
By default, the name of the temporary file used begins with a
prefix of '@'. This may be configred for other tool chains by
setting '$TEMPFILEPREFIX'.
env["TEMPFILEPREFIX"] = '-@' # diab compiler
env["TEMPFILEPREFIX"] = '-via' # arm tool chain
"""
def __init__(self, cmd):
self.cmd = cmd
def __call__(self, target, source, env, for_signature):
if for_signature:
return self.cmd
cmd = env.subst_list(self.cmd, 0, target, source)[0]
try:
maxline = int(env.subst('$MAXLINELENGTH'))
except ValueError:
maxline = 2048
if (reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)) <= maxline:
return self.cmd
# We do a normpath because mktemp() has what appears to be
# a bug in Windows that will use a forward slash as a path
# delimiter. Windows's link mistakes that for a command line
# switch and barfs.
#
# We use the .lnk suffix for the benefit of the Phar Lap
# linkloc linker, which likes to append an .lnk suffix if
# none is given.
tmp = os.path.normpath(tempfile.mktemp('.lnk'))
native_tmp = SCons.Util.get_native_path(tmp)
if env['SHELL'] and env['SHELL'] == 'sh':
# The sh shell will try to escape the backslashes in the
# path, so unescape them.
native_tmp = string.replace(native_tmp, '\\', r'\\\\')
# In Cygwin, we want to use rm to delete the temporary
# file, because del does not exist in the sh shell.
rm = env.Detect('rm') or 'del'
else:
# Don't use 'rm' if the shell is not sh, because rm won't
# work with the Windows shells (cmd.exe or command.com) or
# Windows path names.
rm = 'del'
prefix = env.subst('$TEMPFILEPREFIX')
if not prefix:
prefix = '@'
args = map(SCons.Subst.quote_spaces, cmd[1:])
open(tmp, 'w').write(string.join(args, " ") + "\n")
# XXX Using the SCons.Action.print_actions value directly
# like this is bogus, but expedient. This class should
# really be rewritten as an Action that defines the
# __call__() and strfunction() methods and lets the
# normal action-execution logic handle whether or not to
# print/execute the action. The problem, though, is all
# of that is decided before we execute this method as
# part of expanding the $TEMPFILE construction variable.
# Consequently, refactoring this will have to wait until
# we get more flexible with allowing Actions to exist
# independently and get strung together arbitrarily like
# Ant tasks. In the meantime, it's going to be more
# user-friendly to not let obsession with architectural
# purity get in the way of just being helpful, so we'll
# reach into SCons.Action directly.
if SCons.Action.print_actions:
print("Using tempfile "+native_tmp+" for command line:\n"+
str(cmd[0]) + " " + string.join(args," "))
return [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
def Platform(name = platform_default()):
"""Select a canned Platform specification.
"""
module = platform_module(name)
spec = PlatformSpec(name)
spec.__call__ = module.generate
return spec

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,20 +30,23 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/aix.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/aix.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import string
import posix
def get_xlc(env, xlc, xlc_r, packages):
def get_xlc(env, xlc=None, xlc_r=None, packages=[]):
# Use the AIX package installer tool lslpp to figure out where a
# given xl* compiler is installed and what version it is.
xlcPath = None
xlcVersion = None
if xlc is None:
xlc = env.get('CC', 'xlc')
if xlc_r is None:
xlc_r = xlc + '_r'
for package in packages:
cmd = "lslpp -fc " + package + " 2>/dev/null | egrep '" + xlc + "([^-_a-zA-Z0-9].*)?$'"
line = os.popen(cmd).readline()
@ -57,3 +60,6 @@ def get_xlc(env, xlc, xlc_r, packages):
def generate(env):
posix.generate(env)
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
env['MAXLINELENGTH'] = 21576

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,10 +30,10 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/cygwin.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/cygwin.py 0.97.D001 2007/05/17 11:35:19 knight"
import posix
import win32
from SCons.Platform import TempFileMunge
def generate(env):
posix.generate(env)
@ -44,4 +44,6 @@ def generate(env):
env['SHLIBSUFFIX'] = '.dll'
env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX' ]
env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
env['TEMPFILE'] = win32.TempFileMunge
env['TEMPFILE'] = TempFileMunge
env['TEMPFILEPREFIX'] = '@'
env['MAXLINELENGTH'] = 2048

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,11 +30,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/darwin.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/darwin.py 0.97.D001 2007/05/17 11:35:19 knight"
import posix
import os
def generate(env):
posix.generate(env)
env['SHLIBSUFFIX'] = '.dylib'
env['ENV']['PATH'] = env['ENV']['PATH'] + ':/sw/bin'

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,9 +30,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/hpux.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/hpux.py 0.97.D001 2007/05/17 11:35:19 knight"
import posix
def generate(env):
posix.generate(env)
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
env['MAXLINELENGTH'] = 2045000

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/irix.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/irix.py 0.97.D001 2007/05/17 11:35:19 knight"
import posix

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/os2.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/os2.py 0.97.D001 2007/05/17 11:35:19 knight"
def generate(env):
if not env.has_key('ENV'):

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/posix.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/posix.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
@ -40,6 +40,7 @@ import sys
import select
import SCons.Util
from SCons.Platform import TempFileMunge
exitvalmap = {
2 : 127,
@ -57,42 +58,28 @@ def escape(arg):
return '"' + arg + '"'
def _get_env_command(sh, escape, cmd, args, env):
if env:
s = 'env - '
for key in env.keys():
s = s + '%s=%s '%(key, escape(env[key]))
s = s + sh + ' -c '
s = s + escape(string.join(args))
else:
s = string.join(args)
return s
def env_spawn(sh, escape, cmd, args, env):
s = _get_env_command( sh, escape, cmd, args, env)
stat = os.system(s)
def exec_system(l, env):
stat = os.system(string.join(l))
if stat & 0xff:
return stat | 0x80
return stat >> 8
def spawn_spawn(sh, escape, cmd, args, env):
args = [sh, '-c', string.join(args)]
stat = os.spawnvpe(os.P_WAIT, sh, args, env)
def exec_spawnvpe(l, env):
stat = os.spawnvpe(os.P_WAIT, l[0], l, env)
# os.spawnvpe() returns the actual exit code, not the encoding
# returned by os.waitpid() or os.system().
return stat
def fork_spawn(sh, escape, cmd, args, env):
def exec_fork(l, env):
pid = os.fork()
if not pid:
# Child process.
exitval = 127
args = [sh, '-c', string.join(args)]
try:
os.execvpe(sh, args, env)
os.execvpe(l[0], l, env)
except OSError, e:
exitval = exitvalmap[e[0]]
sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
exitval = exitvalmap.get(e[0], e[0])
sys.stderr.write("scons: %s: %s\n" % (l[0], e[1]))
os._exit(exitval)
else:
# Parent process.
@ -101,6 +88,24 @@ def fork_spawn(sh, escape, cmd, args, env):
return stat | 0x80
return stat >> 8
def _get_env_command(sh, escape, cmd, args, env):
s = string.join(args)
if env:
l = ['env', '-'] + \
map(lambda t, e=escape: t[0]+'='+e(t[1]), env.items()) + \
[sh, '-c', escape(s)]
s = string.join(l)
return s
def env_spawn(sh, escape, cmd, args, env):
return exec_system([_get_env_command( sh, escape, cmd, args, env)], env)
def spawnvpe_spawn(sh, escape, cmd, args, env):
return exec_spawnvpe([sh, '-c', string.join(args)], env)
def fork_spawn(sh, escape, cmd, args, env):
return exec_fork([sh, '-c', string.join(args)], env)
def process_cmd_output(cmd_stdout, cmd_stderr, stdout, stderr):
stdout_eof = stderr_eof = 0
while not (stdout_eof and stderr_eof):
@ -120,20 +125,15 @@ def process_cmd_output(cmd_stdout, cmd_stderr, stdout, stderr):
#sys.__stderr__.write( "str(stderr) = %s\n" % str )
stderr.write(str)
def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr):
# spawn using Popen3 combined with the env command
# the command name and the command's stdout is written to stdout
# the command's stderr is written to stderr
s = _get_env_command( sh, escape, cmd, args, env)
proc = popen2.Popen3(s, 1)
def exec_popen3(l, env, stdout, stderr):
proc = popen2.Popen3(string.join(l), 1)
process_cmd_output(proc.fromchild, proc.childerr, stdout, stderr)
stat = proc.wait()
if stat & 0xff:
return stat | 0x80
return stat >> 8
def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr):
def exec_piped_fork(l, env, stdout, stderr):
# spawn using fork / exec and providing a pipe for the command's
# stdout / stderr stream
if stdout != stderr:
@ -156,12 +156,11 @@ def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr):
if stdout != stderr:
os.close( wFdErr )
exitval = 127
args = [sh, '-c', string.join(args)]
try:
os.execvpe(sh, args, env)
os.execvpe(l[0], l, env)
except OSError, e:
exitval = exitvalmap[e[0]]
stderr.write("scons: %s: %s\n" % (cmd, e[1]))
exitval = exitvalmap.get(e[0], e[0])
stderr.write("scons: %s: %s\n" % (l[0], e[1]))
os._exit(exitval)
else:
# Parent process
@ -182,6 +181,19 @@ def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr):
return stat | 0x80
return stat >> 8
def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr):
# spawn using Popen3 combined with the env command
# the command name and the command's stdout is written to stdout
# the command's stderr is written to stderr
return exec_popen3([_get_env_command(sh, escape, cmd, args, env)],
env, stdout, stderr)
def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr):
# spawn using fork / exec and providing a pipe for the command's
# stdout / stderr stream
return exec_piped_fork([sh, '-c', string.join(args)],
env, stdout, stderr)
def generate(env):
@ -199,7 +211,7 @@ def generate(env):
# not be a default that works best for all users.
if os.__dict__.has_key('spawnvpe'):
spawn = spawn_spawn
spawn = spawnvpe_spawn
elif env.Detect('env'):
spawn = env_spawn
else:
@ -212,7 +224,7 @@ def generate(env):
if not env.has_key('ENV'):
env['ENV'] = {}
env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'
env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin'
env['OBJPREFIX'] = ''
env['OBJSUFFIX'] = '.o'
env['SHOBJPREFIX'] = '$OBJPREFIX'
@ -229,6 +241,11 @@ def generate(env):
env['SPAWN'] = spawn
env['SHELL'] = 'sh'
env['ESCAPE'] = escape
env['TEMPFILE'] = TempFileMunge
env['TEMPFILEPREFIX'] = '@'
#Based on LINUX: ARG_MAX=ARG_MAX=131072 - 3000 for environment expansion
#Note: specific platforms might rise or lower this value
env['MAXLINELENGTH'] = 128072
# This platform supports RPATH specifications.
env['__RPATH'] = '$_RPATH'

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,9 +30,15 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/sunos.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/sunos.py 0.97.D001 2007/05/17 11:35:19 knight"
import posix
def generate(env):
posix.generate(env)
# Based on sunSparc 8:32bit
# ARG_MAX=1048320 - 3000 for environment expansion
env['MAXLINELENGTH'] = 1045320
env['PKGINFO'] = 'pkginfo'
env['PKGCHK'] = '/usr/sbin/pkgchk'
env['ENV']['PATH'] = env['ENV']['PATH'] + ':/usr/ccs/bin'

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,89 +30,22 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/win32.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/win32.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
import string
import sys
import tempfile
from SCons.Platform.posix import exitvalmap
from SCons.Platform import TempFileMunge
# XXX See note below about why importing SCons.Action should be
# eventually refactored.
import SCons.Action
import SCons.Util
class TempFileMunge:
"""A callable class. You can set an Environment variable to this,
then call it with a string argument, then it will perform temporary
file substitution on it. This is used to circumvent the win32 long command
line limitation.
Example usage:
env["TEMPFILE"] = TempFileMunge
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES')}"
"""
def __init__(self, cmd):
self.cmd = cmd
def __call__(self, target, source, env, for_signature):
if for_signature:
return self.cmd
cmd = env.subst_list(self.cmd, 0, target, source)[0]
try:
maxline = int(env.subst('$MAXLINELENGTH'))
except ValueError:
maxline = 2048
if (reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)) <= maxline:
return self.cmd
else:
# We do a normpath because mktemp() has what appears to be
# a bug in Win32 that will use a forward slash as a path
# delimiter. Win32's link mistakes that for a command line
# switch and barfs.
#
# We use the .lnk suffix for the benefit of the Phar Lap
# linkloc linker, which likes to append an .lnk suffix if
# none is given.
tmp = os.path.normpath(tempfile.mktemp('.lnk'))
native_tmp = SCons.Util.get_native_path(tmp)
if env['SHELL'] and env['SHELL'] == 'sh':
# The sh shell will try to escape the backslashes in the
# path, so unescape them.
native_tmp = string.replace(native_tmp, '\\', r'\\\\')
# In Cygwin, we want to use rm to delete the temporary
# file, because del does not exist in the sh shell.
rm = env.Detect('rm') or 'del'
else:
# Don't use 'rm' if the shell is not sh, because rm won't
# work with the win32 shells (cmd.exe or command.com) or
# win32 path names.
rm = 'del'
args = map(SCons.Util.quote_spaces, cmd[1:])
open(tmp, 'w').write(string.join(args, " ") + "\n")
# XXX Using the SCons.Action.print_actions value directly
# like this is bogus, but expedient. This class should
# really be rewritten as an Action that defines the
# __call__() and strfunction() methods and lets the
# normal action-execution logic handle whether or not to
# print/execute the action. The problem, though, is all
# of that is decided before we execute this method as
# part of expanding the $TEMPFILE construction variable.
# Consequently, refactoring this will have to wait until
# we get more flexible with allowing Actions to exist
# independently and get strung together arbitrarily like
# Ant tasks. In the meantime, it's going to be more
# user-friendly to not let obsession with architectural
# purity get in the way of just being helpful, so we'll
# reach into SCons.Action directly.
if SCons.Action.print_actions:
print("Using tempfile "+native_tmp+" for command line:\n"+
str(cmd[0]) + " " + string.join(args," "))
return [ cmd[0], '@' + native_tmp + '\n' + rm, native_tmp ]
# The upshot of all this is that, if you are using Python 1.5.2,
# you had better have cmd or command.com in your PATH when you run
@ -157,7 +90,10 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
ret = os.spawnve(os.P_WAIT, sh, args, env)
except OSError, e:
# catch any error
try:
ret = exitvalmap[e[0]]
except KeyError:
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1]))
if stderr != None:
stderr.write("scons: %s: %s\n" % (cmd, e[1]))
# copy child output from tempfiles to our streams
@ -177,22 +113,40 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
pass
return ret
def exec_spawn(l, env):
try:
result = os.spawnve(os.P_WAIT, l[0], l, env)
except OSError, e:
try:
result = exitvalmap[e[0]]
sys.stderr.write("scons: %s: %s\n" % (l[0], e[1]))
except KeyError:
result = 127
if len(l) > 2:
if len(l[2]) < 1000:
command = string.join(l[0:3])
else:
command = l[0]
else:
command = l[0]
sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e[0], command, e[1]))
return result
def spawn(sh, escape, cmd, args, env):
if not sh:
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
return 127
else:
try:
args = [sh, '/C', escape(string.join(args)) ]
ret = os.spawnve(os.P_WAIT, sh, args, env)
except OSError, e:
ret = exitvalmap[e[0]]
sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
return ret
return exec_spawn([sh, '/C', escape(string.join(args))], env)
# Windows does not allow special characters in file names anyway, so
# no need for a complex escape function, we will just quote the arg.
escape = lambda x: '"' + x + '"'
# Windows does not allow special characters in file names anyway, so no
# need for a complex escape function, we will just quote the arg, except
# that "cmd /c" requires that if an argument ends with a backslash it
# needs to be escaped so as not to interfere with closing double quote
# that we add.
def escape(x):
if x[-1] == '\\':
x = x + '\\'
return '"' + x + '"'
# Get the windows system directory name
def get_system_root():
@ -298,9 +252,11 @@ def generate(env):
# environment's ENV. This is a potential slippery slope, because we
# *don't* want to make builds dependent on the user's environment by
# default. We're doing this for SYSTEMROOT, though, because it's
# needed for anything that uses sockets, and seldom changes. Weigh
# the impact carefully before adding other variables to this list.
import_env = [ 'SYSTEMROOT' ]
# needed for anything that uses sockets, and seldom changes, and
# for SYSTEMDRIVE because it's related.
#
# Weigh the impact carefully before adding other variables to this list.
import_env = [ 'SYSTEMDRIVE', 'SYSTEMROOT', 'TEMP', 'TMP' ]
for var in import_env:
v = os.environ.get(var)
if v:
@ -323,5 +279,6 @@ def generate(env):
env['SPAWN'] = spawn
env['SHELL'] = cmd_interp
env['TEMPFILE'] = TempFileMunge
env['TEMPFILEPREFIX'] = '@'
env['MAXLINELENGTH'] = 2048
env['ESCAPE'] = escape

View file

@ -4,7 +4,7 @@ Autoconf-like configuration support.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -26,11 +26,12 @@ Autoconf-like configuration support.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConf.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConf.py 0.97.D001 2007/05/17 11:35:19 knight"
import cPickle
import os
import re
import string
import StringIO
import sys
import traceback
import types
@ -38,41 +39,286 @@ import types
import SCons.Action
import SCons.Builder
import SCons.Errors
import SCons.Job
import SCons.Node.FS
import SCons.Taskmaster
import SCons.Util
import SCons.Warnings
import SCons.Conftest
# First i thought of using a different filesystem as the default_fs,
# but it showed up that there are too many side effects in doing that.
SConfFS=SCons.Node.FS.default_fs
# Turn off the Conftest error logging
SCons.Conftest.LogInputFiles = 0
SCons.Conftest.LogErrorMessages = 0
# to be set, if we are in dry-run mode
dryrun = 0
_ac_build_counter = 0
_ac_config_counter = 0
_activeSConfObjects = {}
AUTO=0 # use SCons dependency scanning for up-to-date checks
FORCE=1 # force all tests to be rebuilt
CACHE=2 # force all tests to be taken from cache (raise an error, if necessary)
cache_mode = AUTO
def SetCacheMode(mode):
"""Set the Configure cache mode. mode must be one of "auto", "force",
or "cache"."""
global cache_mode
if mode == "auto":
cache_mode = AUTO
elif mode == "force":
cache_mode = FORCE
elif mode == "cache":
cache_mode = CACHE
else:
raise ValueError, "SCons.SConf.SetCacheMode: Unknown mode " + mode
progress_display = SCons.Util.display # will be overwritten by SCons.Script
def SetProgressDisplay(display):
"""Set the progress display to use (called from SCons.Script)"""
global progress_display
progress_display = display
SConfFS = None
_ac_build_counter = 0 # incremented, whenever TryBuild is called
_ac_config_logs = {} # all config.log files created in this build
_ac_config_hs = {} # all config.h files created in this build
sconf_global = None # current sconf object
def _createConfigH(target, source, env):
t = open(str(target[0]), "w")
defname = re.sub('[^A-Za-z0-9_]', '_', string.upper(str(target[0])))
t.write("""#ifndef %(DEFNAME)s_SEEN
#define %(DEFNAME)s_SEEN
""" % {'DEFNAME' : defname})
t.write(source[0].get_contents())
t.write("""
#endif /* %(DEFNAME)s_SEEN */
""" % {'DEFNAME' : defname})
t.close()
def _stringConfigH(target, source, env):
return "scons: Configure: creating " + str(target[0])
def CreateConfigHBuilder(env):
"""Called just before the building targets phase begins."""
if len(_ac_config_hs) == 0:
return
action = SCons.Action.Action(_createConfigH,
_stringConfigH)
sconfigHBld = SCons.Builder.Builder(action=action)
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
for k in _ac_config_hs.keys():
env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
class SConfWarning(SCons.Warnings.Warning):
pass
SCons.Warnings.enableWarningClass( SConfWarning )
SCons.Warnings.enableWarningClass(SConfWarning)
# action to create the source
# some error definitions
class SConfError(SCons.Errors.UserError):
def __init__(self,msg):
SCons.Errors.UserError.__init__(self,msg)
class ConfigureDryRunError(SConfError):
"""Raised when a file or directory needs to be updated during a Configure
process, but the user requested a dry-run"""
def __init__(self,target):
if not isinstance(target, SCons.Node.FS.File):
msg = 'Cannot create configure directory "%s" within a dry-run.' % str(target)
else:
msg = 'Cannot update configure test "%s" within a dry-run.' % str(target)
SConfError.__init__(self,msg)
class ConfigureCacheError(SConfError):
"""Raised when a use explicitely requested the cache feature, but the test
is run the first time."""
def __init__(self,target):
SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
# define actions for building text files
def _createSource( target, source, env ):
fd = open(str(target[0]), "w")
fd.write(env['SCONF_TEXT'])
fd.write(source[0].get_contents())
fd.close()
def _stringSource( target, source, env ):
import string
return (str(target[0]) + ' <- \n |' +
string.replace( env['SCONF_TEXT'], "\n", "\n |" ) )
return (str(target[0]) + ' <-\n |' +
string.replace( source[0].get_contents(),
'\n', "\n |" ) )
# python 2.2 introduces types.BooleanType
BooleanTypes = [types.IntType]
if hasattr(types, 'BooleanType'): BooleanTypes.append(types.BooleanType)
class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
"""
Special build info for targets of configure tests. Additional members
are result (did the builder succeed last time?) and string, which
contains messages of the original build phase.
"""
result = None # -> 0/None -> no error, != 0 error
string = None # the stdout / stderr output when building the target
def __init__(self, node, result, string, sig):
SCons.Node.FS.FileBuildInfo.__init__(self, node)
self.result = result
self.string = string
self.ninfo.bsig = sig
class Streamer:
"""
'Sniffer' for a file-like writable object. Similar to the unix tool tee.
"""
def __init__(self, orig):
self.orig = orig
self.s = StringIO.StringIO()
def write(self, str):
if self.orig:
self.orig.write(str)
self.s.write(str)
def writelines(self, lines):
for l in lines:
self.write(l + '\n')
def getvalue(self):
"""
Return everything written to orig since the Streamer was created.
"""
return self.s.getvalue()
def flush(self):
if self.orig:
self.orig.flush()
self.s.flush()
class SConfBuildTask(SCons.Taskmaster.Task):
"""
This is almost the same as SCons.Script.BuildTask. Handles SConfErrors
correctly and knows about the current cache_mode.
"""
def display(self, message):
if sconf_global.logstream:
sconf_global.logstream.write("scons: Configure: " + message + "\n")
def display_cached_string(self, bi):
"""
Logs the original builder messages, given the SConfBuildInfo instance
bi.
"""
if not isinstance(bi, SConfBuildInfo):
SCons.Warnings.warn(SConfWarning,
"The stored build information has an unexpected class.")
else:
self.display("The original builder output was:\n" +
string.replace(" |" + str(bi.string),
"\n", "\n |"))
def failed(self):
# check, if the reason was a ConfigureDryRunError or a
# ConfigureCacheError and if yes, reraise the exception
exc_type = self.exc_info()[0]
if issubclass(exc_type, SConfError):
raise
elif issubclass(exc_type, SCons.Errors.BuildError):
# we ignore Build Errors (occurs, when a test doesn't pass)
pass
else:
self.display('Caught exception while building "%s":\n' %
self.targets[0])
try:
excepthook = sys.excepthook
except AttributeError:
# Earlier versions of Python don't have sys.excepthook...
def excepthook(type, value, tb):
traceback.print_tb(tb)
print type, value
apply(excepthook, self.exc_info())
return SCons.Taskmaster.Task.failed(self)
def collect_node_states(self):
# returns (is_up_to_date, cached_error, cachable)
# where is_up_to_date is 1, if the node(s) are up_to_date
# cached_error is 1, if the node(s) are up_to_date, but the
# build will fail
# cachable is 0, if some nodes are not in our cache
is_up_to_date = 1
cached_error = 0
cachable = 1
for t in self.targets:
bi = t.get_stored_info()
if isinstance(bi, SConfBuildInfo):
if cache_mode == CACHE:
t.set_state(SCons.Node.up_to_date)
else:
new_bsig = t.calc_signature(sconf_global.calc)
if t.env.use_build_signature():
old_bsig = bi.ninfo.bsig
else:
old_bsig = bi.ninfo.csig
is_up_to_date = (is_up_to_date and new_bsig == old_bsig)
cached_error = cached_error or bi.result
else:
# the node hasn't been built in a SConf context or doesn't
# exist
cachable = 0
is_up_to_date = 0
return (is_up_to_date, cached_error, cachable)
def execute(self):
sconf = sconf_global
is_up_to_date, cached_error, cachable = self.collect_node_states()
if cache_mode == CACHE and not cachable:
raise ConfigureCacheError(self.targets[0])
elif cache_mode == FORCE:
is_up_to_date = 0
if cached_error and is_up_to_date:
self.display("Building \"%s\" failed in a previous run and all "
"its sources are up to date." % str(self.targets[0]))
self.display_cached_string(self.targets[0].get_stored_info())
raise SCons.Errors.BuildError # will be 'caught' in self.failed
elif is_up_to_date:
self.display("\"%s\" is up to date." % str(self.targets[0]))
self.display_cached_string(self.targets[0].get_stored_info())
elif dryrun:
raise ConfigureDryRunError(self.targets[0])
else:
# note stdout and stderr are the same here
s = sys.stdout = sys.stderr = Streamer(sys.stdout)
try:
env = self.targets[0].get_build_env()
env['PSTDOUT'] = env['PSTDERR'] = s
try:
sconf.cached = 0
self.targets[0].build()
finally:
sys.stdout = sys.stderr = env['PSTDOUT'] = \
env['PSTDERR'] = sconf.logstream
except KeyboardInterrupt:
raise
except SystemExit:
exc_value = sys.exc_info()[1]
raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code)
except:
for t in self.targets:
sig = t.calc_signature(sconf.calc)
string = s.getvalue()
binfo = SConfBuildInfo(t,1,string,sig)
t.dir.sconsign().set_entry(t.name, binfo)
raise
else:
for t in self.targets:
sig = t.calc_signature(sconf.calc)
string = s.getvalue()
binfo = SConfBuildInfo(t,0,string,sig)
t.dir.sconsign().set_entry(t.name, binfo)
class SConf:
"""This is simply a class to represent a configure context. After
creating a SConf object, you can call any tests. After finished with your
@ -86,30 +332,29 @@ class SConf:
SConf run, we need to explicitely cache this error.
"""
def __init__(self, env, custom_tests = {}, conf_dir='#/.sconf_temp',
log_file='#/config.log'):
def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR',
log_file='$CONFIGURELOG', config_h = None, _depth = 0):
"""Constructor. Pass additional tests in the custom_tests-dictinary,
e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
defines a custom test.
Note also the conf_dir and log_file arguments (you may want to
build tests in the BuildDir, not in the SourceDir)
"""
import SCons.Script.SConscript
if not SCons.Script.SConscript.sconscript_reading:
raise SCons.Errors.UserError, "Calling Configure from Builders is not supported."
global SConfFS
if not SConfFS:
SConfFS = SCons.Node.FS.FS(SCons.Node.FS.default_fs.pathTop)
if len(_activeSConfObjects.keys()) > 0:
SConfFS = SCons.Node.FS.default_fs or \
SCons.Node.FS.FS(env.fs.pathTop)
if not sconf_global is None:
raise (SCons.Errors.UserError,
"Only one SConf object may be active at one time")
self.env = env
if log_file != None:
self.logfile = SConfFS.File(log_file)
else:
self.logfile = None
log_file = SConfFS.File(env.subst(log_file))
self.logfile = log_file
self.logstream = None
self.lastTarget = None
self.depth = _depth
self.cached = 0 # will be set, if all test results are cached
# add default tests
default_tests = {
@ -123,83 +368,24 @@ class SConf:
}
self.AddTests(default_tests)
self.AddTests(custom_tests)
self.confdir = SConfFS.Dir(conf_dir)
self.confdir = SConfFS.Dir(env.subst(conf_dir))
self.calc = None
self.cache = {}
if not config_h is None:
config_h = SConfFS.File(config_h)
self.config_h = config_h
self._startup()
def Finish(self):
"""Call this method after finished with your tests:
env = sconf.Finish()"""
global _lastSConfObj
_lastSConfObj = None
self._shutdown()
return self.env
def _setCache(self, nodes, already_done = []):
# Set up actions used for caching errors
# Caching positive tests should not be necessary, cause
# the build system knows, if test objects/programs/outputs
# are up to date.
for n in nodes:
# The 'n in already_done' expression is not really efficient.
# We may do something more sophisticated in the future :-),
# but there should not be that many dependencies in configure
# tests
if (n.has_builder() and
not n in already_done):
n.add_pre_action(SCons.Action.Action(self._preCache,
self._stringCache))
n.add_post_action(SCons.Action.Action(self._postCache,
self._stringCache))
already_done.append( n )
self._setCache(n.children())
# Calling children() has set up the implicit cache (and
# other state), but we're not really building things yet,
# so generated files won't have been generated. Clear the
# state so we will, in fact, build everything that's necessary
# when we do the build.
#
# XXX - it would be good to find a better way to do this,
# maybe by doing something with the actions in the actual
# Taskmaster...?
n.clear()
def BuildNodes(self, nodes):
"""
Tries to build the given nodes immediately. Returns 1 on success,
0 on error.
"""
global SCons
import SCons.Script # really ugly, but we need BuildTask :-(
# Is it better to provide a seperate Task for SConf builds ?
class SConfBuildTask(SCons.Script.BuildTask):
"""Errors in SConf builds are not fatal, so we override
the do_failed method"""
def do_failed(self, status=2):
pass
class SConfDryRunTask(SConfBuildTask):
"""Raise ConfiugreDryRunErrors whenever a target is to
be built. Pass these Errors to the main script."""
def execute(self):
target = self.targets[0]
if (target.get_state() != SCons.Node.up_to_date and
target.has_builder() and
not hasattr(target.builder, 'status')):
raise SCons.Errors.ConfigureDryRunError(target)
def failed(self):
exc_type, exc_value = self.exc_info()[:2]
if exc_type == SCons.Errors.ConfigureDryRunError:
raise exc_type, exc_value
# Should be SConfBuildTask.failed(), really,
# but that causes name errors in Python 1.5.2.
SCons.Script.BuildTask.failed(self)
if self.logstream != None:
# override stdout / stderr to write in log file
oldStdout = sys.stdout
@ -212,26 +398,16 @@ class SConf:
old_os_dir = os.getcwd()
SConfFS.chdir(SConfFS.Top, change_os_dir=1)
self._setCache( nodes )
ret = 1
try:
# ToDo: use user options for calc
self.calc = SCons.Sig.Calculator(max_drift=0)
if dryrun:
buildTask = SConfDryRunTask
else:
buildTask = SConfBuildTask
tm = SCons.Taskmaster.Taskmaster( nodes, buildTask )
save_max_drift = SConfFS.get_max_drift()
SConfFS.set_max_drift(0)
tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask)
# we don't want to build tests in parallel
jobs = SCons.Job.Jobs(1, tm )
try:
jobs.run()
except SCons.Errors.BuildError, e:
sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
if e.errstr == 'Exception':
traceback.print_exception(e.args[0], e.args[1], e.args[2])
for n in nodes:
state = n.get_state()
if (state != SCons.Node.executed and
@ -239,6 +415,7 @@ class SConf:
# the node could not be built. we return 0 in this case
ret = 0
finally:
SConfFS.set_max_drift(save_max_drift)
os.chdir(old_os_dir)
SConfFS.chdir(old_fs_dir, change_os_dir=0)
if self.logstream != None:
@ -247,6 +424,18 @@ class SConf:
sys.stderr = oldStderr
return ret
def pspawn_wrapper(self, sh, escape, cmd, args, env):
"""Wrapper function for handling piped spawns.
This looks to the calling interface (in Action.py) like a "normal"
spawn, but associates the call with the PSPAWN variable from
the construction environment and with the streams to which we
want the output logged. This gets slid into the construction
environment as the SPAWN variable so Action.py doesn't have to
know or care whether it's spawning a piped command or not.
"""
return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream)
def TryBuild(self, builder, text = None, extension = ""):
"""Low level TryBuild implementation. Normally you don't need to
@ -254,21 +443,36 @@ class SConf:
"""
global _ac_build_counter
# Make sure we have a PSPAWN value, and save the current
# SPAWN value.
try:
self.pspawn = self.env['PSPAWN']
except KeyError:
raise SCons.Errors.UserError('Missing PSPAWN construction variable.')
try:
save_spawn = self.env['SPAWN']
except KeyError:
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
nodesToBeBuilt = []
f = "conftest_" + str(_ac_build_counter)
pref = self.env.subst( builder.builder.prefix )
suff = self.env.subst( builder.builder.suffix )
target = self.confdir.File(pref + f + suff)
self.env['SCONF_TEXT'] = text
self.env['PIPE_BUILD'] = 1
self.env['PSTDOUT'] = self.logstream
self.env['PSTDERR'] = self.logstream
try:
# Slide our wrapper into the construction environment as
# the SPAWN function.
self.env['SPAWN'] = self.pspawn_wrapper
sourcetext = self.env.Value(text)
if text != None:
source = self.confdir.File(f + extension)
sourceNode = self.env.SConfSourceBuilder(target=source,
source=None)
nodesToBeBuilt.extend(sourceNode)
textFile = self.confdir.File(f + extension)
textFileNode = self.env.SConfSourceBuilder(target=textFile,
source=sourcetext)
nodesToBeBuilt.extend(textFileNode)
source = textFileNode
else:
source = None
@ -276,21 +480,18 @@ class SConf:
if not SCons.Util.is_List(nodes):
nodes = [nodes]
nodesToBeBuilt.extend(nodes)
ret = self.BuildNodes(nodesToBeBuilt)
result = self.BuildNodes(nodesToBeBuilt)
# clean up environment
del self.env['PIPE_BUILD']
del self.env['PSTDOUT']
del self.env['PSTDERR']
del self.env['SCONF_TEXT']
finally:
self.env['SPAWN'] = save_spawn
_ac_build_counter = _ac_build_counter + 1
if ret:
if result:
self.lastTarget = nodes[0]
else:
self.lastTarget = None
return ret
return result
def TryAction(self, action, text = None, extension = ""):
"""Tries to execute the given action with optional source file
@ -352,6 +553,8 @@ class SConf:
"Test called after sconf.Finish()")
context = CheckContext(self.sconf)
ret = apply(self.test, (context,) + args, kw)
if not self.sconf.config_h is None:
self.sconf.config_h_text = self.sconf.config_h_text + context.config_h
context.Result("error: no result")
return ret
@ -367,75 +570,11 @@ class SConf:
for name in tests.keys():
self.AddTest(name, tests[name])
def _preCache(self, target, source, env):
# Action before target is actually built
#
# We record errors in the cache. Only non-exisiting targets may
# have recorded errors
needs_rebuild = target[0].exists()
buildSig = target[0].calc_signature(self.calc)
for node in source:
if node.get_state() != SCons.Node.up_to_date:
# if any of the sources has changed, we cannot use our cache
needs_rebuild = 1
tname = str(target[0])
if not self.cache.has_key( tname ):
# We have no recorded error, so we try to build the target
needs_rebuild = 1
else:
lastBuildSig = self.cache[tname]['builder']
if lastBuildSig != buildSig:
needs_rebuild = 1
if not needs_rebuild:
# When we are here, we can savely pass the recorded error
print ('(cached): Building "%s" failed in a previous run.' %
target[0])
return 1
else:
# Otherwise, we try to record an error
self.cache[tname] = {
'builder' : buildSig
}
def _postCache(self, target, source, env):
# Action after target is successfully built
#
# No error during build -> remove the recorded error
del self.cache[str(target[0])]
def _stringCache(self, target, source, env):
return None
def _loadCache(self):
# try to load build-error cache
try:
cacheDesc = cPickle.load(open(str(self.confdir.File(".cache"))))
if cacheDesc['scons_version'] != SCons.__version__:
raise Exception, "version mismatch"
self.cache = cacheDesc['data']
except KeyboardInterrupt:
raise
except:
self.cache = {}
def _dumpCache(self):
if dryrun:
return
# try to dump build-error cache
try:
cacheDesc = {'scons_version' : SCons.__version__,
'data' : self.cache }
cPickle.dump(cacheDesc, open(str(self.confdir.File(".cache")),"w"))
except Exception, e:
# this is most likely not only an IO error, but an error
# inside SConf ...
SCons.Warnings.warn( SConfWarning, "Couldn't dump SConf cache" )
def _createDir( self, node ):
dirName = str(node)
if dryrun:
if not os.path.isdir( dirName ):
raise SCons.Errors.ConfigureDryRunError(dirName)
raise ConfigureDryRunError(dirName)
else:
if not os.path.isdir( dirName ):
os.makedirs( dirName )
@ -445,8 +584,8 @@ class SConf:
"""Private method. Set up logstream, and set the environment
variables necessary for a piped build
"""
global _ac_config_counter
global _activeSConfObjects
global _ac_config_logs
global sconf_global
global SConfFS
self.lastEnvFs = self.env.fs
@ -457,41 +596,44 @@ class SConf:
if self.logfile != None and not dryrun:
# truncate logfile, if SConf.Configure is called for the first time
# in a build
if _ac_config_counter == 0:
log_mode = "w"
else:
if _ac_config_logs.has_key(self.logfile):
log_mode = "a"
self.logstream = open(str(self.logfile), log_mode)
else:
_ac_config_logs[self.logfile] = None
log_mode = "w"
fp = open(str(self.logfile), log_mode)
self.logstream = SCons.Util.Unbuffered(fp)
# logfile may stay in a build directory, so we tell
# the build system not to override it with a eventually
# existing file with the same name in the source directory
self.logfile.dir.add_ignore( [self.logfile] )
tb = traceback.extract_stack()[-3]
self.logstream.write( '\nfile %s,line %d:\n\tConfigure( confdir = %s )\n\n' %
tb = traceback.extract_stack()[-3-self.depth]
old_fs_dir = SConfFS.getcwd()
SConfFS.chdir(SConfFS.Top, change_os_dir=0)
self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' %
(tb[0], tb[1], str(self.confdir)) )
SConfFS.chdir(old_fs_dir)
else:
self.logstream = None
# we use a special builder to create source files from TEXT
action = SCons.Action.Action(_createSource,
_stringSource,
varlist=['SCONF_TEXT'])
_stringSource)
sconfSrcBld = SCons.Builder.Builder(action=action)
self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} )
self.config_h_text = _ac_config_hs.get(self.config_h, "")
self.active = 1
# only one SConf instance should be active at a time ...
_activeSConfObjects[self] = None
_ac_config_counter = _ac_config_counter + 1
self._loadCache()
sconf_global = self
def _shutdown(self):
"""Private method. Reset to non-piped spawn"""
global _activeSConfObjets
global sconf_global, _ac_config_hs
if not self.active:
raise SCons.Errors.UserError, "Finish may be called only once!"
if self.logstream != None:
if self.logstream != None and not dryrun:
self.logstream.write("\n")
self.logstream.close()
self.logstream = None
# remove the SConfSourceBuilder from the environment
@ -499,8 +641,9 @@ class SConf:
del blds['SConfSourceBuilder']
self.env.Replace( BUILDERS=blds )
self.active = 0
del _activeSConfObjects[self]
self._dumpCache()
sconf_global = None
if not self.config_h is None:
_ac_config_hs[self.config_h] = self.config_h_text
self.env.fs = self.lastEnvFs
class CheckContext:
@ -524,22 +667,27 @@ class CheckContext:
def __init__(self, sconf):
"""Constructor. Pass the corresponding SConf instance."""
self.sconf = sconf
self.cached = 0
self.did_show_result = 0
# for Conftest.py:
self.vardict = {}
self.havedict = {}
self.headerfilename = None # XXX may cause trouble!
self.headerfilename = None
self.config_h = "" # config_h text will be stored here
# we don't regenerate the config.h file after each test. That means,
# that tests won't be able to include the config.h file, and so
# they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major
# issue, though. If it turns out, that we need to include config.h
# in tests, we must ensure, that the dependencies are worked out
# correctly. Note that we can't use Conftest.py's support for config.h,
# cause we will need to specify a builder for the config.h file ...
def Message(self, text):
"""Inform about what we are doing right now, e.g.
'Checking for SOMETHING ... '
"""
# write to config.log
if self.sconf.logstream != None:
self.sconf.logstream.write(text + '\n')
sys.stdout.write(text)
self.Display(text)
self.sconf.cached = 1
self.did_show_result = 0
def Result(self, res):
@ -550,25 +698,19 @@ class CheckContext:
"""
if type(res) in BooleanTypes:
if res:
text = "ok"
text = "yes"
else:
text = "failed"
text = "no"
elif type(res) == types.StringType:
text = res
else:
raise TypeError, "Expected string, int or bool, got " + str(type(res))
if self.did_show_result == 0:
if self.cached:
text = text + " (cached)"
# Didn't show result yet, do it now.
if self.sconf.logstream != None:
self.sconf.logstream.write("Result: " + text + "\n\n")
sys.stdout.write(text + "\n")
self.Display(text + "\n")
self.did_show_result = 1
def TryBuild(self, *args, **kw):
return apply(self.sconf.TryBuild, args, kw)
@ -595,32 +737,14 @@ class CheckContext:
#### Stuff used by Conftest.py (look there for explanations).
def BuildProg(self, text, ext):
self.sconf.cached = 1
# TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
res = self.TryBuild(self.env.Program, text, ext)
if type(res) in BooleanTypes:
if res:
ret = ""
else:
ret = "failed to build test program"
elif type(res) == types.StringType:
ret = res
else:
raise TypeError, "Expected string or int"
return ret
return not self.TryBuild(self.env.Program, text, ext)
def CompileProg(self, text, ext):
self.sconf.cached = 1
# TODO: should use self.vardict for $CC, $CPPFLAGS, etc.
res = self.TryBuild(self.env.Object, text, ext)
if type(res) in BooleanTypes:
if res:
ret = ""
else:
ret = "failed to compile test program"
elif type(res) == types.StringType:
ret = res
else:
raise TypeError, "Expected string or int"
return ret
return not self.TryBuild(self.env.Object, text, ext)
def AppendLIBS(self, lib_name_list):
oldLIBS = self.env.get( 'LIBS', [] )
@ -633,8 +757,14 @@ class CheckContext:
return oldLIBS
def Display(self, msg):
sys.stdout.write(msg)
self.Log(msg)
if self.sconf.cached:
# We assume that Display is called twice for each test here
# once for the Checking for ... message and once for the result.
# The self.sconf.cached flag can only be set between those calls
msg = "(cached) " + msg
self.sconf.cached = 0
progress_display(msg, append_newline=0)
self.Log("scons: Configure: " + msg + "\n")
def Log(self, msg):
if self.sconf.logstream != None:
@ -643,40 +773,44 @@ class CheckContext:
#### End of stuff used by Conftest.py.
def CheckFunc(context, function_name, language = None):
res = SCons.Conftest.CheckFunc(context, function_name, language = language)
def CheckFunc(context, function_name, header = None, language = None):
res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language)
context.did_show_result = 1
if not res:
return 1 # Ok
return 0 # Failed
return not res
def CheckType(context, type_name, includes = "", language = None):
res = SCons.Conftest.CheckType(context, type_name,
header = includes, language = language)
context.did_show_result = 1
if not res:
return 1 # Ok
return 0 # Failed
return not res
def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'):
# used by CheckHeader and CheckLibWithHeader to produce C - #include
# statements from the specified header (list)
if not SCons.Util.is_List(headers):
headers = [headers]
l = []
if leaveLast:
lastHeader = headers[-1]
headers = headers[:-1]
else:
lastHeader = None
for s in headers:
l.append("#include %s%s%s\n"
% (include_quotes[0], s, include_quotes[1]))
return string.join(l, ''), lastHeader
def CheckHeader(context, header, include_quotes = '<>', language = None):
"""
A test for a C or C++ header file.
"""
if not SCons.Util.is_List(header):
header = [header]
l = []
for s in header[:-1]:
l.append("#include %s%s%s\n" % (include_quotes[0], s, include_quotes[1]))
res = SCons.Conftest.CheckHeader(context, header[-1], string.join(l, ''),
prog_prefix, hdr_to_check = \
createIncludesFromHeaders(header, 1, include_quotes)
res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix,
language = language,
include_quotes = include_quotes)
context.did_show_result = 1
if not res:
return 1 # Ok
return 0 # Failed
return not res
# Bram: Make this function obsolete? CheckHeader() is more generic.
@ -696,8 +830,8 @@ def CheckCXXHeader(context, header, include_quotes = '""'):
return CheckHeader(context, header, include_quotes, language = "C++")
def CheckLib(context, library = None, symbol = "main", autoadd = 1,
header = None, language = None):
def CheckLib(context, library = None, symbol = "main",
header = None, language = None, autoadd = 1):
"""
A test for a library. See also CheckLibWithHeader.
Note that library may also be None to test whether the given symbol
@ -714,43 +848,30 @@ def CheckLib(context, library = None, symbol = "main", autoadd = 1,
res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
language = language, autoadd = autoadd)
context.did_show_result = 1
if not res:
return 1 # Ok
return 0 # Failed
return not res
# XXX
# Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H.
def CheckLibWithHeader(context, libs, header, language,
call = "main();", autoadd = 1):
call = None, autoadd = 1):
# ToDo: accept path for library. Support system header files.
"""
Another (more sophisticated) test for a library.
Checks, if library and header is available for language (maybe 'C'
Checks, if library and header is available for language (may be 'C'
or 'CXX'). Call maybe be a valid expression _with_ a trailing ';'.
As in CheckLib, we support library=None, to test if the call compiles
without extra link flags.
"""
if not SCons.Util.is_List(header):
header = [header]
l = []
for s in header:
l.append('#include "%s"\n' % (s))
prog_prefix, dummy = \
createIncludesFromHeaders(header, 0)
if libs == []:
libs = [None]
if not SCons.Util.is_List(libs):
libs = [libs]
res = SCons.Conftest.CheckLib(context, libs, "main", string.join(l, ''),
res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix,
call = call, language = language, autoadd = autoadd)
context.did_show_result = 1
if not res:
return 1 # Ok
return 0 # Failed
return not res

View file

@ -5,7 +5,7 @@ Writing and reading information to the .sconsign file or files.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,26 +27,85 @@ Writing and reading information to the .sconsign file or files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConsign.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConsign.py 0.97.D001 2007/05/17 11:35:19 knight"
import cPickle
import os
import os.path
import time
import SCons.Node
import SCons.dblite
import SCons.Sig
import SCons.Warnings
def corrupt_dblite_warning(filename):
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
"Ignoring corrupt .sconsign file: %s"%filename)
SCons.dblite.ignore_corrupt_dbfiles = 1
SCons.dblite.corruption_warning = corrupt_dblite_warning
#XXX Get rid of the global array so this becomes re-entrant.
sig_files = []
database = None
# Info for the database SConsign implementation (now the default):
# "DataBase" is a dictionary that maps top-level SConstruct directories
# to open database handles.
# "DB_Module" is the Python database module to create the handles.
# "DB_Name" is the base name of the database file (minus any
# extension the underlying DB module will add).
DataBase = {}
DB_Module = SCons.dblite
DB_Name = ".sconsign"
DB_sync_list = []
def Get_DataBase(dir):
global DataBase, DB_Module, DB_Name
top = dir.fs.Top
if not os.path.isabs(DB_Name) and top.repositories:
mode = "c"
for d in [top] + top.repositories:
if dir.is_under(d):
try:
return DataBase[d], mode
except KeyError:
path = d.entry_abspath(DB_Name)
try: db = DataBase[d] = DB_Module.open(path, mode)
except (IOError, OSError): pass
else:
if mode != "r":
DB_sync_list.append(db)
return db, mode
mode = "r"
try:
return DataBase[top], "c"
except KeyError:
db = DataBase[top] = DB_Module.open(DB_Name, "c")
DB_sync_list.append(db)
return db, "c"
except TypeError:
print "DataBase =", DataBase
raise
def Reset():
"""Reset global state. Used by unit tests that end up using
SConsign multiple times to get a clean slate for each test."""
global sig_files, DB_sync_list
sig_files = []
DB_sync_list = []
normcase = os.path.normcase
def write():
global sig_files
for sig_file in sig_files:
sig_file.write()
sig_file.write(sync=0)
for db in DB_sync_list:
try:
syncmethod = db.sync
except AttributeError:
pass # Not all anydbm modules have sync() methods.
else:
syncmethod()
class Base:
"""
@ -79,19 +138,28 @@ class Base:
self.entries[filename] = obj
self.dirty = 1
def do_not_set_entry(self, filename, obj):
pass
class DB(Base):
"""
A Base subclass that reads and writes signature information
from a global .sconsign.dbm file.
from a global .sconsign.db* file--the actual file suffix is
determined by the specified database module.
"""
def __init__(self, dir, module=None):
Base.__init__(self, module)
self.dir = dir
db, mode = Get_DataBase(dir)
# Read using the path relative to the top of the Repository
# (self.dir.tpath) from which we're fetching the signature
# information.
path = normcase(dir.tpath)
try:
global database
rawentries = database[self.dir.path]
rawentries = db[path]
except KeyError:
pass
else:
@ -102,22 +170,45 @@ class DB(Base):
raise TypeError
except KeyboardInterrupt:
raise
except:
except Exception, e:
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
"Ignoring corrupt sconsign entry : %s"%self.dir.path)
"Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.tpath, e))
for key, entry in self.entries.items():
entry.convert_from_sconsign(dir, key)
if mode == "r":
# This directory is actually under a repository, which means
# likely they're reaching in directly for a dependency on
# a file there. Don't actually set any entry info, so we
# won't try to write to that .sconsign.dblite file.
self.set_entry = self.do_not_set_entry
global sig_files
sig_files.append(self)
def write(self):
if self.dirty:
global database
database[self.dir.path] = cPickle.dumps(self.entries, 1)
def write(self, sync=1):
if not self.dirty:
return
db, mode = Get_DataBase(self.dir)
# Write using the path relative to the top of the SConstruct
# directory (self.dir.path), not relative to the top of
# the Repository; we only write to our own .sconsign file,
# not to .sconsign files in Repositories.
path = normcase(self.dir.path)
for key, entry in self.entries.items():
entry.convert_to_sconsign()
db[path] = cPickle.dumps(self.entries, 1)
if sync:
try:
database.sync()
syncmethod = db.sync
except AttributeError:
# Not all anydbm modules have sync() methods.
pass
else:
syncmethod()
class Dir(Base):
def __init__(self, fp=None, module=None):
@ -162,7 +253,16 @@ class DirFile(Dir):
global sig_files
sig_files.append(self)
def write(self):
def get_entry(self, filename):
"""
Fetch the specified entry attribute, converting from .sconsign
format to in-memory format.
"""
entry = Dir.get_entry(self, filename)
entry.convert_from_sconsign(self.dir, filename)
return entry
def write(self, sync=1):
"""
Write the .sconsign file to disk.
@ -186,6 +286,8 @@ class DirFile(Dir):
fname = self.sconsign
except IOError:
return
for key, entry in self.entries.items():
entry.convert_to_sconsign()
cPickle.dump(self.entries, file, 1)
file.close()
if fname != self.sconsign:
@ -193,31 +295,42 @@ class DirFile(Dir):
mode = os.stat(self.sconsign)[0]
os.chmod(self.sconsign, 0666)
os.unlink(self.sconsign)
except OSError:
except (IOError, OSError):
# Try to carry on in the face of either OSError
# (things like permission issues) or IOError (disk
# or network issues). If there's a really dangerous
# issue, it should get re-raised by the calls below.
pass
try:
os.rename(fname, self.sconsign)
except OSError:
# An OSError failure to rename may indicate something
# like the directory has no write permission, but
# the .sconsign file itself might still be writable,
# so try writing on top of it directly. An IOError
# here, or in any of the following calls, would get
# raised, indicating something like a potentially
# serious disk or network issue.
open(self.sconsign, 'wb').write(open(fname, 'rb').read())
os.chmod(self.sconsign, mode)
try:
os.unlink(temp)
except OSError:
except (IOError, OSError):
pass
ForDirectory = DirFile
ForDirectory = DB
def File(name, dbm_module=None):
"""
Arrange for all signatures to be stored in a global .sconsign.dbm
Arrange for all signatures to be stored in a global .sconsign.db*
file.
"""
global database
if database is None:
if dbm_module is None:
import SCons.dblite
dbm_module = SCons.dblite
database = dbm_module.open(name, "c")
global ForDirectory
global ForDirectory, DB_Name, DB_Module
if name is None:
ForDirectory = DirFile
DB_Module = None
else:
ForDirectory = DB
DB_Name = name
if not dbm_module is None:
DB_Module = dbm_module

View file

@ -5,7 +5,7 @@ This module implements the depenency scanner for C/C++ code.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,17 +27,16 @@ This module implements the depenency scanner for C/C++ code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/C.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/C.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Node.FS
import SCons.Scanner
def CScan(fs = SCons.Node.FS.default_fs):
def CScanner():
"""Return a prototype Scanner instance for scanning source files
that use the C pre-processor"""
cs = SCons.Scanner.ClassicCPP("CScan",
cs = SCons.Scanner.ClassicCPP("CScanner",
"$CPPSUFFIXES",
"CPPPATH",
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")',
fs = fs)
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")')
return cs

View file

@ -8,7 +8,7 @@ Coded by Andy Friesen
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,27 +30,24 @@ Coded by Andy Friesen
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/D.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/D.py 0.97.D001 2007/05/17 11:35:19 knight"
import string
import SCons.Scanner
def DScan(fs = SCons.Node.FS.default_fs):
def DScanner():
"""Return a prototype Scanner instance for scanning D source files"""
ds = DScanner(name = "DScan",
ds = D(name = "DScanner",
suffixes = '$DSUFFIXES',
path_variable = 'DPATH',
regex = 'import\s+([^\;]*)\;',
fs = fs)
regex = 'import\s+([^\;]*)\;')
return ds
class DScanner(SCons.Scanner.Classic):
class D(SCons.Scanner.Classic):
def find_include(self, include, source_dir, path):
# translate dots (package separators) to slashes
inc = string.replace(include, '.', '/')
i = SCons.Node.FS.find_file(inc + '.d',
(source_dir,) + path,
self.fs.File)
i = SCons.Node.FS.find_file(inc + '.d', (source_dir,) + path)
return i, include

View file

@ -0,0 +1,105 @@
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Dir.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Node.FS
import SCons.Scanner
def only_dirs(nodes):
is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir)
return filter(is_Dir, nodes)
def DirScanner(**kw):
"""Return a prototype Scanner instance for scanning
directories for on-disk files"""
kw['node_factory'] = SCons.Node.FS.Entry
kw['recursive'] = only_dirs
return apply(SCons.Scanner.Base, (scan_on_disk, "DirScanner"), kw)
def DirEntryScanner(**kw):
"""Return a prototype Scanner instance for "scanning"
directory Nodes for their in-memory entries"""
kw['node_factory'] = SCons.Node.FS.Entry
kw['recursive'] = None
return apply(SCons.Scanner.Base, (scan_in_memory, "DirEntryScanner"), kw)
skip_entry = {}
skip_entry_list = [
'.',
'..',
'.sconsign',
# Used by the native dblite.py module.
'.sconsign.dblite',
# Used by dbm and dumbdbm.
'.sconsign.dir',
# Used by dbm.
'.sconsign.pag',
# Used by dumbdbm.
'.sconsign.dat',
'.sconsign.bak',
# Used by some dbm emulations using Berkeley DB.
'.sconsign.db',
]
for skip in skip_entry_list:
skip_entry[skip] = 1
skip_entry[SCons.Node.FS._my_normcase(skip)] = 1
do_not_scan = lambda k: not skip_entry.has_key(k)
def scan_on_disk(node, env, path=()):
"""
Scans a directory for on-disk files and directories therein.
Looking up the entries will add these to the in-memory Node tree
representation of the file system, so all we have to do is just
that and then call the in-memory scanning function.
"""
try:
flist = node.fs.listdir(node.abspath)
except (IOError, OSError):
return []
e = node.Entry
for f in filter(do_not_scan, flist):
# Add ./ to the beginning of the file name so if it begins with a
# '#' we don't look it up relative to the top-level directory.
e('./' + f)
return scan_in_memory(node, env, path)
def scan_in_memory(node, env, path=()):
"""
"Scans" a Node.FS.Dir for its in-memory entries.
"""
try:
entries = node.entries
except AttributeError:
# It's not a Node.FS.Dir (or doesn't look enough like one for
# our purposes), which can happen if a target list containing
# mixed Node types (Dirs and Files, for example) has a Dir as
# the first entry.
return []
entry_list = filter(do_not_scan, entries.keys())
entry_list.sort()
return map(lambda n, e=entries: e[n], entry_list)

View file

@ -5,7 +5,7 @@ This module implements the dependency scanner for Fortran code.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,7 +27,7 @@ This module implements the dependency scanner for Fortran code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Fortran.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Fortran.py 0.97.D001 2007/05/17 11:35:19 knight"
import re
import string
@ -54,18 +54,23 @@ class F90Scanner(SCons.Scanner.Classic):
smart thing to do.
"""
def __init__(self, name, suffixes, path_variable, use_regex,
incl_regex, fs=SCons.Node.FS.default_fs, *args, **kw):
def __init__(self, name, suffixes, path_variable,
use_regex, incl_regex, def_regex, *args, **kw):
self.cre_use = re.compile(use_regex, re.M)
self.cre_incl = re.compile(incl_regex, re.M)
self.fs = fs
self.cre_def = re.compile(def_regex, re.M)
def _scan(node, env, path, self=self):
node = node.rfile()
if not node.exists():
return []
def _scan(node, env, path, self=self, fs=fs):
return self.scan(node, env, path)
kw['function'] = _scan
kw['path_function'] = SCons.Scanner.FindPathDirs(path_variable, fs)
kw['path_function'] = SCons.Scanner.FindPathDirs(path_variable)
kw['recursive'] = 1
kw['skeys'] = suffixes
kw['name'] = name
@ -73,10 +78,6 @@ class F90Scanner(SCons.Scanner.Classic):
apply(SCons.Scanner.Current.__init__, (self,) + args, kw)
def scan(self, node, env, path=()):
node = node.rfile()
if not node.exists():
return []
# cache the includes list in node so we only scan it once:
if node.includes != None:
@ -86,6 +87,15 @@ class F90Scanner(SCons.Scanner.Classic):
includes = self.cre_incl.findall(node.get_contents())
# retrieve all USE'd module names
modules = self.cre_use.findall(node.get_contents())
# retrieve all defined module names
defmodules = self.cre_def.findall(node.get_contents())
# Remove all USE'd module names that are defined in the same file
d = {}
for m in defmodules:
d[m] = 1
modules = filter(lambda m, d=d: not d.has_key(m), modules)
#modules = self.undefinedModules(modules, defmodules)
# Convert module name to a .mod filename
suffix = env.subst('$FORTRANMODSUFFIX')
@ -94,44 +104,30 @@ class F90Scanner(SCons.Scanner.Classic):
mods_and_includes = SCons.Util.unique(includes+modules)
node.includes = mods_and_includes
# This is a hand-coded DSU (decorate-sort-undecorate, or
# Schwartzian transform) pattern. The sort key is the raw name
# of the file as specifed on the USE or INCLUDE line, which lets
# us keep the sort order constant regardless of whether the file
# is actually found in a Repository or locally.
nodes = []
source_dir = node.get_dir()
if callable(path):
path = path()
for dep in mods_and_includes:
n, i = self.find_include(dep, source_dir, path)
if not n is None:
nodes.append(n)
else:
if n is None:
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
"No dependency generated for file: %s (referenced by: %s) -- file not found" % (i, node))
else:
sortkey = self.sort_key(dep)
nodes.append((sortkey, n))
# Sort the list of dependencies
nodes.sort()
nodes = map(lambda pair: pair[1], nodes)
return nodes
# Schwartzian transform from the Python FAQ Wizard
def st(List, Metric):
def pairing(element, M = Metric):
return (M(element), element)
def stripit(pair):
return pair[1]
paired = map(pairing, List)
paired.sort()
return map(stripit, paired)
def normalize(node):
# We don't want the order of includes to be
# modified by case changes on case insensitive OSes, so
# normalize the case of the filename here:
# (see test/win32pathmadness.py for a test of this)
return SCons.Node.FS._my_normcase(str(node))
# Apply a Schwartzian transform to return the list of
# dependencies, sorted according to their normalized names
transformed = st(nodes, normalize)
# print "ClassicF90: " + str(node) + " => " + str(map(lambda x: str(x),list(transformed)))
return transformed
def FortranScan(path_variable="FORTRANPATH", fs=SCons.Node.FS.default_fs):
def FortranScan(path_variable="FORTRANPATH"):
"""Return a prototype Scanner instance for scanning source files
for Fortran USE & INCLUDE statements"""
@ -285,10 +281,34 @@ def FortranScan(path_variable="FORTRANPATH", fs=SCons.Node.FS.default_fs):
include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
# The MODULE statement regex finds module definitions by matching
# the following:
#
# MODULE module_name
#
# but *not* the following:
#
# MODULE PROCEDURE procedure_name
#
# Here is a breakdown of the regex:
#
# (?i) : regex is case insensitive
# ^\s* : any amount of white space
# MODULE : match the string MODULE, case insensitive
# \s+ : match one or more white space characters
# (?!PROCEDURE) : but *don't* match if the next word matches
# PROCEDURE (negative lookahead assertion),
# case insensitive
# (\w+) : match one or more alphanumeric characters
# that make up the defined module name and
# save it in a group
def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
scanner = F90Scanner("FortranScan",
"$FORTRANSUFFIXES",
path_variable,
use_regex,
include_regex,
fs = fs)
def_regex)
return scanner

View file

@ -6,7 +6,7 @@ Definition Language) files.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -28,16 +28,15 @@ Definition Language) files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/IDL.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/IDL.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Node.FS
import SCons.Scanner
def IDLScan(fs = SCons.Node.FS.default_fs):
def IDLScan():
"""Return a prototype Scanner instance for scanning IDL source files"""
cs = SCons.Scanner.ClassicCPP("IDLScan",
"$IDLSUFFIXES",
"CPPPATH",
'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")',
fs = fs)
'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")')
return cs

View file

@ -0,0 +1,122 @@
"""SCons.Scanner.LaTeX
This module implements the dependency scanner for LaTeX code.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/LaTeX.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Scanner
import string
import os.path
def LaTeXScanner(fs = SCons.Node.FS.default_fs):
"""Return a prototype Scanner instance for scanning LaTeX source files"""
ds = LaTeX(name = "LaTeXScanner",
suffixes = '$LATEXSUFFIXES',
path_variable = 'TEXINPUTS',
regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography){([^}]*)}',
recursive = 0)
return ds
class LaTeX(SCons.Scanner.Classic):
"""Class for scanning LaTeX files for included files.
Unlike most scanners, which use regular expressions that just
return the included file name, this returns a tuple consisting
of the keyword for the inclusion ("include", "includegraphics",
"input", or "bibliography"), and then the file name itself.
Based on a quick look at LaTeX documentation, it seems that we
need a should append .tex suffix for the "include" keywords,
append .tex if there is no extension for the "input" keyword,
but leave the file name untouched for "includegraphics." For
the "bibliography" keyword we need to add .bib if there is
no extension. (This need to be revisited since if there
is no extension for an :includegraphics" keyword latex will
append .ps or .eps to find the file; while pdftex will use
other extensions.)
"""
def latex_name(self, include):
filename = include[1]
if include[0] == 'input':
base, ext = os.path.splitext( filename )
if ext == "":
filename = filename + '.tex'
if (include[0] == 'include'):
filename = filename + '.tex'
if include[0] == 'bibliography':
base, ext = os.path.splitext( filename )
if ext == "":
filename = filename + '.bib'
return filename
def sort_key(self, include):
return SCons.Node.FS._my_normcase(self.latex_name(include))
def find_include(self, include, source_dir, path):
i = SCons.Node.FS.find_file(self.latex_name(include),
(source_dir,) + path)
return i, include
def scan(self, node, path=()):
#
# Modify the default scan function to allow for the regular
# expression to return a comma separated list of file names
# as can be the case with the bibliography keyword.
#
# cache the includes list in node so we only scan it once:
if node.includes != None:
includes = node.includes
else:
includes = self.cre.findall(node.get_contents())
node.includes = includes
# This is a hand-coded DSU (decorate-sort-undecorate, or
# Schwartzian transform) pattern. The sort key is the raw name
# of the file as specifed on the #include line (including the
# " or <, since that may affect what file is found), which lets
# us keep the sort order constant regardless of whether the file
# is actually found in a Repository or locally.
nodes = []
source_dir = node.get_dir()
for include in includes:
#
# Handle multiple filenames in include[1]
#
inc_list = string.split(include[1],',')
for j in range(len(inc_list)):
include_local = [include[0],inc_list[j]]
n, i = self.find_include(include_local, source_dir, path)
if n is None:
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
"No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
else:
sortkey = self.sort_key(include)
nodes.append((sortkey, n))
nodes.sort()
nodes = map(lambda pair: pair[1], nodes)
return nodes

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -21,7 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Prog.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Prog.py 0.97.D001 2007/05/17 11:35:19 knight"
import string
@ -30,57 +30,70 @@ import SCons.Node.FS
import SCons.Scanner
import SCons.Util
def ProgScan(fs = SCons.Node.FS.default_fs):
# global, set by --debug=findlibs
print_find_libs = None
def ProgramScanner(**kw):
"""Return a prototype Scanner instance for scanning executable
files for static-lib dependencies"""
pf = SCons.Scanner.FindPathDirs('LIBPATH', fs)
ps = SCons.Scanner.Base(scan, "ProgScan", path_function = pf)
kw['path_function'] = SCons.Scanner.FindPathDirs('LIBPATH')
ps = apply(SCons.Scanner.Base, [scan, "ProgramScanner"], kw)
return ps
def scan(node, env, libpath = (), fs = SCons.Node.FS.default_fs):
def scan(node, env, libpath = ()):
"""
This scanner scans program files for static-library
dependencies. It will search the LIBPATH environment variable
for libraries specified in the LIBS variable, returning any
files it finds as dependencies.
"""
try:
libs = env.Dictionary('LIBS')
libs = env['LIBS']
except KeyError:
# There are no LIBS in this environment, so just return a null list:
return []
if SCons.Util.is_String(libs):
libs = string.split(libs)
elif not SCons.Util.is_List(libs):
elif SCons.Util.is_List(libs):
libs = SCons.Util.flatten(libs)
else:
libs = [libs]
try:
prefix = env.Dictionary('LIBPREFIXES')
prefix = env['LIBPREFIXES']
if not SCons.Util.is_List(prefix):
prefix = [ prefix ]
except KeyError:
prefix = [ '' ]
try:
suffix = env.Dictionary('LIBSUFFIXES')
suffix = env['LIBSUFFIXES']
if not SCons.Util.is_List(suffix):
suffix = [ suffix ]
except KeyError:
suffix = [ '' ]
find_file = SCons.Node.FS.find_file
adjustixes = SCons.Util.adjustixes
result = []
pairs = []
for suf in map(env.subst, suffix):
for pref in map(env.subst, prefix):
pairs.append((pref, suf))
result = []
if callable(libpath):
libpath = libpath()
find_file = SCons.Node.FS.find_file
adjustixes = SCons.Util.adjustixes
for lib in libs:
if SCons.Util.is_String(lib):
lib = env.subst(lib)
lib = adjustixes(lib, pref, suf)
lib = find_file(lib, libpath, fs.File)
if lib:
result.append(lib)
for pref, suf in pairs:
l = adjustixes(lib, pref, suf)
l = find_file(l, libpath, verbose=print_find_libs)
if l:
result.append(l)
else:
result.append(lib)
return result

View file

@ -5,7 +5,7 @@ The Scanner package for the SCons software construction utility.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,9 +27,10 @@ The Scanner package for the SCons software construction utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
import re
import string
import SCons.Node.FS
import SCons.Sig
@ -44,30 +45,41 @@ class _Null:
_null = _Null
def Scanner(function, *args, **kw):
"""Public interface factory function for creating different types
"""
Public interface factory function for creating different types
of Scanners based on the different types of "functions" that may
be supplied."""
be supplied.
TODO: Deprecate this some day. We've moved the functionality
inside the Base class and really don't need this factory function
any more. It was, however, used by some of our Tool modules, so
the call probably ended up in various people's custom modules
patterned on SCons code.
"""
if SCons.Util.is_Dict(function):
return apply(Selector, (function,) + args, kw)
else:
return apply(Base, (function,) + args, kw)
class FindPathDirs:
"""A class to bind a specific *PATH variable name and the fs object
to a function that will return all of the *path directories."""
def __init__(self, variable, fs):
"""A class to bind a specific *PATH variable name to a function that
will return all of the *path directories."""
def __init__(self, variable):
self.variable = variable
self.fs = fs
def __call__(self, env, dir, argument=None):
def __call__(self, env, dir, target=None, source=None, argument=None):
import SCons.PathList
try:
path = env[self.variable]
except KeyError:
return ()
return tuple(self.fs.Rsearchall(env.subst_path(path),
must_exist = 0,
clazz = SCons.Node.FS.Dir,
cwd = dir))
dir = dir or env.fs._cwd
path = SCons.PathList.PathList(path).subst_path(env, target, source)
return tuple(dir.Rfindalldirs(path))
class Base:
"""
@ -79,10 +91,10 @@ class Base:
function,
name = "NONE",
argument = _null,
skeys = [],
skeys = _null,
path_function = None,
node_class = SCons.Node.FS.Entry,
node_factory = SCons.Node.FS.default_fs.File,
node_factory = None,
scan_check = None,
recursive = None):
"""
@ -100,10 +112,14 @@ class Base:
which scanner should be used for a given Node. In the case of File
nodes, for example, the 'skeys' would be file suffixes.
'path_function' - a function that takes one to three arguments
(a construction environment, optional directory, and optional
argument for this instance) and returns a tuple of the
directories that can be searched for implicit dependency files.
'path_function' - a function that takes four or five arguments
(a construction environment, Node for the directory containing
the SConscript file that defined the primary target, list of
target nodes, list of source nodes, and optional argument for
this instance) and returns a tuple of the directories that can
be searched for implicit dependency files. May also return a
callable() which is called with no args and returns the tuple
(supporting Bindable class).
'node_class' - the class of Nodes which this scan will return.
If node_class is None, then this scanner will not enforce any
@ -118,14 +134,19 @@ class Base:
this node really needs to be scanned.
'recursive' - specifies that this scanner should be invoked
recursively on the implicit dependencies it returns (the
canonical example being #include lines in C source files).
recursively on all of the implicit dependencies it returns
(the canonical example being #include lines in C source files).
May be a callable, which will be called to filter the list
of nodes found to select a subset for recursive scanning
(the canonical example being only recursively scanning
subdirectories within a directory).
The scanner function's first argument will be the name of a file
that should be scanned for dependencies, the second argument will
be an Environment object, the third argument will be the value
passed into 'argument', and the returned list should contain the
Nodes for all the direct dependencies of the file.
The scanner function's first argument will be a Node that should
be scanned for dependencies, the second argument will be an
Environment object, the third argument will be the tuple of paths
returned by the path_function, and the fourth argument will be
the value passed into 'argument', and the returned list should
contain the Nodes for all the direct dependencies of the file.
Examples:
@ -146,19 +167,31 @@ class Base:
self.path_function = path_function
self.name = name
self.argument = argument
if skeys is _null:
if SCons.Util.is_Dict(function):
skeys = function.keys()
else:
skeys = []
self.skeys = skeys
self.node_class = node_class
self.node_factory = node_factory
self.scan_check = scan_check
self.recursive = recursive
if callable(recursive):
self.recurse_nodes = recursive
elif recursive:
self.recurse_nodes = self._recurse_all_nodes
else:
self.recurse_nodes = self._recurse_no_nodes
def path(self, env, dir = None):
def path(self, env, dir=None, target=None, source=None):
if not self.path_function:
return ()
if not self.argument is _null:
return self.path_function(env, dir, self.argument)
return self.path_function(env, dir, target, source, self.argument)
else:
return self.path_function(env, dir)
return self.path_function(env, dir, target, source)
def __call__(self, node, env, path = ()):
"""
@ -170,47 +203,85 @@ class Base:
if self.scan_check and not self.scan_check(node, env):
return []
self = self.select(node)
if not self.argument is _null:
list = self.function(node, env, path, self.argument)
else:
list = self.function(node, env, path)
kw = {}
if hasattr(node, 'dir'):
kw['directory'] = node.dir
node_factory = env.get_factory(self.node_factory)
nodes = []
for l in list:
if self.node_class and not isinstance(l, self.node_class):
l = apply(self.node_factory, (l,), kw)
l = apply(node_factory, (l,), kw)
nodes.append(l)
return nodes
def __cmp__(self, other):
try:
return cmp(self.__dict__, other.__dict__)
except AttributeError:
# other probably doesn't have a __dict__
return cmp(self.__dict__, other)
def __hash__(self):
return hash(repr(self))
return id(self)
def __str__(self):
return self.name
def add_skey(self, skey):
"""Add a skey to the list of skeys"""
self.skeys.append(skey)
def get_skeys(self, env=None):
if SCons.Util.is_String(self.skeys):
if env and SCons.Util.is_String(self.skeys):
return env.subst_list(self.skeys)[0]
return self.skeys
def select(self, node):
if SCons.Util.is_Dict(self.function):
key = node.scanner_key()
try:
return self.function[key]
except KeyError:
return None
else:
return self
def _recurse_all_nodes(self, nodes):
return nodes
def _recurse_no_nodes(self, nodes):
return []
recurse_nodes = _recurse_no_nodes
def add_scanner(self, skey, scanner):
self.function[skey] = scanner
self.add_skey(skey)
class Selector(Base):
"""
A class for selecting a more specific scanner based on the
scanner_key() (suffix) for a specific Node.
TODO: This functionality has been moved into the inner workings of
the Base class, and this class will be deprecated at some point.
(It was never exposed directly as part of the public interface,
although it is used by the Scanner() factory function that was
used by various Tool modules and therefore was likely a template
for custom modules that may be out there.)
"""
def __init__(self, dict, *args, **kw):
Base.__init__(self, (None,)+args, kw)
apply(Base.__init__, (self, None,)+args, kw)
self.dict = dict
self.skeys = dict.keys()
def __call__(self, node, env, path = ()):
return self.select(node)(node, env, path)
@ -223,6 +294,7 @@ class Selector(Base):
def add_scanner(self, skey, scanner):
self.dict[skey] = scanner
self.add_skey(skey)
class Current(Base):
@ -246,22 +318,23 @@ class Classic(Current):
regular expressions to find the includes.
Note that in order for this to work "out of the box" (without
overriding the find_include() method), the regular expression passed
to the constructor must return the name of the include file in group
0.
overriding the find_include() and sort_key() methods), the regular
expression passed to the constructor must return the name of the
include file in group 0.
"""
def __init__(self, name, suffixes, path_variable, regex,
fs=SCons.Node.FS.default_fs, *args, **kw):
def __init__(self, name, suffixes, path_variable, regex, *args, **kw):
self.cre = re.compile(regex, re.M)
self.fs = fs
def _scan(node, env, path, self=self, fs=fs):
return self.scan(node, env, path)
def _scan(node, env, path=(), self=self):
node = node.rfile()
if not node.exists():
return []
return self.scan(node, path)
kw['function'] = _scan
kw['path_function'] = FindPathDirs(path_variable, fs)
kw['path_function'] = FindPathDirs(path_variable)
kw['recursive'] = 1
kw['skeys'] = suffixes
kw['name'] = name
@ -269,14 +342,13 @@ class Classic(Current):
apply(Current.__init__, (self,) + args, kw)
def find_include(self, include, source_dir, path):
n = SCons.Node.FS.find_file(include, (source_dir,) + path, self.fs.File)
n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path))
return n, include
def scan(self, node, env, path=()):
node = node.rfile()
def sort_key(self, include):
return SCons.Node.FS._my_normcase(include)
if not node.exists():
return []
def scan(self, node, path=()):
# cache the includes list in node so we only scan it once:
if node.includes != None:
@ -285,37 +357,29 @@ class Classic(Current):
includes = self.cre.findall(node.get_contents())
node.includes = includes
# This is a hand-coded DSU (decorate-sort-undecorate, or
# Schwartzian transform) pattern. The sort key is the raw name
# of the file as specifed on the #include line (including the
# " or <, since that may affect what file is found), which lets
# us keep the sort order constant regardless of whether the file
# is actually found in a Repository or locally.
nodes = []
source_dir = node.get_dir()
if callable(path):
path = path()
for include in includes:
n, i = self.find_include(include, source_dir, path)
if not n is None:
nodes.append(n)
else:
if n is None:
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
"No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
else:
sortkey = self.sort_key(include)
nodes.append((sortkey, n))
# Schwartzian transform from the Python FAQ Wizard
def st(List, Metric):
def pairing(element, M = Metric):
return (M(element), element)
def stripit(pair):
return pair[1]
paired = map(pairing, List)
paired.sort()
return map(stripit, paired)
def normalize(node):
# We don't want the order of includes to be
# modified by case changes on case insensitive OSes, so
# normalize the case of the filename here:
# (see test/win32pathmadness.py for a test of this)
return SCons.Node.FS._my_normcase(str(node))
transformed = st(nodes, normalize)
# print "Classic: " + str(node) + " => " + str(map(lambda x: str(x),list(transformed)))
return transformed
nodes.sort()
nodes = map(lambda pair: pair[1], nodes)
return nodes
class ClassicCPP(Classic):
"""
@ -329,11 +393,13 @@ class ClassicCPP(Classic):
"""
def find_include(self, include, source_dir, path):
if include[0] == '"':
n = SCons.Node.FS.find_file(include[1],
(source_dir,) + path,
self.fs.File)
paths = (source_dir,) + tuple(path)
else:
n = SCons.Node.FS.find_file(include[1],
path + (source_dir,),
self.fs.File)
paths = tuple(path) + (source_dir,)
n = SCons.Node.FS.find_file(include[1], paths)
return n, include[1]
def sort_key(self, include):
return SCons.Node.FS._my_normcase(string.join(include))

View file

@ -6,7 +6,7 @@ files.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -28,7 +28,7 @@ files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/SConscript.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/SConscript.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons
import SCons.Action
@ -42,7 +42,7 @@ import SCons.Node.FS
import SCons.Options
import SCons.Platform
import SCons.SConf
import SCons.Script
import SCons.Script.Main
import SCons.Tool
import SCons.Util
@ -55,26 +55,19 @@ import traceback
import types
import UserList
# The following variables used to live in this module. Some
# SConscript files out there may have referred to them directly as
# SCons.Script.SConscript.*. This is now supported by some special
# handling towards the bottom of the SConscript.__init__.py module.
#Arguments = {}
#ArgList = []
#BuildTargets = TargetList()
#CommandLineTargets = []
#DefaultTargets = []
launch_dir = os.path.abspath(os.curdir)
def do_nothing(text): pass
HelpFunction = do_nothing
Arguments = {}
ArgList = []
CommandLineTargets = []
DefaultCalled = None
DefaultTargets = []
GlobalDict = {}
class TargetList(UserList.UserList):
def _do_nothing(self, *args, **kw):
pass
def _add_Default(self, list):
self.extend(list)
def _clear(self):
del self[:]
BuildTargets = TargetList()
GlobalDict = None
# global exports set by Export():
global_exports = {}
@ -82,29 +75,21 @@ global_exports = {}
# chdir flag
sconscript_chdir = 1
# will be set to 1, if we are reading a SConscript
sconscript_reading = 0
def _scons_add_args(alist):
for arg in alist:
a, b = string.split(arg, '=', 1)
Arguments[a] = b
ArgList.append((a, b))
def _scons_add_targets(tlist):
if tlist:
CommandLineTargets.extend(tlist)
BuildTargets.extend(tlist)
BuildTargets._add_Default = BuildTargets._do_nothing
BuildTargets._clear = BuildTargets._do_nothing
def get_calling_namespaces():
"""Return the locals and globals for the function that called
into this module in the current callstack."""
into this module in the current call stack."""
try: 1/0
except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
while frame.f_globals.get("__name__") == __name__: frame = frame.f_back
# Find the first frame that *isn't* from this file. This means
# that we expect all of the SCons frames that implement an Export()
# or SConscript() call to be in this file, so that we can identify
# the first non-Script.SConscript frame as the user's local calling
# environment, and the locals and globals dictionaries from that
# frame as the calling namespaces. See the comment below preceding
# the DefaultEnvironmentCall block for even more explanation.
while frame.f_globals.get("__name__") == __name__:
frame = frame.f_back
return frame.f_locals, frame.f_globals
@ -130,22 +115,21 @@ def compute_exports(exports):
return retval
class Frame:
"""A frame on the SConstruct/SConscript call stack"""
def __init__(self, exports, sconscript):
def __init__(self, fs, exports, sconscript):
self.globals = BuildDefaultGlobals()
self.retval = None
self.prev_dir = SCons.Node.FS.default_fs.getcwd()
self.prev_dir = fs.getcwd()
self.exports = compute_exports(exports) # exports from the calling SConscript
# make sure the sconscript attr is a Node.
if isinstance(sconscript, SCons.Node.Node):
self.sconscript = sconscript
else:
self.sconscript = SCons.Node.FS.default_fs.File(str(sconscript))
self.sconscript = fs.File(str(sconscript))
# the SConstruct/SConscript call stack:
stack = []
call_stack = []
# For documentation on the methods in this file, see the scons man-page
@ -154,14 +138,17 @@ def Return(*vars):
try:
for var in vars:
for v in string.split(var):
retval.append(stack[-1].globals[v])
retval.append(call_stack[-1].globals[v])
except KeyError, x:
raise SCons.Errors.UserError, "Return of non-existent variable '%s'"%x
if len(retval) == 1:
stack[-1].retval = retval[0]
call_stack[-1].retval = retval[0]
else:
stack[-1].retval = tuple(retval)
call_stack[-1].retval = tuple(retval)
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
def _SConscript(fs, *files, **kw):
top = fs.Top
@ -171,13 +158,12 @@ def _SConscript(fs, *files, **kw):
# evaluate each SConscript file
results = []
for fn in files:
stack.append(Frame(exports,fn))
call_stack.append(Frame(fs, exports, fn))
old_sys_path = sys.path
try:
global sconscript_reading
sconscript_reading = 1
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1
if fn == "-":
exec sys.stdin in stack[-1].globals
exec sys.stdin in call_stack[-1].globals
else:
if isinstance(fn, SCons.Node.Node):
f = fn
@ -190,17 +176,17 @@ def _SConscript(fs, *files, **kw):
# fs match so we can open the SConscript.
fs.chdir(top, change_os_dir=1)
if f.rexists():
_file_ = open(f.rstr(), "r")
_file_ = open(f.rfile().get_abspath(), "r")
elif f.has_src_builder():
# The SConscript file apparently exists in a source
# code management system. Build it, but then clear
# the builder so that it doesn't get built *again*
# during the actual build phase.
f.build()
f.built()
f.builder_set(None)
s = str(f)
if os.path.exists(s):
_file_ = open(s, "r")
if f.exists():
_file_ = open(f.get_abspath(), "r")
if _file_:
# Chdir to the SConscript directory. Use a path
# name relative to the SConstruct file so that if
@ -212,6 +198,17 @@ def _SConscript(fs, *files, **kw):
# where the SConstruct and SConscript files might be
# in different Repositories. For now, cross that
# bridge when someone comes to it.
try:
src_dir = kw['src_dir']
except KeyError:
ldir = fs.Dir(f.dir.get_path(sd))
else:
ldir = fs.Dir(src_dir)
if not ldir.is_under(f.dir):
# They specified a source directory, but
# it's above the SConscript directory.
# Do the sensible thing and just use the
# SConcript directory.
ldir = fs.Dir(f.dir.get_path(sd))
try:
fs.chdir(ldir, change_os_dir=sconscript_chdir)
@ -223,6 +220,7 @@ def _SConscript(fs, *files, **kw):
# interpret the stuff within the SConscript file
# relative to where we are logically.
fs.chdir(ldir, change_os_dir=0)
# TODO Not sure how to handle src_dir here
os.chdir(f.rfile().dir.get_abspath())
# Append the SConscript directory to the beginning
@ -230,21 +228,32 @@ def _SConscript(fs, *files, **kw):
# directory can be easily imported.
sys.path = [ f.dir.get_abspath() ] + sys.path
# This is the magic line that actually reads up and
# executes the stuff in the SConscript file. We
# look for the "exec _file_ " from the beginning
# of this line to find the right stack frame (the
# next one) describing the SConscript file and line
# number that creates a node.
exec _file_ in stack[-1].globals
# This is the magic line that actually reads up
# and executes the stuff in the SConscript file.
# The locals for this frame contain the special
# bottom-of-the-stack marker so that any
# exceptions that occur when processing this
# SConscript can base the printed frames at this
# level and not show SCons internals as well.
call_stack[-1].globals.update({stack_bottom:1})
old_file = call_stack[-1].globals.get('__file__')
try:
del call_stack[-1].globals['__file__']
except KeyError:
pass
try:
exec _file_ in call_stack[-1].globals
finally:
if old_file is not None:
call_stack[-1].globals.update({__file__:old_file})
else:
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning,
"Ignoring missing SConscript '%s'" % f.path)
finally:
sconscript_reading = 0
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
sys.path = old_sys_path
frame = stack.pop()
frame = call_stack.pop()
try:
fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir)
except OSError:
@ -252,7 +261,9 @@ def _SConscript(fs, *files, **kw):
# Repository directory. Like above, we do this
# directly.
fs.chdir(frame.prev_dir, change_os_dir=0)
os.chdir(frame.prev_dir.rdir().get_abspath())
rdir = frame.prev_dir.rdir()
rdir._create() # Make sure there's a directory there.
os.chdir(rdir.get_abspath())
results.append(frame.retval)
@ -262,51 +273,41 @@ def _SConscript(fs, *files, **kw):
else:
return tuple(results)
def is_our_exec_statement(line):
return not line is None and line[:12] == "exec _file_ "
def SConscript_exception(file=sys.stderr):
"""Print an exception stack trace just for the SConscript file(s).
This will show users who have Python errors where the problem is,
without cluttering the output with all of the internal calls leading
up to where we exec the SConscript."""
exc_type, exc_value, exc_tb = sys.exc_info()
stack = traceback.extract_tb(exc_tb)
last_text = ""
found = 0
i = 0
for frame in stack:
if is_our_exec_statement(last_text):
found = 1
break
i = i + 1
last_text = frame[3]
if not found:
tb = exc_tb
while tb and not tb.tb_frame.f_locals.has_key(stack_bottom):
tb = tb.tb_next
if not tb:
# We did not find our exec statement, so this was actually a bug
# in SCons itself. Show the whole stack.
i = 0
tb = exc_tb
stack = traceback.extract_tb(tb)
try:
type = exc_type.__name__
except AttributeError:
type = str(exc_type)
if type[:11] == "exceptions.":
type = type[11:]
file.write('%s: %s:\n' % (type, exc_value))
for fname, line, func, text in stack[i:]:
for fname, line, func, text in stack:
file.write(' File "%s", line %d:\n' % (fname, line))
file.write(' %s\n' % text)
def annotate(node):
"""Annotate a node with the stack frame describing the
SConscript file and line number that created it."""
stack = traceback.extract_stack()
last_text = ""
for frame in stack:
# If the script text of the previous frame begins with the
# magic "exec _file_ " string, then this frame describes the
# SConscript file and line number that caused this node to be
# created. Record the tuple and carry on.
if is_our_exec_statement(last_text):
node.creator = frame
return
last_text = frame[3]
tb = sys.exc_info()[2]
while tb and not tb.tb_frame.f_locals.has_key(stack_bottom):
tb = tb.tb_next
if not tb:
# We did not find any exec of an SConscript file: what?!
raise SCons.Errors.InternalError, "could not find SConscript stack frame"
node.creator = traceback.extract_stack(tb)[0]
# The following line would cause each Node to be annotated using the
# above function. Unfortunately, this is a *huge* performance hit, so
@ -330,14 +331,20 @@ class SConsEnvironment(SCons.Environment.Base):
in 'v_major' and 'v_minor', and 0 otherwise."""
return (major > v_major or (major == v_major and minor > v_minor))
def _get_major_minor(self, version_string):
"""Split a version string into major and minor parts. This
is complicated by the fact that a version string can be something
like 3.2b1."""
def _get_major_minor_revision(self, version_string):
"""Split a version string into major, minor and (optionally)
revision parts.
This is complicated by the fact that a version string can be
something like 3.2b1."""
version = string.split(string.split(version_string, ' ')[0], '.')
v_major = int(version[0])
v_minor = int(re.match('\d+', version[1]).group())
return v_major, v_minor
if len(version) >= 3:
v_revision = int(re.match('\d+', version[2]).group())
else:
v_revision = 0
return v_major, v_minor, v_revision
def _get_SConscript_filenames(self, ls, kw):
"""
@ -392,6 +399,7 @@ class SConsEnvironment(SCons.Environment.Base):
src_dir = kw.get('src_dir')
if not src_dir:
src_dir, fname = os.path.split(str(files[0]))
files = [os.path.join(str(build_dir), fname)]
else:
if not isinstance(src_dir, SCons.Node.Node):
src_dir = self.fs.Dir(src_dir)
@ -401,11 +409,11 @@ class SConsEnvironment(SCons.Environment.Base):
if fn.is_under(src_dir):
# Get path relative to the source directory.
fname = fn.get_path(src_dir)
else:
# Fast way to only get the terminal path component of a Node.
fname = fn.get_path(fn.dir)
self.fs.BuildDir(build_dir, src_dir, duplicate)
files = [os.path.join(str(build_dir), fname)]
else:
files = [fn.abspath]
kw['src_dir'] = build_dir
self.fs.BuildDir(build_dir, src_dir, duplicate)
return (files, exports)
@ -415,40 +423,35 @@ class SConsEnvironment(SCons.Environment.Base):
# as global functions.
#
def Default(self, *targets):
global DefaultCalled
global DefaultTargets
DefaultCalled = 1
for t in targets:
if t is None:
# Delete the elements from the list in-place, don't
# reassign an empty list to DefaultTargets, so that the
# DEFAULT_TARGETS variable will still point to the
# same object we point to.
del DefaultTargets[:]
BuildTargets._clear()
elif isinstance(t, SCons.Node.Node):
DefaultTargets.append(t)
BuildTargets._add_Default([t])
else:
nodes = self.arg2nodes(t, self.fs.Entry)
DefaultTargets.extend(nodes)
BuildTargets._add_Default(nodes)
def Configure(self, *args, **kw):
if not SCons.Script.sconscript_reading:
raise SCons.Errors.UserError, "Calling Configure from Builders is not supported."
kw['_depth'] = kw.get('_depth', 0) + 1
return apply(SCons.Environment.Base.Configure, (self,)+args, kw)
def EnsureSConsVersion(self, major, minor):
def Default(self, *targets):
SCons.Script._Set_Default_Targets(self, targets)
def EnsureSConsVersion(self, major, minor, revision=0):
"""Exit abnormally if the SCons version is not late enough."""
v_major, v_minor = self._get_major_minor(SCons.__version__)
if self._exceeds_version(major, minor, v_major, v_minor):
print "SCons %d.%d or greater required, but you have SCons %s" %(major,minor,SCons.__version__)
scons_ver = self._get_major_minor_revision(SCons.__version__)
if scons_ver < (major, minor, revision):
if revision:
scons_ver_string = '%d.%d.%d' % (major, minor, revision)
else:
scons_ver_string = '%d.%d' % (major, minor)
print "SCons %s or greater required, but you have SCons %s" % \
(scons_ver_string, SCons.__version__)
sys.exit(2)
def EnsurePythonVersion(self, major, minor):
"""Exit abnormally if the Python version is not late enough."""
try:
v_major, v_minor, v_micro, release, serial = sys.version_info
python_ver = (v_major, v_minor)
except AttributeError:
v_major, v_minor = self._get_major_minor(sys.version)
if self._exceeds_version(major, minor, v_major, v_minor):
python_ver = self._get_major_minor_revision(sys.version)[:2]
if python_ver < (major, minor):
v = string.split(sys.version, " ", 1)[0]
print "Python %d.%d or greater required, but you have Python %s" %(major,minor,v)
sys.exit(2)
@ -466,30 +469,39 @@ class SConsEnvironment(SCons.Environment.Base):
def GetOption(self, name):
name = self.subst(name)
return SCons.Script.ssoptions.get(name)
return SCons.Script.Main.ssoptions.get(name)
def Help(self, text):
text = self.subst(text, raw=1)
HelpFunction(text)
SCons.Script.HelpFunction(text)
def Import(self, *vars):
try:
frame = call_stack[-1]
globals = frame.globals
exports = frame.exports
for var in vars:
var = self.Split(var)
for v in var:
if v == '*':
stack[-1].globals.update(global_exports)
stack[-1].globals.update(stack[-1].exports)
globals.update(global_exports)
globals.update(exports)
else:
if stack[-1].exports.has_key(v):
stack[-1].globals[v] = stack[-1].exports[v]
if exports.has_key(v):
globals[v] = exports[v]
else:
stack[-1].globals[v] = global_exports[v]
globals[v] = global_exports[v]
except KeyError,x:
raise SCons.Errors.UserError, "Import of non-existent variable '%s'"%x
def SConscript(self, *ls, **kw):
ls = map(lambda l, self=self: self.subst(l), ls)
def subst_element(x, subst=self.subst):
if SCons.Util.is_List(x):
x = map(subst, x)
else:
x = subst(x)
return x
ls = map(subst_element, ls)
subst_kw = {}
for key, val in kw.items():
if SCons.Util.is_String(val):
@ -504,8 +516,8 @@ class SConsEnvironment(SCons.Environment.Base):
subst_kw[key] = val
files, exports = self._get_SConscript_filenames(ls, subst_kw)
return apply(_SConscript, [self.fs,] + files, {'exports' : exports})
subst_kw['exports'] = exports
return apply(_SConscript, [self.fs,] + files, subst_kw)
def SConscriptChdir(self, flag):
global sconscript_chdir
@ -513,48 +525,34 @@ class SConsEnvironment(SCons.Environment.Base):
def SetOption(self, name, value):
name = self.subst(name)
SCons.Script.ssoptions.set(name, value)
SCons.Script.Main.ssoptions.set(name, value)
#
#
#
SCons.Environment.Environment = SConsEnvironment
def Options(files=None, args=Arguments):
return SCons.Options.Options(files, args)
def SetBuildSignatureType(type):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The SetBuildSignatureType() function has been deprecated;\n" +\
"\tuse the TargetSignatures() function instead.")
SCons.Defaults.DefaultEnvironment().TargetSignatures(type)
def SetContentSignatureType(type):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The SetContentSignatureType() function has been deprecated;\n" +\
"\tuse the SourceSignatures() function instead.")
SCons.Defaults.DefaultEnvironment().SourceSignatures(type)
def GetJobs():
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):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The SetJobs() function has been deprecated;\n" +\
"\tuse SetOption('num_jobs', num) instead.")
SetOption('num_jobs', num)
def ParseConfig(env, command, function=None):
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The ParseConfig() function has been deprecated;\n" +\
"\tuse the env.ParseConfig() method instead.")
return env.ParseConfig(command, function)
def Configure(*args, **kw):
if not SCons.Script.sconscript_reading:
raise SCons.Errors.UserError, "Calling Configure from Builders is not supported."
kw['_depth'] = 1
return apply(SCons.SConf.SConf, args, kw)
# It's very important that the DefaultEnvironmentCall() class stay in this
# file, with the get_calling_namespaces() function, the compute_exports()
# function, the Frame class and the SConsEnvironment.Export() method.
# These things make up the calling stack leading up to the actual global
# Export() or SConscript() call that the user issued. We want to allow
# users to export local variables that they define, like so:
#
# def func():
# x = 1
# Export('x')
#
# To support this, the get_calling_namespaces() function assumes that
# the *first* stack frame that's not from this file is the local frame
# for the Export() or SConscript() call.
_DefaultEnvironmentProxy = None
def get_DefaultEnvironmentProxy():
@ -573,92 +571,17 @@ class DefaultEnvironmentCall:
thereby prevent expansion of construction variables (since from
the user's point of view this was called as a global function,
with no associated construction environment)."""
def __init__(self, method_name):
def __init__(self, method_name, subst=0):
self.method_name = method_name
if subst:
self.factory = SCons.Defaults.DefaultEnvironment
else:
self.factory = get_DefaultEnvironmentProxy
def __call__(self, *args, **kw):
proxy = get_DefaultEnvironmentProxy()
method = getattr(proxy, self.method_name)
env = self.factory()
method = getattr(env, self.method_name)
return apply(method, args, kw)
# The list of global functions to add to the SConscript name space
# that end up calling corresponding methods or Builders in the
# DefaultEnvironment().
GlobalDefaultEnvironmentFunctions = [
# Methods from the SConsEnvironment class, above.
'Default',
'EnsurePythonVersion',
'EnsureSConsVersion',
'Exit',
'Export',
'GetLaunchDir',
'GetOption',
'Help',
'Import',
'SConscript',
'SConscriptChdir',
'SetOption',
# Methods from the Environment.Base class.
'AddPostAction',
'AddPreAction',
'Alias',
'AlwaysBuild',
'BuildDir',
'CacheDir',
'Clean',
'Command',
'Depends',
'Dir',
'Execute',
'File',
'FindFile',
'Flatten',
'GetBuildPath',
'Ignore',
'Install',
'InstallAs',
'Literal',
'Local',
'Precious',
'Repository',
'SConsignFile',
'SideEffect',
'SourceCode',
'SourceSignatures',
'Split',
'TargetSignatures',
'Value',
]
GlobalDefaultBuilders = [
# Supported builders.
'CFile',
'CXXFile',
'DVI',
'Jar',
'Java',
'JavaH',
'Library',
'M4',
'MSVSProject',
'Object',
'PCH',
'PDF',
'PostScript',
'Program',
'RES',
'RMIC',
'SharedLibrary',
'SharedObject',
'StaticLibrary',
'StaticObject',
'Tar',
'TypeLibrary',
'Zip',
]
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
GlobalDict[name] = DefaultEnvironmentCall(name)
def BuildDefaultGlobals():
"""
@ -666,52 +589,15 @@ def BuildDefaultGlobals():
SConstruct and SConscript files.
"""
globals = {
# Global functions that don't get executed through the
# default Environment.
'Action' : SCons.Action.Action,
'BoolOption' : SCons.Options.BoolOption,
'Builder' : SCons.Builder.Builder,
'Configure' : SCons.SConf.SConf,
'EnumOption' : SCons.Options.EnumOption,
'Environment' : SCons.Environment.Environment,
'ListOption' : SCons.Options.ListOption,
'Options' : Options,
'PackageOption' : SCons.Options.PackageOption,
'PathOption' : SCons.Options.PathOption,
'Platform' : SCons.Platform.Platform,
'Return' : Return,
'Scanner' : SCons.Scanner.Base,
'Tool' : SCons.Tool.Tool,
'WhereIs' : SCons.Util.WhereIs,
global GlobalDict
if GlobalDict is None:
GlobalDict = {}
# Action factories.
'Chmod' : SCons.Defaults.Chmod,
'Copy' : SCons.Defaults.Copy,
'Delete' : SCons.Defaults.Delete,
'Mkdir' : SCons.Defaults.Mkdir,
'Move' : SCons.Defaults.Move,
'Touch' : SCons.Defaults.Touch,
import SCons.Script
d = SCons.Script.__dict__
def not_a_module(m, d=d, mtype=type(SCons.Script)):
return type(d[m]) != mtype
for m in filter(not_a_module, dir(SCons.Script)):
GlobalDict[m] = d[m]
# Other variables we provide.
'ARGUMENTS' : Arguments,
'ARGLIST' : ArgList,
'BUILD_TARGETS' : BuildTargets,
'COMMAND_LINE_TARGETS' : CommandLineTargets,
'DEFAULT_TARGETS' : DefaultTargets,
}
# Functions we might still convert to Environment methods.
globals['CScan'] = SCons.Defaults.CScan
globals['DefaultEnvironment'] = SCons.Defaults.DefaultEnvironment
# Deprecated functions, leave these here for now.
globals['GetJobs'] = GetJobs
globals['ParseConfig'] = ParseConfig
globals['SetBuildSignatureType'] = SetBuildSignatureType
globals['SetContentSignatureType'] = SetContentSignatureType
globals['SetJobs'] = SetJobs
globals.update(GlobalDict)
return globals
return GlobalDict.copy()

View file

@ -0,0 +1,382 @@
"""SCons.Script
This file implements the main() function used by the scons script.
Architecturally, this *is* the scons script, and will likely only be
called from the external "scons" wrapper. Consequently, anything here
should not be, or be considered, part of the build engine. If it's
something that we expect other software to want to use, it should go in
some other module. If it's specific to the "scons" script invocation,
it goes here.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
import time
start_time = time.time()
import os
import string
import sys
import UserList
# Special chicken-and-egg handling of the "--debug=memoizer" flag:
#
# SCons.Memoize contains a metaclass implementation that affects how
# the other classes are instantiated. The Memoizer may add shim methods
# to classes that have methods that cache computed values in order to
# count and report the hits and misses.
#
# If we wait to enable the Memoization until after we've parsed the
# command line options normally, it will be too late, because the Memoizer
# will have already analyzed the classes that it's Memoizing and decided
# to not add the shims. So we use a special-case, up-front check for
# the "--debug=memoizer" flag and enable Memoizer before we import any
# of the other modules that use it.
_args = sys.argv + string.split(os.environ.get('SCONSFLAGS', ''))
if "--debug=memoizer" in _args:
import SCons.Memoize
import SCons.Warnings
try:
SCons.Memoize.EnableMemoization()
except SCons.Warnings.Warning:
# Some warning was thrown (inability to --debug=memoizer on
# Python 1.5.2 because it doesn't have metaclasses). Arrange
# for it to be displayed or not after warnings are configured.
import Main
exc_type, exc_value, tb = sys.exc_info()
Main.delayed_warnings.append(exc_type, exc_value)
del _args
import SCons.Action
import SCons.Builder
import SCons.Environment
import SCons.Node.FS
import SCons.Options
import SCons.Platform
import SCons.Scanner
import SCons.SConf
import SCons.Subst
import SCons.Tool
import SCons.Util
import SCons.Defaults
import Main
main = Main.main
# The following are global class definitions and variables that used to
# live directly in this module back before 0.96.90, when it contained
# a lot of code. Some SConscript files in widely-distributed packages
# (Blender is the specific example) actually reached into SCons.Script
# directly to use some of these. Rather than break those SConscript
# files, we're going to propagate these names into the SCons.Script
# namespace here.
#
# Some of these are commented out because it's *really* unlikely anyone
# used them, but we're going to leave the comment here to try to make
# it obvious what to do if the situation arises.
BuildTask = Main.BuildTask
CleanTask = Main.CleanTask
QuestionTask = Main.QuestionTask
#PrintHelp = Main.PrintHelp
OptParser = Main.OptParser
SConscriptSettableOptions = Main.SConscriptSettableOptions
keep_going_on_error = Main.keep_going_on_error
#print_dtree = Main.print_dtree
print_explanations = Main.print_explanations
print_includes = Main.print_includes
print_objects = Main.print_objects
print_time = Main.print_time
#print_tree = Main.print_tree
memory_stats = Main.memory_stats
ignore_errors = Main.ignore_errors
#sconscript_time = Main.sconscript_time
#command_time = Main.command_time
#exit_status = Main.exit_status
#profiling = Main.profiling
repositories = Main.repositories
#
import SConscript
_SConscript = SConscript
call_stack = _SConscript.call_stack
#
Action = SCons.Action.Action
AllowSubstExceptions = SCons.Subst.SetAllowableExceptions
BoolOption = SCons.Options.BoolOption
Builder = SCons.Builder.Builder
Configure = _SConscript.Configure
EnumOption = SCons.Options.EnumOption
Environment = SCons.Environment.Environment
FindPathDirs = SCons.Scanner.FindPathDirs
ListOption = SCons.Options.ListOption
PackageOption = SCons.Options.PackageOption
PathOption = SCons.Options.PathOption
Platform = SCons.Platform.Platform
Return = _SConscript.Return
Scanner = SCons.Scanner.Base
Tool = SCons.Tool.Tool
WhereIs = SCons.Util.WhereIs
# Action factories.
Chmod = SCons.Defaults.Chmod
Copy = SCons.Defaults.Copy
Delete = SCons.Defaults.Delete
Mkdir = SCons.Defaults.Mkdir
Move = SCons.Defaults.Move
Touch = SCons.Defaults.Touch
# Pre-made, public scanners.
CScanner = SCons.Tool.CScanner
DScanner = SCons.Tool.DScanner
DirScanner = SCons.Defaults.DirScanner
ProgramScanner = SCons.Tool.ProgramScanner
SourceFileScanner = SCons.Tool.SourceFileScanner
# Functions we might still convert to Environment methods.
CScan = SCons.Defaults.CScan
DefaultEnvironment = SCons.Defaults.DefaultEnvironment
# Other variables we provide.
class TargetList(UserList.UserList):
def _do_nothing(self, *args, **kw):
pass
def _add_Default(self, list):
self.extend(list)
def _clear(self):
del self[:]
ARGUMENTS = {}
ARGLIST = []
BUILD_TARGETS = TargetList()
COMMAND_LINE_TARGETS = []
DEFAULT_TARGETS = []
# BUILD_TARGETS can be modified in the SConscript files. If so, we
# want to treat the modified BUILD_TARGETS list as if they specified
# targets on the command line. To do that, though, we need to know if
# BUILD_TARGETS was modified through "official" APIs or by hand. We do
# this by updating two lists in parallel, the documented BUILD_TARGETS
# list, above, and this internal _build_plus_default targets list which
# should only have "official" API changes. Then Script/Main.py can
# compare these two afterwards to figure out if the user added their
# own targets to BUILD_TARGETS.
_build_plus_default = TargetList()
def _Add_Arguments(alist):
for arg in alist:
a, b = string.split(arg, '=', 1)
ARGUMENTS[a] = b
ARGLIST.append((a, b))
def _Add_Targets(tlist):
if tlist:
COMMAND_LINE_TARGETS.extend(tlist)
BUILD_TARGETS.extend(tlist)
BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
_build_plus_default.extend(tlist)
_build_plus_default._add_Default = _build_plus_default._do_nothing
_build_plus_default._clear = _build_plus_default._do_nothing
def _Set_Default_Targets_Has_Been_Called(d, fs):
return DEFAULT_TARGETS
def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
if d is None:
d = [fs.Dir('.')]
return d
_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
def _Set_Default_Targets(env, tlist):
global DEFAULT_TARGETS
global _Get_Default_Targets
_Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
for t in tlist:
if t is None:
# Delete the elements from the list in-place, don't
# reassign an empty list to DEFAULT_TARGETS, so that the
# variables will still point to the same object we point to.
del DEFAULT_TARGETS[:]
BUILD_TARGETS._clear()
_build_plus_default._clear()
elif isinstance(t, SCons.Node.Node):
DEFAULT_TARGETS.append(t)
BUILD_TARGETS._add_Default([t])
_build_plus_default._add_Default([t])
else:
nodes = env.arg2nodes(t, env.fs.Entry)
DEFAULT_TARGETS.extend(nodes)
BUILD_TARGETS._add_Default(nodes)
_build_plus_default._add_Default(nodes)
#
help_text = None
def HelpFunction(text):
global help_text
if SCons.Script.help_text is None:
SCons.Script.help_text = text
else:
help_text = help_text + text
#
# Will be non-zero if we are reading an SConscript file.
sconscript_reading = 0
#
def Options(files=None, args=ARGUMENTS):
return SCons.Options.Options(files, args)
# The list of global functions to add to the SConscript name space
# that end up calling corresponding methods or Builders in the
# DefaultEnvironment().
GlobalDefaultEnvironmentFunctions = [
# Methods from the SConsEnvironment class, above.
'Default',
'EnsurePythonVersion',
'EnsureSConsVersion',
'Exit',
'Export',
'GetLaunchDir',
'GetOption',
'Help',
'Import',
#'SConscript', is handled separately, below.
'SConscriptChdir',
'SetOption',
# Methods from the Environment.Base class.
'AddPostAction',
'AddPreAction',
'Alias',
'AlwaysBuild',
'BuildDir',
'CacheDir',
'Clean',
#The Command() method is handled separately, below.
'Depends',
'Dir',
'NoClean',
'NoCache',
'Entry',
'Execute',
'File',
'FindFile',
'Flatten',
'GetBuildPath',
'Ignore',
'Install',
'InstallAs',
'Literal',
'Local',
'ParseDepends',
'Precious',
'Repository',
'SConsignFile',
'SideEffect',
'SourceCode',
'SourceSignatures',
'Split',
'TargetSignatures',
'Value',
]
GlobalDefaultBuilders = [
# Supported builders.
'CFile',
'CXXFile',
'DVI',
'Jar',
'Java',
'JavaH',
'Library',
'M4',
'MSVSProject',
'Object',
'PCH',
'PDF',
'PostScript',
'Program',
'RES',
'RMIC',
'SharedLibrary',
'SharedObject',
'StaticLibrary',
'StaticObject',
'Tar',
'TypeLibrary',
'Zip',
]
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
del name
# There are a handful of variables that used to live in the
# Script/SConscript.py module that some SConscript files out there were
# accessing directly as SCons.Script.SConscript.*. The problem is that
# "SConscript" in this namespace is no longer a module, it's a global
# function call--or more precisely, an object that implements a global
# function call through the default Environment. Nevertheless, we can
# maintain backwards compatibility for SConscripts that were reaching in
# this way by hanging some attributes off the "SConscript" object here.
SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
# Make SConscript look enough like the module it used to be so
# that pychecker doesn't barf.
SConscript.__name__ = 'SConscript'
SConscript.Arguments = ARGUMENTS
SConscript.ArgList = ARGLIST
SConscript.BuildTargets = BUILD_TARGETS
SConscript.CommandLineTargets = COMMAND_LINE_TARGETS
SConscript.DefaultTargets = DEFAULT_TARGETS
# The global Command() function must be handled differently than the
# global functions for other construction environment methods because
# we want people to be able to use Actions that must expand $TARGET
# and $SOURCE later, when (and if) the Action is invoked to build
# the target(s). We do this with the subst=1 argument, which creates
# a DefaultEnvironmentCall instance that wraps up a normal default
# construction environment that performs variable substitution, not a
# proxy that doesn't.
#
# There's a flaw here, though, because any other $-variables on a command
# line will *also* be expanded, each to a null string, but that should
# only be a problem in the unusual case where someone was passing a '$'
# on a command line and *expected* the $ to get through to the shell
# because they were calling Command() and not env.Command()... This is
# unlikely enough that we're going to leave this as is and cross that
# bridge if someone actually comes to it.
Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)

View file

@ -6,7 +6,7 @@ utility.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -28,13 +28,13 @@ utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/MD5.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/MD5.py 0.97.D001 2007/05/17 11:35:19 knight"
import imp
import string
# Force Python to load the builtin "md5" module. If we do this with a
# normal import statement, then case-insensitive systems (Win32) get
# normal import statement, then case-insensitive systems (Windows) get
# confused and thinks there's a case mismatch with *this* MD5.py module.
file, name, desc = imp.find_module('md5')
try:
@ -49,18 +49,30 @@ def current(new, old):
"""
return new == old
def hexdigest(s):
"""Return a signature as a string of hex characters.
"""
# NOTE: This routine is a method in the Python 2.0 interface
# of the native md5 module, but we want SCons to operate all
# the way back to at least Python 1.5.2, which doesn't have it.
try:
md5.new('').hexdigest
except AttributeError:
# The md5 objects created by the module have no native hexdigest()
# method (*cough* 1.5.2 *cough*) so provide an equivalent.
class new_md5:
def __init__(self, s):
self.m = md5.new(str(s))
#def copy(self):
# return self.m.copy()
def digest(self):
return self.m.digest()
def hexdigest(self):
h = string.hexdigits
r = ''
for c in s:
for c in self.m.digest():
i = ord(c)
r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
return r
def update(self, s):
return self.m.update(s)
else:
new_md5 = lambda s: md5.new(str(s))
def collect(signatures):
"""
@ -72,8 +84,7 @@ def collect(signatures):
if len(signatures) == 1:
return signatures[0]
else:
contents = string.join(signatures, ', ')
return hexdigest(md5.new(contents).digest())
return new_md5(string.join(signatures, ', ')).hexdigest()
def signature(obj):
"""Generate a signature for an object
@ -82,7 +93,7 @@ def signature(obj):
gc = obj.get_contents
except AttributeError:
raise AttributeError, "unable to fetch contents of '%s'" % str(obj)
return hexdigest(md5.new(str(gc())).digest())
return new_md5(gc()).hexdigest()
def to_string(signature):
"""Convert a signature to a string"""

View file

@ -6,7 +6,7 @@ utility.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -28,7 +28,7 @@ utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/TimeStamp.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/TimeStamp.py 0.97.D001 2007/05/17 11:35:19 knight"
def current(new, old):
"""Return whether a new timestamp is up-to-date with

View file

@ -5,7 +5,7 @@ The Signature package for the scons software construction utility.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,7 +27,7 @@ The Signature package for the scons software construction utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
try:
import MD5
@ -36,34 +36,18 @@ except ImportError:
import TimeStamp
default_module = TimeStamp
# XXX We should move max_drift into Node/FS.py,
# since it's really something about files.
default_max_drift = 2*24*60*60
class SConsignEntry:
"""The old SConsignEntry format.
We keep this around to handle conversions from old .sconsign files."""
timestamp = None
bsig = None
csig = None
implicit = None
class Calculator:
"""
Encapsulates signature calculations and .sconsign file generating
for the build engine.
"""
def __init__(self, module=default_module, max_drift=default_max_drift):
def __init__(self, module=default_module):
"""
Initialize the calculator.
module - the signature module to use for signature calculations
max_drift - the maximum system clock drift used to determine when to
cache content signatures. A negative value means to never cache
content signatures. (defaults to 2 days)
"""
self.module = module
self.max_drift = max_drift
default_calc = Calculator()

View file

@ -0,0 +1,853 @@
"""SCons.Subst
SCons string substitution.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Subst.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.compat
import re
import string
import types
import UserList
import UserString
import SCons.Errors
from SCons.Util import is_String, is_List, is_Tuple
# Indexed by the SUBST_* constants below.
_strconv = [SCons.Util.to_String,
SCons.Util.to_String,
SCons.Util.to_String_for_signature]
AllowableExceptions = (IndexError, NameError)
def SetAllowableExceptions(*excepts):
global AllowableExceptions
AllowableExceptions = filter(None, excepts)
def raise_exception(exception, target, s):
name = exception.__class__.__name__
msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s)
if target:
raise SCons.Errors.BuildError, (target[0], msg)
else:
raise SCons.Errors.UserError, msg
class Literal:
"""A wrapper for a string. If you use this object wrapped
around a string, then it will be interpreted as literal.
When passed to the command interpreter, all special
characters will be escaped."""
def __init__(self, lstr):
self.lstr = lstr
def __str__(self):
return self.lstr
def escape(self, escape_func):
return escape_func(self.lstr)
def for_signature(self):
return self.lstr
def is_literal(self):
return 1
class SpecialAttrWrapper:
"""This is a wrapper for what we call a 'Node special attribute.'
This is any of the attributes of a Node that we can reference from
Environment variable substitution, such as $TARGET.abspath or
$SOURCES[1].filebase. We implement the same methods as Literal
so we can handle special characters, plus a for_signature method,
such that we can return some canonical string during signature
calculation to avoid unnecessary rebuilds."""
def __init__(self, lstr, for_signature=None):
"""The for_signature parameter, if supplied, will be the
canonical string we return from for_signature(). Else
we will simply return lstr."""
self.lstr = lstr
if for_signature:
self.forsig = for_signature
else:
self.forsig = lstr
def __str__(self):
return self.lstr
def escape(self, escape_func):
return escape_func(self.lstr)
def for_signature(self):
return self.forsig
def is_literal(self):
return 1
def quote_spaces(arg):
"""Generic function for putting double quotes around any string that
has white space in it."""
if ' ' in arg or '\t' in arg:
return '"%s"' % arg
else:
return str(arg)
class CmdStringHolder(UserString.UserString):
"""This is a special class used to hold strings generated by
scons_subst() and scons_subst_list(). It defines a special method
escape(). When passed a function with an escape algorithm for a
particular platform, it will return the contained string with the
proper escape sequences inserted.
"""
def __init__(self, cmd, literal=None):
UserString.UserString.__init__(self, cmd)
self.literal = literal
def is_literal(self):
return self.literal
def escape(self, escape_func, quote_func=quote_spaces):
"""Escape the string with the supplied function. The
function is expected to take an arbitrary string, then
return it with all special characters escaped and ready
for passing to the command interpreter.
After calling this function, the next call to str() will
return the escaped string.
"""
if self.is_literal():
return escape_func(self.data)
elif ' ' in self.data or '\t' in self.data:
return quote_func(self.data)
else:
return self.data
def escape_list(list, escape_func):
"""Escape a list of arguments by running the specified escape_func
on every object in the list that has an escape() method."""
def escape(obj, escape_func=escape_func):
try:
e = obj.escape
except AttributeError:
return obj
else:
return e(escape_func)
return map(escape, list)
class NLWrapper:
"""A wrapper class that delays turning a list of sources or targets
into a NodeList until it's needed. The specified function supplied
when the object is initialized is responsible for turning raw nodes
into proxies that implement the special attributes like .abspath,
.source, etc. This way, we avoid creating those proxies just
"in case" someone is going to use $TARGET or the like, and only
go through the trouble if we really have to.
In practice, this might be a wash performance-wise, but it's a little
cleaner conceptually...
"""
def __init__(self, list, func):
self.list = list
self.func = func
def _return_nodelist(self):
return self.nodelist
def _gen_nodelist(self):
list = self.list
if list is None:
list = []
elif not is_List(list) and not is_Tuple(list):
list = [list]
# The map(self.func) call is what actually turns
# a list into appropriate proxies.
self.nodelist = SCons.Util.NodeList(map(self.func, list))
self._create_nodelist = self._return_nodelist
return self.nodelist
_create_nodelist = _gen_nodelist
class Targets_or_Sources(UserList.UserList):
"""A class that implements $TARGETS or $SOURCES expansions by in turn
wrapping a NLWrapper. This class handles the different methods used
to access the list, calling the NLWrapper to create proxies on demand.
Note that we subclass UserList.UserList purely so that the is_List()
function will identify an object of this class as a list during
variable expansion. We're not really using any UserList.UserList
methods in practice.
"""
def __init__(self, nl):
self.nl = nl
def __getattr__(self, attr):
nl = self.nl._create_nodelist()
return getattr(nl, attr)
def __getitem__(self, i):
nl = self.nl._create_nodelist()
return nl[i]
def __getslice__(self, i, j):
nl = self.nl._create_nodelist()
i = max(i, 0); j = max(j, 0)
return nl[i:j]
def __str__(self):
nl = self.nl._create_nodelist()
return str(nl)
def __repr__(self):
nl = self.nl._create_nodelist()
return repr(nl)
class Target_or_Source:
"""A class that implements $TARGET or $SOURCE expansions by in turn
wrapping a NLWrapper. This class handles the different methods used
to access an individual proxy Node, calling the NLWrapper to create
a proxy on demand.
"""
def __init__(self, nl):
self.nl = nl
def __getattr__(self, attr):
nl = self.nl._create_nodelist()
try:
nl0 = nl[0]
except IndexError:
# If there is nothing in the list, then we have no attributes to
# pass through, so raise AttributeError for everything.
raise AttributeError, "NodeList has no attribute: %s" % attr
return getattr(nl0, attr)
def __str__(self):
nl = self.nl._create_nodelist()
if nl:
return str(nl[0])
return ''
def __repr__(self):
nl = self.nl._create_nodelist()
if nl:
return repr(nl[0])
return ''
def subst_dict(target, source):
"""Create a dictionary for substitution of special
construction variables.
This translates the following special arguments:
target - the target (object or array of objects),
used to generate the TARGET and TARGETS
construction variables
source - the source (object or array of objects),
used to generate the SOURCES and SOURCE
construction variables
"""
dict = {}
if target:
tnl = NLWrapper(target, lambda x: x.get_subst_proxy())
dict['TARGETS'] = Targets_or_Sources(tnl)
dict['TARGET'] = Target_or_Source(tnl)
else:
dict['TARGETS'] = None
dict['TARGET'] = None
if source:
def get_src_subst_proxy(node):
try:
rfile = node.rfile
except AttributeError:
pass
else:
node = rfile()
return node.get_subst_proxy()
snl = NLWrapper(source, get_src_subst_proxy)
dict['SOURCES'] = Targets_or_Sources(snl)
dict['SOURCE'] = Target_or_Source(snl)
else:
dict['SOURCES'] = None
dict['SOURCE'] = None
return dict
# Constants for the "mode" parameter to scons_subst_list() and
# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
# gives a command line suitable for passing to a shell. SUBST_SIG
# gives a command line appropriate for calculating the signature
# of a command line...if this changes, we should rebuild.
SUBST_CMD = 0
SUBST_RAW = 1
SUBST_SIG = 2
_rm = re.compile(r'\$[()]')
_remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)')
# Indexed by the SUBST_* constants above.
_regex_remove = [ _rm, None, _remove ]
# Regular expressions for splitting strings and handling substitutions,
# for use by the scons_subst() and scons_subst_list() functions:
#
# The first expression compiled matches all of the $-introduced tokens
# that we need to process in some way, and is used for substitutions.
# The expressions it matches are:
#
# "$$"
# "$("
# "$)"
# "$variable" [must begin with alphabetic or underscore]
# "${any stuff}"
#
# The second expression compiled is used for splitting strings into tokens
# to be processed, and it matches all of the tokens listed above, plus
# the following that affect how arguments do or don't get joined together:
#
# " " [white space]
# "non-white-space" [without any dollar signs]
# "$" [single dollar sign]
#
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
_separate_args = re.compile(r'(%s|\s+|[^\s\$]+|\$)' % _dollar_exps_str)
# This regular expression is used to replace strings of multiple white
# space characters in the string result from the scons_subst() function.
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
"""Expand a string containing construction variable substitutions.
This is the work-horse function for substitutions in file names
and the like. The companion scons_subst_list() function (below)
handles separating command lines into lists of arguments, so see
that function if that's what you're looking for.
"""
if type(strSubst) == types.StringType and string.find(strSubst, '$') < 0:
return strSubst
class StringSubber:
"""A class to construct the results of a scons_subst() call.
This binds a specific construction environment, mode, target and
source with two methods (substitute() and expand()) that handle
the expansion.
"""
def __init__(self, env, mode, target, source, conv, gvars):
self.env = env
self.mode = mode
self.target = target
self.source = source
self.conv = conv
self.gvars = gvars
def expand(self, s, lvars):
"""Expand a single "token" as necessary, returning an
appropriate string containing the expansion.
This handles expanding different types of things (strings,
lists, callables) appropriately. It calls the wrapper
substitute() method to re-expand things as necessary, so that
the results of expansions of side-by-side strings still get
re-evaluated separately, not smushed together.
"""
if is_String(s):
try:
s0, s1 = s[:2]
except (IndexError, ValueError):
return s
if s0 != '$':
return s
if s1 == '$':
return '$'
elif s1 in '()':
return s
else:
key = s[1:]
if key[0] == '{' or string.find(key, '.') >= 0:
if key[0] == '{':
key = key[1:-1]
try:
s = eval(key, self.gvars, lvars)
except KeyboardInterrupt:
raise
except Exception, e:
if e.__class__ in AllowableExceptions:
return ''
raise_exception(e, self.target, s)
else:
if lvars.has_key(key):
s = lvars[key]
elif self.gvars.has_key(key):
s = self.gvars[key]
elif not NameError in AllowableExceptions:
raise_exception(NameError(key), self.target, s)
else:
return ''
# Before re-expanding the result, handle
# recursive expansion by copying the local
# variable dictionary and overwriting a null
# string for the value of the variable name
# we just expanded.
#
# This could potentially be optimized by only
# copying lvars when s contains more expansions,
# but lvars is usually supposed to be pretty
# small, and deeply nested variable expansions
# are probably more the exception than the norm,
# so it should be tolerable for now.
lv = lvars.copy()
var = string.split(key, '.')[0]
lv[var] = ''
return self.substitute(s, lv)
elif is_List(s) or is_Tuple(s):
def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
return conv(substitute(l, lvars))
r = map(func, s)
return string.join(r)
elif callable(s):
try:
s = s(target=self.target,
source=self.source,
env=self.env,
for_signature=(self.mode != SUBST_CMD))
except TypeError:
# This probably indicates that it's a callable
# object that doesn't match our calling arguments
# (like an Action).
if self.mode == SUBST_RAW:
return s
s = self.conv(s)
return self.substitute(s, lvars)
elif s is None:
return ''
else:
return s
def substitute(self, args, lvars):
"""Substitute expansions in an argument or list of arguments.
This serves as a wrapper for splitting up a string into
separate tokens.
"""
if is_String(args) and not isinstance(args, CmdStringHolder):
try:
def sub_match(match, conv=self.conv, expand=self.expand, lvars=lvars):
return conv(expand(match.group(1), lvars))
result = _dollar_exps.sub(sub_match, args)
except TypeError:
# If the internal conversion routine doesn't return
# strings (it could be overridden to return Nodes, for
# example), then the 1.5.2 re module will throw this
# exception. Back off to a slower, general-purpose
# algorithm that works for all data types.
args = _separate_args.findall(args)
result = []
for a in args:
result.append(self.conv(self.expand(a, lvars)))
try:
result = string.join(result, '')
except TypeError:
if len(result) == 1:
result = result[0]
return result
else:
return self.expand(args, lvars)
if conv is None:
conv = _strconv[mode]
# Doing this every time is a bit of a waste, since the Executor
# has typically already populated the OverrideEnvironment with
# $TARGET/$SOURCE variables. We're keeping this (for now), though,
# because it supports existing behavior that allows us to call
# an Action directly with an arbitrary target+source pair, which
# we use in Tool/tex.py to handle calling $BIBTEX when necessary.
# If we dropped that behavior (or found another way to cover it),
# we could get rid of this call completely and just rely on the
# Executor setting the variables.
d = subst_dict(target, source)
if d:
lvars = lvars.copy()
lvars.update(d)
# We're (most likely) going to eval() things. If Python doesn't
# find a __builtins__ value in the global dictionary used for eval(),
# it copies the current global values for you. Avoid this by
# setting it explicitly and then deleting, so we don't pollute the
# construction environment Dictionary(ies) that are typically used
# for expansion.
gvars['__builtins__'] = __builtins__
ss = StringSubber(env, mode, target, source, conv, gvars)
result = ss.substitute(strSubst, lvars)
try:
del gvars['__builtins__']
except KeyError:
pass
if is_String(result):
# Remove $(-$) pairs and any stuff in between,
# if that's appropriate.
remove = _regex_remove[mode]
if remove:
result = remove.sub('', result)
if mode != SUBST_RAW:
# Compress strings of white space characters into
# a single space.
result = string.strip(_space_sep.sub(' ', result))
return result
#Subst_List_Strings = {}
def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
"""Substitute construction variables in a string (or list or other
object) and separate the arguments into a command list.
The companion scons_subst() function (above) handles basic
substitutions within strings, so see that function instead
if that's what you're looking for.
"""
# try:
# Subst_List_Strings[strSubst] = Subst_List_Strings[strSubst] + 1
# except KeyError:
# Subst_List_Strings[strSubst] = 1
# import SCons.Debug
# SCons.Debug.caller(1)
class ListSubber(UserList.UserList):
"""A class to construct the results of a scons_subst_list() call.
Like StringSubber, this class binds a specific construction
environment, mode, target and source with two methods
(substitute() and expand()) that handle the expansion.
In addition, however, this class is used to track the state of
the result(s) we're gathering so we can do the appropriate thing
whenever we have to append another word to the result--start a new
line, start a new word, append to the current word, etc. We do
this by setting the "append" attribute to the right method so
that our wrapper methods only need ever call ListSubber.append(),
and the rest of the object takes care of doing the right thing
internally.
"""
def __init__(self, env, mode, target, source, conv, gvars):
UserList.UserList.__init__(self, [])
self.env = env
self.mode = mode
self.target = target
self.source = source
self.conv = conv
self.gvars = gvars
if self.mode == SUBST_RAW:
self.add_strip = lambda x, s=self: s.append(x)
else:
self.add_strip = lambda x, s=self: None
self.in_strip = None
self.next_line()
def expand(self, s, lvars, within_list):
"""Expand a single "token" as necessary, appending the
expansion to the current result.
This handles expanding different types of things (strings,
lists, callables) appropriately. It calls the wrapper
substitute() method to re-expand things as necessary, so that
the results of expansions of side-by-side strings still get
re-evaluated separately, not smushed together.
"""
if is_String(s):
try:
s0, s1 = s[:2]
except (IndexError, ValueError):
self.append(s)
return
if s0 != '$':
self.append(s)
return
if s1 == '$':
self.append('$')
elif s1 == '(':
self.open_strip('$(')
elif s1 == ')':
self.close_strip('$)')
else:
key = s[1:]
if key[0] == '{' or string.find(key, '.') >= 0:
if key[0] == '{':
key = key[1:-1]
try:
s = eval(key, self.gvars, lvars)
except KeyboardInterrupt:
raise
except Exception, e:
if e.__class__ in AllowableExceptions:
return
raise_exception(e, self.target, s)
else:
if lvars.has_key(key):
s = lvars[key]
elif self.gvars.has_key(key):
s = self.gvars[key]
elif not NameError in AllowableExceptions:
raise_exception(NameError(), self.target, s)
else:
return
# Before re-expanding the result, handle
# recursive expansion by copying the local
# variable dictionary and overwriting a null
# string for the value of the variable name
# we just expanded.
lv = lvars.copy()
var = string.split(key, '.')[0]
lv[var] = ''
self.substitute(s, lv, 0)
self.this_word()
elif is_List(s) or is_Tuple(s):
for a in s:
self.substitute(a, lvars, 1)
self.next_word()
elif callable(s):
try:
s = s(target=self.target,
source=self.source,
env=self.env,
for_signature=(self.mode != SUBST_CMD))
except TypeError:
# This probably indicates that it's a callable
# object that doesn't match our calling arguments
# (like an Action).
if self.mode == SUBST_RAW:
self.append(s)
return
s = self.conv(s)
self.substitute(s, lvars, within_list)
elif s is None:
self.this_word()
else:
self.append(s)
def substitute(self, args, lvars, within_list):
"""Substitute expansions in an argument or list of arguments.
This serves as a wrapper for splitting up a string into
separate tokens.
"""
if is_String(args) and not isinstance(args, CmdStringHolder):
args = _separate_args.findall(args)
for a in args:
if a[0] in ' \t\n\r\f\v':
if '\n' in a:
self.next_line()
elif within_list:
self.append(a)
else:
self.next_word()
else:
self.expand(a, lvars, within_list)
else:
self.expand(args, lvars, within_list)
def next_line(self):
"""Arrange for the next word to start a new line. This
is like starting a new word, except that we have to append
another line to the result."""
UserList.UserList.append(self, [])
self.next_word()
def this_word(self):
"""Arrange for the next word to append to the end of the
current last word in the result."""
self.append = self.add_to_current_word
def next_word(self):
"""Arrange for the next word to start a new word."""
self.append = self.add_new_word
def add_to_current_word(self, x):
"""Append the string x to the end of the current last word
in the result. If that is not possible, then just add
it as a new word. Make sure the entire concatenated string
inherits the object attributes of x (in particular, the
escape function) by wrapping it as CmdStringHolder."""
if not self.in_strip or self.mode != SUBST_SIG:
try:
current_word = self[-1][-1]
except IndexError:
self.add_new_word(x)
else:
# All right, this is a hack and it should probably
# be refactored out of existence in the future.
# The issue is that we want to smoosh words together
# and make one file name that gets escaped if
# we're expanding something like foo$EXTENSION,
# but we don't want to smoosh them together if
# it's something like >$TARGET, because then we'll
# treat the '>' like it's part of the file name.
# So for now, just hard-code looking for the special
# command-line redirection characters...
try:
last_char = str(current_word)[-1]
except IndexError:
last_char = '\0'
if last_char in '<>|':
self.add_new_word(x)
else:
y = current_word + x
# We used to treat a word appended to a literal
# as a literal itself, but this caused problems
# with interpreting quotes around space-separated
# targets on command lines. Removing this makes
# none of the "substantive" end-to-end tests fail,
# so we'll take this out but leave it commented
# for now in case there's a problem not covered
# by the test cases and we need to resurrect this.
#literal1 = self.literal(self[-1][-1])
#literal2 = self.literal(x)
y = self.conv(y)
if is_String(y):
#y = CmdStringHolder(y, literal1 or literal2)
y = CmdStringHolder(y, None)
self[-1][-1] = y
def add_new_word(self, x):
if not self.in_strip or self.mode != SUBST_SIG:
literal = self.literal(x)
x = self.conv(x)
if is_String(x):
x = CmdStringHolder(x, literal)
self[-1].append(x)
self.append = self.add_to_current_word
def literal(self, x):
try:
l = x.is_literal
except AttributeError:
return None
else:
return l()
def open_strip(self, x):
"""Handle the "open strip" $( token."""
self.add_strip(x)
self.in_strip = 1
def close_strip(self, x):
"""Handle the "close strip" $) token."""
self.add_strip(x)
self.in_strip = None
if conv is None:
conv = _strconv[mode]
# Doing this every time is a bit of a waste, since the Executor
# has typically already populated the OverrideEnvironment with
# $TARGET/$SOURCE variables. We're keeping this (for now), though,
# because it supports existing behavior that allows us to call
# an Action directly with an arbitrary target+source pair, which
# we use in Tool/tex.py to handle calling $BIBTEX when necessary.
# If we dropped that behavior (or found another way to cover it),
# we could get rid of this call completely and just rely on the
# Executor setting the variables.
d = subst_dict(target, source)
if d:
lvars = lvars.copy()
lvars.update(d)
# We're (most likely) going to eval() things. If Python doesn't
# find a __builtins__ value in the global dictionary used for eval(),
# it copies the current global values for you. Avoid this by
# setting it explicitly and then deleting, so we don't pollute the
# construction environment Dictionary(ies) that are typically used
# for expansion.
gvars['__builtins__'] = __builtins__
ls = ListSubber(env, mode, target, source, conv, gvars)
ls.substitute(strSubst, lvars, 0)
try:
del gvars['__builtins__']
except KeyError:
pass
return ls.data
def scons_subst_once(strSubst, env, key):
"""Perform single (non-recursive) substitution of a single
construction variable keyword.
This is used when setting a variable when copying or overriding values
in an Environment. We want to capture (expand) the old value before
we override it, so people can do things like:
env2 = env.Clone(CCFLAGS = '$CCFLAGS -g')
We do this with some straightforward, brute-force code here...
"""
if type(strSubst) == types.StringType and string.find(strSubst, '$') < 0:
return strSubst
matchlist = ['$' + key, '${' + key + '}']
val = env.get(key, '')
def sub_match(match, val=val, matchlist=matchlist):
a = match.group(1)
if a in matchlist:
a = val
if is_List(a) or is_Tuple(a):
return string.join(map(str, a))
else:
return str(a)
if is_List(strSubst) or is_Tuple(strSubst):
result = []
for arg in strSubst:
if is_String(arg):
if arg in matchlist:
arg = val
if is_List(arg) or is_Tuple(arg):
result.extend(arg)
else:
result.append(arg)
else:
result.append(_dollar_exps.sub(sub_match, arg))
else:
result.append(arg)
return result
elif is_String(strSubst):
return _dollar_exps.sub(sub_match, strSubst)
else:
return strSubst

View file

@ -0,0 +1,685 @@
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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.
#
__doc__ = """
Generic Taskmaster module for the SCons build engine.
This module contains the primary interface(s) between a wrapping user
interface and the SCons build engine. There are two key classes here:
Taskmaster
This is the main engine for walking the dependency graph and
calling things to decide what does or doesn't need to be built.
Task
This is the base class for allowing a wrapping interface to
decide what does or doesn't actually need to be done. The
intention is for a wrapping interface to subclass this as
appropriate for different types of behavior it may need.
The canonical example is the SCons native Python interface,
which has Task subclasses that handle its specific behavior,
like printing "`foo' is up to date" when a top-level target
doesn't need to be built, and handling the -c option by removing
targets as its "build" action. There is also a separate subclass
for suppressing this output when the -q option is used.
The Taskmaster instantiates a Task object for each (set of)
target(s) that it decides need to be evaluated and/or built.
"""
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Taskmaster.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.compat
import operator
import string
import sys
import traceback
import SCons.Node
import SCons.Errors
StateString = SCons.Node.StateString
# A subsystem for recording stats about how different Nodes are handled by
# the main Taskmaster loop. There's no external control here (no need for
# a --debug= option); enable it by changing the value of CollectStats.
CollectStats = None
class Stats:
"""
A simple class for holding statistics about the disposition of a
Node by the Taskmaster. If we're collecting statistics, each Node
processed by the Taskmaster gets one of these attached, in which case
the Taskmaster records its decision each time it processes the Node.
(Ideally, that's just once per Node.)
"""
def __init__(self):
"""
Instantiates a Taskmaster.Stats object, initializing all
appropriate counters to zero.
"""
self.considered = 0
self.already_handled = 0
self.problem = 0
self.child_failed = 0
self.not_built = 0
self.side_effects = 0
self.build = 0
StatsNodes = []
fmt = "%(considered)3d "\
"%(already_handled)3d " \
"%(problem)3d " \
"%(child_failed)3d " \
"%(not_built)3d " \
"%(side_effects)3d " \
"%(build)3d "
def dump_stats():
StatsNodes.sort(lambda a, b: cmp(str(a), str(b)))
for n in StatsNodes:
print (fmt % n.stats.__dict__) + str(n)
class Task:
"""
Default SCons build engine task.
This controls the interaction of the actual building of node
and the rest of the engine.
This is expected to handle all of the normally-customizable
aspects of controlling a build, so any given application
*should* be able to do what it wants by sub-classing this
class and overriding methods as appropriate. If an application
needs to customze something by sub-classing Taskmaster (or
some other build engine class), we should first try to migrate
that functionality into this class.
Note that it's generally a good idea for sub-classes to call
these methods explicitly to update state, etc., rather than
roll their own interaction with Taskmaster from scratch.
"""
def __init__(self, tm, targets, top, node):
self.tm = tm
self.targets = targets
self.top = top
self.node = node
self.exc_clear()
def display(self, message):
"""
Hook to allow the calling interface to display a message.
This hook gets called as part of preparing a task for execution
(that is, a Node to be built). As part of figuring out what Node
should be built next, the actually target list may be altered,
along with a message describing the alteration. The calling
interface can subclass Task and provide a concrete implementation
of this method to see those messages.
"""
pass
def prepare(self):
"""
Called just before the task is executed.
This is mainly intended to give the target Nodes a chance to
unlink underlying files and make all necessary directories before
the Action is actually called to build the targets.
"""
# Now that it's the appropriate time, give the TaskMaster a
# chance to raise any exceptions it encountered while preparing
# this task.
self.exception_raise()
if self.tm.message:
self.display(self.tm.message)
self.tm.message = None
for t in self.targets:
t.prepare()
for s in t.side_effects:
s.prepare()
def get_target(self):
"""Fetch the target being built or updated by this task.
"""
return self.node
def execute(self):
"""
Called to execute the task.
This method is called from multiple threads in a parallel build,
so only do thread safe stuff here. Do thread unsafe stuff in
prepare(), executed() or failed().
"""
try:
everything_was_cached = 1
for t in self.targets:
if not t.retrieve_from_cache():
everything_was_cached = 0
break
if not everything_was_cached:
self.targets[0].build()
except KeyboardInterrupt:
raise
except SystemExit:
exc_value = sys.exc_info()[1]
raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code)
except SCons.Errors.UserError:
raise
except SCons.Errors.BuildError:
raise
except:
raise SCons.Errors.TaskmasterException(self.targets[0],
sys.exc_info())
def executed(self):
"""
Called when the task has been successfully executed.
This may have been a do-nothing operation (to preserve build
order), so we have to check the node's state before deciding
whether it was "built" or just "visited."
"""
for t in self.targets:
if t.get_state() == SCons.Node.executing:
t.set_state(SCons.Node.executed)
t.built()
else:
t.visited()
def failed(self):
"""
Default action when a task fails: stop the build.
"""
self.fail_stop()
def fail_stop(self):
"""
Explicit stop-the-build failure.
"""
for t in self.targets:
t.set_state(SCons.Node.failed)
self.tm.stop()
# We're stopping because of a build failure, but give the
# calling Task class a chance to postprocess() the top-level
# target under which the build failure occurred.
self.targets = [self.tm.current_top]
self.top = 1
def fail_continue(self):
"""
Explicit continue-the-build failure.
This sets failure status on the target nodes and all of
their dependent parent nodes.
"""
for t in self.targets:
# Set failure state on all of the parents that were dependent
# on this failed build.
def set_state(node): node.set_state(SCons.Node.failed)
t.call_for_all_waiting_parents(set_state)
def make_ready_all(self):
"""
Marks all targets in a task ready for execution.
This is used when the interface needs every target Node to be
visited--the canonical example being the "scons -c" option.
"""
self.out_of_date = self.targets[:]
for t in self.targets:
t.disambiguate().set_state(SCons.Node.executing)
for s in t.side_effects:
s.set_state(SCons.Node.executing)
def make_ready_current(self):
"""
Marks all targets in a task ready for execution if any target
is not current.
This is the default behavior for building only what's necessary.
"""
self.out_of_date = []
for t in self.targets:
try:
is_up_to_date = t.disambiguate().current()
except EnvironmentError, e:
raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename)
if is_up_to_date:
t.set_state(SCons.Node.up_to_date)
else:
self.out_of_date.append(t)
t.set_state(SCons.Node.executing)
for s in t.side_effects:
s.set_state(SCons.Node.executing)
make_ready = make_ready_current
def postprocess(self):
"""
Post-processes a task after it's been executed.
This examines all the targets just built (or not, we don't care
if the build was successful, or even if there was no build
because everything was up-to-date) to see if they have any
waiting parent Nodes, or Nodes waiting on a common side effect,
that can be put back on the candidates list.
"""
# We may have built multiple targets, some of which may have
# common parents waiting for this build. Count up how many
# targets each parent was waiting for so we can subtract the
# values later, and so we *don't* put waiting side-effect Nodes
# back on the candidates list if the Node is also a waiting
# parent.
parents = {}
for t in self.targets:
for p in t.waiting_parents.keys():
parents[p] = parents.get(p, 0) + 1
for t in self.targets:
for s in t.side_effects:
if s.get_state() == SCons.Node.executing:
s.set_state(SCons.Node.no_state)
for p in s.waiting_parents.keys():
if not parents.has_key(p):
parents[p] = 1
for p in s.waiting_s_e.keys():
if p.ref_count == 0:
self.tm.candidates.append(p)
for p, subtract in parents.items():
p.ref_count = p.ref_count - subtract
if p.ref_count == 0:
self.tm.candidates.append(p)
for t in self.targets:
t.postprocess()
# Exception handling subsystem.
#
# Exceptions that occur while walking the DAG or examining Nodes
# must be raised, but must be raised at an appropriate time and in
# a controlled manner so we can, if necessary, recover gracefully,
# possibly write out signature information for Nodes we've updated,
# etc. This is done by having the Taskmaster tell us about the
# exception, and letting
def exc_info(self):
"""
Returns info about a recorded exception.
"""
return self.exception
def exc_clear(self):
"""
Clears any recorded exception.
This also changes the "exception_raise" attribute to point
to the appropriate do-nothing method.
"""
self.exception = (None, None, None)
self.exception_raise = self._no_exception_to_raise
def exception_set(self, exception=None):
"""
Records an exception to be raised at the appropriate time.
This also changes the "exception_raise" attribute to point
to the method that will, in fact
"""
if not exception:
exception = sys.exc_info()
self.exception = exception
self.exception_raise = self._exception_raise
def _no_exception_to_raise(self):
pass
def _exception_raise(self):
"""
Raises a pending exception that was recorded while getting a
Task ready for execution.
"""
exc = self.exc_info()[:]
try:
exc_type, exc_value, exc_traceback = exc
except ValueError:
exc_type, exc_value = exc
exc_traceback = None
raise exc_type, exc_value, exc_traceback
def find_cycle(stack):
if stack[0] == stack[-1]:
return stack
for n in stack[-1].waiting_parents.keys():
stack.append(n)
if find_cycle(stack):
return stack
stack.pop()
return None
class Taskmaster:
"""
The Taskmaster for walking the dependency DAG.
"""
def __init__(self, targets=[], tasker=Task, order=None, trace=None):
self.top_targets = targets[:]
self.top_targets.reverse()
self.candidates = []
self.tasker = tasker
if not order:
order = lambda l: l
self.order = order
self.message = None
self.trace = trace
self.next_candidate = self.find_next_candidate
def find_next_candidate(self):
"""
Returns the next candidate Node for (potential) evaluation.
The candidate list (really a stack) initially consists of all of
the top-level (command line) targets provided when the Taskmaster
was initialized. While we walk the DAG, visiting Nodes, all the
children that haven't finished processing get pushed on to the
candidate list. Each child can then be popped and examined in
turn for whether *their* children are all up-to-date, in which
case a Task will be created for their actual evaluation and
potential building.
Here is where we also allow candidate Nodes to alter the list of
Nodes that should be examined. This is used, for example, when
invoking SCons in a source directory. A source directory Node can
return its corresponding build directory Node, essentially saying,
"Hey, you really need to build this thing over here instead."
"""
try:
return self.candidates.pop()
except IndexError:
pass
try:
node = self.top_targets.pop()
except IndexError:
return None
self.current_top = node
alt, message = node.alter_targets()
if alt:
self.message = message
self.candidates.append(node)
self.candidates.extend(self.order(alt))
node = self.candidates.pop()
return node
def no_next_candidate(self):
"""
Stops Taskmaster processing by not returning a next candidate.
"""
return None
def _find_next_ready_node(self):
"""
Finds the next node that is ready to be built.
This is *the* main guts of the DAG walk. We loop through the
list of candidates, looking for something that has no un-built
children (i.e., that is a leaf Node or has dependencies that are
all leaf Nodes or up-to-date). Candidate Nodes are re-scanned
(both the target Node itself and its sources, which are always
scanned in the context of a given target) to discover implicit
dependencies. A Node that must wait for some children to be
built will be put back on the candidates list after the children
have finished building. A Node that has been put back on the
candidates list in this way may have itself (or its sources)
re-scanned, in order to handle generated header files (e.g.) and
the implicit dependencies therein.
Note that this method does not do any signature calculation or
up-to-date check itself. All of that is handled by the Task
class. This is purely concerned with the dependency graph walk.
"""
self.ready_exc = None
T = self.trace
while 1:
node = self.next_candidate()
if node is None:
return None
node = node.disambiguate()
state = node.get_state()
if CollectStats:
if not hasattr(node, 'stats'):
node.stats = Stats()
StatsNodes.append(node)
S = node.stats
S.considered = S.considered + 1
else:
S = None
if T: T.write('Taskmaster: %s:' % repr(str(node)))
# Skip this node if it has already been evaluated:
if state > SCons.Node.pending:
if S: S.already_handled = S.already_handled + 1
if T: T.write(' already handled (%s)\n' % StateString[state])
continue
# Mark this node as being on the execution stack:
node.set_state(SCons.Node.pending)
try:
children = node.children()
except SystemExit:
exc_value = sys.exc_info()[1]
e = SCons.Errors.ExplicitExit(node, exc_value.code)
self.ready_exc = (SCons.Errors.ExplicitExit, e)
if T: T.write(' SystemExit\n')
return node
except KeyboardInterrupt:
if T: T.write(' KeyboardInterrupt\n')
raise
except:
# We had a problem just trying to figure out the
# children (like a child couldn't be linked in to a
# BuildDir, or a Scanner threw something). Arrange to
# raise the exception when the Task is "executed."
self.ready_exc = sys.exc_info()
if S: S.problem = S.problem + 1
if T: T.write(' exception\n')
return node
if T and children:
c = map(str, children)
c.sort()
T.write(' children:\n %s\n ' % c)
childinfo = map(lambda N: (N.get_state(),
N.is_derived() or N.is_pseudo_derived(),
N), children)
# Skip this node if any of its children have failed. This
# catches the case where we're descending a top-level target
# and one of our children failed while trying to be built
# by a *previous* descent of an earlier top-level target.
failed_children = filter(lambda I: I[0] == SCons.Node.failed,
childinfo)
if failed_children:
node.set_state(SCons.Node.failed)
if S: S.child_failed = S.child_failed + 1
if T:
c = map(str, failed_children)
c.sort()
T.write(' children failed:\n %s\n' % c)
continue
# Detect dependency cycles:
pending_nodes = filter(lambda I: I[0] == SCons.Node.pending, childinfo)
if pending_nodes:
for p in pending_nodes:
cycle = find_cycle([p[2], node])
if cycle:
desc = "Dependency cycle: " + string.join(map(str, cycle), " -> ")
if T: T.write(' dependency cycle\n')
raise SCons.Errors.UserError, desc
# Select all of the dependencies that are derived targets
# (that is, children who have builders or are side effects).
derived_children = filter(lambda I: I[1], childinfo)
not_started = filter(lambda I: not I[0], derived_children)
if not_started:
not_started = map(lambda I: I[2], not_started)
# We're waiting on one more derived targets that have
# not yet started building. Add this node to the
# waiting_parents lists of those derived files so that
# when they've finished building, our implicit dependency
# list will get cleared and we'll re-scan the newly-built
# file(s) for updated implicit dependencies.
added = map(lambda n, P=node: n.add_to_waiting_parents(P), not_started)
node.ref_count = node.ref_count + reduce(operator.add, added, 0)
# Now we add these derived targets to the candidates
# list so they can be examined and built. We have to
# add ourselves back to the list first, though, so we get
# a chance to re-scan and build after the dependencies.
#
# We reverse the order in which the children are added
# to the candidates stack so the order in which they're
# popped matches the order in which they show up in our
# children's list. This is more logical / efficient for
# builders with multiple targets, since the "primary"
# target will be examined first.
self.candidates.append(node)
not_started.reverse()
self.candidates.extend(self.order(not_started))
if S: S.not_started = S.not_started + 1
if T:
c = map(str, not_started)
c.sort()
T.write(' waiting on unstarted children:\n %s\n' % c)
continue
not_built = filter(lambda I: I[0] <= SCons.Node.executing, derived_children)
if not_built:
not_built = map(lambda I: I[2], not_built)
# We're waiting on one or more derived targets that have
# started building but not yet finished. Add this node
# to the waiting parents lists of those derived files
# so that when they've finished building, our implicit
# dependency list will get cleared and we'll re-scan the
# newly-built file(s) for updated implicit dependencies.
added = map(lambda n, P=node: n.add_to_waiting_parents(P), not_built)
node.ref_count = node.ref_count + reduce(operator.add, added, 0)
if S: S.not_built = S.not_built + 1
if T:
c = map(str, not_built)
c.sort()
T.write(' waiting on unfinished children:\n %s\n' % c)
continue
# Skip this node if it has side-effects that are currently being
# built themselves or waiting for something else being built.
side_effects = filter(lambda N:
N.get_state() == SCons.Node.executing,
node.side_effects)
if side_effects:
map(lambda n, P=node: n.add_to_waiting_s_e(P), side_effects)
if S: S.side_effects = S.side_effects + 1
if T:
c = map(str, side_effects)
c.sort()
T.write(' waiting on side effects:\n %s\n' % c)
continue
# 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(' evaluating %s\n' % node)
return node
return None
def next_task(self):
"""
Returns the next task to be executed.
This simply asks for the next Node to be evaluated, and then wraps
it in the specific Task subclass with which we were initialized.
"""
node = self._find_next_ready_node()
if node is None:
return None
tlist = node.get_executor().targets
task = self.tasker(self, tlist, node is self.current_top, node)
try:
task.make_ready()
except KeyboardInterrupt:
raise
except:
# We had a problem just trying to get this task ready (like
# a child couldn't be linked in to a BuildDir when deciding
# whether this node is current). Arrange to raise the
# exception when the Task is "executed."
self.ready_exc = sys.exc_info()
if self.ready_exc:
task.exception_set(self.ready_exc)
self.ready_exc = None
return task
def stop(self):
"""
Stops the current build completely.
"""
self.next_candidate = self.no_next_candidate

View file

@ -10,7 +10,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -32,21 +32,22 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/386asm.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/386asm.py 0.97.D001 2007/05/17 11:35:19 knight"
from SCons.Tool.PharLapCommon import addPharLapPaths
import SCons.Util
import as
as_module = __import__('as', globals(), locals(), [])
def generate(env):
"""Add Builders and construction variables for ar to an Environment."""
as.generate(env)
as_module.generate(env)
env['AS'] = '386asm'
env['ASFLAGS'] = SCons.Util.CLVar('')
env['ASPPFLAGS'] = '$ASFLAGS'
env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET'
env['ASPPCOM'] = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET'
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET'
addPharLapPaths(env)

View file

@ -10,7 +10,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -32,10 +32,9 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/BitKeeper.py 0.96.1.D001 2004/08/23 09:55:29 knight"
import os.path
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/BitKeeper.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Builder
import SCons.Util
@ -45,7 +44,8 @@ def generate(env):
def BitKeeperFactory(env=env):
""" """
return SCons.Builder.Builder(action = "$BITKEEPERCOM", env = env)
act = SCons.Action.Action("$BITKEEPERCOM", "$BITKEEPERCOMSTR")
return SCons.Builder.Builder(action = act, env = env)
#setattr(env, 'BitKeeper', BitKeeperFactory)
env.BitKeeper = BitKeeperFactory

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,8 +31,9 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/CVS.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/CVS.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Builder
import SCons.Util
@ -48,7 +49,8 @@ def generate(env):
# be across a network and must use POSIX slashes as separators.
module = module + '/'
env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS -d ${TARGET.dir} $CVSMODULE${TARGET.posix}'
return SCons.Builder.Builder(action = '$CVSCOM',
act = SCons.Action.Action('$CVSCOM', '$CVSCOMSTR')
return SCons.Builder.Builder(action = act,
env = env,
CVSREPOSITORY = repos,
CVSMODULE = module)

View file

@ -5,7 +5,7 @@ Stuff for processing Java.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,7 +27,7 @@ Stuff for processing Java.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/JavaCommon.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/JavaCommon.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
@ -42,13 +42,19 @@ if java_parsing:
# This is a really cool parser from Charles Crain
# that finds appropriate class names in Java source.
# A regular expression that will find, in a java file: newlines;
# any alphanumeric token (keyword, class name, specifier); open or
# close brackets; a single-line comment "//"; the multi-line comment
# begin and end tokens /* and */; single or double quotes; and
# single or double quotes preceeded by a backslash.
_reToken = re.compile(r'(\n|//|\\[\'"]|[\'"\{\}]|[A-Za-z_][\w\.]*|' +
r'/\*|\*/)')
# A regular expression that will find, in a java file:
# newlines;
# double-backslashes;
# a single-line comment "//";
# single or double quotes preceeded by a backslash;
# single quotes, double quotes, open or close braces, semi-colons;
# any alphanumeric token (keyword, class name, specifier);
# the multi-line comment begin and end tokens /* and */;
# array declarations "[]";
# semi-colons;
# periods.
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.]|' +
r'[A-Za-z_][\w\.]*|/\*|\*/|\[\])')
class OuterState:
"""The initial state for parsing a Java file for classes,
@ -61,6 +67,9 @@ if java_parsing:
self.nextAnon = 1
self.package = None
def trace(self):
pass
def __getClassState(self):
try:
return self.classState
@ -93,41 +102,51 @@ if java_parsing:
self.skipState = ret
return ret
def parseToken(self, token):
if token[:2] == '//':
return IgnoreState('\n', self)
elif token == '/*':
return IgnoreState('*/', self)
elif token == '{':
def openBracket(self):
self.brackets = self.brackets + 1
elif token == '}':
def closeBracket(self):
self.brackets = self.brackets - 1
if len(self.stackBrackets) and \
self.brackets == self.stackBrackets[-1]:
self.listOutputs.append(string.join(self.listClasses, '$'))
self.listClasses.pop()
self.stackBrackets.pop()
elif token == '"' or token == "'":
def parseToken(self, token):
if token[:2] == '//':
return IgnoreState('\n', self)
elif token == '/*':
return IgnoreState('*/', self)
elif token == '{':
self.openBracket()
elif token == '}':
self.closeBracket()
elif token in [ '"', "'" ]:
return IgnoreState(token, self)
elif token == "new":
# anonymous inner class
if len(self.listClasses) > 0:
return self.__getAnonClassState()
return self.__getSkipState() # Skip the class name
elif token == 'class' or token == 'interface':
elif token in ['class', 'interface', 'enum']:
if len(self.listClasses) == 0:
self.nextAnon = 1
self.stackBrackets.append(self.brackets)
return self.__getClassState()
elif token == 'package':
return self.__getPackageState()
elif token == '.':
# Skip the attribute, it might be named "class", in which
# case we don't want to treat the following token as
# an inner class name...
return self.__getSkipState()
return self
def addAnonClass(self):
"""Add an anonymous inner class"""
clazz = self.listClasses[0]
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
self.brackets = self.brackets + 1
self.nextAnon = self.nextAnon + 1
def setPackage(self, package):
@ -140,9 +159,17 @@ if java_parsing:
self.outer_state = outer_state
self.tokens_to_find = 2
def parseToken(self, token):
# This is an anonymous class if and only if the next token is a bracket
# This is an anonymous class if and only if the next
# non-whitespace token is a bracket
if token == '\n':
return self
if token == '{':
self.outer_state.openBracket()
self.outer_state.addAnonClass()
elif token == '}':
self.outer_state.closeBracket()
elif token in ['"', "'"]:
return IgnoreState(token, self)
return self.outer_state
class SkipState:
@ -193,7 +220,7 @@ if java_parsing:
def parse_java_file(fn):
return parse_java(open(fn, 'r').read())
def parse_java(contents):
def parse_java(contents, trace=None):
"""Parse a .java file and return a double of package directory,
plus a list of .class files that compiling that .java file will
produce"""
@ -204,6 +231,7 @@ if java_parsing:
# The regex produces a bunch of groups, but only one will
# have anything in it.
currstate = currstate.parseToken(token)
if trace: trace(token, currstate)
if initial.package:
package = string.replace(initial.package, '.', os.sep)
return (package, initial.listOutputs)

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,10 +31,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Perforce.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Perforce.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import SCons.Action
import SCons.Builder
import SCons.Node.FS
import SCons.Util
@ -42,18 +43,21 @@ import SCons.Util
# This function should maybe be moved to SCons.Util?
from SCons.Tool.PharLapCommon import addPathIfNotExists
# Variables that we want to import from the base OS environment.
_import_env = [ 'P4PORT', 'P4CLIENT', 'P4USER', 'USER', 'USERNAME', 'P4PASSWD',
'P4CHARSET', 'P4LANGUAGE', 'SYSTEMROOT' ]
PerforceAction = SCons.Action.Action('$P4COM', '$P4COMSTR')
def generate(env):
"""Add a Builder factory function and construction variables for
Perforce to an Environment."""
def PerforceFactory(env=env):
""" """
return SCons.Builder.Builder(action = '$P4COM',
env = env)
return SCons.Builder.Builder(action = PerforceAction, env = env)
#setattr(env, 'Perforce', PerforceFactory)
env.Perforce = PerforceFactory
@ -70,8 +74,8 @@ def generate(env):
# Perforce seems to use the PWD environment variable rather than
# calling getcwd() for itself, which is odd. If no PWD variable
# is present, p4 WILL call getcwd, but this seems to cause problems
# with good ol' Win32's tilde-mangling for long file names.
environ['PWD'] = SCons.Node.FS.default_fs.Dir('#').get_abspath()
# with good ol' Windows's tilde-mangling for long file names.
environ['PWD'] = env.Dir('#').get_abspath()
for var in _import_env:
v = os.environ.get(var)

View file

@ -7,7 +7,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -29,7 +29,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/PharLapCommon.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/PharLapCommon.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,8 +31,9 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/RCS.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/RCS.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Builder
import SCons.Util
@ -42,7 +43,8 @@ def generate(env):
def RCSFactory(env=env):
""" """
return SCons.Builder.Builder(action = '$RCS_COCOM', env = env)
act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR')
return SCons.Builder.Builder(action = act, env = env)
#setattr(env, 'RCS', RCSFactory)
env.RCS = RCSFactory

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,8 +31,9 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/SCCS.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/SCCS.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Builder
import SCons.Util
@ -42,7 +43,8 @@ def generate(env):
def SCCSFactory(env=env):
""" """
return SCons.Builder.Builder(action = '$SCCSCOM', env = env)
act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR')
return SCons.Builder.Builder(action = act, env = env)
#setattr(env, 'SCCS', SCCSFactory)
env.SCCS = SCCSFactory

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,10 +31,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Subversion.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Subversion.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path
import SCons.Action
import SCons.Builder
import SCons.Util
@ -47,7 +48,8 @@ def generate(env):
# fail if repos is not an absolute path name?
if module != '':
module = os.path.join(module, '')
return SCons.Builder.Builder(action = '$SVNCOM',
act = SCons.Action.Action('$SVNCOM', '$SVNCOMSTR')
return SCons.Builder.Builder(action = act,
env = env,
SVNREPOSITORY = repos,
SVNMODULE = module)

View file

@ -14,7 +14,7 @@ tool definition.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -36,58 +36,129 @@ tool definition.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/__init__.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/__init__.py 0.97.D001 2007/05/17 11:35:19 knight"
import imp
import sys
import SCons.Builder
import SCons.Errors
import SCons.Defaults
import SCons.Scanner
import SCons.Scanner.C
import SCons.Scanner.D
import SCons.Scanner.LaTeX
import SCons.Scanner.Prog
class ToolSpec:
def __init__(self, name):
DefaultToolpath=[]
CScanner = SCons.Scanner.C.CScanner()
DScanner = SCons.Scanner.D.DScanner()
LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
".h", ".H", ".hxx", ".hpp", ".hh",
".F", ".fpp", ".FPP",
".m", ".mm",
".S", ".spp", ".SPP"]
DSuffixes = ['.d']
IDLSuffixes = [".idl", ".IDL"]
LaTeXSuffixes = [".tex", ".ltx", ".latex"]
for suffix in CSuffixes:
SourceFileScanner.add_scanner(suffix, CScanner)
for suffix in DSuffixes:
SourceFileScanner.add_scanner(suffix, DScanner)
for suffix in LaTeXSuffixes:
SourceFileScanner.add_scanner(suffix, LaTeXScanner)
class Tool:
def __init__(self, name, toolpath=[], **kw):
self.name = name
self.toolpath = toolpath + DefaultToolpath
# remember these so we can merge them into the call
self.init_kw = kw
module = self._tool_module()
self.generate = module.generate
self.exists = module.exists
def _tool_module(self):
oldpythonpath = sys.path
sys.path = self.toolpath + sys.path
try:
try:
file, path, desc = imp.find_module(self.name, self.toolpath)
try:
return imp.load_module(self.name, file, path, desc)
finally:
if file:
file.close()
except ImportError, e:
try:
import zipimport
except ImportError:
pass
else:
for aPath in self.toolpath:
try:
importer = zipimport.zipimporter(aPath)
return importer.load_module(self.name)
except ImportError, e:
pass
finally:
sys.path = oldpythonpath
full_name = 'SCons.Tool.' + self.name
try:
return sys.modules[full_name]
except KeyError:
try:
smpath = sys.modules['SCons.Tool'].__path__
try:
file, path, desc = imp.find_module(self.name, smpath)
module = imp.load_module(full_name, file, path, desc)
setattr(SCons.Tool, self.name, module)
if file:
file.close()
return module
except ImportError, e:
try:
import zipimport
importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
module = importer.load_module(full_name)
setattr(SCons.Tool, self.name, module)
return module
except ImportError, e:
m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.UserError, m
except ImportError, e:
m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.UserError, m
def __call__(self, env, *args, **kw):
if self.init_kw is not None:
# Merge call kws into init kws;
# but don't bash self.init_kw.
if kw is not None:
call_kw = kw
kw = self.init_kw.copy()
kw.update(call_kw)
else:
kw = self.init_kw
env.Append(TOOLS = [ self.name ])
apply(self.generate, ( env, ) + args, kw)
def __str__(self):
return self.name
def Tool(name, toolpath=[]):
"Select a canned Tool specification, optionally searching in toolpath."
try:
file, path, desc = imp.find_module(name, toolpath)
try:
module = imp.load_module(name, file, path, desc)
spec = ToolSpec(name)
spec.generate = module.generate
spec.exists = module.exists
return spec
finally:
if file:
file.close()
except ImportError, e:
pass
full_name = 'SCons.Tool.' + name
if not sys.modules.has_key(full_name):
try:
file, path, desc = imp.find_module(name,
sys.modules['SCons.Tool'].__path__)
mod = imp.load_module(full_name, file, path, desc)
setattr(SCons.Tool, name, mod)
except ImportError, e:
raise SCons.Errors.UserError, "No tool named '%s': %s" % (name, e)
if file:
file.close()
spec = ToolSpec(name)
spec.generate = sys.modules[full_name].generate
spec.exists = sys.modules[full_name].exists
return spec
def createProgBuilder(env):
"""This is a utility function that creates the Program
Builder in an Environment if it is not there already.
@ -98,13 +169,14 @@ def createProgBuilder(env):
try:
program = env['BUILDERS']['Program']
except KeyError:
import SCons.Defaults
program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction,
emitter = '$PROGEMITTER',
prefix = '$PROGPREFIX',
suffix = '$PROGSUFFIX',
src_suffix = '$OBJSUFFIX',
src_builder = 'Object',
target_scanner = SCons.Defaults.ProgScan)
target_scanner = ProgramScanner)
env['BUILDERS']['Program'] = program
return program
@ -119,7 +191,12 @@ def createStaticLibBuilder(env):
try:
static_lib = env['BUILDERS']['StaticLibrary']
except KeyError:
static_lib = SCons.Builder.Builder(action = SCons.Defaults.ArAction,
action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
if env.Detect('ranlib'):
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
action_list.append(ranlib_action)
static_lib = SCons.Builder.Builder(action = action_list,
emitter = '$LIBEMITTER',
prefix = '$LIBPREFIX',
suffix = '$LIBSUFFIX',
@ -140,19 +217,44 @@ def createSharedLibBuilder(env):
try:
shared_lib = env['BUILDERS']['SharedLibrary']
except KeyError:
import SCons.Defaults
action_list = [ SCons.Defaults.SharedCheck,
SCons.Defaults.ShLinkAction ]
shared_lib = SCons.Builder.Builder(action = action_list,
emitter = "$SHLIBEMITTER",
prefix = '$SHLIBPREFIX',
suffix = '$SHLIBSUFFIX',
target_scanner = SCons.Defaults.ProgScan,
target_scanner = ProgramScanner,
src_suffix = '$SHOBJSUFFIX',
src_builder = 'SharedObject')
env['BUILDERS']['SharedLibrary'] = shared_lib
return shared_lib
def createLoadableModuleBuilder(env):
"""This is a utility function that creates the LoadableModule
Builder in an Environment if it is not there already.
If it is already there, we return the existing one.
"""
try:
ld_module = env['BUILDERS']['LoadableModule']
except KeyError:
import SCons.Defaults
action_list = [ SCons.Defaults.SharedCheck,
SCons.Defaults.LdModuleLinkAction ]
ld_module = SCons.Builder.Builder(action = action_list,
emitter = "$SHLIBEMITTER",
prefix = '$LDMODULEPREFIX',
suffix = '$LDMODULESUFFIX',
target_scanner = ProgramScanner,
src_suffix = '$SHOBJSUFFIX',
src_builder = 'SharedObject')
env['BUILDERS']['LoadableModule'] = ld_module
return ld_module
def createObjBuilders(env):
"""This is a utility function that creates the StaticObject
and SharedObject Builders in an Environment if they
@ -166,6 +268,7 @@ def createObjBuilders(env):
The return is a 2-tuple of (StaticObject, SharedObject)
"""
try:
static_obj = env['BUILDERS']['StaticObject']
except KeyError:
@ -174,7 +277,8 @@ def createObjBuilders(env):
prefix = '$OBJPREFIX',
suffix = '$OBJSUFFIX',
src_builder = ['CFile', 'CXXFile'],
source_scanner = SCons.Defaults.ObjSourceScan, single_source=1)
source_scanner = SourceFileScanner,
single_source = 1)
env['BUILDERS']['StaticObject'] = static_obj
env['BUILDERS']['Object'] = static_obj
@ -186,7 +290,8 @@ def createObjBuilders(env):
prefix = '$SHOBJPREFIX',
suffix = '$SHOBJSUFFIX',
src_builder = ['CFile', 'CXXFile'],
source_scanner = SCons.Defaults.ObjSourceScan, single_source=1)
source_scanner = SourceFileScanner,
single_source = 1)
env['BUILDERS']['SharedObject'] = shared_obj
return (static_obj, shared_obj)
@ -246,10 +351,10 @@ def tool_list(platform, env):
if str(platform) == 'win32':
"prefer Microsoft tools on Windows"
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
c_compilers = ['msvc', 'mingw', 'gcc', 'icl', 'icc', 'cc', 'bcc32' ]
cxx_compilers = ['msvc', 'icc', 'g++', 'c++', 'bcc32' ]
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ]
assemblers = ['masm', 'nasm', 'gas', '386asm' ]
fortran_compilers = ['g77', 'ifl', 'cvf', 'fortran']
fortran_compilers = ['g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
ars = ['mslib', 'ar', 'tlib']
elif str(platform) == 'os2':
"prefer IBM tools on OS/2"
@ -265,7 +370,7 @@ def tool_list(platform, env):
c_compilers = ['sgicc', 'gcc', 'cc']
cxx_compilers = ['sgic++', 'g++', 'c++']
assemblers = ['as', 'gas']
fortran_compilers = ['f77', 'g77', 'fortran']
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
ars = ['sgiar']
elif str(platform) == 'sunos':
"prefer Forte tools on SunOS"
@ -273,7 +378,7 @@ def tool_list(platform, env):
c_compilers = ['suncc', 'gcc', 'cc']
cxx_compilers = ['sunc++', 'g++', 'c++']
assemblers = ['as', 'gas']
fortran_compilers = ['f77', 'g77', 'fortran']
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
ars = ['sunar']
elif str(platform) == 'hpux':
"prefer aCC tools on HP-UX"
@ -281,7 +386,7 @@ def tool_list(platform, env):
c_compilers = ['hpcc', 'gcc', 'cc']
cxx_compilers = ['hpc++', 'g++', 'c++']
assemblers = ['as', 'gas']
fortran_compilers = ['f77', 'g77', 'fortran']
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
ars = ['ar']
elif str(platform) == 'aix':
"prefer AIX Visual Age tools on AIX"
@ -289,15 +394,23 @@ def tool_list(platform, env):
c_compilers = ['aixcc', 'gcc', 'cc']
cxx_compilers = ['aixc++', 'g++', 'c++']
assemblers = ['as', 'gas']
fortran_compilers = ['aixf77', 'g77', 'fortran']
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
ars = ['ar']
elif str(platform) == 'darwin':
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
linkers = ['applelink', 'gnulink']
c_compilers = ['gcc', 'cc']
cxx_compilers = ['g++', 'c++']
assemblers = ['as']
fortran_compilers = ['f95', 'f90', 'g77']
ars = ['ar']
else:
"prefer GNU tools on all other platforms"
linkers = ['gnulink', 'mslink', 'ilink']
c_compilers = ['gcc', 'msvc', 'icc', 'cc']
cxx_compilers = ['g++', 'msvc', 'icc', 'c++']
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++']
assemblers = ['gas', 'nasm', 'masm']
fortran_compilers = ['g77', 'ifort', 'ifl', 'fortran']
fortran_compilers = ['f95', 'f90', 'g77', 'ifort', 'ifl', 'fortran']
ars = ['ar', 'mslib']
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
@ -314,7 +427,7 @@ def tool_list(platform, env):
ar = None
else:
# Don't use g++ if the C compiler has built-in C++ support:
if c_compiler in ('msvc', 'icc'):
if c_compiler in ('msvc', 'intelc', 'icc'):
cxx_compiler = None
else:
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
@ -327,12 +440,15 @@ def tool_list(platform, env):
'dmd',
'dvipdf', 'dvips', 'gs',
'jar', 'javac', 'javah',
'latex', 'lex', 'm4', 'midl', 'msvs',
'latex', 'lex',
'm4', 'midl', 'msvs',
'pdflatex', 'pdftex', 'Perforce',
'RCS', 'rmic', 'SCCS',
'RCS', 'rmic', 'rpcgen',
'SCCS',
# 'Subversion',
'swig',
'tar', 'tex', 'yacc', 'zip'],
'tar', 'tex',
'yacc', 'zip'],
env)
tools = ([linker, c_compiler, cxx_compiler,

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,12 +31,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixc++.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixc++.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path
import SCons.Platform.aix
import SCons.Script.SConscript
cplusplus = __import__('c++', globals(), locals(), [])
@ -48,7 +47,7 @@ def get_xlc(env):
return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages)
def smart_cxxflags(source, target, env, for_signature):
build_dir = SCons.Script.SConscript.GetBuildPath()
build_dir = env.GetBuildPath()
if build_dir:
return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
return ''

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixcc.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixcc.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixf77.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixf77.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixlink.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixlink.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path

View file

@ -1,6 +1,6 @@
"""SCons.Tool.swig
"""SCons.Tool.applelink
Tool-specific initialization for swig.
Tool-specific initialization for the Apple gnu-like linker.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,33 +31,34 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/swig.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/applelink.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Tool
import SCons.Util
def swigSuffixEmitter(env, source):
if '-c++' in SCons.Util.CLVar(env.subst("$SWIGFLAGS")):
return '$SWIGCXXFILESUFFIX'
else:
return '$SWIGCFILESUFFIX'
import gnulink
def generate(env):
"""Add Builders and construction variables for swig to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
"""Add Builders and construction variables for applelink to an
Environment."""
gnulink.generate(env)
c_file.suffix['.i'] = swigSuffixEmitter
cxx_file.suffix['.i'] = swigSuffixEmitter
env['FRAMEWORKPATHPREFIX'] = '-F'
env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__)}'
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS'
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS'
# override the default for loadable modules, which are different
# on OS X than dynamic shared libs. echoing what XCode does for
# pre/suffixes:
env['LDMODULEPREFIX'] = ''
env['LDMODULESUFFIX'] = ''
env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
c_file.add_action('.i', '$SWIGCOM')
cxx_file.add_action('.i', '$SWIGCOM')
env['SWIG'] = 'swig'
env['SWIGFLAGS'] = SCons.Util.CLVar('')
env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX'
env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX'
env['SWIGCOM'] = '$SWIG $SWIGFLAGS -o $TARGET $SOURCES'
def exists(env):
return env.Detect(['swig'])
import sys
return sys.platform == 'darwin'

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,28 +31,27 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ar.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ar.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Tool
import SCons.Util
def generate(env):
"""Add Builders and construction variables for ar to an Environment."""
SCons.Tool.createStaticLibBuilder(env)
arcom = '$AR $ARFLAGS $TARGET $SOURCES'
ranlib = 'ranlib'
if env.Detect(ranlib):
arcom = arcom + '\n$RANLIB $RANLIBFLAGS $TARGET'
env['AR'] = 'ar'
env['ARFLAGS'] = SCons.Util.CLVar('r')
env['RANLIB'] = ranlib
env['RANLIBFLAGS'] = SCons.Util.CLVar('')
env['ARCOM'] = arcom
env['ARFLAGS'] = SCons.Util.CLVar('rc')
env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES'
env['LIBPREFIX'] = 'lib'
env['LIBSUFFIX'] = '.a'
if env.Detect('ranlib'):
env['RANLIB'] = 'ranlib'
env['RANLIBFLAGS'] = SCons.Util.CLVar('')
env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET'
def exists(env):
return env.Detect('ar')

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/as.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/as.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Tool
@ -52,16 +52,21 @@ def generate(env):
for suffix in ASSuffixes:
static_obj.add_action(suffix, SCons.Defaults.ASAction)
shared_obj.add_action(suffix, SCons.Defaults.ASAction)
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
for suffix in ASPPSuffixes:
static_obj.add_action(suffix, SCons.Defaults.ASPPAction)
shared_obj.add_action(suffix, SCons.Defaults.ASPPAction)
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
env['AS'] = env.Detect(assemblers) or 'as'
env['ASFLAGS'] = SCons.Util.CLVar('')
env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES'
env['ASPPCOM'] = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['ASPPFLAGS'] = '$ASFLAGS'
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
def exists(env):
return env.Detect(assemblers)

View file

@ -5,7 +5,7 @@ XXX
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,7 +27,7 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/bcc32.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/bcc32.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import os.path
@ -63,10 +63,12 @@ def generate(env):
env['CC'] = 'bcc32'
env['CCFLAGS'] = SCons.Util.CLVar('')
env['CCCOM'] = '$CC -q $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['CFLAGS'] = SCons.Util.CLVar('')
env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
env['SHCCCOM'] = '$SHCC -WD $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CPPDEFSUFFIX'] = ''
env['INCPREFIX'] = '-I'

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/c++.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/c++.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path
@ -40,7 +40,7 @@ import SCons.Util
compilers = ['CC', 'c++']
CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++']
CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm']
if SCons.Util.case_sensitive_suffixes('.c', '.C'):
CXXSuffixes.append('.C')
@ -60,6 +60,8 @@ def generate(env):
Add Builders and construction variables for Visual Age C++ compilers
to an Environment.
"""
import SCons.Tool
import SCons.Tool.cc
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
for suffix in CXXSuffixes:
@ -68,12 +70,14 @@ def generate(env):
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
SCons.Tool.cc.add_common_cc_variables(env)
env['CXX'] = 'c++'
env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $_CCCOMCOM $SOURCES'
env['SHCXX'] = '$CXX'
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $_CCCOMCOM $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CPPDEFSUFFIX'] = ''

View file

@ -8,7 +8,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -30,16 +30,38 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cc.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cc.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Tool
import SCons.Defaults
import SCons.Util
CSuffixes = ['.c']
CSuffixes = ['.c', '.m']
if not SCons.Util.case_sensitive_suffixes('.c', '.C'):
CSuffixes.append('.C')
def add_common_cc_variables(env):
"""
Add underlying common "C compiler" variables that
are used by multiple tools (specifically, c++).
"""
if not env.has_key('_CCCOMCOM'):
env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
# It's a hack to test for darwin here, but the alternative
# of creating an applecc.py to contain this seems overkill.
# Maybe someday the Apple platform will require more setup and
# this logic will be moved.
env['FRAMEWORKS'] = SCons.Util.CLVar('')
env['FRAMEWORKPATH'] = SCons.Util.CLVar('')
if env['PLATFORM'] == 'darwin':
env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH'
if not env.has_key('CCFLAGS'):
env['CCFLAGS'] = SCons.Util.CLVar('')
if not env.has_key('SHCCFLAGS'):
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
def generate(env):
"""
Add Builders and construction variables for C compilers to an Environment.
@ -52,12 +74,14 @@ def generate(env):
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
add_common_cc_variables(env)
env['CC'] = 'cc'
env['CCFLAGS'] = SCons.Util.CLVar('')
env['CCCOM'] = '$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['CFLAGS'] = SCons.Util.CLVar('')
env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['SHCC'] = '$CC'
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
env['CPPDEFPREFIX'] = '-D'
env['CPPDEFSUFFIX'] = ''

View file

@ -5,7 +5,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -27,9 +27,8 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cvf.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cvf.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Util
import fortran
compilers = ['f90']
@ -40,10 +39,10 @@ def generate(env):
fortran.generate(env)
env['FORTRAN'] = 'f90'
env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.win32} /object:${TARGET.win32}'
env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.win32} /object:${TARGET.win32}'
env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.win32} /object:${TARGET.win32}'
env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.win32} /object:${TARGET.win32}'
env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
env['OBJSUFFIX'] = '.obj'
env['FORTRANMODDIR'] = '${TARGET.dir}'
env['FORTRANMODDIRPREFIX'] = '/module:'

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/default.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/default.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Tool

View file

@ -7,7 +7,7 @@ Coded by Andy Friesen (andy@ikagames.com)
15 November 2003
There are a number of problems with this script at this point in time.
The one that irritates me the most is the win32 linker setup. The D
The one that irritates me the most is the Windows linker setup. The D
linker doesn't have a way to add lib paths on the commandline, as far
as I can see. You have to specify paths relative to the SConscript or
use absolute paths. To hack around it, add '#/blah'. This will link
@ -31,7 +31,7 @@ Lib tool variables:
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -53,15 +53,16 @@ Lib tool variables:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dmd.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dmd.py 0.97.D001 2007/05/17 11:35:19 knight"
import os
import string
import SCons.Tool
import SCons.Scanner.D
import SCons.Action
import SCons.Builder
import SCons.Defaults
import SCons.Scanner.D
import SCons.Tool
# Adapted from c++.py
def isD(source):
@ -85,14 +86,16 @@ def generate(env):
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
static_obj.add_action('.d', '$DCOM')
shared_obj.add_action('.d', '$DCOM')
DAction = SCons.Action.Action('$DCOM', '$DCOMSTR')
static_obj.add_action('.d', DAction)
shared_obj.add_action('.d', DAction)
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
env['DC'] = 'dmd'
env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES'
env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs)} $)'
env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)'
env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)'
env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)'
@ -129,7 +132,7 @@ def generate(env):
env['DLIB'] = 'lib'
env['DLIBCOM'] = '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLINKLIBFLAGS'
env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs)} $)'
env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
env['DLINKFLAGS'] = []
env['DLIBLINKPREFIX'] = ''
@ -152,6 +155,10 @@ def generate(env):
def _smartLink(source, target, env, for_signature,
defaultLinker=linkcom):
if isD(source):
# XXX I'm not sure how to add a $DLINKCOMSTR variable
# so that it works with this _smartLink() logic,
# and I don't have a D compiler/linker to try it out,
# so we'll leave it alone for now.
return '$DLINKCOM'
else:
return defaultLinker
@ -164,6 +171,10 @@ def generate(env):
def _smartLib(source, target, env, for_signature,
defaultLib=arcom):
if isD(source):
# XXX I'm not sure how to add a $DLIBCOMSTR variable
# so that it works with this _smartLib() logic, and
# I don't have a D compiler/archiver to try it out,
# so we'll leave it alone for now.
return '$DLIBCOM'
else:
return defaultLib
@ -190,6 +201,8 @@ def generate(env):
env.Append(LIBS = ['phobos'])
if 'pthread' not in libs:
env.Append(LIBS = ['pthread'])
if 'm' not in libs:
env.Append(LIBS = ['m'])
return defaultLinker
env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink

View file

@ -0,0 +1,58 @@
"""SCons.Tool.dvi
Common DVI Builder definition for various other Tool modules that use it.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvi.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Builder
import SCons.Tool
DVIBuilder = None
def generate(env):
try:
env['BUILDERS']['DVI']
except KeyError:
global DVIBuilder
if DVIBuilder is None:
# The suffix is hard-coded to '.dvi', not configurable via a
# construction variable like $DVISUFFIX, because the output
# file name is hard-coded within TeX.
DVIBuilder = SCons.Builder.Builder(action = {},
source_scanner = SCons.Tool.LaTeXScanner,
suffix = '.dvi',
emitter = {},
source_ext_match = None)
env['BUILDERS']['DVI'] = DVIBuilder
def exists(env):
# This only puts a skeleton Builder in place, so if someone
# references this Tool directly, it's always "available."
return 1

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,23 +31,42 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvipdf.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvipdf.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Defaults
import SCons.Tool.pdf
import SCons.Util
PDFAction = None
def PDFEmitter(target, source, env):
"""Strips any .aux or .log files from the input source list.
These are created by the TeX Builder that in all likelihood was
used to generate the .dvi file we're using as input, and we only
care about the .dvi file.
"""
def strip_suffixes(n):
return not SCons.Util.splitext(str(n))[1] in ['.aux', '.log']
source = filter(strip_suffixes, source)
return (target, source)
def generate(env):
"""Add Builders and construction variables for dvipdf to an Environment."""
try:
global PDFAction
if PDFAction is None:
PDFAction = SCons.Action.Action('$DVIPDFCOM', '$DVIPDFCOMSTR')
import pdf
pdf.generate(env)
bld = env['BUILDERS']['PDF']
except KeyError:
bld = SCons.Defaults.PDF()
env['BUILDERS']['PDF'] = bld
bld.add_action('.dvi', '$PDFCOM')
bld.add_action('.dvi', PDFAction)
bld.add_emitter('.dvi', PDFEmitter)
env['DVIPDF'] = 'dvipdf'
env['DVIPDFFLAGS'] = SCons.Util.CLVar('')
env['DVIPDFCOM'] = '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET'
env['DVIPDFCOM'] = 'cd ${TARGET.dir} && $DVIPDF $DVIPDFFLAGS ${SOURCE.file} ${TARGET.file}'
# Deprecated synonym.
env['PDFCOM'] = ['$DVIPDFCOM']

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,25 +31,38 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvips.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvips.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Action
import SCons.Defaults
import SCons.Builder
import SCons.Util
PostScript = SCons.Builder.Builder(action = '$PSCOM',
PSAction = None
PSBuilder = None
def generate(env):
"""Add Builders and construction variables for dvips to an Environment."""
global PSAction
if PSAction is None:
PSAction = SCons.Action.Action('$PSCOM', '$PSCOMSTR')
global PSBuilder
if PSBuilder is None:
PSBuilder = SCons.Builder.Builder(action = PSAction,
prefix = '$PSPREFIX',
suffix = '$PSSUFFIX',
src_suffix = '.dvi',
src_builder = 'DVI')
def generate(env):
"""Add Builders and construction variables for dvips to an Environment."""
env['BUILDERS']['PostScript'] = PostScript
env['BUILDERS']['PostScript'] = PSBuilder
env['DVIPS'] = 'dvips'
env['DVIPSFLAGS'] = SCons.Util.CLVar('')
env['PSCOM'] = '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES'
# I'm not quite sure I got the directories and filenames right for build_dir
# We need to be in the correct directory for the sake of latex \includegraphics eps included files.
env['PSCOM'] = 'cd ${TARGET.dir} && $DVIPS $DVIPSFLAGS -o ${TARGET.file} ${SOURCE.file}'
env['PSPREFIX'] = ''
env['PSSUFFIX'] = '.ps'
def exists(env):
return env.Detect('dvips')

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f77.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f77.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Scanner.Fortran
@ -53,7 +53,8 @@ else:
F77Scan = SCons.Scanner.Fortran.FortranScan("F77PATH")
for suffix in F77Suffixes + F77PPSuffixes:
SCons.Defaults.ObjSourceScan.add_scanner(suffix, F77Scan)
SCons.Tool.SourceFileScanner.add_scanner(suffix, F77Scan)
del suffix
#
fVLG = fortran.VariableListGenerator
@ -61,19 +62,23 @@ fVLG = fortran.VariableListGenerator
F77Generator = fVLG('F77', 'FORTRAN', '_FORTRAND')
F77FlagsGenerator = fVLG('F77FLAGS', 'FORTRANFLAGS')
F77CommandGenerator = fVLG('F77COM', 'FORTRANCOM', '_F77COMD')
F77CommandStrGenerator = fVLG('F77COMSTR', 'FORTRANCOMSTR', '_F77COMSTRD')
F77PPCommandGenerator = fVLG('F77PPCOM', 'FORTRANPPCOM', '_F77PPCOMD')
F77PPCommandStrGenerator = fVLG('F77PPCOMSTR', 'FORTRANPPCOMSTR', '_F77PPCOMSTRD')
ShF77Generator = fVLG('SHF77', 'SHFORTRAN', 'F77', 'FORTRAN', '_FORTRAND')
ShF77FlagsGenerator = fVLG('SHF77FLAGS', 'SHFORTRANFLAGS')
ShF77CommandGenerator = fVLG('SHF77COM', 'SHFORTRANCOM', '_SHF77COMD')
ShF77CommandStrGenerator = fVLG('SHF77COMSTR', 'SHFORTRANCOMSTR', '_SHF77COMSTRD')
ShF77PPCommandGenerator = fVLG('SHF77PPCOM', 'SHFORTRANPPCOM', '_SHF77PPCOMD')
ShF77PPCommandStrGenerator = fVLG('SHF77PPCOMSTR', 'SHFORTRANPPCOMSTR', '_SHF77PPCOMSTRD')
del fVLG
#
F77Action = SCons.Action.Action('$_F77COMG ')
F77PPAction = SCons.Action.Action('$_F77PPCOMG ')
ShF77Action = SCons.Action.Action('$_SHF77COMG ')
ShF77PPAction = SCons.Action.Action('$_SHF77PPCOMG ')
F77Action = SCons.Action.Action('$_F77COMG ', '$_F77COMSTRG')
F77PPAction = SCons.Action.Action('$_F77PPCOMG ', '$_F77PPCOMSTRG')
ShF77Action = SCons.Action.Action('$_SHF77COMG ', '$_SHF77COMSTRG')
ShF77PPAction = SCons.Action.Action('$_SHF77PPCOMG ', '$_SHF77PPCOMSTRG')
def add_to_env(env):
"""Add Builders and construction variables for f77 to an Environment."""
@ -97,18 +102,22 @@ def add_to_env(env):
env['_F77FLAGSG'] = F77FlagsGenerator
env['_F77COMG'] = F77CommandGenerator
env['_F77PPCOMG'] = F77PPCommandGenerator
env['_F77COMSTRG'] = F77CommandStrGenerator
env['_F77PPCOMSTRG'] = F77PPCommandStrGenerator
env['_SHF77G'] = ShF77Generator
env['_SHF77FLAGSG'] = ShF77FlagsGenerator
env['_SHF77COMG'] = ShF77CommandGenerator
env['_SHF77PPCOMG'] = ShF77PPCommandGenerator
env['_SHF77COMSTRG'] = ShF77CommandStrGenerator
env['_SHF77PPCOMSTRG'] = ShF77PPCommandStrGenerator
env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs)} $)'
env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_F77COMD'] = '$_F77G $_F77FLAGSG $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_F77PPCOMD'] = '$_F77G $_F77FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_SHF77COMD'] = '$_SHF77G $_SHF77FLAGSG $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_SHF77PPCOMD'] = '$_SHF77G $_SHF77FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_F77COMD'] = '$_F77G -o $TARGET -c $_F77FLAGSG $_F77INCFLAGS $SOURCES'
env['_F77PPCOMD'] = '$_F77G -o $TARGET -c $_F77FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS $SOURCES'
env['_SHF77COMD'] = '$_SHF77G -o $TARGET -c $_SHF77FLAGSG $_F77INCFLAGS $SOURCES'
env['_SHF77PPCOMD'] = '$_SHF77G -o $TARGET -c $_SHF77FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS $SOURCES'
def generate(env):
fortran.add_to_env(env)

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f90.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f90.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Scanner.Fortran
@ -53,7 +53,8 @@ else:
F90Scan = SCons.Scanner.Fortran.FortranScan("F90PATH")
for suffix in F90Suffixes + F90PPSuffixes:
SCons.Defaults.ObjSourceScan.add_scanner(suffix, F90Scan)
SCons.Tool.SourceFileScanner.add_scanner(suffix, F90Scan)
del suffix
#
fVLG = fortran.VariableListGenerator
@ -61,19 +62,23 @@ fVLG = fortran.VariableListGenerator
F90Generator = fVLG('F90', 'FORTRAN', '_FORTRAND')
F90FlagsGenerator = fVLG('F90FLAGS', 'FORTRANFLAGS')
F90CommandGenerator = fVLG('F90COM', 'FORTRANCOM', '_F90COMD')
F90CommandStrGenerator = fVLG('F90COMSTR', 'FORTRANCOMSTR', '_F90COMSTRD')
F90PPCommandGenerator = fVLG('F90PPCOM', 'FORTRANPPCOM', '_F90PPCOMD')
F90PPCommandStrGenerator = fVLG('F90PPCOMSTR', 'FORTRANPPCOMSTR', '_F90PPCOMSTRD')
ShF90Generator = fVLG('SHF90', 'SHFORTRAN', 'F90', 'FORTRAN', '_FORTRAND')
ShF90FlagsGenerator = fVLG('SHF90FLAGS', 'SHFORTRANFLAGS')
ShF90CommandGenerator = fVLG('SHF90COM', 'SHFORTRANCOM', '_SHF90COMD')
ShF90CommandStrGenerator = fVLG('SHF90COMSTR', 'SHFORTRANCOMSTR', '_SHF90COMSTRD')
ShF90PPCommandGenerator = fVLG('SHF90PPCOM', 'SHFORTRANPPCOM', '_SHF90PPCOMD')
ShF90PPCommandStrGenerator = fVLG('SHF90PPCOMSTR', 'SHFORTRANPPCOMSTR', '_SHF90PPCOMSTRD')
del fVLG
#
F90Action = SCons.Action.Action('$_F90COMG ')
F90PPAction = SCons.Action.Action('$_F90PPCOMG ')
ShF90Action = SCons.Action.Action('$_SHF90COMG ')
ShF90PPAction = SCons.Action.Action('$_SHF90PPCOMG ')
F90Action = SCons.Action.Action('$_F90COMG ', '$_F90COMSTRG')
F90PPAction = SCons.Action.Action('$_F90PPCOMG ', '$_F90PPCOMSTRG')
ShF90Action = SCons.Action.Action('$_SHF90COMG ', '$_SHF90COMSTRG')
ShF90PPAction = SCons.Action.Action('$_SHF90PPCOMG ', '$_SHF90PPCOMSTRG')
def add_to_env(env):
"""Add Builders and construction variables for f90 to an Environment."""
@ -96,21 +101,29 @@ def add_to_env(env):
env['_F90G'] = F90Generator
env['_F90FLAGSG'] = F90FlagsGenerator
env['_F90COMG'] = F90CommandGenerator
env['_F90COMSTRG'] = F90CommandStrGenerator
env['_F90PPCOMG'] = F90PPCommandGenerator
env['_F90PPCOMSTRG'] = F90PPCommandStrGenerator
env['_SHF90G'] = ShF90Generator
env['_SHF90FLAGSG'] = ShF90FlagsGenerator
env['_SHF90COMG'] = ShF90CommandGenerator
env['_SHF90COMSTRG'] = ShF90CommandStrGenerator
env['_SHF90PPCOMG'] = ShF90PPCommandGenerator
env['_SHF90PPCOMSTRG'] = ShF90PPCommandStrGenerator
env['_F90INCFLAGS'] = '$( ${_concat(INCPREFIX, F90PATH, INCSUFFIX, __env__, RDirs)} $)'
env['_F90COMD'] = '$_F90G $_F90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F90PPCOMD'] = '$_F90G $_F90FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF90COMD'] = '$_SHF90G $_SHF90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF90PPCOMD'] = '$_SHF90G $_SHF90FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F90INCFLAGS'] = '$( ${_concat(INCPREFIX, F90PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_F90COMD'] = '$_F90G -o $TARGET -c $_F90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_F90PPCOMD'] = '$_F90G -o $TARGET -c $_F90FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHF90COMD'] = '$_SHF90G -o $TARGET -c $_SHF90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHF90PPCOMD'] = '$_SHF90G -o $TARGET -c $_SHF90FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG $SOURCES'
def generate(env):
fortran.add_to_env(env)
import f77
f77.add_to_env(env)
add_to_env(env)
env['_FORTRAND'] = env.Detect(compilers) or 'f90'

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f95.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f95.py 0.97.D001 2007/05/17 11:35:19 knight"
import SCons.Defaults
import SCons.Tool
@ -52,7 +52,8 @@ else:
F95Scan = SCons.Scanner.Fortran.FortranScan("F95PATH")
for suffix in F95Suffixes + F95PPSuffixes:
SCons.Defaults.ObjSourceScan.add_scanner(suffix, F95Scan)
SCons.Tool.SourceFileScanner.add_scanner(suffix, F95Scan)
del suffix
#
fVLG = fortran.VariableListGenerator
@ -60,19 +61,23 @@ fVLG = fortran.VariableListGenerator
F95Generator = fVLG('F95', 'FORTRAN', '_FORTRAND')
F95FlagsGenerator = fVLG('F95FLAGS', 'FORTRANFLAGS')
F95CommandGenerator = fVLG('F95COM', 'FORTRANCOM', '_F95COMD')
F95CommandStrGenerator = fVLG('F95COMSTR', 'FORTRANCOMSTR', '_F95COMSTRD')
F95PPCommandGenerator = fVLG('F95PPCOM', 'FORTRANPPCOM', '_F95PPCOMD')
F95PPCommandStrGenerator = fVLG('F95PPCOMSTR', 'FORTRANPPCOMSTR', '_F95PPCOMSTRD')
ShF95Generator = fVLG('SHF95', 'SHFORTRAN', 'F95', 'FORTRAN', '_FORTRAND')
ShF95FlagsGenerator = fVLG('SHF95FLAGS', 'SHFORTRANFLAGS')
ShF95CommandGenerator = fVLG('SHF95COM', 'SHFORTRANCOM', '_SHF95COMD')
ShF95CommandStrGenerator = fVLG('SHF95COMSTR', 'SHFORTRANCOMSTR', '_SHF95COMSTRD')
ShF95PPCommandGenerator = fVLG('SHF95PPCOM', 'SHFORTRANPPCOM', '_SHF95PPCOMD')
ShF95PPCommandStrGenerator = fVLG('SHF95PPCOMSTR', 'SHFORTRANPPCOMSTR', '_SHF95PPCOMSTRD')
del fVLG
#
F95Action = SCons.Action.Action('$_F95COMG ')
F95PPAction = SCons.Action.Action('$_F95PPCOMG ')
ShF95Action = SCons.Action.Action('$_SHF95COMG ')
ShF95PPAction = SCons.Action.Action('$_SHF95PPCOMG ')
F95Action = SCons.Action.Action('$_F95COMG ', '$_F95COMSTRG')
F95PPAction = SCons.Action.Action('$_F95PPCOMG ', '$_F95PPCOMSTRG')
ShF95Action = SCons.Action.Action('$_SHF95COMG ', '$_SHF95COMSTRG')
ShF95PPAction = SCons.Action.Action('$_SHF95PPCOMG ', '$_SHF95PPCOMSTRG')
def add_to_env(env):
"""Add Builders and construction variables for f95 to an Environment."""
@ -95,22 +100,33 @@ def add_to_env(env):
env['_F95G'] = F95Generator
env['_F95FLAGSG'] = F95FlagsGenerator
env['_F95COMG'] = F95CommandGenerator
env['_F95COMSTRG'] = F95CommandStrGenerator
env['_F95PPCOMG'] = F95PPCommandGenerator
env['_F95PPCOMSTRG'] = F95PPCommandStrGenerator
env['_SHF95G'] = ShF95Generator
env['_SHF95FLAGSG'] = ShF95FlagsGenerator
env['_SHF95COMG'] = ShF95CommandGenerator
env['_SHF95COMSTRG'] = ShF95CommandStrGenerator
env['_SHF95PPCOMG'] = ShF95PPCommandGenerator
env['_SHF95PPCOMSTRG'] = ShF95PPCommandStrGenerator
env['_F95INCFLAGS'] = '$( ${_concat(INCPREFIX, F95PATH, INCSUFFIX, __env__, RDirs)} $)'
env['_F95INCFLAGS'] = '$( ${_concat(INCPREFIX, F95PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_F95COMD'] = '$_F95G $_F95FLAGSG $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F95PPCOMD'] = '$_F95G $_F95FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF95COMD'] = '$_SHF95G $_SHF95FLAGSG $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF95PPCOMD'] = '$_SHF95G $_SHF95FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F95COMD'] = '$_F95G -o $TARGET -c $_F95FLAGSG $_F95INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_F95PPCOMD'] = '$_F95G -o $TARGET -c $_F95FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHF95COMD'] = '$_SHF95G -o $TARGET -c $_SHF95FLAGSG $_F95INCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHF95PPCOMD'] = '$_SHF95G -o $TARGET -c $_SHF95FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG $SOURCES'
def generate(env):
fortran.add_to_env(env)
import f77
f77.add_to_env(env)
import f90
f90.add_to_env(env)
add_to_env(env)
env['_FORTRAND'] = env.Detect(compilers) or 'f95'

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/fortran.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/fortran.py 0.97.D001 2007/05/17 11:35:19 knight"
import re
import string
@ -62,7 +62,8 @@ else:
FortranScan = SCons.Scanner.Fortran.FortranScan("FORTRANPATH")
for suffix in FortranSuffixes + FortranPPSuffixes:
SCons.Defaults.ObjSourceScan.add_scanner(suffix, FortranScan)
SCons.Tool.SourceFileScanner.add_scanner(suffix, FortranScan)
del suffix
#
def _fortranEmitter(target, source, env):
@ -78,9 +79,10 @@ def _fortranEmitter(target, source, env):
modules = SCons.Util.unique(modules)
# Convert module name to a .mod filename
suffix = env.subst('$FORTRANMODSUFFIX')
moddir = env.subst('$FORTRANMODDIR')
modules = map(lambda x, s=suffix: string.lower(x) + s, modules)
for m in modules:
target.append(env.fs.File(m))
target.append(env.fs.File(m, moddir))
return (target, source)
def FortranEmitter(target, source, env):
@ -94,7 +96,7 @@ def ShFortranEmitter(target, source, env):
class VariableListGenerator:
def __init__(self, *variablelist):
self.variablelist = variablelist
def __call__(self, env, target, source, for_signature):
def __call__(self, env, target, source, for_signature=0):
for v in self.variablelist:
try: return env[v]
except KeyError: pass
@ -104,17 +106,21 @@ class VariableListGenerator:
FortranGenerator = VariableListGenerator('FORTRAN', 'F77', '_FORTRAND')
FortranFlagsGenerator = VariableListGenerator('FORTRANFLAGS', 'F77FLAGS')
FortranCommandGenerator = VariableListGenerator('FORTRANCOM', 'F77COM', '_FORTRANCOMD')
FortranCommandStrGenerator = VariableListGenerator('FORTRANCOMSTR', 'F77COMSTR', '_FORTRANCOMSTRD')
FortranPPCommandGenerator = VariableListGenerator('FORTRANPPCOM', 'F77PPCOM', '_FORTRANPPCOMD')
FortranPPCommandStrGenerator = VariableListGenerator('FORTRANPPCOMSTR', 'F77PPCOMSTR', '_FORTRANPPCOMSTRD')
ShFortranGenerator = VariableListGenerator('SHFORTRAN', 'SHF77', 'FORTRAN', 'F77', '_FORTRAND')
ShFortranFlagsGenerator = VariableListGenerator('SHFORTRANFLAGS', 'SHF77FLAGS')
ShFortranCommandGenerator = VariableListGenerator('SHFORTRANCOM', 'SHF77COM', '_SHFORTRANCOMD')
ShFortranCommandStrGenerator = VariableListGenerator('SHFORTRANCOMSTR', 'SHF77COMSTR', '_SHFORTRANCOMSTRD')
ShFortranPPCommandGenerator = VariableListGenerator('SHFORTRANPPCOM', 'SHF77PPCOM', '_SHFORTRANPPCOMD')
ShFortranPPCommandStrGenerator = VariableListGenerator('SHFORTRANPPCOMSTR', 'SHF77PPCOMSTR', '_SHFORTRANPPCOMSTRD')
#
FortranAction = SCons.Action.Action('$_FORTRANCOMG ')
FortranPPAction = SCons.Action.Action('$_FORTRANPPCOMG ')
ShFortranAction = SCons.Action.Action('$_SHFORTRANCOMG ')
ShFortranPPAction = SCons.Action.Action('$_SHFORTRANPPCOMG ')
FortranAction = SCons.Action.Action('$_FORTRANCOMG ', '$_FORTRANCOMSTRG')
FortranPPAction = SCons.Action.Action('$_FORTRANPPCOMG ', '$_FORTRANPPCOMSTRG')
ShFortranAction = SCons.Action.Action('$_SHFORTRANCOMG ', '$_SHFORTRANCOMSTRG')
ShFortranPPAction = SCons.Action.Action('$_SHFORTRANPPCOMG ', '$_SHFORTRANPPCOMSTRG')
def add_to_env(env):
"""Add Builders and construction variables for Fortran to an Environment."""
@ -122,14 +128,18 @@ def add_to_env(env):
env['_FORTRANG'] = FortranGenerator
env['_FORTRANFLAGSG'] = FortranFlagsGenerator
env['_FORTRANCOMG'] = FortranCommandGenerator
env['_FORTRANCOMSTRG'] = FortranCommandStrGenerator
env['_FORTRANPPCOMG'] = FortranPPCommandGenerator
env['_FORTRANPPCOMSTRG'] = FortranPPCommandStrGenerator
env['_SHFORTRANG'] = ShFortranGenerator
env['_SHFORTRANFLAGSG'] = ShFortranFlagsGenerator
env['_SHFORTRANCOMG'] = ShFortranCommandGenerator
env['_SHFORTRANCOMSTRG'] = ShFortranCommandStrGenerator
env['_SHFORTRANPPCOMG'] = ShFortranPPCommandGenerator
env['_SHFORTRANPPCOMSTRG'] = ShFortranPPCommandStrGenerator
env['_FORTRANINCFLAGS'] = '$( ${_concat(INCPREFIX, FORTRANPATH, INCSUFFIX, __env__, RDirs)} $)'
env['_FORTRANINCFLAGS'] = '$( ${_concat(INCPREFIX, FORTRANPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX
env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX
@ -137,7 +147,7 @@ def add_to_env(env):
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__)} $)'
env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs)} $)'
env.AppendUnique(FORTRANSUFFIXES = FortranSuffixes + FortranPPSuffixes)
@ -155,10 +165,10 @@ def add_to_env(env):
static_obj.add_emitter(suffix, FortranEmitter)
shared_obj.add_emitter(suffix, ShFortranEmitter)
env['_FORTRANCOMD'] = '$_FORTRANG $_FORTRANFLAGSG $_FORTRANINCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_FORTRANPPCOMD'] = '$_FORTRANG $_FORTRANFLAGSG $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHFORTRANCOMD'] = '$_SHFORTRANG $_SHFORTRANFLAGSG $_FORTRANINCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHFORTRANPPCOMD'] = '$_SHFORTRANG $_SHFORTRANFLAGSG $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_FORTRANCOMD'] = '$_FORTRANG -o $TARGET -c $_FORTRANFLAGSG $_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_FORTRANPPCOMD'] = '$_FORTRANG -o $TARGET -c $_FORTRANFLAGSG $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHFORTRANCOMD'] = '$_SHFORTRANG -o $TARGET -c $_SHFORTRANFLAGSG $_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES'
env['_SHFORTRANPPCOMD'] = '$_SHFORTRANG -o $TARGET -c $_SHFORTRANFLAGSG $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES'
def generate(env):
import f77

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g++.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g++.py 0.97.D001 2007/05/17 11:35:19 knight"
import os.path
import re

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g77.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g77.py 0.97.D001 2007/05/17 11:35:19 knight"
import f77

View file

@ -9,7 +9,7 @@ selection method.
"""
#
# Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -31,15 +31,15 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gas.py 0.96.1.D001 2004/08/23 09:55:29 knight"
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gas.py 0.97.D001 2007/05/17 11:35:19 knight"
import as
as_module = __import__('as', globals(), locals(), [])
assemblers = ['as', 'gas']
def generate(env):
"""Add Builders and construction variables for as to an Environment."""
as.generate(env)
as_module.generate(env)
env['AS'] = env.Detect(assemblers) or 'as'

Some files were not shown because too many files have changed in this diff Show more