port Scons3 support from master

This commit is contained in:
Artem Pavlenko 2017-11-24 11:29:14 +01:00
parent f5ea42b11f
commit b0f3f1aed7
219 changed files with 4903 additions and 3679 deletions

View file

@ -1,6 +1,6 @@
# This file is part of Mapnik (c++ mapping toolkit) # This file is part of Mapnik (c++ mapping toolkit)
# #
# Copyright (C) 2015 Artem Pavlenko # Copyright (C) 2017 Artem Pavlenko
# #
# Mapnik is free software; you can redistribute it and/or # Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +16,7 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from __future__ import print_function # support python2
import os import os
import sys import sys
@ -136,7 +137,7 @@ env = Environment(ENV=os.environ)
init_environment(env) init_environment(env)
def fix_path(path): def fix_path(path):
return os.path.abspath(path) return str(os.path.abspath(path))
def color_print(color,text,newline=True): def color_print(color,text,newline=True):
# 1 - red # 1 - red
@ -145,15 +146,15 @@ def color_print(color,text,newline=True):
# 4 - blue # 4 - blue
text = "\033[9%sm%s\033[0m" % (color,text) text = "\033[9%sm%s\033[0m" % (color,text)
if not newline: if not newline:
print text, print (text, end='')
else: else:
print text print (text)
def regular_print(color,text,newline=True): def regular_print(color,text,newline=True):
if not newline: if not newline:
print text, print (text, end='')
else: else:
print text print (text)
def call(cmd, silent=False): def call(cmd, silent=False):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate() stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
@ -244,7 +245,7 @@ def sort_paths(items,priority):
path_types['other'].append(i) path_types['other'].append(i)
# build up new list based on priority list # build up new list based on priority list
for path in priority: for path in priority:
if path_types.has_key(path): if path in path_types:
dirs = path_types[path] dirs = path_types[path]
new.extend(dirs) new.extend(dirs)
path_types.pop(path) path_types.pop(path)
@ -510,7 +511,7 @@ elif HELP_REQUESTED:
# https://github.com/mapnik/mapnik/issues/2112 # https://github.com/mapnik/mapnik/issues/2112
if not os.path.exists(SCONS_LOCAL_LOG) and not os.path.exists(SCONS_CONFIGURE_CACHE) \ if not os.path.exists(SCONS_LOCAL_LOG) and not os.path.exists(SCONS_CONFIGURE_CACHE) \
and ('-c' in command_line_args or '--clean' in command_line_args): and ('-c' in command_line_args or '--clean' in command_line_args):
print 'all good: nothing to clean, but you might want to run "make distclean"' print ('all good: nothing to clean, but you might want to run "make distclean"')
Exit(0) Exit(0)
# initially populate environment with defaults and any possible custom arguments # initially populate environment with defaults and any possible custom arguments
@ -520,7 +521,7 @@ opts.Update(env)
if not force_configure: if not force_configure:
if os.path.exists(SCONS_CONFIGURE_CACHE): if os.path.exists(SCONS_CONFIGURE_CACHE):
try: try:
pickled_environment = open(SCONS_CONFIGURE_CACHE, 'r') pickled_environment = open(SCONS_CONFIGURE_CACHE, 'rb')
pickled_values = pickle.load(pickled_environment) pickled_values = pickle.load(pickled_environment)
for key, value in pickled_values.items(): for key, value in pickled_values.items():
env[key] = value env[key] = value
@ -552,7 +553,7 @@ elif preconfigured:
color_print(4,'Using previous successful configuration...') color_print(4,'Using previous successful configuration...')
color_print(4,'Re-configure by running "python scons/scons.py configure".') color_print(4,'Re-configure by running "python scons/scons.py configure".')
if env.has_key('COLOR_PRINT') and env['COLOR_PRINT'] == False: if 'COLOR_PRINT' in env and env['COLOR_PRINT'] == False:
color_print = regular_print color_print = regular_print
if sys.platform == "win32": if sys.platform == "win32":
@ -621,9 +622,9 @@ def parse_config(context, config, checks='--libs --cflags'):
else: else:
env.ParseConfig(cmd) env.ParseConfig(cmd)
parsed = True parsed = True
except OSError, e: except OSError as e:
ret = False ret = False
print ' (xml2-config not found!)' print (' (xml2-config not found!)')
if not parsed: if not parsed:
if config in ('GDAL_CONFIG'): if config in ('GDAL_CONFIG'):
# optional deps... # optional deps...
@ -646,7 +647,7 @@ def get_pkg_lib(context, config, lib):
parsed = False parsed = False
if ret: if ret:
try: try:
value = call(cmd,silent=True) value = call(cmd,silent=True).decode("utf8")
if ' ' in value: if ' ' in value:
parts = value.split(' ') parts = value.split(' ')
if len(parts) > 1: if len(parts) > 1:
@ -657,9 +658,9 @@ def get_pkg_lib(context, config, lib):
else: else:
# osx 1.8 install gives '-framework GDAL' # osx 1.8 install gives '-framework GDAL'
libname = 'gdal' libname = 'gdal'
except Exception, e: except Exception as e:
ret = False ret = False
print ' unable to determine library name:'# %s' % str(e) print (' unable to determine library name:# {0!s}'.format(e))
return None return None
context.Result( libname ) context.Result( libname )
return libname return libname
@ -671,8 +672,8 @@ def parse_pg_config(context, config):
context.Message( 'Checking for %s... ' % tool) context.Message( 'Checking for %s... ' % tool)
ret = context.TryAction(env[config])[0] ret = context.TryAction(env[config])[0]
if ret: if ret:
lib_path = call('%s --libdir' % env[config]) lib_path = call('%s --libdir' % env[config]).decode("utf8")
inc_path = call('%s --includedir' % env[config]) inc_path = call('%s --includedir' % env[config]).decode("utf8")
env.AppendUnique(CPPPATH = fix_path(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = fix_path(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
lpq = env['PLUGINS']['postgis']['lib'] lpq = env['PLUGINS']['postgis']['lib']
@ -807,7 +808,7 @@ int main()
return ret return ret
def CheckIcuData(context, silent=False): def CheckIcuData(context, silent=False):
if not silent: if not silent:
context.Message('Checking for ICU data directory...') context.Message('Checking for ICU data directory...')
ret = context.TryRun(""" ret = context.TryRun("""
@ -834,7 +835,7 @@ int main() {
return ret[1].strip() return ret[1].strip()
def CheckGdalData(context, silent=False): def CheckGdalData(context, silent=False):
if not silent: if not silent:
context.Message('Checking for GDAL data directory...') context.Message('Checking for GDAL data directory...')
ret = context.TryRun(""" ret = context.TryRun("""
@ -857,7 +858,7 @@ int main() {
return ret[1].strip() return ret[1].strip()
def CheckProjData(context, silent=False): def CheckProjData(context, silent=False):
if not silent: if not silent:
context.Message('Checking for PROJ_LIB directory...') context.Message('Checking for PROJ_LIB directory...')
ret = context.TryRun(""" ret = context.TryRun("""
@ -1235,7 +1236,7 @@ if not preconfigured:
if os.path.exists(conf): if os.path.exists(conf):
opts.files.append(conf) opts.files.append(conf)
color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf) color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf)
optfile = file(conf) optfile = open(conf, 'r')
#print optfile.read().replace("\n", " ").replace("'","").replace(" = ","=") #print optfile.read().replace("\n", " ").replace("'","").replace(" = ","=")
optfile.close() optfile.close()
@ -1402,7 +1403,7 @@ if not preconfigured:
temp_env.ParseConfig('%s --libs' % env['FREETYPE_CONFIG']) temp_env.ParseConfig('%s --libs' % env['FREETYPE_CONFIG'])
if 'bz2' in temp_env['LIBS']: if 'bz2' in temp_env['LIBS']:
env['EXTRA_FREETYPE_LIBS'].append('bz2') env['EXTRA_FREETYPE_LIBS'].append('bz2')
except OSError,e: except OSError as e:
pass pass
# libxml2 should be optional but is currently not # libxml2 should be optional but is currently not
@ -1703,7 +1704,7 @@ if not preconfigured:
if not lib in env['LIBS']: if not lib in env['LIBS']:
env["SQLITE_LINKFLAGS"].append(lib) env["SQLITE_LINKFLAGS"].append(lib)
env.Append(LIBS=lib) env.Append(LIBS=lib)
except OSError,e: except OSError as e:
for lib in ["sqlite3","dl","pthread"]: for lib in ["sqlite3","dl","pthread"]:
if not lib in env['LIBS']: if not lib in env['LIBS']:
env["SQLITE_LINKFLAGS"].append("lib") env["SQLITE_LINKFLAGS"].append("lib")
@ -1786,7 +1787,7 @@ if not preconfigured:
env['HAS_CAIRO'] = False env['HAS_CAIRO'] = False
env['SKIPPED_DEPS'].append('cairo') env['SKIPPED_DEPS'].append('cairo')
else: else:
print 'Checking for cairo lib and include paths... ', print ('Checking for cairo lib and include paths... ', end='')
cmd = 'pkg-config --libs --cflags cairo' cmd = 'pkg-config --libs --cflags cairo'
if env['RUNTIME_LINK'] == 'static': if env['RUNTIME_LINK'] == 'static':
cmd += ' --static' cmd += ' --static'
@ -1803,8 +1804,8 @@ if not preconfigured:
if not inc in env['CPPPATH']: if not inc in env['CPPPATH']:
env["CAIRO_CPPPATHS"].append(inc) env["CAIRO_CPPPATHS"].append(inc)
env['HAS_CAIRO'] = True env['HAS_CAIRO'] = True
print 'yes' print ('yes')
except OSError,e: except OSError as e:
color_print(1,'no') color_print(1,'no')
env['SKIPPED_DEPS'].append('cairo') env['SKIPPED_DEPS'].append('cairo')
color_print(1,'pkg-config reported: %s' % e) color_print(1,'pkg-config reported: %s' % e)
@ -1959,7 +1960,7 @@ if not preconfigured:
# finish config stage and pickle results # finish config stage and pickle results
env = conf.Finish() env = conf.Finish()
env_cache = open(SCONS_CONFIGURE_CACHE, 'w') env_cache = open(SCONS_CONFIGURE_CACHE, 'wb')
pickle_dict = {} pickle_dict = {}
for i in pickle_store: for i in pickle_store:
pickle_dict[i] = env.get(i) pickle_dict[i] = env.get(i)
@ -1970,20 +1971,20 @@ if not preconfigured:
# with a non-root configure following a root install # with a non-root configure following a root install
# that also triggered a re-configure # that also triggered a re-configure
try: try:
os.chmod(SCONS_CONFIGURE_CACHE,0666) os.chmod(SCONS_CONFIGURE_CACHE,0o666)
except: pass except: pass
try: try:
os.chmod(SCONS_LOCAL_CONFIG,0666) os.chmod(SCONS_LOCAL_CONFIG,0o666)
except: pass except: pass
try: try:
os.chmod('.sconsign.dblite',0666) os.chmod('.sconsign.dblite',0o666)
except: pass except: pass
try: try:
os.chmod(SCONS_LOCAL_LOG,0666) os.chmod(SCONS_LOCAL_LOG,0o666)
except: pass except: pass
try: try:
for item in glob('%s/*' % SCONF_TEMP_DIR): for item in glob('%s/*' % SCONF_TEMP_DIR):
os.chmod(item,0666) os.chmod(item, 0o666)
except: pass except: pass
if 'configure' in command_line_args: if 'configure' in command_line_args:

View file

@ -43,5 +43,5 @@ ini = ini_template % locals()
open('viewer.ini','w').write(ini) open('viewer.ini','w').write(ini)
try: try:
os.chmod('viewer.ini',0666) os.chmod('viewer.ini',0o666)
except: pass except: pass

View file

@ -29,7 +29,7 @@ if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
can_build = True can_build = True
if not can_build: if not can_build:
print 'WARNING: skipping building the optional CSV datasource plugin which requires boost >= 1.56' print ('WARNING: skipping building the optional CSV datasource plugin which requires boost >= 1.56')
else: else:
Import ('plugin_base') Import ('plugin_base')

View file

@ -29,7 +29,7 @@ if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
can_build = True can_build = True
if not can_build: if not can_build:
print 'WARNING: skipping building the optional geojson datasource plugin which requires boost >= 1.56' print ('WARNING: skipping building the optional geojson datasource plugin which requires boost >= 1.56')
else: else:
Import ('plugin_base') Import ('plugin_base')

View file

@ -43,7 +43,7 @@ if env['RUNTIME_LINK'] == 'static':
cmd = 'pkg-config libpq --libs --static' cmd = 'pkg-config libpq --libs --static'
try: try:
plugin_env.ParseConfig(cmd) plugin_env.ParseConfig(cmd)
except OSError, e: except OSError as e:
plugin_env.Append(LIBS='pq') plugin_env.Append(LIBS='pq')
else: else:
plugin_env.Append(LIBS='pq') plugin_env.Append(LIBS='pq')

View file

@ -42,7 +42,7 @@ if env['RUNTIME_LINK'] == 'static':
cmd = 'pkg-config libpq --libs --static' cmd = 'pkg-config libpq --libs --static'
try: try:
plugin_env.ParseConfig(cmd) plugin_env.ParseConfig(cmd)
except OSError, e: except OSError as e:
plugin_env.Append(LIBS='pq') plugin_env.Append(LIBS='pq')
else: else:
plugin_env.Append(LIBS='pq') plugin_env.Append(LIBS='pq')

View file

@ -29,7 +29,7 @@ if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
can_build = True can_build = True
if not can_build: if not can_build:
print 'WARNING: skipping building the optional topojson datasource plugin which requires boost >= 1.56' print ('WARNING: skipping building the optional topojson datasource plugin which requires boost >= 1.56')
else: else:
Import ('plugin_base') Import ('plugin_base')

View file

@ -3,7 +3,7 @@
This copyright and license do not apply to any other software This copyright and license do not apply to any other software
with which this software may have been included. with which this software may have been included.
Copyright (c) 2001 - 2016 The SCons Foundation Copyright (c) 2001 - 2017 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

View file

@ -1,4 +1,4 @@
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 The SCons Foundation
SCons - a software construction tool SCons - a software construction tool

View file

@ -1,63 +0,0 @@
#
# Copyright (c) 2001 - 2016 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 rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
__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.DeprecatedSigModuleWarning, 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()
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,66 +0,0 @@
"""SCons.Tool.BitKeeper.py
Tool-specific initialization for the BitKeeper source code control
system.
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 - 2016 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/BitKeeper.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import SCons.Action
import SCons.Builder
import SCons.Util
def generate(env):
"""Add a Builder factory function and construction variables for
BitKeeper to an Environment."""
def BitKeeperFactory(env=env):
""" """
import SCons.Warnings as W
W.warn(W.DeprecatedSourceCodeWarning, """The BitKeeper() factory is deprecated and there is no replacement.""")
act = SCons.Action.Action("$BITKEEPERCOM", "$BITKEEPERCOMSTR")
return SCons.Builder.Builder(action = act, env = env)
env.BitKeeper = BitKeeperFactory
env['BITKEEPER'] = 'bk'
env['BITKEEPERGET'] = '$BITKEEPER get'
env['BITKEEPERGETFLAGS'] = SCons.Util.CLVar('')
env['BITKEEPERCOM'] = '$BITKEEPERGET $BITKEEPERGETFLAGS $TARGET'
def exists(env):
return env.Detect('bk')
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,72 +0,0 @@
"""SCons.Tool.CVS.py
Tool-specific initialization for CVS.
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 - 2016 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/CVS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import SCons.Action
import SCons.Builder
import SCons.Util
def generate(env):
"""Add a Builder factory function and construction variables for
CVS to an Environment."""
def CVSFactory(repos, module='', env=env):
""" """
import SCons.Warnings as W
W.warn(W.DeprecatedSourceCodeWarning, """The CVS() factory is deprecated and there is no replacement.""")
# fail if repos is not an absolute path name?
if module != '':
# Don't use os.path.join() because the name we fetch might
# be across a network and must use POSIX slashes as separators.
module = module + '/'
env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS -d ${TARGET.dir} $CVSMODULE${TARGET.posix}'
act = SCons.Action.Action('$CVSCOM', '$CVSCOMSTR')
return SCons.Builder.Builder(action = act,
env = env,
CVSREPOSITORY = repos,
CVSMODULE = module)
env.CVS = CVSFactory
env['CVS'] = 'cvs'
env['CVSFLAGS'] = SCons.Util.CLVar('-d $CVSREPOSITORY')
env['CVSCOFLAGS'] = SCons.Util.CLVar('')
env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS ${TARGET.posix}'
def exists(env):
return env.Detect('cvs')
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,413 +0,0 @@
"""SCons.Tool.GettextCommon module
Used by several tools of `gettext` toolset.
"""
# Copyright (c) 2001 - 2016 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/GettextCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import SCons.Warnings
import re
#############################################################################
class XgettextToolWarning(SCons.Warnings.Warning): pass
class XgettextNotFound(XgettextToolWarning): pass
class MsginitToolWarning(SCons.Warnings.Warning): pass
class MsginitNotFound(MsginitToolWarning): pass
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
class MsgmergeNotFound(MsgmergeToolWarning): pass
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
class MsgfmtNotFound(MsgfmtToolWarning): pass
#############################################################################
SCons.Warnings.enableWarningClass(XgettextToolWarning)
SCons.Warnings.enableWarningClass(XgettextNotFound)
SCons.Warnings.enableWarningClass(MsginitToolWarning)
SCons.Warnings.enableWarningClass(MsginitNotFound)
SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
SCons.Warnings.enableWarningClass(MsgmergeNotFound)
SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
SCons.Warnings.enableWarningClass(MsgfmtNotFound)
#############################################################################
#############################################################################
class _POTargetFactory(object):
""" A factory of `PO` target files.
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
(this is required by builders and actions gettext) and `noclean` flags by
default for all produced nodes.
"""
def __init__( self, env, nodefault = True, alias = None, precious = True
, noclean = True ):
""" Object constructor.
**Arguments**
- *env* (`SCons.Environment.Environment`)
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
from default target `'.'`
- *alias* (`string`) - if provided, produced nodes will be automatically
added to this alias, and alias will be set as `AlwaysBuild`
- *precious* (`boolean`) - if `True`, the produced nodes will be set as
`Precious`.
- *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
from `Clean`.
"""
self.env = env
self.alias = alias
self.precious = precious
self.noclean = noclean
self.nodefault = nodefault
def _create_node(self, name, factory, directory = None, create = 1):
""" Create node, and set it up to factory settings. """
import SCons.Util
node = factory(name, directory, create)
node.set_noclean(self.noclean)
node.set_precious(self.precious)
if self.nodefault:
self.env.Ignore('.', node)
if self.alias:
self.env.AlwaysBuild(self.env.Alias(self.alias, node))
return node
def Entry(self, name, directory = None, create = 1):
""" Create `SCons.Node.FS.Entry` """
return self._create_node(name, self.env.fs.Entry, directory, create)
def File(self, name, directory = None, create = 1):
""" Create `SCons.Node.FS.File` """
return self._create_node(name, self.env.fs.File, directory, create)
#############################################################################
#############################################################################
_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
#############################################################################
def _read_linguas_from_files(env, linguas_files = None):
""" Parse `LINGUAS` file and return list of extracted languages """
import SCons.Util
import SCons.Environment
global _re_comment
global _re_lang
if not SCons.Util.is_List(linguas_files) \
and not SCons.Util.is_String(linguas_files) \
and not isinstance(linguas_files, SCons.Node.FS.Base) \
and linguas_files:
# If, linguas_files==True or such, then read 'LINGUAS' file.
linguas_files = [ 'LINGUAS' ]
if linguas_files is None:
return []
fnodes = env.arg2nodes(linguas_files)
linguas = []
for fnode in fnodes:
contents = _re_comment.sub("", fnode.get_text_contents())
ls = [ l for l in _re_lang.findall(contents) if l ]
linguas.extend(ls)
return linguas
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
#############################################################################
class _POFileBuilder(BuilderBase):
""" `PO` file builder.
This is multi-target single-source builder. In typical situation the source
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
targets to be updated from this `POT`. We must run
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
dependencies separatelly for each target file.
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
with target being list of all targets, all targets would be rebuilt each time
one of the targets from this list is missing. This would happen, for example,
when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
`ll.po` file yet). To avoid this, we override
`SCons.Builder.BuilerBase._execute()` and call it separatelly for each
target. Here we also append to the target list the languages read from
`LINGUAS_FILE`.
"""
#
#* The argument for overriding _execute(): We must use environment with
# builder overrides applied (see BuilderBase.__init__(). Here it comes for
# free.
#* The argument against using 'emitter': The emitter is called too late
# by BuilderBase._execute(). If user calls, for example:
#
# env.POUpdate(LINGUAS_FILE = 'LINGUAS')
#
# the builder throws error, because it is called with target=None,
# source=None and is trying to "generate" sources or target list first.
# If user calls
#
# env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
#
# the env.BuilderWrapper() calls our builder with target=None,
# source=['foo', 'baz']. The BuilderBase._execute() then splits execution
# and execute iterativelly (recursion) self._execute(None, source[i]).
# After that it calls emitter (which is quite too late). The emitter is
# also called in each iteration, what makes things yet worse.
def __init__(self, env, **kw):
if not 'suffix' in kw:
kw['suffix'] = '$POSUFFIX'
if not 'src_suffix' in kw:
kw['src_suffix'] = '$POTSUFFIX'
if not 'src_builder' in kw:
kw['src_builder'] = '_POTUpdateBuilder'
if not 'single_source' in kw:
kw['single_source'] = True
alias = None
if 'target_alias' in kw:
alias = kw['target_alias']
del kw['target_alias']
if not 'target_factory' in kw:
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
BuilderBase.__init__(self, **kw)
def _execute(self, env, target, source, *args, **kw):
""" Execute builder's actions.
Here we append to `target` the languages read from `$LINGUAS_FILE` and
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
The arguments and return value are same as for
`SCons.Builder.BuilderBase._execute()`.
"""
import SCons.Util
import SCons.Node
linguas_files = None
if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE']:
linguas_files = env['LINGUAS_FILE']
# This prevents endless recursion loop (we'll be invoked once for
# each target appended here, we must not extend the list again).
env['LINGUAS_FILE'] = None
linguas = _read_linguas_from_files(env,linguas_files)
if SCons.Util.is_List(target):
target.extend(linguas)
elif target is not None:
target = [target] + linguas
else:
target = linguas
if not target:
# Let the SCons.BuilderBase to handle this patologic situation
return BuilderBase._execute( self, env, target, source, *args, **kw)
# The rest is ours
if not SCons.Util.is_List(target):
target = [ target ]
result = []
for tgt in target:
r = BuilderBase._execute( self, env, [tgt], source, *args, **kw)
result.extend(r)
if linguas_files is not None:
env['LINGUAS_FILE'] = linguas_files
return SCons.Node.NodeList(result)
#############################################################################
import SCons.Environment
#############################################################################
def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
""" Function for `Translate()` pseudo-builder """
if target is None: target = []
pot = env.POTUpdate(None, source, *args, **kw)
po = env.POUpdate(target, pot, *args, **kw)
return po
#############################################################################
#############################################################################
class RPaths(object):
""" Callable object, which returns pathnames relative to SCons current
working directory.
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
for nodes that are outside of current working directory (`env.fs.getcwd()`).
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
directory and source files (e.g. `*.c`) outside of it. When generating `POT`
template file, references to source files are written to `POT` template, so
a translator may later quickly jump to appropriate source file and line from
its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
interpreted by `PO` editor as paths relative to the place, where `PO` file
lives. The absolute paths would make resultant `POT` file nonportable, as
the references would be correct only on the machine, where `POT` file was
recently re-created. For such reason, we need a function, which always
returns relative paths. This is the purpose of `RPaths` callable object.
The `__call__` method returns paths relative to current working directory, but
we assume, that *xgettext(1)* is run from the directory, where target file is
going to be created.
Note, that this may not work for files distributed over several hosts or
across different drives on windows. We assume here, that single local
filesystem holds both source files and target `POT` templates.
Intended use of `RPaths` - in `xgettext.py`::
def generate(env):
from GettextCommon import RPaths
...
sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
env.Append(
...
XGETTEXTCOM = 'XGETTEXT ... ' + sources,
...
XgettextRPaths = RPaths(env)
)
"""
# NOTE: This callable object returns pathnames of dirs/files relative to
# current working directory. The pathname remains relative also for entries
# that are outside of current working directory (node, that
# SCons.Node.FS.File and siblings return absolute path in such case). For
# simplicity we compute path relative to current working directory, this
# seems be enough for our purposes (don't need TARGET variable and
# SCons.Defaults.Variable_Caller stuff).
def __init__(self, env):
""" Initialize `RPaths` callable object.
**Arguments**:
- *env* - a `SCons.Environment.Environment` object, defines *current
working dir*.
"""
self.env = env
# FIXME: I'm not sure, how it should be implemented (what the *args are in
# general, what is **kw).
def __call__(self, nodes, *args, **kw):
""" Return nodes' paths (strings) relative to current working directory.
**Arguments**:
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
- *args* - currently unused.
- *kw* - currently unused.
**Returns**:
- Tuple of strings, which represent paths relative to current working
directory (for given environment).
"""
import os
import SCons.Node.FS
rpaths = ()
cwd = self.env.fs.getcwd().get_abspath()
for node in nodes:
rpath = None
if isinstance(node, SCons.Node.FS.Base):
rpath = os.path.relpath(node.get_abspath(), cwd)
# FIXME: Other types possible here?
if rpath is not None:
rpaths += (rpath,)
return rpaths
#############################################################################
#############################################################################
def _init_po_files(target, source, env):
""" Action function for `POInit` builder. """
nop = lambda target, source, env : 0
if env.has_key('POAUTOINIT'):
autoinit = env['POAUTOINIT']
else:
autoinit = False
# Well, if everything outside works well, this loop should do single
# iteration. Otherwise we are rebuilding all the targets even, if just
# one has changed (but is this our fault?).
for tgt in target:
if not tgt.exists():
if autoinit:
action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
else:
msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
+ 'If you are a translator, you can create it through: \n' \
+ '$MSGINITCOM'
action = SCons.Action.Action(nop, msg)
status = action([tgt], source, env)
if status: return status
return 0
#############################################################################
#############################################################################
def _detect_xgettext(env):
""" Detects *xgettext(1)* binary """
if env.has_key('XGETTEXT'):
return env['XGETTEXT']
xgettext = env.Detect('xgettext');
if xgettext:
return xgettext
raise SCons.Errors.StopError(XgettextNotFound,"Could not detect xgettext")
return None
#############################################################################
def _xgettext_exists(env):
return _detect_xgettext(env)
#############################################################################
#############################################################################
def _detect_msginit(env):
""" Detects *msginit(1)* program. """
if env.has_key('MSGINIT'):
return env['MSGINIT']
msginit = env.Detect('msginit');
if msginit:
return msginit
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
return None
#############################################################################
def _msginit_exists(env):
return _detect_msginit(env)
#############################################################################
#############################################################################
def _detect_msgmerge(env):
""" Detects *msgmerge(1)* program. """
if env.has_key('MSGMERGE'):
return env['MSGMERGE']
msgmerge = env.Detect('msgmerge');
if msgmerge:
return msgmerge
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
return None
#############################################################################
def _msgmerge_exists(env):
return _detect_msgmerge(env)
#############################################################################
#############################################################################
def _detect_msgfmt(env):
""" Detects *msgmfmt(1)* program. """
if env.has_key('MSGFMT'):
return env['MSGFMT']
msgfmt = env.Detect('msgfmt');
if msgfmt:
return msgfmt
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
return None
#############################################################################
def _msgfmt_exists(env):
return _detect_msgfmt(env)
#############################################################################
#############################################################################
def tool_list(platform, env):
""" List tools that shall be generated by top-level `gettext` tool """
return [ 'xgettext', 'msginit', 'msgmerge', 'msgfmt' ]
#############################################################################

View file

@ -1,99 +0,0 @@
"""SCons.Tool.Perforce.py
Tool-specific initialization for Perforce Source Code Management system.
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 - 2016 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/Perforce.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import os
import SCons.Action
import SCons.Builder
import SCons.Node.FS
import SCons.Util
# Variables that we want to import from the base OS environment.
_import_env = [ 'P4PORT', 'P4CLIENT', 'P4USER', 'USER', 'USERNAME', 'P4PASSWD',
'P4CHARSET', 'P4LANGUAGE', 'SystemRoot' ]
PerforceAction = SCons.Action.Action('$P4COM', '$P4COMSTR')
def generate(env):
"""Add a Builder factory function and construction variables for
Perforce to an Environment."""
def PerforceFactory(env=env):
""" """
import SCons.Warnings as W
W.warn(W.DeprecatedSourceCodeWarning, """The Perforce() factory is deprecated and there is no replacement.""")
return SCons.Builder.Builder(action = PerforceAction, env = env)
env.Perforce = PerforceFactory
env['P4'] = 'p4'
env['P4FLAGS'] = SCons.Util.CLVar('')
env['P4COM'] = '$P4 $P4FLAGS sync $TARGET'
try:
environ = env['ENV']
except KeyError:
environ = {}
env['ENV'] = environ
# Perforce seems to use the PWD environment variable rather than
# calling getcwd() for itself, which is odd. If no PWD variable
# is present, p4 WILL call getcwd, but this seems to cause problems
# with good ol' Windows's tilde-mangling for long file names.
environ['PWD'] = env.Dir('#').get_abspath()
for var in _import_env:
v = os.environ.get(var)
if v:
environ[var] = v
if SCons.Util.can_read_reg:
# If we can read the registry, add the path to Perforce to our environment.
try:
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
'Software\\Perforce\\environment')
val, tok = SCons.Util.RegQueryValueEx(k, 'P4INSTROOT')
SCons.Util.AddPathIfNotExists(environ, 'PATH', val)
except SCons.Util.RegError:
# Can't detect where Perforce is, hope the user has it set in the
# PATH.
pass
def exists(env):
return env.Detect('p4')
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,63 +0,0 @@
"""SCons.Tool.SCCS.py
Tool-specific initialization for SCCS.
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 - 2016 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/SCCS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import SCons.Action
import SCons.Builder
import SCons.Util
def generate(env):
"""Add a Builder factory function and construction variables for
SCCS to an Environment."""
def SCCSFactory(env=env):
""" """
import SCons.Warnings as W
W.warn(W.DeprecatedSourceCodeWarning, """The SCCS() factory is deprecated and there is no replacement.""")
act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR')
return SCons.Builder.Builder(action = act, env = env)
env.SCCS = SCCSFactory
env['SCCS'] = 'sccs'
env['SCCSFLAGS'] = SCons.Util.CLVar('')
env['SCCSGETFLAGS'] = SCons.Util.CLVar('')
env['SCCSCOM'] = '$SCCS $SCCSFLAGS get $SCCSGETFLAGS $TARGET'
def exists(env):
return env.Detect('sccs')
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,70 +0,0 @@
"""SCons.Tool.Subversion.py
Tool-specific initialization for Subversion.
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 - 2016 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/Subversion.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import os.path
import SCons.Action
import SCons.Builder
import SCons.Util
def generate(env):
"""Add a Builder factory function and construction variables for
Subversion to an Environment."""
def SubversionFactory(repos, module='', env=env):
""" """
# fail if repos is not an absolute path name?
import SCons.Warnings as W
W.warn(W.DeprecatedSourceCodeWarning, """The Subversion() factory is deprecated and there is no replacement.""")
if module != '':
module = os.path.join(module, '')
act = SCons.Action.Action('$SVNCOM', '$SVNCOMSTR')
return SCons.Builder.Builder(action = act,
env = env,
SVNREPOSITORY = repos,
SVNMODULE = module)
env.Subversion = SubversionFactory
env['SVN'] = 'svn'
env['SVNFLAGS'] = SCons.Util.CLVar('')
env['SVNCOM'] = '$SVN $SVNFLAGS cat $SVNREPOSITORY/$SVNMODULE$TARGET > $TARGET'
def exists(env):
return env.Detect('svn')
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,116 +0,0 @@
"""SCons.Tool.jar
Tool-specific initialization for jar.
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 - 2016 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/jar.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
import SCons.Subst
import SCons.Util
def jarSources(target, source, env, for_signature):
"""Only include sources that are not a manifest file."""
try:
env['JARCHDIR']
except KeyError:
jarchdir_set = False
else:
jarchdir_set = True
jarchdir = env.subst('$JARCHDIR', target=target, source=source)
if jarchdir:
jarchdir = env.fs.Dir(jarchdir)
result = []
for src in source:
contents = src.get_text_contents()
if contents[:16] != "Manifest-Version":
if jarchdir_set:
_chdir = jarchdir
else:
try:
_chdir = src.attributes.java_classdir
except AttributeError:
_chdir = None
if _chdir:
# If we are changing the dir with -C, then sources should
# be relative to that directory.
src = SCons.Subst.Literal(src.get_path(_chdir))
result.append('-C')
result.append(_chdir)
result.append(src)
return result
def jarManifest(target, source, env, for_signature):
"""Look in sources for a manifest file, if any."""
for src in source:
contents = src.get_text_contents()
if contents[:16] == "Manifest-Version":
return src
return ''
def jarFlags(target, source, env, for_signature):
"""If we have a manifest, make sure that the 'm'
flag is specified."""
jarflags = env.subst('$JARFLAGS', target=target, source=source)
for src in source:
contents = src.get_text_contents()
if contents[:16] == "Manifest-Version":
if not 'm' in jarflags:
return jarflags + 'm'
break
return jarflags
def generate(env):
"""Add Builders and construction variables for jar to an Environment."""
SCons.Tool.CreateJarBuilder(env)
env['JAR'] = 'jar'
env['JARFLAGS'] = SCons.Util.CLVar('cf')
env['_JARFLAGS'] = jarFlags
env['_JARMANIFEST'] = jarManifest
env['_JARSOURCES'] = jarSources
env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES'
env['JARCOM'] = "${TEMPFILE('$_JARCOM','$JARCOMSTR')}"
env['JARSUFFIX'] = '.jar'
def exists(env):
# As reported by Jan Nijtmans in issue #2730, the simple
# return env.Detect('jar')
# doesn't always work during initialization. For now, we
# stop trying to detect an executable (analogous to the
# javac Builder).
# TODO: Come up with a proper detect() routine...and enable it.
return 1
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,339 +0,0 @@
""" xgettext tool
Tool specific initialization of `xgettext` tool.
"""
# Copyright (c) 2001 - 2016 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/xgettext.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
#############################################################################
class _CmdRunner(object):
""" Callabe object, which runs shell command storing its stdout and stderr to
variables. It also provides `strfunction()` method, which shall be used by
scons Action objects to print command string. """
def __init__( self, command, commandstr = None):
self.out = None
self.err = None
self.status = None
self.command = command
self.commandstr = commandstr
def __call__(self, target, source, env):
import SCons.Action
import subprocess
import os
import sys
kw = {
'stdin' : 'devnull',
'stdout' : subprocess.PIPE,
'stderr' : subprocess.PIPE,
'universal_newlines' : True,
'shell' : True
}
command = env.subst(self.command, target = target, source = source)
proc = SCons.Action._subproc(env, command, **kw)
self.out, self.err = proc.communicate()
self.status = proc.wait()
if self.err: sys.stderr.write(unicode(self.err))
return self.status
def strfunction(self, target, source, env):
import os
comstr = self.commandstr
if env.subst(comstr, target = target, source = source) == "":
comstr = self.command
s = env.subst(comstr, target = target, source = source)
return s
#############################################################################
#############################################################################
def _update_pot_file(target, source, env):
""" Action function for `POTUpdate` builder """
import re
import os
import SCons.Action
nop = lambda target, source, env : 0
# Save scons cwd and os cwd (NOTE: they may be different. After the job, we
# revert each one to its original state).
save_cwd = env.fs.getcwd()
save_os_cwd = os.getcwd()
chdir = target[0].dir
chdir_str = repr(chdir.get_abspath())
# Print chdir message (employ SCons.Action.Action for that. It knows better
# than me how to to this correctly).
env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
# Go to target's directory and do our job
env.fs.chdir(chdir, 1) # Go into target's directory
try:
cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
status = action([ target[0] ], source, env)
except:
# Something went wrong.
env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
# Revert working dirs to previous state and re-throw exception.
env.fs.chdir(save_cwd, 0)
os.chdir(save_os_cwd)
raise
# Print chdir message.
env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
# Revert working dirs to previous state.
env.fs.chdir(save_cwd, 0)
os.chdir(save_os_cwd)
# If the command was not successfull, return error code.
if status: return status
new_content = cmd.out
if not new_content:
# When xgettext finds no internationalized messages, no *.pot is created
# (because we don't want to bother translators with empty POT files).
needs_update = False
explain = "no internationalized messages encountered"
else:
if target[0].exists():
# If the file already exists, it's left unaltered unless its messages
# are outdated (w.r.t. to these recovered by xgettext from sources).
old_content = target[0].get_text_contents()
re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
old_content_nocdate = re.sub(re_cdate,"",old_content)
new_content_nocdate = re.sub(re_cdate,"",new_content)
if(old_content_nocdate == new_content_nocdate):
# Messages are up-to-date
needs_update = False
explain = "messages in file found to be up-to-date"
else:
# Messages are outdated
needs_update = True
explain = "messages in file were outdated"
else:
# No POT file found, create new one
needs_update = True
explain = "new file"
if needs_update:
# Print message employing SCons.Action.Action for that.
msg = "Writing " + repr(str(target[0])) + " (" + explain + ")"
env.Execute(SCons.Action.Action(nop, msg))
f = open(str(target[0]),"w")
f.write(new_content)
f.close()
return 0
else:
# Print message employing SCons.Action.Action for that.
msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")"
env.Execute(SCons.Action.Action(nop, msg))
return 0
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
#############################################################################
class _POTBuilder(BuilderBase):
def _execute(self, env, target, source, *args):
if not target:
if env.has_key('POTDOMAIN') and env['POTDOMAIN']:
domain = env['POTDOMAIN']
else:
domain = 'messages'
target = [ domain ]
return BuilderBase._execute(self, env, target, source, *args)
#############################################################################
#############################################################################
def _scan_xgettext_from_files(target, source, env, files = None, path = None):
""" Parses `POTFILES.in`-like file and returns list of extracted file names.
"""
import re
import SCons.Util
import SCons.Node.FS
if files is None:
return 0
if not SCons.Util.is_List(files):
files = [ files ]
if path is None:
if env.has_key('XGETTEXTPATH'):
path = env['XGETTEXTPATH']
else:
path = []
if not SCons.Util.is_List(path):
path = [ path ]
path = SCons.Util.flatten(path)
dirs = ()
for p in path:
if not isinstance(p, SCons.Node.FS.Base):
if SCons.Util.is_String(p):
p = env.subst(p, source = source, target = target)
p = env.arg2nodes(p, env.fs.Dir)
dirs += tuple(p)
# cwd is the default search path (when no path is defined by user)
if not dirs:
dirs = (env.fs.getcwd(),)
# Parse 'POTFILE.in' files.
re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
re_trailws = re.compile(r'[ \t\r]+$')
for f in files:
# Find files in search path $XGETTEXTPATH
if isinstance(f, SCons.Node.FS.Base) and f.rexists():
contents = f.get_text_contents()
contents = re_comment.sub("", contents)
contents = re_emptyln.sub("", contents)
contents = re_trailws.sub("", contents)
depnames = contents.splitlines()
for depname in depnames:
depfile = SCons.Node.FS.find_file(depname, dirs)
if not depfile:
depfile = env.arg2nodes(depname, dirs[0].File)
env.Depends(target, depfile)
return 0
#############################################################################
#############################################################################
def _pot_update_emitter(target, source, env):
""" Emitter function for `POTUpdate` builder """
from SCons.Tool.GettextCommon import _POTargetFactory
import SCons.Util
import SCons.Node.FS
if env.has_key('XGETTEXTFROM'):
xfrom = env['XGETTEXTFROM']
else:
return target, source
if not SCons.Util.is_List(xfrom):
xfrom = [ xfrom ]
xfrom = SCons.Util.flatten(xfrom)
# Prepare list of 'POTFILE.in' files.
files = []
for xf in xfrom:
if not isinstance(xf, SCons.Node.FS.Base):
if SCons.Util.is_String(xf):
# Interpolate variables in strings
xf = env.subst(xf, source = source, target = target)
xf = env.arg2nodes(xf)
files.extend(xf)
if files:
env.Depends(target, files)
_scan_xgettext_from_files(target, source, env, files)
return target, source
#############################################################################
#############################################################################
from SCons.Environment import _null
#############################################################################
def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
return env._POTUpdateBuilder(target, source, **kw)
#############################################################################
#############################################################################
def _POTUpdateBuilder(env, **kw):
""" Creates `POTUpdate` builder object """
import SCons.Action
from SCons.Tool.GettextCommon import _POTargetFactory
kw['action'] = SCons.Action.Action(_update_pot_file, None)
kw['suffix'] = '$POTSUFFIX'
kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
kw['emitter'] = _pot_update_emitter
return _POTBuilder(**kw)
#############################################################################
#############################################################################
def generate(env,**kw):
""" Generate `xgettext` tool """
import SCons.Util
from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
try:
env['XGETTEXT'] = _detect_xgettext(env)
except:
env['XGETTEXT'] = 'xgettext'
# NOTE: sources="$SOURCES" would work as well. However, we use following
# construction to convert absolute paths provided by scons onto paths
# relative to current working dir. Note, that scons expands $SOURCE(S) to
# absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
# "../"). With source=$SOURCE these absolute paths would be written to the
# resultant *.pot file (and its derived *.po files) as references to lines in
# source code (e.g. referring lines in *.c files). Such references would be
# correct (e.g. in poedit) only on machine on which *.pot was generated and
# would be of no use on other hosts (having a copy of source code located
# in different place in filesystem).
sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
+ ', SOURCES)} $)'
# NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
# This is required by the POTUpdate builder's action.
xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
+ ' $_XGETTEXTFROMFLAGS -o - ' + sources
xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
+ ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
+ ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
env.SetDefault(
_XGETTEXTDOMAIN = '${TARGET.filebase}',
XGETTEXTFLAGS = [ ],
XGETTEXTCOM = xgettextcom,
XGETTEXTCOMSTR = '',
XGETTEXTPATH = [ ],
XGETTEXTPATHPREFIX = '-D',
XGETTEXTPATHSUFFIX = '',
XGETTEXTFROM = None,
XGETTEXTFROMPREFIX = '-f',
XGETTEXTFROMSUFFIX = '',
_XGETTEXTPATHFLAGS = xgettextpathflags,
_XGETTEXTFROMFLAGS = xgettextfromflags,
POTSUFFIX = ['.pot'],
POTUPDATE_ALIAS = 'pot-update',
XgettextRPaths = RPaths(env)
)
env.Append( BUILDERS = {
'_POTUpdateBuilder' : _POTUpdateBuilder(env)
} )
env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
#############################################################################
#############################################################################
def exists(env):
""" Check, whether the tool exists """
from SCons.Tool.GettextCommon import _xgettext_exists
try:
return _xgettext_exists(env)
except:
return False
#############################################################################
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -1,256 +0,0 @@
# dblite.py module contributed by Ralf W. Grosse-Kunstleve.
# Extended for Unicode by Steven Knight.
import SCons.compat
import os
# compat layer imports "cPickle" for us if it's available.
import pickle
import shutil
import time
keep_all_files = 00000
ignore_corrupt_dbfiles = 0
def corruption_warning(filename):
print "Warning: Discarding corrupt database:", filename
try: unicode
except NameError:
def is_string(s):
return isinstance(s, str)
else:
def is_string(s):
return type(s) in (str, unicode)
try:
unicode('a')
except NameError:
def unicode(s): return s
dblite_suffix = '.dblite'
tmp_suffix = '.tmp'
class dblite(object):
# Squirrel away references to the functions in various modules
# that we'll use when our __del__() method calls our sync() method
# during shutdown. We might get destroyed when Python is in the midst
# of tearing down the different modules we import in an essentially
# arbitrary order, and some of the various modules's global attributes
# may already be wiped out from under us.
#
# See the discussion at:
# http://mail.python.org/pipermail/python-bugs-list/2003-March/016877.html
_open = open
_pickle_dump = staticmethod(pickle.dump)
_os_chmod = os.chmod
try:
_os_chown = os.chown
except AttributeError:
_os_chown = None
_os_rename = os.rename
_os_unlink = os.unlink
_shutil_copyfile = shutil.copyfile
_time_time = time.time
def __init__(self, file_base_name, flag, mode):
assert flag in (None, "r", "w", "c", "n")
if (flag is None): flag = "r"
base, ext = os.path.splitext(file_base_name)
if ext == dblite_suffix:
# There's already a suffix on the file name, don't add one.
self._file_name = file_base_name
self._tmp_name = base + tmp_suffix
else:
self._file_name = file_base_name + dblite_suffix
self._tmp_name = file_base_name + tmp_suffix
self._flag = flag
self._mode = mode
self._dict = {}
self._needs_sync = 00000
if self._os_chown is not None and (os.geteuid()==0 or os.getuid()==0):
# running as root; chown back to current owner/group when done
try:
statinfo = os.stat(self._file_name)
self._chown_to = statinfo.st_uid
self._chgrp_to = statinfo.st_gid
except OSError, e:
# db file doesn't exist yet.
# Check os.environ for SUDO_UID, use if set
self._chown_to = int(os.environ.get('SUDO_UID', -1))
self._chgrp_to = int(os.environ.get('SUDO_GID', -1))
else:
self._chown_to = -1 # don't chown
self._chgrp_to = -1 # don't chgrp
if (self._flag == "n"):
self._open(self._file_name, "wb", self._mode)
else:
try:
f = self._open(self._file_name, "rb")
except IOError, e:
if (self._flag != "c"):
raise e
self._open(self._file_name, "wb", self._mode)
else:
p = f.read()
if (len(p) > 0):
try:
self._dict = pickle.loads(p)
except (pickle.UnpicklingError, EOFError, KeyError):
# Note how we catch KeyErrors too here, which might happen
# when we don't have cPickle available (default pickle
# throws it).
if (ignore_corrupt_dbfiles == 0): raise
if (ignore_corrupt_dbfiles == 1):
corruption_warning(self._file_name)
def close(self):
if (self._needs_sync):
self.sync()
def __del__(self):
self.close()
def sync(self):
self._check_writable()
f = self._open(self._tmp_name, "wb", self._mode)
self._pickle_dump(self._dict, f, 1)
f.close()
# Windows doesn't allow renaming if the file exists, so unlink
# it first, chmod'ing it to make sure we can do so. On UNIX, we
# may not be able to chmod the file if it's owned by someone else
# (e.g. from a previous run as root). We should still be able to
# unlink() the file if the directory's writable, though, so ignore
# any OSError exception thrown by the chmod() call.
try: self._os_chmod(self._file_name, 0777)
except OSError: pass
self._os_unlink(self._file_name)
self._os_rename(self._tmp_name, self._file_name)
if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1
try:
self._os_chown(self._file_name, self._chown_to, self._chgrp_to)
except OSError:
pass
self._needs_sync = 00000
if (keep_all_files):
self._shutil_copyfile(
self._file_name,
self._file_name + "_" + str(int(self._time_time())))
def _check_writable(self):
if (self._flag == "r"):
raise IOError("Read-only database: %s" % self._file_name)
def __getitem__(self, key):
return self._dict[key]
def __setitem__(self, key, value):
self._check_writable()
if (not is_string(key)):
raise TypeError("key `%s' must be a string but is %s" % (key, type(key)))
if (not is_string(value)):
raise TypeError("value `%s' must be a string but is %s" % (value, type(value)))
self._dict[key] = value
self._needs_sync = 0001
def keys(self):
return list(self._dict.keys())
def has_key(self, key):
return key in self._dict
def __contains__(self, key):
return key in self._dict
def iterkeys(self):
# Wrapping name in () prevents fixer from "fixing" this
return (self._dict.iterkeys)()
__iter__ = iterkeys
def __len__(self):
return len(self._dict)
def open(file, flag=None, mode=0666):
return dblite(file, flag, mode)
def _exercise():
db = open("tmp", "n")
assert len(db) == 0
db["foo"] = "bar"
assert db["foo"] == "bar"
db[unicode("ufoo")] = unicode("ubar")
assert db[unicode("ufoo")] == unicode("ubar")
db.sync()
db = open("tmp", "c")
assert len(db) == 2, len(db)
assert db["foo"] == "bar"
db["bar"] = "foo"
assert db["bar"] == "foo"
db[unicode("ubar")] = unicode("ufoo")
assert db[unicode("ubar")] == unicode("ufoo")
db.sync()
db = open("tmp", "r")
assert len(db) == 4, len(db)
assert db["foo"] == "bar"
assert db["bar"] == "foo"
assert db[unicode("ufoo")] == unicode("ubar")
assert db[unicode("ubar")] == unicode("ufoo")
try:
db.sync()
except IOError, e:
assert str(e) == "Read-only database: tmp.dblite"
else:
raise RuntimeError("IOError expected.")
db = open("tmp", "w")
assert len(db) == 4
db["ping"] = "pong"
db.sync()
try:
db[(1,2)] = "tuple"
except TypeError, e:
assert str(e) == "key `(1, 2)' must be a string but is <type 'tuple'>", str(e)
else:
raise RuntimeError("TypeError exception expected")
try:
db["list"] = [1,2]
except TypeError, e:
assert str(e) == "value `[1, 2]' must be a string but is <type 'list'>", str(e)
else:
raise RuntimeError("TypeError exception expected")
db = open("tmp", "r")
assert len(db) == 5
db = open("tmp", "n")
assert len(db) == 0
dblite._open("tmp.dblite", "w")
db = open("tmp", "r")
dblite._open("tmp.dblite", "w").write("x")
try:
db = open("tmp", "r")
except pickle.UnpicklingError:
pass
else:
raise RuntimeError("pickle exception expected.")
global ignore_corrupt_dbfiles
ignore_corrupt_dbfiles = 2
db = open("tmp", "r")
assert len(db) == 0
os.unlink("tmp.dblite")
try:
db = open("tmp", "w")
except IOError, e:
assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e)
else:
raise RuntimeError("IOError expected.")
print "OK"
if (__name__ == "__main__"):
_exercise()
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -60,6 +60,7 @@ this module:
get_presig() get_presig()
Fetches the "contents" of a subclass for signature calculation. Fetches the "contents" of a subclass for signature calculation.
The varlist is added to this to produce the Action's contents. The varlist is added to this to produce the Action's contents.
TODO(?): Change this to always return ascii/bytes and not unicode (or py3 strings)
strfunction() strfunction()
Returns a substituted string representation of the Action. Returns a substituted string representation of the Action.
@ -76,7 +77,7 @@ way for wrapping up the functions.
""" """
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -97,15 +98,15 @@ way for wrapping up the functions.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Action.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Action.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import dis
import os import os
# compat layer imports "cPickle" for us if it's available.
import pickle import pickle
import re import re
import sys import sys
import subprocess import subprocess
import itertools
import inspect
import SCons.Debug import SCons.Debug
from SCons.Debug import logInstanceCreation from SCons.Debug import logInstanceCreation
@ -124,37 +125,25 @@ print_actions = 1
execute_actions = 1 execute_actions = 1
print_actions_presub = 0 print_actions_presub = 0
# Use pickle protocol 1 when pickling functions for signature
# otherwise python3 and python2 will yield different pickles
# for the same object.
# This is due to default being 1 for python 2.7, and 3 for 3.x
# TODO: We can roll this forward to 2 (if it has value), but not
# before a deprecation cycle as the sconsigns will change
ACTION_SIGNATURE_PICKLE_PROTOCOL = 1
def rfile(n): def rfile(n):
try: try:
return n.rfile() return n.rfile()
except AttributeError: except AttributeError:
return n return n
def default_exitstatfunc(s): def default_exitstatfunc(s):
return s return s
try:
SET_LINENO = dis.SET_LINENO
HAVE_ARGUMENT = dis.HAVE_ARGUMENT
except AttributeError:
remove_set_lineno_codes = lambda x: x
else:
def remove_set_lineno_codes(code):
result = []
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
if op >= HAVE_ARGUMENT:
if op != SET_LINENO:
result.append(code[i:i+3])
i = i+3
else:
result.append(c)
i = i+1
return ''.join(result)
strip_quotes = re.compile('^[\'"](.*)[\'"]$') strip_quotes = re.compile('^[\'"](.*)[\'"]$')
@ -163,12 +152,12 @@ def _callable_contents(obj):
""" """
try: try:
# Test if obj is a method. # Test if obj is a method.
return _function_contents(obj.im_func) return _function_contents(obj.__func__)
except AttributeError: except AttributeError:
try: try:
# Test if obj is a callable object. # Test if obj is a callable object.
return _function_contents(obj.__call__.im_func) return _function_contents(obj.__call__.__func__)
except AttributeError: except AttributeError:
try: try:
@ -176,8 +165,8 @@ def _callable_contents(obj):
return _code_contents(obj) return _code_contents(obj)
except AttributeError: except AttributeError:
# Test if obj is a function object. # Test if obj is a function object.
return _function_contents(obj) return _function_contents(obj)
def _object_contents(obj): def _object_contents(obj):
@ -188,12 +177,12 @@ def _object_contents(obj):
""" """
try: try:
# Test if obj is a method. # Test if obj is a method.
return _function_contents(obj.im_func) return _function_contents(obj.__func__)
except AttributeError: except AttributeError:
try: try:
# Test if obj is a callable object. # Test if obj is a callable object.
return _function_contents(obj.__call__.im_func) return _function_contents(obj.__call__.__func__)
except AttributeError: except AttributeError:
try: try:
@ -205,20 +194,23 @@ def _object_contents(obj):
# Test if obj is a function object. # Test if obj is a function object.
return _function_contents(obj) return _function_contents(obj)
except AttributeError: except AttributeError as ae:
# Should be a pickable Python object. # Should be a pickle-able Python object.
try: try:
return pickle.dumps(obj) return _object_instance_content(obj)
except (pickle.PicklingError, TypeError): # pickling an Action instance or object doesn't yield a stable
# content as instance property may be dumped in different orders
# return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL)
except (pickle.PicklingError, TypeError, AttributeError) as ex:
# This is weird, but it seems that nested classes # This is weird, but it seems that nested classes
# are unpickable. The Python docs say it should # are unpickable. The Python docs say it should
# always be a PicklingError, but some Python # always be a PicklingError, but some Python
# versions seem to return TypeError. Just do # versions seem to return TypeError. Just do
# the best we can. # the best we can.
return str(obj) return bytearray(repr(obj), 'utf-8')
def _code_contents(code): def _code_contents(code, docstring=None):
"""Return the signature contents of a code object. """Return the signature contents of a code object.
By providing direct access to the code object of the By providing direct access to the code object of the
@ -228,61 +220,173 @@ def _code_contents(code):
number indications in the compiled byte code. Boo! number indications in the compiled byte code. Boo!
So we remove the line number byte codes to prevent So we remove the line number byte codes to prevent
recompilations from moving a Python function. recompilations from moving a Python function.
See:
- https://docs.python.org/2/library/inspect.html
- http://python-reference.readthedocs.io/en/latest/docs/code/index.html
For info on what each co\_ variable provides
The signature is as follows (should be byte/chars):
co_argcount, len(co_varnames), len(co_cellvars), len(co_freevars),
( comma separated signature for each object in co_consts ),
( comma separated signature for each object in co_names ),
( The bytecode with line number bytecodes removed from co_code )
co_argcount - Returns the number of positional arguments (including arguments with default values).
co_varnames - Returns a tuple containing the names of the local variables (starting with the argument names).
co_cellvars - Returns a tuple containing the names of local variables that are referenced by nested functions.
co_freevars - Returns a tuple containing the names of free variables. (?)
co_consts - Returns a tuple containing the literals used by the bytecode.
co_names - Returns a tuple containing the names used by the bytecode.
co_code - Returns a string representing the sequence of bytecode instructions.
""" """
contents = [] # contents = []
# The code contents depends on the number of local variables # The code contents depends on the number of local variables
# but not their actual names. # but not their actual names.
contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) contents = bytearray("{}, {}".format(code.co_argcount, len(code.co_varnames)), 'utf-8')
contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
contents.extend(b", ")
contents.extend(bytearray(str(len(code.co_cellvars)), 'utf-8'))
contents.extend(b", ")
contents.extend(bytearray(str(len(code.co_freevars)), 'utf-8'))
# The code contents depends on any constants accessed by the # The code contents depends on any constants accessed by the
# function. Note that we have to call _object_contents on each # function. Note that we have to call _object_contents on each
# constants because the code object of nested functions can # constants because the code object of nested functions can
# show-up among the constants. # show-up among the constants.
#
# Note that we also always ignore the first entry of co_consts z = [_object_contents(cc) for cc in code.co_consts[1:]]
# which contains the function doc string. We assume that the contents.extend(b',(')
# function does not access its doc string. contents.extend(bytearray(',', 'utf-8').join(z))
contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')') contents.extend(b')')
# The code contents depends on the variable names used to # The code contents depends on the variable names used to
# accessed global variable, as changing the variable name changes # accessed global variable, as changing the variable name changes
# the variable actually accessed and therefore changes the # the variable actually accessed and therefore changes the
# function result. # function result.
contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')') z= [bytearray(_object_contents(cc)) for cc in code.co_names]
contents.extend(b',(')
contents.extend(bytearray(',','utf-8').join(z))
contents.extend(b')')
# The code contents depends on its actual code!!! # The code contents depends on its actual code!!!
contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') contents.extend(b',(')
contents.extend(code.co_code)
contents.extend(b')')
return ''.join(contents) return contents
def _function_contents(func): def _function_contents(func):
"""Return the signature contents of a function.""" """
The signature is as follows (should be byte/chars):
< _code_contents (see above) from func.__code__ >
,( comma separated _object_contents for function argument defaults)
,( comma separated _object_contents for any closure contents )
contents = [_code_contents(func.func_code)]
See also: https://docs.python.org/3/reference/datamodel.html
- func.__code__ - The code object representing the compiled function body.
- func.__defaults__ - A tuple containing default argument values for those arguments that have defaults, or None if no arguments have a default value
- func.__closure__ - None or a tuple of cells that contain bindings for the function's free variables.
:Returns:
Signature contents of a function. (in bytes)
"""
contents = [_code_contents(func.__code__, func.__doc__)]
# The function contents depends on the value of defaults arguments # The function contents depends on the value of defaults arguments
if func.func_defaults: if func.__defaults__:
contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
function_defaults_contents = [_object_contents(cc) for cc in func.__defaults__]
defaults = bytearray(b',(')
defaults.extend(bytearray(b',').join(function_defaults_contents))
defaults.extend(b')')
contents.append(defaults)
else: else:
contents.append(',()') contents.append(b',()')
# The function contents depends on the closure captured cell values. # The function contents depends on the closure captured cell values.
closure = func.func_closure or [] closure = func.__closure__ or []
#xxx = [_object_contents(x.cell_contents) for x in closure]
try: try:
xxx = [_object_contents(x.cell_contents) for x in closure] closure_contents = [_object_contents(x.cell_contents) for x in closure]
except AttributeError: except AttributeError:
xxx = [] closure_contents = []
contents.append(',(' + ','.join(xxx) + ')')
return ''.join(contents) contents.append(b',(')
contents.append(bytearray(b',').join(closure_contents))
contents.append(b')')
retval = bytearray(b'').join(contents)
return retval
def _object_instance_content(obj):
"""
Returns consistant content for a action class or an instance thereof
:Parameters:
- `obj` Should be either and action class or an instance thereof
:Returns:
bytearray or bytes representing the obj suitable for generating a signature from.
"""
retval = bytearray()
if obj is None:
return b'N.'
if isinstance(obj, SCons.Util.BaseStringTypes):
return SCons.Util.to_bytes(obj)
inst_class = obj.__class__
inst_class_name = bytearray(obj.__class__.__name__,'utf-8')
inst_class_module = bytearray(obj.__class__.__module__,'utf-8')
inst_class_hierarchy = bytearray(repr(inspect.getclasstree([obj.__class__,])),'utf-8')
# print("ICH:%s : %s"%(inst_class_hierarchy, repr(obj)))
properties = [(p, getattr(obj, p, "None")) for p in dir(obj) if not (p[:2] == '__' or inspect.ismethod(getattr(obj, p)) or inspect.isbuiltin(getattr(obj,p))) ]
properties.sort()
properties_str = ','.join(["%s=%s"%(p[0],p[1]) for p in properties])
properties_bytes = bytearray(properties_str,'utf-8')
methods = [p for p in dir(obj) if inspect.ismethod(getattr(obj, p))]
methods.sort()
method_contents = []
for m in methods:
# print("Method:%s"%m)
v = _function_contents(getattr(obj, m))
# print("[%s->]V:%s [%s]"%(m,v,type(v)))
method_contents.append(v)
retval = bytearray(b'{')
retval.extend(inst_class_name)
retval.extend(b":")
retval.extend(inst_class_module)
retval.extend(b'}[[')
retval.extend(inst_class_hierarchy)
retval.extend(b']]{{')
retval.extend(bytearray(b",").join(method_contents))
retval.extend(b"}}{{{")
retval.extend(properties_bytes)
retval.extend(b'}}}')
return retval
# print("class :%s"%inst_class)
# print("class_name :%s"%inst_class_name)
# print("class_module :%s"%inst_class_module)
# print("Class hier :\n%s"%pp.pformat(inst_class_hierarchy))
# print("Inst Properties:\n%s"%pp.pformat(properties))
# print("Inst Methods :\n%s"%pp.pformat(methods))
def _actionAppend(act1, act2): def _actionAppend(act1, act2):
# This function knows how to slap two actions together. # This function knows how to slap two actions together.
@ -305,6 +409,7 @@ def _actionAppend(act1, act2):
else: else:
return ListAction([ a1, a2 ]) return ListAction([ a1, a2 ])
def _do_create_keywords(args, kw): def _do_create_keywords(args, kw):
"""This converts any arguments after the action argument into """This converts any arguments after the action argument into
their equivalent keywords and adds them to the kw argument. their equivalent keywords and adds them to the kw argument.
@ -332,6 +437,7 @@ def _do_create_keywords(args, kw):
raise SCons.Errors.UserError( raise SCons.Errors.UserError(
'Cannot have both strfunction and cmdstr args to Action()') 'Cannot have both strfunction and cmdstr args to Action()')
def _do_create_action(act, kw): def _do_create_action(act, kw):
"""This is the actual "implementation" for the """This is the actual "implementation" for the
Action factory method, below. This handles the Action factory method, below. This handles the
@ -362,7 +468,7 @@ def _do_create_action(act, kw):
# The list of string commands may include a LazyAction, so we # The list of string commands may include a LazyAction, so we
# reprocess them via _do_create_list_action. # reprocess them via _do_create_list_action.
return _do_create_list_action(commands, kw) return _do_create_list_action(commands, kw)
if is_List(act): if is_List(act):
return CommandAction(act, **kw) return CommandAction(act, **kw)
@ -384,6 +490,7 @@ def _do_create_action(act, kw):
# Else fail silently (???) # Else fail silently (???)
return None return None
def _do_create_list_action(act, kw): def _do_create_list_action(act, kw):
"""A factory for list actions. Convert the input list into Actions """A factory for list actions. Convert the input list into Actions
and then wrap them in a ListAction.""" and then wrap them in a ListAction."""
@ -398,6 +505,7 @@ def _do_create_list_action(act, kw):
else: else:
return ListAction(acts) return ListAction(acts)
def Action(act, *args, **kw): def Action(act, *args, **kw):
"""A factory for action objects.""" """A factory for action objects."""
# Really simple: the _do_create_* routines do the heavy lifting. # Really simple: the _do_create_* routines do the heavy lifting.
@ -406,13 +514,14 @@ def Action(act, *args, **kw):
return _do_create_list_action(act, kw) return _do_create_list_action(act, kw)
return _do_create_action(act, kw) return _do_create_action(act, kw)
class ActionBase(object): class ActionBase(object):
"""Base class for all types of action objects that can be held by """Base class for all types of action objects that can be held by
other objects (Builders, Executors, etc.) This provides the other objects (Builders, Executors, etc.) This provides the
common methods for manipulating and combining those actions.""" common methods for manipulating and combining those actions."""
def __cmp__(self, other): def __eq__(self, other):
return cmp(self.__dict__, other) return self.__dict__ == other
def no_batch_key(self, env, target, source): def no_batch_key(self, env, target, source):
return None return None
@ -423,7 +532,18 @@ class ActionBase(object):
return str(self) return str(self)
def get_contents(self, target, source, env): def get_contents(self, target, source, env):
result = [ self.get_presig(target, source, env) ] result = self.get_presig(target, source, env)
if not isinstance(result,(bytes, bytearray)):
result = bytearray("",'utf-8').join([ SCons.Util.to_bytes(r) for r in result ])
else:
# Make a copy and put in bytearray, without this the contents returned by get_presig
# can be changed by the logic below, appending with each call and causing very
# hard to track down issues...
result = bytearray(result)
# At this point everything should be a bytearray
# This should never happen, as the Action() factory should wrap # This should never happen, as the Action() factory should wrap
# the varlist, but just in case an action is created directly, # the varlist, but just in case an action is created directly,
# we duplicate this check here. # we duplicate this check here.
@ -431,8 +551,18 @@ class ActionBase(object):
if is_String(vl): vl = (vl,) if is_String(vl): vl = (vl,)
for v in vl: for v in vl:
# do the subst this way to ignore $(...$) parts: # do the subst this way to ignore $(...$) parts:
result.append(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source)) if isinstance(result, bytearray):
return ''.join(result) result.extend(SCons.Util.to_bytes(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source)))
else:
raise Exception("WE SHOULD NEVER GET HERE result should be bytearray not:%s"%type(result))
# result.append(SCons.Util.to_bytes(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source)))
if isinstance(result, (bytes,bytearray)):
return result
else:
raise Exception("WE SHOULD NEVER GET HERE - #2 result should be bytearray not:%s" % type(result))
# return b''.join(result)
def __add__(self, other): def __add__(self, other):
return _actionAppend(self, other) return _actionAppend(self, other)
@ -462,6 +592,7 @@ class ActionBase(object):
""" """
return self.targets return self.targets
class _ActionAction(ActionBase): class _ActionAction(ActionBase):
"""Base class for actions that create output objects.""" """Base class for actions that create output objects."""
def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
@ -495,16 +626,18 @@ class _ActionAction(ActionBase):
SCons.Util.AddMethod(self, batch_key, 'batch_key') SCons.Util.AddMethod(self, batch_key, 'batch_key')
def print_cmd_line(self, s, target, source, env): def print_cmd_line(self, s, target, source, env):
# In python 3, and in some of our tests, sys.stdout is """
# a String io object, and it takes unicode strings only In python 3, and in some of our tests, sys.stdout is
# In other cases it's a regular Python 2.x file object a String io object, and it takes unicode strings only
# which takes strings (bytes), and if you pass those a In other cases it's a regular Python 2.x file object
# unicode object they try to decode with 'ascii' codec which takes strings (bytes), and if you pass those a
# which fails if the cmd line has any hi-bit-set chars. unicode object they try to decode with 'ascii' codec
# This code assumes s is a regular string, but should which fails if the cmd line has any hi-bit-set chars.
# work if it's unicode too. This code assumes s is a regular string, but should
work if it's unicode too.
"""
try: try:
sys.stdout.write(unicode(s + "\n")) sys.stdout.write(s + u"\n")
except UnicodeDecodeError: except UnicodeDecodeError:
sys.stdout.write(s + "\n") sys.stdout.write(s + "\n")
@ -601,13 +734,17 @@ def _string_from_cmd_list(cmd_list):
cl.append(arg) cl.append(arg)
return ' '.join(cl) return ' '.join(cl)
# A fiddlin' little function that has an 'import SCons.Environment' which
# can't be moved to the top level without creating an import loop. Since
# this import creates a local variable named 'SCons', it blocks access to
# the global variable, so we move it here to prevent complaints about local
# variables being used uninitialized.
default_ENV = None default_ENV = None
def get_default_ENV(env): def get_default_ENV(env):
"""
A fiddlin' little function that has an 'import SCons.Environment' which
can't be moved to the top level without creating an import loop. Since
this import creates a local variable named 'SCons', it blocks access to
the global variable, so we move it here to prevent complaints about local
variables being used uninitialized.
"""
global default_ENV global default_ENV
try: try:
return env['ENV'] return env['ENV']
@ -622,12 +759,15 @@ def get_default_ENV(env):
default_ENV = SCons.Environment.Environment()['ENV'] default_ENV = SCons.Environment.Environment()['ENV']
return default_ENV return default_ENV
# This function is still in draft mode. We're going to need something like
# it in the long run as more and more places use subprocess, but I'm sure
# it'll have to be tweaked to get the full desired functionality.
# one special arg (so far?), 'error', to tell what to do with exceptions.
def _subproc(scons_env, cmd, error = 'ignore', **kw): def _subproc(scons_env, cmd, error = 'ignore', **kw):
"""Do common setup for a subprocess.Popen() call""" """Do common setup for a subprocess.Popen() call
This function is still in draft mode. We're going to need something like
it in the long run as more and more places use subprocess, but I'm sure
it'll have to be tweaked to get the full desired functionality.
one special arg (so far?), 'error', to tell what to do with exceptions.
"""
# allow std{in,out,err} to be "'devnull'" # allow std{in,out,err} to be "'devnull'"
io = kw.get('stdin') io = kw.get('stdin')
if is_String(io) and io == 'devnull': if is_String(io) and io == 'devnull':
@ -664,12 +804,12 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
try: try:
return subprocess.Popen(cmd, **kw) return subprocess.Popen(cmd, **kw)
except EnvironmentError, e: except EnvironmentError as e:
if error == 'raise': raise if error == 'raise': raise
# return a dummy Popen instance that only returns error # return a dummy Popen instance that only returns error
class dummyPopen(object): class dummyPopen(object):
def __init__(self, e): self.exception = e def __init__(self, e): self.exception = e
def communicate(self,input=None): return ('','') def communicate(self, input=None): return ('', '')
def wait(self): return -self.exception.errno def wait(self): return -self.exception.errno
stdin = None stdin = None
class f(object): class f(object):
@ -679,6 +819,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
stdout = stderr = f() stdout = stderr = f()
return dummyPopen(e) return dummyPopen(e)
class CommandAction(_ActionAction): class CommandAction(_ActionAction):
"""Class for command-execution actions.""" """Class for command-execution actions."""
def __init__(self, cmd, **kw): def __init__(self, cmd, **kw):
@ -695,7 +836,7 @@ class CommandAction(_ActionAction):
_ActionAction.__init__(self, **kw) _ActionAction.__init__(self, **kw)
if is_List(cmd): if is_List(cmd):
if list(filter(is_List, cmd)): if [c for c in cmd if is_List(c)]:
raise TypeError("CommandAction should be given only " \ raise TypeError("CommandAction should be given only " \
"a single command") "a single command")
self.cmd_list = cmd self.cmd_list = cmd
@ -845,6 +986,7 @@ class CommandAction(_ActionAction):
res.append(env.fs.File(d)) res.append(env.fs.File(d))
return res return res
class CommandGeneratorAction(ActionBase): class CommandGeneratorAction(ActionBase):
"""Class for command-generator actions.""" """Class for command-generator actions."""
def __init__(self, generator, kw): def __init__(self, generator, kw):
@ -916,25 +1058,25 @@ class CommandGeneratorAction(ActionBase):
return self._generate(None, None, env, 1, executor).get_targets(env, executor) return self._generate(None, None, env, 1, executor).get_targets(env, executor)
# A LazyAction is a kind of hybrid generator and command action for
# strings of the form "$VAR". These strings normally expand to other
# strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
# want to be able to replace them with functions in the construction
# environment. Consequently, we want lazy evaluation and creation of
# an Action in the case of the function, but that's overkill in the more
# normal case of expansion to other strings.
#
# So we do this with a subclass that's both a generator *and*
# a command action. The overridden methods all do a quick check
# of the construction variable, and if it's a string we just call
# the corresponding CommandAction method to do the heavy lifting.
# If not, then we call the same-named CommandGeneratorAction method.
# The CommandGeneratorAction methods work by using the overridden
# _generate() method, that is, our own way of handling "generation" of
# an action based on what's in the construction variable.
class LazyAction(CommandGeneratorAction, CommandAction): class LazyAction(CommandGeneratorAction, CommandAction):
"""
A LazyAction is a kind of hybrid generator and command action for
strings of the form "$VAR". These strings normally expand to other
strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
want to be able to replace them with functions in the construction
environment. Consequently, we want lazy evaluation and creation of
an Action in the case of the function, but that's overkill in the more
normal case of expansion to other strings.
So we do this with a subclass that's both a generator *and*
a command action. The overridden methods all do a quick check
of the construction variable, and if it's a string we just call
the corresponding CommandAction method to do the heavy lifting.
If not, then we call the same-named CommandGeneratorAction method.
The CommandGeneratorAction methods work by using the overridden
_generate() method, that is, our own way of handling "generation" of
an action based on what's in the construction variable.
"""
def __init__(self, var, kw): def __init__(self, var, kw):
if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.LazyAction') if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.LazyAction')
@ -1013,6 +1155,7 @@ class FunctionAction(_ActionAction):
c = env.subst(self.cmdstr, SUBST_RAW, target, source) c = env.subst(self.cmdstr, SUBST_RAW, target, source)
if c: if c:
return c return c
def array(a): def array(a):
def quote(s): def quote(s):
try: try:
@ -1052,11 +1195,11 @@ class FunctionAction(_ActionAction):
rsources = list(map(rfile, source)) rsources = list(map(rfile, source))
try: try:
result = self.execfunction(target=target, source=rsources, env=env) result = self.execfunction(target=target, source=rsources, env=env)
except KeyboardInterrupt, e: except KeyboardInterrupt as e:
raise raise
except SystemExit, e: except SystemExit as e:
raise raise
except Exception, e: except Exception as e:
result = e result = e
exc_info = sys.exc_info() exc_info = sys.exc_info()
@ -1086,7 +1229,6 @@ class FunctionAction(_ActionAction):
# more information about this issue. # more information about this issue.
del exc_info del exc_info
def get_presig(self, target, source, env): def get_presig(self, target, source, env):
"""Return the signature contents of this callable action.""" """Return the signature contents of this callable action."""
try: try:
@ -1126,7 +1268,7 @@ class ListAction(ActionBase):
Simple concatenation of the signatures of the elements. Simple concatenation of the signatures of the elements.
""" """
return "".join([x.get_contents(target, source, env) for x in self.list]) return b"".join([bytes(x.get_contents(target, source, env)) for x in self.list])
def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
show=_null, execute=_null, chdir=_null, executor=None): show=_null, execute=_null, chdir=_null, executor=None):
@ -1153,6 +1295,7 @@ class ListAction(ActionBase):
result[var] = True result[var] = True
return list(result.keys()) return list(result.keys())
class ActionCaller(object): class ActionCaller(object):
"""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
@ -1171,16 +1314,16 @@ class ActionCaller(object):
actfunc = self.parent.actfunc actfunc = self.parent.actfunc
try: try:
# "self.actfunc" is a function. # "self.actfunc" is a function.
contents = str(actfunc.func_code.co_code) contents = actfunc.__code__.co_code
except AttributeError: except AttributeError:
# "self.actfunc" is a callable object. # "self.actfunc" is a callable object.
try: try:
contents = str(actfunc.__call__.im_func.func_code.co_code) contents = actfunc.__call__.__func__.__code__.co_code
except AttributeError: except AttributeError:
# No __call__() method, so it might be a builtin # No __call__() method, so it might be a builtin
# or something like that. Do the best we can. # or something like that. Do the best we can.
contents = str(actfunc) contents = repr(actfunc)
contents = remove_set_lineno_codes(contents)
return contents return contents
def subst(self, s, target, source, env): def subst(self, s, target, source, env):
@ -1206,7 +1349,7 @@ class ActionCaller(object):
def subst_kw(self, target, source, env): def subst_kw(self, target, source, env):
kw = {} kw = {}
for key in self.kw.keys(): for key in list(self.kw.keys()):
kw[key] = self.subst(self.kw[key], target, source, env) kw[key] = self.subst(self.kw[key], target, source, env)
return kw return kw
@ -1223,6 +1366,7 @@ class ActionCaller(object):
def __str__(self): def __str__(self):
return self.parent.strfunc(*self.args, **self.kw) return self.parent.strfunc(*self.args, **self.kw)
class ActionFactory(object): class ActionFactory(object):
"""A factory class that will wrap up an arbitrary function """A factory class that will wrap up an arbitrary function
as an SCons-executable Action object. as an SCons-executable Action object.

View file

@ -1,4 +1,5 @@
"""SCons.Builder """
SCons.Builder
Builder object subsystem. Builder object subsystem.
@ -31,7 +32,7 @@ There is also a proxy that looks like a Builder:
Builders and their proxies have the following public interface methods Builders and their proxies have the following public interface methods
used by other modules: used by other modules:
__call__() - __call__()
THE public interface. Calling a Builder object (with the THE public interface. Calling a Builder object (with the
use of internal helper methods) sets up the target and source use of internal helper methods) sets up the target and source
dependencies, appropriate mapping to a specific action, and the dependencies, appropriate mapping to a specific action, and the
@ -39,12 +40,12 @@ 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.
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
can create a .h *and* a .c file. can create a .h *and* a .c file.
add_action() - add_action()
Adds an action for a specific file suffix, heavily used by Adds an action for a specific file suffix, heavily used by
Tool modules to add their specific action(s) for turning Tool modules to add their specific action(s) for turning
a source file into an object file to the global static a source file into an object file to the global static
@ -52,23 +53,23 @@ used by other modules:
There are the following methods for internal use within this module: There are the following methods for internal use within this module:
_execute() - _execute()
The internal method that handles the heavily lifting when a The internal method that handles the heavily lifting when a
Builder is called. This is used so that the __call__() methods Builder is called. This is used so that the __call__() methods
can set up warning about possible mistakes in keyword-argument can set up warning about possible mistakes in keyword-argument
overrides, and *then* execute all of the steps necessary so that overrides, and *then* execute all of the steps necessary so that
the warnings only occur once. the warnings only occur once.
get_name() - get_name()
Returns the Builder's name within a specific Environment, Returns the Builder's name within a specific Environment,
primarily used to try to return helpful information in error primarily used to try to return helpful information in error
messages. messages.
adjust_suffix() - adjust_suffix()
get_prefix() - get_prefix()
get_suffix() - get_suffix()
get_src_suffix() - get_src_suffix()
set_src_suffix() - set_src_suffix()
Miscellaneous stuff for handling the prefix and suffix Miscellaneous stuff for handling the prefix and suffix
manipulation we use in turning source file names into target manipulation we use in turning source file names into target
file names. file names.
@ -76,7 +77,7 @@ There are the following methods for internal use within this module:
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -97,7 +98,7 @@ There are the following methods for internal use within this module:
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Builder.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Builder.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import collections import collections
@ -166,7 +167,7 @@ class DictCmdGenerator(SCons.Util.Selector):
try: try:
ret = SCons.Util.Selector.__call__(self, env, source, ext) ret = SCons.Util.Selector.__call__(self, env, source, ext)
except KeyError, e: except KeyError as e:
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2])) raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2]))
if ret is None: if ret is None:
raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \ raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \
@ -229,7 +230,7 @@ class OverrideWarner(collections.UserDict):
def warn(self): def warn(self):
if self.already_warned: if self.already_warned:
return return
for k in self.keys(): for k in list(self.keys()):
if k in misleading_keywords: if k in misleading_keywords:
alt = misleading_keywords[k] alt = misleading_keywords[k]
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k) msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
@ -290,7 +291,14 @@ def _node_errors(builder, env, tlist, slist):
if t.side_effect: if t.side_effect:
raise UserError("Multiple ways to build the same target were specified for: %s" % t) raise UserError("Multiple ways to build the same target were specified for: %s" % t)
if t.has_explicit_builder(): if t.has_explicit_builder():
if not t.env is None and not t.env is env: # Check for errors when the environments are different
# No error if environments are the same Environment instance
if (not t.env is None and not t.env is env and
# Check OverrideEnvironment case - no error if wrapped Environments
# are the same instance, and overrides lists match
not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
getattr(t.env, 'overrides', 0) == getattr(env, 'overrides', 1) and
not builder.multi)):
action = t.builder.action action = t.builder.action
t_contents = t.builder.action.get_contents(tlist, slist, t.env) t_contents = t.builder.action.get_contents(tlist, slist, t.env)
contents = builder.action.get_contents(tlist, slist, env) contents = builder.action.get_contents(tlist, slist, env)
@ -299,7 +307,10 @@ def _node_errors(builder, env, tlist, slist):
msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env)) msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg) SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
else: else:
msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents,contents) try:
msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8'))
except UnicodeDecodeError as e:
msg = "Two environments with different actions were specified for the same target: %s"%t
raise UserError(msg) raise UserError(msg)
if builder.multi: if builder.multi:
if t.builder != builder: if t.builder != builder:
@ -344,8 +355,11 @@ class EmitterProxy(object):
return (target, source) return (target, source)
def __cmp__(self, other): def __eq__(self, other):
return cmp(self.var, other.var) return self.var == other.var
def __lt__(self, other):
return self.var < other.var
class BuilderBase(object): class BuilderBase(object):
"""Base class for Builders, objects that create output """Base class for Builders, objects that create output
@ -423,6 +437,9 @@ class BuilderBase(object):
def __nonzero__(self): def __nonzero__(self):
raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead") raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
def __bool__(self):
return self.__nonzero__()
def get_name(self, env): def get_name(self, env):
"""Attempts to get the name of the Builder. """Attempts to get the name of the Builder.
@ -440,8 +457,8 @@ class BuilderBase(object):
except AttributeError: except AttributeError:
return str(self.__class__) return str(self.__class__)
def __cmp__(self, other): def __eq__(self, other):
return cmp(self.__dict__, other.__dict__) return self.__dict__ == other.__dict__
def splitext(self, path, env=None): def splitext(self, path, env=None):
if not env: if not env:
@ -604,6 +621,8 @@ class BuilderBase(object):
else: else:
ekw = self.executor_kw.copy() ekw = self.executor_kw.copy()
ekw['chdir'] = chdir ekw['chdir'] = chdir
if 'chdir' in ekw and SCons.Util.is_String(ekw['chdir']):
ekw['chdir'] = env.subst(ekw['chdir'])
if kw: if kw:
if 'srcdir' in kw: if 'srcdir' in kw:
def prependDirIfRelative(f, srcdir=kw['srcdir']): def prependDirIfRelative(f, srcdir=kw['srcdir']):

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/CacheDir.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/CacheDir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """ __doc__ = """
CacheDir support CacheDir support

View file

@ -101,7 +101,6 @@ Autoconf-like configuration support; low level implementation of tests.
# #
import re import re
from types import IntType
# #
# PUBLIC VARIABLES # PUBLIC VARIABLES
@ -707,11 +706,12 @@ def CheckProg(context, prog_name):
def _YesNoResult(context, ret, key, text, comment = None): def _YesNoResult(context, ret, key, text, comment = None):
""" """
Handle the result of a test with a "yes" or "no" result. Handle the result of a test with a "yes" or "no" result.
"ret" is the return value: empty if OK, error message when not.
"key" is the name of the symbol to be defined (HAVE_foo). :Parameters:
"text" is the source code of the program used for testing. - `ret` is the return value: empty if OK, error message when not.
"comment" is the C comment to add above the line defining the symbol (the - `key` is the name of the symbol to be defined (HAVE_foo).
comment is automatically put inside a /* */). If None, no comment is added. - `text` is the source code of the program used for testing.
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
""" """
if key: if key:
_Have(context, key, not ret, comment) _Have(context, key, not ret, comment)
@ -725,18 +725,20 @@ def _YesNoResult(context, ret, key, text, comment = None):
def _Have(context, key, have, comment = None): def _Have(context, key, have, comment = None):
""" """
Store result of a test in context.havedict and context.headerfilename. Store result of a test in context.havedict and context.headerfilename.
"key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-
alphanumerics are replaced by an underscore. :Parameters:
- `key` - is a "HAVE_abc" name. It is turned into all CAPITALS and non-alphanumerics are replaced by an underscore.
- `have` - value as it should appear in the header file, include quotes when desired and escape special characters!
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
The value of "have" can be: The value of "have" can be:
1 - Feature is defined, add "#define key". - 1 - Feature is defined, add "#define key".
0 - Feature is not defined, add "/* #undef key */". - 0 - Feature is not defined, add "/\* #undef key \*/". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done.
Adding "undef" is what autoconf does. Not useful for the - number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then.
compiler, but it shows that the test was done. - string - Feature is defined to this string "#define key have".
number - Feature is defined to this number "#define key have".
Doesn't work for 0 or 1, use a string then.
string - Feature is defined to this string "#define key have".
Give "have" as is should appear in the header file, include quotes
when desired and escape special characters!
""" """
key_up = key.upper() key_up = key.upper()
key_up = re.sub('[^A-Z0-9_]', '_', key_up) key_up = re.sub('[^A-Z0-9_]', '_', key_up)
@ -745,7 +747,7 @@ def _Have(context, key, have, comment = None):
line = "#define %s 1\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 isinstance(have, IntType): elif isinstance(have, int):
line = "#define %s %d\n" % (key_up, have) line = "#define %s %d\n" % (key_up, have)
else: else:
line = "#define %s %s\n" % (key_up, str(have)) line = "#define %s %s\n" % (key_up, str(have))
@ -787,10 +789,11 @@ def _lang2suffix(lang):
When "lang" is empty or None C is assumed. When "lang" is empty or None C is assumed.
Returns a tuple (lang, suffix, None) when it works. Returns a tuple (lang, suffix, None) when it works.
For an unrecognized language returns (None, None, msg). For an unrecognized language returns (None, None, msg).
Where: Where:
lang = the unified language name - lang = the unified language name
suffix = the suffix, including the leading dot - suffix = the suffix, including the leading dot
msg = an error message - msg = an error message
""" """
if not lang or lang in ["C", "c"]: if not lang or lang in ["C", "c"]:
return ("C", ".c", None) return ("C", ".c", None)

View file

@ -9,7 +9,7 @@ caller_trace()
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -31,7 +31,7 @@ caller_trace()
# 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__ = "src/engine/SCons/Debug.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Debug.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import sys import sys
@ -97,7 +97,8 @@ def dumpLoggedInstances(classes, file=sys.stdout):
if sys.platform[:5] == "linux": if sys.platform[:5] == "linux":
# Linux doesn't actually support memory usage stats from getrusage(). # Linux doesn't actually support memory usage stats from getrusage().
def memory(): def memory():
mstr = open('/proc/self/stat').read() with open('/proc/self/stat') as f:
mstr = f.read()
mstr = mstr.split()[22] mstr = mstr.split()[22]
return int(mstr) return int(mstr)
elif sys.platform[:6] == 'darwin': elif sys.platform[:6] == 'darwin':
@ -233,6 +234,7 @@ def Trace(msg, file=None, mode='w', tstamp=None):
PreviousTime = now PreviousTime = now
fp.write(msg) fp.write(msg)
fp.flush() fp.flush()
fp.close()
# Local Variables: # Local Variables:
# tab-width:4 # tab-width:4

View file

@ -10,7 +10,7 @@ from distutils.msvccompiler.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -33,7 +33,7 @@ from distutils.msvccompiler.
# #
from __future__ import division from __future__ import division
__revision__ = "src/engine/SCons/Defaults.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Defaults.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
@ -261,9 +261,13 @@ def copy_func(dest, src, symlinks=True):
else: else:
return copy_func(dest, os.path.realpath(src)) return copy_func(dest, os.path.realpath(src))
elif os.path.isfile(src): elif os.path.isfile(src):
return shutil.copy2(src, dest) shutil.copy2(src, dest)
return 0
else: else:
return shutil.copytree(src, dest, symlinks) shutil.copytree(src, dest, symlinks)
# copytree returns None in python2 and destination string in python3
# A error is raised in both cases, so we can just return 0 for success
return 0
Copy = ActionFactory( Copy = ActionFactory(
copy_func, copy_func,
@ -298,7 +302,7 @@ def mkdir_func(dest):
for entry in dest: for entry in dest:
try: try:
os.makedirs(str(entry)) os.makedirs(str(entry))
except os.error, e: except os.error as e:
p = str(entry) p = str(entry)
if (e.args[0] == errno.EEXIST or if (e.args[0] == errno.EEXIST or
(sys.platform=='win32' and e.args[0]==183)) \ (sys.platform=='win32' and e.args[0]==183)) \
@ -458,7 +462,7 @@ def processDefines(defs):
else: else:
l.append(str(d[0])) l.append(str(d[0]))
elif SCons.Util.is_Dict(d): elif SCons.Util.is_Dict(d):
for macro,value in d.iteritems(): for macro,value in d.items():
if value is not None: if value is not None:
l.append(str(macro) + '=' + str(value)) l.append(str(macro) + '=' + str(value))
else: else:
@ -484,6 +488,7 @@ def processDefines(defs):
l = [str(defs)] l = [str(defs)]
return l return l
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
into a list of C preprocessor command-line definitions. into a list of C preprocessor command-line definitions.
@ -491,6 +496,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
return c(prefix, env.subst_path(processDefines(defs)), suffix, env) return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
class NullCmdGenerator(object): class NullCmdGenerator(object):
"""This is a callable class that can be used in place of other """This is a callable class that can be used in place of other
command generators if you don't want them to do anything. command generators if you don't want them to do anything.
@ -509,6 +515,7 @@ class NullCmdGenerator(object):
def __call__(self, target, source, env, for_signature=None): def __call__(self, target, source, env, for_signature=None):
return self.cmd return self.cmd
class Variable_Method_Caller(object): class Variable_Method_Caller(object):
"""A class for finding a construction variable on the stack and """A class for finding a construction variable on the stack and
calling one of its methods. calling one of its methods.
@ -540,10 +547,10 @@ class Variable_Method_Caller(object):
frame = frame.f_back frame = frame.f_back
return None return None
# if env[version_var] id defined, returns env[flags_var], otherwise returns None # if $version_var is not empty, returns env[flags_var], otherwise returns None
def __libversionflags(env, version_var, flags_var): def __libversionflags(env, version_var, flags_var):
try: try:
if env[version_var]: if env.subst('$'+version_var):
return env[flags_var] return env[flags_var]
except KeyError: except KeyError:
pass pass

View file

@ -10,7 +10,7 @@ Environment
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -31,7 +31,7 @@ Environment
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Environment.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Environment.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import copy import copy
@ -128,7 +128,7 @@ future_reserved_construction_var_names = [
def copy_non_reserved_keywords(dict): def copy_non_reserved_keywords(dict):
result = semi_deepcopy(dict) result = semi_deepcopy(dict)
for k in result.keys(): for k in list(result.keys()):
if k in reserved_construction_var_names: if k in reserved_construction_var_names:
msg = "Ignoring attempt to set reserved variable `$%s'" msg = "Ignoring attempt to set reserved variable `$%s'"
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k)
@ -147,7 +147,7 @@ def _set_future_reserved(env, key, value):
def _set_BUILDERS(env, key, value): def _set_BUILDERS(env, key, value):
try: try:
bd = env._dict[key] bd = env._dict[key]
for k in bd.keys(): for k in list(bd.keys()):
del bd[k] del bd[k]
except KeyError: except KeyError:
bd = BuilderDict(kwbd, env) bd = BuilderDict(kwbd, env)
@ -167,7 +167,7 @@ def _set_SCANNERS(env, key, value):
def _delete_duplicates(l, keep_last): def _delete_duplicates(l, keep_last):
"""Delete duplicates from a sequence, keeping the first or last.""" """Delete duplicates from a sequence, keeping the first or last."""
seen={} seen=set()
result=[] result=[]
if keep_last: # reverse in & out, then keep first if keep_last: # reverse in & out, then keep first
l.reverse() l.reverse()
@ -175,7 +175,7 @@ def _delete_duplicates(l, keep_last):
try: try:
if i not in seen: if i not in seen:
result.append(i) result.append(i)
seen[i]=1 seen.add(i)
except TypeError: except TypeError:
# probably unhashable. Just keep it. # probably unhashable. Just keep it.
result.append(i) result.append(i)
@ -342,7 +342,7 @@ def is_valid_construction_var(varstr):
class SubstitutionEnvironment(object): class SubstitutionEnvironment(object):
"""Base class for different flavors of construction environments. """Base class for different flavors of construction environments.
This class contains a minimal set of methods that handle contruction This class contains a minimal set of methods that handle construction
variable expansion and conversion of strings to Nodes, which may or variable expansion and conversion of strings to Nodes, which may or
may not be actually useful as a stand-alone class. Which methods may not be actually useful as a stand-alone class. Which methods
ended up in this class is pretty arbitrary right now. They're ended up in this class is pretty arbitrary right now. They're
@ -396,8 +396,8 @@ class SubstitutionEnvironment(object):
# gotten better than dict.has_key() in Python 2.5.) # gotten better than dict.has_key() in Python 2.5.)
self._special_set_keys = list(self._special_set.keys()) self._special_set_keys = list(self._special_set.keys())
def __cmp__(self, other): def __eq__(self, other):
return cmp(self._dict, other._dict) return self._dict == other._dict
def __delitem__(self, key): def __delitem__(self, key):
special = self._special_del.get(key) special = self._special_del.get(key)
@ -589,7 +589,7 @@ class SubstitutionEnvironment(object):
out,err = p.communicate() out,err = p.communicate()
status = p.wait() status = p.wait()
if err: if err:
sys.stderr.write(unicode(err)) sys.stderr.write(u"" + err)
if status: if status:
raise OSError("'%s' exited %d" % (command, status)) raise OSError("'%s' exited %d" % (command, status))
return out return out
@ -1185,7 +1185,7 @@ class Base(SubstitutionEnvironment):
if SCons.Util.is_List(val): if SCons.Util.is_List(val):
if key == 'CPPDEFINES': if key == 'CPPDEFINES':
tmp = [] tmp = []
for (k, v) in orig.iteritems(): for (k, v) in orig.items():
if v is not None: if v is not None:
tmp.append((k, v)) tmp.append((k, v))
else: else:
@ -1273,7 +1273,7 @@ class Base(SubstitutionEnvironment):
# Construct a list of (key, value) tuples. # Construct a list of (key, value) tuples.
if SCons.Util.is_Dict(dk): if SCons.Util.is_Dict(dk):
tmp = [] tmp = []
for (k, v) in dk.iteritems(): for (k, v) in dk.items():
if v is not None: if v is not None:
tmp.append((k, v)) tmp.append((k, v))
else: else:
@ -1321,7 +1321,7 @@ class Base(SubstitutionEnvironment):
# Construct a list of (key, value) tuples. # Construct a list of (key, value) tuples.
if SCons.Util.is_Dict(val): if SCons.Util.is_Dict(val):
tmp = [] tmp = []
for (k, v) in val.iteritems(): for (k, v) in val.items():
if v is not None: if v is not None:
tmp.append((k, v)) tmp.append((k, v))
else: else:
@ -1330,7 +1330,7 @@ class Base(SubstitutionEnvironment):
elif SCons.Util.is_String(val): elif SCons.Util.is_String(val):
val = [(val,)] val = [(val,)]
if delete_existing: if delete_existing:
dk = filter(lambda x, val=val: x not in val, dk) dk = list(filter(lambda x, val=val: x not in val, dk))
self._dict[key] = dk + val self._dict[key] = dk + val
else: else:
dk = [x for x in dk if x not in val] dk = [x for x in dk if x not in val]
@ -1339,7 +1339,7 @@ class Base(SubstitutionEnvironment):
# By elimination, val is not a list. Since dk is a # By elimination, val is not a list. Since dk is a
# list, wrap val in a list first. # list, wrap val in a list first.
if delete_existing: if delete_existing:
dk = filter(lambda x, val=val: x not in val, dk) dk = list(filter(lambda x, val=val: x not in val, dk))
self._dict[key] = dk + [val] self._dict[key] = dk + [val]
else: else:
if not val in dk: if not val in dk:
@ -1350,7 +1350,7 @@ class Base(SubstitutionEnvironment):
dk = [dk] dk = [dk]
elif SCons.Util.is_Dict(dk): elif SCons.Util.is_Dict(dk):
tmp = [] tmp = []
for (k, v) in dk.iteritems(): for (k, v) in dk.items():
if v is not None: if v is not None:
tmp.append((k, v)) tmp.append((k, v))
else: else:
@ -1363,7 +1363,7 @@ class Base(SubstitutionEnvironment):
val = [val] val = [val]
elif SCons.Util.is_Dict(val): elif SCons.Util.is_Dict(val):
tmp = [] tmp = []
for i,j in val.iteritems(): for i,j in val.items():
if j is not None: if j is not None:
tmp.append((i,j)) tmp.append((i,j))
else: else:
@ -1771,7 +1771,7 @@ class Base(SubstitutionEnvironment):
return os.path.join(dir, new_prefix+name+new_suffix) return os.path.join(dir, new_prefix+name+new_suffix)
def SetDefault(self, **kw): def SetDefault(self, **kw):
for k in kw.keys(): for k in list(kw.keys()):
if k in self._dict: if k in self._dict:
del kw[k] del kw[k]
self.Replace(**kw) self.Replace(**kw)
@ -1833,7 +1833,7 @@ class Base(SubstitutionEnvironment):
uniq = {} uniq = {}
for executor in [n.get_executor() for n in nodes]: for executor in [n.get_executor() for n in nodes]:
uniq[executor] = 1 uniq[executor] = 1
for executor in uniq.keys(): for executor in list(uniq.keys()):
executor.add_pre_action(action) executor.add_pre_action(action)
return nodes return nodes
@ -1843,7 +1843,7 @@ class Base(SubstitutionEnvironment):
uniq = {} uniq = {}
for executor in [n.get_executor() for n in nodes]: for executor in [n.get_executor() for n in nodes]:
uniq[executor] = 1 uniq[executor] = 1
for executor in uniq.keys(): for executor in list(uniq.keys()):
executor.add_post_action(action) executor.add_post_action(action)
return nodes return nodes
@ -1983,6 +1983,15 @@ class Base(SubstitutionEnvironment):
return result return result
return self.fs.Dir(s, *args, **kw) return self.fs.Dir(s, *args, **kw)
def PyPackageDir(self, modulename):
s = self.subst(modulename)
if SCons.Util.is_Sequence(s):
result=[]
for e in s:
result.append(self.fs.PyPackageDir(e))
return result
return self.fs.PyPackageDir(s)
def NoClean(self, *targets): def NoClean(self, *targets):
"""Tags a target so that it will not be cleaned by -c""" """Tags a target so that it will not be cleaned by -c"""
tlist = [] tlist = []
@ -2180,13 +2189,16 @@ class Base(SubstitutionEnvironment):
"""This function converts a string or list into a list of strings """This function converts a string or list into a list of strings
or Nodes. This makes things easier for users by allowing files to or Nodes. This makes things easier for users by allowing files to
be specified as a white-space separated list to be split. be specified as a white-space separated list to be split.
The input rules are: The input rules are:
- A single string containing names separated by spaces. These will be - A single string containing names separated by spaces. These will be
split apart at the spaces. split apart at the spaces.
- A single Node instance - A single Node instance
- A list containing either strings or Node instances. Any strings - A list containing either strings or Node instances. Any strings
in the list are not split at spaces. in the list are not split at spaces.
In all cases, the function returns a list of Nodes and strings.""" In all cases, the function returns a list of Nodes and strings."""
if SCons.Util.is_List(arg): if SCons.Util.is_List(arg):
return list(map(self.subst, arg)) return list(map(self.subst, arg))
elif SCons.Util.is_String(arg): elif SCons.Util.is_String(arg):
@ -2246,7 +2258,7 @@ class Base(SubstitutionEnvironment):
while (node != node.srcnode()): while (node != node.srcnode()):
node = node.srcnode() node = node.srcnode()
return node return node
sources = map( final_source, sources ); sources = list(map( final_source, sources ));
# remove duplicates # remove duplicates
return list(set(sources)) return list(set(sources))
@ -2368,19 +2380,21 @@ class OverrideEnvironment(Base):
Environment = Base Environment = Base
# An entry point for returning a proxy subclass instance that overrides
# the subst*() methods so they don't actually perform construction
# variable substitution. This is specifically intended to be the shim
# layer in between global function calls (which don't want construction
# variable substitution) and the DefaultEnvironment() (which would
# substitute variables if left to its own devices)."""
#
# We have to wrap this in a function that allows us to delay definition of
# the class until it's necessary, so that when it subclasses Environment
# it will pick up whatever Environment subclass the wrapper interface
# might have assigned to SCons.Environment.Environment.
def NoSubstitutionProxy(subject): def NoSubstitutionProxy(subject):
"""
An entry point for returning a proxy subclass instance that overrides
the subst*() methods so they don't actually perform construction
variable substitution. This is specifically intended to be the shim
layer in between global function calls (which don't want construction
variable substitution) and the DefaultEnvironment() (which would
substitute variables if left to its own devices).
We have to wrap this in a function that allows us to delay definition of
the class until it's necessary, so that when it subclasses Environment
it will pick up whatever Environment subclass the wrapper interface
might have assigned to SCons.Environment.Environment.
"""
class _NoSubstitutionProxy(Environment): class _NoSubstitutionProxy(Environment):
def __init__(self, subject): def __init__(self, subject):
self.__dict__['__subject'] = subject self.__dict__['__subject'] = subject
@ -2389,7 +2403,7 @@ def NoSubstitutionProxy(subject):
def __setattr__(self, name, value): def __setattr__(self, name, value):
return setattr(self.__dict__['__subject'], name, value) return setattr(self.__dict__['__subject'], name, value)
def executor_to_lvars(self, kwdict): def executor_to_lvars(self, kwdict):
if kwdict.has_key('executor'): if 'executor' in kwdict:
kwdict['lvars'] = kwdict['executor'].get_lvars() kwdict['lvars'] = kwdict['executor'].get_lvars()
del kwdict['executor'] del kwdict['executor']
else: else:

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -28,72 +28,74 @@ and user errors in SCons.
""" """
__revision__ = "src/engine/SCons/Errors.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Errors.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import shutil
import SCons.Util import SCons.Util
import exceptions
class BuildError(Exception): class BuildError(Exception):
""" Errors occuring while building. """ Errors occurring while building.
BuildError have the following attributes: BuildError have the following attributes:
=========================================
Information about the cause of the build error: Information about the cause of the build error:
----------------------------------------------- -----------------------------------------------
errstr : a description of the error message errstr : a description of the error message
status : the return code of the action that caused the build status : the return code of the action that caused the build error.
error. Must be set to a non-zero value even if the Must be set to a non-zero value even if the build error is not due
build error is not due to an action returning a to an action returning a non-zero returned code.
non-zero returned code.
exitstatus : SCons exit status due to this build error. exitstatus : SCons exit status due to this build error.
Must be nonzero unless due to an explicit Exit() Must be nonzero unless due to an explicit Exit()
call. Not always the same as status, since call. Not always the same as status, since
actions return a status code that should be actions return a status code that should be
respected, but SCons typically exits with 2 respected, but SCons typically exits with 2
irrespective of the return value of the failed irrespective of the return value of the failed
action. action.
filename : The name of the file or directory that caused the filename : The name of the file or directory that caused the
build error. Set to None if no files are associated with build error. Set to None if no files are associated with
this error. This might be different from the target this error. This might be different from the target
being built. For example, failure to create the being built. For example, failure to create the
directory in which the target file will appear. It directory in which the target file will appear. It
can be None if the error is not due to a particular can be None if the error is not due to a particular
filename. filename.
exc_info : Info about exception that caused the build exc_info : Info about exception that caused the build
error. Set to (None, None, None) if this build error. Set to (None, None, None) if this build
error is not due to an exception. error is not due to an exception.
Information about the cause of the location of the error: Information about the cause of the location of the error:
--------------------------------------------------------- ---------------------------------------------------------
node : the error occured while building this target node(s) 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 executor : the executor that caused the build to fail (might
build to fail (might be None if the build failures be None if the build failures is not due to the
is not due to the an action failure) executor failing)
"""
def __init__(self, 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, node=None, errstr="Unknown error", status=2, exitstatus=2,
filename=None, executor=None, action=None, command=None, filename=None, executor=None, action=None, command=None,
exc_info=(None, None, None)): exc_info=(None, None, None)):
self.errstr = errstr # py3: errstr should be string and not bytes.
self.errstr = SCons.Util.to_str(errstr)
self.status = status self.status = status
self.exitstatus = exitstatus self.exitstatus = exitstatus
self.filename = filename self.filename = filename
@ -104,7 +106,7 @@ class BuildError(Exception):
self.action = action self.action = action
self.command = command self.command = command
Exception.__init__(self, node, errstr, status, exitstatus, filename, Exception.__init__(self, node, errstr, status, exitstatus, filename,
executor, action, command, exc_info) executor, action, command, exc_info)
def __str__(self): def __str__(self):
@ -139,13 +141,17 @@ def convert_to_BuildError(status, exc_info=None):
""" """
Convert any return code a BuildError Exception. Convert any return code a BuildError Exception.
`status' can either be a return code or an Exception. :Parameters:
- `status`: can either be a return code or an Exception.
The buildError.status we set here will normally be The buildError.status we set here will normally be
used as the exit status of the "scons" process. used as the exit status of the "scons" process.
""" """
if not exc_info and isinstance(status, Exception): if not exc_info and isinstance(status, Exception):
exc_info = (status.__class__, status, None) exc_info = (status.__class__, status, None)
if isinstance(status, BuildError): if isinstance(status, BuildError):
buildError = status buildError = status
buildError.exitstatus = 2 # always exit with 2 on build errors buildError.exitstatus = 2 # always exit with 2 on build errors
@ -163,14 +169,32 @@ def convert_to_BuildError(status, exc_info=None):
status=2, status=2,
exitstatus=2, exitstatus=2,
exc_info=exc_info) exc_info=exc_info)
elif isinstance(status, exceptions.EnvironmentError): elif isinstance(status, shutil.SameFileError):
# PY3 has a exception for when copying file to itself
# It's object provides info differently than below
try:
filename = status.filename
except AttributeError:
filename = None
buildError = BuildError(
errstr=status.args[0],
status=status.errno,
exitstatus=2,
filename=filename,
exc_info=exc_info)
elif isinstance(status, (EnvironmentError, OSError, IOError)):
# If an IOError/OSError happens, raise a BuildError. # If an IOError/OSError happens, raise a BuildError.
# Report the name of the file or directory that caused the # Report the name of the file or directory that caused the
# error, which might be different from the target being built # error, which might be different from the target being built
# (for example, failure to create the directory in which the # (for example, failure to create the directory in which the
# target file will appear). # target file will appear).
try: filename = status.filename try:
except AttributeError: filename = None filename = status.filename
except AttributeError:
filename = None
buildError = BuildError( buildError = BuildError(
errstr=status.strerror, errstr=status.strerror,
status=status.errno, status=status.errno,
@ -195,7 +219,7 @@ def convert_to_BuildError(status, exc_info=None):
exitstatus=2) exitstatus=2)
#import sys #import sys
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)"%(status,buildError.errstr, buildError.status)) #sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
return buildError return buildError
# Local Variables: # Local Variables:

View file

@ -6,7 +6,7 @@ Nodes.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -26,8 +26,9 @@ Nodes.
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
__revision__ = "src/engine/SCons/Executor.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Executor.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import collections import collections
@ -35,7 +36,7 @@ import SCons.Debug
from SCons.Debug import logInstanceCreation from SCons.Debug import logInstanceCreation
import SCons.Errors import SCons.Errors
import SCons.Memoize import SCons.Memoize
from SCons.compat import with_metaclass, NoSlotsPyPy
class Batch(object): class Batch(object):
"""Remembers exact association between targets """Remembers exact association between targets
@ -154,7 +155,7 @@ _execute_str_map = {0 : execute_null_str,
1 : execute_actions_str} 1 : execute_actions_str}
class Executor(object): class Executor(object, with_metaclass(NoSlotsPyPy)):
"""A class for controlling instances of executing an action. """A class for controlling instances of executing an action.
This largely exists to hold a single association of an action, This largely exists to hold a single association of an action,
@ -455,10 +456,16 @@ class Executor(object):
except KeyError: except KeyError:
pass pass
env = self.get_build_env() env = self.get_build_env()
result = "".join([action.get_contents(self.get_all_targets(),
self.get_all_sources(), action_list = self.get_action_list()
env) all_targets = self.get_all_targets()
for action in self.get_action_list()]) all_sources = self.get_all_sources()
result = bytearray("",'utf-8').join([action.get_contents(all_targets,
all_sources,
env)
for action in action_list])
self._memo['get_contents'] = result self._memo['get_contents'] = result
return result return result
@ -580,7 +587,7 @@ def get_NullEnvironment():
nullenv = NullEnvironment() nullenv = NullEnvironment()
return nullenv return nullenv
class Null(object): class Null(object, with_metaclass(NoSlotsPyPy)):
"""A null Executor, with a null build Environment, that does """A null Executor, with a null build Environment, that does
nothing when the rest of the methods call it. nothing when the rest of the methods call it.

View file

@ -7,7 +7,7 @@ stop, and wait on jobs.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Job.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Job.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.compat import SCons.compat
@ -278,14 +278,14 @@ else:
try: try:
prev_size = threading.stack_size(stack_size*1024) prev_size = threading.stack_size(stack_size*1024)
except AttributeError, e: except AttributeError as e:
# Only print a warning if the stack size has been # Only print a warning if the stack size has been
# explicitly set. # explicitly set.
if not explicit_stack_size is None: if not explicit_stack_size is None:
msg = "Setting stack size is unsupported by this version of Python:\n " + \ msg = "Setting stack size is unsupported by this version of Python:\n " + \
e.args[0] e.args[0]
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
except ValueError, e: except ValueError as e:
msg = "Setting stack size failed:\n " + str(e) msg = "Setting stack size failed:\n " + str(e)
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -20,8 +20,9 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
from __future__ import print_function
__revision__ = "src/engine/SCons/Memoize.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Memoize.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Memoizer __doc__ = """Memoizer
@ -33,7 +34,7 @@ values in a consistent way. In particular, it requires that the class uses a
dictionary named "_memo" to store the cached values. dictionary named "_memo" to store the cached values.
Here is an example of wrapping a method that returns a computed value, Here is an example of wrapping a method that returns a computed value,
with no input parameters: with no input parameters::
@SCons.Memoize.CountMethodCall @SCons.Memoize.CountMethodCall
def foo(self): def foo(self):
@ -50,7 +51,7 @@ with no input parameters:
return result return result
Here is an example of wrapping a method that will return different values Here is an example of wrapping a method that will return different values
based on one or more input arguments: based on one or more input arguments::
def _bar_key(self, argument): # Memoization def _bar_key(self, argument): # Memoization
return argument # Memoization return argument # Memoization
@ -123,13 +124,12 @@ class Counter(object):
def key(self): def key(self):
return self.cls_name+'.'+self.method_name return self.cls_name+'.'+self.method_name
def display(self): def display(self):
fmt = " %7d hits %7d misses %s()" print(" {:7d} hits {:7d} misses {}()".format(self.hit, self.miss, self.key()))
print fmt % (self.hit, self.miss, self.key()) def __eq__(self, other):
def __cmp__(self, other):
try: try:
return cmp(self.key(), other.key()) return self.key() == other.key()
except AttributeError: except AttributeError:
return 0 return True
class CountValue(Counter): class CountValue(Counter):
""" """
@ -185,7 +185,7 @@ def Dump(title=None):
collected so far. collected so far.
""" """
if title: if title:
print title print(title)
for counter in sorted(CounterList): for counter in sorted(CounterList):
CounterList[counter].display() CounterList[counter].display()

View file

@ -8,7 +8,7 @@ This creates a hash of global Aliases (dummy targets).
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Node/Alias.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Node/Alias.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import collections import collections

View file

@ -11,7 +11,7 @@ that can be used by scripts or modules looking for the canonical default.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -31,8 +31,9 @@ that can be used by scripts or modules looking for the canonical default.
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
__revision__ = "src/engine/SCons/Node/FS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Node/FS.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import fnmatch import fnmatch
import os import os
@ -122,7 +123,7 @@ def save_strings(val):
# tells us whether or not os.path.splitdrive() actually does anything # tells us whether or not os.path.splitdrive() actually does anything
# on this system, and therefore whether we need to bother calling it # on this system, and therefore whether we need to bother calling it
# when looking up path names in various methods below. # when looking up path names in various methods below.
# #
do_splitdrive = None do_splitdrive = None
_my_splitdrive =None _my_splitdrive =None
@ -157,7 +158,7 @@ def initialize_do_splitdrive():
global OS_SEP global OS_SEP
global UNC_PREFIX global UNC_PREFIX
global os_sep_is_slash global os_sep_is_slash
OS_SEP = os.sep OS_SEP = os.sep
UNC_PREFIX = OS_SEP + OS_SEP UNC_PREFIX = OS_SEP + OS_SEP
os_sep_is_slash = OS_SEP == '/' os_sep_is_slash = OS_SEP == '/'
@ -178,7 +179,7 @@ needs_normpath_check = re.compile(
# b) The path starts with '..'. E.g. '../' or '../moredirs' # b) The path starts with '..'. E.g. '../' or '../moredirs'
# but we not match '..abc/'. # but we not match '..abc/'.
# c) The path ends with '..'. E.g. '/..' or 'dirs/..' # c) The path ends with '..'. E.g. '/..' or 'dirs/..'
# d) The path contains a '..' in the middle. # d) The path contains a '..' in the middle.
# E.g. dirs/../moredirs # E.g. dirs/../moredirs
(.*/)?\.\.(?:/|$) | (.*/)?\.\.(?:/|$) |
@ -200,7 +201,7 @@ needs_normpath_check = re.compile(
\./|.*/\.(?:/|$) \./|.*/\.(?:/|$)
''', ''',
re.VERBOSE re.VERBOSE
) )
needs_normpath_match = needs_normpath_check.match needs_normpath_match = needs_normpath_check.match
@ -219,7 +220,12 @@ needs_normpath_match = needs_normpath_check.match
# there should be *no* changes to the external file system(s)... # there should be *no* changes to the external file system(s)...
# #
if hasattr(os, 'link'): # For Now disable hard & softlinks for win32
# PY3 supports them, but the rest of SCons is not ready for this
# in some cases user permissions may be required.
# TODO: See if theres a reasonable way to enable using links on win32/64
if hasattr(os, 'link') and sys.platform != 'win32':
def _hardlink_func(fs, src, dst): def _hardlink_func(fs, src, dst):
# If the source is a symlink, we can't just hard-link to it # If the source is a symlink, we can't just hard-link to it
# because a relative symlink may point somewhere completely # because a relative symlink may point somewhere completely
@ -235,7 +241,7 @@ if hasattr(os, 'link'):
else: else:
_hardlink_func = None _hardlink_func = None
if hasattr(os, 'symlink'): if hasattr(os, 'symlink') and sys.platform != 'win32':
def _softlink_func(fs, src, dst): def _softlink_func(fs, src, dst):
fs.symlink(src, dst) fs.symlink(src, dst)
else: else:
@ -350,33 +356,6 @@ class _Null(object):
_null = _Null() _null = _Null()
DefaultSCCSBuilder = None
DefaultRCSBuilder = None
def get_DefaultSCCSBuilder():
global DefaultSCCSBuilder
if DefaultSCCSBuilder is None:
import SCons.Builder
# "env" will get filled in by Executor.get_build_env()
# calling SCons.Defaults.DefaultEnvironment() when necessary.
act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR')
DefaultSCCSBuilder = SCons.Builder.Builder(action = act,
env = None,
name = "DefaultSCCSBuilder")
return DefaultSCCSBuilder
def get_DefaultRCSBuilder():
global DefaultRCSBuilder
if DefaultRCSBuilder is None:
import SCons.Builder
# "env" will get filled in by Executor.get_build_env()
# calling SCons.Defaults.DefaultEnvironment() when necessary.
act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR')
DefaultRCSBuilder = SCons.Builder.Builder(action = act,
env = None,
name = "DefaultRCSBuilder")
return DefaultRCSBuilder
# Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem. # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
_is_cygwin = sys.platform == "cygwin" _is_cygwin = sys.platform == "cygwin"
if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin: if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
@ -421,46 +400,12 @@ def do_diskcheck_match(node, predicate, errorfmt):
def ignore_diskcheck_match(node, predicate, errorfmt): def ignore_diskcheck_match(node, predicate, errorfmt):
pass pass
def do_diskcheck_rcs(node, name):
try:
rcs_dir = node.rcs_dir
except AttributeError:
if node.entry_exists_on_disk('RCS'):
rcs_dir = node.Dir('RCS')
else:
rcs_dir = None
node.rcs_dir = rcs_dir
if rcs_dir:
return rcs_dir.entry_exists_on_disk(name+',v')
return None
def ignore_diskcheck_rcs(node, name):
return None
def do_diskcheck_sccs(node, name):
try:
sccs_dir = node.sccs_dir
except AttributeError:
if node.entry_exists_on_disk('SCCS'):
sccs_dir = node.Dir('SCCS')
else:
sccs_dir = None
node.sccs_dir = sccs_dir
if sccs_dir:
return sccs_dir.entry_exists_on_disk('s.'+name)
return None
def ignore_diskcheck_sccs(node, name):
return None
diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match) diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs)
diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs)
diskcheckers = [ diskcheckers = [
diskcheck_match, diskcheck_match,
diskcheck_rcs,
diskcheck_sccs,
] ]
def set_diskcheck(list): def set_diskcheck(list):
@ -476,6 +421,11 @@ class EntryProxy(SCons.Util.Proxy):
__str__ = SCons.Util.Delegate('__str__') __str__ = SCons.Util.Delegate('__str__')
# In PY3 if a class defines __eq__, then it must explicitly provide
# __hash__. Since SCons.Util.Proxy provides __eq__ we need the following
# see: https://docs.python.org/3.1/reference/datamodel.html#object.__hash__
__hash__ = SCons.Util.Delegate('__hash__')
def __get_abspath(self): def __get_abspath(self):
entry = self.get() entry = self.get()
return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(),
@ -564,7 +514,7 @@ class EntryProxy(SCons.Util.Proxy):
except KeyError: except KeyError:
try: try:
attr = SCons.Util.Proxy.__getattr__(self, name) attr = SCons.Util.Proxy.__getattr__(self, name)
except AttributeError, e: except AttributeError as e:
# Raise our own AttributeError subclass with an # Raise our own AttributeError subclass with an
# overridden __str__() method that identifies the # overridden __str__() method that identifies the
# name of the entry that caused the exception. # name of the entry that caused the exception.
@ -573,6 +523,7 @@ class EntryProxy(SCons.Util.Proxy):
else: else:
return attr_function(self) return attr_function(self)
class Base(SCons.Node.Node): class Base(SCons.Node.Node):
"""A generic class for file system entries. This class is for """A generic class for file system entries. This class is for
when we don't know yet whether the entry being looked up is a file when we don't know yet whether the entry being looked up is a file
@ -608,14 +559,13 @@ class Base(SCons.Node.Node):
our relative and absolute paths, identify our parent our relative and absolute paths, identify our parent
directory, and indicate that this node should use directory, and indicate that this node should use
signatures.""" signatures."""
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Base') if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Base')
SCons.Node.Node.__init__(self) SCons.Node.Node.__init__(self)
# Filenames and paths are probably reused and are intern'ed to # Filenames and paths are probably reused and are intern'ed to save some memory.
# save some memory. # Filename with extension as it was specified when the object was
# created; to obtain filesystem path, use Python str() function
#: Filename with extension as it was specified when the object was
#: created; to obtain filesystem path, use Python str() function
self.name = SCons.Util.silent_intern(name) self.name = SCons.Util.silent_intern(name)
self.fs = fs #: Reference to parent Node.FS object self.fs = fs #: Reference to parent Node.FS object
@ -670,14 +620,14 @@ class Base(SCons.Node.Node):
single variables lazily when required, in order to save memory. single variables lazily when required, in order to save memory.
The redirection to the getters lets older Tools and The redirection to the getters lets older Tools and
SConstruct continue to work without any additional changes, SConstruct continue to work without any additional changes,
fully transparent to the user. fully transparent to the user.
Note, that __getattr__ is only called as fallback when the Note, that __getattr__ is only called as fallback when the
requested attribute can't be found, so there should be no requested attribute can't be found, so there should be no
speed performance penalty involved for standard builds. speed performance penalty involved for standard builds.
""" """
if attr in node_bwcomp: if attr in node_bwcomp:
return node_bwcomp[attr](self) return node_bwcomp[attr](self)
raise AttributeError("%r object has no attribute %r" % raise AttributeError("%r object has no attribute %r" %
(self.__class__, attr)) (self.__class__, attr))
@ -689,13 +639,17 @@ class Base(SCons.Node.Node):
return self._save_str() return self._save_str()
return self._get_str() return self._get_str()
def __lt__(self, other):
""" less than operator used by sorting on py3"""
return str(self) < str(other)
@SCons.Memoize.CountMethodCall @SCons.Memoize.CountMethodCall
def _save_str(self): def _save_str(self):
try: try:
return self._memo['_save_str'] return self._memo['_save_str']
except KeyError: except KeyError:
pass pass
result = sys.intern(self._get_str()) result = SCons.Util.silent_intern(self._get_str())
self._memo['_save_str'] = result self._memo['_save_str'] = result
return result return result
@ -799,7 +753,7 @@ class Base(SCons.Node.Node):
path_elems = self.get_path_elements() path_elems = self.get_path_elements()
pathname = '' pathname = ''
try: i = path_elems.index(dir) try: i = path_elems.index(dir)
except ValueError: except ValueError:
for p in path_elems[:-1]: for p in path_elems[:-1]:
pathname += p.dirname pathname += p.dirname
else: else:
@ -840,13 +794,13 @@ class Base(SCons.Node.Node):
return self.name return self.name
else: else:
return self.dir.entry_path(self.name) return self.dir.entry_path(self.name)
def get_tpath(self): def get_tpath(self):
if self.dir._tpath == '.': if self.dir._tpath == '.':
return self.name return self.name
else: else:
return self.dir.entry_tpath(self.name) return self.dir.entry_tpath(self.name)
def get_path_elements(self): def get_path_elements(self):
return self.dir._path_elements + [self] return self.dir._path_elements + [self]
@ -939,7 +893,7 @@ class Base(SCons.Node.Node):
def _glob1(self, pattern, ondisk=True, source=False, strings=False): def _glob1(self, pattern, ondisk=True, source=False, strings=False):
return [] return []
# Dict that provides a simple backward compatibility # Dict that provides a simple backward compatibility
# layer for the Node attributes 'abspath', 'labspath', # layer for the Node attributes 'abspath', 'labspath',
# 'path', 'tpath' and 'path_elements'. # 'path', 'tpath' and 'path_elements'.
@ -971,15 +925,13 @@ class Entry(Base):
'root', 'root',
'dirname', 'dirname',
'on_disk_entries', 'on_disk_entries',
'sccs_dir',
'rcs_dir',
'released_target_info', 'released_target_info',
'contentsig'] 'contentsig']
def __init__(self, name, directory, fs): def __init__(self, name, directory, fs):
Base.__init__(self, name, directory, fs) Base.__init__(self, name, directory, fs)
self._func_exists = 3 self._func_exists = 3
self._func_get_contents = 1 self._func_get_contents = 1
def diskcheck_match(self): def diskcheck_match(self):
pass pass
@ -1198,7 +1150,7 @@ class FS(LocalFS):
DirNodeInfo.fs = self DirNodeInfo.fs = self
FileNodeInfo.fs = self FileNodeInfo.fs = self
def set_SConstruct_dir(self, dir): def set_SConstruct_dir(self, dir):
self.SConstruct_dir = dir self.SConstruct_dir = dir
@ -1210,9 +1162,9 @@ class FS(LocalFS):
def getcwd(self): def getcwd(self):
if hasattr(self, "_cwd"): if hasattr(self, "_cwd"):
return self._cwd return self._cwd
else: else:
return "<no cwd>" return "<no cwd>"
def chdir(self, dir, change_os_dir=0): def chdir(self, dir, change_os_dir=0):
"""Change the current working directory for lookups. """Change the current working directory for lookups.
@ -1310,7 +1262,7 @@ class FS(LocalFS):
p = p.strip('/') p = p.strip('/')
needs_normpath = needs_normpath_match(p) needs_normpath = needs_normpath_match(p)
# The path is relative to the top-level SCons directory. # The path is relative to the top-level SCons directory.
if p in ('', '.'): if p in ('', '.'):
p = directory.get_labspath() p = directory.get_labspath()
@ -1437,6 +1389,35 @@ class FS(LocalFS):
if not isinstance(d, SCons.Node.Node): if not isinstance(d, SCons.Node.Node):
d = self.Dir(d) d = self.Dir(d)
self.Top.addRepository(d) self.Top.addRepository(d)
def PyPackageDir(self, modulename):
"""Locate the directory of a given python module name
For example scons might resolve to
Windows: C:\Python27\Lib\site-packages\scons-2.5.1
Linux: /usr/lib/scons
This can be useful when we want to determine a toolpath based on a python module name"""
dirpath = ''
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
# Python2 Code
import imp
splitname = modulename.split('.')
srchpths = sys.path
for item in splitname:
file, path, desc = imp.find_module(item, srchpths)
if file is not None:
path = os.path.dirname(path)
srchpths = [path]
dirpath = path
else:
# Python3 Code
import importlib.util
modspec = importlib.util.find_spec(modulename)
dirpath = os.path.dirname(modspec.origin)
return self._lookup(dirpath, None, Dir, True)
def variant_dir_target_climb(self, orig, dir, tail): def variant_dir_target_climb(self, orig, dir, tail):
"""Create targets in corresponding variant directories """Create targets in corresponding variant directories
@ -1469,7 +1450,7 @@ class FS(LocalFS):
""" """
Globs Globs
This is mainly a shim layer This is mainly a shim layer
""" """
if cwd is None: if cwd is None:
cwd = self.getcwd() cwd = self.getcwd()
@ -1518,8 +1499,6 @@ class Dir(Base):
'root', 'root',
'dirname', 'dirname',
'on_disk_entries', 'on_disk_entries',
'sccs_dir',
'rcs_dir',
'released_target_info', 'released_target_info',
'contentsig'] 'contentsig']
@ -1555,7 +1534,7 @@ class Dir(Base):
self._func_sconsign = 1 self._func_sconsign = 1
self._func_exists = 2 self._func_exists = 2
self._func_get_contents = 2 self._func_get_contents = 2
self._abspath = SCons.Util.silent_intern(self.dir.entry_abspath(self.name)) self._abspath = SCons.Util.silent_intern(self.dir.entry_abspath(self.name))
self._labspath = SCons.Util.silent_intern(self.dir.entry_labspath(self.name)) self._labspath = SCons.Util.silent_intern(self.dir.entry_labspath(self.name))
if self.dir._path == '.': if self.dir._path == '.':
@ -1594,7 +1573,7 @@ class Dir(Base):
# Prepend MkdirBuilder action to existing action list # Prepend MkdirBuilder action to existing action list
l = self.get_executor().action_list l = self.get_executor().action_list
a = get_MkdirBuilder().action a = get_MkdirBuilder().action
l.insert(0, a) l.insert(0, a)
self.get_executor().set_action_list(l) self.get_executor().set_action_list(l)
def diskcheck_match(self): def diskcheck_match(self):
@ -1606,7 +1585,7 @@ class Dir(Base):
This clears any cached information that is invalidated by changing This clears any cached information that is invalidated by changing
the repository.""" the repository."""
for node in self.entries.values(): for node in list(self.entries.values()):
if node != self.dir: if node != self.dir:
if node != self and isinstance(node, Dir): if node != self and isinstance(node, Dir):
node.__clearRepositoryCache(duplicate) node.__clearRepositoryCache(duplicate)
@ -1742,7 +1721,7 @@ class Dir(Base):
path_elems = ['..'] * (len(self._path_elements) - i) \ path_elems = ['..'] * (len(self._path_elements) - i) \
+ [n.name for n in other._path_elements[i:]] + [n.name for n in other._path_elements[i:]]
result = OS_SEP.join(path_elems) result = OS_SEP.join(path_elems)
memo_dict[other] = result memo_dict[other] = result
@ -1913,10 +1892,10 @@ class Dir(Base):
def get_internal_path(self): def get_internal_path(self):
return self._path return self._path
def get_tpath(self): def get_tpath(self):
return self._tpath return self._tpath
def get_path_elements(self): def get_path_elements(self):
return self._path_elements return self._path_elements
@ -1936,7 +1915,7 @@ class Dir(Base):
""" Searches through the file/dir entries of the current """ Searches through the file/dir entries of the current
directory, and returns True if a physical entry with the given directory, and returns True if a physical entry with the given
name could be found. name could be found.
@see rentry_exists_on_disk @see rentry_exists_on_disk
""" """
try: try:
@ -1970,10 +1949,10 @@ class Dir(Base):
The local directory (self) gets searched first, so The local directory (self) gets searched first, so
repositories take a lower precedence regarding the repositories take a lower precedence regarding the
searching order. searching order.
@see entry_exists_on_disk @see entry_exists_on_disk
""" """
rentry_exists = self.entry_exists_on_disk(name) rentry_exists = self.entry_exists_on_disk(name)
if not rentry_exists: if not rentry_exists:
# Search through the repository folders # Search through the repository folders
@ -2085,9 +2064,7 @@ class Dir(Base):
return node return node
def file_on_disk(self, name): def file_on_disk(self, name):
if self.entry_exists_on_disk(name) or \ if self.entry_exists_on_disk(name):
diskcheck_rcs(self, name) or \
diskcheck_sccs(self, name):
try: return self.File(name) try: return self.File(name)
except TypeError: pass except TypeError: pass
node = self.srcdir_duplicate(name) node = self.srcdir_duplicate(name)
@ -2178,7 +2155,7 @@ class Dir(Base):
for x in excludeList: for x in excludeList:
r = self.glob(x, ondisk, source, strings) r = self.glob(x, ondisk, source, strings)
excludes.extend(r) excludes.extend(r)
result = filter(lambda x: not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes)), result) result = [x for x in result if not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes))]
return sorted(result, key=lambda a: str(a)) return sorted(result, key=lambda a: str(a))
def _glob1(self, pattern, ondisk=True, source=False, strings=False): def _glob1(self, pattern, ondisk=True, source=False, strings=False):
@ -2256,9 +2233,9 @@ class RootDir(Dir):
add a separator when creating the path names of entries within add a separator when creating the path names of entries within
this directory. this directory.
""" """
__slots__ = ['_lookupDict'] __slots__ = ['_lookupDict']
def __init__(self, drive, fs): def __init__(self, drive, fs):
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir') if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
SCons.Node.Node.__init__(self) SCons.Node.Node.__init__(self)
@ -2266,7 +2243,7 @@ class RootDir(Dir):
# Handle all the types of drives: # Handle all the types of drives:
if drive == '': if drive == '':
# No drive, regular UNIX root or Windows default drive. # No drive, regular UNIX root or Windows default drive.
name = OS_SEP name = OS_SEP
dirname = OS_SEP dirname = OS_SEP
elif drive == '//': elif drive == '//':
# UNC path # UNC path
@ -2277,8 +2254,8 @@ class RootDir(Dir):
name = drive name = drive
dirname = drive + OS_SEP dirname = drive + OS_SEP
#: Filename with extension as it was specified when the object was # Filename with extension as it was specified when the object was
#: created; to obtain filesystem path, use Python str() function # created; to obtain filesystem path, use Python str() function
self.name = SCons.Util.silent_intern(name) self.name = SCons.Util.silent_intern(name)
self.fs = fs #: Reference to parent Node.FS object self.fs = fs #: Reference to parent Node.FS object
@ -2336,7 +2313,7 @@ class RootDir(Dir):
self._func_sconsign = 1 self._func_sconsign = 1
self._func_exists = 2 self._func_exists = 2
self._func_get_contents = 2 self._func_get_contents = 2
# Don't just reset the executor, replace its action list, # Don't just reset the executor, replace its action list,
# because it might have some pre-or post-actions that need to # because it might have some pre-or post-actions that need to
# be preserved. # be preserved.
@ -2352,9 +2329,9 @@ class RootDir(Dir):
# Prepend MkdirBuilder action to existing action list # Prepend MkdirBuilder action to existing action list
l = self.get_executor().action_list l = self.get_executor().action_list
a = get_MkdirBuilder().action a = get_MkdirBuilder().action
l.insert(0, a) l.insert(0, a)
self.get_executor().set_action_list(l) self.get_executor().set_action_list(l)
def must_be_same(self, klass): def must_be_same(self, klass):
if klass is Dir: if klass is Dir:
@ -2433,6 +2410,7 @@ class RootDir(Dir):
def src_builder(self): def src_builder(self):
return _null return _null
class FileNodeInfo(SCons.Node.NodeInfoBase): class FileNodeInfo(SCons.Node.NodeInfoBase):
__slots__ = ('csig', 'timestamp', 'size') __slots__ = ('csig', 'timestamp', 'size')
current_version_id = 2 current_version_id = 2
@ -2484,6 +2462,7 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
if key not in ('__weakref__',): if key not in ('__weakref__',):
setattr(self, key, value) setattr(self, key, value)
class FileBuildInfo(SCons.Node.BuildInfoBase): class FileBuildInfo(SCons.Node.BuildInfoBase):
__slots__ = () __slots__ = ()
current_version_id = 2 current_version_id = 2
@ -2514,6 +2493,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase):
pass pass
else: else:
setattr(self, attr, list(map(node_to_str, val))) setattr(self, attr, list(map(node_to_str, val)))
def convert_from_sconsign(self, dir, name): def convert_from_sconsign(self, dir, name):
""" """
Converts a newly-read FileBuildInfo object for in-SCons use Converts a newly-read FileBuildInfo object for in-SCons use
@ -2522,6 +2502,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase):
perform--but we're leaving this method here to make that clear. perform--but we're leaving this method here to make that clear.
""" """
pass pass
def prepare_dependencies(self): def prepare_dependencies(self):
""" """
Prepares a FileBuildInfo object for explaining what changed Prepares a FileBuildInfo object for explaining what changed
@ -2550,6 +2531,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase):
s = ni.str_to_node(s) s = ni.str_to_node(s)
nodes.append(s) nodes.append(s)
setattr(self, nattr, nodes) setattr(self, nattr, nodes)
def format(self, names=0): def format(self, names=0):
result = [] result = []
bkids = self.bsources + self.bdepends + self.bimplicit bkids = self.bsources + self.bdepends + self.bimplicit
@ -2562,6 +2544,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase):
result.append('%s [%s]' % (self.bactsig, self.bact)) result.append('%s [%s]' % (self.bactsig, self.bact))
return '\n'.join(result) return '\n'.join(result)
class File(Base): class File(Base):
"""A class for files in a file system. """A class for files in a file system.
""" """
@ -2578,8 +2561,6 @@ class File(Base):
'root', 'root',
'dirname', 'dirname',
'on_disk_entries', 'on_disk_entries',
'sccs_dir',
'rcs_dir',
'released_target_info', 'released_target_info',
'contentsig'] 'contentsig']
@ -2628,11 +2609,11 @@ class File(Base):
self.store_info = 1 self.store_info = 1
self._func_exists = 4 self._func_exists = 4
self._func_get_contents = 3 self._func_get_contents = 3
# Initialize this Node's decider function to decide_source() because # Initialize this Node's decider function to decide_source() because
# every file is a source file until it has a Builder attached... # every file is a source file until it has a Builder attached...
self.changed_since_last_build = 4 self.changed_since_last_build = 4
# If there was already a Builder set on this entry, then # If there was already a Builder set on this entry, then
# we need to make sure we call the target-decider function, # we need to make sure we call the target-decider function,
# not the source-decider. Reaching in and doing this by hand # not the source-decider. Reaching in and doing this by hand
@ -2652,10 +2633,12 @@ class File(Base):
def get_contents(self): def get_contents(self):
return SCons.Node._get_contents_map[self._func_get_contents](self) return SCons.Node._get_contents_map[self._func_get_contents](self)
# This attempts to figure out what the encoding of the text is
# based upon the BOM bytes, and then decodes the contents so that
# it's a valid python string.
def get_text_contents(self): def get_text_contents(self):
"""
This attempts to figure out what the encoding of the text is
based upon the BOM bytes, and then decodes the contents so that
it's a valid python string.
"""
contents = self.get_contents() contents = self.get_contents()
# The behavior of various decode() methods and functions # The behavior of various decode() methods and functions
# w.r.t. the initial BOM bytes is different for different # w.r.t. the initial BOM bytes is different for different
@ -2663,13 +2646,20 @@ class File(Base):
# them, but has a 'utf-8-sig' which does; 'utf-16' seems to # them, but has a 'utf-8-sig' which does; 'utf-16' seems to
# strip them; etc.) Just sidestep all the complication by # strip them; etc.) Just sidestep all the complication by
# explicitly stripping the BOM before we decode(). # explicitly stripping the BOM before we decode().
if contents.startswith(codecs.BOM_UTF8): if contents[:len(codecs.BOM_UTF8)] == codecs.BOM_UTF8:
return contents[len(codecs.BOM_UTF8):].decode('utf-8') return contents[len(codecs.BOM_UTF8):].decode('utf-8')
if contents.startswith(codecs.BOM_UTF16_LE): if contents[:len(codecs.BOM_UTF16_LE)] == codecs.BOM_UTF16_LE:
return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le') return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le')
if contents.startswith(codecs.BOM_UTF16_BE): if contents[:len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE:
return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be') return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be')
return contents try:
return contents.decode('utf-8')
except UnicodeDecodeError as e:
try:
return contents.decode('latin-1')
except UnicodeDecodeError as e:
return contents.decode('utf-8', error='backslashreplace')
def get_content_hash(self): def get_content_hash(self):
""" """
@ -2681,12 +2671,12 @@ class File(Base):
try: try:
cs = SCons.Util.MD5filesignature(fname, cs = SCons.Util.MD5filesignature(fname,
chunksize=SCons.Node.FS.File.md5_chunksize*1024) chunksize=SCons.Node.FS.File.md5_chunksize*1024)
except EnvironmentError, e: except EnvironmentError as e:
if not e.filename: if not e.filename:
e.filename = fname e.filename = fname
raise raise
return cs return cs
@SCons.Memoize.CountMethodCall @SCons.Memoize.CountMethodCall
def get_size(self): def get_size(self):
try: try:
@ -2960,30 +2950,30 @@ class File(Base):
def release_target_info(self): def release_target_info(self):
"""Called just after this node has been marked """Called just after this node has been marked
up-to-date or was built completely. up-to-date or was built completely.
This is where we try to release as many target node infos This is where we try to release as many target node infos
as possible for clean builds and update runs, in order as possible for clean builds and update runs, in order
to minimize the overall memory consumption. to minimize the overall memory consumption.
We'd like to remove a lot more attributes like self.sources We'd like to remove a lot more attributes like self.sources
and self.sources_set, but they might get used and self.sources_set, but they might get used
in a next build step. For example, during configuration in a next build step. For example, during configuration
the source files for a built *.o file are used to figure out the source files for a built E{*}.o file are used to figure out
which linker to use for the resulting Program (gcc vs. g++)! which linker to use for the resulting Program (gcc vs. g++)!
That's why we check for the 'keep_targetinfo' attribute, That's why we check for the 'keep_targetinfo' attribute,
config Nodes and the Interactive mode just don't allow config Nodes and the Interactive mode just don't allow
an early release of most variables. an early release of most variables.
In the same manner, we can't simply remove the self.attributes In the same manner, we can't simply remove the self.attributes
here. The smart linking relies on the shared flag, and some here. The smart linking relies on the shared flag, and some
parts of the java Tool use it to transport information parts of the java Tool use it to transport information
about nodes... about nodes...
@see: built() and Node.release_target_info() @see: built() and Node.release_target_info()
""" """
if (self.released_target_info or SCons.Node.interactive): if (self.released_target_info or SCons.Node.interactive):
return return
if not hasattr(self.attributes, 'keep_targetinfo'): if not hasattr(self.attributes, 'keep_targetinfo'):
# Cache some required values, before releasing # Cache some required values, before releasing
# stuff like env, executor and builder... # stuff like env, executor and builder...
@ -3014,12 +3004,7 @@ class File(Base):
return None return None
scb = self.dir.src_builder() scb = self.dir.src_builder()
if scb is _null: if scb is _null:
if diskcheck_sccs(self.dir, self.name): scb = None
scb = get_DefaultSCCSBuilder()
elif diskcheck_rcs(self.dir, self.name):
scb = get_DefaultRCSBuilder()
else:
scb = None
if scb is not None: if scb is not None:
try: try:
b = self.builder b = self.builder
@ -3056,7 +3041,7 @@ class File(Base):
def _rmv_existing(self): def _rmv_existing(self):
self.clear_memoized_values() self.clear_memoized_values()
if SCons.Node.print_duplicate: if SCons.Node.print_duplicate:
print "dup: removing existing target %s"%self print("dup: removing existing target {}".format(self))
e = Unlink(self, [], None) e = Unlink(self, [], None)
if isinstance(e, SCons.Errors.BuildError): if isinstance(e, SCons.Errors.BuildError):
raise e raise e
@ -3080,9 +3065,8 @@ class File(Base):
else: else:
try: try:
self._createDir() self._createDir()
except SCons.Errors.StopError, drive: except SCons.Errors.StopError as drive:
desc = "No drive `%s' for target `%s'." % (drive, self) raise SCons.Errors.StopError("No drive `{}' for target `{}'.".format(drive, self))
raise SCons.Errors.StopError(desc)
# #
# #
@ -3098,12 +3082,11 @@ class File(Base):
def do_duplicate(self, src): def do_duplicate(self, src):
self._createDir() self._createDir()
if SCons.Node.print_duplicate: if SCons.Node.print_duplicate:
print "dup: relinking variant '%s' from '%s'"%(self, src) print("dup: relinking variant '{}' from '{}'".format(self, src))
Unlink(self, None, None) Unlink(self, None, None)
e = Link(self, src, None) e = Link(self, src, None)
if isinstance(e, SCons.Errors.BuildError): if isinstance(e, SCons.Errors.BuildError):
desc = "Cannot duplicate `%s' in `%s': %s." % (src.get_internal_path(), self.dir._path, e.errstr) raise SCons.Errors.StopError("Cannot duplicate `{}' in `{}': {}.".format(src.get_internal_path(), self.dir._path, e.errstr))
raise SCons.Errors.StopError(desc)
self.linked = 1 self.linked = 1
# The Link() action may or may not have actually # The Link() action may or may not have actually
# created the file, depending on whether the -n # created the file, depending on whether the -n
@ -3117,7 +3100,6 @@ class File(Base):
return self._memo['exists'] return self._memo['exists']
except KeyError: except KeyError:
pass pass
result = SCons.Node._exists_map[self._func_exists](self) result = SCons.Node._exists_map[self._func_exists](self)
self._memo['exists'] = result self._memo['exists'] = result
return result return result
@ -3199,37 +3181,37 @@ class File(Base):
def built(self): def built(self):
"""Called just after this File node is successfully built. """Called just after this File node is successfully built.
Just like for 'release_target_info' we try to release Just like for 'release_target_info' we try to release
some more target node attributes in order to minimize the some more target node attributes in order to minimize the
overall memory consumption. overall memory consumption.
@see: release_target_info @see: release_target_info
""" """
SCons.Node.Node.built(self) SCons.Node.Node.built(self)
if (not SCons.Node.interactive and if (not SCons.Node.interactive and
not hasattr(self.attributes, 'keep_targetinfo')): not hasattr(self.attributes, 'keep_targetinfo')):
# Ensure that the build infos get computed and cached... # Ensure that the build infos get computed and cached...
SCons.Node.store_info_map[self.store_info](self) SCons.Node.store_info_map[self.store_info](self)
# ... then release some more variables. # ... then release some more variables.
self._specific_sources = False self._specific_sources = False
self._labspath = None self._labspath = None
self._save_str() self._save_str()
self.cwd = None self.cwd = None
self.scanner_paths = None self.scanner_paths = None
def changed(self, node=None, allowcache=False): def changed(self, node=None, allowcache=False):
""" """
Returns if the node is up-to-date with respect to the BuildInfo Returns if the node is up-to-date with respect to the BuildInfo
stored last time it was built. stored last time it was built.
For File nodes this is basically a wrapper around Node.changed(), For File nodes this is basically a wrapper around Node.changed(),
but we allow the return value to get cached after the reference but we allow the return value to get cached after the reference
to the Executor got released in release_target_info(). to the Executor got released in release_target_info().
@see: Node.changed() @see: Node.changed()
""" """
if node is None: if node is None:
@ -3237,7 +3219,7 @@ class File(Base):
return self._memo['changed'] return self._memo['changed']
except KeyError: except KeyError:
pass pass
has_changed = SCons.Node.Node.changed(self, node) has_changed = SCons.Node.Node.changed(self, node)
if allowcache: if allowcache:
self._memo['changed'] = has_changed self._memo['changed'] = has_changed
@ -3290,7 +3272,7 @@ class File(Base):
# ...and they'd like a local copy. # ...and they'd like a local copy.
e = LocalCopy(self, r, None) e = LocalCopy(self, r, None)
if isinstance(e, SCons.Errors.BuildError): if isinstance(e, SCons.Errors.BuildError):
raise raise
SCons.Node.store_info_map[self.store_info](self) SCons.Node.store_info_map[self.store_info](self)
if T: Trace(' 1\n') if T: Trace(' 1\n')
return 1 return 1
@ -3372,12 +3354,12 @@ class File(Base):
It computes and returns the signature for this It computes and returns the signature for this
node's contents. node's contents.
""" """
try: try:
return self.contentsig return self.contentsig
except AttributeError: except AttributeError:
pass pass
executor = self.get_executor() executor = self.get_executor()
result = self.contentsig = SCons.Util.MD5signature(executor.get_contents()) result = self.contentsig = SCons.Util.MD5signature(executor.get_contents())
@ -3397,7 +3379,7 @@ class File(Base):
return self.cachesig return self.cachesig
except AttributeError: except AttributeError:
pass pass
# Collect signatures for all children # Collect signatures for all children
children = self.children() children = self.children()
sigs = [n.get_cachedir_csig() for n in children] sigs = [n.get_cachedir_csig() for n in children]
@ -3461,24 +3443,19 @@ class FileFinder(object):
def _find_file_key(self, filename, paths, verbose=None): def _find_file_key(self, filename, paths, verbose=None):
return (filename, paths) return (filename, paths)
@SCons.Memoize.CountDictCall(_find_file_key) @SCons.Memoize.CountDictCall(_find_file_key)
def find_file(self, filename, paths, verbose=None): def find_file(self, filename, paths, verbose=None):
""" """
find_file(str, [Dir()]) -> [nodes] Find a node corresponding to either a derived file or a file that exists already.
filename - a filename to find Only the first file found is returned, and none is returned if no file is found.
paths - a list of directory path *nodes* to search in. Can be
represented as a list, a tuple, or a callable that is
called with no arguments and returns the list or tuple.
returns - the node created from the found file. filename: A filename to find
paths: A list of directory path *nodes* to search in. Can be represented as a list, a tuple, or a callable that is called with no arguments and returns the list or tuple.
Find a node corresponding to either a derived file or a file returns The node created from the found file.
that exists already.
Only the first file found is returned, and none is returned
if no file is found.
""" """
memo_key = self._find_file_key(filename, paths) memo_key = self._find_file_key(filename, paths)
try: try:
@ -3547,7 +3524,7 @@ def invalidate_node_memos(targets):
if not SCons.Util.is_List(targets): if not SCons.Util.is_List(targets):
targets = [targets] targets = [targets]
for entry in targets: for entry in targets:
# If the target is a Node object, clear the cache. If it is a # If the target is a Node object, clear the cache. If it is a
# filename, look up potentially existing Node object first. # filename, look up potentially existing Node object first.
@ -3559,7 +3536,7 @@ def invalidate_node_memos(targets):
# do not correspond to an existing Node object. # do not correspond to an existing Node object.
node = get_default_fs().Entry(entry) node = get_default_fs().Entry(entry)
if node: if node:
node.clear_memoized_values() node.clear_memoized_values()
# Local Variables: # Local Variables:
# tab-width:4 # tab-width:4

View file

@ -5,7 +5,7 @@ Python nodes.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,7 +27,7 @@ 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__ = "src/engine/SCons/Node/Python.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Node/Python.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Node import SCons.Node
@ -58,7 +58,7 @@ class ValueNodeInfo(SCons.Node.NodeInfoBase):
del state['__weakref__'] del state['__weakref__']
except KeyError: except KeyError:
pass pass
return state return state
def __setstate__(self, state): def __setstate__(self, state):
@ -77,7 +77,7 @@ class ValueBuildInfo(SCons.Node.BuildInfoBase):
current_version_id = 2 current_version_id = 2
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
or generated by a script, but not from a file or some other source. or generated by a script, but not from a file or some other source.
""" """
@ -108,7 +108,7 @@ class Value(SCons.Node.Node):
is_up_to_date = 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
# what directory scons was run from. Value nodes # what directory scons was run from. Value nodes
# are outside the filesystem: # are outside the filesystem:
return 1 return 1
@ -133,10 +133,17 @@ class Value(SCons.Node.Node):
###TODO: something reasonable about universal newlines ###TODO: something reasonable about universal newlines
contents = str(self.value) contents = str(self.value)
for kid in self.children(None): for kid in self.children(None):
contents = contents + kid.get_contents() contents = contents + kid.get_contents().decode()
return contents return contents
get_contents = get_text_contents ###TODO should return 'bytes' value def get_contents(self):
text_contents = self.get_text_contents()
try:
return text_contents.encode()
except UnicodeDecodeError:
# Already encoded as python2 str are bytes
return text_contents
def changed_since_last_build(self, target, prev_ni): def changed_since_last_build(self, target, prev_ni):
cur_csig = self.get_csig() cur_csig = self.get_csig()

View file

@ -19,8 +19,10 @@ be able to depend on any other type of "thing."
""" """
from __future__ import print_function
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -41,7 +43,7 @@ be able to depend on any other type of "thing."
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Node/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Node/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import collections import collections
import copy import copy
@ -55,6 +57,8 @@ import SCons.Util
from SCons.Debug import Trace from SCons.Debug import Trace
from SCons.compat import with_metaclass, NoSlotsPyPy
print_duplicate = 0 print_duplicate = 0
def classname(obj): def classname(obj):
@ -151,7 +155,7 @@ def exists_file(node):
# The source file does not exist. Make sure no old # The source file does not exist. Make sure no old
# copy remains in the variant directory. # copy remains in the variant directory.
if print_duplicate: if print_duplicate:
print "dup: no src for %s, unlinking old variant copy"%self print("dup: no src for %s, unlinking old variant copy"%self)
if exists_base(node) or node.islink(): if exists_base(node) or node.islink():
node.fs.unlink(node.get_internal_path()) node.fs.unlink(node.get_internal_path())
# Return None explicitly because the Base.exists() call # Return None explicitly because the Base.exists() call
@ -205,13 +209,14 @@ def get_contents_dir(node):
contents.append('%s %s\n' % (n.get_csig(), n.name)) contents.append('%s %s\n' % (n.get_csig(), n.name))
return ''.join(contents) return ''.join(contents)
def get_contents_file(node): def get_contents_file(node):
if not node.rexists(): if not node.rexists():
return '' return b''
fname = node.rfile().get_abspath() fname = node.rfile().get_abspath()
try: try:
contents = open(fname, "rb").read() with open(fname, "rb") as fp:
except EnvironmentError, e: contents = fp.read()
except EnvironmentError as e:
if not e.filename: if not e.filename:
e.filename = fname e.filename = fname
raise raise
@ -345,6 +350,7 @@ class NodeInfoBase(object):
""" """
__slots__ = ('__weakref__',) __slots__ = ('__weakref__',)
current_version_id = 2 current_version_id = 2
def update(self, node): def update(self, node):
try: try:
field_list = self.field_list field_list = self.field_list
@ -361,8 +367,10 @@ class NodeInfoBase(object):
pass pass
else: else:
setattr(self, f, func()) setattr(self, f, func())
def convert(self, node, val): def convert(self, node, val):
pass pass
def merge(self, other): def merge(self, other):
""" """
Merge the fields of another object into this object. Already existing Merge the fields of another object into this object. Already existing
@ -377,7 +385,7 @@ class NodeInfoBase(object):
try: try:
field_list = self.field_list field_list = self.field_list
except AttributeError: except AttributeError:
field_list = getattr(self, '__dict__', {}).keys() field_list = list(getattr(self, '__dict__', {}).keys())
for obj in type(self).mro(): for obj in type(self).mro():
for slot in getattr(obj, '__slots__', ()): for slot in getattr(obj, '__slots__', ()):
if slot not in ('__weakref__', '__dict__'): if slot not in ('__weakref__', '__dict__'):
@ -407,21 +415,21 @@ class NodeInfoBase(object):
for name in getattr(obj,'__slots__',()): for name in getattr(obj,'__slots__',()):
if hasattr(self, name): if hasattr(self, name):
state[name] = getattr(self, name) state[name] = getattr(self, name)
state['_version_id'] = self.current_version_id state['_version_id'] = self.current_version_id
try: try:
del state['__weakref__'] del state['__weakref__']
except KeyError: except KeyError:
pass pass
return state return state
def __setstate__(self, state): def __setstate__(self, state):
""" """
Restore the attributes from a pickled state. The version is discarded. Restore the attributes from a pickled state. The version is discarded.
""" """
# TODO check or discard version # TODO check or discard version
del state['_version_id'] del state['_version_id']
for key, value in state.items(): for key, value in state.items():
if key not in ('__weakref__',): if key not in ('__weakref__',):
setattr(self, key, value) setattr(self, key, value)
@ -440,6 +448,7 @@ class BuildInfoBase(object):
__slots__ = ("bsourcesigs", "bdependsigs", "bimplicitsigs", "bactsig", __slots__ = ("bsourcesigs", "bdependsigs", "bimplicitsigs", "bactsig",
"bsources", "bdepends", "bact", "bimplicit", "__weakref__") "bsources", "bdepends", "bact", "bimplicit", "__weakref__")
current_version_id = 2 current_version_id = 2
def __init__(self): def __init__(self):
# Create an object attribute from the class attribute so it ends up # Create an object attribute from the class attribute so it ends up
# in the pickled data in the .sconsign file. # in the pickled data in the .sconsign file.
@ -447,6 +456,7 @@ class BuildInfoBase(object):
self.bdependsigs = [] self.bdependsigs = []
self.bimplicitsigs = [] self.bimplicitsigs = []
self.bactsig = None self.bactsig = None
def merge(self, other): def merge(self, other):
""" """
Merge the fields of another object into this object. Already existing Merge the fields of another object into this object. Already existing
@ -456,7 +466,7 @@ class BuildInfoBase(object):
""" """
state = other.__getstate__() state = other.__getstate__()
self.__setstate__(state) self.__setstate__(state)
def __getstate__(self): def __getstate__(self):
""" """
Return all fields that shall be pickled. Walk the slots in the class Return all fields that shall be pickled. Walk the slots in the class
@ -487,7 +497,8 @@ class BuildInfoBase(object):
if key not in ('__weakref__',): if key not in ('__weakref__',):
setattr(self, key, value) setattr(self, key, value)
class Node(object):
class Node(object, with_metaclass(NoSlotsPyPy)):
"""The base Node class, for entities that we know how to """The base Node class, for entities that we know how to
build, or use to build other Nodes. build, or use to build other Nodes.
""" """
@ -536,7 +547,7 @@ class Node(object):
class Attrs(object): class Attrs(object):
__slots__ = ('shared', '__dict__') __slots__ = ('shared', '__dict__')
def __init__(self): def __init__(self):
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.Node') if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.Node')
@ -588,7 +599,7 @@ class Node(object):
self._func_rexists = 1 self._func_rexists = 1
self._func_get_contents = 0 self._func_get_contents = 0
self._func_target_from_source = 0 self._func_target_from_source = 0
self.clear_memoized_values() self.clear_memoized_values()
# Let the interface in which the build engine is embedded # Let the interface in which the build engine is embedded
@ -737,7 +748,7 @@ class Node(object):
""" """
try: try:
self.get_executor()(self, **kw) self.get_executor()(self, **kw)
except SCons.Errors.BuildError, e: except SCons.Errors.BuildError as e:
e.node = self e.node = self
raise raise
@ -776,16 +787,16 @@ class Node(object):
def release_target_info(self): def release_target_info(self):
"""Called just after this node has been marked """Called just after this node has been marked
up-to-date or was built completely. up-to-date or was built completely.
This is where we try to release as many target node infos This is where we try to release as many target node infos
as possible for clean builds and update runs, in order as possible for clean builds and update runs, in order
to minimize the overall memory consumption. to minimize the overall memory consumption.
By purging attributes that aren't needed any longer after By purging attributes that aren't needed any longer after
a Node (=File) got built, we don't have to care that much how a Node (=File) got built, we don't have to care that much how
many KBytes a Node actually requires...as long as we free many KBytes a Node actually requires...as long as we free
the memory shortly afterwards. the memory shortly afterwards.
@see: built() and File.release_target_info() @see: built() and File.release_target_info()
""" """
pass pass
@ -965,9 +976,9 @@ class Node(object):
# no scanner could be found for the given node's scanner key; # no scanner could be found for the given node's scanner key;
# thus, make an attempt at using a default. # thus, make an attempt at using a default.
scanner = root_node_scanner scanner = root_node_scanner
return scanner return scanner
def get_env_scanner(self, env, kw={}): def get_env_scanner(self, env, kw={}):
return env.get_scanner(self.scanner_key()) return env.get_scanner(self.scanner_key())
@ -1125,38 +1136,22 @@ class Node(object):
binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
if self._specific_sources: if self._specific_sources:
sources = [] sources = [ s for s in self.sources if not s in ignore_set]
for s in self.sources:
if s not in ignore_set:
sources.append(s)
else: else:
sources = executor.get_unignored_sources(self, self.ignore) sources = executor.get_unignored_sources(self, self.ignore)
seen = set() seen = set()
bsources = [] binfo.bsources = [s for s in sources if s not in seen and not seen.add(s)]
bsourcesigs = [] binfo.bsourcesigs = [s.get_ninfo() for s in binfo.bsources]
for s in sources:
if not s in seen:
seen.add(s)
bsources.append(s)
bsourcesigs.append(s.get_ninfo())
binfo.bsources = bsources
binfo.bsourcesigs = bsourcesigs
depends = self.depends
dependsigs = []
for d in depends:
if d not in ignore_set:
dependsigs.append(d.get_ninfo())
binfo.bdepends = depends
binfo.bdependsigs = dependsigs
implicit = self.implicit or [] binfo.bdepends = self.depends
implicitsigs = [] binfo.bdependsigs = [d.get_ninfo() for d in self.depends if d not in ignore_set]
for i in implicit:
if i not in ignore_set: binfo.bimplicit = self.implicit or []
implicitsigs.append(i.get_ninfo()) binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit if i not in ignore_set]
binfo.bimplicit = implicit
binfo.bimplicitsigs = implicitsigs
return binfo return binfo
@ -1239,7 +1234,7 @@ class Node(object):
"""Adds dependencies.""" """Adds dependencies."""
try: try:
self._add_child(self.depends, self.depends_set, depend) self._add_child(self.depends, self.depends_set, depend)
except TypeError, e: except TypeError as e:
e = e.args[0] e = e.args[0]
if SCons.Util.is_List(e): if SCons.Util.is_List(e):
s = list(map(str, e)) s = list(map(str, e))
@ -1258,7 +1253,7 @@ class Node(object):
"""Adds dependencies to ignore.""" """Adds dependencies to ignore."""
try: try:
self._add_child(self.ignore, self.ignore_set, depend) self._add_child(self.ignore, self.ignore_set, depend)
except TypeError, e: except TypeError as e:
e = e.args[0] e = e.args[0]
if SCons.Util.is_List(e): if SCons.Util.is_List(e):
s = list(map(str, e)) s = list(map(str, e))
@ -1272,7 +1267,7 @@ class Node(object):
return return
try: try:
self._add_child(self.sources, self.sources_set, source) self._add_child(self.sources, self.sources_set, source)
except TypeError, e: except TypeError as e:
e = e.args[0] e = e.args[0]
if SCons.Util.is_List(e): if SCons.Util.is_List(e):
s = list(map(str, e)) s = list(map(str, e))
@ -1332,7 +1327,7 @@ class Node(object):
# dictionary patterns I found all ended up using "not in" # dictionary patterns I found all ended up using "not in"
# internally anyway...) # internally anyway...)
if self.ignore_set: if self.ignore_set:
iter = chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])) iter = chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f])
children = [] children = []
for i in iter: for i in iter:
@ -1366,7 +1361,7 @@ class Node(object):
# using dictionary keys, lose the order, and the only ordered # using dictionary keys, lose the order, and the only ordered
# dictionary patterns I found all ended up using "not in" # dictionary patterns I found all ended up using "not in"
# internally anyway...) # internally anyway...)
return list(chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit]))) return list(chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f]))
def children(self, scan=1): def children(self, scan=1):
"""Return a list of the node's direct children, minus those """Return a list of the node's direct children, minus those
@ -1390,7 +1385,7 @@ class Node(object):
def Decider(self, function): def Decider(self, function):
foundkey = None foundkey = None
for k, v in _decider_map.iteritems(): for k, v in _decider_map.items():
if v == function: if v == function:
foundkey = k foundkey = k
break break
@ -1424,14 +1419,14 @@ class Node(object):
any difference, but we now rely on checking every dependency any difference, but we now rely on checking every dependency
to make sure that any necessary Node information (for example, to make sure that any necessary Node information (for example,
the content signature of an #included .h file) is updated. the content signature of an #included .h file) is updated.
The allowcache option was added for supporting the early The allowcache option was added for supporting the early
release of the executor/builder structures, right after release of the executor/builder structures, right after
a File target was built. When set to true, the return a File target was built. When set to true, the return
value of this changed method gets cached for File nodes. value of this changed method gets cached for File nodes.
Like this, the executor isn't needed any longer for subsequent Like this, the executor isn't needed any longer for subsequent
calls to changed(). calls to changed().
@see: FS.File.changed(), FS.File.release_target_info() @see: FS.File.changed(), FS.File.release_target_info()
""" """
t = 0 t = 0
@ -1603,8 +1598,8 @@ class Node(object):
new_bkids = new.bsources + new.bdepends + new.bimplicit new_bkids = new.bsources + new.bdepends + new.bimplicit
new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
osig = dict(zip(old_bkids, old_bkidsigs)) osig = dict(list(zip(old_bkids, old_bkidsigs)))
nsig = dict(zip(new_bkids, new_bkidsigs)) nsig = dict(list(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
@ -1645,6 +1640,9 @@ class Node(object):
if old.bact == new.bact: if old.bact == new.bact:
lines.append("the contents of the build action changed\n" + lines.append("the contents of the build action changed\n" +
fmt_with_title('action: ', new.bact)) fmt_with_title('action: ', new.bact))
# lines.append("the contents of the build action changed [%s] [%s]\n"%(old.bactsig,new.bactsig) +
# fmt_with_title('action: ', new.bact))
else: else:
lines.append("the build action changed:\n" + lines.append("the build action changed:\n" +
fmt_with_title('old: ', old.bact) + fmt_with_title('old: ', old.bact) +

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/BoolOption.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/BoolOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/EnumOption.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/EnumOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/ListOption.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/ListOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/PackageOption.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/PackageOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/PathOption.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/PathOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Options/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Options/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Place-holder for the old SCons.Options module hierarchy __doc__ = """Place-holder for the old SCons.Options module hierarchy
@ -33,11 +33,11 @@ and will then be removed entirely (some day).
import SCons.Variables import SCons.Variables
import SCons.Warnings import SCons.Warnings
from BoolOption import BoolOption # okay from .BoolOption import BoolOption # okay
from EnumOption import EnumOption # okay from .EnumOption import EnumOption # okay
from ListOption import ListOption # naja from .ListOption import ListOption # naja
from PackageOption import PackageOption # naja from .PackageOption import PackageOption # naja
from PathOption import PathOption # okay from .PathOption import PathOption # okay
warned = False warned = False

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/PathList.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/PathList.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """SCons.PathList __doc__ = """SCons.PathList
@ -104,11 +104,11 @@ class _PathList(object):
pl = [] pl = []
for p in pathlist: for p in pathlist:
try: try:
index = p.find('$') found = '$' in p
except (AttributeError, TypeError): except (AttributeError, TypeError):
type = TYPE_OBJECT type = TYPE_OBJECT
else: else:
if index == -1: if not found:
type = TYPE_STRING_NO_SUBST type = TYPE_STRING_NO_SUBST
else: else:
type = TYPE_STRING_SUBST type = TYPE_STRING_SUBST

View file

@ -20,8 +20,8 @@ their own platform definition.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -41,8 +41,9 @@ their own platform definition.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
from __future__ import print_function
__revision__ = "src/engine/SCons/Platform/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.compat import SCons.compat
@ -55,6 +56,7 @@ import SCons.Errors
import SCons.Subst import SCons.Subst
import SCons.Tool import SCons.Tool
def platform_default(): def platform_default():
"""Return the platform string for our execution environment. """Return the platform string for our execution environment.
@ -130,7 +132,7 @@ class PlatformSpec(object):
def __str__(self): def __str__(self):
return self.name return self.name
class TempFileMunge(object): class TempFileMunge(object):
"""A callable class. You can set an Environment variable to this, """A callable class. You can set an Environment variable to this,
then call it with a string argument, then it will perform temporary then call it with a string argument, then it will perform temporary
@ -183,9 +185,9 @@ class TempFileMunge(object):
node = target[0] if SCons.Util.is_List(target) else target node = target[0] if SCons.Util.is_List(target) else target
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \ cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
if node is not None else None if node is not None else None
if cmdlist is not None : if cmdlist is not None :
return cmdlist return cmdlist
# We do a normpath because mktemp() has what appears to be # We do a normpath because mktemp() has what appears to be
# a bug in Windows that will use a forward slash as a path # a bug in Windows that will use a forward slash as a path
# delimiter. Windows's link mistakes that for a command line # delimiter. Windows's link mistakes that for a command line
@ -215,7 +217,7 @@ class TempFileMunge(object):
prefix = '@' prefix = '@'
args = list(map(SCons.Subst.quote_spaces, cmd[1:])) args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
os.write(fd, " ".join(args) + "\n") os.write(fd, bytearray(" ".join(args) + "\n",'utf-8'))
os.close(fd) os.close(fd)
# XXX Using the SCons.Action.print_actions value directly # XXX Using the SCons.Action.print_actions value directly
# like this is bogus, but expedient. This class should # like this is bogus, but expedient. This class should
@ -233,14 +235,14 @@ class TempFileMunge(object):
# purity get in the way of just being helpful, so we'll # purity get in the way of just being helpful, so we'll
# reach into SCons.Action directly. # reach into SCons.Action directly.
if SCons.Action.print_actions: if SCons.Action.print_actions:
cmdstr = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target, cmdstr = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target,
source) if self.cmdstr is not None else '' source) if self.cmdstr is not None else ''
# Print our message only if XXXCOMSTR returns an empty string # Print our message only if XXXCOMSTR returns an empty string
if len(cmdstr) == 0 : if len(cmdstr) == 0 :
print("Using tempfile "+native_tmp+" for command line:\n"+ print("Using tempfile "+native_tmp+" for command line:\n"+
str(cmd[0]) + " " + " ".join(args)) str(cmd[0]) + " " + " ".join(args))
# Store the temporary file command list into the target Node.attributes # Store the temporary file command list into the target Node.attributes
# to avoid creating two temporary files one for print and one for execute. # to avoid creating two temporary files one for print and one for execute.
cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
if node is not None: if node is not None:
@ -249,7 +251,8 @@ class TempFileMunge(object):
except AttributeError: except AttributeError:
pass pass
return cmdlist return cmdlist
def Platform(name = platform_default()): def Platform(name = platform_default()):
"""Select a canned Platform specification. """Select a canned Platform specification.
""" """

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,12 +30,12 @@ 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__ = "src/engine/SCons/Platform/aix.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/aix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import subprocess import subprocess
import posix from . import posix
import SCons.Util import SCons.Util
import SCons.Action import SCons.Action

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +30,9 @@ 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__ = "src/engine/SCons/Platform/cygwin.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/cygwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import posix from . import posix
from SCons.Platform import TempFileMunge from SCons.Platform import TempFileMunge
def generate(env): def generate(env):

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +30,9 @@ 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__ = "src/engine/SCons/Platform/darwin.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/darwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import posix from . import posix
import os import os
def generate(env): def generate(env):
@ -63,6 +63,10 @@ def generate(env):
env.AppendENVPath('PATHOSX', line.strip('\n')) env.AppendENVPath('PATHOSX', line.strip('\n'))
f.close() f.close()
# Not sure why this wasn't the case all along?
if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
env.AppendENVPath('PATH',env['ENV']['PATHOSX'])
# Local Variables: # Local Variables:
# tab-width:4 # tab-width:4
# indent-tabs-mode:nil # indent-tabs-mode:nil

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +30,9 @@ 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__ = "src/engine/SCons/Platform/hpux.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/hpux.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import posix from . import posix
def generate(env): def generate(env):
posix.generate(env) posix.generate(env)

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +30,9 @@ 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__ = "src/engine/SCons/Platform/irix.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/irix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import posix from . import posix
def generate(env): def generate(env):
posix.generate(env) posix.generate(env)

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,8 +30,8 @@ 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__ = "src/engine/SCons/Platform/os2.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/os2.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import win32 from . import win32
def generate(env): def generate(env):
if 'ENV' not in env: if 'ENV' not in env:

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Platform/posix.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/posix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import errno import errno
import os import os
@ -56,7 +56,7 @@ def escape(arg):
for c in special: for c in special:
arg = arg.replace(c, slash+c) arg = arg.replace(c, slash+c)
# print "ESCAPE RESULT: %s"%arg # print("ESCAPE RESULT: %s" % arg)
return '"' + arg + '"' return '"' + arg + '"'

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +30,9 @@ 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__ = "src/engine/SCons/Platform/sunos.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/sunos.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import posix from . import posix
def generate(env): def generate(env):
posix.generate(env) posix.generate(env)

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Platform/win32.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Platform/win32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import os.path import os.path
@ -60,15 +60,8 @@ except AttributeError:
else: else:
parallel_msg = None parallel_msg = None
_builtin_file = file
_builtin_open = open _builtin_open = open
class _scons_file(_builtin_file):
def __init__(self, *args, **kw):
_builtin_file.__init__(self, *args, **kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()),
win32con.HANDLE_FLAG_INHERIT, 0)
def _scons_open(*args, **kw): def _scons_open(*args, **kw):
fp = _builtin_open(*args, **kw) fp = _builtin_open(*args, **kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
@ -76,13 +69,64 @@ else:
0) 0)
return fp return fp
file = _scons_file
open = _scons_open open = _scons_open
if sys.version_info.major == 2:
_builtin_file = file
class _scons_file(_builtin_file):
def __init__(self, *args, **kw):
_builtin_file.__init__(self, *args, **kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()),
win32con.HANDLE_FLAG_INHERIT, 0)
file = _scons_file
else:
import io
for io_class in ['BufferedReader', 'BufferedWriter', 'BufferedRWPair',
'BufferedRandom', 'TextIOWrapper']:
_builtin_file = getattr(io, io_class)
class _scons_file(_builtin_file):
def __init__(self, *args, **kw):
_builtin_file.__init__(self, *args, **kw)
win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()),
win32con.HANDLE_FLAG_INHERIT, 0)
setattr(io, io_class, _scons_file)
if False:
# Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile
try:
from ctypes import windll
import shutil
CopyFile = windll.kernel32.CopyFileA
SetFileTime = windll.kernel32.SetFileTime
_shutil_copy = shutil.copy
_shutil_copy2 = shutil.copy2
shutil.copy2 = CopyFile
def win_api_copyfile(src,dst):
CopyFile(src,dst)
os.utime(dst)
shutil.copy = win_api_copyfile
except AttributeError:
parallel_msg = \
"Couldn't override shutil.copy or shutil.copy2 falling back to shutil defaults"
try: try:
import threading import threading
spawn_lock = threading.Lock() spawn_lock = threading.Lock()
# This locked version of spawnve works around a Windows # This locked version of spawnve works around a Windows
# MSVCRT bug, because its spawnve is not thread-safe. # MSVCRT bug, because its spawnve is not thread-safe.
# Without this, python can randomly crash while using -jN. # Without this, python can randomly crash while using -jN.
@ -111,11 +155,12 @@ except ImportError:
# simulating a non-existent package. # simulating a non-existent package.
def spawnve(mode, file, args, env): def spawnve(mode, file, args, env):
return os.spawnve(mode, file, args, env) return os.spawnve(mode, file, args, env)
# 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.
def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
# There is no direct way to do that in python. What we do # There is no direct way to do that in python. What we do
# here should work for most cases: # here should work for most cases:
@ -136,8 +181,7 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
stderrRedirected = 0 stderrRedirected = 0
for arg in args: for arg in args:
# are there more possibilities to redirect stdout ? # are there more possibilities to redirect stdout ?
if (arg.find( ">", 0, 1 ) != -1 or if arg.find( ">", 0, 1 ) != -1 or arg.find( "1>", 0, 2 ) != -1:
arg.find( "1>", 0, 2 ) != -1):
stdoutRedirected = 1 stdoutRedirected = 1
# are there more possibilities to redirect stderr ? # are there more possibilities to redirect stderr ?
if arg.find( "2>", 0, 2 ) != -1: if arg.find( "2>", 0, 2 ) != -1:
@ -153,7 +197,7 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
try: try:
args = [sh, '/C', escape(' '.join(args)) ] args = [sh, '/C', escape(' '.join(args)) ]
ret = spawnve(os.P_WAIT, sh, args, env) ret = spawnve(os.P_WAIT, sh, args, env)
except OSError, e: except OSError as e:
# catch any error # catch any error
try: try:
ret = exitvalmap[e[0]] ret = exitvalmap[e[0]]
@ -178,13 +222,14 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
pass pass
return ret return ret
def exec_spawn(l, env): def exec_spawn(l, env):
try: try:
result = spawnve(os.P_WAIT, l[0], l, env) result = spawnve(os.P_WAIT, l[0], l, env)
except OSError, e: except (OSError, EnvironmentError) as e:
try: try:
result = exitvalmap[e[0]] result = exitvalmap[e.errno]
sys.stderr.write("scons: %s: %s\n" % (l[0], e[1])) sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror))
except KeyError: except KeyError:
result = 127 result = 127
if len(l) > 2: if len(l) > 2:
@ -194,9 +239,10 @@ def exec_spawn(l, env):
command = l[0] command = l[0]
else: else:
command = l[0] command = l[0]
sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e[0], command, e[1])) sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror))
return result return result
def spawn(sh, escape, cmd, args, env): def spawn(sh, escape, cmd, args, env):
if not sh: if not sh:
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
@ -216,6 +262,7 @@ def escape(x):
# Get the windows system directory name # Get the windows system directory name
_system_root = None _system_root = None
def get_system_root(): def get_system_root():
global _system_root global _system_root
if _system_root is not None: if _system_root is not None:
@ -240,11 +287,21 @@ def get_system_root():
raise raise
except: except:
pass pass
# Ensure system root is a string and not unicode
# (This only matters for py27 were unicode in env passed to POpen fails)
val = str(val)
_system_root = val _system_root = val
return val return val
# Get the location of the program files directory
def get_program_files_dir(): def get_program_files_dir():
"""
Get the location of the program files directory
Returns
-------
"""
# Now see if we can look in the registry... # Now see if we can look in the registry...
val = '' val = ''
if SCons.Util.can_read_reg: if SCons.Util.can_read_reg:
@ -261,14 +318,13 @@ def get_program_files_dir():
# A reasonable default if we can't read the registry # A reasonable default if we can't read the registry
# (Actually, it's pretty reasonable even if we can :-) # (Actually, it's pretty reasonable even if we can :-)
val = os.path.join(os.path.dirname(get_system_root()),"Program Files") val = os.path.join(os.path.dirname(get_system_root()),"Program Files")
return val return val
# Determine which windows CPU were running on.
class ArchDefinition(object): class ArchDefinition(object):
""" """
Determine which windows CPU were running on.
A class for defining architecture-specific settings and logic. A class for defining architecture-specific settings and logic.
""" """
def __init__(self, arch, synonyms=[]): def __init__(self, arch, synonyms=[]):
@ -298,6 +354,7 @@ for a in SupportedArchitectureList:
for s in a.synonyms: for s in a.synonyms:
SupportedArchitectureMap[s] = a SupportedArchitectureMap[s] = a
def get_architecture(arch=None): def get_architecture(arch=None):
"""Returns the definition for the specified architecture string. """Returns the definition for the specified architecture string.
@ -311,6 +368,7 @@ def get_architecture(arch=None):
arch = os.environ.get('PROCESSOR_ARCHITECTURE') arch = os.environ.get('PROCESSOR_ARCHITECTURE')
return SupportedArchitectureMap.get(arch, ArchDefinition('', [''])) return SupportedArchitectureMap.get(arch, ArchDefinition('', ['']))
def generate(env): def generate(env):
# Attempt to find cmd.exe (for WinNT/2k/XP) or # Attempt to find cmd.exe (for WinNT/2k/XP) or
# command.com for Win9x # command.com for Win9x
@ -346,7 +404,7 @@ def generate(env):
os.path.join(systemroot,'System32') os.path.join(systemroot,'System32')
tmp_pathext = '.com;.exe;.bat;.cmd' tmp_pathext = '.com;.exe;.bat;.cmd'
if 'PATHEXT' in os.environ: if 'PATHEXT' in os.environ:
tmp_pathext = os.environ['PATHEXT'] tmp_pathext = os.environ['PATHEXT']
cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext) cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
if not cmd_interp: if not cmd_interp:
cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext) cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
@ -356,7 +414,6 @@ def generate(env):
if not cmd_interp: if not cmd_interp:
cmd_interp = env.Detect('command') cmd_interp = env.Detect('command')
if 'ENV' not in env: if 'ENV' not in env:
env['ENV'] = {} env['ENV'] = {}
@ -368,7 +425,7 @@ def generate(env):
# for SystemDrive because it's related. # for SystemDrive because it's related.
# #
# Weigh the impact carefully before adding other variables to this list. # Weigh the impact carefully before adding other variables to this list.
import_env = [ 'SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ] import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ]
for var in import_env: for var in import_env:
v = os.environ.get(var) v = os.environ.get(var)
if v: if v:
@ -401,10 +458,10 @@ def generate(env):
env['TEMPFILEPREFIX'] = '@' env['TEMPFILEPREFIX'] = '@'
env['MAXLINELENGTH'] = 2048 env['MAXLINELENGTH'] = 2048
env['ESCAPE'] = escape env['ESCAPE'] = escape
env['HOST_OS'] = 'win32' env['HOST_OS'] = 'win32'
env['HOST_ARCH'] = get_architecture().arch env['HOST_ARCH'] = get_architecture().arch
# Local Variables: # Local Variables:
# tab-width:4 # tab-width:4

View file

@ -12,7 +12,7 @@ libraries are installed, if some command line options are supported etc.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -33,8 +33,9 @@ libraries are installed, if some command line options are supported etc.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
from __future__ import print_function
__revision__ = "src/engine/SCons/SConf.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/SConf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.compat import SCons.compat
@ -109,7 +110,7 @@ def _createConfigH(target, source, env):
#define %(DEFNAME)s_SEEN #define %(DEFNAME)s_SEEN
""" % {'DEFNAME' : defname}) """ % {'DEFNAME' : defname})
t.write(source[0].get_contents()) t.write(source[0].get_contents().decode())
t.write(""" t.write("""
#endif /* %(DEFNAME)s_SEEN */ #endif /* %(DEFNAME)s_SEEN */
""" % {'DEFNAME' : defname}) """ % {'DEFNAME' : defname})
@ -131,10 +132,10 @@ def CreateConfigHBuilder(env):
_stringConfigH) _stringConfigH)
sconfigHBld = SCons.Builder.Builder(action=action) sconfigHBld = SCons.Builder.Builder(action=action)
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} ) env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
for k in _ac_config_hs.keys(): for k in list(_ac_config_hs.keys()):
env.SConfigHBuilder(k, env.Value(_ac_config_hs[k])) env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
class SConfWarning(SCons.Warnings.Warning): class SConfWarning(SCons.Warnings.Warning):
pass pass
SCons.Warnings.enableWarningClass(SConfWarning) SCons.Warnings.enableWarningClass(SConfWarning)
@ -163,11 +164,11 @@ class ConfigureCacheError(SConfError):
# define actions for building text files # define actions for building text files
def _createSource( target, source, env ): def _createSource( target, source, env ):
fd = open(str(target[0]), "w") fd = open(str(target[0]), "w")
fd.write(source[0].get_contents()) fd.write(source[0].get_contents().decode())
fd.close() fd.close()
def _stringSource( target, source, env ): def _stringSource( target, source, env ):
return (str(target[0]) + ' <-\n |' + return (str(target[0]) + ' <-\n |' +
source[0].get_contents().replace( '\n', "\n |" ) ) source[0].get_contents().decode().replace( '\n', "\n |" ) )
class SConfBuildInfo(SCons.Node.FS.FileBuildInfo): class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
""" """
@ -176,7 +177,7 @@ class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
contains messages of the original build phase. contains messages of the original build phase.
""" """
__slots__ = ('result', 'string') __slots__ = ('result', 'string')
def __init__(self): def __init__(self):
self.result = None # -> 0/None -> no error, != 0 error self.result = None # -> 0/None -> no error, != 0 error
self.string = None # the stdout / stderr output when building the target self.string = None # the stdout / stderr output when building the target
@ -217,7 +218,7 @@ class Streamer(object):
if self.orig: if self.orig:
self.orig.flush() self.orig.flush()
self.s.flush() self.s.flush()
class SConfBuildTask(SCons.Taskmaster.AlwaysTask): class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
""" """
@ -311,7 +312,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
binfo = self.targets[0].get_stored_info().binfo binfo = self.targets[0].get_stored_info().binfo
self.display_cached_string(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]))
binfo = self.targets[0].get_stored_info().binfo binfo = self.targets[0].get_stored_info().binfo
self.display_cached_string(binfo) self.display_cached_string(binfo)
@ -332,7 +333,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
env_decider=env.decide_source): env_decider=env.decide_source):
env_decider(dependency, target, prev_ni) env_decider(dependency, target, prev_ni)
return True return True
if env.decide_source.func_code is not force_build.func_code: if env.decide_source.__code__ is not force_build.__code__:
env.Decider(force_build) env.Decider(force_build)
env['PSTDOUT'] = env['PSTDERR'] = s env['PSTDOUT'] = env['PSTDERR'] = s
try: try:
@ -346,7 +347,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
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 Exception, e: except Exception as e:
for t in self.targets: for t in self.targets:
binfo = SConfBuildInfo() binfo = SConfBuildInfo()
binfo.merge(t.get_binfo()) binfo.merge(t.get_binfo())
@ -396,7 +397,7 @@ class SConfBase(object):
""" """
def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR', def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR',
log_file='$CONFIGURELOG', config_h = None, _depth = 0): log_file='$CONFIGURELOG', config_h = None, _depth = 0):
"""Constructor. Pass additional tests in the custom_tests-dictionary, """Constructor. Pass additional tests in the custom_tests-dictionary,
e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
defines a custom test. defines a custom test.
@ -457,10 +458,10 @@ class SConfBase(object):
If value is None (default), then #define name is written. If value is not If value is None (default), then #define name is written. If value is not
none, then #define name value is written. none, then #define name value is written.
comment is a string which will be put as a C comment in the comment is a string which will be put as a C comment in the header, to explain the meaning of the value
header, to explain the meaning of the value (appropriate C comments /* and (appropriate C comments will be added automatically).
*/ will be put automatically.""" """
lines = [] lines = []
if comment: if comment:
comment_str = "/* %s */" % comment comment_str = "/* %s */" % comment
@ -608,7 +609,7 @@ class SConfBase(object):
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension) ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
del self.env['BUILDERS']['SConfActionBuilder'] del self.env['BUILDERS']['SConfActionBuilder']
if ok: if ok:
outputStr = self.lastTarget.get_contents() outputStr = self.lastTarget.get_contents().decode()
return (1, outputStr) return (1, outputStr)
return (0, "") return (0, "")
@ -642,7 +643,7 @@ class SConfBase(object):
node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ]) node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ])
ok = self.BuildNodes(node) ok = self.BuildNodes(node)
if ok: if ok:
outputStr = output.get_contents() outputStr = SCons.Util.to_str(output.get_contents())
return( 1, outputStr) return( 1, outputStr)
return (0, "") return (0, "")
@ -670,7 +671,7 @@ class SConfBase(object):
"""Adds all the tests given in the tests dictionary to this SConf """Adds all the tests given in the tests dictionary to this SConf
instance instance
""" """
for name in tests.keys(): for name in list(tests.keys()):
self.AddTest(name, tests[name]) self.AddTest(name, tests[name])
def _createDir( self, node ): def _createDir( self, node ):
@ -689,7 +690,7 @@ class SConfBase(object):
global _ac_config_logs global _ac_config_logs
global sconf_global global sconf_global
global SConfFS global SConfFS
self.lastEnvFs = self.env.fs self.lastEnvFs = self.env.fs
self.env.fs = SConfFS self.env.fs = SConfFS
self._createDir(self.confdir) self._createDir(self.confdir)
@ -716,7 +717,7 @@ class SConfBase(object):
self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' % self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' %
(tb[0], tb[1], str(self.confdir)) ) (tb[0], tb[1], str(self.confdir)) )
SConfFS.chdir(old_fs_dir) SConfFS.chdir(old_fs_dir)
else: else:
self.logstream = None self.logstream = None
# we use a special builder to create source files from TEXT # we use a special builder to create source files from TEXT
action = SCons.Action.Action(_createSource, action = SCons.Action.Action(_createSource,
@ -913,14 +914,14 @@ def CheckType(context, type_name, includes = "", language = None):
def CheckTypeSize(context, type_name, includes = "", language = None, expect = None): def CheckTypeSize(context, type_name, includes = "", language = None, expect = None):
res = SCons.Conftest.CheckTypeSize(context, type_name, res = SCons.Conftest.CheckTypeSize(context, type_name,
header = includes, language = language, header = includes, language = language,
expect = expect) expect = expect)
context.did_show_result = 1 context.did_show_result = 1
return res return res
def CheckDeclaration(context, declaration, includes = "", language = None): def CheckDeclaration(context, declaration, includes = "", language = None):
res = SCons.Conftest.CheckDeclaration(context, declaration, res = SCons.Conftest.CheckDeclaration(context, declaration,
includes = includes, includes = includes,
language = language) language = language)
context.did_show_result = 1 context.did_show_result = 1
return not res return not res
@ -1004,7 +1005,7 @@ def CheckLib(context, library = None, symbol = "main",
if not SCons.Util.is_List(library): if not SCons.Util.is_List(library):
library = [library] library = [library]
# ToDo: accept path for the library # ToDo: accept path for the library
res = SCons.Conftest.CheckLib(context, library, symbol, header = header, res = SCons.Conftest.CheckLib(context, library, symbol, header = header,
language = language, autoadd = autoadd) language = language, autoadd = autoadd)

View file

@ -5,7 +5,7 @@ Writing and reading information to the .sconsign file or files.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,17 +27,21 @@ 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__ = "src/engine/SCons/SConsign.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" from __future__ import print_function
__revision__ = "src/engine/SCons/SConsign.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.compat import SCons.compat
import os import os
# compat layer imports "cPickle" for us if it's available.
import pickle import pickle
import SCons.dblite import SCons.dblite
import SCons.Warnings import SCons.Warnings
from SCons.compat import PICKLE_PROTOCOL
def corrupt_dblite_warning(filename): def corrupt_dblite_warning(filename):
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
"Ignoring corrupt .sconsign file: %s"%filename) "Ignoring corrupt .sconsign file: %s"%filename)
@ -45,7 +49,7 @@ def corrupt_dblite_warning(filename):
SCons.dblite.ignore_corrupt_dbfiles = 1 SCons.dblite.ignore_corrupt_dbfiles = 1
SCons.dblite.corruption_warning = corrupt_dblite_warning SCons.dblite.corruption_warning = corrupt_dblite_warning
#XXX Get rid of the global array so this becomes re-entrant. # XXX Get rid of the global array so this becomes re-entrant.
sig_files = [] sig_files = []
# Info for the database SConsign implementation (now the default): # Info for the database SConsign implementation (now the default):
@ -59,6 +63,7 @@ DB_Module = SCons.dblite
DB_Name = ".sconsign" DB_Name = ".sconsign"
DB_sync_list = [] DB_sync_list = []
def Get_DataBase(dir): def Get_DataBase(dir):
global DataBase, DB_Module, DB_Name global DataBase, DB_Module, DB_Name
top = dir.fs.Top top = dir.fs.Top
@ -84,9 +89,10 @@ def Get_DataBase(dir):
DB_sync_list.append(db) DB_sync_list.append(db)
return db, "c" return db, "c"
except TypeError: except TypeError:
print "DataBase =", DataBase print("DataBase =", DataBase)
raise raise
def Reset(): def Reset():
"""Reset global state. Used by unit tests that end up using """Reset global state. Used by unit tests that end up using
SConsign multiple times to get a clean slate for each test.""" SConsign multiple times to get a clean slate for each test."""
@ -96,6 +102,7 @@ def Reset():
normcase = os.path.normcase normcase = os.path.normcase
def write(): def write():
global sig_files global sig_files
for sig_file in sig_files: for sig_file in sig_files:
@ -114,6 +121,7 @@ def write():
else: else:
closemethod() closemethod()
class SConsignEntry(object): class SConsignEntry(object):
""" """
Wrapper class for the generic entry in a .sconsign file. Wrapper class for the generic entry in a .sconsign file.
@ -124,16 +132,16 @@ class SConsignEntry(object):
""" """
__slots__ = ("binfo", "ninfo", "__weakref__") __slots__ = ("binfo", "ninfo", "__weakref__")
current_version_id = 2 current_version_id = 2
def __init__(self): def __init__(self):
# Create an object attribute from the class attribute so it ends up # Create an object attribute from the class attribute so it ends up
# in the pickled data in the .sconsign file. # in the pickled data in the .sconsign file.
#_version_id = self.current_version_id #_version_id = self.current_version_id
pass pass
def convert_to_sconsign(self): def convert_to_sconsign(self):
self.binfo.convert_to_sconsign() self.binfo.convert_to_sconsign()
def convert_from_sconsign(self, dir, name): def convert_from_sconsign(self, dir, name):
self.binfo.convert_from_sconsign(dir, name) self.binfo.convert_from_sconsign(dir, name)
@ -155,7 +163,8 @@ class SConsignEntry(object):
for key, value in state.items(): for key, value in state.items():
if key not in ('_version_id','__weakref__'): if key not in ('_version_id','__weakref__'):
setattr(self, key, value) setattr(self, key, value)
class Base(object): class Base(object):
""" """
This is the controlling class for the signatures for the collection of This is the controlling class for the signatures for the collection of
@ -210,6 +219,7 @@ class Base(object):
self.entries[key] = entry self.entries[key] = entry
self.to_be_merged = {} 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
@ -239,7 +249,7 @@ class DB(Base):
raise TypeError raise TypeError
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Exception, e: except Exception as e:
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
"Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.get_tpath(), e)) "Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.get_tpath(), e))
for key, entry in self.entries.items(): for key, entry in self.entries.items():
@ -271,7 +281,7 @@ class DB(Base):
path = normcase(self.dir.get_internal_path()) path = normcase(self.dir.get_internal_path())
for key, entry in self.entries.items(): for key, entry in self.entries.items():
entry.convert_to_sconsign() entry.convert_to_sconsign()
db[path] = pickle.dumps(self.entries, 1) db[path] = pickle.dumps(self.entries, PICKLE_PROTOCOL)
if sync: if sync:
try: try:
@ -282,6 +292,7 @@ class DB(Base):
else: else:
syncmethod() syncmethod()
class Dir(Base): class Dir(Base):
def __init__(self, fp=None, dir=None): def __init__(self, fp=None, dir=None):
""" """
@ -301,6 +312,7 @@ class Dir(Base):
for key, entry in self.entries.items(): for key, entry in self.entries.items():
entry.convert_from_sconsign(dir, key) 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.
@ -359,12 +371,12 @@ class DirFile(Dir):
return return
for key, entry in self.entries.items(): for key, entry in self.entries.items():
entry.convert_to_sconsign() entry.convert_to_sconsign()
pickle.dump(self.entries, file, 1) pickle.dump(self.entries, file, PICKLE_PROTOCOL)
file.close() file.close()
if fname != self.sconsign: if fname != self.sconsign:
try: try:
mode = os.stat(self.sconsign)[0] mode = os.stat(self.sconsign)[0]
os.chmod(self.sconsign, 0666) os.chmod(self.sconsign, 0o666)
os.unlink(self.sconsign) os.unlink(self.sconsign)
except (IOError, OSError): except (IOError, OSError):
# Try to carry on in the face of either OSError # Try to carry on in the face of either OSError
@ -391,6 +403,7 @@ class DirFile(Dir):
ForDirectory = DB ForDirectory = DB
def File(name, dbm_module=None): def File(name, dbm_module=None):
""" """
Arrange for all signatures to be stored in a global .sconsign.db* Arrange for all signatures to be stored in a global .sconsign.db*

View file

@ -5,7 +5,7 @@ This module implements the dependency scanner for C/C++ code.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,7 +27,7 @@ This module implements the dependency 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__ = "src/engine/SCons/Scanner/C.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/C.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner
@ -58,12 +58,11 @@ class SConsCPPScanner(SCons.cpp.PreProcessor):
return result return result
def read_file(self, file): def read_file(self, file):
try: try:
fp = open(str(file.rfile())) with open(str(file.rfile())) as fp:
except EnvironmentError, e: return fp.read()
except EnvironmentError as e:
self.missing.append((file, self.current_file)) self.missing.append((file, self.current_file))
return '' return ''
else:
return fp.read()
def dictify_CPPDEFINES(env): def dictify_CPPDEFINES(env):
cppdefines = env.get('CPPDEFINES', {}) cppdefines = env.get('CPPDEFINES', {})

View file

@ -8,7 +8,7 @@ Coded by Andy Friesen
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,9 +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__ = "src/engine/SCons/Scanner/D.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/D.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import re
import SCons.Scanner import SCons.Scanner
@ -43,13 +41,13 @@ def DScanner():
class D(SCons.Scanner.Classic): class D(SCons.Scanner.Classic):
def __init__ (self): def __init__ (self):
SCons.Scanner.Classic.__init__ (self, SCons.Scanner.Classic.__init__ (
self,
name = "DScanner", name = "DScanner",
suffixes = '$DSUFFIXES', suffixes = '$DSUFFIXES',
path_variable = 'DPATH', path_variable = 'DPATH',
regex = 'import\s+(?:[a-zA-Z0-9_.]+)\s*(?:,\s*(?:[a-zA-Z0-9_.]+)\s*)*;') regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
)
self.cre2 = re.compile ('(?:import\s)?\s*([a-zA-Z0-9_.]+)\s*(?:,|;)', re.M)
def find_include(self, include, source_dir, path): def find_include(self, include, source_dir, path):
# translate dots (package separators) to slashes # translate dots (package separators) to slashes
@ -62,8 +60,10 @@ class D(SCons.Scanner.Classic):
def find_include_names(self, node): def find_include_names(self, node):
includes = [] includes = []
for i in self.cre.findall(node.get_text_contents()): for iii in self.cre.findall(node.get_text_contents()):
includes = includes + self.cre2.findall(i) for jjj in iii.split(','):
kkk = jjj.split('=')[-1]
includes.append(kkk.strip())
return includes return includes
# Local Variables: # Local Variables:

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -20,14 +20,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Scanner/Dir.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/Dir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner
def only_dirs(nodes): def only_dirs(nodes):
is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir) is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir)
return list(filter(is_Dir, nodes)) return [node for node in nodes if is_Dir(node)]
def DirScanner(**kw): def DirScanner(**kw):
"""Return a prototype Scanner instance for scanning """Return a prototype Scanner instance for scanning

View file

@ -5,7 +5,7 @@ This module implements the dependency scanner for Fortran code.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -26,7 +26,7 @@ This module implements the dependency scanner for Fortran code.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Scanner/Fortran.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/Fortran.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import re import re

View file

@ -6,7 +6,7 @@ Definition Language) files.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Scanner/IDL.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/IDL.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner

View file

@ -5,7 +5,7 @@ This module implements the dependency scanner for LaTeX code.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,7 +27,7 @@ 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__ = "src/engine/SCons/Scanner/LaTeX.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/LaTeX.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path
import re import re
@ -37,7 +37,9 @@ import SCons.Util
# list of graphics file extensions for TeX and LaTeX # list of graphics file extensions for TeX and LaTeX
TexGraphics = ['.eps', '.ps'] TexGraphics = ['.eps', '.ps']
LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] #LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif']
LatexGraphics = [ '.png', '.jpg', '.gif', '.tif']
# Used as a return value of modify_env_var if the variable is not set. # Used as a return value of modify_env_var if the variable is not set.
class _Null(object): class _Null(object):
@ -76,8 +78,10 @@ def modify_env_var(env, var, abspath):
return save return save
class FindENVPathDirs(object): class FindENVPathDirs(object):
"""A class to bind a specific *PATH variable name to a function that """
will return all of the *path directories.""" A class to bind a specific E{*}PATH variable name to a function that
will return all of the E{*}path directories.
"""
def __init__(self, variable): def __init__(self, variable):
self.variable = variable self.variable = variable
def __call__(self, env, dir=None, target=None, source=None, argument=None): def __call__(self, env, dir=None, target=None, source=None, argument=None):
@ -94,7 +98,8 @@ class FindENVPathDirs(object):
def LaTeXScanner(): def LaTeXScanner():
"""Return a prototype Scanner instance for scanning LaTeX source files """
Return a prototype Scanner instance for scanning LaTeX source files
when built with latex. when built with latex.
""" """
ds = LaTeX(name = "LaTeXScanner", ds = LaTeX(name = "LaTeXScanner",
@ -105,7 +110,8 @@ def LaTeXScanner():
return ds return ds
def PDFLaTeXScanner(): def PDFLaTeXScanner():
"""Return a prototype Scanner instance for scanning LaTeX source files """
Return a prototype Scanner instance for scanning LaTeX source files
when built with pdflatex. when built with pdflatex.
""" """
ds = LaTeX(name = "PDFLaTeXScanner", ds = LaTeX(name = "PDFLaTeXScanner",
@ -116,7 +122,8 @@ def PDFLaTeXScanner():
return ds return ds
class LaTeX(SCons.Scanner.Base): class LaTeX(SCons.Scanner.Base):
"""Class for scanning LaTeX files for included files. """
Class for scanning LaTeX files for included files.
Unlike most scanners, which use regular expressions that just Unlike most scanners, which use regular expressions that just
return the included file name, this returns a tuple consisting return the included file name, this returns a tuple consisting
@ -133,10 +140,12 @@ class LaTeX(SCons.Scanner.Base):
The actual subset and search order may be altered by The actual subset and search order may be altered by
DeclareGraphicsExtensions command. This complication is ignored. DeclareGraphicsExtensions command. This complication is ignored.
The default order corresponds to experimentation with teTeX The default order corresponds to experimentation with teTeX::
$ latex --version $ latex --version
pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4) pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4)
kpathsea version 3.5.4 kpathsea version 3.5.4
The order is: The order is:
['.eps', '.ps'] for latex ['.eps', '.ps'] for latex
['.png', '.pdf', '.jpg', '.tif']. ['.png', '.pdf', '.jpg', '.tif'].
@ -148,8 +157,7 @@ class LaTeX(SCons.Scanner.Base):
env['TEXINPUTS'] for "lstinputlisting" keyword env['TEXINPUTS'] for "lstinputlisting" keyword
env['BIBINPUTS'] for "bibliography" keyword env['BIBINPUTS'] for "bibliography" keyword
env['BSTINPUTS'] for "bibliographystyle" keyword env['BSTINPUTS'] for "bibliographystyle" keyword
env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed just allows user to set it if needed.
just allows user to set it if needed.
FIXME: also look for the class or style in document[class|style]{} FIXME: also look for the class or style in document[class|style]{}
FIXME: also look for the argument of bibliographystyle{} FIXME: also look for the argument of bibliographystyle{}
@ -166,6 +174,9 @@ class LaTeX(SCons.Scanner.Base):
'usepackage': 'TEXINPUTS', 'usepackage': 'TEXINPUTS',
'lstinputlisting': 'TEXINPUTS'} 'lstinputlisting': 'TEXINPUTS'}
env_variables = SCons.Util.unique(list(keyword_paths.values())) env_variables = SCons.Util.unique(list(keyword_paths.values()))
two_arg_commands = ['import', 'subimport',
'includefrom', 'subincludefrom',
'inputfrom', 'subinputfrom']
def __init__(self, name, suffixes, graphics_extensions, *args, **kw): def __init__(self, name, suffixes, graphics_extensions, *args, **kw):
@ -175,8 +186,29 @@ class LaTeX(SCons.Scanner.Base):
# line followed by one or more newline characters (i.e. blank # line followed by one or more newline characters (i.e. blank
# lines), interfering with a match on the next line. # lines), interfering with a match on the next line.
# add option for whitespace before the '[options]' or the '{filename}' # add option for whitespace before the '[options]' or the '{filename}'
regex = r'^[^%\n]*\\(include|includegraphics(?:\s*\[[^\]]+\])?|lstinputlisting(?:\[[^\]]+\])?|input|bibliography|addbibresource|addglobalbib|addsectionbib|usepackage)\s*{([^}]*)}' regex = r'''
self.cre = re.compile(regex, re.M) ^[^%\n]*
\\(
include
| includegraphics(?:\s*\[[^\]]+\])?
| lstinputlisting(?:\[[^\]]+\])?
| input
| import
| subimport
| includefrom
| subincludefrom
| inputfrom
| subinputfrom
| bibliography
| addbibresource
| addglobalbib
| addsectionbib
| usepackage
)
\s*{([^}]*)} # first arg
(?: \s*{([^}]*)} )? # maybe another arg
'''
self.cre = re.compile(regex, re.M | re.X)
self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M) self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M)
self.graphics_extensions = graphics_extensions self.graphics_extensions = graphics_extensions
@ -236,23 +268,26 @@ class LaTeX(SCons.Scanner.Base):
SCons.Scanner.Base.__init__(self, *args, **kw) SCons.Scanner.Base.__init__(self, *args, **kw)
def _latex_names(self, include): def _latex_names(self, include_type, filename):
filename = include[1] if include_type == 'input':
if include[0] == 'input':
base, ext = os.path.splitext( filename ) base, ext = os.path.splitext( filename )
if ext == "": if ext == "":
return [filename + '.tex'] return [filename + '.tex']
if (include[0] == 'include'): if include_type in ('include', 'import', 'subimport',
return [filename + '.tex'] 'includefrom', 'subincludefrom',
if include[0] == 'bibliography': 'inputfrom', 'subinputfrom'):
base, ext = os.path.splitext( filename )
if ext == "":
return [filename + '.tex']
if include_type == 'bibliography':
base, ext = os.path.splitext( filename ) base, ext = os.path.splitext( filename )
if ext == "": if ext == "":
return [filename + '.bib'] return [filename + '.bib']
if include[0] == 'usepackage': if include_type == 'usepackage':
base, ext = os.path.splitext( filename ) base, ext = os.path.splitext( filename )
if ext == "": if ext == "":
return [filename + '.sty'] return [filename + '.sty']
if include[0] == 'includegraphics': if include_type == 'includegraphics':
base, ext = os.path.splitext( filename ) base, ext = os.path.splitext( filename )
if ext == "": if ext == "":
#return [filename+e for e in self.graphics_extensions + TexGraphics] #return [filename+e for e in self.graphics_extensions + TexGraphics]
@ -267,21 +302,26 @@ class LaTeX(SCons.Scanner.Base):
return SCons.Node.FS._my_normcase(str(include)) return SCons.Node.FS._my_normcase(str(include))
def find_include(self, include, source_dir, path): def find_include(self, include, source_dir, path):
inc_type, inc_subdir, inc_filename = include
try: try:
sub_path = path[include[0]] sub_paths = path[inc_type]
except (IndexError, KeyError): except (IndexError, KeyError):
sub_path = () sub_paths = ((), ())
try_names = self._latex_names(include) try_names = self._latex_names(inc_type, inc_filename)
# There are three search paths to try:
# 1. current directory "source_dir"
# 2. env[var]
# 3. env['ENV'][var]
search_paths = [(source_dir,)] + list(sub_paths)
for n in try_names: for n in try_names:
# see if we find it using the path in env[var] for search_path in search_paths:
i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[0]) paths = tuple([d.Dir(inc_subdir) for d in search_path])
if i: i = SCons.Node.FS.find_file(n, paths)
return i, include if i:
# see if we find it using the path in env['ENV'][var] return i, include
i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[1]) return None, include
if i:
return i, include
return i, include
def canonical_text(self, text): def canonical_text(self, text):
"""Standardize an input TeX-file contents. """Standardize an input TeX-file contents.
@ -300,7 +340,7 @@ class LaTeX(SCons.Scanner.Base):
line_continues_a_comment = len(comment) > 0 line_continues_a_comment = len(comment) > 0
return '\n'.join(out).rstrip()+'\n' return '\n'.join(out).rstrip()+'\n'
def scan(self, node): def scan(self, node, subdir='.'):
# Modify the default scan function to allow for the regular # Modify the default scan function to allow for the regular
# expression to return a comma separated list of file names # expression to return a comma separated list of file names
# as can be the case with the bibliography keyword. # as can be the case with the bibliography keyword.
@ -326,9 +366,14 @@ class LaTeX(SCons.Scanner.Base):
split_includes = [] split_includes = []
for include in includes: for include in includes:
inc_type = noopt_cre.sub('', include[0]) inc_type = noopt_cre.sub('', include[0])
inc_list = include[1].split(',') inc_subdir = subdir
if inc_type in self.two_arg_commands:
inc_subdir = os.path.join(subdir, include[1])
inc_list = include[2].split(',')
else:
inc_list = include[1].split(',')
for j in range(len(inc_list)): for j in range(len(inc_list)):
split_includes.append( (inc_type, inc_list[j]) ) split_includes.append( (inc_type, inc_subdir, inc_list[j]) )
# #
includes = split_includes includes = split_includes
node.includes = includes node.includes = includes
@ -359,11 +404,13 @@ class LaTeX(SCons.Scanner.Base):
while queue: while queue:
include = queue.pop() include = queue.pop()
inc_type, inc_subdir, inc_filename = include
try: try:
if seen[include[1]] == 1: if seen[inc_filename] == 1:
continue continue
except KeyError: except KeyError:
seen[include[1]] = 1 seen[inc_filename] = 1
# #
# Handle multiple filenames in include[1] # Handle multiple filenames in include[1]
@ -372,14 +419,14 @@ class LaTeX(SCons.Scanner.Base):
if n is None: if n is None:
# Do not bother with 'usepackage' warnings, as they most # Do not bother with 'usepackage' warnings, as they most
# likely refer to system-level files # likely refer to system-level files
if include[0] != 'usepackage': if inc_type != 'usepackage':
SCons.Warnings.warn(SCons.Warnings.DependencyWarning, SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
"No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
else: else:
sortkey = self.sort_key(n) sortkey = self.sort_key(n)
nodes.append((sortkey, n)) nodes.append((sortkey, n))
# recurse down # recurse down
queue.extend( self.scan(n) ) queue.extend( self.scan(n, inc_subdir) )
return [pair[1] for pair in sorted(nodes)] return [pair[1] for pair in sorted(nodes)]

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Scanner/Prog.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/Prog.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Node import SCons.Node
import SCons.Node.FS import SCons.Node.FS

View file

@ -6,7 +6,7 @@ Definition Language) files.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -28,23 +28,34 @@ 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__ = "src/engine/SCons/Scanner/RC.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/RC.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import re
import SCons.Node.FS import SCons.Node.FS
import SCons.Scanner import SCons.Scanner
import re
def no_tlb(nodes):
"""
Filter out .tlb files as they are binary and shouldn't be scanned
"""
# print("Nodes:%s"%[str(n) for n in nodes])
return [n for n in nodes if str(n)[-4:] != '.tlb']
def RCScan(): def RCScan():
"""Return a prototype Scanner instance for scanning RC source files""" """Return a prototype Scanner instance for scanning RC source files"""
res_re= r'^(?:\s*#\s*(?:include)|' \ res_re= r'^(?:\s*#\s*(?:include)|' \
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \ '.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
'\s*.*?)' \ '\s*.*?)' \
'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$' '\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
resScanner = SCons.Scanner.ClassicCPP( "ResourceScanner", resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
"$RCSUFFIXES", "$RCSUFFIXES",
"CPPPATH", "CPPPATH",
res_re ) res_re,
recursive=no_tlb)
return resScanner return resScanner

View file

@ -5,7 +5,7 @@ This module implements the dependency scanner for SWIG code.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,7 +27,7 @@ This module implements the dependency scanner for SWIG 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__ = "src/engine/SCons/Scanner/SWIG.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/SWIG.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Scanner import SCons.Scanner

View file

@ -5,7 +5,7 @@ The Scanner package for the SCons software construction utility.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,7 +27,7 @@ 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__ = "src/engine/SCons/Scanner/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Scanner/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import re import re
@ -62,8 +62,10 @@ def Scanner(function, *args, **kw):
class FindPathDirs(object): class FindPathDirs(object):
"""A class to bind a specific *PATH variable name to a function that """
will return all of the *path directories.""" A class to bind a specific E{*}PATH variable name to a function that
will return all of the E{*}path directories.
"""
def __init__(self, variable): def __init__(self, variable):
self.variable = variable self.variable = variable
def __call__(self, env, dir=None, target=None, source=None, argument=None): def __call__(self, env, dir=None, target=None, source=None, argument=None):
@ -188,12 +190,12 @@ class Base(object):
def path(self, env, dir=None, target=None, source=None): def path(self, env, dir=None, target=None, source=None):
if not self.path_function: if not self.path_function:
return () return ()
if not self.argument is _null: if self.argument is not _null:
return self.path_function(env, dir, target, source, self.argument) return self.path_function(env, dir, target, source, self.argument)
else: else:
return self.path_function(env, dir, target, source) return self.path_function(env, dir, target, source)
def __call__(self, node, env, path = ()): def __call__(self, node, env, path=()):
""" """
This method scans a single object. 'node' is the node This method scans a single object. 'node' is the node
that will be passed to the scanner function, and 'env' is the that will be passed to the scanner function, and 'env' is the
@ -206,27 +208,27 @@ class Base(object):
self = self.select(node) self = self.select(node)
if not self.argument is _null: if not self.argument is _null:
list = self.function(node, env, path, self.argument) node_list = self.function(node, env, path, self.argument)
else: else:
list = self.function(node, env, path) node_list = self.function(node, env, path)
kw = {} kw = {}
if hasattr(node, 'dir'): if hasattr(node, 'dir'):
kw['directory'] = node.dir kw['directory'] = node.dir
node_factory = env.get_factory(self.node_factory) node_factory = env.get_factory(self.node_factory)
nodes = [] nodes = []
for l in list: for l in node_list:
if self.node_class and not isinstance(l, self.node_class): if self.node_class and not isinstance(l, self.node_class):
l = node_factory(l, **kw) l = node_factory(l, **kw)
nodes.append(l) nodes.append(l)
return nodes return nodes
def __cmp__(self, other): def __eq__(self, other):
try: try:
return cmp(self.__dict__, other.__dict__) return self.__dict__ == other.__dict__
except AttributeError: except AttributeError:
# other probably doesn't have a __dict__ # other probably doesn't have a __dict__
return cmp(self.__dict__, other) return self.__dict__ == other
def __hash__(self): def __hash__(self):
return id(self) return id(self)
@ -259,7 +261,7 @@ class Base(object):
def _recurse_no_nodes(self, nodes): def _recurse_no_nodes(self, nodes):
return [] return []
recurse_nodes = _recurse_no_nodes # recurse_nodes = _recurse_no_nodes
def add_scanner(self, skey, scanner): def add_scanner(self, skey, scanner):
self.function[skey] = scanner self.function[skey] = scanner
@ -283,7 +285,7 @@ class Selector(Base):
self.dict = dict self.dict = dict
self.skeys = list(dict.keys()) self.skeys = list(dict.keys())
def __call__(self, node, env, path = ()): def __call__(self, node, env, path=()):
return self.select(node)(node, env, path) return self.select(node)(node, env, path)
def select(self, node): def select(self, node):
@ -326,7 +328,7 @@ class Classic(Current):
self.cre = re.compile(regex, re.M) self.cre = re.compile(regex, re.M)
def _scan(node, env, path=(), self=self): def _scan(node, _, path=(), self=self):
node = node.rfile() node = node.rfile()
if not node.exists(): if not node.exists():
return [] return []
@ -334,7 +336,12 @@ class Classic(Current):
kw['function'] = _scan kw['function'] = _scan
kw['path_function'] = FindPathDirs(path_variable) kw['path_function'] = FindPathDirs(path_variable)
kw['recursive'] = 1
# Allow recursive to propagate if child class specifies.
# In this case resource scanner needs to specify a filter on which files
# get recursively processed. Previously was hardcoded to 1 instead of
# defaulted to 1.
kw['recursive'] = kw.get('recursive', 1)
kw['skeys'] = suffixes kw['skeys'] = suffixes
kw['name'] = name kw['name'] = name
@ -356,7 +363,7 @@ class Classic(Current):
if node.includes is not None: if node.includes is not None:
includes = node.includes includes = node.includes
else: else:
includes = self.find_include_names (node) includes = self.find_include_names(node)
# Intern the names of the include files. Saves some memory # Intern the names of the include files. Saves some memory
# if the same header is included many times. # if the same header is included many times.
node.includes = list(map(SCons.Util.silent_intern, includes)) node.includes = list(map(SCons.Util.silent_intern, includes))
@ -393,6 +400,7 @@ class ClassicCPP(Classic):
the contained filename in group 1. the contained filename in group 1.
""" """
def find_include(self, include, source_dir, path): def find_include(self, include, source_dir, path):
include = list(map(SCons.Util.to_str, include))
if include[0] == '"': if include[0] == '"':
paths = (source_dir,) + tuple(path) paths = (source_dir,) + tuple(path)
else: else:

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -19,8 +19,9 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
__revision__ = "src/engine/SCons/Script/Interactive.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Script/Interactive.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """ __doc__ = """
SCons interactive mode SCons interactive mode
@ -98,17 +99,14 @@ except ImportError:
class SConsInteractiveCmd(cmd.Cmd): class SConsInteractiveCmd(cmd.Cmd):
"""\ """\
build [TARGETS] Build the specified TARGETS and their dependencies.
'b' is a synonym. build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym.
clean [TARGETS] Clean (remove) the specified TARGETS and their clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym.
dependencies. 'c' is a synonym. exit Exit SCons interactive mode.
exit Exit SCons interactive mode. help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms.
help [COMMAND] Prints help for the specified COMMAND. 'h' and shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms.
'?' are synonyms. version Prints SCons version information.
shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' """
are synonyms.
version Prints SCons version information.
"""
synonyms = { synonyms = {
'b' : 'build', 'b' : 'build',
@ -129,12 +127,12 @@ class SConsInteractiveCmd(cmd.Cmd):
self.shell_variable = 'SHELL' self.shell_variable = 'SHELL'
def default(self, argv): def default(self, argv):
print "*** Unknown command: %s" % argv[0] print("*** Unknown command: %s" % argv[0])
def onecmd(self, line): def onecmd(self, line):
line = line.strip() line = line.strip()
if not line: if not line:
print self.lastcmd print(self.lastcmd)
return self.emptyline() return self.emptyline()
self.lastcmd = line self.lastcmd = line
if line[0] == '!': if line[0] == '!':
@ -221,7 +219,7 @@ class SConsInteractiveCmd(cmd.Cmd):
def get_unseen_children(node, parent, seen_nodes=seen_nodes): def get_unseen_children(node, parent, seen_nodes=seen_nodes):
def is_unseen(node, seen_nodes=seen_nodes): def is_unseen(node, seen_nodes=seen_nodes):
return node not in seen_nodes return node not in seen_nodes
return list(filter(is_unseen, node.children(scan=1))) return [child for child in node.children(scan=1) if is_unseen(child)]
def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes): def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes):
seen_nodes[node] = 1 seen_nodes[node] = 1
@ -249,7 +247,7 @@ class SConsInteractiveCmd(cmd.Cmd):
while n: while n:
n = walker.get_next() n = walker.get_next()
for node in seen_nodes.keys(): for node in list(seen_nodes.keys()):
# Call node.clear() to clear most of the state # Call node.clear() to clear most of the state
node.clear() node.clear()
# node.clear() doesn't reset node.state, so call # node.clear() doesn't reset node.state, so call
@ -274,7 +272,7 @@ class SConsInteractiveCmd(cmd.Cmd):
return self.do_build(['build', '--clean'] + argv[1:]) return self.do_build(['build', '--clean'] + argv[1:])
def do_EOF(self, argv): def do_EOF(self, argv):
print print()
self.do_exit(argv) self.do_exit(argv)
def _do_one_help(self, arg): def _do_one_help(self, arg):
@ -351,7 +349,7 @@ class SConsInteractiveCmd(cmd.Cmd):
# Doing the right thing with an argument list currently # Doing the right thing with an argument list currently
# requires different shell= values on Windows and Linux. # requires different shell= values on Windows and Linux.
p = subprocess.Popen(argv, shell=(sys.platform=='win32')) p = subprocess.Popen(argv, shell=(sys.platform=='win32'))
except EnvironmentError, e: except EnvironmentError as e:
sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror)) sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror))
else: else:
p.wait() p.wait()

View file

@ -10,10 +10,14 @@ some other module. If it's specific to the "scons" script invocation,
it goes here. it goes here.
""" """
from __future__ import print_function
unsupported_python_version = (2, 6, 0) unsupported_python_version = (2, 6, 0)
deprecated_python_version = (2, 7, 0) deprecated_python_version = (2, 7, 0)
# Copyright (c) 2001 - 2016 The SCons Foundation
# Copyright (c) 2001 - 2017 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
@ -34,7 +38,8 @@ deprecated_python_version = (2, 7, 0)
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Script/Main.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Script/Main.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.compat import SCons.compat
@ -42,6 +47,7 @@ import os
import sys import sys
import time import time
import traceback import traceback
import sysconfig
import SCons.CacheDir import SCons.CacheDir
import SCons.Debug import SCons.Debug
@ -60,6 +66,7 @@ import SCons.Warnings
import SCons.Script.Interactive import SCons.Script.Interactive
def fetch_win32_parallel_msg(): def fetch_win32_parallel_msg():
# A subsidiary function that exists solely to isolate this import # A subsidiary function that exists solely to isolate this import
# so we don't have to pull it in on all platforms, and so that an # so we don't have to pull it in on all platforms, and so that an
@ -70,6 +77,7 @@ def fetch_win32_parallel_msg():
import SCons.Platform.win32 import SCons.Platform.win32
return SCons.Platform.win32.parallel_msg return SCons.Platform.win32.parallel_msg
def revert_io(): def revert_io():
# This call is added to revert stderr and stdout to the original # This call is added to revert stderr and stdout to the original
# ones just in case some build rule or something else in the system # ones just in case some build rule or something else in the system
@ -86,6 +94,7 @@ progress_display = SCons.Util.DisplayEngine()
first_command_start = None first_command_start = None
last_command_end = None last_command_end = None
class Progressor(object): class Progressor(object):
prev = '' prev = ''
count = 0 count = 0
@ -149,9 +158,11 @@ def Progress(*args, **kw):
_BuildFailures = [] _BuildFailures = []
def GetBuildFailures(): def GetBuildFailures():
return _BuildFailures return _BuildFailures
class BuildTask(SCons.Taskmaster.OutOfDateTask): class BuildTask(SCons.Taskmaster.OutOfDateTask):
"""An SCons build task.""" """An SCons build task."""
progress = ProgressObject progress = ProgressObject
@ -220,7 +231,7 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
self.exception_set() self.exception_set()
self.do_failed() self.do_failed()
else: else:
print "scons: Nothing to be done for `%s'." % t print("scons: Nothing to be done for `%s'." % t)
SCons.Taskmaster.OutOfDateTask.executed(self) SCons.Taskmaster.OutOfDateTask.executed(self)
else: else:
SCons.Taskmaster.OutOfDateTask.executed(self) SCons.Taskmaster.OutOfDateTask.executed(self)
@ -289,8 +300,8 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
if self.options.debug_includes: if self.options.debug_includes:
tree = t.render_include_tree() tree = t.render_include_tree()
if tree: if tree:
print print()
print tree print(tree)
SCons.Taskmaster.OutOfDateTask.postprocess(self) SCons.Taskmaster.OutOfDateTask.postprocess(self)
def make_ready(self): def make_ready(self):
@ -301,6 +312,7 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
if explanation: if explanation:
sys.stdout.write("scons: " + explanation) sys.stdout.write("scons: " + explanation)
class CleanTask(SCons.Taskmaster.AlwaysTask): class CleanTask(SCons.Taskmaster.AlwaysTask):
"""An SCons clean task.""" """An SCons clean task."""
def fs_delete(self, path, pathstr, remove=True): def fs_delete(self, path, pathstr, remove=True):
@ -325,10 +337,10 @@ class CleanTask(SCons.Taskmaster.AlwaysTask):
else: else:
errstr = "Path '%s' exists but isn't a file or directory." errstr = "Path '%s' exists but isn't a file or directory."
raise SCons.Errors.UserError(errstr % (pathstr)) raise SCons.Errors.UserError(errstr % (pathstr))
except SCons.Errors.UserError, e: except SCons.Errors.UserError as e:
print e print(e)
except (IOError, OSError), e: except (IOError, OSError) as e:
print "scons: Could not remove '%s':" % pathstr, e.strerror print("scons: Could not remove '%s':" % pathstr, e.strerror)
def _get_files_to_clean(self): def _get_files_to_clean(self):
result = [] result = []
@ -354,13 +366,13 @@ class CleanTask(SCons.Taskmaster.AlwaysTask):
for t in self._get_files_to_clean(): for t in self._get_files_to_clean():
try: try:
removed = t.remove() removed = t.remove()
except OSError, e: except OSError as e:
# An OSError may indicate something like a permissions # An OSError may indicate something like a permissions
# issue, an IOError would indicate something like # issue, an IOError would indicate something like
# the file not existing. In either case, print a # the file not existing. In either case, print a
# message and keep going to try to remove as many # message and keep going to try to remove as many
# targets as possible. # targets as possible.
print "scons: Could not remove '%s':" % str(t), e.strerror print("scons: Could not remove '{0}'".format(str(t)), e.strerror)
else: else:
if removed: if removed:
display("Removed " + str(t)) display("Removed " + str(t))
@ -600,7 +612,7 @@ def _scons_internal_error():
"""Handle all errors but user errors. Print out a message telling """Handle all errors but user errors. Print out a message telling
the user what to do in this case and print a normal trace. the user what to do in this case and print a normal trace.
""" """
print 'internal error' print('internal error')
traceback.print_exc() traceback.print_exc()
sys.exit(2) sys.exit(2)
@ -714,7 +726,7 @@ def _load_site_scons_dir(topdir, site_dir_name=None):
# the error checking makes it longer. # the error checking makes it longer.
try: try:
m = sys.modules['SCons.Script'] m = sys.modules['SCons.Script']
except Exception, e: except Exception as e:
fmt = 'cannot import site_init.py: missing SCons.Script module %s' fmt = 'cannot import site_init.py: missing SCons.Script module %s'
raise SCons.Errors.InternalError(fmt % repr(e)) raise SCons.Errors.InternalError(fmt % repr(e))
try: try:
@ -722,15 +734,15 @@ def _load_site_scons_dir(topdir, site_dir_name=None):
modname = os.path.basename(pathname)[:-len(sfx)] modname = os.path.basename(pathname)[:-len(sfx)]
site_m = {"__file__": pathname, "__name__": modname, "__doc__": None} site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
re_special = re.compile("__[^_]+__") re_special = re.compile("__[^_]+__")
for k in m.__dict__.keys(): for k in list(m.__dict__.keys()):
if not re_special.match(k): if not re_special.match(k):
site_m[k] = m.__dict__[k] site_m[k] = m.__dict__[k]
# This is the magic. # This is the magic.
exec fp in site_m exec(compile(fp.read(), fp.name, 'exec'), site_m)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Exception, e: except Exception as e:
fmt = '*** Error loading site_init file %s:\n' fmt = '*** Error loading site_init file %s:\n'
sys.stderr.write(fmt % repr(site_init_file)) sys.stderr.write(fmt % repr(site_init_file))
raise raise
@ -740,7 +752,7 @@ def _load_site_scons_dir(topdir, site_dir_name=None):
m.__dict__[k] = site_m[k] m.__dict__[k] = site_m[k]
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except ImportError, e: except ImportError as e:
fmt = '*** cannot import site init file %s:\n' fmt = '*** cannot import site init file %s:\n'
sys.stderr.write(fmt % repr(site_init_file)) sys.stderr.write(fmt % repr(site_init_file))
raise raise
@ -792,7 +804,7 @@ def _load_all_site_scons_dirs(topdir, verbose=None):
dirs=sysdirs + [topdir] dirs=sysdirs + [topdir]
for d in dirs: for d in dirs:
if verbose: # this is used by unit tests. if verbose: # this is used by unit tests.
print "Loading site dir ", d print("Loading site dir ", d)
_load_site_scons_dir(d) _load_site_scons_dir(d)
def test_load_all_site_scons_dirs(d): def test_load_all_site_scons_dirs(d):
@ -992,7 +1004,7 @@ def _main(parser):
try: try:
for script in scripts: for script in scripts:
SCons.Script._SConscript._SConscript(fs, script) SCons.Script._SConscript._SConscript(fs, script)
except SCons.Errors.StopError, e: except SCons.Errors.StopError as e:
# We had problems reading an SConscript file, such as it # We had problems reading an SConscript file, such as it
# couldn't be copied in to the VariantDir. Since we're just # couldn't be copied in to the VariantDir. Since we're just
# reading SConscript files and haven't started building # reading SConscript files and haven't started building
@ -1053,8 +1065,8 @@ def _main(parser):
# SConscript files. Give them the options usage. # SConscript files. Give them the options usage.
raise SConsPrintHelpException raise SConsPrintHelpException
else: else:
print help_text print(help_text)
print "Use scons -H for help about command-line options." print("Use scons -H for help about command-line options.")
exit_status = 0 exit_status = 0
return return
@ -1091,7 +1103,7 @@ def _main(parser):
nodes = _build_targets(fs, options, targets, target_top) nodes = _build_targets(fs, options, targets, target_top)
if not nodes: if not nodes:
revert_io() revert_io()
print 'Found nothing to build' print('Found nothing to build')
exit_status = 2 exit_status = 2
def _build_targets(fs, options, targets, target_top): def _build_targets(fs, options, targets, target_top):
@ -1157,7 +1169,7 @@ def _build_targets(fs, options, targets, target_top):
# or not a file, so go ahead and keep it as a default # or not a file, so go ahead and keep it as a default
# target and let the engine sort it out: # target and let the engine sort it out:
return 1 return 1
d = list(filter(check_dir, SCons.Script.DEFAULT_TARGETS)) d = [tgt for tgt in SCons.Script.DEFAULT_TARGETS if check_dir(tgt)]
SCons.Script.DEFAULT_TARGETS[:] = d SCons.Script.DEFAULT_TARGETS[:] = d
target_top = None target_top = None
lookup_top = None lookup_top = None
@ -1231,7 +1243,7 @@ def _build_targets(fs, options, targets, target_top):
if options.taskmastertrace_file == '-': if options.taskmastertrace_file == '-':
tmtrace = sys.stdout tmtrace = sys.stdout
elif options.taskmastertrace_file: elif options.taskmastertrace_file:
tmtrace = open(options.taskmastertrace_file, 'wb') tmtrace = open(options.taskmastertrace_file, 'w')
else: else:
tmtrace = None tmtrace = None
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace) taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
@ -1240,16 +1252,19 @@ def _build_targets(fs, options, targets, target_top):
# various print_* settings, tree_printer list, etc. # various print_* settings, tree_printer list, etc.
BuildTask.options = options BuildTask.options = options
python_has_threads = sysconfig.get_config_var('WITH_THREAD')
# to check if python configured with threads.
global num_jobs global num_jobs
num_jobs = options.num_jobs num_jobs = options.num_jobs
jobs = SCons.Job.Jobs(num_jobs, taskmaster) jobs = SCons.Job.Jobs(num_jobs, taskmaster)
if num_jobs > 1: if num_jobs > 1:
msg = None msg = None
if jobs.num_jobs == 1: if sys.platform == 'win32':
msg = fetch_win32_parallel_msg()
elif jobs.num_jobs == 1 or not python_has_threads:
msg = "parallel builds are unsupported by this version of Python;\n" + \ msg = "parallel builds are unsupported by this version of Python;\n" + \
"\tignoring -j or num_jobs option.\n" "\tignoring -j or num_jobs option.\n"
elif sys.platform == 'win32':
msg = fetch_win32_parallel_msg()
if msg: if msg:
SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
@ -1332,10 +1347,10 @@ def main():
pass pass
parts.append(version_string("engine", SCons)) parts.append(version_string("engine", SCons))
parts.append(path_string("engine", SCons)) parts.append(path_string("engine", SCons))
parts.append("Copyright (c) 2001 - 2016 The SCons Foundation") parts.append("Copyright (c) 2001 - 2017 The SCons Foundation")
version = ''.join(parts) version = ''.join(parts)
import SConsOptions from . import SConsOptions
parser = SConsOptions.Parser(version) parser = SConsOptions.Parser(version)
values = SConsOptions.SConsValues(parser.get_default_values()) values = SConsOptions.SConsValues(parser.get_default_values())
@ -1346,23 +1361,23 @@ def main():
_exec_main(parser, values) _exec_main(parser, values)
finally: finally:
revert_io() revert_io()
except SystemExit, s: except SystemExit as s:
if s: if s:
exit_status = s exit_status = s
except KeyboardInterrupt: except KeyboardInterrupt:
print("scons: Build interrupted.") print("scons: Build interrupted.")
sys.exit(2) sys.exit(2)
except SyntaxError, e: except SyntaxError as e:
_scons_syntax_error(e) _scons_syntax_error(e)
except SCons.Errors.InternalError: except SCons.Errors.InternalError:
_scons_internal_error() _scons_internal_error()
except SCons.Errors.UserError, e: except SCons.Errors.UserError as e:
_scons_user_error(e) _scons_user_error(e)
except SConsPrintHelpException: except SConsPrintHelpException:
parser.print_help() parser.print_help()
exit_status = 0 exit_status = 0
except SCons.Errors.BuildError, e: except SCons.Errors.BuildError as e:
print e print(e)
exit_status = e.exitstatus exit_status = e.exitstatus
except: except:
# An exception here is likely a builtin Python exception Python # An exception here is likely a builtin Python exception Python
@ -1398,10 +1413,10 @@ def main():
else: else:
ct = last_command_end - first_command_start ct = last_command_end - first_command_start
scons_time = total_time - sconscript_time - ct scons_time = total_time - sconscript_time - ct
print "Total build time: %f seconds"%total_time print("Total build time: %f seconds"%total_time)
print "Total SConscript file execution time: %f seconds"%sconscript_time print("Total SConscript file execution time: %f seconds"%sconscript_time)
print "Total SCons execution time: %f seconds"%scons_time print("Total SCons execution time: %f seconds"%scons_time)
print "Total command execution time: %f seconds"%ct print("Total command execution time: %f seconds"%ct)
sys.exit(exit_status) sys.exit(exit_status)

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Script/SConsOptions.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Script/SConsOptions.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import optparse import optparse
import re import re
@ -63,6 +63,7 @@ def diskcheck_convert(value):
raise ValueError(v) raise ValueError(v)
return result return result
class SConsValues(optparse.Values): class SConsValues(optparse.Values):
""" """
Holder class for uniform access to SCons options, regardless Holder class for uniform access to SCons options, regardless
@ -112,7 +113,18 @@ class SConsValues(optparse.Values):
try: try:
return self.__dict__['__SConscript_settings__'][attr] return self.__dict__['__SConscript_settings__'][attr]
except KeyError: except KeyError:
return getattr(self.__dict__['__defaults__'], attr) try:
return getattr(self.__dict__['__defaults__'], attr)
except KeyError:
# Added because with py3 this is a new class,
# not a classic class, and due to the way
# In that case it will create an object without
# __defaults__, and then query for __setstate__
# which will throw an exception of KeyError
# deepcopy() is expecting AttributeError if __setstate__
# is not available.
raise AttributeError(attr)
settable = [ settable = [
'clean', 'clean',
@ -127,6 +139,7 @@ class SConsValues(optparse.Values):
'random', 'random',
'stack_size', 'stack_size',
'warn', 'warn',
'silent'
] ]
def set_option(self, name, value): def set_option(self, name, value):
@ -161,7 +174,7 @@ class SConsValues(optparse.Values):
elif name == 'diskcheck': elif name == 'diskcheck':
try: try:
value = diskcheck_convert(value) value = diskcheck_convert(value)
except ValueError, v: except ValueError as v:
raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v) raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v)
if 'diskcheck' not in self.__dict__: if 'diskcheck' not in self.__dict__:
# No --diskcheck= option was specified on the command line. # No --diskcheck= option was specified on the command line.
@ -186,6 +199,7 @@ class SConsValues(optparse.Values):
self.__SConscript_settings__[name] = value self.__SConscript_settings__[name] = value
class SConsOption(optparse.Option): class SConsOption(optparse.Option):
def convert_value(self, opt, value): def convert_value(self, opt, value):
if value is not None: if value is not None:
@ -638,7 +652,7 @@ def Parser(version):
for value in value__.split(','): for value in value__.split(','):
if value in debug_options: if value in debug_options:
parser.values.debug.append(value) parser.values.debug.append(value)
elif value in deprecated_debug_options.keys(): elif value in list(deprecated_debug_options.keys()):
parser.values.debug.append(value) parser.values.debug.append(value)
try: try:
parser.values.delayed_warnings parser.values.delayed_warnings
@ -663,7 +677,7 @@ def Parser(version):
def opt_diskcheck(option, opt, value, parser): def opt_diskcheck(option, opt, value, parser):
try: try:
diskcheck_value = diskcheck_convert(value) diskcheck_value = diskcheck_convert(value)
except ValueError, e: except ValueError as e:
raise OptionValueError("`%s' is not a valid diskcheck type" % e) raise OptionValueError("`%s' is not a valid diskcheck type" % e)
setattr(parser.values, option.dest, diskcheck_value) setattr(parser.values, option.dest, diskcheck_value)
@ -830,7 +844,7 @@ def Parser(version):
tree_options = ["all", "derived", "prune", "status"] tree_options = ["all", "derived", "prune", "status"]
def opt_tree(option, opt, value, parser, tree_options=tree_options): def opt_tree(option, opt, value, parser, tree_options=tree_options):
import Main from . import Main
tp = Main.TreePrinter() tp = Main.TreePrinter()
for o in value.split(','): for o in value.split(','):
if o == 'all': if o == 'all':

View file

@ -6,7 +6,7 @@ files.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -26,9 +26,8 @@ files.
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import division
__revision__ = "src/engine/SCons/Script/SConscript.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Script/SConscript.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons import SCons
import SCons.Action import SCons.Action
@ -45,12 +44,15 @@ import SCons.Script.Main
import SCons.Tool import SCons.Tool
import SCons.Util import SCons.Util
from . import Main
import collections import collections
import os import os
import os.path import os.path
import re import re
import sys import sys
import traceback import traceback
import time
class SConscriptReturn(Exception): class SConscriptReturn(Exception):
pass pass
@ -69,7 +71,7 @@ def get_calling_namespaces():
"""Return the locals and globals for the function that called """Return the locals and globals for the function that called
into this module in the current call stack.""" into this module in the current call stack."""
try: 1//0 try: 1//0
except ZeroDivisionError: except ZeroDivisionError:
# Don't start iterating with the current stack-frame to # Don't start iterating with the current stack-frame to
# prevent creating reference cycles (f_back is safe). # prevent creating reference cycles (f_back is safe).
frame = sys.exc_info()[2].tb_frame.f_back frame = sys.exc_info()[2].tb_frame.f_back
@ -103,7 +105,7 @@ def compute_exports(exports):
retval[export] = loc[export] retval[export] = loc[export]
except KeyError: except KeyError:
retval[export] = glob[export] retval[export] = glob[export]
except KeyError, x: except KeyError as x:
raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x) raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x)
return retval return retval
@ -135,7 +137,7 @@ def Return(*vars, **kw):
for var in fvars: for var in fvars:
for v in var.split(): for v in var.split():
retval.append(call_stack[-1].globals[v]) retval.append(call_stack[-1].globals[v])
except KeyError, x: except KeyError as x:
raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x) raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x)
if len(retval) == 1: if len(retval) == 1:
@ -164,7 +166,7 @@ def _SConscript(fs, *files, **kw):
try: try:
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1 SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1
if fn == "-": if fn == "-":
exec sys.stdin in call_stack[-1].globals exec(sys.stdin.read(), call_stack[-1].globals)
else: else:
if isinstance(fn, SCons.Node.Node): if isinstance(fn, SCons.Node.Node):
f = fn f = fn
@ -178,10 +180,10 @@ def _SConscript(fs, *files, **kw):
fs.chdir(top, change_os_dir=1) fs.chdir(top, change_os_dir=1)
if f.rexists(): if f.rexists():
actual = f.rfile() actual = f.rfile()
_file_ = open(actual.get_abspath(), "r") _file_ = open(actual.get_abspath(), "rb")
elif f.srcnode().rexists(): elif f.srcnode().rexists():
actual = f.srcnode().rfile() actual = f.srcnode().rfile()
_file_ = open(actual.get_abspath(), "r") _file_ = open(actual.get_abspath(), "rb")
elif f.has_src_builder(): elif f.has_src_builder():
# The SConscript file apparently exists in a source # The SConscript file apparently exists in a source
# code management system. Build it, but then clear # code management system. Build it, but then clear
@ -191,7 +193,7 @@ def _SConscript(fs, *files, **kw):
f.built() f.built()
f.builder_set(None) f.builder_set(None)
if f.exists(): if f.exists():
_file_ = open(f.get_abspath(), "r") _file_ = open(f.get_abspath(), "rb")
if _file_: if _file_:
# Chdir to the SConscript directory. Use a path # Chdir to the SConscript directory. Use a path
# name relative to the SConstruct file so that if # name relative to the SConstruct file so that if
@ -247,10 +249,18 @@ def _SConscript(fs, *files, **kw):
pass pass
try: try:
try: try:
exec _file_ in call_stack[-1].globals # _file_ = SCons.Util.to_str(_file_)
if Main.print_time:
time1 = time.time()
exec(compile(_file_.read(), _file_.name, 'exec'),
call_stack[-1].globals)
except SConscriptReturn: except SConscriptReturn:
pass pass
finally: finally:
if Main.print_time:
time2 = time.time()
print('SConscript:%s took %0.3f ms' % (f.get_abspath(), (time2 - time1) * 1000.0))
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})
else: else:
@ -272,7 +282,7 @@ def _SConscript(fs, *files, **kw):
rdir._create() # Make sure there's a directory there. rdir._create() # Make sure there's a directory there.
try: try:
os.chdir(rdir.get_abspath()) os.chdir(rdir.get_abspath())
except OSError, e: except OSError as e:
# We still couldn't chdir there, so raise the error, # We still couldn't chdir there, so raise the error,
# but only if actions are being executed. # but only if actions are being executed.
# #
@ -462,15 +472,15 @@ class SConsEnvironment(SCons.Environment.Base):
scons_ver_string = '%d.%d.%d' % (major, minor, revision) scons_ver_string = '%d.%d.%d' % (major, minor, revision)
else: else:
scons_ver_string = '%d.%d' % (major, minor) scons_ver_string = '%d.%d' % (major, minor)
print "SCons %s or greater required, but you have SCons %s" % \ print("SCons %s or greater required, but you have SCons %s" % \
(scons_ver_string, SCons.__version__) (scons_ver_string, SCons.__version__))
sys.exit(2) sys.exit(2)
def EnsurePythonVersion(self, major, minor): def EnsurePythonVersion(self, major, minor):
"""Exit abnormally if the Python version is not late enough.""" """Exit abnormally if the Python version is not late enough."""
if sys.version_info < (major, minor): if sys.version_info < (major, minor):
v = sys.version.split()[0] v = sys.version.split()[0]
print "Python %d.%d or greater required, but you have Python %s" %(major,minor,v) print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v))
sys.exit(2) sys.exit(2)
def Exit(self, value=0): def Exit(self, value=0):
@ -509,7 +519,7 @@ class SConsEnvironment(SCons.Environment.Base):
globals[v] = exports[v] globals[v] = exports[v]
else: else:
globals[v] = global_exports[v] globals[v] = global_exports[v]
except KeyError,x: except KeyError as x:
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x) raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
def SConscript(self, *ls, **kw): def SConscript(self, *ls, **kw):

View file

@ -12,7 +12,7 @@ it goes here.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -34,14 +34,19 @@ 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__ = "src/engine/SCons/Script/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Script/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import time import time
start_time = time.time() start_time = time.time()
import collections import collections
import os import os
import StringIO
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import sys import sys
# Special chicken-and-egg handling of the "--debug=memoizer" flag: # Special chicken-and-egg handling of the "--debug=memoizer" flag:
@ -67,7 +72,7 @@ if "--debug=memoizer" in _args:
except SCons.Warnings.Warning: except SCons.Warnings.Warning:
# Some warning was thrown. Arrange for it to be displayed # Some warning was thrown. Arrange for it to be displayed
# or not after warnings are configured. # or not after warnings are configured.
import Main from . 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
@ -86,7 +91,7 @@ import SCons.Util
import SCons.Variables import SCons.Variables
import SCons.Defaults import SCons.Defaults
import Main from . import Main
main = Main.main main = Main.main
@ -130,7 +135,7 @@ GetBuildFailures = Main.GetBuildFailures
#repositories = Main.repositories #repositories = Main.repositories
# #
import SConscript from . import SConscript
_SConscript = SConscript _SConscript = SConscript
call_stack = _SConscript.call_stack call_stack = _SConscript.call_stack
@ -264,7 +269,7 @@ def HelpFunction(text, append=False):
global help_text global help_text
if help_text is None: if help_text is None:
if append: if append:
s = StringIO.StringIO() s = StringIO()
PrintHelp(s) PrintHelp(s)
help_text = s.getvalue() help_text = s.getvalue()
s.close() s.close()
@ -332,6 +337,7 @@ GlobalDefaultEnvironmentFunctions = [
'Local', 'Local',
'ParseDepends', 'ParseDepends',
'Precious', 'Precious',
'PyPackageDir',
'Repository', 'Repository',
'Requires', 'Requires',
'SConsignFile', 'SConsignFile',
@ -354,6 +360,7 @@ GlobalDefaultBuilders = [
'Java', 'Java',
'JavaH', 'JavaH',
'Library', 'Library',
'LoadableModule',
'M4', 'M4',
'MSVSProject', 'MSVSProject',
'Object', 'Object',
@ -374,7 +381,7 @@ GlobalDefaultBuilders = [
] ]
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name)) exec ("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name)))
del name del name
# There are a handful of variables that used to live in the # There are a handful of variables that used to live in the

View file

@ -5,7 +5,7 @@ SCons string substitution.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -26,7 +26,7 @@ SCons string substitution.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Subst.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Subst.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import collections import collections
import re import re
@ -338,24 +338,31 @@ SUBST_RAW = 1
SUBST_SIG = 2 SUBST_SIG = 2
_rm = re.compile(r'\$[()]') _rm = re.compile(r'\$[()]')
_remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)')
# Note the pattern below only matches $( or $) when there is no
# preceeding $. (Thus the (?<!\$))
_rm_split = re.compile(r'(?<!\$)(\$[()])')
# Indexed by the SUBST_* constants above. # Indexed by the SUBST_* constants above.
_regex_remove = [ _rm, None, _remove ] _regex_remove = [ _rm, None, _rm_split ]
def _rm_list(list): def _rm_list(list):
return [l for l in list if not l in ('$(', '$)')] return [l for l in list if not l in ('$(', '$)')]
def _remove_list(list): def _remove_list(list):
result = [] result = []
do_append = result.append depth = 0
for l in list: for l in list:
if l == '$(': if l == '$(':
do_append = lambda x: None depth += 1
elif l == '$)': elif l == '$)':
do_append = result.append depth -= 1
else: if depth < 0:
do_append(l) break
elif depth == 0:
result.append(l)
if depth != 0:
return None
return result return result
# Indexed by the SUBST_* constants above. # Indexed by the SUBST_* constants above.
@ -433,19 +440,23 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
if s0 != '$': if s0 != '$':
return s return s
if s1 == '$': if s1 == '$':
return '$' # In this case keep the double $'s which we'll later
# swap for a single dollar sign as we need to retain
# this information to properly avoid matching "$("" when
# the actual text was "$$("" (or "$)"" when "$$)"" )
return '$$'
elif s1 in '()': elif s1 in '()':
return s return s
else: else:
key = s[1:] key = s[1:]
if key[0] == '{' or key.find('.') >= 0: if key[0] == '{' or '.' in key:
if key[0] == '{': if key[0] == '{':
key = key[1:-1] key = key[1:-1]
try: try:
s = eval(key, self.gvars, lvars) s = eval(key, self.gvars, lvars)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Exception, e: except Exception as e:
if e.__class__ in AllowableExceptions: if e.__class__ in AllowableExceptions:
return '' return ''
raise_exception(e, lvars['TARGETS'], s) raise_exception(e, lvars['TARGETS'], s)
@ -562,20 +573,35 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
except KeyError: except KeyError:
pass pass
res = result
if is_String(result): if is_String(result):
# Remove $(-$) pairs and any stuff in between, # Remove $(-$) pairs and any stuff in between,
# if that's appropriate. # if that's appropriate.
remove = _regex_remove[mode] remove = _regex_remove[mode]
if remove: if remove:
result = remove.sub('', result) if mode == SUBST_SIG:
result = _list_remove[mode](remove.split(result))
if result is None:
raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
result = ' '.join(result)
else:
result = remove.sub('', result)
if mode != SUBST_RAW: if mode != SUBST_RAW:
# Compress strings of white space characters into # Compress strings of white space characters into
# a single space. # a single space.
result = _space_sep.sub(' ', result).strip() result = _space_sep.sub(' ', result).strip()
# Now replace escaped $'s currently "$$"
# This is needed because we now retain $$ instead of
# replacing them during substition to avoid
# improperly trying to escape "$$(" as being "$("
result = result.replace('$$','$')
elif is_Sequence(result): elif is_Sequence(result):
remove = _list_remove[mode] remove = _list_remove[mode]
if remove: if remove:
result = remove(result) result = remove(result)
if result is None:
raise SCons.Errors.UserError("Unbalanced $(/$) in: " + str(res))
return result return result
@ -652,7 +678,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv
s = eval(key, self.gvars, lvars) s = eval(key, self.gvars, lvars)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Exception, e: except Exception as e:
if e.__class__ in AllowableExceptions: if e.__class__ in AllowableExceptions:
return return
raise_exception(e, lvars['TARGETS'], s) raise_exception(e, lvars['TARGETS'], s)

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -20,17 +20,24 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
import sys
__doc__ = """ __doc__ = """
Generic Taskmaster module for the SCons build engine. Generic Taskmaster module for the SCons build engine.
=====================================================
This module contains the primary interface(s) between a wrapping user
interface and the SCons build engine. There are two key classes here: This module contains the primary interface(s) between a wrapping user
interface and the SCons build engine. There are two key classes here:
Taskmaster Taskmaster
----------
This is the main engine for walking the dependency graph and This is the main engine for walking the dependency graph and
calling things to decide what does or doesn't need to be built. calling things to decide what does or doesn't need to be built.
Task Task
----
This is the base class for allowing a wrapping interface to This is the base class for allowing a wrapping interface to
decide what does or doesn't actually need to be done. The decide what does or doesn't actually need to be done. The
intention is for a wrapping interface to subclass this as intention is for a wrapping interface to subclass this as
@ -38,7 +45,7 @@ interface and the SCons build engine. There are two key classes here:
The canonical example is the SCons native Python interface, The canonical example is the SCons native Python interface,
which has Task subclasses that handle its specific behavior, which has Task subclasses that handle its specific behavior,
like printing "`foo' is up to date" when a top-level target like printing "'foo' is up to date" when a top-level target
doesn't need to be built, and handling the -c option by removing doesn't need to be built, and handling the -c option by removing
targets as its "build" action. There is also a separate subclass targets as its "build" action. There is also a separate subclass
for suppressing this output when the -q option is used. for suppressing this output when the -q option is used.
@ -47,7 +54,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__ = "src/engine/SCons/Taskmaster.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Taskmaster.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
from itertools import chain from itertools import chain
import operator import operator
@ -107,7 +114,7 @@ fmt = "%(considered)3d "\
def dump_stats(): def dump_stats():
for n in sorted(StatsNodes, key=lambda a: str(a)): for n in sorted(StatsNodes, key=lambda a: str(a)):
print (fmt % n.attributes.stats.__dict__) + str(n) print((fmt % n.attributes.stats.__dict__) + str(n))
@ -191,13 +198,13 @@ class Task(object):
executor.prepare() executor.prepare()
for t in executor.get_action_targets(): for t in executor.get_action_targets():
if print_prepare: if print_prepare:
print "Preparing target %s..."%t print("Preparing target %s..."%t)
for s in t.side_effects: for s in t.side_effects:
print "...with side-effect %s..."%s print("...with side-effect %s..."%s)
t.prepare() t.prepare()
for s in t.side_effects: for s in t.side_effects:
if print_prepare: if print_prepare:
print "...Preparing side-effect %s..."%s print("...Preparing side-effect %s..."%s)
s.prepare() s.prepare()
def get_target(self): def get_target(self):
@ -256,7 +263,7 @@ class Task(object):
raise raise
except SCons.Errors.BuildError: except SCons.Errors.BuildError:
raise raise
except Exception, e: except Exception as e:
buildError = SCons.Errors.convert_to_BuildError(e) buildError = SCons.Errors.convert_to_BuildError(e)
buildError.node = self.targets[0] buildError.node = self.targets[0]
buildError.exc_info = sys.exc_info() buildError.exc_info = sys.exc_info()
@ -305,7 +312,7 @@ class Task(object):
t.push_to_cache() t.push_to_cache()
t.built() t.built()
t.visited() t.visited()
if (not print_prepare and if (not print_prepare and
(not hasattr(self, 'options') or not self.options.debug_includes)): (not hasattr(self, 'options') or not self.options.debug_includes)):
t.release_target_info() t.release_target_info()
else: else:
@ -402,7 +409,7 @@ class Task(object):
t.disambiguate().make_ready() t.disambiguate().make_ready()
is_up_to_date = not t.has_builder() or \ is_up_to_date = not t.has_builder() or \
(not t.always_build and t.is_up_to_date()) (not t.always_build and t.is_up_to_date())
except EnvironmentError, e: except EnvironmentError as 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 not is_up_to_date: if not is_up_to_date:
@ -423,7 +430,7 @@ class Task(object):
# parallel build...) # parallel build...)
t.visited() t.visited()
t.set_state(NODE_UP_TO_DATE) t.set_state(NODE_UP_TO_DATE)
if (not print_prepare and if (not print_prepare and
(not hasattr(self, 'options') or not self.options.debug_includes)): (not hasattr(self, 'options') or not self.options.debug_includes)):
t.release_target_info() t.release_target_info()
@ -537,7 +544,23 @@ class Task(object):
except ValueError: except ValueError:
exc_type, exc_value = exc exc_type, exc_value = exc
exc_traceback = None exc_traceback = None
raise exc_type, exc_value, exc_traceback
# raise exc_type(exc_value).with_traceback(exc_traceback)
if sys.version_info[0] == 2:
exec("raise exc_type, exc_value, exc_traceback")
else: # sys.version_info[0] == 3:
if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'):
# If exc_value is an exception, then just reraise
exec("raise exc_value.with_traceback(exc_traceback)")
else:
# else we'll create an exception using the value and raise that
exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
# raise e.__class__, e.__class__(e), sys.exc_info()[2]
# exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
class AlwaysTask(Task): class AlwaysTask(Task):
def needs_execute(self): def needs_execute(self):
@ -669,14 +692,14 @@ class Taskmaster(object):
at node A. The Taskmaster first considers whether node A's at node A. The Taskmaster first considers whether node A's
child B is up-to-date. Then, recursively, node B needs to child B is up-to-date. Then, recursively, node B needs to
check whether node C is up-to-date. This leaves us with a check whether node C is up-to-date. This leaves us with a
dependency graph looking like: dependency graph looking like::
Next candidate \ Next candidate \
\ \
Node A (Pending) --> Node B(Pending) --> Node C (NoState) Node A (Pending) --> Node B(Pending) --> Node C (NoState)
^ | ^ |
| | | |
+-------------------------------------+ +-------------------------------------+
Now, when the Taskmaster examines the Node C's child Node A, Now, when the Taskmaster examines the Node C's child Node A,
it finds that Node A is in the "pending" state. Therefore, it finds that Node A is in the "pending" state. Therefore,
@ -685,15 +708,14 @@ class Taskmaster(object):
Pending children indicate that the Taskmaster has potentially Pending children indicate that the Taskmaster has potentially
loop back through a cycle. We say potentially because it could loop back through a cycle. We say potentially because it could
also occur when a DAG is evaluated in parallel. For example, also occur when a DAG is evaluated in parallel. For example,
consider the following graph: consider the following graph::
Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ...
Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... | ^
| ^ | |
| | +----------> Node D (NoState) --------+
+----------> Node D (NoState) --------+ /
/ Next candidate /
Next candidate /
The Taskmaster first evaluates the nodes A, B, and C and The Taskmaster first evaluates the nodes A, B, and C and
starts building some children of node C. Assuming, that the starts building some children of node C. Assuming, that the
@ -761,7 +783,7 @@ class Taskmaster(object):
self.ready_exc = None self.ready_exc = None
T = self.trace T = self.trace
if T: T.write(u'\n' + self.trace_message('Looking for a node to evaluate')) if T: T.write(SCons.Util.UnicodeType('\n') + self.trace_message('Looking for a node to evaluate'))
while True: while True:
node = self.next_candidate() node = self.next_candidate()
@ -810,7 +832,7 @@ class Taskmaster(object):
self.ready_exc = (SCons.Errors.ExplicitExit, e) self.ready_exc = (SCons.Errors.ExplicitExit, e)
if T: T.write(self.trace_message(' SystemExit')) if T: T.write(self.trace_message(' SystemExit'))
return node return node
except Exception, e: except Exception as e:
# We had a problem just trying to figure out the # We had a problem just trying to figure out the
# children (like a child couldn't be linked in to a # children (like a child couldn't be linked in to a
# VariantDir, or a Scanner threw something). Arrange to # VariantDir, or a Scanner threw something). Arrange to
@ -840,13 +862,13 @@ class Taskmaster(object):
if childstate <= NODE_EXECUTING: if childstate <= NODE_EXECUTING:
children_not_ready.append(child) children_not_ready.append(child)
# These nodes have not even been visited yet. Add # These nodes have not even been visited yet. Add
# them to the list so that on some next pass we can # them to the list so that on some next pass we can
# take a stab at evaluating them (or their children). # take a stab at evaluating them (or their children).
children_not_visited.reverse() children_not_visited.reverse()
self.candidates.extend(self.order(children_not_visited)) self.candidates.extend(self.order(children_not_visited))
#if T and children_not_visited:
# if T and children_not_visited:
# T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited))) # T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited)))
# T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates))) # T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates)))
@ -943,13 +965,13 @@ class Taskmaster(object):
executor = node.get_executor() executor = node.get_executor()
if executor is None: if executor is None:
return None return None
tlist = executor.get_all_targets() tlist = executor.get_all_targets()
task = self.tasker(self, tlist, node in self.original_top, node) task = self.tasker(self, tlist, node in self.original_top, node)
try: try:
task.make_ready() task.make_ready()
except: except Exception as e :
# We had a problem just trying to get this task ready (like # We had a problem just trying to get this task ready (like
# a child couldn't be linked to a VariantDir when deciding # a child couldn't be linked to a VariantDir when deciding
# whether this node is current). Arrange to raise the # whether this node is current). Arrange to raise the

View file

@ -10,7 +10,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -32,12 +32,12 @@ 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__ = "src/engine/SCons/Tool/386asm.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/386asm.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
from SCons.Tool.PharLapCommon import addPharLapPaths from SCons.Tool.PharLapCommon import addPharLapPaths
import SCons.Util import SCons.Util
as_module = __import__('as', globals(), locals(), []) as_module = __import__('as', globals(), locals(), [], 1)
def generate(env): def generate(env):
"""Add Builders and construction variables for ar to an Environment.""" """Add Builders and construction variables for ar to an Environment."""

View file

@ -1,3 +1,5 @@
from __future__ import print_function
"""SCons.Tool.DCommon """SCons.Tool.DCommon
Common code for the various D tools. Common code for the various D tools.
@ -5,8 +7,9 @@ Common code for the various D tools.
Coded by Russel Winder (russel@winder.org.uk) Coded by Russel Winder (russel@winder.org.uk)
2012-09-06 2012-09-06
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -28,10 +31,11 @@ Coded by Russel Winder (russel@winder.org.uk)
# 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__ = "src/engine/SCons/Tool/DCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/DCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path
def isD(env, source): def isD(env, source):
if not source: if not source:
return 0 return 0
@ -42,6 +46,7 @@ def isD(env, source):
return 1 return 1
return 0 return 0
def addDPATHToEnv(env, executable): def addDPATHToEnv(env, executable):
dPath = env.WhereIs(executable) dPath = env.WhereIs(executable)
if dPath: if dPath:
@ -49,6 +54,14 @@ def addDPATHToEnv(env, executable):
if os.path.isdir(phobosDir): if os.path.isdir(phobosDir):
env.Append(DPATH=[phobosDir]) env.Append(DPATH=[phobosDir])
def allAtOnceEmitter(target, source, env):
if env['DC'] in ('ldc2', 'dmd'):
env.SideEffect(str(target[0]) + '.o', target[0])
env.Clean(target[0], str(target[0]) + '.o')
return target, source
# Local Variables: # Local Variables:
# tab-width:4 # tab-width:4
# indent-tabs-mode:nil # indent-tabs-mode:nil

View file

@ -5,7 +5,7 @@ Stuff for processing Fortran, common to all fortran dialects.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -26,8 +26,9 @@ Stuff for processing Fortran, common to all fortran dialects.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
from __future__ import print_function
__revision__ = "src/engine/SCons/Tool/FortranCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/FortranCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import re import re
import os.path import os.path
@ -61,7 +62,7 @@ def isfortran(env, source):
def _fortranEmitter(target, source, env): def _fortranEmitter(target, source, env):
node = source[0].rfile() node = source[0].rfile()
if not node.exists() and not node.is_derived(): if not node.exists() and not node.is_derived():
print "Could not locate " + str(node.name) print("Could not locate " + str(node.name))
return ([], []) return ([], [])
mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
cre = re.compile(mod_regex,re.M) cre = re.compile(mod_regex,re.M)
@ -167,7 +168,7 @@ def add_fortran_to_env(env):
except KeyError: except KeyError:
FortranSuffixes = ['.f', '.for', '.ftn'] FortranSuffixes = ['.f', '.for', '.ftn']
#print "Adding %s to fortran suffixes" % FortranSuffixes #print("Adding %s to fortran suffixes" % FortranSuffixes)
try: try:
FortranPPSuffixes = env['FORTRANPPFILESUFFIXES'] FortranPPSuffixes = env['FORTRANPPFILESUFFIXES']
except KeyError: except KeyError:
@ -191,7 +192,7 @@ def add_f77_to_env(env):
except KeyError: except KeyError:
F77Suffixes = ['.f77'] F77Suffixes = ['.f77']
#print "Adding %s to f77 suffixes" % F77Suffixes #print("Adding %s to f77 suffixes" % F77Suffixes)
try: try:
F77PPSuffixes = env['F77PPFILESUFFIXES'] F77PPSuffixes = env['F77PPFILESUFFIXES']
except KeyError: except KeyError:
@ -206,7 +207,7 @@ def add_f90_to_env(env):
except KeyError: except KeyError:
F90Suffixes = ['.f90'] F90Suffixes = ['.f90']
#print "Adding %s to f90 suffixes" % F90Suffixes #print("Adding %s to f90 suffixes" % F90Suffixes)
try: try:
F90PPSuffixes = env['F90PPFILESUFFIXES'] F90PPSuffixes = env['F90PPFILESUFFIXES']
except KeyError: except KeyError:
@ -222,7 +223,7 @@ def add_f95_to_env(env):
except KeyError: except KeyError:
F95Suffixes = ['.f95'] F95Suffixes = ['.f95']
#print "Adding %s to f95 suffixes" % F95Suffixes #print("Adding %s to f95 suffixes" % F95Suffixes)
try: try:
F95PPSuffixes = env['F95PPFILESUFFIXES'] F95PPSuffixes = env['F95PPFILESUFFIXES']
except KeyError: except KeyError:
@ -238,7 +239,7 @@ def add_f03_to_env(env):
except KeyError: except KeyError:
F03Suffixes = ['.f03'] F03Suffixes = ['.f03']
#print "Adding %s to f95 suffixes" % F95Suffixes #print("Adding %s to f95 suffixes" % F95Suffixes)
try: try:
F03PPSuffixes = env['F03PPFILESUFFIXES'] F03PPSuffixes = env['F03PPFILESUFFIXES']
except KeyError: except KeyError:

View file

@ -0,0 +1,469 @@
"""SCons.Tool.GettextCommon module
Used by several tools of `gettext` toolset.
"""
# Copyright (c) 2001 - 2017 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/GettextCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Warnings
import re
#############################################################################
class XgettextToolWarning(SCons.Warnings.Warning): pass
class XgettextNotFound(XgettextToolWarning): pass
class MsginitToolWarning(SCons.Warnings.Warning): pass
class MsginitNotFound(MsginitToolWarning): pass
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
class MsgmergeNotFound(MsgmergeToolWarning): pass
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
class MsgfmtNotFound(MsgfmtToolWarning): pass
#############################################################################
SCons.Warnings.enableWarningClass(XgettextToolWarning)
SCons.Warnings.enableWarningClass(XgettextNotFound)
SCons.Warnings.enableWarningClass(MsginitToolWarning)
SCons.Warnings.enableWarningClass(MsginitNotFound)
SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
SCons.Warnings.enableWarningClass(MsgmergeNotFound)
SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
SCons.Warnings.enableWarningClass(MsgfmtNotFound)
#############################################################################
#############################################################################
class _POTargetFactory(object):
""" A factory of `PO` target files.
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
(this is required by builders and actions gettext) and `noclean` flags by
default for all produced nodes.
"""
def __init__(self, env, nodefault=True, alias=None, precious=True
, noclean=True):
""" Object constructor.
**Arguments**
- *env* (`SCons.Environment.Environment`)
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
from default target `'.'`
- *alias* (`string`) - if provided, produced nodes will be automatically
added to this alias, and alias will be set as `AlwaysBuild`
- *precious* (`boolean`) - if `True`, the produced nodes will be set as
`Precious`.
- *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
from `Clean`.
"""
self.env = env
self.alias = alias
self.precious = precious
self.noclean = noclean
self.nodefault = nodefault
def _create_node(self, name, factory, directory=None, create=1):
""" Create node, and set it up to factory settings. """
import SCons.Util
node = factory(name, directory, create)
node.set_noclean(self.noclean)
node.set_precious(self.precious)
if self.nodefault:
self.env.Ignore('.', node)
if self.alias:
self.env.AlwaysBuild(self.env.Alias(self.alias, node))
return node
def Entry(self, name, directory=None, create=1):
""" Create `SCons.Node.FS.Entry` """
return self._create_node(name, self.env.fs.Entry, directory, create)
def File(self, name, directory=None, create=1):
""" Create `SCons.Node.FS.File` """
return self._create_node(name, self.env.fs.File, directory, create)
#############################################################################
#############################################################################
_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
#############################################################################
def _read_linguas_from_files(env, linguas_files=None):
""" Parse `LINGUAS` file and return list of extracted languages """
import SCons.Util
import SCons.Environment
global _re_comment
global _re_lang
if not SCons.Util.is_List(linguas_files) \
and not SCons.Util.is_String(linguas_files) \
and not isinstance(linguas_files, SCons.Node.FS.Base) \
and linguas_files:
# If, linguas_files==True or such, then read 'LINGUAS' file.
linguas_files = ['LINGUAS']
if linguas_files is None:
return []
fnodes = env.arg2nodes(linguas_files)
linguas = []
for fnode in fnodes:
contents = _re_comment.sub("", fnode.get_text_contents())
ls = [l for l in _re_lang.findall(contents) if l]
linguas.extend(ls)
return linguas
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
#############################################################################
class _POFileBuilder(BuilderBase):
""" `PO` file builder.
This is multi-target single-source builder. In typical situation the source
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
targets to be updated from this `POT`. We must run
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
dependencies separatelly for each target file.
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
with target being list of all targets, all targets would be rebuilt each time
one of the targets from this list is missing. This would happen, for example,
when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
`ll.po` file yet). To avoid this, we override
`SCons.Builder.BuilerBase._execute()` and call it separatelly for each
target. Here we also append to the target list the languages read from
`LINGUAS_FILE`.
"""
#
# * The argument for overriding _execute(): We must use environment with
# builder overrides applied (see BuilderBase.__init__(). Here it comes for
# free.
# * The argument against using 'emitter': The emitter is called too late
# by BuilderBase._execute(). If user calls, for example:
#
# env.POUpdate(LINGUAS_FILE = 'LINGUAS')
#
# the builder throws error, because it is called with target=None,
# source=None and is trying to "generate" sources or target list first.
# If user calls
#
# env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
#
# the env.BuilderWrapper() calls our builder with target=None,
# source=['foo', 'baz']. The BuilderBase._execute() then splits execution
# and execute iterativelly (recursion) self._execute(None, source[i]).
# After that it calls emitter (which is quite too late). The emitter is
# also called in each iteration, what makes things yet worse.
def __init__(self, env, **kw):
if not 'suffix' in kw:
kw['suffix'] = '$POSUFFIX'
if not 'src_suffix' in kw:
kw['src_suffix'] = '$POTSUFFIX'
if not 'src_builder' in kw:
kw['src_builder'] = '_POTUpdateBuilder'
if not 'single_source' in kw:
kw['single_source'] = True
alias = None
if 'target_alias' in kw:
alias = kw['target_alias']
del kw['target_alias']
if not 'target_factory' in kw:
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
BuilderBase.__init__(self, **kw)
def _execute(self, env, target, source, *args, **kw):
""" Execute builder's actions.
Here we append to `target` the languages read from `$LINGUAS_FILE` and
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
The arguments and return value are same as for
`SCons.Builder.BuilderBase._execute()`.
"""
import SCons.Util
import SCons.Node
linguas_files = None
if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']:
linguas_files = env['LINGUAS_FILE']
# This prevents endless recursion loop (we'll be invoked once for
# each target appended here, we must not extend the list again).
env['LINGUAS_FILE'] = None
linguas = _read_linguas_from_files(env, linguas_files)
if SCons.Util.is_List(target):
target.extend(linguas)
elif target is not None:
target = [target] + linguas
else:
target = linguas
if not target:
# Let the SCons.BuilderBase to handle this patologic situation
return BuilderBase._execute(self, env, target, source, *args, **kw)
# The rest is ours
if not SCons.Util.is_List(target):
target = [target]
result = []
for tgt in target:
r = BuilderBase._execute(self, env, [tgt], source, *args, **kw)
result.extend(r)
if linguas_files is not None:
env['LINGUAS_FILE'] = linguas_files
return SCons.Node.NodeList(result)
#############################################################################
import SCons.Environment
#############################################################################
def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
""" Function for `Translate()` pseudo-builder """
if target is None: target = []
pot = env.POTUpdate(None, source, *args, **kw)
po = env.POUpdate(target, pot, *args, **kw)
return po
#############################################################################
#############################################################################
class RPaths(object):
""" Callable object, which returns pathnames relative to SCons current
working directory.
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
for nodes that are outside of current working directory (`env.fs.getcwd()`).
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
directory and source files (e.g. `*.c`) outside of it. When generating `POT`
template file, references to source files are written to `POT` template, so
a translator may later quickly jump to appropriate source file and line from
its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
interpreted by `PO` editor as paths relative to the place, where `PO` file
lives. The absolute paths would make resultant `POT` file nonportable, as
the references would be correct only on the machine, where `POT` file was
recently re-created. For such reason, we need a function, which always
returns relative paths. This is the purpose of `RPaths` callable object.
The `__call__` method returns paths relative to current working directory, but
we assume, that *xgettext(1)* is run from the directory, where target file is
going to be created.
Note, that this may not work for files distributed over several hosts or
across different drives on windows. We assume here, that single local
filesystem holds both source files and target `POT` templates.
Intended use of `RPaths` - in `xgettext.py`::
def generate(env):
from GettextCommon import RPaths
...
sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
env.Append(
...
XGETTEXTCOM = 'XGETTEXT ... ' + sources,
...
XgettextRPaths = RPaths(env)
)
"""
# NOTE: This callable object returns pathnames of dirs/files relative to
# current working directory. The pathname remains relative also for entries
# that are outside of current working directory (node, that
# SCons.Node.FS.File and siblings return absolute path in such case). For
# simplicity we compute path relative to current working directory, this
# seems be enough for our purposes (don't need TARGET variable and
# SCons.Defaults.Variable_Caller stuff).
def __init__(self, env):
""" Initialize `RPaths` callable object.
**Arguments**:
- *env* - a `SCons.Environment.Environment` object, defines *current
working dir*.
"""
self.env = env
# FIXME: I'm not sure, how it should be implemented (what the *args are in
# general, what is **kw).
def __call__(self, nodes, *args, **kw):
""" Return nodes' paths (strings) relative to current working directory.
**Arguments**:
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
- *args* - currently unused.
- *kw* - currently unused.
**Returns**:
- Tuple of strings, which represent paths relative to current working
directory (for given environment).
"""
import os
import SCons.Node.FS
rpaths = ()
cwd = self.env.fs.getcwd().get_abspath()
for node in nodes:
rpath = None
if isinstance(node, SCons.Node.FS.Base):
rpath = os.path.relpath(node.get_abspath(), cwd)
# FIXME: Other types possible here?
if rpath is not None:
rpaths += (rpath,)
return rpaths
#############################################################################
#############################################################################
def _init_po_files(target, source, env):
""" Action function for `POInit` builder. """
nop = lambda target, source, env: 0
if 'POAUTOINIT' in env:
autoinit = env['POAUTOINIT']
else:
autoinit = False
# Well, if everything outside works well, this loop should do single
# iteration. Otherwise we are rebuilding all the targets even, if just
# one has changed (but is this our fault?).
for tgt in target:
if not tgt.exists():
if autoinit:
action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
else:
msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
+ 'If you are a translator, you can create it through: \n' \
+ '$MSGINITCOM'
action = SCons.Action.Action(nop, msg)
status = action([tgt], source, env)
if status: return status
return 0
#############################################################################
#############################################################################
def _detect_xgettext(env):
""" Detects *xgettext(1)* binary """
if 'XGETTEXT' in env:
return env['XGETTEXT']
xgettext = env.Detect('xgettext');
if xgettext:
return xgettext
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
return None
#############################################################################
def _xgettext_exists(env):
return _detect_xgettext(env)
#############################################################################
#############################################################################
def _detect_msginit(env):
""" Detects *msginit(1)* program. """
if 'MSGINIT' in env:
return env['MSGINIT']
msginit = env.Detect('msginit');
if msginit:
return msginit
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
return None
#############################################################################
def _msginit_exists(env):
return _detect_msginit(env)
#############################################################################
#############################################################################
def _detect_msgmerge(env):
""" Detects *msgmerge(1)* program. """
if 'MSGMERGE' in env:
return env['MSGMERGE']
msgmerge = env.Detect('msgmerge');
if msgmerge:
return msgmerge
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
return None
#############################################################################
def _msgmerge_exists(env):
return _detect_msgmerge(env)
#############################################################################
#############################################################################
def _detect_msgfmt(env):
""" Detects *msgmfmt(1)* program. """
if 'MSGFMT' in env:
return env['MSGFMT']
msgfmt = env.Detect('msgfmt');
if msgfmt:
return msgfmt
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
return None
#############################################################################
def _msgfmt_exists(env):
return _detect_msgfmt(env)
#############################################################################
#############################################################################
def tool_list(platform, env):
""" List tools that shall be generated by top-level `gettext` tool """
return ['xgettext', 'msginit', 'msgmerge', 'msgfmt']
#############################################################################

View file

@ -5,7 +5,7 @@ Stuff for processing Java.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/JavaCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/JavaCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import os.path import os.path

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/MSCommon/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """ __doc__ = """
Common functions for Microsoft Visual Studio and Visual C/C++. Common functions for Microsoft Visual Studio and Visual C/C++.
@ -41,7 +41,8 @@ from SCons.Tool.MSCommon.sdk import mssdk_exists, \
from SCons.Tool.MSCommon.vc import msvc_exists, \ from SCons.Tool.MSCommon.vc import msvc_exists, \
msvc_setup_env, \ msvc_setup_env, \
msvc_setup_env_once msvc_setup_env_once, \
msvc_version_to_maj_min
from SCons.Tool.MSCommon.vs import get_default_version, \ from SCons.Tool.MSCommon.vs import get_default_version, \
get_vs_by_version, \ get_vs_by_version, \

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/MSCommon/arch.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/arch.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Module to define supported Windows chip architectures. __doc__ = """Module to define supported Windows chip architectures.
""" """

View file

@ -1,5 +1,8 @@
"""
Common helper functions for working with the Microsoft tool chain.
"""
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -20,12 +23,9 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
from __future__ import print_function
__revision__ = "src/engine/SCons/Tool/MSCommon/common.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/common.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """
Common helper functions for working with the Microsoft tool chain.
"""
import copy import copy
import os import os
@ -35,17 +35,17 @@ import re
import SCons.Util import SCons.Util
logfile = os.environ.get('SCONS_MSCOMMON_DEBUG') LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG')
if logfile == '-': if LOGFILE == '-':
def debug(x): def debug(message):
print x print(message)
elif logfile: elif LOGFILE:
try: try:
import logging import logging
except ImportError: except ImportError:
debug = lambda x: open(logfile, 'a').write(x + '\n') debug = lambda message: open(LOGFILE, 'a').write(message + '\n')
else: else:
logging.basicConfig(filename=logfile, level=logging.DEBUG) logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
debug = logging.debug debug = logging.debug
else: else:
debug = lambda x: None debug = lambda x: None
@ -75,7 +75,7 @@ def is_win64():
# I structured these tests to make it easy to add new ones or # I structured these tests to make it easy to add new ones or
# add exceptions in the future, because this is a bit fragile. # add exceptions in the future, because this is a bit fragile.
_is_win64 = False _is_win64 = False
if os.environ.get('PROCESSOR_ARCHITECTURE','x86') != 'x86': if os.environ.get('PROCESSOR_ARCHITECTURE', 'x86') != 'x86':
_is_win64 = True _is_win64 = True
if os.environ.get('PROCESSOR_ARCHITEW6432'): if os.environ.get('PROCESSOR_ARCHITEW6432'):
_is_win64 = True _is_win64 = True
@ -113,21 +113,30 @@ def normalize_env(env, keys, force=False):
Note: the environment is copied.""" Note: the environment is copied."""
normenv = {} normenv = {}
if env: if env:
for k in env.keys(): for k in list(env.keys()):
normenv[k] = copy.deepcopy(env[k]).encode('mbcs') normenv[k] = copy.deepcopy(env[k])
for k in keys: for k in keys:
if k in os.environ and (force or not k in normenv): if k in os.environ and (force or not k in normenv):
normenv[k] = os.environ[k].encode('mbcs') normenv[k] = os.environ[k]
# This shouldn't be necessary, since the default environment should include system32, # This shouldn't be necessary, since the default environment should include system32,
# but keep this here to be safe, since it's needed to find reg.exe which the MSVC # but keep this here to be safe, since it's needed to find reg.exe which the MSVC
# bat scripts use. # bat scripts use.
sys32_dir = os.path.join(os.environ.get("SystemRoot", os.environ.get("windir",r"C:\Windows\system32")),"System32") sys32_dir = os.path.join(os.environ.get("SystemRoot",
os.environ.get("windir", r"C:\Windows\system32")),
"System32")
if sys32_dir not in normenv['PATH']: if sys32_dir not in normenv['PATH']:
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir
# Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
# error starting with Visual Studio 2017, although the script still
# seems to work anyway.
sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem')
if sys32_wbem_dir not in normenv['PATH']:
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
debug("PATH: %s"%normenv['PATH']) debug("PATH: %s"%normenv['PATH'])
return normenv return normenv
@ -144,11 +153,13 @@ def get_output(vcbat, args = None, env = None):
# execution to work. This list should really be either directly # execution to work. This list should really be either directly
# controlled by vc.py, or else derived from the common_tools_var # controlled by vc.py, or else derived from the common_tools_var
# settings in vs.py. # settings in vs.py.
vars = [ vs_vc_vars = [
'COMSPEC', 'COMSPEC',
# VS100 and VS110: Still set, but modern MSVC setup scripts will # VS100 and VS110: Still set, but modern MSVC setup scripts will
# discard these if registry has values. However Intel compiler setup # discard these if registry has values. However Intel compiler setup
# script still requires these as of 2013/2014. # script still requires these as of 2013/2014.
'VS140COMNTOOLS',
'VS120COMNTOOLS',
'VS110COMNTOOLS', 'VS110COMNTOOLS',
'VS100COMNTOOLS', 'VS100COMNTOOLS',
'VS90COMNTOOLS', 'VS90COMNTOOLS',
@ -157,22 +168,22 @@ def get_output(vcbat, args = None, env = None):
'VS70COMNTOOLS', 'VS70COMNTOOLS',
'VS60COMNTOOLS', 'VS60COMNTOOLS',
] ]
env['ENV'] = normalize_env(env['ENV'], vars, force=False) env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False)
if args: if args:
debug("Calling '%s %s'" % (vcbat, args)) debug("Calling '%s %s'" % (vcbat, args))
popen = SCons.Action._subproc(env, popen = SCons.Action._subproc(env,
'"%s" %s & set' % (vcbat, args), '"%s" %s & set' % (vcbat, args),
stdin = 'devnull', stdin='devnull',
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
else: else:
debug("Calling '%s'" % vcbat) debug("Calling '%s'" % vcbat)
popen = SCons.Action._subproc(env, popen = SCons.Action._subproc(env,
'"%s" & set' % vcbat, '"%s" & set' % vcbat,
stdin = 'devnull', stdin='devnull',
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
# Use the .stdout and .stderr attributes directly because the # Use the .stdout and .stderr attributes directly because the
# .communicate() method uses the threading module on Windows # .communicate() method uses the threading module on Windows
@ -195,10 +206,14 @@ def get_output(vcbat, args = None, env = None):
output = stdout.decode("mbcs") output = stdout.decode("mbcs")
return output return output
def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH")):
"""
Parse output from running visual c++/studios vcvarsall.bat and running set
To capture the values listed in keep
"""
# dkeep is a dict associating key: path_list, where key is one item from # dkeep is a dict associating key: path_list, where key is one item from
# keep, and pat_list the associated list of paths # keep, and pat_list the associated list of paths
dkeep = dict([(i, []) for i in keep]) dkeep = dict([(i, []) for i in keep])
# rdk will keep the regex to match the .bat file output line starts # rdk will keep the regex to match the .bat file output line starts
@ -207,22 +222,21 @@ def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")):
rdk[i] = re.compile('%s=(.*)' % i, re.I) rdk[i] = re.compile('%s=(.*)' % i, re.I)
def add_env(rmatch, key, dkeep=dkeep): def add_env(rmatch, key, dkeep=dkeep):
plist = rmatch.group(1).split(os.pathsep) path_list = rmatch.group(1).split(os.pathsep)
for p in plist: for path in path_list:
# Do not add empty paths (when a var ends with ;) # Do not add empty paths (when a var ends with ;)
if p: if path:
p = p.encode('mbcs')
# XXX: For some reason, VC98 .bat file adds "" around the PATH # XXX: For some reason, VC98 .bat file adds "" around the PATH
# values, and it screws up the environment later, so we strip # values, and it screws up the environment later, so we strip
# it. # it.
p = p.strip('"') path = path.strip('"')
dkeep[key].append(p) dkeep[key].append(str(path))
for line in output.splitlines(): for line in output.splitlines():
for k,v in rdk.items(): for k, value in rdk.items():
m = v.match(line) match = value.match(line)
if m: if match:
add_env(m, k) add_env(match, k)
return dkeep return dkeep

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -20,7 +20,7 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Tool/MSCommon/netframework.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """ __doc__ = """
""" """
@ -29,7 +29,7 @@ import os
import re import re
import SCons.Util import SCons.Util
from common import read_reg, debug from .common import read_reg, debug
# Original value recorded by dcournapeau # Original value recorded by dcournapeau
_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot' _FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot'
@ -40,13 +40,13 @@ def find_framework_root():
# XXX: find it from environment (FrameworkDir) # XXX: find it from environment (FrameworkDir)
try: try:
froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT) froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT)
debug("Found framework install root in registry: %s" % froot) debug("Found framework install root in registry: {}".format(froot))
except SCons.Util.WinError, e: except SCons.Util.WinError as e:
debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT) debug("Could not read reg key {}".format(_FRAMEWORKDIR_HKEY_ROOT))
return None return None
if not os.path.exists(froot): if not os.path.exists(froot):
debug("%s not found on fs" % froot) debug("{} not found on fs".format(froot))
return None return None
return froot return froot

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/MSCommon/sdk.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Module to detect the Platform/Windows SDK __doc__ = """Module to detect the Platform/Windows SDK
@ -33,7 +33,7 @@ import os
import SCons.Errors import SCons.Errors
import SCons.Util import SCons.Util
import common from . import common
debug = common.debug debug = common.debug
@ -76,23 +76,23 @@ class SDKDefinition(object):
return None return None
hkey = self.HKEY_FMT % self.hkey_data hkey = self.HKEY_FMT % self.hkey_data
debug('find_sdk_dir(): checking registry:%s'%hkey) debug('find_sdk_dir(): checking registry:{}'.format(hkey))
try: try:
sdk_dir = common.read_reg(hkey) sdk_dir = common.read_reg(hkey)
except SCons.Util.WinError, e: except SCons.Util.WinError as e:
debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey)) debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
return None return None
debug('find_sdk_dir(): Trying SDK Dir: %s'%sdk_dir) debug('find_sdk_dir(): Trying SDK Dir: {}'.format(sdk_dir))
if not os.path.exists(sdk_dir): if not os.path.exists(sdk_dir):
debug('find_sdk_dir(): %s not on file system' % sdk_dir) debug('find_sdk_dir(): {} not on file system'.format(sdk_dir))
return None return None
ftc = os.path.join(sdk_dir, self.sanity_check_file) ftc = os.path.join(sdk_dir, self.sanity_check_file)
if not os.path.exists(ftc): if not os.path.exists(ftc):
debug("find_sdk_dir(): sanity check %s not found" % ftc) debug("find_sdk_dir(): sanity check {} not found".format(ftc))
return None return None
return sdk_dir return sdk_dir
@ -105,7 +105,7 @@ class SDKDefinition(object):
sdk_dir = self.find_sdk_dir() sdk_dir = self.find_sdk_dir()
self._sdk_dir = sdk_dir self._sdk_dir = sdk_dir
return sdk_dir return sdk_dir
def get_sdk_vc_script(self,host_arch, target_arch): def get_sdk_vc_script(self,host_arch, target_arch):
""" Return the script to initialize the VC compiler installed by SDK """ Return the script to initialize the VC compiler installed by SDK
""" """
@ -113,11 +113,11 @@ class SDKDefinition(object):
if (host_arch == 'amd64' and target_arch == 'x86'): if (host_arch == 'amd64' and target_arch == 'x86'):
# No cross tools needed compiling 32 bits on 64 bit machine # No cross tools needed compiling 32 bits on 64 bit machine
host_arch=target_arch host_arch=target_arch
arch_string=target_arch arch_string=target_arch
if (host_arch != target_arch): if (host_arch != target_arch):
arch_string='%s_%s'%(host_arch,target_arch) arch_string='%s_%s'%(host_arch,target_arch)
debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string, debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
host_arch, host_arch,
target_arch)) target_arch))
@ -164,6 +164,12 @@ SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
'x86_ia64' : r'bin\vcvarsx86_ia64.bat', 'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
'ia64' : r'bin\vcvarsia64.bat'} 'ia64' : r'bin\vcvarsia64.bat'}
SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
'amd64' : r'bin\vcvars64.bat',
'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'}
# The list of support SDKs which we know how to detect. # The list of support SDKs which we know how to detect.
# #
# The first SDK found in the list is the one used by default if there # The first SDK found in the list is the one used by default if there
@ -172,6 +178,16 @@ SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
# #
# If you update this list, update the documentation in Tool/mssdk.xml. # If you update this list, update the documentation in Tool/mssdk.xml.
SupportedSDKList = [ SupportedSDKList = [
WindowsSDK('10.0',
sanity_check_file=r'bin\SetEnv.Cmd',
include_subdir='include',
lib_subdir={
'x86' : ['lib'],
'x86_64' : [r'lib\x64'],
'ia64' : [r'lib\ia64'],
},
vc_setup_scripts = SDK70VCSetupScripts,
),
WindowsSDK('7.1', WindowsSDK('7.1',
sanity_check_file=r'bin\SetEnv.Cmd', sanity_check_file=r'bin\SetEnv.Cmd',
include_subdir='include', include_subdir='include',
@ -308,8 +324,7 @@ def set_sdk_by_directory(env, sdk_dir):
def get_sdk_by_version(mssdk): def get_sdk_by_version(mssdk):
if mssdk not in SupportedSDKMap: if mssdk not in SupportedSDKMap:
msg = "SDK version %s is not supported" % repr(mssdk) raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk)))
raise SCons.Errors.UserError(msg)
get_installed_sdks() get_installed_sdks()
return InstalledSDKMap.get(mssdk) return InstalledSDKMap.get(mssdk)
@ -327,16 +342,16 @@ def mssdk_setup_env(env):
if sdk_dir is None: if sdk_dir is None:
return return
sdk_dir = env.subst(sdk_dir) sdk_dir = env.subst(sdk_dir)
debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:%s'%sdk_dir) debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
elif 'MSSDK_VERSION' in env: elif 'MSSDK_VERSION' in env:
sdk_version = env['MSSDK_VERSION'] sdk_version = env['MSSDK_VERSION']
if sdk_version is None: if sdk_version is None:
msg = "SDK version is specified as None" msg = "SDK version is specified as None"
raise SCons.Errors.UserError(msg) raise SCons.Errors.UserError(msg)
sdk_version = env.subst(sdk_version) sdk_version = env.subst(sdk_version)
mssdk = get_sdk_by_version(sdk_version) mssdk = get_sdk_by_version(sdk_version)
if mssdk is None: if mssdk is None:
msg = "SDK version %s is not installed" % sdk_version msg = "SDK version %s is not installed" % sdk_version
raise SCons.Errors.UserError(msg) raise SCons.Errors.UserError(msg)
sdk_dir = mssdk.get_sdk_dir() sdk_dir = mssdk.get_sdk_dir()
debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir) debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
@ -347,7 +362,7 @@ def mssdk_setup_env(env):
debug('sdk.py:mssdk_setup_env thinks msvs_version is None') debug('sdk.py:mssdk_setup_env thinks msvs_version is None')
return return
msvs_version = env.subst(msvs_version) msvs_version = env.subst(msvs_version)
import vs from . import vs
msvs = vs.get_vs_by_version(msvs_version) msvs = vs.get_vs_by_version(msvs_version)
debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs) debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs)
if not msvs: if not msvs:

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,24 +30,25 @@
# * test on 64 bits XP + VS 2005 (and VS 6 if possible) # * test on 64 bits XP + VS 2005 (and VS 6 if possible)
# * SDK # * SDK
# * Assembly # * Assembly
__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/vc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Module for Visual C/C++ detection and configuration. __doc__ = """Module for Visual C/C++ detection and configuration.
""" """
import SCons.compat import SCons.compat
import SCons.Util import SCons.Util
import subprocess
import os import os
import platform import platform
from string import digits as string_digits from string import digits as string_digits
import SCons.Warnings import SCons.Warnings
import common from . import common
debug = common.debug debug = common.debug
import sdk from . import sdk
get_installed_sdks = sdk.get_installed_sdks get_installed_sdks = sdk.get_installed_sdks
@ -108,7 +109,7 @@ def get_host_target(env):
# PROCESSOR_ARCHITECTURE. # PROCESSOR_ARCHITECTURE.
if not host_platform: if not host_platform:
host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
# Retain user requested TARGET_ARCH # Retain user requested TARGET_ARCH
req_target_platform = env.get('TARGET_ARCH') req_target_platform = env.get('TARGET_ARCH')
debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform) debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform)
@ -118,26 +119,28 @@ def get_host_target(env):
target_platform = req_target_platform target_platform = req_target_platform
else: else:
target_platform = host_platform target_platform = host_platform
try: try:
host = _ARCH_TO_CANONICAL[host_platform.lower()] host = _ARCH_TO_CANONICAL[host_platform.lower()]
except KeyError, e: except KeyError as e:
msg = "Unrecognized host architecture %s" msg = "Unrecognized host architecture %s"
raise ValueError(msg % repr(host_platform)) raise ValueError(msg % repr(host_platform))
try: try:
target = _ARCH_TO_CANONICAL[target_platform.lower()] target = _ARCH_TO_CANONICAL[target_platform.lower()]
except KeyError, e: except KeyError as e:
all_archs = str(_ARCH_TO_CANONICAL.keys()) all_archs = str(list(_ARCH_TO_CANONICAL.keys()))
raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs)) raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
return (host, target,req_target_platform) return (host, target,req_target_platform)
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the # If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
# MSVC_VERSION documentation in Tool/msvc.xml. # MSVC_VERSION documentation in Tool/msvc.xml.
_VCVER = ["14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"] _VCVER = ["14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
_VCVER_TO_PRODUCT_DIR = { _VCVER_TO_PRODUCT_DIR = {
'14.1' : [
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore
'14.0' : [ '14.0' : [
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')], (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
'14.0Exp' : [ '14.0Exp' : [
@ -183,19 +186,19 @@ _VCVER_TO_PRODUCT_DIR = {
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'), (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'),
] ]
} }
def msvc_version_to_maj_min(msvc_version):
msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
t = msvc_version_numeric.split(".") def msvc_version_to_maj_min(msvc_version):
if not len(t) == 2: msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
try: t = msvc_version_numeric.split(".")
maj = int(t[0]) if not len(t) == 2:
min = int(t[1]) raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
return maj, min try:
except ValueError, e: maj = int(t[0])
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) min = int(t[1])
return maj, min
except ValueError as e:
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
def is_host_target_supported(host_target, msvc_version): def is_host_target_supported(host_target, msvc_version):
"""Return True if the given (host, target) tuple is supported given the """Return True if the given (host, target) tuple is supported given the
@ -222,6 +225,35 @@ def is_host_target_supported(host_target, msvc_version):
return True return True
def find_vc_pdir_vswhere(msvc_version):
"""
Find the MSVC product directory using vswhere.exe .
Run it asking for specified version and get MSVS install location
:param msvc_version:
:return: MSVC install dir
"""
vswhere_path = os.path.join(
'C:\\',
'Program Files (x86)',
'Microsoft Visual Studio',
'Installer',
'vswhere.exe'
)
vswhere_cmd = [vswhere_path, '-version', msvc_version, '-property', 'installationPath']
if os.path.exists(vswhere_path):
sp = subprocess.Popen(vswhere_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
vsdir, err = sp.communicate()
vsdir = vsdir.decode("mbcs")
vsdir = vsdir.rstrip()
vc_pdir = os.path.join(vsdir, 'VC')
return vc_pdir
else:
# No vswhere on system, no install info available
return None
def find_vc_pdir(msvc_version): def find_vc_pdir(msvc_version):
"""Try to find the product directory for the given """Try to find the product directory for the given
version. version.
@ -240,26 +272,31 @@ def find_vc_pdir(msvc_version):
for hkroot, key in hkeys: for hkroot, key in hkeys:
try: try:
comps = None comps = None
if common.is_win64(): if not key:
try: comps = find_vc_pdir_vswhere(msvc_version)
# ordinally at win64, try Wow6432Node first. if not comps:
comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot) debug('find_vc_dir(): no VC found via vswhere for version {}'.format(repr(key)))
except SCons.Util.WinError, e: raise SCons.Util.WinError
# at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node else:
pass if common.is_win64():
if not comps: try:
# not Win64, or Microsoft Visual Studio for Python 2.7 # ordinally at win64, try Wow6432Node first.
comps = common.read_reg(root + key, hkroot) comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
except SCons.Util.WinError, e: except SCons.Util.WinError as e:
debug('find_vc_dir(): no VC registry key %s' % repr(key)) # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node
pass
if not comps:
# not Win64, or Microsoft Visual Studio for Python 2.7
comps = common.read_reg(root + key, hkroot)
except SCons.Util.WinError as e:
debug('find_vc_dir(): no VC registry key {}'.format(repr(key)))
else: else:
debug('find_vc_dir(): found VC in registry: %s' % comps) debug('find_vc_dir(): found VC in registry: {}'.format(comps))
if os.path.exists(comps): if os.path.exists(comps):
return comps return comps
else: else:
debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\ debug('find_vc_dir(): reg says dir is {}, but it does not exist. (ignoring)'.format(comps))
% comps) raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps))
raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
return None return None
def find_batch_file(env,msvc_version,host_arch,target_arch): def find_batch_file(env,msvc_version,host_arch,target_arch):
@ -270,8 +307,8 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
pdir = find_vc_pdir(msvc_version) pdir = find_vc_pdir(msvc_version)
if pdir is None: if pdir is None:
raise NoVersionFound("No version of Visual Studio found") raise NoVersionFound("No version of Visual Studio found")
debug('vc.py: find_batch_file() pdir:%s'%pdir) debug('vc.py: find_batch_file() pdir:{}'.format(pdir))
# filter out e.g. "Exp" from the version name # filter out e.g. "Exp" from the version name
msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."]) msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
@ -282,13 +319,15 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
elif vernum < 7: elif vernum < 7:
pdir = os.path.join(pdir, "Bin") pdir = os.path.join(pdir, "Bin")
batfilename = os.path.join(pdir, "vcvars32.bat") batfilename = os.path.join(pdir, "vcvars32.bat")
else: # >= 8 elif 8 <= vernum <= 14:
batfilename = os.path.join(pdir, "vcvarsall.bat") batfilename = os.path.join(pdir, "vcvarsall.bat")
else: # vernum >= 14.1 VS2017 and above
batfilename = os.path.join(pdir, "Auxiliary", "Build", "vcvarsall.bat")
if not os.path.exists(batfilename): if not os.path.exists(batfilename):
debug("Not found: %s" % batfilename) debug("Not found: %s" % batfilename)
batfilename = None batfilename = None
installed_sdks=get_installed_sdks() installed_sdks=get_installed_sdks()
for _sdk in installed_sdks: for _sdk in installed_sdks:
sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch) sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch)
@ -296,7 +335,7 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
debug("vc.py:find_batch_file() not found:%s"%_sdk) debug("vc.py:find_batch_file() not found:%s"%_sdk)
else: else:
sdk_bat_file_path = os.path.join(pdir,sdk_bat_file) sdk_bat_file_path = os.path.join(pdir,sdk_bat_file)
if os.path.exists(sdk_bat_file_path): if os.path.exists(sdk_bat_file_path):
debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path) debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path)
return (batfilename,sdk_bat_file_path) return (batfilename,sdk_bat_file_path)
return (batfilename,None) return (batfilename,None)
@ -323,7 +362,7 @@ def get_installed_vcs():
installed_versions.append(ver) installed_versions.append(ver)
else: else:
debug('find_vc_pdir return None for ver %s' % ver) debug('find_vc_pdir return None for ver %s' % ver)
except VisualCException, e: except VisualCException as e:
debug('did not find VC %s: caught exception %s' % (ver, str(e))) debug('did not find VC %s: caught exception %s' % (ver, str(e)))
return installed_versions return installed_versions
@ -359,7 +398,7 @@ def get_default_version(env):
msvc_version = env.get('MSVC_VERSION') msvc_version = env.get('MSVC_VERSION')
msvs_version = env.get('MSVS_VERSION') msvs_version = env.get('MSVS_VERSION')
debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version)) debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
if msvs_version and not msvc_version: if msvs_version and not msvc_version:
@ -409,7 +448,7 @@ def msvc_find_valid_batch_script(env,version):
try_target_archs = [target_platform] try_target_archs = [target_platform]
debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform)) debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform))
# VS2012 has a "cross compile" environment to build 64 bit # VS2012 has a "cross compile" environment to build 64 bit
# with x86_amd64 as the argument to the batch setup script # with x86_amd64 as the argument to the batch setup script
if req_target_platform in ('amd64','x86_64'): if req_target_platform in ('amd64','x86_64'):
try_target_archs.append('x86_amd64') try_target_archs.append('x86_amd64')
@ -427,7 +466,7 @@ def msvc_find_valid_batch_script(env,version):
for tp in try_target_archs: for tp in try_target_archs:
# Set to current arch. # Set to current arch.
env['TARGET_ARCH']=tp env['TARGET_ARCH']=tp
debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp) debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp)
host_target = (host_platform, tp) host_target = (host_platform, tp)
if not is_host_target_supported(host_target, version): if not is_host_target_supported(host_target, version):
@ -436,11 +475,19 @@ def msvc_find_valid_batch_script(env,version):
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target] arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
# Get just version numbers
maj, min = msvc_version_to_maj_min(version)
# VS2015+
if maj >= 14:
if env.get('MSVC_UWP_APP') == '1':
# Initialize environment variables with store/universal paths
arg += ' store'
# Try to locate a batch file for this host/target platform combo # Try to locate a batch file for this host/target platform combo
try: try:
(vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp) (vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp)
debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
except VisualCException, e: except VisualCException as e:
msg = str(e) msg = str(e)
debug('Caught exception while looking for batch file (%s)' % msg) debug('Caught exception while looking for batch file (%s)' % msg)
warn_msg = "VC version %s not installed. " + \ warn_msg = "VC version %s not installed. " + \
@ -449,13 +496,13 @@ def msvc_find_valid_batch_script(env,version):
warn_msg = warn_msg % (version, cached_get_installed_vcs()) warn_msg = warn_msg % (version, cached_get_installed_vcs())
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
continue continue
# Try to use the located batch file for this host/target platform combo # Try to use the located batch file for this host/target platform combo
debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg)) debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
if vc_script: if vc_script:
try: try:
d = script_env(vc_script, args=arg) d = script_env(vc_script, args=arg)
except BatchFileExecutionError, e: except BatchFileExecutionError as e:
debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e)) debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
vc_script=None vc_script=None
continue continue
@ -463,23 +510,23 @@ def msvc_find_valid_batch_script(env,version):
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script)) debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
try: try:
d = script_env(sdk_script) d = script_env(sdk_script)
except BatchFileExecutionError,e: except BatchFileExecutionError as e:
debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e)) debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
continue continue
elif not vc_script and not sdk_script: elif not vc_script and not sdk_script:
debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found') debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
continue continue
debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg)) debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg))
break # We've found a working target_platform, so stop looking break # We've found a working target_platform, so stop looking
# If we cannot find a viable installed compiler, reset the TARGET_ARCH # If we cannot find a viable installed compiler, reset the TARGET_ARCH
# To it's initial value # To it's initial value
if not d: if not d:
env['TARGET_ARCH']=req_target_platform env['TARGET_ARCH']=req_target_platform
return d return d
def msvc_setup_env(env): def msvc_setup_env(env):
debug('msvc_setup_env()') debug('msvc_setup_env()')
@ -498,12 +545,12 @@ def msvc_setup_env(env):
env['MSVS_VERSION'] = version env['MSVS_VERSION'] = version
env['MSVS'] = {} env['MSVS'] = {}
use_script = env.get('MSVC_USE_SCRIPT', True) use_script = env.get('MSVC_USE_SCRIPT', True)
if SCons.Util.is_String(use_script): if SCons.Util.is_String(use_script):
debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script)) debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script))
d = script_env(use_script) d = script_env(use_script)
elif use_script: elif use_script:
d = msvc_find_valid_batch_script(env,version) d = msvc_find_valid_batch_script(env,version)
debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d) debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d)
if not d: if not d:
@ -524,4 +571,3 @@ def msvc_exists(version=None):
if version is None: if version is None:
return len(vcs) > 0 return len(vcs) > 0
return version in vcs return version in vcs

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/MSCommon/vs.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/MSCommon/vs.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
__doc__ = """Module to detect Visual Studio and/or Visual C/C++ __doc__ = """Module to detect Visual Studio and/or Visual C/C++
""" """
@ -31,7 +31,7 @@ import os
import SCons.Errors import SCons.Errors
import SCons.Util import SCons.Util
from common import debug, \ from .common import debug, \
get_output, \ get_output, \
is_win64, \ is_win64, \
normalize_env, \ normalize_env, \
@ -83,10 +83,10 @@ class VisualStudio(object):
key = root + key key = root + key
try: try:
comps = read_reg(key) comps = read_reg(key)
except SCons.Util.WinError, e: except SCons.Util.WinError as e:
debug('find_vs_dir_by_reg(): no VS registry key %s' % repr(key)) debug('find_vs_dir_by_reg(): no VS registry key {}'.format(repr(key)))
else: else:
debug('find_vs_dir_by_reg(): found VS in registry: %s' % comps) debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps))
return comps return comps
return None return None
@ -105,12 +105,12 @@ class VisualStudio(object):
def find_executable(self): def find_executable(self):
vs_dir = self.get_vs_dir() vs_dir = self.get_vs_dir()
if not vs_dir: if not vs_dir:
debug('find_executable(): no vs_dir (%s)'%vs_dir) debug('find_executable(): no vs_dir ({})'.format(vs_dir))
return None return None
executable = os.path.join(vs_dir, self.executable_path) executable = os.path.join(vs_dir, self.executable_path)
executable = os.path.normpath(executable) executable = os.path.normpath(executable)
if not os.path.isfile(executable): if not os.path.isfile(executable):
debug('find_executable(): %s not on file system' % executable) debug('find_executable(): {} not on file system'.format(executable))
return None return None
return executable return executable
@ -199,17 +199,28 @@ class VisualStudio(object):
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml. # Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
SupportedVSList = [ SupportedVSList = [
# Visual Studio 2017
VisualStudio('14.1',
vc_version='14.1',
sdk_version='10.0A',
hkeys=[],
common_tools_var='VS150COMNTOOLS',
executable_path=r'Common7\IDE\devenv.com',
batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat',
supported_arch=['x86', 'amd64', "arm"],
),
# Visual Studio 2015 # Visual Studio 2015
VisualStudio('14.0', VisualStudio('14.0',
vc_version='14.0', vc_version='14.0',
sdk_version='10.0A', sdk_version='10.0',
hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'], hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
common_tools_var='VS140COMNTOOLS', common_tools_var='VS140COMNTOOLS',
executable_path=r'Common7\IDE\devenv.com', executable_path=r'Common7\IDE\devenv.com',
batch_file_path=r'Common7\Tools\vsvars32.bat', batch_file_path=r'Common7\Tools\vsvars32.bat',
supported_arch=['x86', 'amd64', "arm"], supported_arch=['x86', 'amd64', "arm"],
), ),
# Visual C++ 2015 Express Edition (for Desktop) # Visual C++ 2015 Express Edition (for Desktop)
VisualStudio('14.0Exp', VisualStudio('14.0Exp',
vc_version='14.0', vc_version='14.0',

View file

@ -7,7 +7,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/PharLapCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/PharLapCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import os.path import os.path

View file

@ -14,7 +14,7 @@ tool definition.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -35,14 +35,16 @@ tool definition.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# 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__ = "src/engine/SCons/Tool/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import imp import imp
import importlib
import sys import sys
import re import re
import os import os
import shutil import shutil
import SCons.Builder import SCons.Builder
import SCons.Errors import SCons.Errors
import SCons.Node.FS import SCons.Node.FS
@ -52,6 +54,7 @@ import SCons.Scanner.D
import SCons.Scanner.LaTeX import SCons.Scanner.LaTeX
import SCons.Scanner.Prog import SCons.Scanner.Prog
import SCons.Scanner.SWIG import SCons.Scanner.SWIG
import collections
DefaultToolpath=[] DefaultToolpath=[]
@ -94,9 +97,20 @@ for suffix in LaTeXSuffixes:
SourceFileScanner.add_scanner(suffix, LaTeXScanner) SourceFileScanner.add_scanner(suffix, LaTeXScanner)
SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
# Tool aliases are needed for those tools whos module names also
# occur in the python standard library. This causes module shadowing and
# can break using python library functions under python3
TOOL_ALIASES = {
'gettext':'gettext_tool',
'clang++': 'clangxx',
}
class Tool(object): class Tool(object):
def __init__(self, name, toolpath=[], **kw): def __init__(self, name, toolpath=[], **kw):
self.name = name
# Rename if there's a TOOL_ALIAS for this tool
self.name = TOOL_ALIASES.get(name,name)
self.toolpath = toolpath + DefaultToolpath self.toolpath = toolpath + DefaultToolpath
# remember these so we can merge them into the call # remember these so we can merge them into the call
self.init_kw = kw self.init_kw = kw
@ -107,35 +121,130 @@ class Tool(object):
if hasattr(module, 'options'): if hasattr(module, 'options'):
self.options = module.options self.options = module.options
def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None):
splitname = short_name.split('.')
index = 0
srchpths = searchpaths
for item in splitname:
file, path, desc = imp.find_module(item, srchpths)
mod = imp.load_module(full_name, file, path, desc)
srchpths = [path]
return mod, file
def _tool_module(self): def _tool_module(self):
# TODO: Interchange zipimport with normal initialization for better error reporting
oldpythonpath = sys.path oldpythonpath = sys.path
sys.path = self.toolpath + sys.path sys.path = self.toolpath + sys.path
# sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path))
try: if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
# Py 2 code
try: try:
file, path, desc = imp.find_module(self.name, self.toolpath)
try: try:
return imp.load_module(self.name, file, path, desc) file = None
finally: try:
if file: mod, file = self._load_dotted_module_py2(self.name, self.name, self.toolpath)
file.close() return mod
except ImportError, e: finally:
if str(e)!="No module named %s"%self.name: if file:
raise SCons.Errors.EnvironmentError(e) file.close()
try: except ImportError as e:
import zipimport splitname = self.name.split('.')
except ImportError: if str(e)!="No module named %s"%splitname[0]:
pass raise SCons.Errors.EnvironmentError(e)
try:
import zipimport
except ImportError:
pass
else:
for aPath in self.toolpath:
try:
importer = zipimport.zipimporter(aPath)
return importer.load_module(self.name)
except ImportError as e:
pass
finally:
sys.path = oldpythonpath
elif sys.version_info[1] > 4:
# From: http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path/67692#67692
# import importlib.util
# spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
# foo = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(foo)
# foo.MyClass()
# Py 3 code
# import pdb; pdb.set_trace()
import importlib.util
# sys.stderr.write("toolpath:%s\n" % self.toolpath)
# sys.stderr.write("SCONS.TOOL path:%s\n" % sys.modules['SCons.Tool'].__path__)
debug = False
spec = None
found_name = self.name
add_to_scons_tools_namespace = False
for path in self.toolpath:
sepname = self.name.replace('.', os.path.sep)
file_path = os.path.join(path, "%s.py"%sepname)
file_package = os.path.join(path, sepname)
if debug: sys.stderr.write("Trying:%s %s\n"%(file_path, file_package))
if os.path.isfile(file_path):
spec = importlib.util.spec_from_file_location(self.name, file_path)
if debug: print("file_Path:%s FOUND"%file_path)
break
elif os.path.isdir(file_package):
file_package = os.path.join(file_package, '__init__.py')
spec = importlib.util.spec_from_file_location(self.name, file_package)
if debug: print("PACKAGE:%s Found"%file_package)
break
else: else:
for aPath in self.toolpath: continue
try:
importer = zipimport.zipimporter(aPath) if spec is None:
return importer.load_module(self.name) if debug: sys.stderr.write("NO SPEC :%s\n"%self.name)
except ImportError, e: spec = importlib.util.find_spec("."+self.name, package='SCons.Tool')
pass if spec:
finally: found_name = 'SCons.Tool.'+self.name
sys.path = oldpythonpath add_to_scons_tools_namespace = True
if debug: sys.stderr.write("Spec Found? .%s :%s\n"%(self.name, spec))
if spec is None:
error_string = "No module named %s"%self.name
raise SCons.Errors.EnvironmentError(error_string)
module = importlib.util.module_from_spec(spec)
if module is None:
if debug: print("MODULE IS NONE:%s"%self.name)
error_string = "No module named %s"%self.name
raise SCons.Errors.EnvironmentError(error_string)
# Don't reload a tool we already loaded.
sys_modules_value = sys.modules.get(found_name,False)
found_module = None
if sys_modules_value and sys_modules_value.__file__ == spec.origin:
found_module = sys.modules[found_name]
else:
# Not sure what to do in the case that there already
# exists sys.modules[self.name] but the source file is
# different.. ?
module = spec.loader.load_module(spec.name)
sys.modules[found_name] = module
if add_to_scons_tools_namespace:
# If we found it in SCons.Tool, then add it to the module
setattr(SCons.Tool, self.name, module)
found_module = module
if found_module is not None:
sys.path = oldpythonpath
return found_module
sys.path = oldpythonpath
full_name = 'SCons.Tool.' + self.name full_name = 'SCons.Tool.' + self.name
try: try:
@ -144,13 +253,12 @@ class Tool(object):
try: try:
smpath = sys.modules['SCons.Tool'].__path__ smpath = sys.modules['SCons.Tool'].__path__
try: try:
file, path, desc = imp.find_module(self.name, smpath) module, file = self._load_dotted_module_py2(self.name, full_name, smpath)
module = imp.load_module(full_name, file, path, desc)
setattr(SCons.Tool, self.name, module) setattr(SCons.Tool, self.name, module)
if file: if file:
file.close() file.close()
return module return module
except ImportError, e: except ImportError as e:
if str(e)!="No module named %s"%self.name: if str(e)!="No module named %s"%self.name:
raise SCons.Errors.EnvironmentError(e) raise SCons.Errors.EnvironmentError(e)
try: try:
@ -159,10 +267,10 @@ class Tool(object):
module = importer.load_module(full_name) module = importer.load_module(full_name)
setattr(SCons.Tool, self.name, module) setattr(SCons.Tool, self.name, module)
return module return module
except ImportError, e: except ImportError as e:
m = "No tool named '%s': %s" % (self.name, e) m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.EnvironmentError(m) raise SCons.Errors.EnvironmentError(m)
except ImportError, e: except ImportError as e:
m = "No tool named '%s': %s" % (self.name, e) m = "No tool named '%s': %s" % (self.name, e)
raise SCons.Errors.EnvironmentError(m) raise SCons.Errors.EnvironmentError(m)
@ -217,6 +325,7 @@ def createProgBuilder(env):
return program return program
def createStaticLibBuilder(env): def createStaticLibBuilder(env):
"""This is a utility function that creates the StaticLibrary """This is a utility function that creates the StaticLibrary
Builder in an Environment if it is not there already. Builder in an Environment if it is not there already.
@ -228,7 +337,7 @@ def createStaticLibBuilder(env):
static_lib = env['BUILDERS']['StaticLibrary'] static_lib = env['BUILDERS']['StaticLibrary']
except KeyError: except KeyError:
action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
if env.Detect('ranlib'): if env.get('RANLIB',False) or env.Detect('ranlib'):
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
action_list.append(ranlib_action) action_list.append(ranlib_action)
@ -254,22 +363,22 @@ def _call_linker_cb(env, callback, args, result = None):
Verbose = False Verbose = False
if Verbose: if Verbose:
print '_call_linker_cb: args=%r' % args print('_call_linker_cb: args=%r' % args)
print '_call_linker_cb: callback=%r' % callback print('_call_linker_cb: callback=%r' % callback)
try: try:
cbfun = env['LINKCALLBACKS'][callback] cbfun = env['LINKCALLBACKS'][callback]
except (KeyError, TypeError): except (KeyError, TypeError):
if Verbose: if Verbose:
print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback)
pass pass
else: else:
if Verbose: if Verbose:
print '_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback)
print '_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun) print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun))
if(callable(cbfun)): if(isinstance(cbfun, collections.Callable)):
if Verbose: if Verbose:
print '_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback)
result = cbfun(env, *args) result = cbfun(env, *args)
return result return result
@ -388,7 +497,7 @@ class _LibInfoGeneratorBase(object):
def generate_versioned_lib_info(self, env, args, result = None, **kw): def generate_versioned_lib_info(self, env, args, result = None, **kw):
callback = self.get_versioned_lib_info_generator(**kw) callback = self.get_versioned_lib_info_generator(**kw)
return _call_linker_cb(env, callback, args, result) return _call_linker_cb(env, callback, args, result)
class _LibPrefixGenerator(_LibInfoGeneratorBase): class _LibPrefixGenerator(_LibInfoGeneratorBase):
"""Library prefix generator, used as target_prefix in SharedLibrary and """Library prefix generator, used as target_prefix in SharedLibrary and
@ -407,17 +516,17 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase):
prefix = self.get_lib_prefix(env,**kw2) prefix = self.get_lib_prefix(env,**kw2)
if Verbose: if Verbose:
print "_LibPrefixGenerator: input prefix=%r" % prefix print("_LibPrefixGenerator: input prefix=%r" % prefix)
version = self.get_lib_version(env, **kw2) version = self.get_lib_version(env, **kw2)
if Verbose: if Verbose:
print "_LibPrefixGenerator: version=%r" % version print("_LibPrefixGenerator: version=%r" % version)
if version: if version:
prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2)
if Verbose: if Verbose:
print "_LibPrefixGenerator: return prefix=%r" % prefix print("_LibPrefixGenerator: return prefix=%r" % prefix)
return prefix return prefix
ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') ShLibPrefixGenerator = _LibPrefixGenerator('ShLib')
@ -441,17 +550,17 @@ class _LibSuffixGenerator(_LibInfoGeneratorBase):
suffix = self.get_lib_suffix(env, **kw2) suffix = self.get_lib_suffix(env, **kw2)
if Verbose: if Verbose:
print "_LibSuffixGenerator: input suffix=%r" % suffix print("_LibSuffixGenerator: input suffix=%r" % suffix)
version = self.get_lib_version(env, **kw2) version = self.get_lib_version(env, **kw2)
if Verbose: if Verbose:
print "_LibSuffixGenerator: version=%r" % version print("_LibSuffixGenerator: version=%r" % version)
if version: if version:
suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2)
if Verbose: if Verbose:
print "_LibSuffixGenerator: return suffix=%r" % suffix print("_LibSuffixGenerator: return suffix=%r" % suffix)
return suffix return suffix
ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') ShLibSuffixGenerator = _LibSuffixGenerator('ShLib')
@ -474,15 +583,15 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase):
kw2 = kw kw2 = kw
if Verbose: if Verbose:
print "_LibSymLinkGenerator: libnode=%r" % libnode.get_path() print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path())
symlinks = None symlinks = None
version = self.get_lib_version(env, **kw2) version = self.get_lib_version(env, **kw2)
disable = self.get_lib_noversionsymlinks(env, **kw2) disable = self.get_lib_noversionsymlinks(env, **kw2)
if Verbose: if Verbose:
print '_LibSymlinkGenerator: version=%r' % version print('_LibSymlinkGenerator: version=%r' % version)
print '_LibSymlinkGenerator: disable=%r' % disable print('_LibSymlinkGenerator: disable=%r' % disable)
if version and not disable: if version and not disable:
prefix = self.get_lib_prefix(env,**kw2) prefix = self.get_lib_prefix(env,**kw2)
@ -490,7 +599,7 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase):
symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2)
if Verbose: if Verbose:
print '_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks) print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks))
return symlinks return symlinks
ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib')
@ -499,7 +608,7 @@ ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib')
class _LibNameGenerator(_LibInfoGeneratorBase): class _LibNameGenerator(_LibInfoGeneratorBase):
"""Generates "unmangled" library name from a library file node. """Generates "unmangled" library name from a library file node.
Generally, it's thought to revert modifications done by prefix/suffix Generally, it's thought to revert modifications done by prefix/suffix
generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library
builder. For example, on gnulink the suffix generator used by SharedLibrary builder. For example, on gnulink the suffix generator used by SharedLibrary
@ -509,7 +618,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
"$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so",
$SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2",
the _LibNameGenerator shall return "libfoo.so". Other link tools may the _LibNameGenerator shall return "libfoo.so". Other link tools may
implement it's own way of library name unmangling. implement it's own way of library name unmangling.
""" """
def __init__(self, libtype): def __init__(self, libtype):
super(_LibNameGenerator, self).__init__(libtype, 'Name') super(_LibNameGenerator, self).__init__(libtype, 'Name')
@ -525,11 +634,11 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
kw2 = kw kw2 = kw
if Verbose: if Verbose:
print "_LibNameGenerator: libnode=%r" % libnode.get_path() print("_LibNameGenerator: libnode=%r" % libnode.get_path())
version = self.get_lib_version(env, **kw2) version = self.get_lib_version(env, **kw2)
if Verbose: if Verbose:
print '_LibNameGenerator: version=%r' % version print('_LibNameGenerator: version=%r' % version)
name = None name = None
if version: if version:
@ -541,7 +650,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
name = os.path.basename(libnode.get_path()) name = os.path.basename(libnode.get_path())
if Verbose: if Verbose:
print '_LibNameGenerator: return name=%r' % name print('_LibNameGenerator: return name=%r' % name)
return name return name
@ -550,7 +659,7 @@ LdModNameGenerator = _LibNameGenerator('LdMod')
ImpLibNameGenerator = _LibNameGenerator('ImpLib') ImpLibNameGenerator = _LibNameGenerator('ImpLib')
class _LibSonameGenerator(_LibInfoGeneratorBase): class _LibSonameGenerator(_LibInfoGeneratorBase):
"""Library soname generator. Returns library soname (e.g. libfoo.so.0) for """Library soname generator. Returns library soname (e.g. libfoo.so.0) for
a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" a given node (e.g. /foo/bar/libfoo.so.0.1.2)"""
def __init__(self, libtype): def __init__(self, libtype):
super(_LibSonameGenerator, self).__init__(libtype, 'Soname') super(_LibSonameGenerator, self).__init__(libtype, 'Soname')
@ -566,13 +675,13 @@ class _LibSonameGenerator(_LibInfoGeneratorBase):
kw2 = kw kw2 = kw
if Verbose: if Verbose:
print "_LibSonameGenerator: libnode=%r" % libnode.get_path() print("_LibSonameGenerator: libnode=%r" % libnode.get_path())
soname = _call_env_subst(env, '$SONAME', **kw2) soname = _call_env_subst(env, '$SONAME', **kw2)
if not soname: if not soname:
version = self.get_lib_version(env,**kw2) version = self.get_lib_version(env,**kw2)
if Verbose: if Verbose:
print "_LibSonameGenerator: version=%r" % version print("_LibSonameGenerator: version=%r" % version)
if version: if version:
prefix = self.get_lib_prefix(env,**kw2) prefix = self.get_lib_prefix(env,**kw2)
suffix = self.get_lib_suffix(env,**kw2) suffix = self.get_lib_suffix(env,**kw2)
@ -582,10 +691,10 @@ class _LibSonameGenerator(_LibInfoGeneratorBase):
# fallback to library name (as returned by appropriate _LibNameGenerator) # fallback to library name (as returned by appropriate _LibNameGenerator)
soname = _LibNameGenerator(self.get_libtype())(env, libnode) soname = _LibNameGenerator(self.get_libtype())(env, libnode)
if Verbose: if Verbose:
print "_LibSonameGenerator: FALLBACK: soname=%r" % soname print("_LibSonameGenerator: FALLBACK: soname=%r" % soname)
if Verbose: if Verbose:
print "_LibSonameGenerator: return soname=%r" % soname print("_LibSonameGenerator: return soname=%r" % soname)
return soname return soname
@ -613,39 +722,39 @@ def EmitLibSymlinks(env, symlinks, libnode, **kw):
clean_targets = kw.get('clean_targets', []) clean_targets = kw.get('clean_targets', [])
if not SCons.Util.is_List(clean_targets): if not SCons.Util.is_List(clean_targets):
clean_targets = [ clean_targets ] clean_targets = [ clean_targets ]
for link, linktgt in symlinks: for link, linktgt in symlinks:
env.SideEffect(link, linktgt) env.SideEffect(link, linktgt)
if(Verbose): if(Verbose):
print "EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()) print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()))
clean_list = filter(lambda x : x != linktgt, nodes) clean_list = [x for x in nodes if x != linktgt]
env.Clean(list(set([linktgt] + clean_targets)), clean_list) env.Clean(list(set([linktgt] + clean_targets)), clean_list)
if(Verbose): if(Verbose):
print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), map(lambda x : x.get_path(), clean_list)) print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list]))
def CreateLibSymlinks(env, symlinks): def CreateLibSymlinks(env, symlinks):
"""Physically creates symlinks. The symlinks argument must be a list in """Physically creates symlinks. The symlinks argument must be a list in
form [ (link, linktarget), ... ], where link and linktarget are SCons form [ (link, linktarget), ... ], where link and linktarget are SCons
nodes. nodes.
""" """
Verbose = False Verbose = False
for link, linktgt in symlinks: for link, linktgt in symlinks:
linktgt = link.get_dir().rel_path(linktgt) linktgt = link.get_dir().rel_path(linktgt)
link = link.get_path() link = link.get_path()
if(Verbose): if(Verbose):
print "CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt) print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt))
# Delete the (previously created) symlink if exists. Let only symlinks # Delete the (previously created) symlink if exists. Let only symlinks
# to be deleted to prevent accidental deletion of source files... # to be deleted to prevent accidental deletion of source files...
if env.fs.islink(link): if env.fs.islink(link):
env.fs.unlink(link) env.fs.unlink(link)
if(Verbose): if(Verbose):
print "CreateLibSymlinks: removed old symlink %r" % link print("CreateLibSymlinks: removed old symlink %r" % link)
# If a file or directory exists with the same name as link, an OSError # If a file or directory exists with the same name as link, an OSError
# will be thrown, which should be enough, I think. # will be thrown, which should be enough, I think.
env.fs.symlink(linktgt, link) env.fs.symlink(linktgt, link)
if(Verbose): if(Verbose):
print "CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt) print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt))
return 0 return 0
def LibSymlinksActionFunction(target, source, env): def LibSymlinksActionFunction(target, source, env):
@ -670,10 +779,11 @@ def LibSymlinksStrFun(target, source, env, *args):
else: else:
cmd += ": %s" % linkstr cmd += ": %s" % linkstr
return cmd return cmd
LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun)
def createSharedLibBuilder(env): def createSharedLibBuilder(env):
"""This is a utility function that creates the SharedLibrary """This is a utility function that creates the SharedLibrary
Builder in an Environment if it is not there already. Builder in an Environment if it is not there already.
@ -803,17 +913,25 @@ def createCFileBuilders(env):
# Create common Java builders # Create common Java builders
def CreateJarBuilder(env): def CreateJarBuilder(env):
"""The Jar builder expects a list of class files
which it can package into a jar file.
The jar tool provides an interface for passing other types
of java files such as .java, directories or swig interfaces
and will build them to class files in which it can package
into the jar.
"""
try: try:
java_jar = env['BUILDERS']['Jar'] java_jar = env['BUILDERS']['JarFile']
except KeyError: except KeyError:
fs = SCons.Node.FS.get_default_fs() fs = SCons.Node.FS.get_default_fs()
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
java_jar = SCons.Builder.Builder(action = jar_com, java_jar = SCons.Builder.Builder(action = jar_com,
suffix = '$JARSUFFIX', suffix = '$JARSUFFIX',
src_suffix = '$JAVACLASSSUFIX', src_suffix = '$JAVACLASSSUFFIX',
src_builder = 'JavaClassFile', src_builder = 'JavaClassFile',
source_factory = fs.Entry) source_factory = fs.Entry)
env['BUILDERS']['Jar'] = java_jar env['BUILDERS']['JarFile'] = java_jar
return java_jar return java_jar
def CreateJavaHBuilder(env): def CreateJavaHBuilder(env):
@ -890,9 +1008,9 @@ class ToolInitializerMethod(object):
def get_builder(self, env): def get_builder(self, env):
""" """
Returns the appropriate real Builder for this method name Returns the appropriate real Builder for this method name
after having the associated ToolInitializer object apply after having the associated ToolInitializer object apply
the appropriate Tool module. the appropriate Tool module.
""" """
builder = getattr(env, self.__name__) builder = getattr(env, self.__name__)
@ -949,13 +1067,13 @@ class ToolInitializer(object):
so we no longer copy and re-bind them when the construction so we no longer copy and re-bind them when the construction
environment gets cloned. environment gets cloned.
""" """
for method in self.methods.values(): for method in list(self.methods.values()):
env.RemoveMethod(method) env.RemoveMethod(method)
def apply_tools(self, env): def apply_tools(self, env):
""" """
Searches the list of associated Tool modules for one that Searches the list of associated Tool modules for one that
exists, and applies that to the construction environment. exists, and applies that to the construction environment.
""" """
for t in self.tools: for t in self.tools:
tool = SCons.Tool.Tool(t) tool = SCons.Tool.Tool(t)
@ -1005,7 +1123,7 @@ def tool_list(platform, env):
"prefer Microsoft tools on Windows" "prefer Microsoft tools on Windows"
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ] cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32' ]
assemblers = ['masm', 'nasm', 'gas', '386asm' ] assemblers = ['masm', 'nasm', 'gas', '386asm' ]
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
ars = ['mslib', 'ar', 'tlib'] ars = ['mslib', 'ar', 'tlib']
@ -1014,7 +1132,7 @@ def tool_list(platform, env):
"prefer IBM tools on OS/2" "prefer IBM tools on OS/2"
linkers = ['ilink', 'gnulink', ]#'mslink'] linkers = ['ilink', 'gnulink', ]#'mslink']
c_compilers = ['icc', 'gcc',]# 'msvc', 'cc'] c_compilers = ['icc', 'gcc',]# 'msvc', 'cc']
cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++'] cxx_compilers = ['icc', 'g++',]# 'msvc', 'cxx']
assemblers = ['nasm',]# 'masm', 'gas'] assemblers = ['nasm',]# 'masm', 'gas']
fortran_compilers = ['ifl', 'g77'] fortran_compilers = ['ifl', 'g77']
ars = ['ar',]# 'mslib'] ars = ['ar',]# 'mslib']
@ -1022,7 +1140,7 @@ def tool_list(platform, env):
"prefer MIPSPro on IRIX" "prefer MIPSPro on IRIX"
linkers = ['sgilink', 'gnulink'] linkers = ['sgilink', 'gnulink']
c_compilers = ['sgicc', 'gcc', 'cc'] c_compilers = ['sgicc', 'gcc', 'cc']
cxx_compilers = ['sgic++', 'g++', 'c++'] cxx_compilers = ['sgicxx', 'g++', 'cxx']
assemblers = ['as', 'gas'] assemblers = ['as', 'gas']
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
ars = ['sgiar'] ars = ['sgiar']
@ -1030,7 +1148,7 @@ def tool_list(platform, env):
"prefer Forte tools on SunOS" "prefer Forte tools on SunOS"
linkers = ['sunlink', 'gnulink'] linkers = ['sunlink', 'gnulink']
c_compilers = ['suncc', 'gcc', 'cc'] c_compilers = ['suncc', 'gcc', 'cc']
cxx_compilers = ['sunc++', 'g++', 'c++'] cxx_compilers = ['suncxx', 'g++', 'cxx']
assemblers = ['as', 'gas'] assemblers = ['as', 'gas']
fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
'gfortran', 'g77', 'fortran'] 'gfortran', 'g77', 'fortran']
@ -1039,7 +1157,7 @@ def tool_list(platform, env):
"prefer aCC tools on HP-UX" "prefer aCC tools on HP-UX"
linkers = ['hplink', 'gnulink'] linkers = ['hplink', 'gnulink']
c_compilers = ['hpcc', 'gcc', 'cc'] c_compilers = ['hpcc', 'gcc', 'cc']
cxx_compilers = ['hpc++', 'g++', 'c++'] cxx_compilers = ['hpcxx', 'g++', 'cxx']
assemblers = ['as', 'gas'] assemblers = ['as', 'gas']
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
ars = ['ar'] ars = ['ar']
@ -1047,7 +1165,7 @@ def tool_list(platform, env):
"prefer AIX Visual Age tools on AIX" "prefer AIX Visual Age tools on AIX"
linkers = ['aixlink', 'gnulink'] linkers = ['aixlink', 'gnulink']
c_compilers = ['aixcc', 'gcc', 'cc'] c_compilers = ['aixcc', 'gcc', 'cc']
cxx_compilers = ['aixc++', 'g++', 'c++'] cxx_compilers = ['aixcxx', 'g++', 'cxx']
assemblers = ['as', 'gas'] assemblers = ['as', 'gas']
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
ars = ['ar'] ars = ['ar']
@ -1055,7 +1173,7 @@ def tool_list(platform, env):
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools" "prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
linkers = ['applelink', 'gnulink'] linkers = ['applelink', 'gnulink']
c_compilers = ['gcc', 'cc'] c_compilers = ['gcc', 'cc']
cxx_compilers = ['g++', 'c++'] cxx_compilers = ['g++', 'cxx']
assemblers = ['as'] assemblers = ['as']
fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
ars = ['ar'] ars = ['ar']
@ -1063,18 +1181,18 @@ def tool_list(platform, env):
"prefer GNU tools on Cygwin, except for a platform-specific linker" "prefer GNU tools on Cygwin, except for a platform-specific linker"
linkers = ['cyglink', 'mslink', 'ilink'] linkers = ['cyglink', 'mslink', 'ilink']
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx']
assemblers = ['gas', 'nasm', 'masm'] assemblers = ['gas', 'nasm', 'masm']
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
ars = ['ar', 'mslib'] ars = ['ar', 'mslib']
else: else:
"prefer GNU tools on all other platforms" "prefer GNU tools on all other platforms"
linkers = ['gnulink', 'mslink', 'ilink'] linkers = ['gnulink', 'ilink']
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] c_compilers = ['gcc', 'intelc', 'icc', 'cc']
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] cxx_compilers = ['g++', 'intelc', 'icc', 'cxx']
assemblers = ['gas', 'nasm', 'masm'] assemblers = ['gas', 'nasm', 'masm']
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
ars = ['ar', 'mslib'] ars = ['ar',]
if not str(platform) == 'win32': if not str(platform) == 'win32':
other_plat_tools += ['m4', 'rpm'] other_plat_tools += ['m4', 'rpm']
@ -1102,7 +1220,7 @@ def tool_list(platform, env):
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
ar = FindTool(ars, env) or ars[0] ar = FindTool(ars, env) or ars[0]
d_compilers = ['dmd', 'gdc', 'ldc'] d_compilers = ['dmd', 'ldc', 'gdc']
d_compiler = FindTool(d_compilers, env) or d_compilers[0] d_compiler = FindTool(d_compilers, env) or d_compilers[0]
other_tools = FindAllTools(other_plat_tools + [ other_tools = FindAllTools(other_plat_tools + [
@ -1121,9 +1239,6 @@ def tool_list(platform, env):
'tex', 'latex', 'pdflatex', 'pdftex', 'tex', 'latex', 'pdflatex', 'pdftex',
# Archivers # Archivers
'tar', 'zip', 'tar', 'zip',
# SourceCode factories
'BitKeeper', 'CVS', 'Perforce',
'RCS', 'SCCS', # 'Subversion',
], env) ], env)
tools = ([linker, c_compiler, cxx_compiler, tools = ([linker, c_compiler, cxx_compiler,
@ -1137,4 +1252,3 @@ def tool_list(platform, env):
# indent-tabs-mode:nil # indent-tabs-mode:nil
# End: # End:
# vim: set expandtab tabstop=4 shiftwidth=4: # vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -0,0 +1,43 @@
"""SCons.Tool.aixc++
Tool-specific initialization for IBM xlC / Visual Age C++ compiler.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
selection method.
"""
#
# Copyright (c) 2001 - 2017 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/aixc++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
#forward proxy to the preffered cxx version
from SCons.Tool.aixcxx import *
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,13 +30,13 @@ 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__ = "src/engine/SCons/Tool/aixcc.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/aixcc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path
import SCons.Platform.aix import SCons.Platform.aix
import cc from . import cc
packages = ['vac.C', 'ibmcxx.cmp'] packages = ['vac.C', 'ibmcxx.cmp']

View file

@ -9,7 +9,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -31,13 +31,15 @@ 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__ = "src/engine/SCons/Tool/aixc++.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/aixcxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path
import SCons.Platform.aix import SCons.Platform.aix
cplusplus = __import__('c++', globals(), locals(), []) import SCons.Tool.cxx
cplusplus = SCons.Tool.cxx
#cplusplus = __import__('cxx', globals(), locals(), [])
packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp'] packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp']

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,13 +30,13 @@ 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__ = "src/engine/SCons/Tool/aixf77.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/aixf77.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path
#import SCons.Platform.aix #import SCons.Platform.aix
import f77 from . import f77
# It would be good to look for the AIX F77 package the same way we're now # It would be good to look for the AIX F77 package the same way we're now
# looking for the C and C++ packages. This should be as easy as supplying # looking for the C and C++ packages. This should be as easy as supplying

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -30,16 +30,20 @@ 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__ = "src/engine/SCons/Tool/aixlink.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/aixlink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import os.path import os.path
import SCons.Util import SCons.Util
import link from . import aixcc
from . import link
import SCons.Tool.cxx
cplusplus = SCons.Tool.cxx
#cplusplus = __import__('cxx', globals(), locals(), [])
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):

View file

@ -9,7 +9,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -31,13 +31,13 @@ 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__ = "src/engine/SCons/Tool/applelink.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/applelink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Util import SCons.Util
# Even though the Mac is based on the GNU toolchain, it doesn't understand # Even though the Mac is based on the GNU toolchain, it doesn't understand
# the -rpath option, so we use the "link" tool instead of "gnulink". # the -rpath option, so we use the "link" tool instead of "gnulink".
import link from . import link
def generate(env): def generate(env):
"""Add Builders and construction variables for applelink to an """Add Builders and construction variables for applelink to an
@ -51,6 +51,14 @@ def generate(env):
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib') env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
# TODO: Work needed to generate versioned shared libraries
# Leaving this commented out, and also going to disable versioned library checking for now
# see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming
#link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
#env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
# override the default for loadable modules, which are different # override the default for loadable modules, which are different
# on OS X than dynamic shared libs. echoing what XCode does for # on OS X than dynamic shared libs. echoing what XCode does for
# pre/suffixes: # pre/suffixes:

View file

@ -9,7 +9,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/ar.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/ar.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool
@ -48,8 +48,8 @@ def generate(env):
env['LIBPREFIX'] = 'lib' env['LIBPREFIX'] = 'lib'
env['LIBSUFFIX'] = '.a' env['LIBSUFFIX'] = '.a'
if env.Detect('ranlib'): if env.get('RANLIB',env.Detect('ranlib')) :
env['RANLIB'] = 'ranlib' env['RANLIB'] = env.get('RANLIB','ranlib')
env['RANLIBFLAGS'] = SCons.Util.CLVar('') env['RANLIBFLAGS'] = SCons.Util.CLVar('')
env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET' env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET'

View file

@ -9,7 +9,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/as.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/as.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Defaults import SCons.Defaults
import SCons.Tool import SCons.Tool

View file

@ -5,7 +5,7 @@ XXX
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/bcc32.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/bcc32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os import os
import os.path import os.path

View file

@ -0,0 +1,44 @@
"""SCons.Tool.c++
Tool-specific initialization for generic Posix C++ compilers.
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 - 2017 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/c++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
#forward proxy to the preffered cxx version
from SCons.Tool.cxx import *
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/cc.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/cc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import SCons.Tool import SCons.Tool
import SCons.Defaults import SCons.Defaults

View file

@ -0,0 +1,83 @@
# -*- coding: utf-8; -*-
"""SCons.Tool.clang
Tool-specific initialization for clang.
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 - 2017 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/clang.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
# Brought into the SCons mainline by Russel Winder 2017.
import os
import re
import subprocess
import sys
import SCons.Util
import SCons.Tool.cc
compilers = ['clang']
def generate(env):
"""Add Builders and construction variables for clang to an Environment."""
SCons.Tool.cc.generate(env)
env['CC'] = env.Detect(compilers) or 'clang'
if env['PLATFORM'] in ['cygwin', 'win32']:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
else:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
# determine compiler version
if env['CC']:
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
stdin='devnull',
stderr='devnull',
stdout=subprocess.PIPE)
if pipe.wait() != 0: return
# clang -dumpversion is of no use
line = pipe.stdout.readline()
if sys.version_info[0] > 2:
line = line.decode()
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
if match:
env['CCVERSION'] = match.group(1)
def exists(env):
return env.Detect(compilers)
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -0,0 +1,91 @@
# -*- coding: utf-8; -*-
"""SCons.Tool.clang++
Tool-specific initialization for clang++.
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 - 2017 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/clangxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
# Brought into the SCons mainline by Russel Winder 2017.
import os.path
import re
import subprocess
import sys
import SCons.Tool
import SCons.Util
import SCons.Tool.cxx
compilers = ['clang++']
def generate(env):
"""Add Builders and construction variables for clang++ to an Environment."""
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
SCons.Tool.cxx.generate(env)
env['CXX'] = env.Detect(compilers) or 'clang++'
# platform specific settings
if env['PLATFORM'] == 'aix':
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
elif env['PLATFORM'] == 'hpux':
env['SHOBJSUFFIX'] = '.pic.o'
elif env['PLATFORM'] == 'sunos':
env['SHOBJSUFFIX'] = '.pic.o'
# determine compiler version
if env['CXX']:
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
stdin='devnull',
stderr='devnull',
stdout=subprocess.PIPE)
if pipe.wait() != 0: return
# clang -dumpversion is of no use
line = pipe.stdout.readline()
if sys.version_info[0] > 2:
line = line.decode()
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
if match:
env['CXXVERSION'] = match.group(1)
def exists(env):
return env.Detect(compilers)
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

View file

@ -5,7 +5,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -27,9 +27,9 @@ 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__ = "src/engine/SCons/Tool/cvf.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/cvf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import fortran from . import fortran
compilers = ['f90'] compilers = ['f90']

View file

@ -8,7 +8,7 @@ selection method.
""" """
# #
# Copyright (c) 2001 - 2016 The SCons Foundation # Copyright (c) 2001 - 2017 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
@ -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__ = "src/engine/SCons/Tool/c++.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" __revision__ = "src/engine/SCons/Tool/cxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
import os.path import os.path

View file

@ -7,6 +7,9 @@ It will usually be imported through the generic SCons.Tool.Tool()
selection method. selection method.
""" """
from __future__ import absolute_import, print_function
import re import re
import os import os
@ -14,12 +17,13 @@ import SCons.Action
import SCons.Util import SCons.Util
import SCons.Tool import SCons.Tool
import gnulink #MAYBE: from . import gnulink
import link from . import gnulink
from . import link
def _lib_generator(target, source, env, for_signature, **kw): def _lib_generator(target, source, env, for_signature, **kw):
try: cmd = kw['cmd'] try: cmd = kw['cmd']
except KeyError: cmd = SCons.Util.CLVar(['$SHLINK']) except KeyError: cmd = SCons.Util.CLVar(['$SHLINK'])
try: vp = kw['varprefix'] try: vp = kw['varprefix']
except KeyError: vp = 'SHLIB' except KeyError: vp = 'SHLIB'
@ -40,7 +44,7 @@ def _lib_generator(target, source, env, for_signature, **kw):
]) ])
else: else:
cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
return [cmd] return [cmd]
@ -58,37 +62,37 @@ def _lib_emitter(target, source, env, **kw):
Verbose = False Verbose = False
if Verbose: if Verbose:
print "_lib_emitter: target[0]=%r" % target[0].get_path() print("_lib_emitter: target[0]=%r" % target[0].get_path())
try: vp = kw['varprefix'] try: vp = kw['varprefix']
except KeyError: vp = 'SHLIB' except KeyError: vp = 'SHLIB'
try: libtype = kw['libtype'] try: libtype = kw['libtype']
except KeyError: libtype = 'ShLib' except KeyError: libtype = 'ShLib'
dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
no_import_lib = env.get('no_import_lib', 0) no_import_lib = env.get('no_import_lib', 0)
if Verbose: if Verbose:
print "_lib_emitter: dll=%r" % dll.get_path() print("_lib_emitter: dll=%r" % dll.get_path())
if not dll or len(target) > 1: if not dll or len(target) > 1:
raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp))
# Remove any "lib" after the prefix # Remove any "lib" after the prefix
pre = env.subst('$%sPREFIX' % vp) pre = env.subst('$%sPREFIX' % vp)
if dll.name[len(pre):len(pre)+3] == 'lib': if dll.name[len(pre):len(pre)+3] == 'lib':
dll.name = pre + dll.name[len(pre)+3:] dll.name = pre + dll.name[len(pre)+3:]
if Verbose: if Verbose:
print "_lib_emitter: dll.name=%r" % dll.name print("_lib_emitter: dll.name=%r" % dll.name)
orig_target = target orig_target = target
target = [env.fs.File(dll)] target = [env.fs.File(dll)]
target[0].attributes.shared = 1 target[0].attributes.shared = 1
if Verbose: if Verbose:
print "_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path() print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path())
# Append an import lib target # Append an import lib target
if not no_import_lib: if not no_import_lib:
@ -97,11 +101,11 @@ def _lib_emitter(target, source, env, **kw):
'%sPREFIX' % vp, '%sSUFFIX' % vp, '%sPREFIX' % vp, '%sSUFFIX' % vp,
'IMPLIBPREFIX', 'IMPLIBSUFFIX') 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
if Verbose: if Verbose:
print "_lib_emitter: target_strings=%r" % target_strings print("_lib_emitter: target_strings=%r" % target_strings)
implib_target = env.fs.File(target_strings) implib_target = env.fs.File(target_strings)
if Verbose: if Verbose:
print "_lib_emitter: implib_target=%r" % implib_target.get_path() print("_lib_emitter: implib_target=%r" % implib_target.get_path())
implib_target.attributes.shared = 1 implib_target.attributes.shared = 1
target.append(implib_target) target.append(implib_target)
@ -109,7 +113,7 @@ def _lib_emitter(target, source, env, **kw):
implib_libtype=libtype, implib_libtype=libtype,
generator_libtype=libtype+'ImpLib') generator_libtype=libtype+'ImpLib')
if Verbose: if Verbose:
print "_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
if symlinks: if symlinks:
SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0])
implib_target.attributes.shliblinks = symlinks implib_target.attributes.shliblinks = symlinks
@ -121,19 +125,19 @@ def shlib_emitter(target, source, env):
def ldmod_emitter(target, source, env): def ldmod_emitter(target, source, env):
return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod') return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
def _versioned_lib_suffix(env, suffix, version): def _versioned_lib_suffix(env, suffix, version):
"""Generate versioned shared library suffix from a unversioned one. """Generate versioned shared library suffix from a unversioned one.
If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'""" If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'"""
Verbose = False Verbose = False
if Verbose: if Verbose:
print "_versioned_lib_suffix: suffix= ", suffix print("_versioned_lib_suffix: suffix= ", suffix)
print "_versioned_lib_suffix: version= ", version print("_versioned_lib_suffix: version= ", version)
cygversion = re.sub('\.', '-', version) cygversion = re.sub('\.', '-', version)
if not suffix.startswith('-' + cygversion): if not suffix.startswith('-' + cygversion):
suffix = '-' + cygversion + suffix suffix = '-' + cygversion + suffix
if Verbose: if Verbose:
print "_versioned_lib_suffix: return suffix= ", suffix print("_versioned_lib_suffix: return suffix= ", suffix)
return suffix return suffix
def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw): def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw):
@ -149,8 +153,8 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
Verbose = False Verbose = False
if Verbose: if Verbose:
print "_versioned_implib_symlinks: libnode=%r" % libnode.get_path() print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path())
print "_versioned_implib_symlinks: version=%r" % version print("_versioned_implib_symlinks: version=%r" % version)
try: libtype = kw['libtype'] try: libtype = kw['libtype']
except KeyError: libtype = 'ShLib' except KeyError: libtype = 'ShLib'
@ -158,13 +162,13 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
linkdir = os.path.dirname(libnode.get_path()) linkdir = os.path.dirname(libnode.get_path())
if Verbose: if Verbose:
print "_versioned_implib_symlinks: linkdir=%r" % linkdir print("_versioned_implib_symlinks: linkdir=%r" % linkdir)
name = SCons.Tool.ImpLibNameGenerator(env, libnode, name = SCons.Tool.ImpLibNameGenerator(env, libnode,
implib_libtype=libtype, implib_libtype=libtype,
generator_libtype=libtype+'ImpLib') generator_libtype=libtype+'ImpLib')
if Verbose: if Verbose:
print "_versioned_implib_symlinks: name=%r" % name print("_versioned_implib_symlinks: name=%r" % name)
major = version.split('.')[0] major = version.split('.')[0]
@ -172,7 +176,7 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
symlinks = [(link0, libnode)] symlinks = [(link0, libnode)]
if Verbose: if Verbose:
print "_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
return symlinks return symlinks

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