mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Simplify the SCons build:
With wxWidgets 2.9.2 now in Externals, SCons was the only external dependency other than Xcode and building just SCons from Macports caused a fair mount of extra stuff to be built unnecessarily, so just include a copy of scons-local. Always build wxWidgets from Externals which allows us to get rid of the home-grown autoconf machinery in SconsTests. The main use case for args.cache was the wxconfig option, which is no longer relevant after the above changes and caching options has a lot of potential for confusion, especially since other build systems don't tend to do this, so we no longer do it now. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7381 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Vendored
-3
@@ -6,9 +6,6 @@ import sys
|
||||
if env.has_key('shared_png') and env['shared_png']:
|
||||
Return()
|
||||
|
||||
if env.has_key('HAVE_WX') and env['HAVE_WX']:
|
||||
Return() # Currently using libwxpng
|
||||
|
||||
files = [
|
||||
'png.c',
|
||||
'pngerror.c',
|
||||
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
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, 2008, 2009, 2010 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.
|
||||
Vendored
+204
@@ -0,0 +1,204 @@
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
|
||||
|
||||
SCons - a software construction tool
|
||||
|
||||
This is the scons-README file for a version of SCons packaged for local
|
||||
execution--that is, execution out of a specific local directory, without
|
||||
having to install SCons as a system-wide utility.
|
||||
|
||||
You are likely reading this file in one of the following two situations:
|
||||
|
||||
1) You have unpacked an scons-local-{version} package and are
|
||||
examining the contents.
|
||||
|
||||
In this case, you are presumably interested in using this
|
||||
package to include a local copy of SCons with some other
|
||||
software that you package, so that you can use SCons to build
|
||||
your software without forcing all of your users to have it fully
|
||||
installed. Instructions for this can be found below.
|
||||
|
||||
If you are not looking to use SCons in this way, then please
|
||||
use either the scons-{version} package to install SCons on your
|
||||
system, or the scons-src-{version} package if you want the full
|
||||
source to SCons, including its packaging code and underlying
|
||||
tests and testing infrastructure.
|
||||
|
||||
2) This file was included in some other software package so that
|
||||
the package could be built using SCons.
|
||||
|
||||
In this case, follow the instructions provided with the
|
||||
rest of the software package for how to use SCons to build
|
||||
and/or install the software. The file containing build and
|
||||
installation instructions will typically be named README or
|
||||
INSTALL.
|
||||
|
||||
LATEST VERSION
|
||||
==============
|
||||
|
||||
Before going further, you can check for the latest version of the
|
||||
scons-local package, or any SCons package, at the SCons download page:
|
||||
|
||||
http://www.scons.org/download.html
|
||||
|
||||
|
||||
EXECUTION REQUIREMENTS
|
||||
======================
|
||||
|
||||
Running SCons requires Python version 2.4 or later. There should be
|
||||
no other dependencies or requirements to run SCons.
|
||||
|
||||
The default SCons configuration assumes use of the Microsoft Visual C++
|
||||
compiler suite on WIN32 systems, and assumes a C compiler named 'cc',
|
||||
a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such
|
||||
as found in the GNU C compiler suite) on any other type of system.
|
||||
You may, of course, override these default values by appropriate
|
||||
configuration of Environment construction variables.
|
||||
|
||||
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
Installation of this package should be as simple as unpacking the
|
||||
archive (either .tar.gz or .zip) in any directory (top-level or a
|
||||
subdirectory) within the software package with which you want to ship
|
||||
SCons.
|
||||
|
||||
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.
|
||||
|
||||
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):
|
||||
|
||||
$ python scons.py
|
||||
|
||||
Or (if, for example, you installed this package in a subdirectory named
|
||||
"scons"):
|
||||
|
||||
$ python scons/scons.py
|
||||
|
||||
That should be all you have to do. (If it isn't that simple, please let
|
||||
us know!)
|
||||
|
||||
|
||||
CONTENTS OF THIS PACKAGE
|
||||
========================
|
||||
|
||||
This scons-local package consists of the following:
|
||||
|
||||
scons-LICENSE
|
||||
A copy of the copyright and terms under which SCons is
|
||||
distributed (the Open Source Initiative-approved MIT license).
|
||||
|
||||
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.
|
||||
|
||||
scons-README
|
||||
What you're looking at right now.
|
||||
|
||||
scons-local-{version}/
|
||||
The SCons build engine. This is structured as a Python
|
||||
library.
|
||||
|
||||
scons.py
|
||||
The SCons script itself. The script sets up the Python
|
||||
sys.path variable to use the build engine found in the
|
||||
scons-local-{version}/ directory in preference to any other
|
||||
SCons build engine installed on your system.
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
=============
|
||||
|
||||
Because this package is intended to be included with other software by
|
||||
experienced users, we have not included any SCons documentation in this
|
||||
package (other than this scons-README file you're reading right now).
|
||||
|
||||
If, however, you need documentation about SCons, then consult any of the
|
||||
following from the corresponding scons-{version} or scons-src-{version}
|
||||
package:
|
||||
|
||||
The RELEASE.txt file (src/RELEASE.txt file in the
|
||||
scons-src-{version} package), which contains notes about this
|
||||
specific release, including known problems.
|
||||
|
||||
The CHANGES.txt file (src/CHANGES.txt file in the
|
||||
scons-src-{version} package), which contains a list of changes
|
||||
since the previous release.
|
||||
|
||||
The scons.1 man page (doc/man/scons.1 in the scons-src-{version}
|
||||
package), which contains a section of small examples for getting
|
||||
started using SCons.
|
||||
|
||||
Additional documentation for SCons is available at:
|
||||
|
||||
http://www.scons.org/doc.html
|
||||
|
||||
|
||||
LICENSING
|
||||
=========
|
||||
|
||||
SCons is distributed under the MIT license, a full copy of which is
|
||||
available in the scons-LICENSE file in this package. The MIT license is
|
||||
an approved Open Source license, which means:
|
||||
|
||||
This software is OSI Certified Open Source Software. OSI
|
||||
Certified is a certification mark of the Open Source Initiative.
|
||||
|
||||
More information about OSI certifications and Open Source software is
|
||||
available at:
|
||||
|
||||
http://www.opensource.org/
|
||||
|
||||
|
||||
REPORTING BUGS
|
||||
==============
|
||||
|
||||
You can report bugs either by following the "Tracker - Bugs" link
|
||||
on the SCons project page:
|
||||
|
||||
http://sourceforge.net/projects/scons/
|
||||
|
||||
or by sending mail to the SCons developers mailing list:
|
||||
|
||||
scons-devel@lists.sourceforge.net
|
||||
|
||||
|
||||
MAILING LISTS
|
||||
=============
|
||||
|
||||
A mailing list for users of SCons is available. You may send questions
|
||||
or comments to the list at:
|
||||
|
||||
scons-users@lists.sourceforge.net
|
||||
|
||||
You may subscribe to the scons-users mailing list at:
|
||||
|
||||
http://lists.sourceforge.net/lists/listinfo/scons-users
|
||||
|
||||
|
||||
FOR MORE INFORMATION
|
||||
====================
|
||||
|
||||
Check the SCons web site at:
|
||||
|
||||
http://www.scons.org/
|
||||
|
||||
|
||||
AUTHOR INFO
|
||||
===========
|
||||
|
||||
Steven Knight
|
||||
knight at baldmt dot com
|
||||
http://www.baldmt.com/~knight/
|
||||
|
||||
With plenty of help from the SCons Development team:
|
||||
Chad Austin
|
||||
Charles Crain
|
||||
Steve Leblanc
|
||||
Anthony Roach
|
||||
Terrel Shumway
|
||||
|
||||
+1241
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,216 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
__doc__ = """
|
||||
CacheDir support
|
||||
"""
|
||||
|
||||
import os.path
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import SCons.Action
|
||||
|
||||
cache_enabled = True
|
||||
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(object):
|
||||
|
||||
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)
|
||||
self.path = None
|
||||
else:
|
||||
self.path = path
|
||||
self.current_cache_debug = None
|
||||
self.debugFP = None
|
||||
|
||||
def CacheDebug(self, fmt, target, cachefile):
|
||||
if cache_debug != self.current_cache_debug:
|
||||
if cache_debug == '-':
|
||||
self.debugFP = sys.stdout
|
||||
elif cache_debug:
|
||||
self.debugFP = open(cache_debug, 'w')
|
||||
else:
|
||||
self.debugFP = None
|
||||
self.current_cache_debug = cache_debug
|
||||
if self.debugFP:
|
||||
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
|
||||
|
||||
def is_enabled(self):
|
||||
return (cache_enabled and not self.path is None)
|
||||
|
||||
def cachepath(self, node):
|
||||
"""
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return None, None
|
||||
|
||||
sig = node.get_cachedir_bsig()
|
||||
subdir = sig[0].upper()
|
||||
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.
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return False
|
||||
|
||||
env = node.get_build_env()
|
||||
if cache_show:
|
||||
if CacheRetrieveSilent(node, [], env, execute=1) == 0:
|
||||
node.build(presub=0, execute=0)
|
||||
return True
|
||||
else:
|
||||
if CacheRetrieve(node, [], env, execute=1) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def push(self, node):
|
||||
if not self.is_enabled():
|
||||
return
|
||||
return CachePush(node, [], node.get_build_env())
|
||||
|
||||
def push_if_forced(self, node):
|
||||
if cache_force:
|
||||
return self.push(node)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
||||
"""SCons.Debug
|
||||
|
||||
Code for debugging SCons internal things. Shouldn't be
|
||||
needed by most users.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Debug.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import weakref
|
||||
|
||||
tracked_classes = {}
|
||||
|
||||
def logInstanceCreation(instance, name=None):
|
||||
if name is None:
|
||||
name = instance.__class__.__name__
|
||||
if name not in tracked_classes:
|
||||
tracked_classes[name] = []
|
||||
tracked_classes[name].append(weakref.ref(instance))
|
||||
|
||||
def string_to_classes(s):
|
||||
if s == '*':
|
||||
return sorted(tracked_classes.keys())
|
||||
else:
|
||||
return s.split()
|
||||
|
||||
def fetchLoggedInstances(classes="*"):
|
||||
classnames = string_to_classes(classes)
|
||||
return [(cn, len(tracked_classes[cn])) for cn in classnames]
|
||||
|
||||
def countLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
|
||||
|
||||
def listLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
file.write(' %s\n' % repr(obj))
|
||||
|
||||
def dumpLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
file.write(' %s:\n' % obj)
|
||||
for key, value in obj.__dict__.items():
|
||||
file.write(' %20s : %s\n' % (key, value))
|
||||
|
||||
|
||||
|
||||
if sys.platform[:5] == "linux":
|
||||
# Linux doesn't actually support memory usage stats from getrusage().
|
||||
def memory():
|
||||
mstr = open('/proc/self/stat').read()
|
||||
mstr = mstr.split()[22]
|
||||
return int(mstr)
|
||||
elif sys.platform[:6] == 'darwin':
|
||||
#TODO really get memory stats for OS X
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
try:
|
||||
import win32process
|
||||
import win32api
|
||||
except ImportError:
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
def memory():
|
||||
process_handle = win32api.GetCurrentProcess()
|
||||
memory_info = win32process.GetProcessMemoryInfo( process_handle )
|
||||
return memory_info['PeakWorkingSetSize']
|
||||
else:
|
||||
def memory():
|
||||
res = resource.getrusage(resource.RUSAGE_SELF)
|
||||
return res[4]
|
||||
|
||||
# returns caller's stack
|
||||
def caller_stack(*backlist):
|
||||
import traceback
|
||||
if not backlist:
|
||||
backlist = [0]
|
||||
result = []
|
||||
for back in backlist:
|
||||
tb = traceback.extract_stack(limit=3+back)
|
||||
key = tb[0][:3]
|
||||
result.append('%s:%d(%s)' % func_shorten(key))
|
||||
return result
|
||||
|
||||
caller_bases = {}
|
||||
caller_dicts = {}
|
||||
|
||||
# trace a caller's stack
|
||||
def caller_trace(back=0):
|
||||
import traceback
|
||||
tb = traceback.extract_stack(limit=3+back)
|
||||
tb.reverse()
|
||||
callee = tb[1][:3]
|
||||
caller_bases[callee] = caller_bases.get(callee, 0) + 1
|
||||
for caller in tb[2:]:
|
||||
caller = callee + caller[:3]
|
||||
try:
|
||||
entry = caller_dicts[callee]
|
||||
except KeyError:
|
||||
caller_dicts[callee] = entry = {}
|
||||
entry[caller] = entry.get(caller, 0) + 1
|
||||
callee = caller
|
||||
|
||||
# print a single caller and its callers, if any
|
||||
def _dump_one_caller(key, file, level=0):
|
||||
leader = ' '*level
|
||||
for v,c in sorted([(-v,c) for c,v in caller_dicts[key].items()]):
|
||||
file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:])))
|
||||
if c in caller_dicts:
|
||||
_dump_one_caller(c, file, level+1)
|
||||
|
||||
# print each call tree
|
||||
def dump_caller_counts(file=sys.stdout):
|
||||
for k in sorted(caller_bases.keys()):
|
||||
file.write("Callers of %s:%d(%s), %d calls:\n"
|
||||
% (func_shorten(k) + (caller_bases[k],)))
|
||||
_dump_one_caller(k, file)
|
||||
|
||||
shorten_list = [
|
||||
( '/scons/SCons/', 1),
|
||||
( '/src/engine/SCons/', 1),
|
||||
( '/usr/lib/python', 0),
|
||||
]
|
||||
|
||||
if os.sep != '/':
|
||||
shorten_list = [(t[0].replace('/', os.sep), t[1]) for t in shorten_list]
|
||||
|
||||
def func_shorten(func_tuple):
|
||||
f = func_tuple[0]
|
||||
for t in shorten_list:
|
||||
i = f.find(t[0])
|
||||
if i >= 0:
|
||||
if t[1]:
|
||||
i = i + len(t[0])
|
||||
return (f[i:],)+func_tuple[1:]
|
||||
return func_tuple
|
||||
|
||||
|
||||
TraceFP = {}
|
||||
if sys.platform == 'win32':
|
||||
TraceDefault = 'con'
|
||||
else:
|
||||
TraceDefault = '/dev/tty'
|
||||
|
||||
TimeStampDefault = None
|
||||
StartTime = time.time()
|
||||
PreviousTime = StartTime
|
||||
|
||||
def Trace(msg, file=None, mode='w', tstamp=None):
|
||||
"""Write a trace message to a file. Whenever a file is specified,
|
||||
it becomes the default for the next call to Trace()."""
|
||||
global TraceDefault
|
||||
global TimeStampDefault
|
||||
global PreviousTime
|
||||
if file is None:
|
||||
file = TraceDefault
|
||||
else:
|
||||
TraceDefault = file
|
||||
if tstamp is None:
|
||||
tstamp = TimeStampDefault
|
||||
else:
|
||||
TimeStampDefault = tstamp
|
||||
try:
|
||||
fp = TraceFP[file]
|
||||
except KeyError:
|
||||
try:
|
||||
fp = TraceFP[file] = open(file, mode)
|
||||
except TypeError:
|
||||
# Assume we were passed an open file pointer.
|
||||
fp = file
|
||||
if tstamp:
|
||||
now = time.time()
|
||||
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
||||
PreviousTime = now
|
||||
fp.write(msg)
|
||||
fp.flush()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,480 @@
|
||||
"""SCons.Defaults
|
||||
|
||||
Builders and other things for the local site. Here's where we'll
|
||||
duplicate the functionality of autoconf until we move it into the
|
||||
installation procedure or use something like qmconf.
|
||||
|
||||
The code that reads the registry to find MSVC components was borrowed
|
||||
from distutils.msvccompiler.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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.
|
||||
#
|
||||
from __future__ import division
|
||||
|
||||
__revision__ = "src/engine/SCons/Defaults.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
|
||||
import os
|
||||
import errno
|
||||
import shutil
|
||||
import stat
|
||||
import time
|
||||
import sys
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.CacheDir
|
||||
import SCons.Environment
|
||||
import SCons.PathList
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
|
||||
# A placeholder for a default Environment (for fetching source files
|
||||
# from source code management systems and the like). This must be
|
||||
# initialized later, after the top-level directory is set by the calling
|
||||
# interface.
|
||||
_default_env = None
|
||||
|
||||
# Lazily instantiate the default environment so the overhead of creating
|
||||
# it doesn't apply when it's not needed.
|
||||
def _fetch_DefaultEnvironment(*args, **kw):
|
||||
"""
|
||||
Returns the already-created default construction environment.
|
||||
"""
|
||||
global _default_env
|
||||
return _default_env
|
||||
|
||||
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
|
||||
if not _default_env:
|
||||
import SCons.Util
|
||||
_default_env = SCons.Environment.Environment(*args, **kw)
|
||||
if SCons.Util.md5:
|
||||
_default_env.Decider('MD5')
|
||||
else:
|
||||
_default_env.Decider('timestamp-match')
|
||||
global DefaultEnvironment
|
||||
DefaultEnvironment = _fetch_DefaultEnvironment
|
||||
_default_env._CacheDir_path = None
|
||||
return _default_env
|
||||
|
||||
# Emitters for setting the shared attribute on object files,
|
||||
# and an action for checking that all of the source files
|
||||
# going into a shared library are, in fact, shared.
|
||||
def StaticObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = None
|
||||
return (target, source)
|
||||
|
||||
def SharedObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return (target, source)
|
||||
|
||||
def SharedFlagChecker(source, target, env):
|
||||
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
||||
if same == '0' or same == '' or same == 'False':
|
||||
for src in source:
|
||||
try:
|
||||
shared = src.attributes.shared
|
||||
except AttributeError:
|
||||
shared = None
|
||||
if not shared:
|
||||
raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
||||
|
||||
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
|
||||
|
||||
# Some people were using these variable name before we made
|
||||
# SourceFileScanner part of the public interface. Don't break their
|
||||
# SConscript files until we've given them some fair warning and a
|
||||
# transition period.
|
||||
CScan = SCons.Tool.CScanner
|
||||
DScan = SCons.Tool.DScanner
|
||||
LaTeXScan = SCons.Tool.LaTeXScanner
|
||||
ObjSourceScan = SCons.Tool.SourceFileScanner
|
||||
ProgScan = SCons.Tool.ProgramScanner
|
||||
|
||||
# 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
|
||||
# they should go. Leave them here for now.
|
||||
import SCons.Scanner.Dir
|
||||
DirScanner = SCons.Scanner.Dir.DirScanner()
|
||||
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
||||
|
||||
# Actions for common languages.
|
||||
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
|
||||
ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
|
||||
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
|
||||
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
|
||||
|
||||
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
|
||||
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
|
||||
|
||||
LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
|
||||
ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
|
||||
|
||||
LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
||||
|
||||
# Common tasks that we allow users to perform in platform-independent
|
||||
# ways by creating ActionFactory instances.
|
||||
ActionFactory = SCons.Action.ActionFactory
|
||||
|
||||
def get_paths_str(dest):
|
||||
# If dest is a list, we need to manually call str() on each element
|
||||
if SCons.Util.is_List(dest):
|
||||
elem_strs = []
|
||||
for element in dest:
|
||||
elem_strs.append('"' + str(element) + '"')
|
||||
return '[' + ', '.join(elem_strs) + ']'
|
||||
else:
|
||||
return '"' + str(dest) + '"'
|
||||
|
||||
def chmod_func(dest, mode):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for element in dest:
|
||||
os.chmod(str(element), mode)
|
||||
|
||||
def chmod_strfunc(dest, mode):
|
||||
return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
|
||||
|
||||
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
||||
|
||||
def copy_func(dest, src):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if SCons.Util.is_List(src) and os.path.isdir(dest):
|
||||
for file in src:
|
||||
shutil.copy2(file, dest)
|
||||
return 0
|
||||
elif os.path.isfile(src):
|
||||
return shutil.copy2(src, dest)
|
||||
else:
|
||||
return shutil.copytree(src, dest, 1)
|
||||
|
||||
Copy = ActionFactory(copy_func,
|
||||
lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
|
||||
convert=str)
|
||||
|
||||
def delete_func(dest, must_exist=0):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
entry = str(entry)
|
||||
if not must_exist and not os.path.exists(entry):
|
||||
continue
|
||||
if not os.path.exists(entry) or os.path.isfile(entry):
|
||||
os.unlink(entry)
|
||||
continue
|
||||
else:
|
||||
shutil.rmtree(entry, 1)
|
||||
continue
|
||||
|
||||
def delete_strfunc(dest, must_exist=0):
|
||||
return 'Delete(%s)' % get_paths_str(dest)
|
||||
|
||||
Delete = ActionFactory(delete_func, delete_strfunc)
|
||||
|
||||
def mkdir_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
try:
|
||||
os.makedirs(str(entry))
|
||||
except os.error, e:
|
||||
p = str(entry)
|
||||
if (e.args[0] == errno.EEXIST or
|
||||
(sys.platform=='win32' and e.args[0]==183)) \
|
||||
and os.path.isdir(str(entry)):
|
||||
pass # not an error if already exists
|
||||
else:
|
||||
raise
|
||||
|
||||
Mkdir = ActionFactory(mkdir_func,
|
||||
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
||||
|
||||
def move_func(dest, src):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
SCons.Node.FS.invalidate_node_memos(src)
|
||||
shutil.move(src, dest)
|
||||
|
||||
Move = ActionFactory(move_func,
|
||||
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
||||
convert=str)
|
||||
|
||||
def touch_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for file in dest:
|
||||
file = str(file)
|
||||
mtime = int(time.time())
|
||||
if os.path.exists(file):
|
||||
atime = os.path.getatime(file)
|
||||
else:
|
||||
open(file, 'w')
|
||||
atime = mtime
|
||||
os.utime(file, (atime, mtime))
|
||||
|
||||
Touch = ActionFactory(touch_func,
|
||||
lambda file: 'Touch(%s)' % get_paths_str(file))
|
||||
|
||||
# Internal utility functions
|
||||
|
||||
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
||||
"""
|
||||
Creates a new list from 'list' by first interpolating each element
|
||||
in the list using the 'env' dictionary and then calling f on the
|
||||
list, and finally calling _concat_ixes to concatenate 'prefix' and
|
||||
'suffix' onto each element of the list.
|
||||
"""
|
||||
if not list:
|
||||
return list
|
||||
|
||||
l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
|
||||
if l is not None:
|
||||
list = l
|
||||
|
||||
return _concat_ixes(prefix, list, suffix, env)
|
||||
|
||||
def _concat_ixes(prefix, list, suffix, env):
|
||||
"""
|
||||
Creates a new list from 'list' by concatenating the 'prefix' and
|
||||
'suffix' arguments onto each element of the list. A trailing space
|
||||
on 'prefix' or leading space on 'suffix' will cause them to be put
|
||||
into separate list elements rather than being concatenated.
|
||||
"""
|
||||
|
||||
result = []
|
||||
|
||||
# ensure that prefix and suffix are strings
|
||||
prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
|
||||
suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
|
||||
|
||||
for x in list:
|
||||
if isinstance(x, SCons.Node.FS.File):
|
||||
result.append(x)
|
||||
continue
|
||||
x = str(x)
|
||||
if x:
|
||||
|
||||
if prefix:
|
||||
if prefix[-1] == ' ':
|
||||
result.append(prefix[:-1])
|
||||
elif x[:len(prefix)] != prefix:
|
||||
x = prefix + x
|
||||
|
||||
result.append(x)
|
||||
|
||||
if suffix:
|
||||
if suffix[0] == ' ':
|
||||
result.append(suffix[1:])
|
||||
elif x[-len(suffix):] != suffix:
|
||||
result[-1] = result[-1]+suffix
|
||||
|
||||
return result
|
||||
|
||||
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
||||
"""
|
||||
This is a wrapper around _concat()/_concat_ixes() that checks for
|
||||
the existence of prefixes or suffixes on list items and strips them
|
||||
where it finds them. This is used by tools (like the GNU linker)
|
||||
that need to turn something like 'libfoo.a' into '-lfoo'.
|
||||
"""
|
||||
|
||||
if not itms:
|
||||
return itms
|
||||
|
||||
if not callable(c):
|
||||
env_c = env['_concat']
|
||||
if env_c != _concat and callable(env_c):
|
||||
# There's a custom _concat() method in the construction
|
||||
# environment, and we've allowed people to set that in
|
||||
# the past (see test/custom-concat.py), so preserve the
|
||||
# backwards compatibility.
|
||||
c = env_c
|
||||
else:
|
||||
c = _concat_ixes
|
||||
|
||||
stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
|
||||
stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
|
||||
|
||||
stripped = []
|
||||
for l in SCons.PathList.PathList(itms).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)
|
||||
|
||||
for stripprefix in stripprefixes:
|
||||
lsp = len(stripprefix)
|
||||
if l[:lsp] == stripprefix:
|
||||
l = l[lsp:]
|
||||
# Do not strip more than one prefix
|
||||
break
|
||||
|
||||
for stripsuffix in stripsuffixes:
|
||||
lss = len(stripsuffix)
|
||||
if l[-lss:] == stripsuffix:
|
||||
l = l[:-lss]
|
||||
# Do not strip more than one suffix
|
||||
break
|
||||
|
||||
stripped.append(l)
|
||||
|
||||
return c(prefix, stripped, suffix, env)
|
||||
|
||||
def processDefines(defs):
|
||||
"""process defines, resolving strings, lists, dictionaries, into a list of
|
||||
strings
|
||||
"""
|
||||
if SCons.Util.is_List(defs):
|
||||
l = []
|
||||
for d in defs:
|
||||
if SCons.Util.is_List(d) or isinstance(d, tuple):
|
||||
l.append(str(d[0]) + '=' + str(d[1]))
|
||||
else:
|
||||
l.append(str(d))
|
||||
elif SCons.Util.is_Dict(defs):
|
||||
# The items in a dictionary are stored in random order, but
|
||||
# if the order of the command-line options changes from
|
||||
# invocation to invocation, then the signature of the command
|
||||
# line will change and we'll get random unnecessary rebuilds.
|
||||
# Consequently, we have to sort the keys to ensure a
|
||||
# consistent order...
|
||||
l = []
|
||||
for k,v in sorted(defs.items()):
|
||||
if v is None:
|
||||
l.append(str(k))
|
||||
else:
|
||||
l.append(str(k) + '=' + str(v))
|
||||
else:
|
||||
l = [str(defs)]
|
||||
return l
|
||||
|
||||
def _defines(prefix, defs, suffix, env, c=_concat_ixes):
|
||||
"""A wrapper around _concat_ixes that turns a list or string
|
||||
into a list of C preprocessor command-line definitions.
|
||||
"""
|
||||
|
||||
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
||||
|
||||
class NullCmdGenerator(object):
|
||||
"""This is a callable class that can be used in place of other
|
||||
command generators if you don't want them to do anything.
|
||||
|
||||
The __call__ method for this class simply returns the thing
|
||||
you instantiated it with.
|
||||
|
||||
Example usage:
|
||||
env["DO_NOTHING"] = NullCmdGenerator
|
||||
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
|
||||
"""
|
||||
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
|
||||
def __call__(self, target, source, env, for_signature=None):
|
||||
return self.cmd
|
||||
|
||||
class Variable_Method_Caller(object):
|
||||
"""A class for finding a construction variable on the stack and
|
||||
calling one of its methods.
|
||||
|
||||
We use this to support "construction variables" in our string
|
||||
eval()s that actually stand in for methods--specifically, use
|
||||
of "RDirs" in call to _concat that should actually execute the
|
||||
"TARGET.RDirs" method. (We used to support this by creating a little
|
||||
"build dictionary" that mapped RDirs to the method, but this got in
|
||||
the way of Memoizing construction environments, because we had to
|
||||
create new environment objects to hold the variables.)
|
||||
"""
|
||||
def __init__(self, variable, method):
|
||||
self.variable = variable
|
||||
self.method = method
|
||||
def __call__(self, *args, **kw):
|
||||
try: 1//0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
frame = sys.exc_info()[2].tb_frame.f_back
|
||||
variable = self.variable
|
||||
while frame:
|
||||
if variable in frame.f_locals:
|
||||
v = frame.f_locals[variable]
|
||||
if v:
|
||||
method = getattr(v, self.method)
|
||||
return method(*args, **kw)
|
||||
frame = frame.f_back
|
||||
return None
|
||||
|
||||
ConstructionEnvironment = {
|
||||
'BUILDERS' : {},
|
||||
'SCANNERS' : [],
|
||||
'CONFIGUREDIR' : '#/.sconf_temp',
|
||||
'CONFIGURELOG' : '#/config.log',
|
||||
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
|
||||
'DSUFFIXES' : SCons.Tool.DSuffixes,
|
||||
'ENV' : {},
|
||||
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
|
||||
# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
|
||||
'_concat' : _concat,
|
||||
'_defines' : _defines,
|
||||
'_stripixes' : _stripixes,
|
||||
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
||||
'TEMPFILE' : NullCmdGenerator,
|
||||
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
||||
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
||||
'File' : Variable_Method_Caller('TARGET', 'File'),
|
||||
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,205 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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.
|
||||
#
|
||||
|
||||
"""SCons.Errors
|
||||
|
||||
This file contains the exception classes used to handle internal
|
||||
and user errors in SCons.
|
||||
|
||||
"""
|
||||
|
||||
__revision__ = "src/engine/SCons/Errors.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
import SCons.Util
|
||||
|
||||
import exceptions
|
||||
|
||||
class BuildError(Exception):
|
||||
""" Errors occuring while building.
|
||||
|
||||
BuildError have the following attributes:
|
||||
|
||||
Information about the cause of the build error:
|
||||
-----------------------------------------------
|
||||
|
||||
errstr : a description of the error message
|
||||
|
||||
status : the return code of the action that caused the build
|
||||
error. Must be set to a non-zero value even if the
|
||||
build error is not due to an action returning a
|
||||
non-zero returned code.
|
||||
|
||||
exitstatus : SCons exit status due to this build error.
|
||||
Must be nonzero unless due to an explicit Exit()
|
||||
call. Not always the same as status, since
|
||||
actions return a status code that should be
|
||||
respected, but SCons typically exits with 2
|
||||
irrespective of the return value of the failed
|
||||
action.
|
||||
|
||||
filename : The name of the file or directory that caused the
|
||||
build error. Set to None if no files are associated with
|
||||
this error. This might be different from the target
|
||||
being built. For example, failure to create the
|
||||
directory in which the target file will appear. It
|
||||
can be None if the error is not due to a particular
|
||||
filename.
|
||||
|
||||
exc_info : Info about exception that caused the build
|
||||
error. Set to (None, None, None) if this build
|
||||
error is not due to an exception.
|
||||
|
||||
|
||||
Information about the cause of the location of the error:
|
||||
---------------------------------------------------------
|
||||
|
||||
node : the error occured while building this target node(s)
|
||||
|
||||
executor : the executor that caused the build to fail (might
|
||||
be None if the build failures is not due to the
|
||||
executor failing)
|
||||
|
||||
action : the action that caused the build to fail (might be
|
||||
None if the build failures is not due to the an
|
||||
action failure)
|
||||
|
||||
command : the command line for the action that caused the
|
||||
build to fail (might be None if the build failures
|
||||
is not due to the an action failure)
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
node=None, errstr="Unknown error", status=2, exitstatus=2,
|
||||
filename=None, executor=None, action=None, command=None,
|
||||
exc_info=(None, None, None)):
|
||||
|
||||
self.errstr = errstr
|
||||
self.status = status
|
||||
self.exitstatus = exitstatus
|
||||
self.filename = filename
|
||||
self.exc_info = exc_info
|
||||
|
||||
self.node = node
|
||||
self.executor = executor
|
||||
self.action = action
|
||||
self.command = command
|
||||
|
||||
Exception.__init__(self, node, errstr, status, exitstatus, filename,
|
||||
executor, action, command, exc_info)
|
||||
|
||||
def __str__(self):
|
||||
if self.filename:
|
||||
return self.filename + ': ' + self.errstr
|
||||
else:
|
||||
return self.errstr
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
class UserError(Exception):
|
||||
pass
|
||||
|
||||
class StopError(Exception):
|
||||
pass
|
||||
|
||||
class EnvironmentError(Exception):
|
||||
pass
|
||||
|
||||
class MSVCError(IOError):
|
||||
pass
|
||||
|
||||
class ExplicitExit(Exception):
|
||||
def __init__(self, node=None, status=None, *args):
|
||||
self.node = node
|
||||
self.status = status
|
||||
self.exitstatus = status
|
||||
Exception.__init__(self, *args)
|
||||
|
||||
def convert_to_BuildError(status, exc_info=None):
|
||||
"""
|
||||
Convert any return code a BuildError Exception.
|
||||
|
||||
`status' can either be a return code or an Exception.
|
||||
The buildError.status we set here will normally be
|
||||
used as the exit status of the "scons" process.
|
||||
"""
|
||||
if not exc_info and isinstance(status, Exception):
|
||||
exc_info = (status.__class__, status, None)
|
||||
|
||||
if isinstance(status, BuildError):
|
||||
buildError = status
|
||||
buildError.exitstatus = 2 # always exit with 2 on build errors
|
||||
elif isinstance(status, ExplicitExit):
|
||||
status = status.status
|
||||
errstr = 'Explicit exit, status %s' % status
|
||||
buildError = BuildError(
|
||||
errstr=errstr,
|
||||
status=status, # might be 0, OK here
|
||||
exitstatus=status, # might be 0, OK here
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, (StopError, UserError)):
|
||||
buildError = BuildError(
|
||||
errstr=str(status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, exceptions.EnvironmentError):
|
||||
# If an IOError/OSError happens, raise a BuildError.
|
||||
# Report the name of the file or directory that caused the
|
||||
# error, which might be different from the target being built
|
||||
# (for example, failure to create the directory in which the
|
||||
# target file will appear).
|
||||
try: filename = status.filename
|
||||
except AttributeError: filename = None
|
||||
buildError = BuildError(
|
||||
errstr=status.strerror,
|
||||
status=status.errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, Exception):
|
||||
buildError = BuildError(
|
||||
errstr='%s : %s' % (status.__class__.__name__, status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif SCons.Util.is_String(status):
|
||||
buildError = BuildError(
|
||||
errstr=status,
|
||||
status=2,
|
||||
exitstatus=2)
|
||||
else:
|
||||
buildError = BuildError(
|
||||
errstr="Error %s" % status,
|
||||
status=status,
|
||||
exitstatus=2)
|
||||
|
||||
#import sys
|
||||
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)"%(status,buildError.errstr, buildError.status))
|
||||
return buildError
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,435 @@
|
||||
"""SCons.Job
|
||||
|
||||
This module defines the Serial and Parallel classes that execute tasks to
|
||||
complete a build. The Jobs class provides a higher level interface to start,
|
||||
stop, and wait on jobs.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Job.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import os
|
||||
import signal
|
||||
|
||||
import SCons.Errors
|
||||
|
||||
# The default stack size (in kilobytes) of the threads used to execute
|
||||
# jobs in parallel.
|
||||
#
|
||||
# We use a stack size of 256 kilobytes. The default on some platforms
|
||||
# is too large and prevents us from creating enough threads to fully
|
||||
# parallelized the build. For example, the default stack size on linux
|
||||
# is 8 MBytes.
|
||||
|
||||
explicit_stack_size = None
|
||||
default_stack_size = 256
|
||||
|
||||
interrupt_msg = 'Build interrupted.'
|
||||
|
||||
|
||||
class InterruptState(object):
|
||||
def __init__(self):
|
||||
self.interrupted = False
|
||||
|
||||
def set(self):
|
||||
self.interrupted = True
|
||||
|
||||
def __call__(self):
|
||||
return self.interrupted
|
||||
|
||||
|
||||
class Jobs(object):
|
||||
"""An instance of this class initializes N jobs, and provides
|
||||
methods for starting, stopping, and waiting on all N jobs.
|
||||
"""
|
||||
|
||||
def __init__(self, num, taskmaster):
|
||||
"""
|
||||
create 'num' jobs using the given taskmaster.
|
||||
|
||||
If 'num' is 1 or less, then a serial job will be used,
|
||||
otherwise a parallel job with 'num' worker threads will
|
||||
be used.
|
||||
|
||||
The 'num_jobs' attribute will be set to the actual number of jobs
|
||||
allocated. If more than one job is requested but the Parallel
|
||||
class can't do it, it gets reset to 1. Wrapping interfaces that
|
||||
care should check the value of 'num_jobs' after initialization.
|
||||
"""
|
||||
|
||||
self.job = None
|
||||
if num > 1:
|
||||
stack_size = explicit_stack_size
|
||||
if stack_size is None:
|
||||
stack_size = default_stack_size
|
||||
|
||||
try:
|
||||
self.job = Parallel(taskmaster, num, stack_size)
|
||||
self.num_jobs = num
|
||||
except NameError:
|
||||
pass
|
||||
if self.job is None:
|
||||
self.job = Serial(taskmaster)
|
||||
self.num_jobs = 1
|
||||
|
||||
def run(self, postfunc=lambda: None):
|
||||
"""Run the jobs.
|
||||
|
||||
postfunc() will be invoked after the jobs has run. It will be
|
||||
invoked even if the jobs are interrupted by a keyboard
|
||||
interrupt (well, in fact by a signal such as either SIGINT,
|
||||
SIGTERM or SIGHUP). The execution of postfunc() is protected
|
||||
against keyboard interrupts and is guaranteed to run to
|
||||
completion."""
|
||||
self._setup_sig_handler()
|
||||
try:
|
||||
self.job.start()
|
||||
finally:
|
||||
postfunc()
|
||||
self._reset_sig_handler()
|
||||
|
||||
def were_interrupted(self):
|
||||
"""Returns whether the jobs were interrupted by a signal."""
|
||||
return self.job.interrupted()
|
||||
|
||||
def _setup_sig_handler(self):
|
||||
"""Setup an interrupt handler so that SCons can shutdown cleanly in
|
||||
various conditions:
|
||||
|
||||
a) SIGINT: Keyboard interrupt
|
||||
b) SIGTERM: kill or system shutdown
|
||||
c) SIGHUP: Controlling shell exiting
|
||||
|
||||
We handle all of these cases by stopping the taskmaster. It
|
||||
turns out that it very difficult to stop the build process
|
||||
by throwing asynchronously an exception such as
|
||||
KeyboardInterrupt. For example, the python Condition
|
||||
variables (threading.Condition) and queue's do not seem to
|
||||
asynchronous-exception-safe. It would require adding a whole
|
||||
bunch of try/finally block and except KeyboardInterrupt all
|
||||
over the place.
|
||||
|
||||
Note also that we have to be careful to handle the case when
|
||||
SCons forks before executing another process. In that case, we
|
||||
want the child to exit immediately.
|
||||
"""
|
||||
def handler(signum, stack, self=self, parentpid=os.getpid()):
|
||||
if os.getpid() == parentpid:
|
||||
self.job.taskmaster.stop()
|
||||
self.job.interrupted.set()
|
||||
else:
|
||||
os._exit(2)
|
||||
|
||||
self.old_sigint = signal.signal(signal.SIGINT, handler)
|
||||
self.old_sigterm = signal.signal(signal.SIGTERM, handler)
|
||||
try:
|
||||
self.old_sighup = signal.signal(signal.SIGHUP, handler)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def _reset_sig_handler(self):
|
||||
"""Restore the signal handlers to their previous state (before the
|
||||
call to _setup_sig_handler()."""
|
||||
|
||||
signal.signal(signal.SIGINT, self.old_sigint)
|
||||
signal.signal(signal.SIGTERM, self.old_sigterm)
|
||||
try:
|
||||
signal.signal(signal.SIGHUP, self.old_sighup)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
class Serial(object):
|
||||
"""This class is used to execute tasks in series, and is more efficient
|
||||
than Parallel, but is only appropriate for non-parallel builds. Only
|
||||
one instance of this class should be in existence at a time.
|
||||
|
||||
This class is not thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster):
|
||||
"""Create a new serial job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next task
|
||||
that needs to be executed, or None if there are no more tasks. The
|
||||
taskmaster's executed() method will be called for each task when it
|
||||
is successfully executed or failed() will be called if it failed to
|
||||
execute (e.g. execute() raised an exception)."""
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the taskmaster
|
||||
and executing them, and return when there are no more tasks. If a task
|
||||
fails to execute (i.e. execute() raises an exception), then the job will
|
||||
stop."""
|
||||
|
||||
while True:
|
||||
task = self.taskmaster.next_task()
|
||||
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
task.prepare()
|
||||
if task.needs_execute():
|
||||
task.execute()
|
||||
except:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except:
|
||||
task.exception_set()
|
||||
else:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange for the
|
||||
# build to stop if that's appropriate.
|
||||
task.failed()
|
||||
else:
|
||||
task.executed()
|
||||
|
||||
task.postprocess()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
|
||||
# Trap import failure so that everything in the Job module but the
|
||||
# Parallel class (and its dependent classes) will work if the interpreter
|
||||
# doesn't support threads.
|
||||
try:
|
||||
import queue
|
||||
import threading
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
class Worker(threading.Thread):
|
||||
"""A worker thread waits on a task to be posted to its request queue,
|
||||
dequeues the task, executes it, and posts a tuple including the task
|
||||
and a boolean indicating whether the task executed successfully. """
|
||||
|
||||
def __init__(self, requestQueue, resultsQueue, interrupted):
|
||||
threading.Thread.__init__(self)
|
||||
self.setDaemon(1)
|
||||
self.requestQueue = requestQueue
|
||||
self.resultsQueue = resultsQueue
|
||||
self.interrupted = interrupted
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
task = self.requestQueue.get()
|
||||
|
||||
if task is None:
|
||||
# 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:
|
||||
if self.interrupted():
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
task.execute()
|
||||
except:
|
||||
task.exception_set()
|
||||
ok = False
|
||||
else:
|
||||
ok = True
|
||||
|
||||
self.resultsQueue.put((task, ok))
|
||||
|
||||
class ThreadPool(object):
|
||||
"""This class is responsible for spawning and managing worker threads."""
|
||||
|
||||
def __init__(self, num, stack_size, interrupted):
|
||||
"""Create the request and reply queues, and 'num' worker threads.
|
||||
|
||||
One must specify the stack size of the worker threads. The
|
||||
stack size is specified in kilobytes.
|
||||
"""
|
||||
self.requestQueue = queue.Queue(0)
|
||||
self.resultsQueue = queue.Queue(0)
|
||||
|
||||
try:
|
||||
prev_size = threading.stack_size(stack_size*1024)
|
||||
except AttributeError, e:
|
||||
# Only print a warning if the stack size has been
|
||||
# explicitly set.
|
||||
if not explicit_stack_size is None:
|
||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||
e.args[0]
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
except ValueError, e:
|
||||
msg = "Setting stack size failed:\n " + str(e)
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
|
||||
# Create worker threads
|
||||
self.workers = []
|
||||
for _ in range(num):
|
||||
worker = Worker(self.requestQueue, self.resultsQueue, interrupted)
|
||||
self.workers.append(worker)
|
||||
|
||||
if 'prev_size' in locals():
|
||||
threading.stack_size(prev_size)
|
||||
|
||||
def put(self, task):
|
||||
"""Put task into request queue."""
|
||||
self.requestQueue.put(task)
|
||||
|
||||
def get(self):
|
||||
"""Remove and return a result tuple from the results queue."""
|
||||
return self.resultsQueue.get()
|
||||
|
||||
def preparation_failed(self, task):
|
||||
self.resultsQueue.put((task, 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(object):
|
||||
"""This class is used to execute tasks in parallel, and is somewhat
|
||||
less efficient than Serial, but is appropriate for parallel builds.
|
||||
|
||||
This class is thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster, num, stack_size):
|
||||
"""Create a new parallel job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next
|
||||
task that needs to be executed, or None if there are no more
|
||||
tasks. The taskmaster's executed() method will be called
|
||||
for each task when it is successfully executed or failed()
|
||||
will be called if the task failed to execute (i.e. execute()
|
||||
raised an exception).
|
||||
|
||||
Note: calls to taskmaster are serialized, but calls to
|
||||
execute() on distinct tasks are not serialized, because
|
||||
that is the whole point of parallel jobs: they can execute
|
||||
multiple tasks simultaneously. """
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
self.tp = ThreadPool(num, stack_size, self.interrupted)
|
||||
|
||||
self.maxjobs = num
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the
|
||||
taskmaster and executing them, and return when there are no
|
||||
more tasks. If a task fails to execute (i.e. execute() raises
|
||||
an exception), then the job will stop."""
|
||||
|
||||
jobs = 0
|
||||
|
||||
while True:
|
||||
# Start up as many available tasks as we're
|
||||
# allowed to.
|
||||
while jobs < self.maxjobs:
|
||||
task = self.taskmaster.next_task()
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
# prepare task for execution
|
||||
task.prepare()
|
||||
except:
|
||||
task.exception_set()
|
||||
task.failed()
|
||||
task.postprocess()
|
||||
else:
|
||||
if task.needs_execute():
|
||||
# dispatch task
|
||||
self.tp.put(task)
|
||||
jobs = jobs + 1
|
||||
else:
|
||||
task.executed()
|
||||
task.postprocess()
|
||||
|
||||
if not task and not jobs: break
|
||||
|
||||
# Let any/all completed tasks finish up before we go
|
||||
# back and put the next batch of tasks on the queue.
|
||||
while True:
|
||||
task, ok = self.tp.get()
|
||||
jobs = jobs - 1
|
||||
|
||||
if ok:
|
||||
task.executed()
|
||||
else:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange
|
||||
# for the build to stop if that's appropriate.
|
||||
task.failed()
|
||||
|
||||
task.postprocess()
|
||||
|
||||
if self.tp.resultsQueue.empty():
|
||||
break
|
||||
|
||||
self.tp.cleanup()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,244 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Memoize.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
__doc__ = """Memoizer
|
||||
|
||||
A metaclass implementation to count hits and misses of the computed
|
||||
values that various methods cache in memory.
|
||||
|
||||
Use of this modules assumes that wrapped methods be coded to cache their
|
||||
values in a consistent way. Here is an example of wrapping a method
|
||||
that returns a computed value, with no input parameters:
|
||||
|
||||
memoizer_counters = [] # Memoization
|
||||
|
||||
memoizer_counters.append(SCons.Memoize.CountValue('foo')) # Memoization
|
||||
|
||||
def foo(self):
|
||||
|
||||
try: # Memoization
|
||||
return self._memo['foo'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_foo_value()
|
||||
|
||||
self._memo['foo'] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
Here is an example of wrapping a method that will return different values
|
||||
based on one or more input arguments:
|
||||
|
||||
def _bar_key(self, argument): # Memoization
|
||||
return argument # Memoization
|
||||
|
||||
memoizer_counters.append(SCons.Memoize.CountDict('bar', _bar_key)) # Memoization
|
||||
|
||||
def bar(self, argument):
|
||||
|
||||
memo_key = argument # Memoization
|
||||
try: # Memoization
|
||||
memo_dict = self._memo['bar'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
memo_dict = {} # Memoization
|
||||
self._memo['dict'] = memo_dict # Memoization
|
||||
else: # Memoization
|
||||
try: # Memoization
|
||||
return memo_dict[memo_key] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_bar_value(argument)
|
||||
|
||||
memo_dict[memo_key] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
At one point we avoided replicating this sort of logic in all the methods
|
||||
by putting it right into this module, but we've moved away from that at
|
||||
present (see the "Historical Note," below.).
|
||||
|
||||
Deciding what to cache is tricky, because different configurations
|
||||
can have radically different performance tradeoffs, and because the
|
||||
tradeoffs involved are often so non-obvious. Consequently, deciding
|
||||
whether or not to cache a given method will likely be more of an art than
|
||||
a science, but should still be based on available data from this module.
|
||||
Here are some VERY GENERAL guidelines about deciding whether or not to
|
||||
cache return values from a method that's being called a lot:
|
||||
|
||||
-- The first question to ask is, "Can we change the calling code
|
||||
so this method isn't called so often?" Sometimes this can be
|
||||
done by changing the algorithm. Sometimes the *caller* should
|
||||
be memoized, not the method you're looking at.
|
||||
|
||||
-- The memoized function should be timed with multiple configurations
|
||||
to make sure it doesn't inadvertently slow down some other
|
||||
configuration.
|
||||
|
||||
-- When memoizing values based on a dictionary key composed of
|
||||
input arguments, you don't need to use all of the arguments
|
||||
if some of them don't affect the return values.
|
||||
|
||||
Historical Note: The initial Memoizer implementation actually handled
|
||||
the caching of values for the wrapped methods, based on a set of generic
|
||||
algorithms for computing hashable values based on the method's arguments.
|
||||
This collected caching logic nicely, but had two drawbacks:
|
||||
|
||||
Running arguments through a generic key-conversion mechanism is slower
|
||||
(and less flexible) than just coding these things directly. Since the
|
||||
methods that need memoized values are generally performance-critical,
|
||||
slowing them down in order to collect the logic isn't the right
|
||||
tradeoff.
|
||||
|
||||
Use of the memoizer really obscured what was being called, because
|
||||
all the memoized methods were wrapped with re-used generic methods.
|
||||
This made it more difficult, for example, to use the Python profiler
|
||||
to figure out how to optimize the underlying methods.
|
||||
"""
|
||||
|
||||
import types
|
||||
|
||||
# A flag controlling whether or not we actually use memoization.
|
||||
use_memoizer = None
|
||||
|
||||
CounterList = []
|
||||
|
||||
class Counter(object):
|
||||
"""
|
||||
Base class for counting memoization hits and misses.
|
||||
|
||||
We expect that the metaclass initialization will have filled in
|
||||
the .name attribute that represents the name of the function
|
||||
being counted.
|
||||
"""
|
||||
def __init__(self, method_name):
|
||||
"""
|
||||
"""
|
||||
self.method_name = method_name
|
||||
self.hit = 0
|
||||
self.miss = 0
|
||||
CounterList.append(self)
|
||||
def display(self):
|
||||
fmt = " %7d hits %7d misses %s()"
|
||||
print fmt % (self.hit, self.miss, self.name)
|
||||
def __cmp__(self, other):
|
||||
try:
|
||||
return cmp(self.name, other.name)
|
||||
except AttributeError:
|
||||
return 0
|
||||
|
||||
class CountValue(Counter):
|
||||
"""
|
||||
A counter class for simple, atomic memoized values.
|
||||
|
||||
A CountValue object should be instantiated in a class for each of
|
||||
the class's methods that memoizes its return value by simply storing
|
||||
the return value in its _memo dictionary.
|
||||
|
||||
We expect that the metaclass initialization will fill in the
|
||||
.underlying_method attribute with the method that we're wrapping.
|
||||
We then call the underlying_method method after counting whether
|
||||
its memoized value has already been set (a hit) or not (a miss).
|
||||
"""
|
||||
def __call__(self, *args, **kw):
|
||||
obj = args[0]
|
||||
if self.method_name in obj._memo:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
return self.underlying_method(*args, **kw)
|
||||
|
||||
class CountDict(Counter):
|
||||
"""
|
||||
A counter class for memoized values stored in a dictionary, with
|
||||
keys based on the method's input arguments.
|
||||
|
||||
A CountDict object is instantiated in a class for each of the
|
||||
class's methods that memoizes its return value in a dictionary,
|
||||
indexed by some key that can be computed from one or more of
|
||||
its input arguments.
|
||||
|
||||
We expect that the metaclass initialization will fill in the
|
||||
.underlying_method attribute with the method that we're wrapping.
|
||||
We then call the underlying_method method after counting whether the
|
||||
computed key value is already present in the memoization dictionary
|
||||
(a hit) or not (a miss).
|
||||
"""
|
||||
def __init__(self, method_name, keymaker):
|
||||
"""
|
||||
"""
|
||||
Counter.__init__(self, method_name)
|
||||
self.keymaker = keymaker
|
||||
def __call__(self, *args, **kw):
|
||||
obj = args[0]
|
||||
try:
|
||||
memo_dict = obj._memo[self.method_name]
|
||||
except KeyError:
|
||||
self.miss = self.miss + 1
|
||||
else:
|
||||
key = self.keymaker(*args, **kw)
|
||||
if key in memo_dict:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
return self.underlying_method(*args, **kw)
|
||||
|
||||
class Memoizer(object):
|
||||
"""Object which performs caching of method calls for its 'primary'
|
||||
instance."""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Dump(title=None):
|
||||
if title:
|
||||
print title
|
||||
CounterList.sort()
|
||||
for counter in CounterList:
|
||||
counter.display()
|
||||
|
||||
class Memoized_Metaclass(type):
|
||||
def __init__(cls, name, bases, cls_dict):
|
||||
super(Memoized_Metaclass, cls).__init__(name, bases, cls_dict)
|
||||
|
||||
for counter in cls_dict.get('memoizer_counters', []):
|
||||
method_name = counter.method_name
|
||||
|
||||
counter.name = cls.__name__ + '.' + method_name
|
||||
counter.underlying_method = cls_dict[method_name]
|
||||
|
||||
replacement_method = types.MethodType(counter, None, cls)
|
||||
setattr(cls, method_name, replacement_method)
|
||||
|
||||
def EnableMemoization():
|
||||
global use_memoizer
|
||||
use_memoizer = 1
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,152 @@
|
||||
|
||||
"""scons.Node.Alias
|
||||
|
||||
Alias nodes.
|
||||
|
||||
This creates a hash of global Aliases (dummy targets).
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Node/Alias.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
import collections
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
|
||||
class AliasNameSpace(collections.UserDict):
|
||||
def Alias(self, name, **kw):
|
||||
if isinstance(name, SCons.Node.Alias.Alias):
|
||||
return name
|
||||
try:
|
||||
a = self[name]
|
||||
except KeyError:
|
||||
a = SCons.Node.Alias.Alias(name, **kw)
|
||||
self[name] = a
|
||||
return a
|
||||
|
||||
def lookup(self, name, **kw):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
class AliasNodeInfo(SCons.Node.NodeInfoBase):
|
||||
current_version_id = 1
|
||||
field_list = ['csig']
|
||||
def str_to_node(self, s):
|
||||
return default_ans.Alias(s)
|
||||
|
||||
class AliasBuildInfo(SCons.Node.BuildInfoBase):
|
||||
current_version_id = 1
|
||||
|
||||
class Alias(SCons.Node.Node):
|
||||
|
||||
NodeInfo = AliasNodeInfo
|
||||
BuildInfo = AliasBuildInfo
|
||||
|
||||
def __init__(self, name):
|
||||
SCons.Node.Node.__init__(self)
|
||||
self.name = name
|
||||
|
||||
def str_for_display(self):
|
||||
return '"' + self.__str__() + '"'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def make_ready(self):
|
||||
self.get_csig()
|
||||
|
||||
really_build = SCons.Node.Node.build
|
||||
is_up_to_date = SCons.Node.Node.children_are_up_to_date
|
||||
|
||||
def is_under(self, dir):
|
||||
# Make Alias nodes get built regardless of
|
||||
# what directory scons was run from. Alias nodes
|
||||
# are outside the filesystem:
|
||||
return 1
|
||||
|
||||
def get_contents(self):
|
||||
"""The contents of an alias is the concatenation
|
||||
of the content signatures of all its sources."""
|
||||
childsigs = [n.get_csig() for n in self.children()]
|
||||
return ''.join(childsigs)
|
||||
|
||||
def sconsign(self):
|
||||
"""An Alias is not recorded in .sconsign files"""
|
||||
pass
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
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):
|
||||
"""A "builder" for aliases."""
|
||||
pass
|
||||
|
||||
def convert(self):
|
||||
try: del self.builder
|
||||
except AttributeError: pass
|
||||
self.reset_executor()
|
||||
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()
|
||||
|
||||
SCons.Node.arg2nodes_lookups.append(default_ans.lookup)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
"""scons.Node.Python
|
||||
|
||||
Python nodes.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Node/Python.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
import SCons.Node
|
||||
|
||||
class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
||||
current_version_id = 1
|
||||
|
||||
field_list = ['csig']
|
||||
|
||||
def str_to_node(self, s):
|
||||
return Value(s)
|
||||
|
||||
class ValueBuildInfo(SCons.Node.BuildInfoBase):
|
||||
current_version_id = 1
|
||||
|
||||
class Value(SCons.Node.Node):
|
||||
"""A class for Python variables, typically passed on the command line
|
||||
or generated by a script, but not from a file or some other source.
|
||||
"""
|
||||
|
||||
NodeInfo = ValueNodeInfo
|
||||
BuildInfo = ValueBuildInfo
|
||||
|
||||
def __init__(self, value, built_value=None):
|
||||
SCons.Node.Node.__init__(self)
|
||||
self.value = value
|
||||
if built_value is not None:
|
||||
self.built_value = built_value
|
||||
|
||||
def str_for_display(self):
|
||||
return repr(self.value)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
def make_ready(self):
|
||||
self.get_csig()
|
||||
|
||||
def build(self, **kw):
|
||||
if not hasattr(self, 'built_value'):
|
||||
SCons.Node.Node.build(self, **kw)
|
||||
|
||||
is_up_to_date = SCons.Node.Node.children_are_up_to_date
|
||||
|
||||
def is_under(self, dir):
|
||||
# Make Value nodes get built regardless of
|
||||
# what directory scons was run from. Value nodes
|
||||
# are outside the filesystem:
|
||||
return 1
|
||||
|
||||
def write(self, built_value):
|
||||
"""Set the value of the node."""
|
||||
self.built_value = built_value
|
||||
|
||||
def read(self):
|
||||
"""Return the value. If necessary, the value is built."""
|
||||
self.build()
|
||||
if not hasattr(self, 'built_value'):
|
||||
self.built_value = self.value
|
||||
return self.built_value
|
||||
|
||||
def get_text_contents(self):
|
||||
"""By the assumption that the node.built_value is a
|
||||
deterministic product of the sources, the contents of a Value
|
||||
are the concatenation of all the contents of its sources. As
|
||||
the value need not be built when get_contents() is called, we
|
||||
cannot use the actual node.built_value."""
|
||||
###TODO: something reasonable about universal newlines
|
||||
contents = str(self.value)
|
||||
for kid in self.children(None):
|
||||
contents = contents + kid.get_contents()
|
||||
return contents
|
||||
|
||||
get_contents = get_text_contents ###TODO should return 'bytes' value
|
||||
|
||||
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):
|
||||
"""Because we're a Python value node and don't have a real
|
||||
timestamp, we get to ignore the calculator and just use the
|
||||
value contents."""
|
||||
try:
|
||||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
contents = self.get_contents()
|
||||
self.get_ninfo().csig = contents
|
||||
return contents
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Options/BoolOption.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def BoolOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The BoolOption() function is deprecated; use the BoolVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.BoolVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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/Options/EnumOption.py 5134 2010/08/16 23:02:40 bdeegan"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def EnumOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The EnumOption() function is deprecated; use the EnumVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.EnumVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user