updated scons to 0.97.0d20071212

This commit is contained in:
Artem Pavlenko 2008-02-07 09:59:49 +00:00
parent a3652c6e66
commit 2357582cbb
173 changed files with 9806 additions and 4123 deletions

View file

@ -1,161 +0,0 @@
#! /usr/bin/env python
#
# SCons - a Software Constructor
#
# 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/script/scons.py 0.97.D001 2007/05/17 11:35:19 knight"
__version__ = "0.97"
__build__ = "D001"
__buildsys__ = "roxbury"
__date__ = "2007/05/17 11:35:19"
__developer__ = "knight"
import os
import os.path
import sys
##############################################################################
# BEGIN STANDARD SCons SCRIPT HEADER
#
# This is the cut-and-paste logic so that a self-contained script can
# interoperate correctly with different SCons versions and installation
# locations for the engine. If you modify anything in this section, you
# should also change other scripts that use this same header.
##############################################################################
# Strip the script directory from sys.path() so on case-insensitive
# (WIN32) systems Python doesn't think that the "scons" script is the
# "SCons" package. Replace it with our own library directories
# (version-specific first, in case they installed by hand there,
# followed by generic) so we pick up the right version of the build
# engine modules if they're in either directory.
script_dir = sys.path[0]
if script_dir in sys.path:
sys.path.remove(script_dir)
libs = []
if os.environ.has_key("SCONS_LIB_DIR"):
libs.append(os.environ["SCONS_LIB_DIR"])
local = 'scons-local-' + __version__
if script_dir:
local = os.path.join(script_dir, local)
libs.append(os.path.abspath(local))
scons_version = 'scons-%s' % __version__
prefs = []
if sys.platform == 'win32':
# sys.prefix is (likely) C:\Python*;
# check only C:\Python*.
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))
else:
# On other (POSIX) platforms, things are more complicated due to
# the variety of path names and library locations. Try to be smart
# about it.
if script_dir == 'bin':
# script_dir is `pwd`/bin;
# check `pwd`/lib/scons*.
prefs.append(os.getcwd())
else:
if script_dir == '.' or script_dir == '':
script_dir = os.getcwd()
head, tail = os.path.split(script_dir)
if tail == "bin":
# script_dir is /foo/bin;
# check /foo/lib/scons*.
prefs.append(head)
head, tail = os.path.split(sys.prefix)
if tail == "usr":
# sys.prefix is /foo/usr;
# check /foo/usr/lib/scons* first,
# then /foo/usr/local/lib/scons*.
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, "local"))
elif tail == "local":
h, t = os.path.split(head)
if t == "usr":
# sys.prefix is /foo/usr/local;
# check /foo/usr/local/lib/scons* first,
# then /foo/usr/lib/scons*.
prefs.append(sys.prefix)
prefs.append(head)
else:
# sys.prefix is /foo/local;
# check only /foo/local/lib/scons*.
prefs.append(sys.prefix)
else:
# sys.prefix is /foo (ends in neither /usr or /local);
# check only /foo/lib/scons*.
prefs.append(sys.prefix)
temp = map(lambda x: os.path.join(x, 'lib'), prefs)
temp.extend(map(lambda x: os.path.join(x,
'lib',
'python' + sys.version[:3],
'site-packages'),
prefs))
prefs = temp
# Add the parent directory of the current python's library to the
# preferences. On SuSE-91/AMD64, for example, this is /usr/lib64,
# not /usr/lib.
try:
libpath = os.__file__
except AttributeError:
pass
else:
while libpath:
libpath, tail = os.path.split(libpath)
if tail[:6] == "python":
break
if libpath:
# Python library is in /usr/libfoo/python*;
# check /usr/libfoo/scons*.
prefs.append(libpath)
# Look first for 'scons-__version__' in all of our preference libs,
# then for 'scons'.
libs.extend(map(lambda x: os.path.join(x, scons_version), prefs))
libs.extend(map(lambda x: os.path.join(x, 'scons'), prefs))
sys.path = libs + sys.path
##############################################################################
# END STANDARD SCons SCRIPT HEADER
##############################################################################
import SCons.Script
SCons.Script.main()

View file

@ -1,3 +1,8 @@
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, 2005, 2006, 2007 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 Permission is hereby granted, free of charge, to any person obtaining

View file

@ -1,28 +1,42 @@
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 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 SCons - a software construction tool
Version 0.97 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.
You are likely reading this file in one of the following two situations:
This is a beta release of SCons, a tool for building software (and other 1) You have unpacked an scons-local-{version} package and are
files). SCons is implemented in Python, and its "configuration files" examining the contents.
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.
See the RELEASE.txt file for notes about this specific release, In this case, you are presumably interested in using this
including known problems. See the CHANGES.txt file for a list of package to include a local copy of SCons with some other
changes since the previous release. 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.
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 LATEST VERSION
============== ==============
Before going further, you can check that this package you have is Before going further, you can check for the latest version of the
the latest version by checking the SCons download page at: scons-local package, or any SCons package, at the SCons download page:
http://www.scons.org/download.html http://www.scons.org/download.html
@ -31,149 +45,93 @@ EXECUTION REQUIREMENTS
====================== ======================
Running SCons requires Python version 1.5.2 or later. There should be Running SCons requires Python version 1.5.2 or later. There should be
no other dependencies or requirements to run SCons. (There is, however, no other dependencies or requirements to run SCons.
an additional requirement to *install* SCons from this particular
package; see the next section.)
By default, SCons knows how to search for available programming tools The default SCons configuration assumes use of the Microsoft Visual C++
on various systems--see the SCons man page for details. You may, compiler suite on WIN32 systems, and assumes a C compiler named 'cc',
of course, override the default SCons choices made by appropriate 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
configuration of Environment construction variables. 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
============ ============
Assuming your system satisfies the installation requirements in the Installation of this package should be as simple as unpacking the
previous section, install SCons from this package simply by running the archive (either .tar.gz or .zip) in any directory (top-level or a
provided Python-standard setup script as follows: subdirectory) within the software package with which you want to ship
SCons.
# python setup.py install 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.
By default, the above command will do the following: 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):
-- Install the version-numbered "scons-0.97" and "sconsign-0.97" $ python scons.py
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.
-- Install scripts named "scons" and "sconsign" scripts in the Or (if, for example, you installed this package in a subdirectory named
default system script directory (/usr/bin or C:\Python*\Scripts, "scons"):
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.
On UNIX or Linux systems, you can have the "scons" and "sconsign" $ python scons/scons.py
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.
-- Install "scons-0.97.bat" and "scons.bat" wrapper scripts in the That should be all you have to do. (If it isn't that simple, please let
Python prefix directory on Windows (C:\Python*, for example). us know!)
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.
-- Install the SCons build engine (a Python module) in an CONTENTS OF THIS PACKAGE
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.
-- Install the troff-format man pages in an appropriate directory This scons-local package consists of the following:
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.
Note that, by default, SCons does not install its build engine library scons-LICENSE
in the standard Python library directories. If you want to be able to A copy of the copyright and terms under which SCons is
use the SCons library modules (the build engine) in other Python distributed (the Open Source Initiative-approved MIT license).
scripts, specify the "--standard-lib" option on the command line, as
follows:
# python setup.py install --standard-lib 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.
This will install the build engine in the standard Python library scons-README
directory (/usr/lib/python*/site-packages or What you're looking at right now.
C:\Python*\Lib\site-packages).
Alternatively, you can have SCons install its build engine library in a scons-local-{version}/
hard-coded standalone library directory, instead of the default The SCons build engine. This is structured as a Python
version-numbered directory, by specifying the "--standalone-lib" option library.
on the command line, as follows:
# python setup.py install --standalone-lib scons.py
The SCons script itself. The script sets up the Python
This is usually not recommended, however. sys.path variable to use the build engine found in the
scons-local-{version}/ directory in preference to any other
Note that, to install SCons in any of the above system directories, SCons build engine installed on your system.
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 DOCUMENTATION
============= =============
See the RELEASE.txt file for notes about this specific release, Because this package is intended to be included with other software by
including known problems. See the CHANGES.txt file for a list of experienced users, we have not included any SCons documentation in this
changes since the previous release. package (other than this scons-README file you're reading right now).
The scons.1 man page is included in this package, and contains a section If, however, you need documentation about SCons, then consult any of the
of small examples for getting started using SCons. 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.
Additional documentation for SCons is available at: Additional documentation for SCons is available at:
@ -184,8 +142,8 @@ LICENSING
========= =========
SCons is distributed under the MIT license, a full copy of which is SCons is distributed under the MIT license, a full copy of which is
available in the LICENSE.txt file. The MIT license is an approved Open available in the scons-LICENSE file in this package. The MIT license is
Source license, which means: an approved Open Source license, which means:
This software is OSI Certified Open Source Software. OSI This software is OSI Certified Open Source Software. OSI
Certified is a certification mark of the Open Source Initiative. Certified is a certification mark of the Open Source Initiative.
@ -199,51 +157,27 @@ available at:
REPORTING BUGS REPORTING BUGS
============== ==============
Please report bugs by following the detailed instructions on our Bug You can report bugs either by following the "Tracker - Bugs" link
Submission page: on the SCons project page:
http://scons.tigris.org/bug-submission.html http://sourceforge.net/projects/scons/
You can also send mail to the SCons developers' mailing list: or by sending mail to the SCons developers mailing list:
dev@scons.tigris.org scons-devel@lists.sourceforge.net
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 MAILING LISTS
============= =============
An active mailing list for users of SCons is available. You may send A mailing list for users of SCons is available. You may send questions
questions or comments to the list at: or comments to the list at:
users@scons.tigris.org scons-users@lists.sourceforge.net
You may subscribe to the mailing list by sending email to: You may subscribe to the scons-users mailing list at:
users-subscribe@scons.tigris.org http://lists.sourceforge.net/lists/listinfo/scons-users
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 FOR MORE INFORMATION
@ -265,9 +199,6 @@ With plenty of help from the SCons Development team:
Chad Austin Chad Austin
Charles Crain Charles Crain
Steve Leblanc Steve Leblanc
Greg Noel
Gary Oberbrunner
Anthony Roach Anthony Roach
Greg Spencer Terrel Shumway
Christoph Wiedemann

View file

@ -31,8 +31,8 @@ other modules:
get_contents() get_contents()
Fetches the "contents" of an Action for signature calculation. Fetches the "contents" of an Action for signature calculation.
This is what the Sig/*.py subsystem uses to decide if a target This is what gets MD5 checksumm'ed to decide if a target needs
needs to be rebuilt because its action changed. to be rebuilt because its action changed.
genstring() genstring()
Returns a string representation of the Action *without* Returns a string representation of the Action *without*
@ -95,7 +95,7 @@ way for wrapping up the functions.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Action.py 2523 2007/12/12 09:37:41 knight"
import dis import dis
import os import os
@ -287,6 +287,7 @@ class _ActionAction(ActionBase):
target = [target] target = [target]
if not SCons.Util.is_List(source): if not SCons.Util.is_List(source):
source = [source] source = [source]
if exitstatfunc is _null: exitstatfunc = self.exitstatfunc if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
if presub is _null: if presub is _null:
presub = self.presub presub = self.presub
@ -329,12 +330,20 @@ class _ActionAction(ActionBase):
os.chdir(chdir) os.chdir(chdir)
try: try:
stat = self.execute(target, source, env) stat = self.execute(target, source, env)
stat = exitstatfunc(stat) if isinstance(stat, SCons.Errors.BuildError):
s = exitstatfunc(stat.status)
if s:
stat.status = s
else:
stat = s
else:
stat = exitstatfunc(stat)
finally: finally:
if save_cwd: if save_cwd:
os.chdir(save_cwd) os.chdir(save_cwd)
if s and save_cwd: if s and save_cwd:
print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
return stat return stat
@ -476,7 +485,11 @@ class CommandAction(_ActionAction):
cmd_line = escape_list(cmd_line, escape) cmd_line = escape_list(cmd_line, escape)
result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
if not ignore and result: if not ignore and result:
return result msg = "Error %s" % result
return SCons.Errors.BuildError(errstr=msg,
status=result,
action=self,
command=cmd_line)
return 0 return 0
def get_contents(self, target, source, env): def get_contents(self, target, source, env):
@ -493,6 +506,22 @@ class CommandAction(_ActionAction):
cmd = str(cmd) cmd = str(cmd)
return env.subst_target_source(cmd, SUBST_SIG, target, source) return env.subst_target_source(cmd, SUBST_SIG, target, source)
def get_implicit_deps(self, target, source, env):
icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
if SCons.Util.is_String(icd) and icd[:1] == '$':
icd = env.subst(icd)
if not icd or icd in ('0', 'None'):
return []
from SCons.Subst import SUBST_SIG
cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
res = []
for cmd_line in cmd_list:
if cmd_line:
d = env.WhereIs(str(cmd_line[0]))
if d:
res.append(env.fs.File(d))
return res
class CommandGeneratorAction(ActionBase): class CommandGeneratorAction(ActionBase):
"""Class for command-generator actions.""" """Class for command-generator actions."""
def __init__(self, generator, *args, **kw): def __init__(self, generator, *args, **kw):
@ -515,9 +544,11 @@ class CommandGeneratorAction(ActionBase):
def __str__(self): def __str__(self):
try: try:
env = self.presub_env or {} env = self.presub_env
except AttributeError: except AttributeError:
env = {} env = None
if env is None:
env = SCons.Defaults.DefaultEnvironment()
act = self._generate([], [], env, 1) act = self._generate([], [], env, 1)
return str(act) return str(act)
@ -538,6 +569,9 @@ class CommandGeneratorAction(ActionBase):
""" """
return self._generate(target, source, env, 1).get_contents(target, source, env) return self._generate(target, source, env, 1).get_contents(target, source, env)
def get_implicit_deps(self, target, source, env):
return self._generate(target, source, env, 1).get_implicit_deps(target, source, env)
# A LazyAction is a kind of hybrid generator and command action for # A LazyAction is a kind of hybrid generator and command action for
@ -666,9 +700,19 @@ class FunctionAction(_ActionAction):
# target file will appear). # target file will appear).
try: filename = e.filename try: filename = e.filename
except AttributeError: filename = None except AttributeError: filename = None
raise SCons.Errors.BuildError(node=target, result = SCons.Errors.BuildError(node=target,
errstr=e.strerror, errstr=e.strerror,
filename=filename) status=1,
filename=filename,
action=self,
command=self.strfunction(target, source, env))
else:
if result:
msg = "Error %s" % result
result = SCons.Errors.BuildError(errstr=msg,
status=result,
action=self,
command=self.strfunction(target, source, env))
return result return result
def get_contents(self, target, source, env): def get_contents(self, target, source, env):
@ -713,6 +757,9 @@ class FunctionAction(_ActionAction):
return contents + env.subst(string.join(map(lambda v: '${'+v+'}', return contents + env.subst(string.join(map(lambda v: '${'+v+'}',
self.varlist))) self.varlist)))
def get_implicit_deps(self, target, source, env):
return []
class ListAction(ActionBase): class ListAction(ActionBase):
"""Class for lists of other actions.""" """Class for lists of other actions."""
def __init__(self, list): def __init__(self, list):
@ -756,6 +803,12 @@ class ListAction(ActionBase):
return stat return stat
return 0 return 0
def get_implicit_deps(self, target, source, env):
result = []
for act in self.list:
result.extend(act.get_implicit_deps(target, source, env))
return result
class ActionCaller: class ActionCaller:
"""A class for delaying calling an Action function with specific """A class for delaying calling an Action function with specific
(positional and keyword) arguments until the Action is actually (positional and keyword) arguments until the Action is actually
@ -790,8 +843,9 @@ class ActionCaller:
# was called by using this hard-coded value as a special return. # was called by using this hard-coded value as a special return.
if s == '$__env__': if s == '$__env__':
return env return env
else: elif SCons.Util.is_String(s):
return env.subst(s, 0, target, source) return env.subst(s, 0, target, source)
return self.parent.convert(s)
def subst_args(self, target, source, env): def subst_args(self, target, source, env):
return map(lambda x, self=self, t=target, s=source, e=env: return map(lambda x, self=self, t=target, s=source, e=env:
self.subst(x, t, s, e), self.subst(x, t, s, e),
@ -821,9 +875,10 @@ class ActionFactory:
called with and give them to the ActionCaller object we create, called with and give them to the ActionCaller object we create,
so it can hang onto them until it needs them. so it can hang onto them until it needs them.
""" """
def __init__(self, actfunc, strfunc): def __init__(self, actfunc, strfunc, convert=lambda x: x):
self.actfunc = actfunc self.actfunc = actfunc
self.strfunc = strfunc self.strfunc = strfunc
self.convert = convert
def __call__(self, *args, **kw): def __call__(self, *args, **kw):
ac = ActionCaller(self, args, kw) ac = ActionCaller(self, args, kw)
action = Action(ac, strfunction=ac.strfunction) action = Action(ac, strfunction=ac.strfunction)

View file

@ -39,9 +39,6 @@ used by other modules:
variable. This also takes care of warning about possible mistakes variable. This also takes care of warning about possible mistakes
in keyword arguments. in keyword arguments.
targets()
Returns the list of targets for a specific builder instance.
add_emitter() add_emitter()
Adds an emitter for a specific file suffix, used by some Tool Adds an emitter for a specific file suffix, used by some Tool
modules to specify that (for example) a yacc invocation on a .y modules to specify that (for example) a yacc invocation on a .y
@ -101,7 +98,7 @@ There are the following methods for internal use within this module:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Builder.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat import SCons.compat
@ -367,6 +364,7 @@ class BuilderBase:
chdir = _null, chdir = _null,
is_explicit = 1, is_explicit = 1,
src_builder = [], src_builder = [],
ensure_suffix = False,
**overrides): **overrides):
if __debug__: logInstanceCreation(self, 'Builder.BuilderBase') if __debug__: logInstanceCreation(self, 'Builder.BuilderBase')
self._memo = {} self._memo = {}
@ -394,6 +392,7 @@ class BuilderBase:
self.set_suffix(suffix) self.set_suffix(suffix)
self.set_src_suffix(src_suffix) self.set_src_suffix(src_suffix)
self.ensure_suffix = ensure_suffix
self.target_factory = target_factory self.target_factory = target_factory
self.source_factory = source_factory self.source_factory = source_factory
@ -467,28 +466,28 @@ class BuilderBase:
executor.add_sources(slist) executor.add_sources(slist)
return executor return executor
def _adjustixes(self, files, pre, suf, ensure_suffix=False):
if not files:
return []
result = []
if not SCons.Util.is_List(files):
files = [files]
for f in files:
if SCons.Util.is_String(f):
f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
result.append(f)
return result
def _create_nodes(self, env, target = None, source = None): def _create_nodes(self, env, target = None, source = None):
"""Create and return lists of target and source nodes. """Create and return lists of target and source nodes.
""" """
def _adjustixes(files, pre, suf):
if not files:
return []
result = []
if not SCons.Util.is_List(files):
files = [files]
for f in files:
if SCons.Util.is_String(f):
f = SCons.Util.adjustixes(f, pre, suf)
result.append(f)
return result
src_suf = self.get_src_suffix(env) src_suf = self.get_src_suffix(env)
target_factory = env.get_factory(self.target_factory) target_factory = env.get_factory(self.target_factory)
source_factory = env.get_factory(self.source_factory) source_factory = env.get_factory(self.source_factory)
source = _adjustixes(source, None, src_suf) source = self._adjustixes(source, None, src_suf)
slist = env.arg2nodes(source, source_factory) slist = env.arg2nodes(source, source_factory)
pre = self.get_prefix(env, slist) pre = self.get_prefix(env, slist)
@ -505,7 +504,7 @@ class BuilderBase:
splitext = lambda S,self=self,env=env: self.splitext(S,env) splitext = lambda S,self=self,env=env: self.splitext(S,env)
tlist = [ t_from_s(pre, suf, splitext) ] tlist = [ t_from_s(pre, suf, splitext) ]
else: else:
target = _adjustixes(target, pre, suf) target = self._adjustixes(target, pre, suf, self.ensure_suffix)
tlist = env.arg2nodes(target, target_factory) tlist = env.arg2nodes(target, target_factory)
if self.emitter: if self.emitter:
@ -520,6 +519,9 @@ class BuilderBase:
t.builder_set(self) t.builder_set(self)
new_targets.append(t) new_targets.append(t)
orig_tlist = tlist[:]
orig_slist = slist[:]
target, source = self.emitter(target=tlist, source=slist, env=env) target, source = self.emitter(target=tlist, source=slist, env=env)
# Now delete the temporary builders that we attached to any # Now delete the temporary builders that we attached to any
@ -533,8 +535,10 @@ class BuilderBase:
# Have to call arg2nodes yet again, since it is legal for # Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances. # emitters to spit out strings as well as Node instances.
tlist = env.arg2nodes(target, target_factory) tlist = env.arg2nodes(target, target_factory,
slist = env.arg2nodes(source, source_factory) target=orig_tlist, source=orig_slist)
slist = env.arg2nodes(source, source_factory,
target=orig_tlist, source=orig_slist)
return tlist, slist return tlist, slist
@ -550,10 +554,10 @@ class BuilderBase:
if not tgt is None: tgt = [tgt] if not tgt is None: tgt = [tgt]
if not src is None: src = [src] if not src is None: src = [src]
result.extend(self._execute(env, tgt, src, overwarn)) result.extend(self._execute(env, tgt, src, overwarn))
return result return SCons.Node.NodeList(result)
overwarn.warn() overwarn.warn()
tlist, slist = self._create_nodes(env, target, source) tlist, slist = self._create_nodes(env, target, source)
# Check for errors with the specified target/source lists. # Check for errors with the specified target/source lists.
@ -647,13 +651,6 @@ class BuilderBase:
return '' return ''
return ret[0] return ret[0]
def targets(self, node):
"""Return the list of targets for this builder instance.
For most normal builders, this is just the supplied node.
"""
return [ node ]
def add_emitter(self, suffix, emitter): def add_emitter(self, suffix, emitter):
"""Add a suffix-emitter mapping to this Builder. """Add a suffix-emitter mapping to this Builder.
@ -699,22 +696,16 @@ class BuilderBase:
for suf in bld.src_suffixes(env): for suf in bld.src_suffixes(env):
sdict[suf] = bld sdict[suf] = bld
return sdict return sdict
def src_builder_sources(self, env, source, overwarn={}):
source_factory = env.get_factory(self.source_factory)
slist = env.arg2nodes(source, source_factory)
def src_builder_sources(self, env, source, overwarn={}):
sdict = self._get_sdict(env) sdict = self._get_sdict(env)
src_suffixes = self.src_suffixes(env) src_suffixes = self.src_suffixes(env)
lengths_dict = {} lengths = list(set(map(len, src_suffixes)))
for l in map(len, src_suffixes):
lengths_dict[l] = None
lengths = lengths_dict.keys()
def match_src_suffix(node, src_suffixes=src_suffixes, lengths=lengths): def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths):
node_suffixes = map(lambda l, n=node: n.name[-l:], lengths) node_suffixes = map(lambda l, n=name: n[-l:], lengths)
for suf in src_suffixes: for suf in src_suffixes:
if suf in node_suffixes: if suf in node_suffixes:
return suf return suf
@ -722,25 +713,38 @@ class BuilderBase:
result = [] result = []
for snode in slist: if SCons.Util.is_List(source):
match_suffix = match_src_suffix(snode) source = SCons.Util.flatten(source)
else:
source = [source]
for s in source:
if SCons.Util.is_String(s):
match_suffix = match_src_suffix(s)
if not match_suffix and not '.' in s:
src_suf = self.get_src_suffix(env)
s = self._adjustixes(s, None, src_suf)[0]
else:
match_suffix = match_src_suffix(s.name)
if match_suffix: if match_suffix:
try: try:
bld = sdict[match_suffix] bld = sdict[match_suffix]
except KeyError: except KeyError:
result.append(snode) result.append(s)
else: else:
tlist = bld._execute(env, None, [snode], overwarn) tlist = bld._execute(env, None, [s], overwarn)
# If the subsidiary Builder returned more than one # If the subsidiary Builder returned more than one
# target, then filter out any sources that this # target, then filter out any sources that this
# Builder isn't capable of building. # Builder isn't capable of building.
if len(tlist) > 1: if len(tlist) > 1:
tlist = filter(match_src_suffix, tlist) mss = lambda t, m=match_src_suffix: m(t.name)
tlist = filter(mss, tlist)
result.extend(tlist) result.extend(tlist)
else: else:
result.append(snode) result.append(s)
return result source_factory = env.get_factory(self.source_factory)
return env.arg2nodes(result, source_factory)
def _get_src_builders_key(self, env): def _get_src_builders_key(self, env):
return id(env) return id(env)

View file

@ -0,0 +1,217 @@
#
# 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__ = "src/engine/SCons/CacheDir.py 2523 2007/12/12 09:37:41 knight"
__doc__ = """
CacheDir support
"""
import os.path
import stat
import string
import sys
import SCons.Action
cache_debug = False
cache_force = False
cache_show = False
def CacheRetrieveFunc(target, source, env):
t = target[0]
fs = t.fs
cd = env.get_CacheDir()
cachedir, cachefile = cd.cachepath(t)
if not fs.exists(cachefile):
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
return 1
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
if SCons.Action.execute_actions:
if fs.islink(cachefile):
fs.symlink(fs.readlink(cachefile), t.path)
else:
env.copy_from_cache(cachefile, t.path)
st = fs.stat(cachefile)
fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
def CacheRetrieveString(target, source, env):
t = target[0]
fs = t.fs
cd = env.get_CacheDir()
cachedir, cachefile = cd.cachepath(t)
if t.fs.exists(cachefile):
return "Retrieved `%s' from cache" % t.path
return None
CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString)
CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None)
def CachePushFunc(target, source, env):
t = target[0]
if t.nocache:
return
fs = t.fs
cd = env.get_CacheDir()
cachedir, cachefile = cd.cachepath(t)
if fs.exists(cachefile):
# Don't bother copying it if it's already there. Note that
# usually this "shouldn't happen" because if the file already
# existed in cache, we'd have retrieved the file from there,
# not built it. This can happen, though, in a race, if some
# other person running the same build pushes their copy to
# the cache after we decide we need to build it but before our
# build completes.
cd.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile)
return
cd.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile)
tempfile = cachefile+'.tmp'+str(os.getpid())
errfmt = "Unable to copy %s to cache. Cache file is %s"
if not fs.isdir(cachedir):
try:
fs.makedirs(cachedir)
except EnvironmentError:
# We may have received an exception because another process
# has beaten us creating the directory.
if not fs.isdir(cachedir):
msg = errfmt % (str(target), cachefile)
raise SCons.Errors.EnvironmentError, msg
try:
if fs.islink(t.path):
fs.symlink(fs.readlink(t.path), tempfile)
else:
fs.copy2(t.path, tempfile)
fs.rename(tempfile, cachefile)
st = fs.stat(t.path)
fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
except EnvironmentError:
# It's possible someone else tried writing the file at the
# same time we did, or else that there was some problem like
# the CacheDir being on a separate file system that's full.
# In any case, inability to push a file to cache doesn't affect
# the correctness of the build, so just print a warning.
msg = errfmt % (str(target), cachefile)
SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg)
CachePush = SCons.Action.Action(CachePushFunc, None)
class CacheDir:
def __init__(self, path):
try:
import hashlib
except ImportError:
msg = "No hashlib or MD5 module available, CacheDir() not supported"
SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
else:
self.path = path
def CacheDebugWrite(self, fmt, target, cachefile):
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
def CacheDebugQuiet(self, fmt, target, cachefile):
pass
def CacheDebugInit(self, fmt, target, cachefile):
if cache_debug:
if cache_debug == '-':
self.debugFP = sys.stdout
else:
self.debugFP = open(cache_debug, 'w')
self.CacheDebug = self.CacheDebugWrite
self.CacheDebug(fmt, target, cachefile)
else:
self.CacheDebug = self.CacheDebugQuiet
CacheDebug = CacheDebugInit
def cachepath(self, node):
"""
"""
sig = node.get_cachedir_bsig()
subdir = string.upper(sig[0])
dir = os.path.join(self.path, subdir)
return dir, os.path.join(dir, sig)
def retrieve(self, node):
"""
This method is called from multiple threads in a parallel build,
so only do thread safe stuff here. Do thread unsafe stuff in
built().
Note that there's a special trick here with the execute flag
(one that's not normally done for other actions). Basically
if the user requested a no_exec (-n) build, then
SCons.Action.execute_actions is set to 0 and when any action
is called, it does its showing but then just returns zero
instead of actually calling the action execution operation.
The problem for caching is that if the file does NOT exist in
cache then the CacheRetrieveString won't return anything to
show for the task, but the Action.__call__ won't call
CacheRetrieveFunc; instead it just returns zero, which makes
the code below think that the file *was* successfully
retrieved from the cache, therefore it doesn't do any
subsequent building. However, the CacheRetrieveString didn't
print anything because it didn't actually exist in the cache,
and no more build actions will be performed, so the user just
sees nothing. The fix is to tell Action.__call__ to always
execute the CacheRetrieveFunc and then have the latter
explicitly check SCons.Action.execute_actions itself.
"""
retrieved = False
if cache_show:
if CacheRetrieveSilent(node, [], node.get_build_env(), execute=1) == 0:
node.build(presub=0, execute=0)
retrieved = 1
else:
if CacheRetrieve(node, [], node.get_build_env(), execute=1) == 0:
retrieved = 1
if retrieved:
# Record build signature information, but don't
# push it out to cache. (We just got it from there!)
node.set_state(SCons.Node.executed)
SCons.Node.Node.built(node)
return retrieved
def push(self, node):
return CachePush(node, [], node.get_build_env())
def push_if_forced(self, node):
if cache_force:
return self.push(node)
class Null(SCons.Util.Null):
def repr(self):
return 'CacheDir.Null()'
def cachepath(self, node):
return None, None
def retrieve(self, node):
return False

View file

@ -318,6 +318,102 @@ int main() {
return ret return ret
def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
"""This check can be used to get the size of a given type, or to check whether
the type is of expected size.
Arguments:
- type : str
the type to check
- includes : sequence
list of headers to include in the test code before testing the type
- language : str
'C' or 'C++'
- expect : int
if given, will test wether the type has the given number of bytes.
If not given, will automatically find the size.
Returns:
status : int
0 if the check failed, or the found size of the type if the check succeeded."""
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
if context.headerfilename:
includetext = '#include "%s"' % context.headerfilename
else:
includetext = ''
if not header:
header = ""
lang, suffix, msg = _lang2suffix(language)
if msg:
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
return msg
src = includetext + header
if not expect is None:
# Only check if the given size is the right one
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
# test code taken from autoconf: this is a pretty clever hack to find that
# a type is of a given size using only compilation. This speeds things up
# quite a bit compared to straightforward code using TryRun
src = src + r"""
typedef %s scons_check_type;
int main()
{
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
test_array[0] = 0;
return 0;
}
"""
# XXX: Try* vs CompileProg ?
st = context.TryCompile(src % (type_name, expect), suffix)
if st:
_Have(context, "SIZEOF_" + type_name, str(expect))
context.Display("yes\n")
return expect
else:
context.Display("no\n")
_LogFailed(context, src, st)
return 0
else:
# Only check if the given size is the right one
context.Message('Checking size of %s ... ' % type_name)
# We have to be careful with the program we wish to test here since
# compilation will be attempted using the current environment's flags.
# So make sure that the program will compile without any warning. For
# example using: 'int main(int argc, char** argv)' will fail with the
# '-Wall -Werror' flags since the variables argc and argv would not be
# used in the program...
#
src = src + """
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("%d", (int)sizeof(""" + type_name + """));
return 0;
}
"""
ret = context.TryRun(src, suffix)
st = ret[0]
try:
size = int(ret[1])
_Have(context, "SIZEOF_" + type_name, str(size))
context.Display("%d\n" % size)
except ValueError:
size = 0
_LogFailed(context, src, st)
context.Display(" Failed !\n")
if st:
return size
else:
return 0
def CheckLib(context, libs, func_name = None, header = None, def CheckLib(context, libs, func_name = None, header = None,
extra_libs = None, call = None, language = None, autoadd = 1): extra_libs = None, call = None, language = None, autoadd = 1):
@ -462,7 +558,7 @@ def _Have(context, key, have):
key_up = re.sub('[^A-Z0-9_]', '_', key_up) key_up = re.sub('[^A-Z0-9_]', '_', key_up)
context.havedict[key_up] = have context.havedict[key_up] = have
if have == 1: if have == 1:
line = "#define %s\n" % key_up line = "#define %s 1\n" % key_up
elif have == 0: elif have == 0:
line = "/* #undef %s */\n" % key_up line = "/* #undef %s */\n" % key_up
elif type(have) == IntType: elif type(have) == IntType:

View file

@ -29,7 +29,7 @@ needed by most users.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Debug.py 2523 2007/12/12 09:37:41 knight"
import os import os
import string import string
@ -197,3 +197,4 @@ def Trace(msg, file=None, mode='w'):
# Assume we were passed an open file pointer. # Assume we were passed an open file pointer.
fp = file fp = file
fp.write(msg) fp.write(msg)
fp.flush()

View file

@ -32,7 +32,7 @@ from distutils.msvccompiler.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Defaults.py 2523 2007/12/12 09:37:41 knight"
@ -46,9 +46,9 @@ import sys
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder
import SCons.CacheDir
import SCons.Environment import SCons.Environment
import SCons.PathList import SCons.PathList
import SCons.Sig
import SCons.Subst import SCons.Subst
import SCons.Tool import SCons.Tool
@ -60,12 +60,40 @@ _default_env = None
# Lazily instantiate the default environment so the overhead of creating # Lazily instantiate the default environment so the overhead of creating
# it doesn't apply when it's not needed. # it doesn't apply when it's not needed.
def _fetch_DefaultEnvironment(*args, **kw):
"""
Returns the already-created default construction environment.
"""
global _default_env
return _default_env
def DefaultEnvironment(*args, **kw): def DefaultEnvironment(*args, **kw):
"""
Initial public entry point for creating the default construction
Environment.
After creating the environment, we overwrite our name
(DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
which more efficiently returns the initialized default construction
environment without checking for its existence.
(This function still exists with its _default_check because someone
else (*cough* Script/__init__.py *cough*) may keep a reference
to this function. So we can't use the fully functional idiom of
having the name originally be a something that *only* creates the
construction environment and then overwrites the name.)
"""
global _default_env global _default_env
if not _default_env: if not _default_env:
import SCons.Util
_default_env = apply(SCons.Environment.Environment, args, kw) _default_env = apply(SCons.Environment.Environment, args, kw)
_default_env._build_signature = 1 if SCons.Util.md5:
_default_env._calc_module = SCons.Sig.default_module _default_env.Decider('MD5')
else:
_default_env.Decider('timestamp-match')
global DefaultEnvironment
DefaultEnvironment = _fetch_DefaultEnvironment
_default_env._CacheDir = SCons.CacheDir.Null()
return _default_env return _default_env
# Emitters for setting the shared attribute on object files, # Emitters for setting the shared attribute on object files,
@ -104,9 +132,9 @@ LaTeXScan = SCons.Tool.LaTeXScanner
ObjSourceScan = SCons.Tool.SourceFileScanner ObjSourceScan = SCons.Tool.SourceFileScanner
ProgScan = SCons.Tool.ProgramScanner ProgScan = SCons.Tool.ProgramScanner
# This isn't really a tool scanner, so it doesn't quite belong with # These aren't really tool scanners, so they don't quite belong with
# the rest of those in Tool/__init__.py, but I'm not sure where else it # the rest of those in Tool/__init__.py, but I'm not sure where else
# should go. Leave it here for now. # they should go. Leave them here for now.
import SCons.Scanner.Dir import SCons.Scanner.Dir
DirScanner = SCons.Scanner.Dir.DirScanner() DirScanner = SCons.Scanner.Dir.DirScanner()
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
@ -129,19 +157,28 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
# ways by creating ActionFactory instances. # ways by creating ActionFactory instances.
ActionFactory = SCons.Action.ActionFactory ActionFactory = SCons.Action.ActionFactory
Chmod = ActionFactory(os.chmod, def chmod_func(path, mode):
return os.chmod(str(path), mode)
Chmod = ActionFactory(chmod_func,
lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode)) lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
def copy_func(dest, src): def copy_func(dest, src):
if os.path.isfile(src): if SCons.Util.is_List(src) and os.path.isdir(dest):
for file in src:
shutil.copy(file, dest)
return 0
elif os.path.isfile(src):
return shutil.copy(src, dest) return shutil.copy(src, dest)
else: else:
return shutil.copytree(src, dest, 1) return shutil.copytree(src, dest, 1)
Copy = ActionFactory(copy_func, Copy = ActionFactory(copy_func,
lambda dest, src: 'Copy("%s", "%s")' % (dest, src)) lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
convert=str)
def delete_func(entry, must_exist=0): def delete_func(entry, must_exist=0):
entry = str(entry)
if not must_exist and not os.path.exists(entry): if not must_exist and not os.path.exists(entry):
return None return None
if not os.path.exists(entry) or os.path.isfile(entry): if not os.path.exists(entry) or os.path.isfile(entry):
@ -155,12 +192,15 @@ def delete_strfunc(entry, must_exist=0):
Delete = ActionFactory(delete_func, delete_strfunc) Delete = ActionFactory(delete_func, delete_strfunc)
Mkdir = ActionFactory(os.makedirs, Mkdir = ActionFactory(os.makedirs,
lambda dir: 'Mkdir("%s")' % dir) lambda dir: 'Mkdir("%s")' % dir,
convert=str)
Move = ActionFactory(lambda dest, src: os.rename(src, dest), Move = ActionFactory(lambda dest, src: os.rename(src, dest),
lambda dest, src: 'Move("%s", "%s")' % (dest, src)) lambda dest, src: 'Move("%s", "%s")' % (dest, src),
convert=str)
def touch_func(file): def touch_func(file):
file = str(file)
mtime = int(time.time()) mtime = int(time.time())
if os.path.exists(file): if os.path.exists(file):
atime = os.path.getatime(file) atime = os.path.getatime(file)
@ -173,33 +213,6 @@ Touch = ActionFactory(touch_func,
lambda file: 'Touch("%s")' % file) lambda file: 'Touch("%s")' % file)
# Internal utility functions # 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): def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
""" """
@ -258,91 +271,46 @@ def _concat_ixes(prefix, list, suffix, env):
return result return result
def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None): 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 This is a wrapper around _concat()/_concat_ixes() that checks for the
finds them. This is used by tools (like the GNU linker) that need existence of prefixes or suffixes on list elements and strips them
to turn something like 'libfoo.a' into '-lfoo'.""" 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 not list:
if callable(env["_concat"]): return list
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 if not callable(c):
# (as of 21 February 2007), like the current version above. It's more env_c = env['_concat']
# straightforward because it does its manipulation directly, not using if env_c != _concat and callable(env_c):
# the funky f call-back function to _concat(). (In this respect it's # There's a custom _concat() method in the construction
# like the updated _defines() function below.) # environment, and we've allowed people to set that in
# # the past (see test/custom-concat.py), so preserve the
# The most convoluted thing is that it still uses a custom _concat() # backwards compatibility.
# function if one was placed in the construction environment; there's c = env_c
# a specific test for that functionality, but it might be worth getting else:
# rid of. c = _concat_ixes
#
# Since this work was done while trying to get 0.97 out the door if SCons.Util.is_List(list):
# (just prior to 0.96.96), I decided to be cautious and leave the old list = SCons.Util.flatten(list)
# 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 lsp = len(stripprefix)
# using it at a less sensitive time in the development cycle (or when lss = len(stripsuffix)
# it's clearly required to fix something). stripped = []
# for l in SCons.PathList.PathList(list).subst_path(env, None, None):
#def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None): if isinstance(l, SCons.Node.FS.File):
# """ stripped.append(l)
# This is a wrapper around _concat()/_concat_ixes() that checks for the continue
# existence of prefixes or suffixes on list elements and strips them if not SCons.Util.is_String(l):
# where it finds them. This is used by tools (like the GNU linker) l = str(l)
# that need to turn something like 'libfoo.a' into '-lfoo'. if l[:lsp] == stripprefix:
# """ l = l[lsp:]
# if l[-lss:] == stripsuffix:
# if not list: l = l[:-lss]
# return list stripped.append(l)
#
# if not callable(c): return c(prefix, stripped, suffix, env)
# 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): def _defines(prefix, defs, suffix, env, c=_concat_ixes):
"""A wrapper around _concat_ixes that turns a list or string """A wrapper around _concat_ixes that turns a list or string
@ -430,9 +398,6 @@ ConstructionEnvironment = {
'DSUFFIXES' : SCons.Tool.DSuffixes, 'DSUFFIXES' : SCons.Tool.DSuffixes,
'ENV' : {}, 'ENV' : {},
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
'INSTALL' : installFunc,
'INSTALLSTR' : installStr,
'_installStr' : installStr,
'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
'_concat' : _concat, '_concat' : _concat,
'_defines' : _defines, '_defines' : _defines,

View file

@ -6,7 +6,7 @@ construction information to the build engine.
Keyword arguments supplied when the construction Environment Keyword arguments supplied when the construction Environment
is created are construction variables used to initialize the is created are construction variables used to initialize the
Environment Environment
""" """
# #
@ -32,12 +32,13 @@ Environment
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Environment.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Environment.py 2523 2007/12/12 09:37:41 knight"
import copy import copy
import os import os
import os.path import os.path
import shlex
import string import string
from UserDict import UserDict from UserDict import UserDict
@ -53,7 +54,6 @@ import SCons.Node.FS
import SCons.Node.Python import SCons.Node.Python
import SCons.Platform import SCons.Platform
import SCons.SConsign import SCons.SConsign
import SCons.Sig
import SCons.Subst import SCons.Subst
import SCons.Tool import SCons.Tool
import SCons.Util import SCons.Util
@ -67,32 +67,13 @@ _null = _Null
CleanTargets = {} CleanTargets = {}
CalculatorArgs = {} CalculatorArgs = {}
semi_deepcopy = SCons.Util.semi_deepcopy
# Pull UserError into the global name space for the benefit of # Pull UserError into the global name space for the benefit of
# Environment().SourceSignatures(), which has some import statements # Environment().SourceSignatures(), which has some import statements
# which seem to mess up its ability to reference SCons directly. # which seem to mess up its ability to reference SCons directly.
UserError = SCons.Errors.UserError UserError = SCons.Errors.UserError
def installFunc(target, source, env):
"""Install a source file into a target using the function specified
as the INSTALL construction variable."""
try:
install = env['INSTALL']
except KeyError:
raise SCons.Errors.UserError('Missing INSTALL construction variable.')
return install(target[0].path, source[0].path, env)
def installString(target, source, env):
s = env.get('INSTALLSTR', '')
if callable(s):
return s(target[0].path, source[0].path, env)
else:
return env.subst_target_source(s, 0, target, source)
installAction = SCons.Action.Action(installFunc, installString)
InstallBuilder = SCons.Builder.Builder(action=installAction,
name='InstallBuilder')
def alias_builder(env, target, source): def alias_builder(env, target, source):
pass pass
@ -103,23 +84,6 @@ AliasBuilder = SCons.Builder.Builder(action = alias_builder,
is_explicit = None, is_explicit = None,
name='AliasBuilder') name='AliasBuilder')
def our_deepcopy(x):
"""deepcopy lists and dictionaries, and just copy the reference
for everything else."""
if SCons.Util.is_Dict(x):
copy = {}
for key in x.keys():
copy[key] = our_deepcopy(x[key])
elif SCons.Util.is_List(x):
copy = map(our_deepcopy, x)
try:
copy = x.__class__(copy)
except AttributeError:
pass
else:
copy = x
return copy
def apply_tools(env, tools, toolpath): def apply_tools(env, tools, toolpath):
# Store the toolpath in the Environment. # Store the toolpath in the Environment.
if toolpath is not None: if toolpath is not None:
@ -143,7 +107,7 @@ reserved_construction_var_names = \
['TARGET', 'TARGETS', 'SOURCE', 'SOURCES'] ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']
def copy_non_reserved_keywords(dict): def copy_non_reserved_keywords(dict):
result = our_deepcopy(dict) result = semi_deepcopy(dict)
for k in result.keys(): for k in result.keys():
if k in reserved_construction_var_names: if k in reserved_construction_var_names:
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
@ -161,8 +125,9 @@ def _set_BUILDERS(env, key, value):
for k in bd.keys(): for k in bd.keys():
del bd[k] del bd[k]
except KeyError: except KeyError:
env._dict[key] = BuilderDict(kwbd, env) bd = BuilderDict(kwbd, env)
env._dict[key].update(value) env._dict[key] = bd
bd.update(value)
def _del_SCANNERS(env, key): def _del_SCANNERS(env, key):
del env._dict[key] del env._dict[key]
@ -172,13 +137,72 @@ def _set_SCANNERS(env, key, value):
env._dict[key] = value env._dict[key] = value
env.scanner_map_delete() env.scanner_map_delete()
class BuilderWrapper:
"""Wrapper class that associates an environment with a Builder at
instantiation."""
def __init__(self, env, builder):
self.env = env
self.builder = builder
# The following is partly based on code in a comment added by Peter
# Shannon at the following page (there called the "transplant" class):
#
# ASPN : Python Cookbook : Dynamically added methods to a class
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
#
# We had independently been using the idiom as BuilderWrapper, but
# factoring out the common parts into this base class, and making
# BuilderWrapper a subclass that overrides __call__() to enforce specific
# Builder calling conventions, simplified some of our higher-layer code.
class MethodWrapper:
"""
A generic Wrapper class that associates a method (which can
actually be any callable) with an object. As part of creating this
MethodWrapper object an attribute with the specified (by default,
the name of the supplied method) is added to the underlying object.
When that new "method" is called, our __call__() method adds the
object as the first argument, simulating the Python behavior of
supplying "self" on method calls.
We hang on to the name by which the method was added to the underlying
base class so that we can provide a method to "clone" ourselves onto
a new underlying object being copied (without which we wouldn't need
to save that info).
"""
def __init__(self, object, method, name=None):
if name is None:
name = method.__name__
self.object = object
self.method = method
self.name = name
setattr(self.object, name, self)
def __call__(self, *args, **kwargs):
nargs = (self.object,) + args
return apply(self.method, nargs, kwargs)
def clone(self, new_object):
"""
Returns an object that re-binds the underlying "method" to
the specified new object.
"""
return self.__class__(new_object, self.method, self.name)
class BuilderWrapper(MethodWrapper):
"""
A MethodWrapper subclass that that associates an environment with
a Builder.
This mainly exists to wrap the __call__() function so that all calls
to Builders can have their argument lists massaged in the same way
(treat a lone argument as the source, treat two arguments as target
then source, make sure both target and source are lists) without
having to have cut-and-paste code to do it.
As a bit of obsessive backwards compatibility, we also intercept
attempts to get or set the "env" or "builder" attributes, which were
the names we used before we put the common functionality into the
MethodWrapper base class. We'll keep this around for a while in case
people shipped Tool modules that reached into the wrapper (like the
Tool/qt.py module does, or did). There shouldn't be a lot attribute
fetching or setting on these, so a little extra work shouldn't hurt.
"""
def __call__(self, target=None, source=_null, *args, **kw): def __call__(self, target=None, source=_null, *args, **kw):
if source is _null: if source is _null:
source = target source = target
@ -187,7 +211,29 @@ class BuilderWrapper:
target = [target] target = [target]
if not source is None and not SCons.Util.is_List(source): if not source is None and not SCons.Util.is_List(source):
source = [source] source = [source]
return apply(self.builder, (self.env, target, source) + args, kw) return apply(MethodWrapper.__call__, (self, target, source) + args, kw)
def __repr__(self):
return '<BuilderWrapper %s>' % repr(self.name)
def __str__(self):
return self.__repr__()
def __getattr__(self, name):
if name == 'env':
return self.object
elif name == 'builder':
return self.method
else:
return self.__dict__[name]
def __setattr__(self, name, value):
if name == 'env':
self.object = value
elif name == 'builder':
self.method = value
else:
self.__dict__[name] = value
# This allows a Builder to be executed directly # This allows a Builder to be executed directly
# through the Environment to which it's attached. # through the Environment to which it's attached.
@ -196,9 +242,9 @@ class BuilderWrapper:
# But we do have a unit test for this, and can't # But we do have a unit test for this, and can't
# yet rule out that it would be useful in the # yet rule out that it would be useful in the
# future, so leave it for now. # future, so leave it for now.
def execute(self, **kw): #def execute(self, **kw):
kw['env'] = self.env # kw['env'] = self.env
apply(self.builder.execute, (), kw) # apply(self.builder.execute, (), kw)
class BuilderDict(UserDict): class BuilderDict(UserDict):
"""This is a dictionary-like class used by an Environment to hold """This is a dictionary-like class used by an Environment to hold
@ -212,28 +258,18 @@ class BuilderDict(UserDict):
self.env = env self.env = env
UserDict.__init__(self, dict) UserDict.__init__(self, dict)
def __semi_deepcopy__(self):
return self.__class__(self.data, self.env)
def __setitem__(self, item, val): def __setitem__(self, item, val):
UserDict.__setitem__(self, item, val)
try: try:
self.setenvattr(item, val) method = getattr(self.env, item).method
except AttributeError: except AttributeError:
# Have to catch this because sometimes __setitem__ gets
# called out of __init__, when we don't have an env
# attribute yet, nor do we want one!
pass pass
else:
def setenvattr(self, item, val): self.env.RemoveMethod(method)
"""Set the corresponding environment attribute for this Builder. UserDict.__setitem__(self, item, val)
BuilderWrapper(self.env, val, item)
If the value is already a BuilderWrapper, we pull the builder
out of it and make another one, so that making a copy of an
existing BuilderDict is guaranteed separate wrappers for each
Builder + Environment pair."""
try:
builder = val.builder
except AttributeError:
builder = val
setattr(self.env, item, BuilderWrapper(self.env, builder))
def __delitem__(self, item): def __delitem__(self, item):
UserDict.__delitem__(self, item) UserDict.__delitem__(self, item)
@ -276,11 +312,12 @@ class SubstitutionEnvironment:
"""Initialization of an underlying SubstitutionEnvironment class. """Initialization of an underlying SubstitutionEnvironment class.
""" """
if __debug__: logInstanceCreation(self, 'Environment.SubstitutionEnvironment') if __debug__: logInstanceCreation(self, 'Environment.SubstitutionEnvironment')
self.fs = SCons.Node.FS.default_fs or SCons.Node.FS.FS() self.fs = SCons.Node.FS.get_default_fs()
self.ans = SCons.Node.Alias.default_ans self.ans = SCons.Node.Alias.default_ans
self.lookup_list = SCons.Node.arg2nodes_lookups self.lookup_list = SCons.Node.arg2nodes_lookups
self._dict = kw.copy() self._dict = kw.copy()
self._init_special() self._init_special()
self.added_methods = []
#self._memo = {} #self._memo = {}
def _init_special(self): def _init_special(self):
@ -327,7 +364,7 @@ class SubstitutionEnvironment:
def items(self): def items(self):
return self._dict.items() return self._dict.items()
def arg2nodes(self, args, node_factory=_null, lookup_list=_null): def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
if node_factory is _null: if node_factory is _null:
node_factory = self.fs.File node_factory = self.fs.File
if lookup_list is _null: if lookup_list is _null:
@ -351,7 +388,9 @@ class SubstitutionEnvironment:
break break
if not n is None: if not n is None:
if SCons.Util.is_String(n): if SCons.Util.is_String(n):
n = self.subst(n, raw=1) # n = self.subst(n, raw=1, **kw)
kw['raw'] = 1
n = apply(self.subst, (n,), kw)
if node_factory: if node_factory:
n = node_factory(n) n = node_factory(n)
if SCons.Util.is_List(n): if SCons.Util.is_List(n):
@ -359,14 +398,16 @@ class SubstitutionEnvironment:
else: else:
nodes.append(n) nodes.append(n)
elif node_factory: elif node_factory:
v = node_factory(self.subst(v, raw=1)) # v = node_factory(self.subst(v, raw=1, **kw))
kw['raw'] = 1
v = node_factory(apply(self.subst, (v,), kw))
if SCons.Util.is_List(v): if SCons.Util.is_List(v):
nodes.extend(v) nodes.extend(v)
else: else:
nodes.append(v) nodes.append(v)
else: else:
nodes.append(v) nodes.append(v)
return nodes return nodes
def gvars(self): def gvars(self):
@ -473,6 +514,23 @@ class SubstitutionEnvironment:
raise OSError("'%s' exited %d" % (command, status)) raise OSError("'%s' exited %d" % (command, status))
return out return out
def AddMethod(self, function, name=None):
"""
Adds the specified function as a method of this construction
environment with the specified name. If the name is omitted,
the default name is the name of the function itself.
"""
method = MethodWrapper(self, function, name)
self.added_methods.append(method)
def RemoveMethod(self, function):
"""
Removes the specified function's MethodWrapper from the
added_methods list, so we don't re-bind it when making a clone.
"""
is_not_func = lambda dm, f=function: not dm.method is f
self.added_methods = filter(is_not_func, self.added_methods)
def Override(self, overrides): def Override(self, overrides):
""" """
Produce a modified environment whose variables are overriden by Produce a modified environment whose variables are overriden by
@ -564,7 +622,7 @@ class SubstitutionEnvironment:
# -R dir (deprecated linker rpath) # -R dir (deprecated linker rpath)
# IBM compilers may also accept -qframeworkdir=foo # IBM compilers may also accept -qframeworkdir=foo
params = string.split(arg) params = shlex.split(arg)
append_next_arg_to = None # for multi-word args append_next_arg_to = None # for multi-word args
for arg in params: for arg in params:
if append_next_arg_to: if append_next_arg_to:
@ -705,6 +763,29 @@ class SubstitutionEnvironment:
self[key] = t self[key] = t
return self return self
# Used by the FindSourceFiles() method, below.
# Stuck here for support of pre-2.2 Python versions.
def build_source(ss, result):
for s in ss:
if isinstance(s, SCons.Node.FS.Dir):
build_source(s.all_children(), result)
elif s.has_builder():
build_source(s.sources, result)
elif isinstance(s.disambiguate(), SCons.Node.FS.File):
result.append(s)
def default_decide_source(dependency, target, prev_ni):
f = SCons.Defaults.DefaultEnvironment().decide_source
return f(dependency, target, prev_ni)
def default_decide_target(dependency, target, prev_ni):
f = SCons.Defaults.DefaultEnvironment().decide_target
return f(dependency, target, prev_ni)
def default_copy_from_cache(src, dst):
f = SCons.Defaults.DefaultEnvironment().copy_from_cache
return f(src, dst)
class Base(SubstitutionEnvironment): class Base(SubstitutionEnvironment):
"""Base class for "real" construction Environments. These are the """Base class for "real" construction Environments. These are the
primary objects used to communicate dependency and construction primary objects used to communicate dependency and construction
@ -752,11 +833,23 @@ class Base(SubstitutionEnvironment):
""" """
if __debug__: logInstanceCreation(self, 'Environment.Base') if __debug__: logInstanceCreation(self, 'Environment.Base')
self._memo = {} self._memo = {}
self.fs = SCons.Node.FS.default_fs or SCons.Node.FS.FS() self.fs = SCons.Node.FS.get_default_fs()
self.ans = SCons.Node.Alias.default_ans self.ans = SCons.Node.Alias.default_ans
self.lookup_list = SCons.Node.arg2nodes_lookups self.lookup_list = SCons.Node.arg2nodes_lookups
self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment) self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
self._init_special() self._init_special()
self.added_methods = []
# We don't use AddMethod, or define these as methods in this
# class, because we *don't* want these functions to be bound
# methods. They need to operate independently so that the
# settings will work properly regardless of whether a given
# target ends up being built with a Base environment or an
# OverrideEnvironment or what have you.
self.decide_target = default_decide_target
self.decide_source = default_decide_source
self.copy_from_cache = default_copy_from_cache
self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
@ -787,6 +880,8 @@ class Base(SubstitutionEnvironment):
# reserved variable name like TARGETS. # reserved variable name like TARGETS.
pass pass
SCons.Tool.Initializers(self)
if tools is None: if tools is None:
tools = self._dict.get('TOOLS', None) tools = self._dict.get('TOOLS', None)
if tools is None: if tools is None:
@ -812,16 +907,13 @@ class Base(SubstitutionEnvironment):
except KeyError: except KeyError:
return None return None
def get_calculator(self): def get_CacheDir(self):
try: try:
module = self._calc_module return self._CacheDir
c = apply(SCons.Sig.Calculator, (module,), CalculatorArgs)
except AttributeError: except AttributeError:
# Note that we're calling get_calculator() here, so the cd = SCons.Defaults.DefaultEnvironment()._CacheDir
# DefaultEnvironment() must have a _calc_module attribute self._CacheDir = cd
# to avoid infinite recursion. return cd
c = SCons.Defaults.DefaultEnvironment().get_calculator()
return c
def get_factory(self, factory, default='File'): def get_factory(self, factory, default='File'):
"""Return a factory function for creating Nodes for this """Return a factory function for creating Nodes for this
@ -883,7 +975,7 @@ class Base(SubstitutionEnvironment):
self._memo['_gsm'] = result self._memo['_gsm'] = result
return result return result
def get_scanner(self, skey): def get_scanner(self, skey):
"""Find the appropriate scanner given a key (usually a file suffix). """Find the appropriate scanner given a key (usually a file suffix).
""" """
@ -903,13 +995,21 @@ class Base(SubstitutionEnvironment):
""" """
self._dict.update(dict) self._dict.update(dict)
def use_build_signature(self): def get_src_sig_type(self):
try: try:
return self._build_signature return self.src_sig_type
except AttributeError: except AttributeError:
b = SCons.Defaults.DefaultEnvironment()._build_signature t = SCons.Defaults.DefaultEnvironment().src_sig_type
self._build_signature = b self.src_sig_type = t
return b return t
def get_tgt_sig_type(self):
try:
return self.tgt_sig_type
except AttributeError:
t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
self.tgt_sig_type = t
return t
####################################################################### #######################################################################
# Public methods for manipulating an Environment. These begin with # Public methods for manipulating an Environment. These begin with
@ -978,7 +1078,11 @@ class Base(SubstitutionEnvironment):
try: try:
update_dict(val) update_dict(val)
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
orig[val] = None if SCons.Util.is_Dict(val):
for k, v in val.items():
orig[k] = v
else:
orig[val] = None
self.scanner_map_delete(kw) self.scanner_map_delete(kw)
def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
@ -994,7 +1098,7 @@ class Base(SubstitutionEnvironment):
orig = self._dict[envname][name] orig = self._dict[envname][name]
nv = SCons.Util.AppendPath(orig, newpath, sep) nv = SCons.Util.AppendPath(orig, newpath, sep)
if not self._dict.has_key(envname): if not self._dict.has_key(envname):
self._dict[envname] = {} self._dict[envname] = {}
@ -1037,29 +1141,95 @@ class Base(SubstitutionEnvironment):
objects in the original Environment. objects in the original Environment.
""" """
clone = copy.copy(self) clone = copy.copy(self)
clone._dict = our_deepcopy(self._dict) clone._dict = semi_deepcopy(self._dict)
try: try:
cbd = clone._dict['BUILDERS'] cbd = clone._dict['BUILDERS']
clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
except KeyError: except KeyError:
pass pass
else:
clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
clone.added_methods = []
for mw in self.added_methods:
clone.added_methods.append(mw.clone(clone))
clone._memo = {} clone._memo = {}
apply_tools(clone, tools, toolpath) # Apply passed-in variables before the tools
# so the tools can use the new variables
# Apply passed-in variables after the new tools.
kw = copy_non_reserved_keywords(kw) kw = copy_non_reserved_keywords(kw)
new = {} new = {}
for key, value in kw.items(): for key, value in kw.items():
new[key] = SCons.Subst.scons_subst_once(value, self, key) new[key] = SCons.Subst.scons_subst_once(value, self, key)
apply(clone.Replace, (), new) apply(clone.Replace, (), new)
apply_tools(clone, tools, toolpath)
# apply them again in case the tools overwrote them
apply(clone.Replace, (), new)
if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone') if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone')
return clone return clone
def Copy(self, *args, **kw): def Copy(self, *args, **kw):
return apply(self.Clone, args, kw) return apply(self.Clone, args, kw)
def _changed_build(self, dependency, target, prev_ni):
if dependency.changed_state(target, prev_ni):
return 1
return self.decide_source(dependency, target, prev_ni)
def _changed_content(self, dependency, target, prev_ni):
return dependency.changed_content(target, prev_ni)
def _changed_source(self, dependency, target, prev_ni):
target_env = dependency.get_build_env()
type = target_env.get_tgt_sig_type()
if type == 'source':
return target_env.decide_source(dependency, target, prev_ni)
else:
return target_env.decide_target(dependency, target, prev_ni)
def _changed_timestamp_then_content(self, dependency, target, prev_ni):
return dependency.changed_timestamp_then_content(target, prev_ni)
def _changed_timestamp_newer(self, dependency, target, prev_ni):
return dependency.changed_timestamp_newer(target, prev_ni)
def _changed_timestamp_match(self, dependency, target, prev_ni):
return dependency.changed_timestamp_match(target, prev_ni)
def _copy_from_cache(self, src, dst):
return self.fs.copy(src, dst)
def _copy2_from_cache(self, src, dst):
return self.fs.copy2(src, dst)
def Decider(self, function):
copy_function = self._copy2_from_cache
if function in ('MD5', 'content'):
if not SCons.Util.md5:
raise UserError, "MD5 signatures are not available in this version of Python."
function = self._changed_content
elif function == 'MD5-timestamp':
function = self._changed_timestamp_then_content
elif function in ('timestamp-newer', 'make'):
function = self._changed_timestamp_newer
copy_function = self._copy_from_cache
elif function == 'timestamp-match':
function = self._changed_timestamp_match
elif not callable(function):
raise UserError, "Unknown Decider value %s" % repr(function)
# We don't use AddMethod because we don't want to turn the
# function, which only expects three arguments, into a bound
# method, which would add self as an initial, fourth argument.
self.decide_target = function
self.decide_source = function
self.copy_from_cache = copy_function
def Detect(self, progs): def Detect(self, progs):
"""Return the first available program in progs. """Return the first available program in progs.
""" """
@ -1110,7 +1280,7 @@ class Base(SubstitutionEnvironment):
for path in paths: for path in paths:
dir,name = os.path.split(str(path)) dir,name = os.path.split(str(path))
if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
return path return path
def ParseConfig(self, command, function=None, unique=1): def ParseConfig(self, command, function=None, unique=1):
@ -1233,7 +1403,11 @@ class Base(SubstitutionEnvironment):
try: try:
update_dict(val) update_dict(val)
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
orig[val] = None if SCons.Util.is_Dict(val):
for k, v in val.items():
orig[k] = v
else:
orig[val] = None
self.scanner_map_delete(kw) self.scanner_map_delete(kw)
def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
@ -1249,7 +1423,7 @@ class Base(SubstitutionEnvironment):
orig = self._dict[envname][name] orig = self._dict[envname][name]
nv = SCons.Util.PrependPath(orig, newpath, sep) nv = SCons.Util.PrependPath(orig, newpath, sep)
if not self._dict.has_key(envname): if not self._dict.has_key(envname):
self._dict[envname] = {} self._dict[envname] = {}
@ -1288,13 +1462,15 @@ class Base(SubstitutionEnvironment):
with new construction variables and/or values. with new construction variables and/or values.
""" """
try: try:
kwbd = our_deepcopy(kw['BUILDERS']) kwbd = kw['BUILDERS']
del kw['BUILDERS']
self.__setitem__('BUILDERS', kwbd)
except KeyError: except KeyError:
pass pass
else:
kwbd = semi_deepcopy(kwbd)
del kw['BUILDERS']
self.__setitem__('BUILDERS', kwbd)
kw = copy_non_reserved_keywords(kw) kw = copy_non_reserved_keywords(kw)
self._update(our_deepcopy(kw)) self._update(semi_deepcopy(kw))
self.scanner_map_delete(kw) self.scanner_map_delete(kw)
def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
@ -1453,7 +1629,7 @@ class Base(SubstitutionEnvironment):
def AlwaysBuild(self, *targets): def AlwaysBuild(self, *targets):
tlist = [] tlist = []
for t in targets: for t in targets:
tlist.extend(self.arg2nodes(t, self.fs.File)) tlist.extend(self.arg2nodes(t, self.fs.Entry))
for t in tlist: for t in tlist:
t.set_always_build() t.set_always_build()
return tlist return tlist
@ -1468,7 +1644,11 @@ class Base(SubstitutionEnvironment):
return apply(SCons.Builder.Builder, [], nkw) return apply(SCons.Builder.Builder, [], nkw)
def CacheDir(self, path): def CacheDir(self, path):
self.fs.CacheDir(self.subst(path)) import SCons.CacheDir
if path is None:
self._CacheDir = SCons.CacheDir.Null()
else:
self._CacheDir = SCons.CacheDir.CacheDir(self.subst(path))
def Clean(self, targets, files): def Clean(self, targets, files):
global CleanTargets global CleanTargets
@ -1551,7 +1731,11 @@ class Base(SubstitutionEnvironment):
"""Directly execute an action through an Environment """Directly execute an action through an Environment
""" """
action = apply(self.Action, (action,) + args, kw) action = apply(self.Action, (action,) + args, kw)
return action([], [], self) result = action([], [], self)
if isinstance(result, SCons.Errors.BuildError):
return result.status
else:
return result
def File(self, name, *args, **kw): def File(self, name, *args, **kw):
""" """
@ -1573,6 +1757,9 @@ class Base(SubstitutionEnvironment):
else: else:
return result[0] return result[0]
def Glob(self, pattern, ondisk=True, source=False, strings=False):
return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
def Ignore(self, target, dependency): def Ignore(self, target, dependency):
"""Ignore a dependency.""" """Ignore a dependency."""
tlist = self.arg2nodes(target, self.fs.Entry) tlist = self.arg2nodes(target, self.fs.Entry)
@ -1581,50 +1768,6 @@ class Base(SubstitutionEnvironment):
t.add_ignore(dlist) t.add_ignore(dlist)
return tlist return tlist
def Install(self, dir, source):
"""Install specified files in the given directory."""
try:
dnodes = self.arg2nodes(dir, self.fs.Dir)
except TypeError:
fmt = "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?"
raise SCons.Errors.UserError, fmt % str(dir)
try:
sources = self.arg2nodes(source, self.fs.Entry)
except TypeError:
if SCons.Util.is_List(source):
s = repr(map(str, source))
else:
s = str(source)
fmt = "Source `%s' of Install() is neither a file nor a directory. Install() source must be one or more files or directories"
raise SCons.Errors.UserError, fmt % s
tgt = []
for dnode in dnodes:
for src in sources:
# Prepend './' so the lookup doesn't interpret an initial
# '#' on the file name portion as meaning the Node should
# be relative to the top-level SConstruct directory.
target = self.fs.Entry('.'+os.sep+src.name, dnode)
tgt.extend(InstallBuilder(self, target, src))
return tgt
def InstallAs(self, target, source):
"""Install sources as targets."""
sources = self.arg2nodes(source, self.fs.Entry)
targets = self.arg2nodes(target, self.fs.Entry)
if len(sources) != len(targets):
if not SCons.Util.is_List(target):
target = [target]
if not SCons.Util.is_List(source):
source = [source]
t = repr(map(str, target))
s = repr(map(str, source))
fmt = "Target (%s) and source (%s) lists of InstallAs() must be the same length."
raise SCons.Errors.UserError, fmt % (t, s)
result = []
for src, tgt in map(lambda x, y: (x, y), sources, targets):
result.extend(InstallBuilder(self, tgt, src))
return result
def Literal(self, string): def Literal(self, string):
return SCons.Subst.Literal(string) return SCons.Subst.Literal(string)
@ -1652,6 +1795,16 @@ class Base(SubstitutionEnvironment):
dirs = self.arg2nodes(list(dirs), self.fs.Dir) dirs = self.arg2nodes(list(dirs), self.fs.Dir)
apply(self.fs.Repository, dirs, kw) apply(self.fs.Repository, dirs, kw)
def Requires(self, target, prerequisite):
"""Specify that 'prerequisite' must be built before 'target',
(but 'target' does not actually depend on 'prerequisite'
and need not be rebuilt if it changes)."""
tlist = self.arg2nodes(target, self.fs.Entry)
plist = self.arg2nodes(prerequisite, self.fs.Entry)
for t in tlist:
t.add_prerequisite(plist)
return tlist
def Scanner(self, *args, **kw): def Scanner(self, *args, **kw):
nargs = [] nargs = []
for arg in args: for arg in args:
@ -1669,7 +1822,7 @@ class Base(SubstitutionEnvironment):
SCons.SConsign.File(name, dbm_module) SCons.SConsign.File(name, dbm_module)
def SideEffect(self, side_effect, target): def SideEffect(self, side_effect, target):
"""Tell scons that side_effects are built as side """Tell scons that side_effects are built as side
effects of building targets.""" effects of building targets."""
side_effects = self.arg2nodes(side_effect, self.fs.Entry) side_effects = self.arg2nodes(side_effect, self.fs.Entry)
targets = self.arg2nodes(target, self.fs.Entry) targets = self.arg2nodes(target, self.fs.Entry)
@ -1693,21 +1846,15 @@ class Base(SubstitutionEnvironment):
def SourceSignatures(self, type): def SourceSignatures(self, type):
type = self.subst(type) type = self.subst(type)
self.src_sig_type = type
if type == 'MD5': if type == 'MD5':
try: if not SCons.Util.md5:
import SCons.Sig.MD5 raise UserError, "MD5 signatures are not available in this version of Python."
except ImportError: self.decide_source = self._changed_content
msg = "No MD5 module available, using time stamps"
SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
import SCons.Sig.TimeStamp
self._calc_module = SCons.Sig.TimeStamp
else:
self._calc_module = SCons.Sig.MD5
elif type == 'timestamp': elif type == 'timestamp':
import SCons.Sig.TimeStamp self.decide_source = self._changed_timestamp_match
self._calc_module = SCons.Sig.TimeStamp
else: else:
raise UserError, "Unknown source signature type '%s'"%type raise UserError, "Unknown source signature type '%s'" % type
def Split(self, arg): def Split(self, arg):
"""This function converts a string or list into a list of strings """This function converts a string or list into a list of strings
@ -1729,18 +1876,66 @@ class Base(SubstitutionEnvironment):
def TargetSignatures(self, type): def TargetSignatures(self, type):
type = self.subst(type) type = self.subst(type)
if type == 'build': self.tgt_sig_type = type
self._build_signature = 1 if type in ('MD5', 'content'):
elif type == 'content': if not SCons.Util.md5:
self._build_signature = 0 raise UserError, "MD5 signatures are not available in this version of Python."
self.decide_target = self._changed_content
elif type == 'timestamp':
self.decide_target = self._changed_timestamp_match
elif type == 'build':
self.decide_target = self._changed_build
elif type == 'source':
self.decide_target = self._changed_source
else: else:
raise SCons.Errors.UserError, "Unknown target signature type '%s'"%type raise UserError, "Unknown target signature type '%s'"%type
def Value(self, value, built_value=None): def Value(self, value, built_value=None):
""" """
""" """
return SCons.Node.Python.Value(value, built_value) return SCons.Node.Python.Value(value, built_value)
def FindSourceFiles(self, node='.'):
""" returns a list of all source files.
"""
node = self.arg2nodes(node, self.fs.Entry)[0]
sources = []
# Uncomment this and get rid of the global definition when we
# drop support for pre-2.2 Python versions.
#def build_source(ss, result):
# for s in ss:
# if isinstance(s, SCons.Node.FS.Dir):
# build_source(s.all_children(), result)
# elif s.has_builder():
# build_source(s.sources, result)
# elif isinstance(s.disambiguate(), SCons.Node.FS.File):
# result.append(s)
build_source(node.all_children(), sources)
# now strip the build_node from the sources by calling the srcnode
# function
def get_final_srcnode(file):
srcnode = file.srcnode()
while srcnode != file.srcnode():
srcnode = file.srcnode()
return srcnode
# get the final srcnode for all nodes, this means stripping any
# attached build node.
map( get_final_srcnode, sources )
# remove duplicates
return list(set(sources))
def FindInstalledFiles(self):
""" returns the list of all targets of the Install and InstallAs Builder.
"""
from SCons.Tool import install
if install._UNIQUE_INSTALLED_FILES is None:
install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
return install._UNIQUE_INSTALLED_FILES
class OverrideEnvironment(Base): class OverrideEnvironment(Base):
"""A proxy that overrides variables in a wrapped construction """A proxy that overrides variables in a wrapped construction
environment by returning values from an overrides dictionary in environment by returning values from an overrides dictionary in
@ -1839,7 +2034,7 @@ class OverrideEnvironment(Base):
# Overridden public construction environment methods. # Overridden public construction environment methods.
def Replace(self, **kw): def Replace(self, **kw):
kw = copy_non_reserved_keywords(kw) kw = copy_non_reserved_keywords(kw)
self.__dict__['overrides'].update(our_deepcopy(kw)) self.__dict__['overrides'].update(semi_deepcopy(kw))
# The entry point that will be used by the external world # The entry point that will be used by the external world
# to refer to a construction environment. This allows the wrapper # to refer to a construction environment. This allows the wrapper

View file

@ -28,15 +28,21 @@ and user errors in SCons.
""" """
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Errors.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Errors.py 2523 2007/12/12 09:37:41 knight"
class BuildError(Exception): class BuildError(Exception):
def __init__(self, node=None, errstr="Unknown error", filename=None, *args): def __init__(self, node=None, errstr="Unknown error", status=0,
filename=None, executor=None, action=None, command=None,
*args):
self.node = node self.node = node
self.errstr = errstr self.errstr = errstr
self.status = status
self.filename = filename self.filename = filename
self.executor = executor
self.action = action
self.command = command
apply(Exception.__init__, (self,) + args) apply(Exception.__init__, (self,) + args)
class InternalError(Exception): class InternalError(Exception):
@ -48,6 +54,9 @@ class UserError(Exception):
class StopError(Exception): class StopError(Exception):
pass pass
class EnvironmentError(Exception):
pass
class ExplicitExit(Exception): class ExplicitExit(Exception):
def __init__(self, node=None, status=None, *args): def __init__(self, node=None, status=None, *args):
self.node = node self.node = node

View file

@ -28,11 +28,12 @@ Nodes.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Executor.py 2523 2007/12/12 09:37:41 knight"
import string import string
from SCons.Debug import logInstanceCreation from SCons.Debug import logInstanceCreation
import SCons.Errors
import SCons.Memoize import SCons.Memoize
@ -59,6 +60,7 @@ class Executor:
self.overridelist = overridelist self.overridelist = overridelist
self.targets = targets self.targets = targets
self.sources = sources[:] self.sources = sources[:]
self.sources_need_sorting = False
self.builder_kw = builder_kw self.builder_kw = builder_kw
self._memo = {} self._memo = {}
@ -74,10 +76,17 @@ class Executor:
def get_action_list(self): def get_action_list(self):
return self.pre_actions + self.action_list + self.post_actions return self.pre_actions + self.action_list + self.post_actions
memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
def get_build_env(self): def get_build_env(self):
"""Fetch or create the appropriate build Environment """Fetch or create the appropriate build Environment
for this Executor. for this Executor.
""" """
try:
return self._memo['get_build_env']
except KeyError:
pass
# Create the build environment instance with appropriate # Create the build environment instance with appropriate
# overrides. These get evaluated against the current # overrides. These get evaluated against the current
# environment's construction variables so that users can # environment's construction variables so that users can
@ -91,42 +100,49 @@ class Executor:
env = self.env or SCons.Defaults.DefaultEnvironment() env = self.env or SCons.Defaults.DefaultEnvironment()
build_env = env.Override(overrides) build_env = env.Override(overrides)
self._memo['get_build_env'] = build_env
return build_env return build_env
def get_build_scanner_path(self, scanner): def get_build_scanner_path(self, scanner):
"""Fetch the scanner path for this executor's targets """Fetch the scanner path for this executor's targets and sources.
and sources.
""" """
env = self.get_build_env() env = self.get_build_env()
try: try:
cwd = self.targets[0].cwd cwd = self.targets[0].cwd
except (IndexError, AttributeError): except (IndexError, AttributeError):
cwd = None cwd = None
return scanner.path(env, cwd, self.targets, self.sources) return scanner.path(env, cwd, self.targets, self.get_sources())
def get_kw(self, kw={}): def get_kw(self, kw={}):
result = self.builder_kw.copy() result = self.builder_kw.copy()
result.update(kw) result.update(kw)
return result return result
def do_nothing(self, target, exitstatfunc, kw): def do_nothing(self, target, kw):
pass return 0
def do_execute(self, target, exitstatfunc, kw): def do_execute(self, target, kw):
"""Actually execute the action list.""" """Actually execute the action list."""
env = self.get_build_env() env = self.get_build_env()
kw = self.get_kw(kw) kw = self.get_kw(kw)
status = 0
for act in self.get_action_list(): for act in self.get_action_list():
apply(act, status = apply(act, (self.targets, self.get_sources(), env), kw)
(self.targets, self.sources, env, exitstatfunc), if isinstance(status, SCons.Errors.BuildError):
kw) status.executor = self
raise status
elif status:
msg = "Error %s" % status
raise SCons.Errors.BuildError(errstr=msg, executor=self, action=act)
return status
# use extra indirection because with new-style objects (Python 2.2 # use extra indirection because with new-style objects (Python 2.2
# and above) we can't override special methods, and nullify() needs # and above) we can't override special methods, and nullify() needs
# to be able to do this. # to be able to do this.
def __call__(self, target, exitstatfunc, **kw): def __call__(self, target, **kw):
self.do_execute(target, exitstatfunc, kw) return self.do_execute(target, kw)
def cleanup(self): def cleanup(self):
self._memo = {} self._memo = {}
@ -135,8 +151,14 @@ class Executor:
"""Add source files to this Executor's list. This is necessary """Add source files to this Executor's list. This is necessary
for "multi" Builders that can be called repeatedly to build up for "multi" Builders that can be called repeatedly to build up
a source file list for a given target.""" a source file list for a given target."""
slist = filter(lambda x, s=self.sources: x not in s, sources) self.sources.extend(sources)
self.sources.extend(slist) self.sources_need_sorting = True
def get_sources(self):
if self.sources_need_sorting:
self.sources = SCons.Util.uniquer_hashables(self.sources)
self.sources_need_sorting = False
return self.sources
def add_pre_action(self, action): def add_pre_action(self, action):
self.pre_actions.append(action) self.pre_actions.append(action)
@ -148,7 +170,7 @@ class Executor:
def my_str(self): def my_str(self):
env = self.get_build_env() env = self.get_build_env()
get = lambda action, t=self.targets, s=self.sources, e=env: \ get = lambda action, t=self.targets, s=self.get_sources(), e=env: \
action.genstring(t, s, e) action.genstring(t, s, e)
return string.join(map(get, self.get_action_list()), "\n") return string.join(map(get, self.get_action_list()), "\n")
@ -173,7 +195,7 @@ class Executor:
except KeyError: except KeyError:
pass pass
env = self.get_build_env() env = self.get_build_env()
get = lambda action, t=self.targets, s=self.sources, e=env: \ get = lambda action, t=self.targets, s=self.get_sources(), e=env: \
action.get_contents(t, s, e) action.get_contents(t, s, e)
result = string.join(map(get, self.get_action_list()), "") result = string.join(map(get, self.get_action_list()), "")
self._memo['get_contents'] = result self._memo['get_contents'] = result
@ -191,7 +213,7 @@ class Executor:
def scan_sources(self, scanner): def scan_sources(self, scanner):
if self.sources: if self.sources:
self.scan(scanner, self.sources) self.scan(scanner, self.get_sources())
def scan(self, scanner, node_list): def scan(self, scanner, node_list):
"""Scan a list of this Executor's files (targets or sources) for """Scan a list of this Executor's files (targets or sources) for
@ -218,17 +240,20 @@ class Executor:
scanner_list = map(select_specific_scanner, scanner_list) scanner_list = map(select_specific_scanner, scanner_list)
scanner_list = filter(remove_null_scanners, scanner_list) scanner_list = filter(remove_null_scanners, scanner_list)
scanner_path_list = map(add_scanner_path, scanner_list) scanner_path_list = map(add_scanner_path, scanner_list)
deps = [] deps = []
for node, scanner, path in scanner_path_list: for node, scanner, path in scanner_path_list:
deps.extend(node.get_implicit_deps(env, scanner, path)) deps.extend(node.get_implicit_deps(env, scanner, path))
deps.extend(self.get_implicit_deps())
for tgt in self.targets: for tgt in self.targets:
tgt.add_to_implicit(deps) tgt.add_to_implicit(deps)
def get_missing_sources(self): def get_missing_sources(self):
""" """
""" """
return filter(lambda s: s.missing(), self.sources) return filter(lambda s: s.missing(), self.get_sources())
def _get_unignored_sources_key(self, ignore=()): def _get_unignored_sources_key(self, ignore=()):
return tuple(ignore) return tuple(ignore)
@ -248,9 +273,12 @@ class Executor:
except KeyError: except KeyError:
pass pass
sourcelist = self.sources sourcelist = self.get_sources()
if ignore: if ignore:
sourcelist = filter(lambda s, i=ignore: not s in i, sourcelist) idict = {}
for i in ignore:
idict[i] = 1
sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist)
memo_dict[ignore] = sourcelist memo_dict[ignore] = sourcelist
@ -280,6 +308,15 @@ class Executor:
return result return result
def get_implicit_deps(self):
"""Return the executor's implicit dependencies, i.e. the nodes of
the commands to be executed."""
result = []
build_env = self.get_build_env()
for act in self.get_action_list():
result.extend(act.get_implicit_deps(self.targets, self.get_sources(), build_env))
return result
_Executor = Executor _Executor = Executor
@ -296,9 +333,15 @@ class Null(_Executor):
kw['action'] = [] kw['action'] = []
apply(_Executor.__init__, (self,), kw) apply(_Executor.__init__, (self,), kw)
def get_build_env(self): def get_build_env(self):
class NullEnvironment: import SCons.Util
def get_scanner(self, key): class NullEnvironment(SCons.Util.Null):
return None #def get_scanner(self, key):
# return None
#def changed_since_last_build(self, dependency, target, prev_ni):
# return dependency.changed_since_last_buld(target, prev_ni)
def get_CacheDir(self):
import SCons.CacheDir
return SCons.CacheDir.Null()
return NullEnvironment() return NullEnvironment()
def get_build_scanner_path(self): def get_build_scanner_path(self):
return None return None

View file

@ -29,7 +29,7 @@ stop, and wait on jobs.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Job.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat import SCons.compat
@ -76,6 +76,9 @@ class Jobs:
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
raise raise
def cleanup(self):
self.job.cleanup()
class Serial: class Serial:
"""This class is used to execute tasks in series, and is more efficient """This class is used to execute tasks in series, and is more efficient
than Parallel, but is only appropriate for non-parallel builds. Only than Parallel, but is only appropriate for non-parallel builds. Only
@ -122,6 +125,8 @@ class Serial:
task.postprocess() task.postprocess()
def cleanup(self):
pass
# Trap import failure so that everything in the Job module but the # Trap import failure so that everything in the Job module but the
# Parallel class (and its dependent classes) will work if the interpreter # Parallel class (and its dependent classes) will work if the interpreter
@ -148,6 +153,12 @@ else:
while 1: while 1:
task = self.requestQueue.get() task = self.requestQueue.get()
if not task:
# The "None" value is used as a sentinel by
# ThreadPool.cleanup(). This indicates that there
# are no more tasks, so we should quit.
break
try: try:
task.execute() task.execute()
except KeyboardInterrupt: except KeyboardInterrupt:
@ -170,8 +181,10 @@ else:
self.resultsQueue = Queue.Queue(0) self.resultsQueue = Queue.Queue(0)
# Create worker threads # Create worker threads
self.workers = []
for _ in range(num): for _ in range(num):
Worker(self.requestQueue, self.resultsQueue) worker = Worker(self.requestQueue, self.resultsQueue)
self.workers.append(worker)
def put(self, obj): def put(self, obj):
"""Put task into request queue.""" """Put task into request queue."""
@ -182,7 +195,36 @@ else:
return self.resultsQueue.get(block) return self.resultsQueue.get(block)
def preparation_failed(self, obj): def preparation_failed(self, obj):
self.resultsQueue.put((obj, 0)) self.resultsQueue.put((obj, False))
def cleanup(self):
"""
Shuts down the thread pool, giving each worker thread a
chance to shut down gracefully.
"""
# For each worker thread, put a sentinel "None" value
# on the requestQueue (indicating that there's no work
# to be done) so that each worker thread will get one and
# terminate gracefully.
for _ in self.workers:
self.requestQueue.put(None)
# Wait for all of the workers to terminate.
#
# If we don't do this, later Python versions (2.4, 2.5) often
# seem to raise exceptions during shutdown. This happens
# in requestQueue.get(), as an assertion failure that
# requestQueue.not_full is notified while not acquired,
# seemingly because the main thread has shut down (or is
# in the process of doing so) while the workers are still
# trying to pull sentinels off the requestQueue.
#
# Normally these terminations should happen fairly quickly,
# but we'll stick a one-second timeout on here just in case
# someone gets hung.
for worker in self.workers:
worker.join(1.0)
self.workers = []
class Parallel: class Parallel:
"""This class is used to execute tasks in parallel, and is somewhat """This class is used to execute tasks in parallel, and is somewhat
@ -261,3 +303,6 @@ else:
if self.tp.resultsQueue.empty(): if self.tp.resultsQueue.empty():
break break
def cleanup(self):
self.tp.cleanup()

View file

@ -21,7 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Memoize.py 2523 2007/12/12 09:37:41 knight"
__doc__ = """Memoizer __doc__ = """Memoizer

View file

@ -30,7 +30,7 @@ This creates a hash of global Aliases (dummy targets).
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Node/Alias.py 2523 2007/12/12 09:37:41 knight"
import string import string
import UserDict import UserDict
@ -57,10 +57,13 @@ class AliasNameSpace(UserDict.UserDict):
return None return None
class AliasNodeInfo(SCons.Node.NodeInfoBase): class AliasNodeInfo(SCons.Node.NodeInfoBase):
pass current_version_id = 1
field_list = ['csig']
def str_to_node(self, s):
return default_ans.Alias(s)
class AliasBuildInfo(SCons.Node.BuildInfoBase): class AliasBuildInfo(SCons.Node.BuildInfoBase):
pass current_version_id = 1
class Alias(SCons.Node.Node): class Alias(SCons.Node.Node):
@ -74,8 +77,11 @@ class Alias(SCons.Node.Node):
def __str__(self): def __str__(self):
return self.name return self.name
def make_ready(self):
self.get_csig()
really_build = SCons.Node.Node.build really_build = SCons.Node.Node.build
current = SCons.Node.Node.children_are_up_to_date is_up_to_date = SCons.Node.Node.children_are_up_to_date
def is_under(self, dir): def is_under(self, dir):
# Make Alias nodes get built regardless of # Make Alias nodes get built regardless of
@ -85,9 +91,9 @@ class Alias(SCons.Node.Node):
def get_contents(self): def get_contents(self):
"""The contents of an alias is the concatenation """The contents of an alias is the concatenation
of all the contents of its sources""" of the content signatures of all its sources."""
contents = map(lambda n: n.get_contents(), self.children()) childsigs = map(lambda n: n.get_csig(), self.children())
return string.join(contents, '') return string.join(childsigs, '')
def sconsign(self): def sconsign(self):
"""An Alias is not recorded in .sconsign files""" """An Alias is not recorded in .sconsign files"""
@ -97,6 +103,13 @@ class Alias(SCons.Node.Node):
# #
# #
def changed_since_last_build(self, target, prev_ni):
cur_csig = self.get_csig()
try:
return cur_csig != prev_ni.csig
except AttributeError:
return 1
def build(self): def build(self):
"""A "builder" for aliases.""" """A "builder" for aliases."""
pass pass
@ -107,6 +120,25 @@ class Alias(SCons.Node.Node):
self.reset_executor() self.reset_executor()
self.build = self.really_build self.build = self.really_build
def get_csig(self):
"""
Generate a node's content signature, the digested signature
of its content.
node - the node
cache - alternate node to use for the signature cache
returns - the content signature
"""
try:
return self.ninfo.csig
except AttributeError:
pass
contents = self.get_contents()
csig = SCons.Util.MD5signature(contents)
self.get_ninfo().csig = csig
return csig
default_ans = AliasNameSpace() default_ans = AliasNameSpace()
SCons.Node.arg2nodes_lookups.append(default_ans.lookup) SCons.Node.arg2nodes_lookups.append(default_ans.lookup)

View file

@ -27,15 +27,20 @@ Python nodes.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Node/Python.py 2523 2007/12/12 09:37:41 knight"
import SCons.Node import SCons.Node
class ValueNodeInfo(SCons.Node.NodeInfoBase): class ValueNodeInfo(SCons.Node.NodeInfoBase):
pass current_version_id = 1
field_list = ['csig']
def str_to_node(self, s):
return Value(s)
class ValueBuildInfo(SCons.Node.BuildInfoBase): class ValueBuildInfo(SCons.Node.BuildInfoBase):
pass current_version_id = 1
class Value(SCons.Node.Node): class Value(SCons.Node.Node):
"""A class for Python variables, typically passed on the command line """A class for Python variables, typically passed on the command line
@ -54,11 +59,14 @@ class Value(SCons.Node.Node):
def __str__(self): def __str__(self):
return repr(self.value) return repr(self.value)
def make_ready(self):
self.get_csig()
def build(self, **kw): def build(self, **kw):
if not hasattr(self, 'built_value'): if not hasattr(self, 'built_value'):
apply (SCons.Node.Node.build, (self,), kw) apply (SCons.Node.Node.build, (self,), kw)
current = SCons.Node.Node.children_are_up_to_date is_up_to_date = SCons.Node.Node.children_are_up_to_date
def is_under(self, dir): def is_under(self, dir):
# Make Value nodes get built regardless of # Make Value nodes get built regardless of
@ -88,17 +96,21 @@ class Value(SCons.Node.Node):
contents = contents + kid.get_contents() contents = contents + kid.get_contents()
return contents return contents
def changed_since_last_build(self, target, prev_ni):
cur_csig = self.get_csig()
try:
return cur_csig != prev_ni.csig
except AttributeError:
return 1
def get_csig(self, calc=None): def get_csig(self, calc=None):
"""Because we're a Python value node and don't have a real """Because we're a Python value node and don't have a real
timestamp, we get to ignore the calculator and just use the timestamp, we get to ignore the calculator and just use the
value contents.""" value contents."""
try: try:
binfo = self.binfo return self.ninfo.csig
except AttributeError: except AttributeError:
binfo = self.binfo = self.new_binfo() pass
try: contents = self.get_contents()
return binfo.ninfo.csig self.get_ninfo().csig = contents
except AttributeError: return contents
binfo.ninfo.csig = self.get_contents()
self.store_info(binfo)
return binfo.ninfo.csig

View file

@ -42,7 +42,7 @@ be able to depend on any other type of "thing."
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Node/__init__.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat import SCons.compat
@ -53,9 +53,13 @@ import UserList
from SCons.Debug import logInstanceCreation from SCons.Debug import logInstanceCreation
import SCons.Executor import SCons.Executor
import SCons.Memoize import SCons.Memoize
import SCons.SConsign
import SCons.Util import SCons.Util
from SCons.Debug import Trace
def classname(obj):
return string.split(str(obj.__class__), '.')[-1]
# Node states # Node states
# #
# These are in "priority" order, so that the maximum value for any # These are in "priority" order, so that the maximum value for any
@ -103,38 +107,53 @@ class NodeInfoBase:
Node subclasses should subclass NodeInfoBase to provide their own Node subclasses should subclass NodeInfoBase to provide their own
logic for dealing with their own Node-specific signature information. logic for dealing with their own Node-specific signature information.
""" """
current_version_id = 1
def __init__(self, node): def __init__(self, node):
"""A null initializer so that subclasses have a superclass # Create an object attribute from the class attribute so it ends up
initialization method to call for future use. # in the pickled data in the .sconsign file.
""" self._version_id = self.current_version_id
pass
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
def update(self, node): def update(self, node):
pass
def merge(self, other):
for key, val in other.__dict__.items():
self.__dict__[key] = val
def prepare_dependencies(self):
pass
def format(self):
try: try:
field_list = self.field_list field_list = self.field_list
except AttributeError: except AttributeError:
field_list = self.__dict__.keys() return
field_list.sort() for f in field_list:
try:
delattr(self, f)
except AttributeError:
pass
try:
func = getattr(node, 'get_' + f)
except AttributeError:
pass
else:
setattr(self, f, func())
def convert(self, node, val):
pass
def merge(self, other):
self.__dict__.update(other.__dict__)
def format(self, field_list=None, names=0):
if field_list is None:
try:
field_list = self.field_list
except AttributeError:
field_list = self.__dict__.keys()
field_list.sort()
fields = [] fields = []
for field in field_list: for field in field_list:
try: try:
f = getattr(self, field) f = getattr(self, field)
except AttributeError: except AttributeError:
f = None f = None
fields.append(str(f)) f = str(f)
return string.join(fields, " ") if names:
f = field + ': ' + f
fields.append(f)
return fields
class BuildInfoBase: class BuildInfoBase:
""" """
The generic base clasee for build information for a Node. The generic base class for build information for a Node.
This is what gets stored in a .sconsign file for each target file. This is what gets stored in a .sconsign file for each target file.
It contains a NodeInfo instance for this node (signature information It contains a NodeInfo instance for this node (signature information
@ -142,22 +161,17 @@ class BuildInfoBase:
generic build stuff we have to track: sources, explicit dependencies, generic build stuff we have to track: sources, explicit dependencies,
implicit dependencies, and action information. implicit dependencies, and action information.
""" """
current_version_id = 1
def __init__(self, node): def __init__(self, node):
self.ninfo = node.NodeInfo(node) # Create an object attribute from the class attribute so it ends up
# in the pickled data in the .sconsign file.
self._version_id = self.current_version_id
self.bsourcesigs = [] self.bsourcesigs = []
self.bdependsigs = [] self.bdependsigs = []
self.bimplicitsigs = [] self.bimplicitsigs = []
self.bactsig = None self.bactsig = None
def __cmp__(self, other):
return cmp(self.ninfo, other.ninfo)
def merge(self, other): def merge(self, other):
for key, val in other.__dict__.items(): self.__dict__.update(other.__dict__)
try:
merge = self.__dict__[key].merge
except (AttributeError, KeyError):
self.__dict__[key] = val
else:
merge(val)
class Node: class Node:
"""The base Node class, for entities that we know how to """The base Node class, for entities that we know how to
@ -193,6 +207,7 @@ class Node:
self.depends_dict = {} self.depends_dict = {}
self.ignore = [] # dependencies to ignore self.ignore = [] # dependencies to ignore
self.ignore_dict = {} self.ignore_dict = {}
self.prerequisites = SCons.Util.UniqueList()
self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
self.waiting_parents = {} self.waiting_parents = {}
self.waiting_s_e = {} self.waiting_s_e = {}
@ -225,10 +240,18 @@ class Node:
def get_suffix(self): def get_suffix(self):
return '' return ''
memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
def get_build_env(self): def get_build_env(self):
"""Fetch the appropriate Environment to build this node. """Fetch the appropriate Environment to build this node.
""" """
return self.get_executor().get_build_env() try:
return self._memo['get_build_env']
except KeyError:
pass
result = self.get_executor().get_build_env()
self._memo['get_build_env'] = result
return result
def get_build_scanner_path(self, scanner): def get_build_scanner_path(self, scanner):
"""Fetch the appropriate scanner path for this node.""" """Fetch the appropriate scanner path for this node."""
@ -286,19 +309,64 @@ class Node:
""" """
return 0 return 0
#
# Taskmaster interface subsystem
#
def make_ready(self):
"""Get a Node ready for evaluation.
This is called before the Taskmaster decides if the Node is
up-to-date or not. Overriding this method allows for a Node
subclass to be disambiguated if necessary, or for an implicit
source builder to be attached.
"""
pass
def prepare(self):
"""Prepare for this Node to be built.
This is called after the Taskmaster has decided that the Node
is out-of-date and must be rebuilt, but before actually calling
the method to build the Node.
This default implemenation checks that all children either exist
or are derived, and initializes the BuildInfo structure that
will hold the information about how this node is, uh, built.
Overriding this method allows for for a Node subclass to remove
the underlying file from the file system. Note that subclass
methods should call this base class method to get the child
check and the BuildInfo structure.
"""
l = self.depends
if not self.implicit is None:
l = l + self.implicit
missing_sources = self.get_executor().get_missing_sources() \
+ filter(lambda c: c.missing(), l)
if missing_sources:
desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self)
raise SCons.Errors.StopError, desc
self.binfo = self.get_binfo()
def build(self, **kw): def build(self, **kw):
"""Actually build the node. """Actually build the node.
This is called by the Taskmaster after it's decided that the
Node is out-of-date and must be rebuilt, and after the prepare()
method has gotten everything, uh, prepared.
This method is called from multiple threads in a parallel build, This method is called from multiple threads in a parallel build,
so only do thread safe stuff here. Do thread unsafe stuff in so only do thread safe stuff here. Do thread unsafe stuff
built(). in built().
""" """
def exitstatfunc(stat, node=self): try:
if stat: apply(self.get_executor(), (self,), kw)
msg = "Error %d" % stat except SCons.Errors.BuildError, e:
raise SCons.Errors.BuildError(node=node, errstr=msg) e.node = self
executor = self.get_executor() raise
apply(executor, (self, exitstatfunc), kw)
def built(self): def built(self):
"""Called just after this node is successfully built.""" """Called just after this node is successfully built."""
@ -309,28 +377,26 @@ class Node:
parent.implicit = None parent.implicit = None
parent.del_binfo() parent.del_binfo()
try:
new = self.binfo
except AttributeError:
# Node arrived here without build info; apparently it
# doesn't need it, so don't bother calculating or storing
# it.
new = None
# Reset this Node's cached state since it was just built and
# various state has changed.
self.clear() self.clear()
if new: self.ninfo.update(self)
# It had build info, so it should be stored in the signature
# cache. However, if the build info included a content def visited(self):
# signature then it must be recalculated before being stored. """Called just after this node has been visited (with or
if hasattr(new.ninfo, 'csig'): without a build)."""
self.get_csig() try:
else: binfo = self.binfo
new.ninfo.update(self) except AttributeError:
self.binfo = new # Apparently this node doesn't need build info, so
self.store_info(self.binfo) # don't bother calculating or storing it.
pass
else:
self.ninfo.update(self)
self.store_info()
#
#
#
def add_to_waiting_s_e(self, node): def add_to_waiting_s_e(self, node):
self.waiting_s_e[node] = 1 self.waiting_s_e[node] = 1
@ -367,27 +433,33 @@ class Node:
can be re-evaluated by interfaces that do continuous integration can be re-evaluated by interfaces that do continuous integration
builds). builds).
""" """
# Note in case it's important in the future: We also used to clear
# the build information (the lists of dependencies) here like this:
#
# self.del_binfo()
#
# But we now rely on the fact that we're going to look at that
# once before the build, and then store the results in the
# .sconsign file after the build.
self.clear_memoized_values() self.clear_memoized_values()
self.ninfo = self.new_ninfo()
self.executor_cleanup() self.executor_cleanup()
self.del_binfo()
try: try:
delattr(self, '_calculated_sig') delattr(self, '_calculated_sig')
except AttributeError: except AttributeError:
pass pass
self.includes = None self.includes = None
self.found_includes = {} self.found_includes = {}
self.implicit = None
def clear_memoized_values(self): def clear_memoized_values(self):
self._memo = {} self._memo = {}
def visited(self):
"""Called just after this node has been visited
without requiring a build.."""
pass
def builder_set(self, builder): def builder_set(self, builder):
self.builder = builder self.builder = builder
try:
del self.executor
except AttributeError:
pass
def has_builder(self): def has_builder(self):
"""Return whether this Node has a builder or not. """Return whether this Node has a builder or not.
@ -405,8 +477,7 @@ class Node:
except AttributeError: except AttributeError:
# There was no explicit builder for this Node, so initialize # There was no explicit builder for this Node, so initialize
# the self.builder attribute to None now. # the self.builder attribute to None now.
self.builder = None b = self.builder = None
b = self.builder
return not b is None return not b is None
def set_explicit(self, is_explicit): def set_explicit(self, is_explicit):
@ -446,14 +517,6 @@ class Node:
""" """
return self.has_builder() or self.side_effect return self.has_builder() or self.side_effect
def is_pseudo_derived(self):
"""
Returns true iff this node is built, but should use a source path
when duplicate=0 and should contribute a content signature (i.e.
source signature) when used as a source for other derived files.
"""
return 0
def alter_targets(self): def alter_targets(self):
"""Return a list of alternate targets for this Node. """Return a list of alternate targets for this Node.
""" """
@ -552,40 +615,33 @@ class Node:
return return
build_env = self.get_build_env() build_env = self.get_build_env()
executor = self.get_executor()
# Here's where we implement --implicit-cache. # Here's where we implement --implicit-cache.
if implicit_cache and not implicit_deps_changed: if implicit_cache and not implicit_deps_changed:
implicit = self.get_stored_implicit() implicit = self.get_stored_implicit()
if implicit is not None: if implicit is not None:
factory = build_env.get_factory(self.builder.source_factory) # We now add the implicit dependencies returned from the
nodes = [] # stored .sconsign entry to have already been converted
for i in implicit: # to Nodes for us. (We used to run them through a
try: # source_factory function here.)
n = factory(i)
except TypeError: # Update all of the targets with them. This
# The implicit dependency was cached as one type # essentially short-circuits an N*M scan of the
# of Node last time, but the configuration has # sources for each individual target, which is a hell
# changed (probably) and it's a different type # of a lot more efficient.
# this time. Just ignore the mismatch and go for tgt in executor.targets:
# with what our current configuration says the tgt.add_to_implicit(implicit)
# Node is.
pass if implicit_deps_unchanged or self.is_up_to_date():
else:
nodes.append(n)
self._add_child(self.implicit, self.implicit_dict, nodes)
calc = build_env.get_calculator()
if implicit_deps_unchanged or self.current(calc):
return return
# one of this node's sources has changed, so # one of this node's sources has changed,
# we need to recalculate the implicit deps, # so we must recalculate the implicit deps:
# and the bsig:
self.implicit = [] self.implicit = []
self.implicit_dict = {} self.implicit_dict = {}
self._children_reset() self._children_reset()
self.del_binfo() self.del_binfo()
executor = self.get_executor()
# Have the executor scan the sources. # Have the executor scan the sources.
executor.scan_sources(self.builder.source_scanner) executor.scan_sources(self.builder.source_scanner)
@ -620,65 +676,24 @@ class Node:
NodeInfo = NodeInfoBase NodeInfo = NodeInfoBase
BuildInfo = BuildInfoBase BuildInfo = BuildInfoBase
def calculator(self):
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
return env.get_calculator()
memoizer_counters.append(SCons.Memoize.CountValue('calc_signature'))
def calc_signature(self, calc=None):
"""
Select and calculate the appropriate build signature for a node.
self - the node
calc - the signature calculation module
returns - the signature
"""
try:
return self._memo['calc_signature']
except KeyError:
pass
if self.is_derived():
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
if env.use_build_signature():
result = self.get_bsig(calc)
else:
result = self.get_csig(calc)
elif not self.rexists():
result = None
else:
result = self.get_csig(calc)
self._memo['calc_signature'] = result
return result
def new_ninfo(self): def new_ninfo(self):
return self.NodeInfo(self) ninfo = self.NodeInfo(self)
return ninfo
def get_ninfo(self):
try:
return self.ninfo
except AttributeError:
self.ninfo = self.new_ninfo()
return self.ninfo
def new_binfo(self): def new_binfo(self):
return self.BuildInfo(self) binfo = self.BuildInfo(self)
return binfo
def get_binfo(self): def get_binfo(self):
try:
return self.binfo
except AttributeError:
self.binfo = self.new_binfo()
return self.binfo
def del_binfo(self):
"""Delete the build info from this node."""
try:
delattr(self, 'binfo')
except AttributeError:
pass
def gen_binfo(self, calc=None, scan=1):
""" """
Generate a node's build signature, the digested signatures Fetch a node's build information.
of its dependency files and build information.
node - the node whose sources will be collected node - the node whose sources will be collected
cache - alternate node to use for the signature cache cache - alternate node to use for the signature cache
@ -689,21 +704,17 @@ class Node:
already built and updated by someone else, if that's already built and updated by someone else, if that's
what's wanted. what's wanted.
""" """
try:
return self.binfo
except AttributeError:
pass
if calc is None: binfo = self.new_binfo()
calc = self.calculator() self.binfo = binfo
binfo = self.get_binfo()
if scan:
self.scan()
executor = self.get_executor() executor = self.get_executor()
def calc_signature(node, calc=calc):
return node.calc_signature(calc)
sources = executor.get_unignored_sources(self.ignore) sources = executor.get_unignored_sources(self.ignore)
sourcesigs = executor.process_sources(calc_signature, self.ignore)
depends = self.depends depends = self.depends
implicit = self.implicit or [] implicit = self.implicit or []
@ -712,15 +723,16 @@ class Node:
depends = filter(self.do_not_ignore, depends) depends = filter(self.do_not_ignore, depends)
implicit = filter(self.do_not_ignore, implicit) implicit = filter(self.do_not_ignore, implicit)
dependsigs = map(calc_signature, depends) def get_ninfo(node):
implicitsigs = map(calc_signature, implicit) return node.get_ninfo()
sigs = sourcesigs + dependsigs + implicitsigs sourcesigs = map(get_ninfo, sources)
dependsigs = map(get_ninfo, depends)
implicitsigs = map(get_ninfo, implicit)
if self.has_builder(): if self.has_builder():
binfo.bact = str(executor) binfo.bact = str(executor)
binfo.bactsig = calc.module.signature(executor) binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
sigs.append(binfo.bactsig)
binfo.bsources = sources binfo.bsources = sources
binfo.bdepends = depends binfo.bdepends = depends
@ -730,33 +742,34 @@ class Node:
binfo.bdependsigs = dependsigs binfo.bdependsigs = dependsigs
binfo.bimplicitsigs = implicitsigs binfo.bimplicitsigs = implicitsigs
binfo.ninfo.bsig = calc.module.collect(filter(None, sigs))
return binfo return binfo
def get_bsig(self, calc=None): def del_binfo(self):
binfo = self.get_binfo() """Delete the build info from this node."""
try: try:
return binfo.ninfo.bsig delattr(self, 'binfo')
except AttributeError: except AttributeError:
self.binfo = self.gen_binfo(calc) pass
return self.binfo.ninfo.bsig
def get_csig(self, calc=None): def get_csig(self):
binfo = self.get_binfo()
try: try:
return binfo.ninfo.csig return self.ninfo.csig
except AttributeError: except AttributeError:
if calc is None: ninfo = self.get_ninfo()
calc = self.calculator() ninfo.csig = SCons.Util.MD5signature(self.get_contents())
csig = binfo.ninfo.csig = calc.module.signature(self) return self.ninfo.csig
return csig
def store_info(self, obj): def get_cachedir_csig(self):
return self.get_csig()
def store_info(self):
"""Make the build signature permanent (that is, store it in the """Make the build signature permanent (that is, store it in the
.sconsign file or equivalent).""" .sconsign file or equivalent)."""
pass pass
def do_not_store_info(self):
pass
def get_stored_info(self): def get_stored_info(self):
return None return None
@ -800,23 +813,8 @@ class Node:
def missing(self): def missing(self):
return not self.is_derived() and \ return not self.is_derived() and \
not self.is_pseudo_derived() and \
not self.linked and \ not self.linked and \
not self.rexists() not self.rexists()
def prepare(self):
"""Prepare for this Node to be created.
The default implemenation checks that all children either exist
or are derived.
"""
l = self.depends
if not self.implicit is None:
l = l + self.implicit
missing_sources = self.get_executor().get_missing_sources() \
+ filter(lambda c: c.missing(), l)
if missing_sources:
desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self)
raise SCons.Errors.StopError, desc
def remove(self): def remove(self):
"""Remove this Node: no-op by default.""" """Remove this Node: no-op by default."""
@ -834,6 +832,11 @@ class Node:
s = str(e) s = str(e)
raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
def add_prerequisite(self, prerequisite):
"""Adds prerequisites"""
self.prerequisites.extend(prerequisite)
self._children_reset()
def add_ignore(self, depend): def add_ignore(self, depend):
"""Adds dependencies to ignore.""" """Adds dependencies to ignore."""
try: try:
@ -861,11 +864,11 @@ class Node:
def _add_child(self, collection, dict, child): def _add_child(self, collection, dict, child):
"""Adds 'child' to 'collection', first checking 'dict' to see """Adds 'child' to 'collection', first checking 'dict' to see
if it's already present.""" if it's already present."""
if type(child) is not type([]): #if type(child) is not type([]):
child = [child] # child = [child]
for c in child: #for c in child:
if not isinstance(c, Node): # if not isinstance(c, Node):
raise TypeError, c # raise TypeError, c
added = None added = None
for c in child: for c in child:
if not dict.has_key(c): if not dict.has_key(c):
@ -883,7 +886,7 @@ class Node:
def _children_reset(self): def _children_reset(self):
self.clear_memoized_values() self.clear_memoized_values()
# We need to let the Executor clear out any calculated # We need to let the Executor clear out any calculated
# bsig info that it's cached so we can re-calculate it. # build info that it's cached so we can re-calculate it.
self.executor_cleanup() self.executor_cleanup()
def do_not_ignore(self, node): def do_not_ignore(self, node):
@ -944,19 +947,107 @@ class Node:
def get_state(self): def get_state(self):
return self.state return self.state
def current(self, calc=None): def state_has_changed(self, target, prev_ni):
return (self.state != SCons.Node.up_to_date)
def get_env(self):
env = self.env
if not env:
import SCons.Defaults
env = SCons.Defaults.DefaultEnvironment()
return env
def changed_since_last_build(self, target, prev_ni):
"""
Must be overridden in a specific subclass to return True if this
Node (a dependency) has changed since the last time it was used
to build the specified target. prev_ni is this Node's state (for
example, its file timestamp, length, maybe content signature)
as of the last time the target was built.
Note that this method is called through the dependency, not the
target, because a dependency Node must be able to use its own
logic to decide if it changed. For example, File Nodes need to
obey if we're configured to use timestamps, but Python Value Nodes
never use timestamps and always use the content. If this method
were called through the target, then each Node's implementation
of this method would have to have more complicated logic to
handle all the different Node types on which it might depend.
"""
raise NotImplementedError
def Decider(self, function):
SCons.Util.AddMethod(self, function, 'changed_since_last_build')
def changed(self, node=None):
"""
Returns if the node is up-to-date with respect to the BuildInfo
stored last time it was built. The default behavior is to compare
it against our own previously stored BuildInfo, but the stored
BuildInfo from another Node (typically one in a Repository)
can be used instead.
Note that we now *always* check every dependency. We used to
short-circuit the check by returning as soon as we detected
any difference, but we now rely on checking every dependency
to make sure that any necessary Node information (for example,
the content signature of an #included .h file) is updated.
"""
t = 0
if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
if node is None:
node = self
result = False
bi = node.get_stored_info().binfo
then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
children = self.children()
diff = len(children) - len(then)
if diff:
# The old and new dependency lists are different lengths.
# This always indicates that the Node must be rebuilt.
# We also extend the old dependency list with enough None
# entries to equal the new dependency list, for the benefit
# of the loop below that updates node information.
then.extend([None] * diff)
result = True
for child, prev_ni in zip(children, then):
if child.changed_since_last_build(self, prev_ni):
if t: Trace(': %s changed' % child)
result = True
contents = self.get_executor().get_contents()
if self.has_builder():
import SCons.Util
newsig = SCons.Util.MD5signature(contents)
if bi.bactsig != newsig:
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
result = True
if not result:
if t: Trace(': up to date')
if t: Trace('\n')
return result
def is_up_to_date(self):
"""Default check for whether the Node is current: unknown Node """Default check for whether the Node is current: unknown Node
subtypes are always out of date, so they will always get built.""" subtypes are always out of date, so they will always get built."""
return None return None
def children_are_up_to_date(self, calc=None): def children_are_up_to_date(self):
"""Alternate check for whether the Node is current: If all of """Alternate check for whether the Node is current: If all of
our children were up-to-date, then this Node was up-to-date, too. our children were up-to-date, then this Node was up-to-date, too.
The SCons.Node.Alias and SCons.Node.Python.Value subclasses The SCons.Node.Alias and SCons.Node.Python.Value subclasses
rebind their current() method to this method.""" rebind their current() method to this method."""
# Allow the children to calculate their signatures. # Allow the children to calculate their signatures.
self.binfo = self.gen_binfo(calc) self.binfo = self.get_binfo()
if self.always_build: if self.always_build:
return None return None
state = 0 state = 0
@ -1046,32 +1137,29 @@ class Node:
if not self.exists(): if not self.exists():
return "building `%s' because it doesn't exist\n" % self return "building `%s' because it doesn't exist\n" % self
if self.always_build:
return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
old = self.get_stored_info() old = self.get_stored_info()
if old is None: if old is None:
return None return None
old = old.binfo
old.prepare_dependencies() old.prepare_dependencies()
def dictify(result, kids, sigs):
for k, s in zip(kids, sigs):
result[k] = s
try: try:
osig = {} old_bkids = old.bsources + old.bdepends + old.bimplicit
dictify(osig, old.bsources, old.bsourcesigs) old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
dictify(osig, old.bdepends, old.bdependsigs)
dictify(osig, old.bimplicit, old.bimplicitsigs)
except AttributeError: except AttributeError:
return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
new = self.get_binfo() new = self.get_binfo()
nsig = {} new_bkids = new.bsources + new.bdepends + new.bimplicit
dictify(nsig, new.bsources, new.bsourcesigs) new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
dictify(nsig, new.bdepends, new.bdependsigs)
dictify(nsig, new.bimplicit, new.bimplicitsigs)
old_bkids = old.bsources + old.bdepends + old.bimplicit osig = dict(zip(old_bkids, old_bkidsigs))
new_bkids = new.bsources + new.bdepends + new.bimplicit nsig = dict(zip(new_bkids, new_bkidsigs))
# The sources and dependencies we'll want to report are all stored # The sources and dependencies we'll want to report are all stored
# as relative paths to this target's directory, but we want to # as relative paths to this target's directory, but we want to
@ -1092,7 +1180,7 @@ class Node:
for k in new_bkids: for k in new_bkids:
if not k in old_bkids: if not k in old_bkids:
lines.append("`%s' is a new dependency\n" % stringify(k)) lines.append("`%s' is a new dependency\n" % stringify(k))
elif osig[k] != nsig[k]: elif k.changed_since_last_build(self, osig[k]):
lines.append("`%s' changed\n" % stringify(k)) lines.append("`%s' changed\n" % stringify(k))
if len(lines) == 0 and old_bkids != new_bkids: if len(lines) == 0 and old_bkids != new_bkids:
@ -1124,19 +1212,18 @@ class Node:
lines = ["%s:\n" % preamble] + lines lines = ["%s:\n" % preamble] + lines
return string.join(lines, ' '*11) return string.join(lines, ' '*11)
l = [1]
ul = UserList.UserList([2])
try: try:
l.extend(ul) [].extend(UserList.UserList([]))
except TypeError: except TypeError:
# Python 1.5.2 doesn't allow a list to be extended by list-like
# objects (such as UserList instances), so just punt and use
# real lists.
def NodeList(l): def NodeList(l):
return l return l
else: else:
class NodeList(UserList.UserList): class NodeList(UserList.UserList):
def __str__(self): def __str__(self):
return str(map(str, self.data)) return str(map(str, self.data))
del l
del ul
def get_children(node, parent): return node.children() def get_children(node, parent): return node.children()
def ignore_cycle(node, stack): pass def ignore_cycle(node, stack): pass

View file

@ -34,7 +34,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Options/BoolOption.py 2523 2007/12/12 09:37:41 knight"
__all__ = ('BoolOption') __all__ = ('BoolOption')

View file

@ -37,7 +37,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Options/EnumOption.py 2523 2007/12/12 09:37:41 knight"
__all__ = ('EnumOption',) __all__ = ('EnumOption',)

View file

@ -47,7 +47,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/ListOption.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Options/ListOption.py 2523 2007/12/12 09:37:41 knight"
# Know Bug: This should behave like a Set-Type, but does not really, # Know Bug: This should behave like a Set-Type, but does not really,
# since elements can occur twice. # since elements can occur twice.

View file

@ -50,7 +50,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Options/PackageOption.py 2523 2007/12/12 09:37:41 knight"
__all__ = ('PackageOption') __all__ = ('PackageOption')

View file

@ -68,7 +68,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Options/PathOption.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path
@ -128,7 +128,12 @@ class _PathOptionClass:
""" """
if validator is None: if validator is None:
validator = self.PathExists validator = self.PathExists
return (key, '%s ( /path/to/%s )' % (help, key), default,
validator, None) if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
return (key, '%s ( /path/to/%s )' % (help, key[0]), default,
validator, None)
else:
return (key, '%s ( /path/to/%s )' % (help, key), default,
validator, None)
PathOption = _PathOptionClass() PathOption = _PathOptionClass()

View file

@ -27,10 +27,13 @@ customizable variables to an SCons build.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Options/__init__.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat
import os.path import os.path
import string import string
import sys
import SCons.Errors import SCons.Errors
import SCons.Util import SCons.Util
@ -44,31 +47,49 @@ from PathOption import PathOption # okay
class Options: class Options:
instance=None
""" """
Holds all the options, updates the environment with the variables, Holds all the options, updates the environment with the variables,
and renders the help text. and renders the help text.
""" """
def __init__(self, files=None, args={}): def __init__(self, files=[], args={}, is_global=1):
""" """
files - [optional] List of option configuration files to load files - [optional] List of option configuration files to load
(backward compatibility) If a single string is passed it is (backward compatibility) If a single string is passed it is
automatically placed in a file list automatically placed in a file list
""" """
self.options = [] self.options = []
self.args = args self.args = args
self.files = None if not SCons.Util.is_List(files):
if SCons.Util.is_String(files): if files:
self.files = [ files ] files = [ files ]
elif files: else:
self.files = files files = []
self.files = files
self.unknown = {}
# create the singleton instance
if is_global:
self=Options.instance
if not Options.instance:
Options.instance=self
def _do_add(self, key, help="", default=None, validator=None, converter=None): def _do_add(self, key, help="", default=None, validator=None, converter=None):
class Option: class Option:
pass pass
option = Option() option = Option()
option.key = key
# if we get a list or a tuple, we take the first element as the
# option key and store the remaining in aliases.
if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
option.key = key[0]
option.aliases = key[1:]
else:
option.key = key
option.aliases = [ key ]
option.help = help option.help = help
option.default = default option.default = default
option.validator = validator option.validator = validator
@ -111,7 +132,7 @@ class Options:
Each list element is a tuple/list of arguments to be passed on Each list element is a tuple/list of arguments to be passed on
to the underlying method for adding options. to the underlying method for adding options.
Example: Example:
opt.AddOptions( opt.AddOptions(
('debug', '', 0), ('debug', '', 0),
@ -139,19 +160,34 @@ class Options:
values[option.key] = option.default values[option.key] = option.default
# next set the value specified in the options file # next set the value specified in the options file
if self.files: for filename in self.files:
for filename in self.files: if os.path.exists(filename):
if os.path.exists(filename): dir = os.path.split(os.path.abspath(filename))[0]
execfile(filename, values) if dir:
sys.path.insert(0, dir)
try:
values['__name__'] = filename
execfile(filename, {}, values)
finally:
if dir:
del sys.path[0]
del values['__name__']
# finally set the values specified on the command line # set the values specified on the command line
if args is None: if args is None:
args = self.args args = self.args
values.update(args)
for arg, value in args.items():
added = False
for option in self.options:
if arg in option.aliases + [ option.key ]:
values[option.key] = value
added = True
if not added:
self.unknown[arg] = value
# put the variables in the environment: # put the variables in the environment:
# (don't copy over variables that are not declared # (don't copy over variables that are not declared as options)
# as options)
for option in self.options: for option in self.options:
try: try:
env[option.key] = values[option.key] env[option.key] = values[option.key]
@ -176,6 +212,13 @@ class Options:
if option.validator and values.has_key(option.key): if option.validator and values.has_key(option.key):
option.validator(option.key, env.subst('${%s}'%option.key), env) option.validator(option.key, env.subst('${%s}'%option.key), env)
def UnknownOptions(self):
"""
Returns any options in the specified arguments lists that
were not known, declared options in this object.
"""
return self.unknown
def Save(self, filename, env): def Save(self, filename, env):
""" """
Saves all the options in the given file. This file can Saves all the options in the given file. This file can
@ -204,7 +247,7 @@ class Options:
# Convert stuff that has a repr() that # Convert stuff that has a repr() that
# cannot be evaluated into a string # cannot be evaluated into a string
value = SCons.Util.to_String(value) value = SCons.Util.to_String(value)
defaultVal = env.subst(SCons.Util.to_String(option.default)) defaultVal = env.subst(SCons.Util.to_String(option.default))
if option.converter: if option.converter:
defaultVal = option.converter(defaultVal) defaultVal = option.converter(defaultVal)
@ -238,12 +281,19 @@ class Options:
actual = env.subst('${%s}' % opt.key) actual = env.subst('${%s}' % opt.key)
else: else:
actual = None actual = None
return self.FormatOptionHelpText(env, opt.key, opt.help, opt.default, actual) return self.FormatOptionHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases)
lines = filter(None, map(format, options)) lines = filter(None, map(format, options))
return string.join(lines, '') return string.join(lines, '')
format = '\n%s: %s\n default: %s\n actual: %s\n' format = '\n%s: %s\n default: %s\n actual: %s\n'
format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n'
def FormatOptionHelpText(self, env, key, help, default, actual, aliases=[]):
# Don't display the key name itself as an alias.
aliases = filter(lambda a, k=key: a != k, aliases)
if len(aliases)==0:
return self.format % (key, help, default, actual)
else:
return self.format_ % (key, help, default, actual, aliases)
def FormatOptionHelpText(self, env, key, help, default, actual):
return self.format % (key, help, default, actual)

View file

@ -21,7 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/PathList.py 2523 2007/12/12 09:37:41 knight"
__doc__ = """SCons.PathList __doc__ = """SCons.PathList
@ -138,7 +138,8 @@ class _PathList:
value = string.join(map(str, value), '') value = string.join(map(str, value), '')
elif type == TYPE_OBJECT: elif type == TYPE_OBJECT:
value = node_conv(value) value = node_conv(value)
result.append(value) if value:
result.append(value)
return tuple(result) return tuple(result)

View file

@ -42,7 +42,7 @@ their own platform definition.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Platform/__init__.py 2523 2007/12/12 09:37:41 knight"
import imp import imp
import os import os

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/aix.py 2523 2007/12/12 09:37:41 knight"
import os import os
import string import string

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/cygwin.py 2523 2007/12/12 09:37:41 knight"
import posix import posix
from SCons.Platform import TempFileMunge from SCons.Platform import TempFileMunge

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/darwin.py 2523 2007/12/12 09:37:41 knight"
import posix import posix

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/hpux.py 2523 2007/12/12 09:37:41 knight"
import posix import posix

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/irix.py 2523 2007/12/12 09:37:41 knight"
import posix import posix

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/os2.py 2523 2007/12/12 09:37:41 knight"
def generate(env): def generate(env):
if not env.has_key('ENV'): if not env.has_key('ENV'):

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/posix.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/sunos.py 2523 2007/12/12 09:37:41 knight"
import posix import posix
@ -41,4 +41,4 @@ def generate(env):
env['MAXLINELENGTH'] = 1045320 env['MAXLINELENGTH'] = 1045320
env['PKGINFO'] = 'pkginfo' env['PKGINFO'] = 'pkginfo'
env['PKGCHK'] = '/usr/sbin/pkgchk' env['PKGCHK'] = '/usr/sbin/pkgchk'
env['ENV']['PATH'] = env['ENV']['PATH'] + ':/usr/ccs/bin' env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin'

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Platform/win32.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path
@ -40,13 +40,53 @@ import tempfile
from SCons.Platform.posix import exitvalmap from SCons.Platform.posix import exitvalmap
from SCons.Platform import TempFileMunge from SCons.Platform import TempFileMunge
# XXX See note below about why importing SCons.Action should be
# eventually refactored.
import SCons.Action
import SCons.Util import SCons.Util
try:
import msvcrt
import win32api
import win32con
msvcrt.get_osfhandle
win32api.SetHandleInformation
win32con.HANDLE_FLAG_INHERIT
except ImportError:
parallel_msg = \
"you do not seem to have the pywin32 extensions installed;\n" + \
"\tparallel (-j) builds may not work reliably with open Python files."
except AttributeError:
parallel_msg = \
"your pywin32 extensions do not support file handle operations;\n" + \
"\tparallel (-j) builds may not work reliably with open Python files."
else:
parallel_msg = None
import __builtin__
_builtin_file = __builtin__.file
_builtin_open = __builtin__.open
def _scons_file(*args, **kw):
fp = apply(_builtin_file, args, kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
win32con.HANDLE_FLAG_INHERIT,
0)
return fp
def _scons_open(*args, **kw):
fp = apply(_builtin_open, args, kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
win32con.HANDLE_FLAG_INHERIT,
0)
return fp
__builtin__.file = _scons_file
__builtin__.open = _scons_open
# The upshot of all this is that, if you are using Python 1.5.2, # 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 # you had better have cmd or command.com in your PATH when you run
# scons. # scons.

View file

@ -26,7 +26,9 @@ Autoconf-like configuration support.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/SConf.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat
import os import os
import re import re
@ -46,10 +48,20 @@ import SCons.Util
import SCons.Warnings import SCons.Warnings
import SCons.Conftest import SCons.Conftest
from SCons.Debug import Trace
# Turn off the Conftest error logging # Turn off the Conftest error logging
SCons.Conftest.LogInputFiles = 0 SCons.Conftest.LogInputFiles = 0
SCons.Conftest.LogErrorMessages = 0 SCons.Conftest.LogErrorMessages = 0
# Set
build_type = None
build_types = ['clean', 'help']
def SetBuildType(type):
global build_type
build_type = type
# to be set, if we are in dry-run mode # to be set, if we are in dry-run mode
dryrun = 0 dryrun = 0
@ -158,12 +170,10 @@ class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
""" """
result = None # -> 0/None -> no error, != 0 error result = None # -> 0/None -> no error, != 0 error
string = None # the stdout / stderr output when building the target string = None # the stdout / stderr output when building the target
def __init__(self, node, result, string, sig): def set_build_result(self, result, string):
SCons.Node.FS.FileBuildInfo.__init__(self, node)
self.result = result self.result = result
self.string = string self.string = string
self.ninfo.bsig = sig
class Streamer: class Streamer:
@ -211,7 +221,7 @@ class SConfBuildTask(SCons.Taskmaster.Task):
""" """
if not isinstance(bi, SConfBuildInfo): if not isinstance(bi, SConfBuildInfo):
SCons.Warnings.warn(SConfWarning, SCons.Warnings.warn(SConfWarning,
"The stored build information has an unexpected class.") "The stored build information has an unexpected class: %s" % bi.__class__)
else: else:
self.display("The original builder output was:\n" + self.display("The original builder output was:\n" +
string.replace(" |" + str(bi.string), string.replace(" |" + str(bi.string),
@ -245,30 +255,39 @@ class SConfBuildTask(SCons.Taskmaster.Task):
# cached_error is 1, if the node(s) are up_to_date, but the # cached_error is 1, if the node(s) are up_to_date, but the
# build will fail # build will fail
# cachable is 0, if some nodes are not in our cache # cachable is 0, if some nodes are not in our cache
is_up_to_date = 1 T = 0
cached_error = 0 changed = False
cachable = 1 cached_error = False
cachable = True
for t in self.targets: for t in self.targets:
bi = t.get_stored_info() if T: Trace('%s' % (t))
bi = t.get_stored_info().binfo
if isinstance(bi, SConfBuildInfo): if isinstance(bi, SConfBuildInfo):
if T: Trace(': SConfBuildInfo')
if cache_mode == CACHE: if cache_mode == CACHE:
t.set_state(SCons.Node.up_to_date) t.set_state(SCons.Node.up_to_date)
if T: Trace(': set_state(up_to-date)')
else: else:
new_bsig = t.calc_signature(sconf_global.calc) if T: Trace(': get_state() %s' % t.get_state())
if t.env.use_build_signature(): if T: Trace(': changed() %s' % t.changed())
old_bsig = bi.ninfo.bsig if (t.get_state() != SCons.Node.up_to_date and t.changed()):
else: changed = True
old_bsig = bi.ninfo.csig if T: Trace(': changed %s' % changed)
is_up_to_date = (is_up_to_date and new_bsig == old_bsig)
cached_error = cached_error or bi.result cached_error = cached_error or bi.result
else: else:
if T: Trace(': else')
# the node hasn't been built in a SConf context or doesn't # the node hasn't been built in a SConf context or doesn't
# exist # exist
cachable = 0 cachable = False
is_up_to_date = 0 changed = ( t.get_state() != SCons.Node.up_to_date )
return (is_up_to_date, cached_error, cachable) if T: Trace(': changed %s' % changed)
if T: Trace('\n')
return (not changed, cached_error, cachable)
def execute(self): def execute(self):
if not self.targets[0].has_builder():
return
sconf = sconf_global sconf = sconf_global
is_up_to_date, cached_error, cachable = self.collect_node_states() is_up_to_date, cached_error, cachable = self.collect_node_states()
@ -281,11 +300,13 @@ class SConfBuildTask(SCons.Taskmaster.Task):
if cached_error and is_up_to_date: if cached_error and is_up_to_date:
self.display("Building \"%s\" failed in a previous run and all " self.display("Building \"%s\" failed in a previous run and all "
"its sources are up to date." % str(self.targets[0])) "its sources are up to date." % str(self.targets[0]))
self.display_cached_string(self.targets[0].get_stored_info()) binfo = self.targets[0].get_stored_info().binfo
self.display_cached_string(binfo)
raise SCons.Errors.BuildError # will be 'caught' in self.failed raise SCons.Errors.BuildError # will be 'caught' in self.failed
elif is_up_to_date: elif is_up_to_date:
self.display("\"%s\" is up to date." % str(self.targets[0])) self.display("\"%s\" is up to date." % str(self.targets[0]))
self.display_cached_string(self.targets[0].get_stored_info()) binfo = self.targets[0].get_stored_info().binfo
self.display_cached_string(binfo)
elif dryrun: elif dryrun:
raise ConfigureDryRunError(self.targets[0]) raise ConfigureDryRunError(self.targets[0])
else: else:
@ -305,21 +326,43 @@ class SConfBuildTask(SCons.Taskmaster.Task):
except SystemExit: except SystemExit:
exc_value = sys.exc_info()[1] exc_value = sys.exc_info()[1]
raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code) raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code)
except: except Exception, e:
for t in self.targets: for t in self.targets:
sig = t.calc_signature(sconf.calc) binfo = t.get_binfo()
string = s.getvalue() binfo.__class__ = SConfBuildInfo
binfo = SConfBuildInfo(t,1,string,sig) binfo.set_build_result(1, s.getvalue())
t.dir.sconsign().set_entry(t.name, binfo) sconsign_entry = SCons.SConsign.SConsignEntry()
raise sconsign_entry.binfo = binfo
#sconsign_entry.ninfo = self.get_ninfo()
# We'd like to do this as follows:
# t.store_info(binfo)
# However, we need to store it as an SConfBuildInfo
# object, and store_info() will turn it into a
# regular FileNodeInfo if the target is itself a
# regular File.
sconsign = t.dir.sconsign()
sconsign.set_entry(t.name, sconsign_entry)
sconsign.merge()
raise e
else: else:
for t in self.targets: for t in self.targets:
sig = t.calc_signature(sconf.calc) binfo = t.get_binfo()
string = s.getvalue() binfo.__class__ = SConfBuildInfo
binfo = SConfBuildInfo(t,0,string,sig) binfo.set_build_result(0, s.getvalue())
t.dir.sconsign().set_entry(t.name, binfo) sconsign_entry = SCons.SConsign.SConsignEntry()
sconsign_entry.binfo = binfo
#sconsign_entry.ninfo = self.get_ninfo()
# We'd like to do this as follows:
# t.store_info(binfo)
# However, we need to store it as an SConfBuildInfo
# object, and store_info() will turn it into a
# regular FileNodeInfo if the target is itself a
# regular File.
sconsign = t.dir.sconsign()
sconsign.set_entry(t.name, sconsign_entry)
sconsign.merge()
class SConf: class SConfBase:
"""This is simply a class to represent a configure context. After """This is simply a class to represent a configure context. After
creating a SConf object, you can call any tests. After finished with your creating a SConf object, you can call any tests. After finished with your
tests, be sure to call the Finish() method, which returns the modified tests, be sure to call the Finish() method, which returns the modified
@ -360,6 +403,7 @@ class SConf:
default_tests = { default_tests = {
'CheckFunc' : CheckFunc, 'CheckFunc' : CheckFunc,
'CheckType' : CheckType, 'CheckType' : CheckType,
'CheckTypeSize' : CheckTypeSize,
'CheckHeader' : CheckHeader, 'CheckHeader' : CheckHeader,
'CheckCHeader' : CheckCHeader, 'CheckCHeader' : CheckCHeader,
'CheckCXXHeader' : CheckCXXHeader, 'CheckCXXHeader' : CheckCXXHeader,
@ -369,7 +413,6 @@ class SConf:
self.AddTests(default_tests) self.AddTests(default_tests)
self.AddTests(custom_tests) self.AddTests(custom_tests)
self.confdir = SConfFS.Dir(env.subst(conf_dir)) self.confdir = SConfFS.Dir(env.subst(conf_dir))
self.calc = None
if not config_h is None: if not config_h is None:
config_h = SConfFS.File(config_h) config_h = SConfFS.File(config_h)
self.config_h = config_h self.config_h = config_h
@ -377,7 +420,8 @@ class SConf:
def Finish(self): def Finish(self):
"""Call this method after finished with your tests: """Call this method after finished with your tests:
env = sconf.Finish()""" env = sconf.Finish()
"""
self._shutdown() self._shutdown()
return self.env return self.env
@ -398,6 +442,13 @@ class SConf:
old_os_dir = os.getcwd() old_os_dir = os.getcwd()
SConfFS.chdir(SConfFS.Top, change_os_dir=1) SConfFS.chdir(SConfFS.Top, change_os_dir=1)
# Because we take responsibility here for writing out our
# own .sconsign info (see SConfBuildTask.execute(), above),
# we override the store_info() method with a null place-holder
# so we really control how it gets written.
for n in nodes:
n.store_info = n.do_not_store_info
ret = 1 ret = 1
try: try:
@ -561,7 +612,7 @@ class SConf:
def AddTest(self, test_name, test_instance): def AddTest(self, test_name, test_instance):
"""Adds test_class to this SConf instance. It can be called with """Adds test_class to this SConf instance. It can be called with
self.test_name(...)""" self.test_name(...)"""
setattr(self, test_name, SConf.TestWrapper(test_instance, self)) setattr(self, test_name, SConfBase.TestWrapper(test_instance, self))
def AddTests(self, tests): def AddTests(self, tests):
"""Adds all the tests given in the tests dictionary to this SConf """Adds all the tests given in the tests dictionary to this SConf
@ -773,6 +824,19 @@ class CheckContext:
#### End of stuff used by Conftest.py. #### End of stuff used by Conftest.py.
def SConf(*args, **kw):
if kw.get(build_type, True):
kw['_depth'] = kw.get('_depth', 0) + 1
for bt in build_types:
try:
del kw[bt]
except KeyError:
pass
return apply(SConfBase, args, kw)
else:
return SCons.Util.Null()
def CheckFunc(context, function_name, header = None, language = None): def CheckFunc(context, function_name, header = None, language = None):
res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language) res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language)
context.did_show_result = 1 context.did_show_result = 1
@ -784,6 +848,13 @@ def CheckType(context, type_name, includes = "", language = None):
context.did_show_result = 1 context.did_show_result = 1
return not res return not res
def CheckTypeSize(context, type_name, includes = "", language = None, expect = None):
res = SCons.Conftest.CheckTypeSize(context, type_name,
header = includes, language = language,
expect = expect)
context.did_show_result = 1
return res
def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'): def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'):
# used by CheckHeader and CheckLibWithHeader to produce C - #include # used by CheckHeader and CheckLibWithHeader to produce C - #include
# statements from the specified header (list) # statements from the specified header (list)

View file

@ -27,14 +27,15 @@ Writing and reading information to the .sconsign file or files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/SConsign.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat
import cPickle import cPickle
import os import os
import os.path import os.path
import SCons.dblite import SCons.dblite
import SCons.Sig
import SCons.Warnings import SCons.Warnings
def corrupt_dblite_warning(filename): def corrupt_dblite_warning(filename):
@ -107,6 +108,24 @@ def write():
else: else:
syncmethod() syncmethod()
class SConsignEntry:
"""
Wrapper class for the generic entry in a .sconsign file.
The Node subclass populates it with attributes as it pleases.
XXX As coded below, we do expect a '.binfo' attribute to be added,
but we'll probably generalize this in the next refactorings.
"""
current_version_id = 1
def __init__(self):
# Create an object attribute from the class attribute so it ends up
# in the pickled data in the .sconsign file.
_version_id = self.current_version_id
def convert_to_sconsign(self):
self.binfo.convert_to_sconsign()
def convert_from_sconsign(self, dir, name):
self.binfo.convert_from_sconsign(dir, name)
class Base: class Base:
""" """
This is the controlling class for the signatures for the collection of This is the controlling class for the signatures for the collection of
@ -116,14 +135,10 @@ class Base:
methods for fetching and storing the individual bits of information methods for fetching and storing the individual bits of information
that make up signature entry. that make up signature entry.
""" """
def __init__(self, module=None): def __init__(self):
"""
module - the signature module being used
"""
self.module = module or SCons.Sig.default_calc.module
self.entries = {} self.entries = {}
self.dirty = 0 self.dirty = False
self.to_be_merged = {}
def get_entry(self, filename): def get_entry(self, filename):
""" """
@ -136,19 +151,43 @@ class Base:
Set the entry. Set the entry.
""" """
self.entries[filename] = obj self.entries[filename] = obj
self.dirty = 1 self.dirty = True
def do_not_set_entry(self, filename, obj): def do_not_set_entry(self, filename, obj):
pass pass
def store_info(self, filename, node):
entry = node.get_stored_info()
entry.binfo.merge(node.get_binfo())
self.to_be_merged[filename] = node
self.dirty = True
def do_not_store_info(self, filename, node):
pass
def merge(self):
for key, node in self.to_be_merged.items():
entry = node.get_stored_info()
try:
ninfo = entry.ninfo
except AttributeError:
# This happens with SConf Nodes, because the configuration
# subsystem takes direct control over how the build decision
# is made and its information stored.
pass
else:
ninfo.merge(node.get_ninfo())
self.entries[key] = entry
self.to_be_merged = {}
class DB(Base): class DB(Base):
""" """
A Base subclass that reads and writes signature information A Base subclass that reads and writes signature information
from a global .sconsign.db* file--the actual file suffix is from a global .sconsign.db* file--the actual file suffix is
determined by the specified database module. determined by the database module.
""" """
def __init__(self, dir, module=None): def __init__(self, dir):
Base.__init__(self, module) Base.__init__(self)
self.dir = dir self.dir = dir
@ -182,6 +221,7 @@ class DB(Base):
# a file there. Don't actually set any entry info, so we # a file there. Don't actually set any entry info, so we
# won't try to write to that .sconsign.dblite file. # won't try to write to that .sconsign.dblite file.
self.set_entry = self.do_not_set_entry self.set_entry = self.do_not_set_entry
self.store_info = self.do_not_store_info
global sig_files global sig_files
sig_files.append(self) sig_files.append(self)
@ -190,6 +230,8 @@ class DB(Base):
if not self.dirty: if not self.dirty:
return return
self.merge()
db, mode = Get_DataBase(self.dir) db, mode = Get_DataBase(self.dir)
# Write using the path relative to the top of the SConstruct # Write using the path relative to the top of the SConstruct
@ -211,27 +253,31 @@ class DB(Base):
syncmethod() syncmethod()
class Dir(Base): class Dir(Base):
def __init__(self, fp=None, module=None): def __init__(self, fp=None, dir=None):
""" """
fp - file pointer to read entries from fp - file pointer to read entries from
module - the signature module being used
""" """
Base.__init__(self, module) Base.__init__(self)
if fp: if not fp:
self.entries = cPickle.load(fp) return
if type(self.entries) is not type({}):
self.entries = {} self.entries = cPickle.load(fp)
raise TypeError if type(self.entries) is not type({}):
self.entries = {}
raise TypeError
if dir:
for key, entry in self.entries.items():
entry.convert_from_sconsign(dir, key)
class DirFile(Dir): class DirFile(Dir):
""" """
Encapsulates reading and writing a per-directory .sconsign file. Encapsulates reading and writing a per-directory .sconsign file.
""" """
def __init__(self, dir, module=None): def __init__(self, dir):
""" """
dir - the directory for the file dir - the directory for the file
module - the signature module being used
""" """
self.dir = dir self.dir = dir
@ -243,7 +289,7 @@ class DirFile(Dir):
fp = None fp = None
try: try:
Dir.__init__(self, fp, module) Dir.__init__(self, fp, dir)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except:
@ -253,15 +299,6 @@ class DirFile(Dir):
global sig_files global sig_files
sig_files.append(self) sig_files.append(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): def write(self, sync=1):
""" """
Write the .sconsign file to disk. Write the .sconsign file to disk.
@ -275,48 +312,52 @@ class DirFile(Dir):
to the .sconsign file. Either way, always try to remove to the .sconsign file. Either way, always try to remove
the temporary file at the end. the temporary file at the end.
""" """
if self.dirty: if not self.dirty:
temp = os.path.join(self.dir.path, '.scons%d' % os.getpid()) return
self.merge()
temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
try:
file = open(temp, 'wb')
fname = temp
except IOError:
try: try:
file = open(temp, 'wb') file = open(self.sconsign, 'wb')
fname = temp fname = self.sconsign
except IOError: except IOError:
try: return
file = open(self.sconsign, 'wb') for key, entry in self.entries.items():
fname = self.sconsign entry.convert_to_sconsign()
except IOError: cPickle.dump(self.entries, file, 1)
return file.close()
for key, entry in self.entries.items(): if fname != self.sconsign:
entry.convert_to_sconsign()
cPickle.dump(self.entries, file, 1)
file.close()
if fname != self.sconsign:
try:
mode = os.stat(self.sconsign)[0]
os.chmod(self.sconsign, 0666)
os.unlink(self.sconsign)
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: try:
os.unlink(temp) mode = os.stat(self.sconsign)[0]
os.chmod(self.sconsign, 0666)
os.unlink(self.sconsign)
except (IOError, 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 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 (IOError, OSError):
pass
ForDirectory = DB ForDirectory = DB

View file

@ -27,7 +27,7 @@ This module implements the depenency scanner for C/C++ code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/C.py 2523 2007/12/12 09:37:41 knight"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner

View file

@ -30,7 +30,7 @@ Coded by Andy Friesen
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/D.py 2523 2007/12/12 09:37:41 knight"
import string import string

View file

@ -21,7 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Scanner/Dir.py 2523 2007/12/12 09:37:41 knight"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner

View file

@ -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. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/Fortran.py 2523 2007/12/12 09:37:41 knight"
import re import re
import string import string

View file

@ -28,7 +28,7 @@ Definition Language) files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/IDL.py 2523 2007/12/12 09:37:41 knight"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner

View file

@ -27,19 +27,19 @@ This module implements the dependency scanner for LaTeX code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Scanner/LaTeX.py 2523 2007/12/12 09:37:41 knight"
import os.path
import string
import SCons.Scanner import SCons.Scanner
import string
import os.path
def LaTeXScanner(fs = SCons.Node.FS.default_fs): def LaTeXScanner():
"""Return a prototype Scanner instance for scanning LaTeX source files""" """Return a prototype Scanner instance for scanning LaTeX source files"""
ds = LaTeX(name = "LaTeXScanner", ds = LaTeX(name = "LaTeXScanner",
suffixes = '$LATEXSUFFIXES', suffixes = '$LATEXSUFFIXES',
path_variable = 'TEXINPUTS', path_variable = 'TEXINPUTS',
regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography){([^}]*)}', regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}',
recursive = 0) recursive = 0)
return ds return ds
@ -72,6 +72,10 @@ class LaTeX(SCons.Scanner.Classic):
base, ext = os.path.splitext( filename ) base, ext = os.path.splitext( filename )
if ext == "": if ext == "":
filename = filename + '.bib' filename = filename + '.bib'
if include[0] == 'usepackage':
base, ext = os.path.splitext( filename )
if ext == "":
filename = filename + '.sty'
return filename return filename
def sort_key(self, include): def sort_key(self, include):
return SCons.Node.FS._my_normcase(self.latex_name(include)) return SCons.Node.FS._my_normcase(self.latex_name(include))

View file

@ -21,7 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/Prog.py 2523 2007/12/12 09:37:41 knight"
import string import string

View file

@ -27,13 +27,12 @@ The Scanner package for the SCons software construction utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Scanner/__init__.py 2523 2007/12/12 09:37:41 knight"
import re import re
import string import string
import SCons.Node.FS import SCons.Node.FS
import SCons.Sig
import SCons.Util import SCons.Util
@ -306,8 +305,7 @@ class Current(Base):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
def current_check(node, env): def current_check(node, env):
c = not node.has_builder() or node.current(env.get_calculator()) return not node.has_builder() or node.is_up_to_date()
return c
kw['scan_check'] = current_check kw['scan_check'] = current_check
apply(Base.__init__, (self,) + args, kw) apply(Base.__init__, (self,) + args, kw)

View file

@ -0,0 +1,884 @@
#
# 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__ = "src/engine/SCons/Script/SConsOptions.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat
import optparse
import string
import sys
import textwrap
try:
from gettext import gettext
except ImportError:
def gettext(message):
return message
_ = gettext
import SCons.Node.FS
OptionValueError = optparse.OptionValueError
SUPPRESS_HELP = optparse.SUPPRESS_HELP
diskcheck_all = SCons.Node.FS.diskcheck_types()
def diskcheck_convert(value):
if value is None:
return []
if not SCons.Util.is_List(value):
value = string.split(value, ',')
result = []
for v in map(string.lower, value):
if v == 'all':
result = diskcheck_all
elif v == 'none':
result = []
elif v in diskcheck_all:
result.append(v)
else:
raise ValueError, v
return result
class SConsValues(optparse.Values):
"""
Holder class for uniform access to SCons options, regardless
of whether or not they can be set on the command line or in the
SConscript files (using the SetOption() function).
A SCons option value can originate three different ways:
1) set on the command line;
2) set in an SConscript file;
3) the default setting (from the the op.add_option()
calls in the Parser() function, below).
The command line always overrides a value set in a SConscript file,
which in turn always overrides default settings. Because we want
to support user-specified options in the SConscript file itself,
though, we may not know about all of the options when the command
line is first parsed, so we can't make all the necessary precedence
decisions at the time the option is configured.
The solution implemented in this class is to keep these different sets
of settings separate (command line, SConscript file, and default)
and to override the __getattr__() method to check them in turn.
This should allow the rest of the code to just fetch values as
attributes of an instance of this class, without having to worry
about where they came from.
Note that not all command line options are settable from SConscript
files, and the ones that are must be explicitly added to the
"settable" list in this class, and optionally validated and coerced
in the set_option() method.
"""
def __init__(self, defaults):
self.__dict__['__defaults__'] = defaults
self.__dict__['__SConscript_settings__'] = {}
def __getattr__(self, attr):
"""
Fetches an options value, checking first for explicit settings
from the command line (which are direct attributes), then the
SConscript file settings, then the default values.
"""
try:
return self.__dict__[attr]
except KeyError:
try:
return self.__dict__['__SConscript_settings__'][attr]
except KeyError:
return getattr(self.__dict__['__defaults__'], attr)
settable = [
'clean',
'diskcheck',
'duplicate',
'help',
'implicit_cache',
'max_drift',
'no_exec',
'num_jobs',
'random',
]
def set_option(self, name, value):
"""
Sets an option from an SConscript file.
"""
if not name in self.settable:
raise SCons.Errors.UserError, "This option is not settable from a SConscript file: %s"%name
if name == 'num_jobs':
try:
value = int(value)
if value < 1:
raise ValueError
except ValueError:
raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value)
elif name == 'max_drift':
try:
value = int(value)
except ValueError:
raise SCons.Errors.UserError, "An integer is required: %s"%repr(value)
elif name == 'duplicate':
try:
value = str(value)
except ValueError:
raise SCons.Errors.UserError, "A string is required: %s"%repr(value)
if not value in SCons.Node.FS.Valid_Duplicates:
raise SCons.Errors.UserError, "Not a valid duplication style: %s" % value
# Set the duplicate style right away so it can affect linking
# of SConscript files.
SCons.Node.FS.set_duplicate(value)
elif name == 'diskcheck':
try:
value = diskcheck_convert(value)
except ValueError, v:
raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v
if not self.__dict__.has_key('diskcheck'):
# No --diskcheck= option was specified on the command line.
# Set this right away so it can affect the rest of the
# file/Node lookups while processing the SConscript files.
SCons.Node.FS.set_diskcheck(value)
self.__SConscript_settings__[name] = value
class SConsOption(optparse.Option):
def convert_value(self, opt, value):
if value is not None:
if self.nargs in (1, '?'):
return self.check_value(opt, value)
else:
return tuple(map(lambda v, o=opt, s=self: s.check_value(o, v), value))
def process(self, opt, value, values, parser):
# First, convert the value(s) to the right type. Howl if any
# value(s) are bogus.
value = self.convert_value(opt, value)
# And then take whatever action is expected of us.
# This is a separate method to make life easier for
# subclasses to add new actions.
return self.take_action(
self.action, self.dest, opt, value, values, parser)
def _check_nargs_optional(self):
if self.nargs == '?' and self._short_opts:
fmt = "option %s: nargs='?' is incompatible with short options"
raise SCons.Errors.UserError, fmt % self._short_opts[0]
try:
_orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS
_orig_CHECK_METHODS = optparse.Option.CHECK_METHODS
except AttributeError:
# optparse.Option had no CONST_ACTIONS before Python 2.5.
_orig_CONST_ACTIONS = ("store_const",)
def _check_const(self):
if self.action not in self.CONST_ACTIONS and self.const is not None:
raise OptionError(
"'const' must not be supplied for action %r" % self.action,
self)
# optparse.Option collects its list of unbound check functions
# up front. This sucks because it means we can't just override
# the _check_const() function like a normal method, we have to
# actually replace it in the list. This seems to be the most
# straightforward way to do that.
_orig_CHECK_METHODS = [optparse.Option._check_action,
optparse.Option._check_type,
optparse.Option._check_choice,
optparse.Option._check_dest,
_check_const,
optparse.Option._check_nargs,
optparse.Option._check_callback]
CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional]
CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
class SConsOptionGroup(optparse.OptionGroup):
"""
A subclass for SCons-specific option groups.
The only difference between this and the base class is that we print
the group's help text flush left, underneath their own title but
lined up with the normal "SCons Options".
"""
def format_help(self, formatter):
"""
Format an option group's help text, outdenting the title so it's
flush with the "SCons Options" title we print at the top.
"""
formatter.dedent()
result = formatter.format_heading(self.title)
formatter.indent()
result = result + optparse.OptionContainer.format_help(self, formatter)
return result
class SConsOptionParser(optparse.OptionParser):
preserve_unknown_options = False
def error(self, msg):
self.print_usage(sys.stderr)
sys.stderr.write("SCons error: %s\n" % msg)
sys.exit(2)
def _process_long_opt(self, rargs, values):
"""
SCons-specific processing of long options.
This is copied directly from the normal
optparse._process_long_opt() method, except that, if configured
to do so, we catch the exception thrown when an unknown option
is encountered and just stick it back on the "leftover" arguments
for later (re-)processing.
"""
arg = rargs.pop(0)
# Value explicitly attached to arg? Pretend it's the next
# argument.
if "=" in arg:
(opt, next_arg) = string.split(arg, "=", 1)
rargs.insert(0, next_arg)
had_explicit_value = True
else:
opt = arg
had_explicit_value = False
try:
opt = self._match_long_opt(opt)
except optparse.BadOptionError:
if self.preserve_unknown_options:
# SCons-specific: if requested, add unknown options to
# the "leftover arguments" list for later processing.
self.largs.append(arg)
if had_explicit_value:
# The unknown option will be re-processed later,
# so undo the insertion of the explicit value.
rargs.pop(0)
return
raise
option = self._long_opt[opt]
if option.takes_value():
nargs = option.nargs
if nargs == '?':
if had_explicit_value:
value = rargs.pop(0)
else:
value = option.const
elif len(rargs) < nargs:
if nargs == 1:
self.error(_("%s option requires an argument") % opt)
else:
self.error(_("%s option requires %d arguments")
% (opt, nargs))
elif nargs == 1:
value = rargs.pop(0)
else:
value = tuple(rargs[0:nargs])
del rargs[0:nargs]
elif had_explicit_value:
self.error(_("%s option does not take a value") % opt)
else:
value = None
option.process(opt, value, values, self)
def add_local_option(self, *args, **kw):
"""
Adds a local option to the parser.
This is initiated by a SetOption() call to add a user-defined
command-line option. We add the option to a separate option
group for the local options, creating the group if necessary.
"""
try:
group = self.local_option_group
except AttributeError:
group = SConsOptionGroup(self, 'Local Options')
group = self.add_option_group(group)
self.local_option_group = group
result = apply(group.add_option, args, kw)
if result:
# The option was added succesfully. We now have to add the
# default value to our object that holds the default values
# (so that an attempt to fetch the option's attribute will
# yield the default value when not overridden) and then
# we re-parse the leftover command-line options, so that
# any value overridden on the command line is immediately
# available if the user turns around and does a GetOption()
# right away.
setattr(self.values.__defaults__, result.dest, result.default)
self.parse_args(self.largs, self.values)
return result
class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter):
def format_usage(self, usage):
return "usage: %s\n" % usage
def format_heading(self, heading):
"""
This translates any heading of "options" or "Options" into
"SCons Options." Unfortunately, we have to do this here,
because those titles are hard-coded in the optparse calls.
"""
if heading == 'options':
# The versions of optparse.py shipped with Pythons 2.3 and
# 2.4 pass this in uncapitalized; override that so we get
# consistent output on all versions.
heading = "Options"
if heading == 'Options':
heading = "SCons Options"
return optparse.IndentedHelpFormatter.format_heading(self, heading)
def format_option(self, option):
"""
A copy of the normal optparse.IndentedHelpFormatter.format_option()
method, snarfed so we can set the subsequent_indent on the
textwrap.wrap() call below...
"""
# The help for each option consists of two parts:
# * the opt strings and metavars
# eg. ("-x", or "-fFILENAME, --file=FILENAME")
# * the user-supplied help string
# eg. ("turn on expert mode", "read data from FILENAME")
#
# If possible, we write both of these on the same line:
# -x turn on expert mode
#
# But if the opt string list is too long, we put the help
# string on a second line, indented to the same column it would
# start in if it fit on the first line.
# -fFILENAME, --file=FILENAME
# read data from FILENAME
result = []
try:
opts = self.option_strings[option]
except AttributeError:
# The Python 2.3 version of optparse attaches this to
# to the option argument, not to this object.
opts = option.option_strings
opt_width = self.help_position - self.current_indent - 2
if len(opts) > opt_width:
opts = "%*s%s\n" % (self.current_indent, "", opts)
indent_first = self.help_position
else: # start help on same line as opts
opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts)
indent_first = 0
result.append(opts)
if option.help:
try:
expand_default = self.expand_default
except AttributeError:
# The HelpFormatter base class in the Python 2.3 version
# of optparse has no expand_default() method.
help_text = option.help
else:
help_text = expand_default(option)
# SCons: indent every line of the help text but the first.
help_lines = textwrap.wrap(help_text, self.help_width,
subsequent_indent = ' ')
result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
for line in help_lines[1:]:
result.append("%*s%s\n" % (self.help_position, "", line))
elif opts[-1] != "\n":
result.append("\n")
return string.join(result, "")
# For consistent help output across Python versions, we provide a
# subclass copy of format_option_strings() and these two variables.
# This is necessary (?) for Python2.3, which otherwise concatenates
# a short option with its metavar.
_short_opt_fmt = "%s %s"
_long_opt_fmt = "%s=%s"
def format_option_strings(self, option):
"""Return a comma-separated list of option strings & metavariables."""
if option.takes_value():
metavar = option.metavar or string.upper(option.dest)
short_opts = []
for sopt in option._short_opts:
short_opts.append(self._short_opt_fmt % (sopt, metavar))
long_opts = []
for lopt in option._long_opts:
long_opts.append(self._long_opt_fmt % (lopt, metavar))
else:
short_opts = option._short_opts
long_opts = option._long_opts
if self.short_first:
opts = short_opts + long_opts
else:
opts = long_opts + short_opts
return string.join(opts, ", ")
def Parser(version):
"""
Returns an options parser object initialized with the standard
SCons options.
"""
formatter = SConsIndentedHelpFormatter(max_help_position=30)
op = SConsOptionParser(option_class=SConsOption,
add_help_option=False,
formatter=formatter,
usage="usage: scons [OPTION] [TARGET] ...",)
op.preserve_unknown_options = True
# Add the options to the parser we just created.
#
# These are in the order we want them to show up in the -H help
# text, basically alphabetical. Each op.add_option() call below
# should have a consistent format:
#
# op.add_option("-L", "--long-option-name",
# nargs=1, type="string",
# dest="long_option_name", default='foo',
# action="callback", callback=opt_long_option,
# help="help text goes here",
# metavar="VAR")
#
# Even though the optparse module constructs reasonable default
# destination names from the long option names, we're going to be
# explicit about each one for easier readability and so this code
# will at least show up when grepping the source for option attribute
# names, or otherwise browsing the source code.
# options ignored for compatibility
def opt_ignore(option, opt, value, parser):
sys.stderr.write("Warning: ignoring %s option\n" % opt)
op.add_option("-b", "-m", "-S", "-t",
"--no-keep-going", "--stop", "--touch",
action="callback", callback=opt_ignore,
help="Ignored for compatibility.")
op.add_option('-c', '--clean', '--remove',
dest="clean", default=False,
action="store_true",
help="Remove specified targets and dependencies.")
op.add_option('-C', '--directory',
nargs=1, type="string",
dest="directory", default=[],
action="append",
help="Change to DIR before doing anything.",
metavar="DIR")
op.add_option('--cache-debug',
nargs=1,
dest="cache_debug", default=None,
action="store",
help="Print CacheDir debug info to FILE.",
metavar="FILE")
op.add_option('--cache-disable', '--no-cache',
dest='cache_disable', default=False,
action="store_true",
help="Do not retrieve built targets from CacheDir.")
op.add_option('--cache-force', '--cache-populate',
dest='cache_force', default=False,
action="store_true",
help="Copy already-built targets into the CacheDir.")
op.add_option('--cache-show',
dest='cache_show', default=False,
action="store_true",
help="Print build actions for files from CacheDir.")
config_options = ["auto", "force" ,"cache"]
def opt_config(option, opt, value, parser, c_options=config_options):
if not value in c_options:
raise OptionValueError("Warning: %s is not a valid config type" % value)
setattr(parser.values, option.dest, value)
opt_config_help = "Controls Configure subsystem: %s." \
% string.join(config_options, ", ")
op.add_option('--config',
nargs=1, type="string",
dest="config", default="auto",
action="callback", callback=opt_config,
help = opt_config_help,
metavar="MODE")
def opt_not_yet(option, opt, value, parser):
sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
sys.exit(0)
op.add_option('-d',
action="callback", callback=opt_not_yet,
help = "Print file dependency information.")
op.add_option('-D',
dest="climb_up", default=None,
action="store_const", const=2,
help="Search up directory tree for SConstruct, "
"build all Default() targets.")
debug_options = ["count", "dtree", "explain", "findlibs",
"includes", "memoizer", "memory", "objects",
"pdb", "presub", "stacktrace", "stree",
"time", "tree"]
deprecated_debug_options = {
"nomemoizer" : ' and has no effect',
}
def opt_debug(option, opt, value, parser,
debug_options=debug_options,
deprecated_debug_options=deprecated_debug_options):
if value in debug_options:
parser.values.debug.append(value)
elif value in deprecated_debug_options.keys():
try:
parser.values.delayed_warnings
except AttributeError:
parser.values.delayed_warnings = []
msg = deprecated_debug_options[value]
w = "The --debug=%s option is deprecated%s." % (value, msg)
t = (SCons.Warnings.DeprecatedWarning, w)
parser.values.delayed_warnings.append(t)
else:
raise OptionValueError("Warning: %s is not a valid debug type" % value)
opt_debug_help = "Print various types of debugging information: %s." \
% string.join(debug_options, ", ")
op.add_option('--debug',
nargs=1, type="string",
dest="debug", default=[],
action="callback", callback=opt_debug,
help=opt_debug_help,
metavar="TYPE")
def opt_diskcheck(option, opt, value, parser):
try:
diskcheck_value = diskcheck_convert(value)
except ValueError, e:
raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e)
setattr(parser.values, option.dest, diskcheck_value)
op.add_option('--diskcheck',
nargs=1, type="string",
dest='diskcheck', default=None,
action="callback", callback=opt_diskcheck,
help="Enable specific on-disk checks.",
metavar="TYPE")
def opt_duplicate(option, opt, value, parser):
if not value in SCons.Node.FS.Valid_Duplicates:
raise OptionValueError("`%s' is not a valid duplication style." % value)
setattr(parser.values, option.dest, value)
# Set the duplicate style right away so it can affect linking
# of SConscript files.
SCons.Node.FS.set_duplicate(value)
opt_duplicate_help = "Set the preferred duplication methods. Must be one of " \
+ string.join(SCons.Node.FS.Valid_Duplicates, ", ")
op.add_option('--duplicate',
nargs=1, type="string",
dest="duplicate", default='hard-soft-copy',
action="callback", callback=opt_duplicate,
help=opt_duplicate_help)
op.add_option('-f', '--file', '--makefile', '--sconstruct',
nargs=1, type="string",
dest="file", default=[],
action="append",
help="Read FILE as the top-level SConstruct file.")
op.add_option('-h', '--help',
dest="help", default=False,
action="store_true",
help="Print defined help message, or this one.")
op.add_option("-H", "--help-options",
action="help",
help="Print this message and exit.")
op.add_option('-i', '--ignore-errors',
dest='ignore_errors', default=False,
action="store_true",
help="Ignore errors from build actions.")
op.add_option('-I', '--include-dir',
nargs=1,
dest='include_dir', default=[],
action="append",
help="Search DIR for imported Python modules.",
metavar="DIR")
op.add_option('--implicit-cache',
dest='implicit_cache', default=False,
action="store_true",
help="Cache implicit dependencies")
def opt_implicit_deps(option, opt, value, parser):
setattr(parser.values, 'implicit_cache', True)
setattr(parser.values, option.dest, True)
op.add_option('--implicit-deps-changed',
dest="implicit_deps_changed", default=False,
action="callback", callback=opt_implicit_deps,
help="Ignore cached implicit dependencies.")
op.add_option('--implicit-deps-unchanged',
dest="implicit_deps_unchanged", default=False,
action="callback", callback=opt_implicit_deps,
help="Ignore changes in implicit dependencies.")
op.add_option('-j', '--jobs',
nargs=1, type="int",
dest="num_jobs", default=1,
action="store",
help="Allow N jobs at once.",
metavar="N")
op.add_option('-k', '--keep-going',
dest='keep_going', default=False,
action="store_true",
help="Keep going when a target can't be made.")
op.add_option('--max-drift',
nargs=1, type="int",
dest='max_drift', default=SCons.Node.FS.default_max_drift,
action="store",
help="Set maximum system clock drift to N seconds.",
metavar="N")
op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon',
dest='no_exec', default=False,
action="store_true",
help="Don't build; just print commands.")
op.add_option('--no-site-dir',
dest='no_site_dir', default=False,
action="store_true",
help="Don't search or use the usual site_scons dir.")
op.add_option('--profile',
nargs=1,
dest="profile_file", default=None,
action="store",
help="Profile SCons and put results in FILE.",
metavar="FILE")
op.add_option('-q', '--question',
dest="question", default=False,
action="store_true",
help="Don't build; exit status says if up to date.")
op.add_option('-Q',
dest='no_progress', default=False,
action="store_true",
help="Suppress \"Reading/Building\" progress messages.")
op.add_option('--random',
dest="random", default=False,
action="store_true",
help="Build dependencies in random order.")
op.add_option('-s', '--silent', '--quiet',
dest="silent", default=False,
action="store_true",
help="Don't print commands.")
op.add_option('--site-dir',
nargs=1,
dest='site_dir', default=None,
action="store",
help="Use DIR instead of the usual site_scons dir.",
metavar="DIR")
op.add_option('--taskmastertrace',
nargs=1,
dest="taskmastertrace_file", default=None,
action="store",
help="Trace Node evaluation to FILE.",
metavar="FILE")
tree_options = ["all", "derived", "prune", "status"]
def opt_tree(option, opt, value, parser, tree_options=tree_options):
import Main
tp = Main.TreePrinter()
for o in string.split(value, ','):
if o == 'all':
tp.derived = False
elif o == 'derived':
tp.derived = True
elif o == 'prune':
tp.prune = True
elif o == 'status':
tp.status = True
else:
raise OptionValueError("Warning: %s is not a valid --tree option" % o)
parser.values.tree_printers.append(tp)
opt_tree_help = "Print a dependency tree in various formats: %s." \
% string.join(tree_options, ", ")
op.add_option('--tree',
nargs=1, type="string",
dest="tree_printers", default=[],
action="callback", callback=opt_tree,
help=opt_tree_help,
metavar="OPTIONS")
op.add_option('-u', '--up', '--search-up',
dest="climb_up", default=0,
action="store_const", const=1,
help="Search up directory tree for SConstruct, "
"build targets at or below current directory.")
op.add_option('-U',
dest="climb_up", default=0,
action="store_const", const=3,
help="Search up directory tree for SConstruct, "
"build Default() targets from local SConscript.")
def opt_version(option, opt, value, parser, version=version):
sys.stdout.write(version + '\n')
sys.exit(0)
op.add_option("-v", "--version",
action="callback", callback=opt_version,
help="Print the SCons version number and exit.")
op.add_option('--warn', '--warning',
nargs=1,
dest="warn", default=None,
action="store",
help="Enable or disable warnings.",
metavar="WARNING-SPEC")
op.add_option('-Y', '--repository', '--srcdir',
nargs=1,
dest="repository", default=[],
action="append",
help="Search REPOSITORY for source and target files.")
# Options from Make and Cons classic that we do not yet support,
# but which we may support someday and whose (potential) meanings
# we don't want to change. These all get a "the -X option is not
# yet implemented" message and don't show up in the help output.
op.add_option('-e', '--environment-overrides',
dest="environment_overrides",
action="callback", callback=opt_not_yet,
# help="Environment variables override makefiles."
help=SUPPRESS_HELP)
op.add_option('-l', '--load-average', '--max-load',
nargs=1, type="int",
dest="load_average", default=0,
action="callback", callback=opt_not_yet,
# action="store",
# help="Don't start multiple jobs unless load is below "
# "LOAD-AVERAGE."
help=SUPPRESS_HELP)
op.add_option('--list-actions',
dest="list_actions",
action="callback", callback=opt_not_yet,
# help="Don't build; list files and build actions."
help=SUPPRESS_HELP)
op.add_option('--list-derived',
dest="list_derived",
action="callback", callback=opt_not_yet,
# help="Don't build; list files that would be built."
help=SUPPRESS_HELP)
op.add_option('--list-where',
dest="list_where",
action="callback", callback=opt_not_yet,
# help="Don't build; list files and where defined."
help=SUPPRESS_HELP)
op.add_option('-o', '--old-file', '--assume-old',
nargs=1, type="string",
dest="old_file", default=[],
action="callback", callback=opt_not_yet,
# action="append",
# help = "Consider FILE to be old; don't rebuild it."
help=SUPPRESS_HELP)
op.add_option('--override',
nargs=1, type="string",
action="callback", callback=opt_not_yet,
dest="override",
# help="Override variables as specified in FILE."
help=SUPPRESS_HELP)
op.add_option('-p',
action="callback", callback=opt_not_yet,
dest="p",
# help="Print internal environments/objects."
help=SUPPRESS_HELP)
op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables',
action="callback", callback=opt_not_yet,
dest="no_builtin_rules",
# help="Clear default environments and variables."
help=SUPPRESS_HELP)
op.add_option('-w', '--print-directory',
action="callback", callback=opt_not_yet,
dest="print_directory",
# help="Print the current directory."
help=SUPPRESS_HELP)
op.add_option('--no-print-directory',
action="callback", callback=opt_not_yet,
dest="no_print_directory",
# help="Turn off -w, even if it was turned on implicitly."
help=SUPPRESS_HELP)
op.add_option('--write-filenames',
nargs=1, type="string",
dest="write_filenames",
action="callback", callback=opt_not_yet,
# help="Write all filenames examined into FILE."
help=SUPPRESS_HELP)
op.add_option('-W', '--new-file', '--assume-new', '--what-if',
nargs=1, type="string",
dest="new_file",
action="callback", callback=opt_not_yet,
# help="Consider FILE to be changed."
help=SUPPRESS_HELP)
op.add_option('--warn-undefined-variables',
dest="warn_undefined_variables",
action="callback", callback=opt_not_yet,
# help="Warn when an undefined variable is referenced."
help=SUPPRESS_HELP)
return op

View file

@ -28,7 +28,7 @@ files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Script/SConscript.py 2523 2007/12/12 09:37:41 knight"
import SCons import SCons
import SCons.Action import SCons.Action
@ -65,6 +65,9 @@ import UserList
#CommandLineTargets = [] #CommandLineTargets = []
#DefaultTargets = [] #DefaultTargets = []
class SConscriptReturn(Exception):
pass
launch_dir = os.path.abspath(os.curdir) launch_dir = os.path.abspath(os.curdir)
GlobalDict = None GlobalDict = None
@ -125,6 +128,8 @@ class Frame:
# make sure the sconscript attr is a Node. # make sure the sconscript attr is a Node.
if isinstance(sconscript, SCons.Node.Node): if isinstance(sconscript, SCons.Node.Node):
self.sconscript = sconscript self.sconscript = sconscript
elif sconscript == '-':
self.sconscript = None
else: else:
self.sconscript = fs.File(str(sconscript)) self.sconscript = fs.File(str(sconscript))
@ -133,7 +138,7 @@ call_stack = []
# For documentation on the methods in this file, see the scons man-page # For documentation on the methods in this file, see the scons man-page
def Return(*vars): def Return(*vars, **kw):
retval = [] retval = []
try: try:
for var in vars: for var in vars:
@ -147,6 +152,11 @@ def Return(*vars):
else: else:
call_stack[-1].retval = tuple(retval) call_stack[-1].retval = tuple(retval)
stop = kw.get('stop', True)
if stop:
raise SConscriptReturn
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
@ -242,7 +252,10 @@ def _SConscript(fs, *files, **kw):
except KeyError: except KeyError:
pass pass
try: try:
exec _file_ in call_stack[-1].globals try:
exec _file_ in call_stack[-1].globals
except SConscriptReturn:
pass
finally: finally:
if old_file is not None: if old_file is not None:
call_stack[-1].globals.update({__file__:old_file}) call_stack[-1].globals.update({__file__:old_file})
@ -469,7 +482,7 @@ class SConsEnvironment(SCons.Environment.Base):
def GetOption(self, name): def GetOption(self, name):
name = self.subst(name) name = self.subst(name)
return SCons.Script.Main.ssoptions.get(name) return SCons.Script.Main.GetOption(name)
def Help(self, text): def Help(self, text):
text = self.subst(text, raw=1) text = self.subst(text, raw=1)
@ -525,7 +538,7 @@ class SConsEnvironment(SCons.Environment.Base):
def SetOption(self, name, value): def SetOption(self, name, value):
name = self.subst(name) name = self.subst(name)
SCons.Script.Main.ssoptions.set(name, value) SCons.Script.Main.SetOption(name, value)
# #
# #

View file

@ -34,7 +34,7 @@ it goes here.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Script/__init__.py 2523 2007/12/12 09:37:41 knight"
import time import time
start_time = time.time() start_time = time.time()
@ -70,7 +70,7 @@ if "--debug=memoizer" in _args:
# for it to be displayed or not after warnings are configured. # for it to be displayed or not after warnings are configured.
import Main import Main
exc_type, exc_value, tb = sys.exc_info() exc_type, exc_value, tb = sys.exc_info()
Main.delayed_warnings.append(exc_type, exc_value) Main.delayed_warnings.append((exc_type, exc_value))
del _args del _args
import SCons.Action import SCons.Action
@ -105,23 +105,28 @@ BuildTask = Main.BuildTask
CleanTask = Main.CleanTask CleanTask = Main.CleanTask
QuestionTask = Main.QuestionTask QuestionTask = Main.QuestionTask
#PrintHelp = Main.PrintHelp #PrintHelp = Main.PrintHelp
OptParser = Main.OptParser #SConscriptSettableOptions = Main.SConscriptSettableOptions
SConscriptSettableOptions = Main.SConscriptSettableOptions
keep_going_on_error = Main.keep_going_on_error AddOption = Main.AddOption
GetOption = Main.GetOption
SetOption = Main.SetOption
Progress = Main.Progress
GetBuildFailures = Main.GetBuildFailures
#keep_going_on_error = Main.keep_going_on_error
#print_dtree = Main.print_dtree #print_dtree = Main.print_dtree
print_explanations = Main.print_explanations #print_explanations = Main.print_explanations
print_includes = Main.print_includes #print_includes = Main.print_includes
print_objects = Main.print_objects #print_objects = Main.print_objects
print_time = Main.print_time #print_time = Main.print_time
#print_tree = Main.print_tree #print_tree = Main.print_tree
memory_stats = Main.memory_stats #memory_stats = Main.memory_stats
ignore_errors = Main.ignore_errors #ignore_errors = Main.ignore_errors
#sconscript_time = Main.sconscript_time #sconscript_time = Main.sconscript_time
#command_time = Main.command_time #command_time = Main.command_time
#exit_status = Main.exit_status #exit_status = Main.exit_status
#profiling = Main.profiling #profiling = Main.profiling
repositories = Main.repositories #repositories = Main.repositories
# #
import SConscript import SConscript
@ -131,12 +136,14 @@ call_stack = _SConscript.call_stack
# #
Action = SCons.Action.Action Action = SCons.Action.Action
AddMethod = SCons.Util.AddMethod
AllowSubstExceptions = SCons.Subst.SetAllowableExceptions AllowSubstExceptions = SCons.Subst.SetAllowableExceptions
BoolOption = SCons.Options.BoolOption BoolOption = SCons.Options.BoolOption
Builder = SCons.Builder.Builder Builder = SCons.Builder.Builder
Configure = _SConscript.Configure Configure = _SConscript.Configure
EnumOption = SCons.Options.EnumOption EnumOption = SCons.Options.EnumOption
Environment = SCons.Environment.Environment Environment = SCons.Environment.Environment
#OptParser = SCons.SConsOptions.OptParser
FindPathDirs = SCons.Scanner.FindPathDirs FindPathDirs = SCons.Scanner.FindPathDirs
ListOption = SCons.Options.ListOption ListOption = SCons.Options.ListOption
PackageOption = SCons.Options.PackageOption PackageOption = SCons.Options.PackageOption
@ -255,7 +262,7 @@ def HelpFunction(text):
sconscript_reading = 0 sconscript_reading = 0
# #
def Options(files=None, args=ARGUMENTS): def Options(files=[], args=ARGUMENTS):
return SCons.Options.Options(files, args) return SCons.Options.Options(files, args)
# The list of global functions to add to the SConscript name space # The list of global functions to add to the SConscript name space
@ -269,12 +276,10 @@ GlobalDefaultEnvironmentFunctions = [
'Exit', 'Exit',
'Export', 'Export',
'GetLaunchDir', 'GetLaunchDir',
'GetOption',
'Help', 'Help',
'Import', 'Import',
#'SConscript', is handled separately, below. #'SConscript', is handled separately, below.
'SConscriptChdir', 'SConscriptChdir',
'SetOption',
# Methods from the Environment.Base class. # Methods from the Environment.Base class.
'AddPostAction', 'AddPostAction',
@ -285,6 +290,7 @@ GlobalDefaultEnvironmentFunctions = [
'CacheDir', 'CacheDir',
'Clean', 'Clean',
#The Command() method is handled separately, below. #The Command() method is handled separately, below.
'Decider',
'Depends', 'Depends',
'Dir', 'Dir',
'NoClean', 'NoClean',
@ -293,8 +299,11 @@ GlobalDefaultEnvironmentFunctions = [
'Execute', 'Execute',
'File', 'File',
'FindFile', 'FindFile',
'FindInstalledFiles',
'FindSourceFiles',
'Flatten', 'Flatten',
'GetBuildPath', 'GetBuildPath',
'Glob',
'Ignore', 'Ignore',
'Install', 'Install',
'InstallAs', 'InstallAs',
@ -303,11 +312,13 @@ GlobalDefaultEnvironmentFunctions = [
'ParseDepends', 'ParseDepends',
'Precious', 'Precious',
'Repository', 'Repository',
'Requires',
'SConsignFile', 'SConsignFile',
'SideEffect', 'SideEffect',
'SourceCode', 'SourceCode',
'SourceSignatures', 'SourceSignatures',
'Split', 'Split',
'Tag',
'TargetSignatures', 'TargetSignatures',
'Value', 'Value',
] ]
@ -337,6 +348,7 @@ GlobalDefaultBuilders = [
'Tar', 'Tar',
'TypeLibrary', 'TypeLibrary',
'Zip', 'Zip',
'Package',
] ]
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:

View file

@ -0,0 +1,57 @@
#
# 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__ = "src/engine/SCons/Sig.py 2523 2007/12/12 09:37:41 knight"
__doc__ = """Place-holder for the old SCons.Sig module hierarchy
This is no longer used, but code out there (such as the NSIS module on
the SCons wiki) may try to import SCons.Sig. If so, we generate a warning
that points them to the line that caused the import, and don't die.
If someone actually tried to use the sub-modules or functions within
the package (for example, SCons.Sig.MD5.signature()), then they'll still
get an AttributeError, but at least they'll know where to start looking.
"""
import SCons.Util
import SCons.Warnings
msg = 'The SCons.Sig module no longer exists.\n' \
' Remove the following "import SCons.Sig" line to eliminate this warning:'
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, msg)
default_calc = None
default_module = None
class MD5Null(SCons.Util.Null):
def __repr__(self):
return "MD5Null()"
class TimeStampNull(SCons.Util.Null):
def __repr__(self):
return "TimeStampNull()"
MD5 = MD5Null()
TimeStamp = TimeStampNull()

View file

@ -27,7 +27,7 @@ SCons string substitution.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Subst.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat import SCons.compat

View file

@ -48,7 +48,7 @@ interface and the SCons build engine. There are two key classes here:
target(s) that it decides need to be evaluated and/or built. 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" __revision__ = "src/engine/SCons/Taskmaster.py 2523 2007/12/12 09:37:41 knight"
import SCons.compat import SCons.compat
@ -205,20 +205,40 @@ class Task:
raise SCons.Errors.TaskmasterException(self.targets[0], raise SCons.Errors.TaskmasterException(self.targets[0],
sys.exc_info()) sys.exc_info())
def executed(self): def executed_without_callbacks(self):
""" """
Called when the task has been successfully executed. Called when the task has been successfully executed
and the Taskmaster instance doesn't want to call
This may have been a do-nothing operation (to preserve build the Node's callback methods.
order), so we have to check the node's state before deciding
whether it was "built" or just "visited."
""" """
for t in self.targets: for t in self.targets:
if t.get_state() == SCons.Node.executing: if t.get_state() == SCons.Node.executing:
for side_effect in t.side_effects:
side_effect.set_state(SCons.Node.no_state)
t.set_state(SCons.Node.executed)
def executed_with_callbacks(self):
"""
Called when the task has been successfully executed and
the Taskmaster instance wants to call the Node's callback
methods.
This may have been a do-nothing operation (to preserve build
order), so we must check the node's state before deciding whether
it was "built", in which case we call the appropriate Node method.
In any event, we always call "visited()", which will handle any
post-visit actions that must take place regardless of whether
or not the target was an actual built target or a source Node.
"""
for t in self.targets:
if t.get_state() == SCons.Node.executing:
for side_effect in t.side_effects:
side_effect.set_state(SCons.Node.no_state)
t.set_state(SCons.Node.executed) t.set_state(SCons.Node.executed)
t.built() t.built()
else: t.visited()
t.visited()
executed = executed_with_callbacks
def failed(self): def failed(self):
""" """
@ -276,7 +296,9 @@ class Task:
self.out_of_date = [] self.out_of_date = []
for t in self.targets: for t in self.targets:
try: try:
is_up_to_date = t.disambiguate().current() t.disambiguate().make_ready()
is_up_to_date = not t.has_builder() or \
(not t.always_build and t.is_up_to_date())
except EnvironmentError, e: except EnvironmentError, e:
raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename)
if is_up_to_date: if is_up_to_date:
@ -307,12 +329,14 @@ class Task:
# back on the candidates list if the Node is also a waiting # back on the candidates list if the Node is also a waiting
# parent. # parent.
targets = set(self.targets)
parents = {} parents = {}
for t in self.targets: for t in targets:
for p in t.waiting_parents.keys(): for p in t.waiting_parents.keys():
parents[p] = parents.get(p, 0) + 1 parents[p] = parents.get(p, 0) + 1
for t in self.targets: for t in targets:
for s in t.side_effects: for s in t.side_effects:
if s.get_state() == SCons.Node.executing: if s.get_state() == SCons.Node.executing:
s.set_state(SCons.Node.no_state) s.set_state(SCons.Node.no_state)
@ -328,7 +352,7 @@ class Task:
if p.ref_count == 0: if p.ref_count == 0:
self.tm.candidates.append(p) self.tm.candidates.append(p)
for t in self.targets: for t in targets:
t.postprocess() t.postprocess()
# Exception handling subsystem. # Exception handling subsystem.
@ -402,8 +426,9 @@ class Taskmaster:
""" """
def __init__(self, targets=[], tasker=Task, order=None, trace=None): def __init__(self, targets=[], tasker=Task, order=None, trace=None):
self.top_targets = targets[:] self.original_top = targets
self.top_targets.reverse() self.top_targets_left = targets[:]
self.top_targets_left.reverse()
self.candidates = [] self.candidates = []
self.tasker = tasker self.tasker = tasker
if not order: if not order:
@ -437,7 +462,7 @@ class Taskmaster:
except IndexError: except IndexError:
pass pass
try: try:
node = self.top_targets.pop() node = self.top_targets_left.pop()
except IndexError: except IndexError:
return None return None
self.current_top = node self.current_top = node
@ -510,7 +535,7 @@ class Taskmaster:
node.set_state(SCons.Node.pending) node.set_state(SCons.Node.pending)
try: try:
children = node.children() children = node.children() + node.prerequisites
except SystemExit: except SystemExit:
exc_value = sys.exc_info()[1] exc_value = sys.exc_info()[1]
e = SCons.Errors.ExplicitExit(node, exc_value.code) e = SCons.Errors.ExplicitExit(node, exc_value.code)
@ -535,16 +560,14 @@ class Taskmaster:
c.sort() c.sort()
T.write(' children:\n %s\n ' % c) T.write(' children:\n %s\n ' % c)
childinfo = map(lambda N: (N.get_state(), childstate = map(lambda N: (N, N.get_state()), children)
N.is_derived() or N.is_pseudo_derived(),
N), children)
# Skip this node if any of its children have failed. This # Skip this node if any of its children have failed. This
# catches the case where we're descending a top-level target # catches the case where we're descending a top-level target
# and one of our children failed while trying to be built # and one of our children failed while trying to be built
# by a *previous* descent of an earlier top-level target. # by a *previous* descent of an earlier top-level target.
failed_children = filter(lambda I: I[0] == SCons.Node.failed, failed_children = filter(lambda I: I[1] == SCons.Node.failed,
childinfo) childstate)
if failed_children: if failed_children:
node.set_state(SCons.Node.failed) node.set_state(SCons.Node.failed)
if S: S.child_failed = S.child_failed + 1 if S: S.child_failed = S.child_failed + 1
@ -555,76 +578,48 @@ class Taskmaster:
continue continue
# Detect dependency cycles: # Detect dependency cycles:
pending_nodes = filter(lambda I: I[0] == SCons.Node.pending, childinfo) pending_nodes = filter(lambda I: I[1] == SCons.Node.pending, childstate)
if pending_nodes: if pending_nodes:
for p in pending_nodes: for p in pending_nodes:
cycle = find_cycle([p[2], node]) cycle = find_cycle([p[0], node])
if cycle: if cycle:
desc = "Dependency cycle: " + string.join(map(str, cycle), " -> ") desc = "Dependency cycle: " + string.join(map(str, cycle), " -> ")
if T: T.write(' dependency cycle\n') if T: T.write(' dependency cycle\n')
raise SCons.Errors.UserError, desc raise SCons.Errors.UserError, desc
# Select all of the dependencies that are derived targets not_built = filter(lambda I: I[1] <= SCons.Node.executing, childstate)
# (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: if not_built:
not_built = map(lambda I: I[2], not_built)
# We're waiting on one or more derived targets that have # We're waiting on one or more derived targets that have
# started building but not yet finished. Add this node # not yet finished building.
# to the waiting parents lists of those derived files
# so that when they've finished building, our implicit not_visited = filter(lambda I: not I[1], not_built)
# dependency list will get cleared and we'll re-scan the if not_visited:
# newly-built file(s) for updated implicit dependencies. # Some of them haven't even been visited yet.
added = map(lambda n, P=node: n.add_to_waiting_parents(P), not_built) # Add them to the list so that on some next pass
node.ref_count = node.ref_count + reduce(operator.add, added, 0) # we can take a stab at evaluating them (or
# their children).
not_visited = map(lambda I: I[0], not_visited)
not_visited.reverse()
self.candidates.extend(self.order(not_visited))
n_b_nodes = map(lambda I: I[0], not_built)
# Add this node to the waiting parents lists of anything
# we're waiting on, with a reference count so we can be
# put back on the list for re-evaluation when they've
# all finished.
map(lambda n, P=node: n.add_to_waiting_parents(P), n_b_nodes)
node.ref_count = len(set(n_b_nodes))
if S: S.not_built = S.not_built + 1 if S: S.not_built = S.not_built + 1
if T: if T:
c = map(str, not_built) c = map(str, n_b_nodes)
c.sort() c.sort()
T.write(' waiting on unfinished children:\n %s\n' % c) T.write(' waiting on unfinished children:\n %s\n' % c)
continue continue
# Skip this node if it has side-effects that are currently being # Skip this node if it has side-effects that are
# built themselves or waiting for something else being built. # currently being built:
side_effects = filter(lambda N: side_effects = filter(lambda N:
N.get_state() == SCons.Node.executing, N.get_state() == SCons.Node.executing,
node.side_effects) node.side_effects)
@ -659,7 +654,7 @@ class Taskmaster:
tlist = node.get_executor().targets tlist = node.get_executor().targets
task = self.tasker(self, tlist, node is self.current_top, node) task = self.tasker(self, tlist, node in self.original_top, node)
try: try:
task.make_ready() task.make_ready()
except KeyboardInterrupt: except KeyboardInterrupt:

View file

@ -32,7 +32,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/386asm.py 2523 2007/12/12 09:37:41 knight"
from SCons.Tool.PharLapCommon import addPharLapPaths from SCons.Tool.PharLapCommon import addPharLapPaths
import SCons.Util import SCons.Util

View file

@ -32,7 +32,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/BitKeeper.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/CVS.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder

View file

@ -27,7 +27,7 @@ Stuff for processing Java.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/JavaCommon.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path
@ -36,6 +36,8 @@ import string
java_parsing = 1 java_parsing = 1
default_java_version = '1.4'
if java_parsing: if java_parsing:
# Parse Java files for class names. # Parse Java files for class names.
# #
@ -53,18 +55,26 @@ if java_parsing:
# array declarations "[]"; # array declarations "[]";
# semi-colons; # semi-colons;
# periods. # periods.
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.]|' + _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
r'[A-Za-z_][\w\.]*|/\*|\*/|\[\])') r'[A-Za-z_][\w\$\.]*|/\*|\*/|\[\])')
class OuterState: class OuterState:
"""The initial state for parsing a Java file for classes, """The initial state for parsing a Java file for classes,
interfaces, and anonymous inner classes.""" interfaces, and anonymous inner classes."""
def __init__(self): def __init__(self, version=default_java_version):
if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6'):
msg = "Java version %s not supported" % version
raise NotImplementedError, msg
self.version = version
self.listClasses = [] self.listClasses = []
self.listOutputs = [] self.listOutputs = []
self.stackBrackets = [] self.stackBrackets = []
self.brackets = 0 self.brackets = 0
self.nextAnon = 1 self.nextAnon = 1
self.stackAnonClassBrackets = []
self.anonStacksStack = [[0]]
self.package = None self.package = None
def trace(self): def trace(self):
@ -90,6 +100,7 @@ if java_parsing:
try: try:
return self.anonState return self.anonState
except AttributeError: except AttributeError:
self.outer_state = self
ret = SkipState(1, AnonClassState(self)) ret = SkipState(1, AnonClassState(self))
self.anonState = ret self.anonState = ret
return ret return ret
@ -101,6 +112,9 @@ if java_parsing:
ret = SkipState(1, self) ret = SkipState(1, self)
self.skipState = ret self.skipState = ret
return ret return ret
def __getAnonStack(self):
return self.anonStacksStack[-1]
def openBracket(self): def openBracket(self):
self.brackets = self.brackets + 1 self.brackets = self.brackets + 1
@ -111,7 +125,12 @@ if java_parsing:
self.brackets == self.stackBrackets[-1]: self.brackets == self.stackBrackets[-1]:
self.listOutputs.append(string.join(self.listClasses, '$')) self.listOutputs.append(string.join(self.listClasses, '$'))
self.listClasses.pop() self.listClasses.pop()
self.anonStacksStack.pop()
self.stackBrackets.pop() self.stackBrackets.pop()
if len(self.stackAnonClassBrackets) and \
self.brackets == self.stackAnonClassBrackets[-1]:
self.__getAnonStack().pop()
self.stackAnonClassBrackets.pop()
def parseToken(self, token): def parseToken(self, token):
if token[:2] == '//': if token[:2] == '//':
@ -145,32 +164,56 @@ if java_parsing:
def addAnonClass(self): def addAnonClass(self):
"""Add an anonymous inner class""" """Add an anonymous inner class"""
clazz = self.listClasses[0] if self.version in ('1.1', '1.2', '1.3', '1.4'):
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) clazz = self.listClasses[0]
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
elif self.version in ('1.5', '1.6'):
self.stackAnonClassBrackets.append(self.brackets)
className = []
className.extend(self.listClasses)
self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1
for anon in self.__getAnonStack():
className.append(str(anon))
self.listOutputs.append(string.join(className, '$'))
self.nextAnon = self.nextAnon + 1 self.nextAnon = self.nextAnon + 1
self.__getAnonStack().append(0)
def setPackage(self, package): def setPackage(self, package):
self.package = package self.package = package
class AnonClassState: class AnonClassState:
"""A state that looks for anonymous inner classes.""" """A state that looks for anonymous inner classes."""
def __init__(self, outer_state): def __init__(self, old_state):
# outer_state is always an instance of OuterState # outer_state is always an instance of OuterState
self.outer_state = outer_state self.outer_state = old_state.outer_state
self.tokens_to_find = 2 self.old_state = old_state
self.brace_level = 0
def parseToken(self, token): def parseToken(self, token):
# This is an anonymous class if and only if the next # This is an anonymous class if and only if the next
# non-whitespace token is a bracket # non-whitespace token is a bracket. Everything between
if token == '\n': # braces should be parsed as normal java code.
if token[:2] == '//':
return IgnoreState('\n', self)
elif token == '/*':
return IgnoreState('*/', self)
elif token == '\n':
return self
elif token == '(':
self.brace_level = self.brace_level + 1
return self
if self.brace_level > 0:
if token == 'new':
# look further for anonymous inner class
return SkipState(1, AnonClassState(self))
elif token in [ '"', "'" ]:
return IgnoreState(token, self)
elif token == ')':
self.brace_level = self.brace_level - 1
return self return self
if token == '{': if token == '{':
self.outer_state.openBracket()
self.outer_state.addAnonClass() self.outer_state.addAnonClass()
elif token == '}': return self.old_state.parseToken(token)
self.outer_state.closeBracket()
elif token in ['"', "'"]:
return IgnoreState(token, self)
return self.outer_state
class SkipState: class SkipState:
"""A state that will skip a specified number of tokens before """A state that will skip a specified number of tokens before
@ -194,6 +237,7 @@ if java_parsing:
if token == '\n': if token == '\n':
return self return self
self.outer_state.listClasses.append(token) self.outer_state.listClasses.append(token)
self.outer_state.anonStacksStack.append([0])
return self.outer_state return self.outer_state
class IgnoreState: class IgnoreState:
@ -217,15 +261,15 @@ if java_parsing:
self.outer_state.setPackage(token) self.outer_state.setPackage(token)
return self.outer_state return self.outer_state
def parse_java_file(fn): def parse_java_file(fn, version=default_java_version):
return parse_java(open(fn, 'r').read()) return parse_java(open(fn, 'r').read(), version)
def parse_java(contents, trace=None): def parse_java(contents, version=default_java_version, trace=None):
"""Parse a .java file and return a double of package directory, """Parse a .java file and return a double of package directory,
plus a list of .class files that compiling that .java file will plus a list of .class files that compiling that .java file will
produce""" produce"""
package = None package = None
initial = OuterState() initial = OuterState(version)
currstate = initial currstate = initial
for token in _reToken.findall(contents): for token in _reToken.findall(contents):
# The regex produces a bunch of groups, but only one will # The regex produces a bunch of groups, but only one will

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/Perforce.py 2523 2007/12/12 09:37:41 knight"
import os import os

View file

@ -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. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/PharLapCommon.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/RCS.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/SCCS.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/Subversion.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path

View file

@ -15,7 +15,7 @@ tool definition.
# #
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 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 # Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the # a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including # "Software"), to deal in the Software without restriction, including
@ -36,13 +36,14 @@ tool definition.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/__init__.py 2523 2007/12/12 09:37:41 knight"
import imp import imp
import sys import sys
import SCons.Builder import SCons.Builder
import SCons.Errors import SCons.Errors
import SCons.Node.FS
import SCons.Scanner import SCons.Scanner
import SCons.Scanner.C import SCons.Scanner.C
import SCons.Scanner.D import SCons.Scanner.D
@ -88,8 +89,11 @@ class Tool:
module = self._tool_module() module = self._tool_module()
self.generate = module.generate self.generate = module.generate
self.exists = module.exists self.exists = module.exists
if hasattr(module, 'options'):
self.options = module.options
def _tool_module(self): def _tool_module(self):
# TODO: Interchange zipimport with normal initilization for better error reporting
oldpythonpath = sys.path oldpythonpath = sys.path
sys.path = self.toolpath + sys.path sys.path = self.toolpath + sys.path
@ -102,6 +106,8 @@ class Tool:
if file: if file:
file.close() file.close()
except ImportError, e: except ImportError, e:
if str(e)!="No module named %s"%self.name:
raise SCons.Errors.EnvironmentError, e
try: try:
import zipimport import zipimport
except ImportError: except ImportError:
@ -130,6 +136,8 @@ class Tool:
file.close() file.close()
return module return module
except ImportError, e: except ImportError, e:
if e!="No module named %s"%self.name:
raise SCons.Errors.EnvironmentError, e
try: try:
import zipimport import zipimport
importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
@ -138,10 +146,10 @@ class Tool:
return module return module
except ImportError, e: except ImportError, e:
m = "No tool named '%s': %s" % (self.name, e) m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.UserError, m raise SCons.Errors.EnvironmentError, m
except ImportError, e: except ImportError, e:
m = "No tool named '%s': %s" % (self.name, e) m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.UserError, m raise SCons.Errors.EnvironmentError, m
def __call__(self, env, *args, **kw): def __call__(self, env, *args, **kw):
if self.init_kw is not None: if self.init_kw is not None:
@ -154,11 +162,24 @@ class Tool:
else: else:
kw = self.init_kw kw = self.init_kw
env.Append(TOOLS = [ self.name ]) env.Append(TOOLS = [ self.name ])
if hasattr(self, 'options'):
from SCons.Options import Options
if not env.has_key('options'):
from SCons.Script import ARGUMENTS
env['options']=Options(args=ARGUMENTS)
opts=env['options']
self.options(opts)
opts.Update(env)
apply(self.generate, ( env, ) + args, kw) apply(self.generate, ( env, ) + args, kw)
def __str__(self): def __str__(self):
return self.name return self.name
##########################################################################
# Create common executable program / library / object builders
def createProgBuilder(env): def createProgBuilder(env):
"""This is a utility function that creates the Program """This is a utility function that creates the Program
Builder in an Environment if it is not there already. Builder in an Environment if it is not there already.
@ -316,7 +337,8 @@ def createCFileBuilders(env):
emitter = {}, emitter = {},
suffix = {None:'$CFILESUFFIX'}) suffix = {None:'$CFILESUFFIX'})
env['BUILDERS']['CFile'] = c_file env['BUILDERS']['CFile'] = c_file
env['CFILESUFFIX'] = '.c'
env.SetDefault(CFILESUFFIX = '.c')
try: try:
cxx_file = env['BUILDERS']['CXXFile'] cxx_file = env['BUILDERS']['CXXFile']
@ -325,10 +347,130 @@ def createCFileBuilders(env):
emitter = {}, emitter = {},
suffix = {None:'$CXXFILESUFFIX'}) suffix = {None:'$CXXFILESUFFIX'})
env['BUILDERS']['CXXFile'] = cxx_file env['BUILDERS']['CXXFile'] = cxx_file
env['CXXFILESUFFIX'] = '.cc' env.SetDefault(CXXFILESUFFIX = '.cc')
return (c_file, cxx_file) return (c_file, cxx_file)
##########################################################################
# Create common Java builders
def CreateJarBuilder(env):
try:
java_jar = env['BUILDERS']['Jar']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
java_jar = SCons.Builder.Builder(action = jar_com,
suffix = '$JARSUFFIX',
src_suffix = '$JAVACLASSSUFIX',
src_builder = 'JavaClassFile',
source_factory = fs.Entry)
env['BUILDERS']['Jar'] = java_jar
return java_jar
def CreateJavaHBuilder(env):
try:
java_javah = env['BUILDERS']['JavaH']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
java_javah = SCons.Builder.Builder(action = java_javah_com,
src_suffix = '$JAVACLASSSUFFIX',
target_factory = fs.Entry,
source_factory = fs.File,
src_builder = 'JavaClassFile')
env['BUILDERS']['JavaH'] = java_javah
return java_javah
def CreateJavaClassFileBuilder(env):
try:
java_class_file = env['BUILDERS']['JavaClassFile']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
java_class_file = SCons.Builder.Builder(action = javac_com,
emitter = {},
#suffix = '$JAVACLASSSUFFIX',
src_suffix = '$JAVASUFFIX',
src_builder = ['JavaFile'],
target_factory = fs.Entry,
source_factory = fs.File)
env['BUILDERS']['JavaClassFile'] = java_class_file
return java_class_file
def CreateJavaClassDirBuilder(env):
try:
java_class_dir = env['BUILDERS']['JavaClassDir']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
java_class_dir = SCons.Builder.Builder(action = javac_com,
emitter = {},
target_factory = fs.Dir,
source_factory = fs.Dir)
env['BUILDERS']['JavaClassDir'] = java_class_dir
return java_class_dir
def CreateJavaFileBuilder(env):
try:
java_file = env['BUILDERS']['JavaFile']
except KeyError:
java_file = SCons.Builder.Builder(action = {},
emitter = {},
suffix = {None:'$JAVASUFFIX'})
env['BUILDERS']['JavaFile'] = java_file
env['JAVASUFFIX'] = '.java'
return java_file
class ToolInitializer:
"""
A class for delayed initialization of Tools modules.
This is intended to be added to a construction environment in
place of the method(s) normally called for a Builder (env.Object,
env.StaticObject, etc.). When called, it searches the specified
list of tools, applies the first one that exists to the construction
environment, and calls whatever builder was (presumably) added the
construction environment in our place.
"""
def __init__(self, name, tools):
"""
Note: we store the tool name as __name__ so it can be used by
the class that attaches this to a construction environment.
"""
self.__name__ = name
if not SCons.Util.is_List(tools):
tools = [tools]
self.tools = tools
def __call__(self, env, *args, **kw):
for t in self.tools:
tool = SCons.Tool.Tool(t)
if tool.exists(env):
env.Tool(tool)
break
builder = getattr(env, self.__name__)
if builder is self:
# There was no Builder added, which means no valid Tool
# for this name was found (or possibly there's a mismatch
# between the name we were called by and the Builder name
# added by the Tool module).
#
# (Eventually this is where we'll put a more informative
# error message about the inability to find that tool
# as cut over more Builders+Tools to using this.
return [], []
# Let the construction environment remove the added method
# so we no longer copy and re-bind this method when the
# construction environment gets cloned.
env.RemoveMethod(self)
return apply(builder, args, kw)
def Initializers(env):
env.AddMethod(ToolInitializer('Install', 'install'))
env.AddMethod(ToolInitializer('InstallAs', 'install'))
def FindTool(tools, env): def FindTool(tools, env):
for tool in tools: for tool in tools:
t = Tool(tool) t = Tool(tool)
@ -340,7 +482,7 @@ def FindAllTools(tools, env):
def ToolExists(tool, env=env): def ToolExists(tool, env=env):
return Tool(tool).exists(env) return Tool(tool).exists(env)
return filter (ToolExists, tools) return filter (ToolExists, tools)
def tool_list(platform, env): def tool_list(platform, env):
# XXX this logic about what tool to prefer on which platform # XXX this logic about what tool to prefer on which platform
@ -414,11 +556,11 @@ def tool_list(platform, env):
ars = ['ar', 'mslib'] ars = ['ar', 'mslib']
c_compiler = FindTool(c_compilers, env) or c_compilers[0] c_compiler = FindTool(c_compilers, env) or c_compilers[0]
# XXX this logic about what tool provides what should somehow be # XXX this logic about what tool provides what should somehow be
# moved into the tool files themselves. # moved into the tool files themselves.
if c_compiler and c_compiler == 'mingw': if c_compiler and c_compiler == 'mingw':
# MinGW contains a linker, C compiler, C++ compiler, # MinGW contains a linker, C compiler, C++ compiler,
# Fortran compiler, archiver and assembler: # Fortran compiler, archiver and assembler:
cxx_compiler = None cxx_compiler = None
linker = None linker = None
@ -438,6 +580,7 @@ def tool_list(platform, env):
other_tools = FindAllTools(['BitKeeper', 'CVS', other_tools = FindAllTools(['BitKeeper', 'CVS',
'dmd', 'dmd',
'filesystem',
'dvipdf', 'dvips', 'gs', 'dvipdf', 'dvips', 'gs',
'jar', 'javac', 'javah', 'jar', 'javac', 'javah',
'latex', 'lex', 'latex', 'lex',
@ -448,11 +591,11 @@ def tool_list(platform, env):
# 'Subversion', # 'Subversion',
'swig', 'swig',
'tar', 'tex', 'tar', 'tex',
'yacc', 'zip'], 'yacc', 'zip', 'rpm', 'wix'],
env) env)
tools = ([linker, c_compiler, cxx_compiler, tools = ([linker, c_compiler, cxx_compiler,
fortran_compiler, assembler, ar] fortran_compiler, assembler, ar]
+ other_tools) + other_tools)
return filter(lambda x: x, tools) return filter(lambda x: x, tools)

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/aixc++.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/aixcc.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/aixf77.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/aixlink.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path
@ -44,7 +44,7 @@ cplusplus = __import__('c++', globals(), locals(), [])
def smart_linkflags(source, target, env, for_signature): def smart_linkflags(source, target, env, for_signature):
if cplusplus.iscplusplus(source): if cplusplus.iscplusplus(source):
build_dir = env.subst('$BUILDDIR') build_dir = env.subst('$BUILDDIR', target=target, source=source)
if build_dir: if build_dir:
return '-qtempinc=' + os.path.join(build_dir, 'tempinc') return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
return '' return ''

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/applelink.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/applelink.py 2523 2007/12/12 09:37:41 knight"
import SCons.Util import SCons.Util

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/ar.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/as.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool

View file

@ -27,7 +27,7 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/bcc32.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path
@ -42,12 +42,7 @@ def findIt(program, env):
borwin = env.WhereIs(program) or SCons.Util.WhereIs(program) borwin = env.WhereIs(program) or SCons.Util.WhereIs(program)
if borwin: if borwin:
dir = os.path.dirname(borwin) dir = os.path.dirname(borwin)
path = env['ENV'].get('PATH', []) env.PrependENVPath('PATH', dir)
if not path:
path = []
if SCons.Util.is_String(path):
path = string.split(path, os.pathsep)
env['ENV']['PATH'] = string.join([dir]+path, os.pathsep)
return borwin return borwin
def generate(env): def generate(env):

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/c++.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/cc.py 2523 2007/12/12 09:37:41 knight"
import SCons.Tool import SCons.Tool
import SCons.Defaults import SCons.Defaults
@ -73,6 +73,18 @@ def generate(env):
shared_obj.add_action(suffix, SCons.Defaults.ShCAction) shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
#<<<<<<< .working
#
# 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'
#=======
#>>>>>>> .merge-right.r1907
add_common_cc_variables(env) add_common_cc_variables(env)

View file

@ -27,7 +27,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/cvf.py 2523 2007/12/12 09:37:41 knight"
import fortran import fortran

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/default.py 2523 2007/12/12 09:37:41 knight"
import SCons.Tool import SCons.Tool

View file

@ -53,7 +53,7 @@ Lib tool variables:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/dmd.py 2523 2007/12/12 09:37:41 knight"
import os import os
import string import string

View file

@ -27,7 +27,7 @@ Common DVI Builder definition for various other Tool modules that use it.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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" __revision__ = "src/engine/SCons/Tool/dvi.py 2523 2007/12/12 09:37:41 knight"
import SCons.Builder import SCons.Builder
import SCons.Tool import SCons.Tool

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/dvipdf.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Defaults import SCons.Defaults

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/dvips.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Builder import SCons.Builder

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/f77.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Scanner.Fortran import SCons.Scanner.Fortran

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/f90.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Scanner.Fortran import SCons.Scanner.Fortran

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/f95.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool

View file

@ -0,0 +1,92 @@
"""SCons.Tool.filesystem
Tool-specific initialization for the filesystem tools.
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, 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__ = "src/engine/SCons/Tool/filesystem.py 2523 2007/12/12 09:37:41 knight"
import SCons
from SCons.Tool.install import copyFunc
copyToBuilder, copyAsBuilder = None, None
def copyto_emitter(target, source, env):
""" changes the path of the source to be under the target (which
are assumed to be directories.
"""
n_target = []
for t in target:
n_target = n_target + map( lambda s, t=t: t.File( str( s ) ), source )
return (n_target, source)
def copy_action_func(target, source, env):
assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(map(str, target),map(str, source))
for t, s in zip(target, source):
if copyFunc(t.get_path(), s.get_path(), env):
return 1
return 0
def copy_action_str(target, source, env):
return env.subst_target_source(env['COPYSTR'], 0, target, source)
copy_action = SCons.Action.Action( copy_action_func, copy_action_str )
def generate(env):
try:
env['BUILDERS']['CopyTo']
env['BUILDERS']['CopyAs']
except KeyError, e:
global copyToBuilder
if copyToBuilder is None:
copyToBuilder = SCons.Builder.Builder(
action = copy_action,
target_factory = env.fs.Dir,
source_factory = env.fs.Entry,
multi = 1,
emitter = [ copyto_emitter, ] )
global copyAsBuilder
if copyAsBuilder is None:
copyAsBuilder = SCons.Builder.Builder(
action = copy_action,
target_factory = env.fs.Entry,
source_factory = env.fs.Entry )
env['BUILDERS']['CopyTo'] = copyToBuilder
env['BUILDERS']['CopyAs'] = copyAsBuilder
env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"'
def exists(env):
return 1

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/fortran.py 2523 2007/12/12 09:37:41 knight"
import re import re
import string import string
@ -78,8 +78,8 @@ def _fortranEmitter(target, source, env):
# Remove unique items from the list # Remove unique items from the list
modules = SCons.Util.unique(modules) modules = SCons.Util.unique(modules)
# Convert module name to a .mod filename # Convert module name to a .mod filename
suffix = env.subst('$FORTRANMODSUFFIX') suffix = env.subst('$FORTRANMODSUFFIX', target=target, source=source)
moddir = env.subst('$FORTRANMODDIR') moddir = env.subst('$FORTRANMODDIR', target=target, source=source)
modules = map(lambda x, s=suffix: string.lower(x) + s, modules) modules = map(lambda x, s=suffix: string.lower(x) + s, modules)
for m in modules: for m in modules:
target.append(env.fs.File(m, moddir)) target.append(env.fs.File(m, moddir))

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/g++.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path
import re import re

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/g77.py 2523 2007/12/12 09:37:41 knight"
import f77 import f77

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/gas.py 2523 2007/12/12 09:37:41 knight"
as_module = __import__('as', globals(), locals(), []) as_module = __import__('as', globals(), locals(), [])

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gcc.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/gcc.py 2523 2007/12/12 09:37:41 knight"
import SCons.Util import SCons.Util

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gnulink.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/gnulink.py 2523 2007/12/12 09:37:41 knight"
import SCons.Util import SCons.Util

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gs.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/gs.py 2523 2007/12/12 09:37:41 knight"
import SCons.Action import SCons.Action
import SCons.Platform import SCons.Platform

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hpc++.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/hpc++.py 2523 2007/12/12 09:37:41 knight"
import os.path import os.path
import string import string

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hpcc.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/hpcc.py 2523 2007/12/12 09:37:41 knight"
import SCons.Util import SCons.Util

View file

@ -30,7 +30,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hplink.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/hplink.py 2523 2007/12/12 09:37:41 knight"
import os import os
import os.path import os.path

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/icc.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/icc.py 2523 2007/12/12 09:37:41 knight"
import cc import cc

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/icl.py 2523 2007/12/12 09:37:41 knight"
import SCons.Tool.intelc import SCons.Tool.intelc

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ifl.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/ifl.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults

View file

@ -32,7 +32,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ifort.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/ifort.py 2523 2007/12/12 09:37:41 knight"
import string import string

View file

@ -31,7 +31,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ilink.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/ilink.py 2523 2007/12/12 09:37:41 knight"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool

View file

@ -27,7 +27,7 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ilink32.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/ilink32.py 2523 2007/12/12 09:37:41 knight"
import SCons.Tool import SCons.Tool
import SCons.Tool.bcc32 import SCons.Tool.bcc32

View file

@ -0,0 +1,226 @@
"""SCons.Tool.install
Tool-specific initialization for the install tool.
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, 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__ = "src/engine/SCons/Tool/install.py 2523 2007/12/12 09:37:41 knight"
import os
import shutil
import stat
import SCons.Action
from SCons.Util import make_path_relative
#
# We keep track of *all* installed files.
_INSTALLED_FILES = []
_UNIQUE_INSTALLED_FILES = None
#
# Functions doing the actual work of the Install Builder.
#
def copyFunc(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 installFunc(target, source, env):
"""Install a source file into a target using the function specified
as the INSTALL construction variable."""
try:
install = env['INSTALL']
except KeyError:
raise SCons.Errors.UserError('Missing INSTALL construction variable.')
assert( len(target)==len(source) )
for t,s in zip(target,source):
if install(t.get_path(),s.get_path(),env):
return 1
return 0
def stringFunc(target, source, env):
installstr = env.get('INSTALLSTR')
if installstr:
return env.subst_target_source(installstr, 0, target, source)
target = str(target[0])
source = str(source[0])
if os.path.isdir(source):
type = 'directory'
else:
type = 'file'
return 'Install %s: "%s" as "%s"' % (type, source, target)
#
# Emitter functions
#
def add_targets_to_INSTALLED_FILES(target, source, env):
""" an emitter that adds all target files to the list stored in the
_INSTALLED_FILES global variable. This way all installed files of one
scons call will be collected.
"""
global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES
_INSTALLED_FILES.extend(target)
_UNIQUE_INSTALLED_FILES = None
return (target, source)
class DESTDIR_factory:
""" a node factory, where all files will be relative to the dir supplied
in the constructor.
"""
def __init__(self, env, dir):
self.env = env
self.dir = env.arg2nodes( dir, env.fs.Dir )[0]
def Entry(self, name):
name = make_path_relative(name)
return self.dir.Entry(name)
def Dir(self, name):
name = make_path_relative(name)
return self.dir.Dir(name)
#
# The Builder Definition
#
install_action = SCons.Action.Action(installFunc, stringFunc)
installas_action = SCons.Action.Action(installFunc, stringFunc)
BaseInstallBuilder = None
def InstallBuilderWrapper(env, target, source, dir=None):
if target and dir:
raise SCons.Errors.UserError, "Both target and dir defined for Install(), only one may be defined."
if not dir:
dir=target
import SCons.Script
install_sandbox = SCons.Script.GetOption('install_sandbox')
if install_sandbox:
target_factory = DESTDIR_factory(env, install_sandbox)
else:
target_factory = env.fs
try:
dnodes = env.arg2nodes(dir, target_factory.Dir)
except TypeError:
raise SCons.Errors.UserError, "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)
sources = env.arg2nodes(source, env.fs.Entry)
tgt = []
for dnode in dnodes:
for src in sources:
# Prepend './' so the lookup doesn't interpret an initial
# '#' on the file name portion as meaning the Node should
# be relative to the top-level SConstruct directory.
target = env.fs.Entry('.'+os.sep+src.name, dnode)
tgt.extend(BaseInstallBuilder(env, target, src))
return tgt
def InstallAsBuilderWrapper(env, target, source):
result = []
for src, tgt in map(lambda x, y: (x, y), source, target):
result.extend(BaseInstallBuilder(env, tgt, src))
return result
added = None
def generate(env):
from SCons.Script import AddOption, GetOption
global added
if not added:
added = 1
AddOption('--install-sandbox',
dest='install_sandbox',
type="string",
action="store",
help='A directory under which all installed files will be placed.')
global BaseInstallBuilder
if BaseInstallBuilder is None:
install_sandbox = GetOption('install_sandbox')
if install_sandbox:
target_factory = DESTDIR_factory(env, install_sandbox)
else:
target_factory = env.fs
BaseInstallBuilder = SCons.Builder.Builder(
action = install_action,
target_factory = target_factory.Entry,
source_factory = env.fs.Entry,
multi = 1,
emitter = [ add_targets_to_INSTALLED_FILES, ],
name = 'InstallBuilder')
try:
env['BUILDERS']['Install']
except KeyError, e:
env['BUILDERS']['Install'] = InstallBuilderWrapper
try:
env['BUILDERS']['InstallAs']
except KeyError, e:
env['BUILDERS']['InstallAs'] = InstallAsBuilderWrapper
# We'd like to initialize this doing something like the following,
# but there isn't yet support for a ${SOURCE.type} expansion that
# will print "file" or "directory" depending on what's being
# installed. For now we punt by not initializing it, and letting
# the stringFunc() that we put in the action fall back to the
# hand-crafted default string if it's not set.
#
#try:
# env['INSTALLSTR']
#except KeyError:
# env['INSTALLSTR'] = 'Install ${SOURCE.type}: "$SOURCES" as "$TARGETS"'
try:
env['INSTALL']
except KeyError:
env['INSTALL'] = copyFunc
def exists(env):
return 1

View file

@ -32,11 +32,14 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/intelc.py 0.97.D001 2007/05/17 11:35:19 knight" __revision__ = "src/engine/SCons/Tool/intelc.py 2523 2007/12/12 09:37:41 knight"
import math, sys, os.path, glob, string, re import math, sys, os.path, glob, string, re
is_windows = sys.platform == 'win32' is_windows = sys.platform == 'win32'
is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or
(os.environ.has_key('PROCESSOR_ARCHITEW6432') and
os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64'))
is_linux = sys.platform == 'linux2' is_linux = sys.platform == 'linux2'
if is_windows: if is_windows:
@ -138,7 +141,10 @@ def get_intel_registry_value(valuename, version=None, abi=None):
Return a value from the Intel compiler registry tree. (Windows only) Return a value from the Intel compiler registry tree. (Windows only)
""" """
# Open the key: # Open the key:
K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() if is_win64:
K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
else:
K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
try: try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
except SCons.Util.RegError: except SCons.Util.RegError:
@ -160,7 +166,10 @@ def get_all_compiler_versions():
""" """
versions=[] versions=[]
if is_windows: if is_windows:
keyname = 'Software\\Intel\\Compilers\\C++' if is_win64:
keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++'
else:
keyname = 'Software\\Intel\\Compilers\\C++'
try: try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
keyname) keyname)
@ -178,7 +187,7 @@ def get_all_compiler_versions():
# than uninstalling properly), so the registry values # than uninstalling properly), so the registry values
# are still there. # are still there.
ok = False ok = False
for try_abi in ('IA32', 'IA32e', 'IA64'): for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'):
try: try:
d = get_intel_registry_value('ProductDir', subkey, try_abi) d = get_intel_registry_value('ProductDir', subkey, try_abi)
except MissingRegistryError: except MissingRegistryError:
@ -212,6 +221,7 @@ def get_intel_compiler_top(version, abi):
The compiler will be in <top>/bin/icl.exe (icc on linux), The compiler will be in <top>/bin/icl.exe (icc on linux),
the include dir is <top>/include, etc. the include dir is <top>/include, etc.
""" """
if is_windows: if is_windows:
if not SCons.Util.can_read_reg: if not SCons.Util.can_read_reg:
raise NoRegistryModuleError, "No Windows registry module was found" raise NoRegistryModuleError, "No Windows registry module was found"
@ -282,8 +292,10 @@ def generate(env, version=None, abi=None, topdir=None, verbose=0):
else: else:
abi = 'ia32' abi = 'ia32'
else: else:
# XXX: how would we do the same test on Windows? if is_win64:
abi = "ia32" abi = 'em64t'
else:
abi = 'ia32'
if version and not topdir: if version and not topdir:
try: try:

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