commit
74c79eb17c
1527 changed files with 417246 additions and 9021 deletions
14
.travis.yml
14
.travis.yml
|
@ -1,4 +1,4 @@
|
|||
language: generic
|
||||
language: cpp
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
@ -9,6 +9,7 @@ env:
|
|||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||
- CCACHE_COMPRESS=1
|
||||
- PREFIX=/tmp/mapnik
|
||||
- PYTHON=python3
|
||||
- secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
|
||||
|
||||
cache:
|
||||
|
@ -28,7 +29,7 @@ matrix:
|
|||
postgresql: "9.5"
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'xutils-dev', 'postgresql-9.5-postgis-2.4' ]
|
||||
packages: [ 'xutils-dev', 'libstdc++-6-dev', 'postgresql-9.5-postgis-2.4' ]
|
||||
- os: linux
|
||||
name: Linux clang + coverage
|
||||
env: >-
|
||||
|
@ -42,13 +43,14 @@ matrix:
|
|||
postgresql: "9.5"
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'xutils-dev', 'postgresql-9.5-postgis-2.4' ]
|
||||
packages: [ 'xutils-dev', 'libstdc++-6-dev','postgresql-9.5-postgis-2.4' ]
|
||||
- os: osx
|
||||
name: OSX clang
|
||||
# https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
|
||||
osx_image: xcode7.3 # upgrades clang from 6 -> 7
|
||||
#https://docs.travis-ci.com/user/reference/osx#macos-version
|
||||
osx_image: xcode12.2
|
||||
env: >-
|
||||
CXX="ccache clang++ -Qunused-arguments"
|
||||
before_install:
|
||||
|
||||
install:
|
||||
- source scripts/travis-common.sh
|
||||
|
@ -81,6 +83,8 @@ before_script:
|
|||
|
||||
script:
|
||||
- git_submodule_update --init deps/
|
||||
- on 'osx' brew unlink $(brew list --formula)
|
||||
- on 'osx' brew link git postgresql postgis
|
||||
- configure BENCHMARK=${BENCH} ENABLE_GLIBC_WORKAROUND=${ENABLE_GLIBC_WORKAROUND:-false} QUIET=${QUIET:-false}
|
||||
#- cat config.log => comment out to reduce log size limit on travis-ci
|
||||
# we limit the `make` to 40 min
|
||||
|
|
35
SConstruct
35
SConstruct
|
@ -16,8 +16,6 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
from __future__ import print_function # support python2
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
@ -34,19 +32,8 @@ try:
|
|||
except:
|
||||
HAS_DISTUTILS = False
|
||||
|
||||
try:
|
||||
# Python 3.3+
|
||||
from shlex import quote as shquote
|
||||
except:
|
||||
# Python 2.7
|
||||
from pipes import quote as shquote
|
||||
|
||||
try:
|
||||
# Python 3.3+
|
||||
from subprocess import DEVNULL
|
||||
except:
|
||||
# Python 2.7
|
||||
DEVNULL = open(os.devnull, 'w')
|
||||
from shlex import quote as shquote
|
||||
from subprocess import DEVNULL
|
||||
|
||||
LIBDIR_SCHEMA_DEFAULT='lib'
|
||||
severities = ['debug', 'warn', 'error', 'none']
|
||||
|
@ -92,7 +79,7 @@ pretty_dep_names = {
|
|||
'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/GDAL',
|
||||
'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR',
|
||||
'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
|
||||
'proj':'Proj.4 C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/',
|
||||
'proj':'Proj C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/',
|
||||
'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS',
|
||||
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite',
|
||||
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
|
||||
|
@ -142,7 +129,6 @@ PLUGINS = { # plugins with external dependencies
|
|||
|
||||
def init_environment(env):
|
||||
env.Decider('MD5-timestamp')
|
||||
env.SourceCode(".", None)
|
||||
env['ORIGIN'] = Literal('$ORIGIN')
|
||||
env['ENV']['ORIGIN'] = '$ORIGIN'
|
||||
if os.environ.get('RANLIB'):
|
||||
|
@ -380,7 +366,6 @@ opts.AddVariables(
|
|||
BoolVariable('ENABLE_GLIBC_WORKAROUND', "Workaround known GLIBC symbol exports to allow building against libstdc++-4.8 without binaries needing throw_out_of_range_fmt", 'False'),
|
||||
# http://www.scons.org/wiki/GoFastButton
|
||||
# http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script
|
||||
BoolVariable('FAST', "Make SCons faster at the cost of less precise dependency tracking", 'False'),
|
||||
BoolVariable('PRIORITIZE_LINKING', 'Sort list of lib and inc directories to ensure preferential compiling and linking (useful when duplicate libs)', 'True'),
|
||||
('LINK_PRIORITY','Priority list in which to sort library and include paths (default order is internal, other, frameworks, user, then system - see source of `sort_paths` function for more detail)',','.join(DEFAULT_LINK_PRIORITY)),
|
||||
|
||||
|
@ -694,7 +679,7 @@ def parse_config(context, config, checks='--libs --cflags'):
|
|||
# and thus breaks knowledge below that gdal worked
|
||||
# TODO - upgrade our scons logic to support Framework linking
|
||||
if env['PLATFORM'] == 'Darwin':
|
||||
if value and b'-framework GDAL' in value:
|
||||
if value and '-framework GDAL' in value:
|
||||
env['LIBS'].append('gdal')
|
||||
if os.path.exists('/Library/Frameworks/GDAL.framework/unix/lib'):
|
||||
env['LIBPATH'].insert(0,'/Library/Frameworks/GDAL.framework/unix/lib')
|
||||
|
@ -1291,12 +1276,7 @@ def GetMapnikLibVersion():
|
|||
return version_string
|
||||
|
||||
if not preconfigured:
|
||||
|
||||
color_print(4,'Configuring build environment...')
|
||||
|
||||
if not env['FAST']:
|
||||
SetCacheMode('force')
|
||||
|
||||
if env['USE_CONFIG']:
|
||||
if not env['CONFIG'].endswith('.py'):
|
||||
color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
|
||||
|
@ -2172,13 +2152,6 @@ if not HELP_REQUESTED:
|
|||
|
||||
Export('plugin_base')
|
||||
|
||||
if env['FAST']:
|
||||
# caching is 'auto' by default in SCons
|
||||
# But let's also cache implicit deps...
|
||||
EnsureSConsVersion(0,98)
|
||||
SetOption('implicit_cache', 1)
|
||||
SetOption('max_drift', 1)
|
||||
|
||||
# Build agg first, doesn't need anything special
|
||||
if env['RUNTIME_LINK'] == 'shared':
|
||||
SConscript('deps/agg/build.py')
|
||||
|
|
|
@ -8,7 +8,7 @@ todo
|
|||
- shrink icu data
|
||||
'
|
||||
|
||||
MASON_VERSION="fde1d9f5"
|
||||
MASON_VERSION="edb620c7"
|
||||
|
||||
function setup_mason() {
|
||||
if [[ ! -d ./.mason ]]; then
|
||||
|
@ -44,7 +44,7 @@ function install() {
|
|||
}
|
||||
|
||||
ICU_VERSION="57.1"
|
||||
BOOST_VERSION="1.73.0"
|
||||
BOOST_VERSION="1.75.0"
|
||||
|
||||
function install_mason_deps() {
|
||||
install ccache 3.3.1
|
||||
|
@ -54,7 +54,6 @@ function install_mason_deps() {
|
|||
install libtiff 4.0.7 libtiff
|
||||
install libpq 9.6.2
|
||||
install sqlite 3.17.0 libsqlite3
|
||||
install expat 2.2.0 libexpat
|
||||
install icu ${ICU_VERSION}
|
||||
install proj 4.9.3 libproj
|
||||
install pixman 0.34.0 libpixman-1
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
This copyright and license do not apply to any other software
|
||||
with which this software may have been included.
|
||||
|
||||
Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2001 - 2021 The SCons Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright (c) 2001 - 2021 The SCons Foundation
|
||||
|
||||
SCons - a software construction tool
|
||||
|
||||
|
@ -38,19 +38,20 @@ LATEST VERSION
|
|||
Before going further, you can check for the latest version of the
|
||||
scons-local package, or any SCons package, at the SCons download page:
|
||||
|
||||
http://www.scons.org/download.html
|
||||
https://scons.org/pages/download.html
|
||||
|
||||
|
||||
EXECUTION REQUIREMENTS
|
||||
======================
|
||||
|
||||
Running SCons requires Python version 2.4 or later. There should be
|
||||
no other dependencies or requirements to run SCons.
|
||||
Running SCons requires Python 3.5 or higher.
|
||||
There should be no other dependencies or requirements to run SCons.
|
||||
|
||||
The default SCons configuration assumes use of the Microsoft Visual C++
|
||||
compiler suite on WIN32 systems, and assumes a C compiler named 'cc',
|
||||
a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such
|
||||
as found in the GNU C compiler suite) on any other type of system.
|
||||
compiler suite on WIN32 systems (either through the Visual Studio
|
||||
product, or through the separate Build Tools), and assumes a C compiler
|
||||
named 'cc', a C++ compiler named 'c++', and a Fortran compiler named 'g77'
|
||||
(such as found in the GNU Compiler Collection) on any other type of system.
|
||||
You may, of course, override these default values by appropriate
|
||||
configuration of Environment construction variables.
|
||||
|
||||
|
@ -157,14 +158,23 @@ available at:
|
|||
REPORTING BUGS
|
||||
==============
|
||||
|
||||
You can report bugs either by following the "Tracker - Bugs" link
|
||||
on the SCons project page:
|
||||
The SCons project welcomes bug reports and feature requests.
|
||||
|
||||
http://sourceforge.net/projects/scons/
|
||||
Please make sure you send email with the problem or feature request to
|
||||
the SCons users mailing list, which you can join via the link below:
|
||||
|
||||
or by sending mail to the SCons developers mailing list:
|
||||
http://two.pairlist.net/mailman/listinfo/scons-users
|
||||
|
||||
Once you have discussed your issue on the users mailing list and the
|
||||
community has confirmed that it is either a new bug or a duplicate of an
|
||||
existing bug, then please follow the instructions the community provides
|
||||
to file a new bug or to add yourself to the CC list for an existing bug
|
||||
|
||||
You can explore the list of existing bugs, which may include workarounds
|
||||
for the problem you've run into, on GitHub:
|
||||
|
||||
https://github.com/SCons/scons/issues
|
||||
|
||||
scons-devel@lists.sourceforge.net
|
||||
|
||||
|
||||
MAILING LISTS
|
||||
|
@ -173,11 +183,29 @@ MAILING LISTS
|
|||
A mailing list for users of SCons is available. You may send questions
|
||||
or comments to the list at:
|
||||
|
||||
scons-users@lists.sourceforge.net
|
||||
scons-users@scons.org
|
||||
|
||||
You may subscribe to the scons-users mailing list at:
|
||||
|
||||
http://lists.sourceforge.net/lists/listinfo/scons-users
|
||||
http://two.pairlist.net/mailman/listinfo/scons-users
|
||||
|
||||
An active mailing list for developers of SCons is available. You may
|
||||
send questions or comments to the list at:
|
||||
|
||||
scons-dev@scons.org
|
||||
|
||||
You may subscribe to the developer's mailing list using form on this page:
|
||||
|
||||
http://two.pairlist.net/mailman/listinfo/scons-dev
|
||||
|
||||
Subscription to the developer's mailing list is by approval. In practice, no
|
||||
one is refused list membership, but we reserve the right to limit membership
|
||||
in the future and/or weed out lurkers.
|
||||
|
||||
There are other mailing lists available for SCons users, for notification of
|
||||
SCons code changes, and for notification of updated bug reports and project
|
||||
documents. Please see our mailing lists page for details.
|
||||
|
||||
|
||||
|
||||
FOR MORE INFORMATION
|
||||
|
@ -188,18 +216,29 @@ Check the SCons web site at:
|
|||
http://www.scons.org/
|
||||
|
||||
|
||||
AUTHOR INFO
|
||||
Author Info
|
||||
===========
|
||||
|
||||
Steven Knight
|
||||
knight at baldmt dot com
|
||||
http://www.baldmt.com/~knight/
|
||||
|
||||
With plenty of help from the SCons Development team:
|
||||
Chad Austin
|
||||
Charles Crain
|
||||
Steve Leblanc
|
||||
Anthony Roach
|
||||
Terrel Shumway
|
||||
SCons was originally written by Steven Knight, knight at baldmt dot com.
|
||||
Since around 2010 it has been maintained by the SCons
|
||||
development team, co-managed by Bill Deegan and Gary Oberbrunner, with
|
||||
many contributors, including but not at all limited to:
|
||||
|
||||
- Chad Austin
|
||||
- Dirk Baechle
|
||||
- Charles Crain
|
||||
- William Deegan
|
||||
- Steve Leblanc
|
||||
- Rob Managan
|
||||
- Greg Noel
|
||||
- Gary Oberbrunner
|
||||
- Anthony Roach
|
||||
- Greg Spencer
|
||||
- Tom Tanner
|
||||
- Anatoly Techtonik
|
||||
- Christoph Wiedemann
|
||||
- Mats Wichmann
|
||||
- Russel Winder
|
||||
- Mats Wichmann
|
||||
|
||||
\... and many others.
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# 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/Options/BoolOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def BoolOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The BoolOption() function is deprecated; use the BoolVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.BoolVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# 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/Options/EnumOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def EnumOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The EnumOption() function is deprecated; use the EnumVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.EnumVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# 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/Options/PackageOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def PackageOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The PackageOption() function is deprecated; use the PackageVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.PackageVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,76 +0,0 @@
|
|||
#
|
||||
# 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/Options/PathOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
class _PathOptionClass(object):
|
||||
def warn(self):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The PathOption() function is deprecated; use the PathVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable(*args, **kw)
|
||||
|
||||
def PathAccept(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable.PathAccept(*args, **kw)
|
||||
|
||||
def PathIsDir(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable.PathIsDir(*args, **kw)
|
||||
|
||||
def PathIsDirCreate(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable.PathIsDirCreate(*args, **kw)
|
||||
|
||||
def PathIsFile(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable.PathIsFile(*args, **kw)
|
||||
|
||||
def PathExists(self, *args, **kw):
|
||||
self.warn()
|
||||
return SCons.Variables.PathVariable.PathExists(*args, **kw)
|
||||
|
||||
PathOption = _PathOptionClass()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,67 +0,0 @@
|
|||
#
|
||||
# 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/Options/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
from .BoolOption import BoolOption # okay
|
||||
from .EnumOption import EnumOption # okay
|
||||
from .ListOption import ListOption # naja
|
||||
from .PackageOption import PackageOption # naja
|
||||
from .PathOption import PathOption # okay
|
||||
|
||||
warned = False
|
||||
|
||||
class Options(SCons.Variables.Variables):
|
||||
def __init__(self, *args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The Options class is deprecated; use the Variables class instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
SCons.Variables.Variables.__init__(self, *args, **kw)
|
||||
|
||||
def AddOptions(self, *args, **kw):
|
||||
return SCons.Variables.Variables.AddVariables(self, *args, **kw)
|
||||
|
||||
def UnknownOptions(self, *args, **kw):
|
||||
return SCons.Variables.Variables.UnknownVariables(self, *args, **kw)
|
||||
|
||||
def FormatOptionHelpText(self, *args, **kw):
|
||||
return SCons.Variables.Variables.FormatVariableHelpText(self, *args,
|
||||
**kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,573 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# TODO:
|
||||
# * supported arch for versions: for old versions of batch file without
|
||||
# argument, giving bogus argument cannot be detected, so we have to hardcode
|
||||
# this here
|
||||
# * print warning when msvc version specified but not found
|
||||
# * find out why warning do not print
|
||||
# * test on 64 bits XP + VS 2005 (and VS 6 if possible)
|
||||
# * SDK
|
||||
# * Assembly
|
||||
__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.
|
||||
"""
|
||||
import SCons.compat
|
||||
import SCons.Util
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import platform
|
||||
from string import digits as string_digits
|
||||
|
||||
import SCons.Warnings
|
||||
|
||||
from . import common
|
||||
|
||||
debug = common.debug
|
||||
|
||||
from . import sdk
|
||||
|
||||
get_installed_sdks = sdk.get_installed_sdks
|
||||
|
||||
|
||||
class VisualCException(Exception):
|
||||
pass
|
||||
|
||||
class UnsupportedVersion(VisualCException):
|
||||
pass
|
||||
|
||||
class UnsupportedArch(VisualCException):
|
||||
pass
|
||||
|
||||
class MissingConfiguration(VisualCException):
|
||||
pass
|
||||
|
||||
class NoVersionFound(VisualCException):
|
||||
pass
|
||||
|
||||
class BatchFileExecutionError(VisualCException):
|
||||
pass
|
||||
|
||||
# Dict to 'canonalize' the arch
|
||||
_ARCH_TO_CANONICAL = {
|
||||
"amd64" : "amd64",
|
||||
"emt64" : "amd64",
|
||||
"i386" : "x86",
|
||||
"i486" : "x86",
|
||||
"i586" : "x86",
|
||||
"i686" : "x86",
|
||||
"ia64" : "ia64",
|
||||
"itanium" : "ia64",
|
||||
"x86" : "x86",
|
||||
"x86_64" : "amd64",
|
||||
"x86_amd64" : "x86_amd64", # Cross compile to 64 bit from 32bits
|
||||
}
|
||||
|
||||
# Given a (host, target) tuple, return the argument for the bat file. Both host
|
||||
# and targets should be canonalized.
|
||||
_HOST_TARGET_ARCH_TO_BAT_ARCH = {
|
||||
("x86", "x86"): "x86",
|
||||
("x86", "amd64"): "x86_amd64",
|
||||
("x86", "x86_amd64"): "x86_amd64",
|
||||
("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express
|
||||
("amd64", "amd64"): "amd64",
|
||||
("amd64", "x86"): "x86",
|
||||
("x86", "ia64"): "x86_ia64"
|
||||
}
|
||||
|
||||
def get_host_target(env):
|
||||
debug('vc.py:get_host_target()')
|
||||
|
||||
host_platform = env.get('HOST_ARCH')
|
||||
if not host_platform:
|
||||
host_platform = platform.machine()
|
||||
# TODO(2.5): the native Python platform.machine() function returns
|
||||
# '' on all Python versions before 2.6, after which it also uses
|
||||
# PROCESSOR_ARCHITECTURE.
|
||||
if not host_platform:
|
||||
host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
|
||||
|
||||
# Retain user requested TARGET_ARCH
|
||||
req_target_platform = env.get('TARGET_ARCH')
|
||||
debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform)
|
||||
|
||||
if req_target_platform:
|
||||
# If user requested a specific platform then only try that one.
|
||||
target_platform = req_target_platform
|
||||
else:
|
||||
target_platform = host_platform
|
||||
|
||||
try:
|
||||
host = _ARCH_TO_CANONICAL[host_platform.lower()]
|
||||
except KeyError as e:
|
||||
msg = "Unrecognized host architecture %s"
|
||||
raise ValueError(msg % repr(host_platform))
|
||||
|
||||
try:
|
||||
target = _ARCH_TO_CANONICAL[target_platform.lower()]
|
||||
except KeyError as e:
|
||||
all_archs = str(list(_ARCH_TO_CANONICAL.keys()))
|
||||
raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
|
||||
|
||||
return (host, target,req_target_platform)
|
||||
|
||||
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
|
||||
# MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
_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 = {
|
||||
'14.1' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore
|
||||
'14.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
|
||||
'14.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\14.0\Setup\VC\ProductDir')],
|
||||
'12.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'12.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'9.0': [
|
||||
(SCons.Util.HKEY_CURRENT_USER, r'Microsoft\DevDiv\VCForPython\9.0\installdir',),
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',),
|
||||
],
|
||||
'9.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0Exp': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.1': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'6.0': [
|
||||
(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(".")
|
||||
if not len(t) == 2:
|
||||
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
|
||||
try:
|
||||
maj = int(t[0])
|
||||
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):
|
||||
"""Return True if the given (host, target) tuple is supported given the
|
||||
msvc version.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
host_target: tuple
|
||||
tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
|
||||
compilation from 32 bits windows to 64 bits.
|
||||
msvc_version: str
|
||||
msvc version (major.minor, e.g. 10.0)
|
||||
|
||||
Note
|
||||
----
|
||||
This only check whether a given version *may* support the given (host,
|
||||
target), not that the toolchain is actually present on the machine.
|
||||
"""
|
||||
# We assume that any Visual Studio version supports x86 as a target
|
||||
if host_target[1] != "x86":
|
||||
maj, min = msvc_version_to_maj_min(msvc_version)
|
||||
if maj < 8:
|
||||
return False
|
||||
|
||||
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):
|
||||
"""Try to find the product directory for the given
|
||||
version.
|
||||
|
||||
Note
|
||||
----
|
||||
If for some reason the requested version could not be found, an
|
||||
exception which inherits from VisualCException will be raised."""
|
||||
root = 'Software\\'
|
||||
try:
|
||||
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
|
||||
except KeyError:
|
||||
debug("Unknown version of MSVC: %s" % msvc_version)
|
||||
raise UnsupportedVersion("Unknown version %s" % msvc_version)
|
||||
|
||||
for hkroot, key in hkeys:
|
||||
try:
|
||||
comps = None
|
||||
if not key:
|
||||
comps = find_vc_pdir_vswhere(msvc_version)
|
||||
if not comps:
|
||||
debug('find_vc_dir(): no VC found via vswhere for version {}'.format(repr(key)))
|
||||
raise SCons.Util.WinError
|
||||
else:
|
||||
if common.is_win64():
|
||||
try:
|
||||
# ordinally at win64, try Wow6432Node first.
|
||||
comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
|
||||
except SCons.Util.WinError as e:
|
||||
# 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:
|
||||
debug('find_vc_dir(): found VC in registry: {}'.format(comps))
|
||||
if os.path.exists(comps):
|
||||
return comps
|
||||
else:
|
||||
debug('find_vc_dir(): reg says dir is {}, but it does not exist. (ignoring)'.format(comps))
|
||||
raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps))
|
||||
return None
|
||||
|
||||
def find_batch_file(env,msvc_version,host_arch,target_arch):
|
||||
"""
|
||||
Find the location of the batch script which should set up the compiler
|
||||
for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
|
||||
"""
|
||||
pdir = find_vc_pdir(msvc_version)
|
||||
if pdir is None:
|
||||
raise NoVersionFound("No version of Visual Studio found")
|
||||
|
||||
debug('vc.py: find_batch_file() pdir:{}'.format(pdir))
|
||||
|
||||
# filter out e.g. "Exp" from the version name
|
||||
msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
|
||||
vernum = float(msvc_ver_numeric)
|
||||
if 7 <= vernum < 8:
|
||||
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
|
||||
batfilename = os.path.join(pdir, "vsvars32.bat")
|
||||
elif vernum < 7:
|
||||
pdir = os.path.join(pdir, "Bin")
|
||||
batfilename = os.path.join(pdir, "vcvars32.bat")
|
||||
elif 8 <= vernum <= 14:
|
||||
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):
|
||||
debug("Not found: %s" % batfilename)
|
||||
batfilename = None
|
||||
|
||||
installed_sdks=get_installed_sdks()
|
||||
for _sdk in installed_sdks:
|
||||
sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch)
|
||||
if not sdk_bat_file:
|
||||
debug("vc.py:find_batch_file() not found:%s"%_sdk)
|
||||
else:
|
||||
sdk_bat_file_path = os.path.join(pdir,sdk_bat_file)
|
||||
if os.path.exists(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,None)
|
||||
|
||||
|
||||
__INSTALLED_VCS_RUN = None
|
||||
|
||||
def cached_get_installed_vcs():
|
||||
global __INSTALLED_VCS_RUN
|
||||
|
||||
if __INSTALLED_VCS_RUN is None:
|
||||
ret = get_installed_vcs()
|
||||
__INSTALLED_VCS_RUN = ret
|
||||
|
||||
return __INSTALLED_VCS_RUN
|
||||
|
||||
def get_installed_vcs():
|
||||
installed_versions = []
|
||||
for ver in _VCVER:
|
||||
debug('trying to find VC %s' % ver)
|
||||
try:
|
||||
if find_vc_pdir(ver):
|
||||
debug('found VC %s' % ver)
|
||||
installed_versions.append(ver)
|
||||
else:
|
||||
debug('find_vc_pdir return None for ver %s' % ver)
|
||||
except VisualCException as e:
|
||||
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
|
||||
return installed_versions
|
||||
|
||||
def reset_installed_vcs():
|
||||
"""Make it try again to find VC. This is just for the tests."""
|
||||
__INSTALLED_VCS_RUN = None
|
||||
|
||||
# Running these batch files isn't cheap: most of the time spent in
|
||||
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
|
||||
# in multiple environments, for example:
|
||||
# env1 = Environment(tools='msvs')
|
||||
# env2 = Environment(tools='msvs')
|
||||
# we can greatly improve the speed of the second and subsequent Environment
|
||||
# (or Clone) calls by memoizing the environment variables set by vcvars*.bat.
|
||||
script_env_stdout_cache = {}
|
||||
def script_env(script, args=None):
|
||||
cache_key = (script, args)
|
||||
stdout = script_env_stdout_cache.get(cache_key, None)
|
||||
if stdout is None:
|
||||
stdout = common.get_output(script, args)
|
||||
script_env_stdout_cache[cache_key] = stdout
|
||||
|
||||
# Stupid batch files do not set return code: we take a look at the
|
||||
# beginning of the output for an error message instead
|
||||
olines = stdout.splitlines()
|
||||
if olines[0].startswith("The specified configuration type is missing"):
|
||||
raise BatchFileExecutionError("\n".join(olines[:2]))
|
||||
|
||||
return common.parse_output(stdout)
|
||||
|
||||
def get_default_version(env):
|
||||
debug('get_default_version()')
|
||||
|
||||
msvc_version = env.get('MSVC_VERSION')
|
||||
msvs_version = env.get('MSVS_VERSION')
|
||||
|
||||
debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
|
||||
|
||||
if msvs_version and not msvc_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DeprecatedWarning,
|
||||
"MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
|
||||
return msvs_version
|
||||
elif msvc_version and msvs_version:
|
||||
if not msvc_version == msvs_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.VisualVersionMismatch,
|
||||
"Requested msvc version (%s) and msvs version (%s) do " \
|
||||
"not match: please use MSVC_VERSION only to request a " \
|
||||
"visual studio version, MSVS_VERSION is deprecated" \
|
||||
% (msvc_version, msvs_version))
|
||||
return msvs_version
|
||||
if not msvc_version:
|
||||
installed_vcs = cached_get_installed_vcs()
|
||||
debug('installed_vcs:%s' % installed_vcs)
|
||||
if not installed_vcs:
|
||||
#msg = 'No installed VCs'
|
||||
#debug('msv %s\n' % repr(msg))
|
||||
#SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
|
||||
debug('msvc_setup_env: No installed VCs')
|
||||
return None
|
||||
msvc_version = installed_vcs[0]
|
||||
debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
|
||||
|
||||
return msvc_version
|
||||
|
||||
def msvc_setup_env_once(env):
|
||||
try:
|
||||
has_run = env["MSVC_SETUP_RUN"]
|
||||
except KeyError:
|
||||
has_run = False
|
||||
|
||||
if not has_run:
|
||||
msvc_setup_env(env)
|
||||
env["MSVC_SETUP_RUN"] = True
|
||||
|
||||
def msvc_find_valid_batch_script(env,version):
|
||||
debug('vc.py:msvc_find_valid_batch_script()')
|
||||
# Find the host platform, target platform, and if present the requested
|
||||
# target platform
|
||||
(host_platform, target_platform,req_target_platform) = get_host_target(env)
|
||||
|
||||
try_target_archs = [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
|
||||
# with x86_amd64 as the argument to the batch setup script
|
||||
if req_target_platform in ('amd64','x86_64'):
|
||||
try_target_archs.append('x86_amd64')
|
||||
elif not req_target_platform and target_platform in ['amd64','x86_64']:
|
||||
# There may not be "native" amd64, but maybe "cross" x86_amd64 tools
|
||||
try_target_archs.append('x86_amd64')
|
||||
# If the user hasn't specifically requested a TARGET_ARCH, and
|
||||
# The TARGET_ARCH is amd64 then also try 32 bits if there are no viable
|
||||
# 64 bit tools installed
|
||||
try_target_archs.append('x86')
|
||||
|
||||
debug("msvs_find_valid_batch_script(): host_platform: %s try_target_archs:%s"%(host_platform, try_target_archs))
|
||||
|
||||
d = None
|
||||
for tp in try_target_archs:
|
||||
# Set to current arch.
|
||||
env['TARGET_ARCH']=tp
|
||||
|
||||
debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp)
|
||||
host_target = (host_platform, tp)
|
||||
if not is_host_target_supported(host_target, version):
|
||||
warn_msg = "host, target = %s not supported for MSVC version %s" % \
|
||||
(host_target, version)
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
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:
|
||||
(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))
|
||||
except VisualCException as e:
|
||||
msg = str(e)
|
||||
debug('Caught exception while looking for batch file (%s)' % msg)
|
||||
warn_msg = "VC version %s not installed. " + \
|
||||
"C/C++ compilers are most likely not set correctly.\n" + \
|
||||
" Installed versions are: %s"
|
||||
warn_msg = warn_msg % (version, cached_get_installed_vcs())
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
continue
|
||||
|
||||
# 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))
|
||||
if vc_script:
|
||||
try:
|
||||
d = script_env(vc_script, args=arg)
|
||||
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))
|
||||
vc_script=None
|
||||
continue
|
||||
if not vc_script and sdk_script:
|
||||
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
|
||||
try:
|
||||
d = script_env(sdk_script)
|
||||
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))
|
||||
continue
|
||||
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')
|
||||
continue
|
||||
|
||||
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
|
||||
|
||||
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
|
||||
# To it's initial value
|
||||
if not d:
|
||||
env['TARGET_ARCH']=req_target_platform
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def msvc_setup_env(env):
|
||||
debug('msvc_setup_env()')
|
||||
|
||||
version = get_default_version(env)
|
||||
if version is None:
|
||||
warn_msg = "No version of Visual Studio compiler found - C/C++ " \
|
||||
"compilers most likely not set correctly"
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
|
||||
|
||||
# XXX: we set-up both MSVS version for backward
|
||||
# compatibility with the msvs tool
|
||||
env['MSVC_VERSION'] = version
|
||||
env['MSVS_VERSION'] = version
|
||||
env['MSVS'] = {}
|
||||
|
||||
|
||||
use_script = env.get('MSVC_USE_SCRIPT', True)
|
||||
if SCons.Util.is_String(use_script):
|
||||
debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script))
|
||||
d = script_env(use_script)
|
||||
elif use_script:
|
||||
d = msvc_find_valid_batch_script(env,version)
|
||||
debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d)
|
||||
if not d:
|
||||
return d
|
||||
else:
|
||||
debug('MSVC_USE_SCRIPT set to False')
|
||||
warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
|
||||
"set correctly."
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
|
||||
for k, v in d.items():
|
||||
debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v))
|
||||
env.PrependENVPath(k, v, delete_existing=True)
|
||||
|
||||
def msvc_exists(version=None):
|
||||
vcs = cached_get_installed_vcs()
|
||||
if version is None:
|
||||
return len(vcs) > 0
|
||||
return version in vcs
|
File diff suppressed because it is too large
Load diff
|
@ -1,79 +0,0 @@
|
|||
"""SCons.Tool.applelink
|
||||
|
||||
Tool-specific initialization for the Apple gnu-like linker.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
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/applelink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import SCons.Util
|
||||
|
||||
# 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".
|
||||
from . import link
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for applelink to an
|
||||
Environment."""
|
||||
link.generate(env)
|
||||
|
||||
env['FRAMEWORKPATHPREFIX'] = '-F'
|
||||
env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__)}'
|
||||
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
|
||||
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
|
||||
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
|
||||
# on OS X than dynamic shared libs. echoing what XCode does for
|
||||
# pre/suffixes:
|
||||
env['LDMODULEPREFIX'] = ''
|
||||
env['LDMODULESUFFIX'] = ''
|
||||
env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
|
||||
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env['PLATFORM'] == 'darwin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,236 +0,0 @@
|
|||
"""SCons.Tool.cyglink
|
||||
|
||||
Customization of gnulink for Cygwin (http://www.cygwin.com/)
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import re
|
||||
import os
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Util
|
||||
import SCons.Tool
|
||||
|
||||
#MAYBE: from . import gnulink
|
||||
from . import gnulink
|
||||
from . import link
|
||||
|
||||
def _lib_generator(target, source, env, for_signature, **kw):
|
||||
try: cmd = kw['cmd']
|
||||
except KeyError: cmd = SCons.Util.CLVar(['$SHLINK'])
|
||||
|
||||
try: vp = kw['varprefix']
|
||||
except KeyError: vp = 'SHLIB'
|
||||
|
||||
dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
|
||||
if dll: cmd.extend(['-o', dll])
|
||||
|
||||
cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH'])
|
||||
|
||||
implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
|
||||
if implib:
|
||||
cmd.extend([
|
||||
'-Wl,--out-implib='+implib.get_string(for_signature),
|
||||
'-Wl,--export-all-symbols',
|
||||
'-Wl,--enable-auto-import',
|
||||
'-Wl,--whole-archive', '$SOURCES',
|
||||
'-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS'
|
||||
])
|
||||
else:
|
||||
cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
|
||||
|
||||
return [cmd]
|
||||
|
||||
|
||||
def shlib_generator(target, source, env, for_signature):
|
||||
return _lib_generator(target, source, env, for_signature,
|
||||
varprefix='SHLIB',
|
||||
cmd = SCons.Util.CLVar(['$SHLINK']))
|
||||
|
||||
def ldmod_generator(target, source, env, for_signature):
|
||||
return _lib_generator(target, source, env, for_signature,
|
||||
varprefix='LDMODULE',
|
||||
cmd = SCons.Util.CLVar(['$LDMODULE']))
|
||||
|
||||
def _lib_emitter(target, source, env, **kw):
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: target[0]=%r" % target[0].get_path())
|
||||
|
||||
try: vp = kw['varprefix']
|
||||
except KeyError: vp = 'SHLIB'
|
||||
|
||||
try: libtype = kw['libtype']
|
||||
except KeyError: libtype = 'ShLib'
|
||||
|
||||
dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
|
||||
no_import_lib = env.get('no_import_lib', 0)
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: dll=%r" % dll.get_path())
|
||||
|
||||
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))
|
||||
|
||||
# Remove any "lib" after the prefix
|
||||
pre = env.subst('$%sPREFIX' % vp)
|
||||
if dll.name[len(pre):len(pre)+3] == 'lib':
|
||||
dll.name = pre + dll.name[len(pre)+3:]
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: dll.name=%r" % dll.name)
|
||||
|
||||
orig_target = target
|
||||
target = [env.fs.File(dll)]
|
||||
target[0].attributes.shared = 1
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path())
|
||||
|
||||
# Append an import lib target
|
||||
if not no_import_lib:
|
||||
# Create list of target libraries as strings
|
||||
target_strings = env.ReplaceIxes(orig_target[0],
|
||||
'%sPREFIX' % vp, '%sSUFFIX' % vp,
|
||||
'IMPLIBPREFIX', 'IMPLIBSUFFIX')
|
||||
if Verbose:
|
||||
print("_lib_emitter: target_strings=%r" % target_strings)
|
||||
|
||||
implib_target = env.fs.File(target_strings)
|
||||
if Verbose:
|
||||
print("_lib_emitter: implib_target=%r" % implib_target.get_path())
|
||||
implib_target.attributes.shared = 1
|
||||
target.append(implib_target)
|
||||
|
||||
symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target,
|
||||
implib_libtype=libtype,
|
||||
generator_libtype=libtype+'ImpLib')
|
||||
if Verbose:
|
||||
print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
|
||||
if symlinks:
|
||||
SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0])
|
||||
implib_target.attributes.shliblinks = symlinks
|
||||
|
||||
return (target, source)
|
||||
|
||||
def shlib_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib')
|
||||
|
||||
def ldmod_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
|
||||
|
||||
def _versioned_lib_suffix(env, suffix, version):
|
||||
"""Generate versioned shared library suffix from a unversioned one.
|
||||
If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: suffix= ", suffix)
|
||||
print("_versioned_lib_suffix: version= ", version)
|
||||
cygversion = re.sub('\.', '-', version)
|
||||
if not suffix.startswith('-' + cygversion):
|
||||
suffix = '-' + cygversion + suffix
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: return suffix= ", suffix)
|
||||
return suffix
|
||||
|
||||
def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw):
|
||||
return link._versioned_lib_name(env, libnode, version, prefix, suffix,
|
||||
SCons.Tool.ImpLibPrefixGenerator,
|
||||
SCons.Tool.ImpLibSuffixGenerator,
|
||||
implib_libtype=kw['libtype'])
|
||||
|
||||
def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
|
||||
"""Generate link names that should be created for a versioned shared library.
|
||||
Returns a list in the form [ (link, linktarget), ... ]
|
||||
"""
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path())
|
||||
print("_versioned_implib_symlinks: version=%r" % version)
|
||||
|
||||
try: libtype = kw['libtype']
|
||||
except KeyError: libtype = 'ShLib'
|
||||
|
||||
|
||||
linkdir = os.path.dirname(libnode.get_path())
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: linkdir=%r" % linkdir)
|
||||
|
||||
name = SCons.Tool.ImpLibNameGenerator(env, libnode,
|
||||
implib_libtype=libtype,
|
||||
generator_libtype=libtype+'ImpLib')
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: name=%r" % name)
|
||||
|
||||
major = version.split('.')[0]
|
||||
|
||||
link0 = env.fs.File(os.path.join(linkdir, name))
|
||||
symlinks = [(link0, libnode)]
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
|
||||
|
||||
return symlinks
|
||||
|
||||
shlib_action = SCons.Action.Action(shlib_generator, generator=1)
|
||||
ldmod_action = SCons.Action.Action(ldmod_generator, generator=1)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for cyglink to an Environment."""
|
||||
gnulink.generate(env)
|
||||
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined')
|
||||
|
||||
env['SHLINKCOM'] = shlib_action
|
||||
env['LDMODULECOM'] = ldmod_action
|
||||
env.Append(SHLIBEMITTER = [shlib_emitter])
|
||||
env.Append(LDMODULEEMITTER = [ldmod_emitter])
|
||||
|
||||
env['SHLIBPREFIX'] = 'cyg'
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
|
||||
env['IMPLIBPREFIX'] = 'lib'
|
||||
env['IMPLIBSUFFIX'] = '.dll.a'
|
||||
|
||||
# Variables used by versioned shared libraries
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
|
||||
|
||||
# SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
|
||||
|
||||
# LINKCALLBACKS are NOT inherited from gnulink
|
||||
env['LINKCALLBACKS'] = {
|
||||
'VersionedShLibSuffix' : _versioned_lib_suffix,
|
||||
'VersionedLdModSuffix' : _versioned_lib_suffix,
|
||||
'VersionedImpLibSuffix' : _versioned_lib_suffix,
|
||||
'VersionedShLibName' : link._versioned_shlib_name,
|
||||
'VersionedLdModName' : link._versioned_ldmod_name,
|
||||
'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'),
|
||||
'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'),
|
||||
'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'),
|
||||
'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'),
|
||||
}
|
||||
|
||||
# these variables were set by gnulink but are not used in cyglink
|
||||
try: del env['_SHLIBSONAME']
|
||||
except KeyError: pass
|
||||
try: del env['_LDMODULESONAME']
|
||||
except KeyError: pass
|
||||
|
||||
def exists(env):
|
||||
return gnulink.exists(env)
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,331 +0,0 @@
|
|||
|
||||
"""SCons.Tool.link
|
||||
|
||||
Tool-specific initialization for the generic Posix linker.
|
||||
|
||||
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.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/link.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
from SCons.Tool.FortranCommon import isfortran
|
||||
|
||||
from SCons.Tool.DCommon import isD
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
# cplusplus = __import__(__package__+'.cxx', globals(), locals(), ['*'])
|
||||
|
||||
issued_mixed_link_warning = False
|
||||
|
||||
def smart_link(source, target, env, for_signature):
|
||||
has_cplusplus = cplusplus.iscplusplus(source)
|
||||
has_fortran = isfortran(env, source)
|
||||
has_d = isD(env, source)
|
||||
if has_cplusplus and has_fortran and not has_d:
|
||||
global issued_mixed_link_warning
|
||||
if not issued_mixed_link_warning:
|
||||
msg = "Using $CXX to link Fortran and C++ code together.\n\t" + \
|
||||
"This may generate a buggy executable if the '%s'\n\t" + \
|
||||
"compiler does not know how to deal with Fortran runtimes."
|
||||
SCons.Warnings.warn(SCons.Warnings.FortranCxxMixWarning,
|
||||
msg % env.subst('$CXX'))
|
||||
issued_mixed_link_warning = True
|
||||
return '$CXX'
|
||||
elif has_d:
|
||||
env['LINKCOM'] = env['DLINKCOM']
|
||||
env['SHLINKCOM'] = env['SHDLINKCOM']
|
||||
return '$DC'
|
||||
elif has_fortran:
|
||||
return '$FORTRAN'
|
||||
elif has_cplusplus:
|
||||
return '$CXX'
|
||||
return '$CC'
|
||||
|
||||
def _lib_emitter(target, source, env, **kw):
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_lib_emitter: target[0]={:r}".format(target[0].get_path()))
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
|
||||
try:
|
||||
symlink_generator = kw['symlink_generator']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
if Verbose:
|
||||
print("_lib_emitter: symlink_generator={:r}".format(symlink_generator))
|
||||
symlinks = symlink_generator(env, target[0])
|
||||
if Verbose:
|
||||
print("_lib_emitter: symlinks={:r}".format(symlinks))
|
||||
|
||||
if symlinks:
|
||||
SCons.Tool.EmitLibSymlinks(env, symlinks, target[0])
|
||||
target[0].attributes.shliblinks = symlinks
|
||||
return (target, source)
|
||||
|
||||
def shlib_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.ShLibSymlinkGenerator)
|
||||
|
||||
def ldmod_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.LdModSymlinkGenerator)
|
||||
|
||||
# This is generic enough to be included here...
|
||||
def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw):
|
||||
"""For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so'"""
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_lib_name: libnode={:r}".format(libnode.get_path()))
|
||||
print("_versioned_lib_name: version={:r}".format(version))
|
||||
print("_versioned_lib_name: prefix={:r}".format(prefix))
|
||||
print("_versioned_lib_name: suffix={:r}".format(suffix))
|
||||
print("_versioned_lib_name: suffix_generator={:r}".format(suffix_generator))
|
||||
|
||||
versioned_name = os.path.basename(libnode.get_path())
|
||||
if Verbose:
|
||||
print("_versioned_lib_name: versioned_name={:r}".format(versioned_name))
|
||||
|
||||
versioned_prefix = prefix_generator(env, **kw)
|
||||
versioned_suffix = suffix_generator(env, **kw)
|
||||
if Verbose:
|
||||
print("_versioned_lib_name: versioned_prefix={:r}".format(versioned_prefix))
|
||||
print("_versioned_lib_name: versioned_suffix={:r}".format(versioned_suffix))
|
||||
|
||||
versioned_prefix_re = '^' + re.escape(versioned_prefix)
|
||||
versioned_suffix_re = re.escape(versioned_suffix) + '$'
|
||||
name = re.sub(versioned_prefix_re, prefix, versioned_name)
|
||||
name = re.sub(versioned_suffix_re, suffix, name)
|
||||
if Verbose:
|
||||
print("_versioned_lib_name: name={:r}".format(name))
|
||||
return name
|
||||
|
||||
def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw):
|
||||
pg = SCons.Tool.ShLibPrefixGenerator
|
||||
sg = SCons.Tool.ShLibSuffixGenerator
|
||||
return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
|
||||
|
||||
def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw):
|
||||
pg = SCons.Tool.LdModPrefixGenerator
|
||||
sg = SCons.Tool.LdModSuffixGenerator
|
||||
return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
|
||||
|
||||
def _versioned_lib_suffix(env, suffix, version):
|
||||
"""For suffix='.so' and version='0.1.2' it returns '.so.0.1.2'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: suffix={:r}".format(suffix))
|
||||
print("_versioned_lib_suffix: version={:r}".format(version))
|
||||
if not suffix.endswith(version):
|
||||
suffix = suffix + '.' + version
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: return suffix={:r}".format(suffix))
|
||||
return suffix
|
||||
|
||||
def _versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
|
||||
"""For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so.X'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_versioned_lib_soname: version={:r}".format(version))
|
||||
name = name_func(env, libnode, version, prefix, suffix)
|
||||
if Verbose:
|
||||
print("_versioned_lib_soname: name={:r}".format(name))
|
||||
major = version.split('.')[0]
|
||||
soname = name + '.' + major
|
||||
if Verbose:
|
||||
print("_versioned_lib_soname: soname={:r}".format(soname))
|
||||
return soname
|
||||
|
||||
def _versioned_shlib_soname(env, libnode, version, prefix, suffix):
|
||||
return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_shlib_name)
|
||||
|
||||
def _versioned_ldmod_soname(env, libnode, version, prefix, suffix):
|
||||
return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_ldmod_name)
|
||||
|
||||
def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func):
|
||||
"""Generate link names that should be created for a versioned shared lirbrary.
|
||||
Returns a dictionary in the form { linkname : linktarget }
|
||||
"""
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_lib_symlinks: libnode={:r}".format(libnode.get_path()))
|
||||
print("_versioned_lib_symlinks: version={:r}".format(version))
|
||||
|
||||
if sys.platform.startswith('openbsd'):
|
||||
# OpenBSD uses x.y shared library versioning numbering convention
|
||||
# and doesn't use symlinks to backwards-compatible libraries
|
||||
if Verbose:
|
||||
print("_versioned_lib_symlinks: return symlinks={:r}".format(None))
|
||||
return None
|
||||
|
||||
linkdir = libnode.get_dir()
|
||||
if Verbose:
|
||||
print("_versioned_lib_symlinks: linkdir={:r}".format(linkdir.get_path()))
|
||||
|
||||
name = name_func(env, libnode, version, prefix, suffix)
|
||||
if Verbose:
|
||||
print("_versioned_lib_symlinks: name={:r}".format(name))
|
||||
|
||||
soname = soname_func(env, libnode, version, prefix, suffix)
|
||||
|
||||
link0 = env.fs.File(soname, linkdir)
|
||||
link1 = env.fs.File(name, linkdir)
|
||||
|
||||
# We create direct symlinks, not daisy-chained.
|
||||
if link0 == libnode:
|
||||
# This enables SHLIBVERSION without periods (e.g. SHLIBVERSION=1)
|
||||
symlinks = [ (link1, libnode) ]
|
||||
else:
|
||||
# This handles usual SHLIBVERSION, i.e. '1.2', '1.2.3', etc.
|
||||
symlinks = [ (link0, libnode), (link1, libnode) ]
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_lib_symlinks: return symlinks={:r}".format(SCons.Tool.StringizeLibSymlinks(symlinks)))
|
||||
|
||||
return symlinks
|
||||
|
||||
def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix):
|
||||
nf = _versioned_shlib_name
|
||||
sf = _versioned_shlib_soname
|
||||
return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf)
|
||||
|
||||
def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix):
|
||||
nf = _versioned_ldmod_name
|
||||
sf = _versioned_ldmod_soname
|
||||
return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf)
|
||||
|
||||
def _versioned_lib_callbacks():
|
||||
return {
|
||||
'VersionedShLibSuffix' : _versioned_lib_suffix,
|
||||
'VersionedLdModSuffix' : _versioned_lib_suffix,
|
||||
'VersionedShLibSymlinks' : _versioned_shlib_symlinks,
|
||||
'VersionedLdModSymlinks' : _versioned_ldmod_symlinks,
|
||||
'VersionedShLibName' : _versioned_shlib_name,
|
||||
'VersionedLdModName' : _versioned_ldmod_name,
|
||||
'VersionedShLibSoname' : _versioned_shlib_soname,
|
||||
'VersionedLdModSoname' : _versioned_ldmod_soname,
|
||||
}.copy()
|
||||
|
||||
def _setup_versioned_lib_variables(env, **kw):
|
||||
"""
|
||||
Setup all variables required by the versioning machinery
|
||||
"""
|
||||
|
||||
tool = None
|
||||
try: tool = kw['tool']
|
||||
except KeyError: pass
|
||||
|
||||
use_soname = False
|
||||
try: use_soname = kw['use_soname']
|
||||
except KeyError: pass
|
||||
|
||||
# The $_SHLIBVERSIONFLAGS define extra commandline flags used when
|
||||
# building VERSIONED shared libraries. It's always set, but used only
|
||||
# when VERSIONED library is built (see __SHLIBVERSIONFLAGS in SCons/Defaults.py).
|
||||
if use_soname:
|
||||
# If the linker uses SONAME, then we need this little automata
|
||||
if tool == 'sunlink':
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLIBSONAME'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME'
|
||||
else:
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME'
|
||||
env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}'
|
||||
env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}'
|
||||
env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator
|
||||
env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator
|
||||
else:
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
|
||||
|
||||
# LDOMDULVERSIONFLAGS should always default to $SHLIBVERSIONFLAGS
|
||||
env['LDMODULEVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for gnulink to an Environment."""
|
||||
SCons.Tool.createSharedLibBuilder(env)
|
||||
SCons.Tool.createProgBuilder(env)
|
||||
|
||||
env['SHLINK'] = '$LINK'
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
|
||||
env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
# don't set up the emitter, cause AppendUnique will generate a list
|
||||
# starting with None :-(
|
||||
env.Append(SHLIBEMITTER = [shlib_emitter])
|
||||
env['SMARTLINK'] = smart_link
|
||||
env['LINK'] = "$SMARTLINK"
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('')
|
||||
# __RPATH is only set to something ($_RPATH typically) on platforms that support it.
|
||||
env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
env['LIBDIRPREFIX']='-L'
|
||||
env['LIBDIRSUFFIX']=''
|
||||
env['_LIBFLAGS']='${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
|
||||
env['LIBLINKPREFIX']='-l'
|
||||
env['LIBLINKSUFFIX']=''
|
||||
|
||||
if env['PLATFORM'] == 'hpux':
|
||||
env['SHLIBSUFFIX'] = '.sl'
|
||||
elif env['PLATFORM'] == 'aix':
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
|
||||
# For most platforms, a loadable module is the same as a shared
|
||||
# library. Platforms which are different can override these, but
|
||||
# setting them the same means that LoadableModule works everywhere.
|
||||
SCons.Tool.createLoadableModuleBuilder(env)
|
||||
env['LDMODULE'] = '$SHLINK'
|
||||
env.Append(LDMODULEEMITTER = [ldmod_emitter])
|
||||
env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
|
||||
env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
|
||||
env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
|
||||
env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
env['LDMODULEVERSION'] = '$SHLIBVERSION'
|
||||
env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS'
|
||||
|
||||
def exists(env):
|
||||
# This module isn't really a Tool on its own, it's common logic for
|
||||
# other linkers.
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,92 +0,0 @@
|
|||
"""SCons.Tool.zip
|
||||
|
||||
Tool-specific initialization for zip.
|
||||
|
||||
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/zip.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Node.FS
|
||||
import SCons.Util
|
||||
|
||||
import zipfile
|
||||
|
||||
zipcompression = zipfile.ZIP_DEFLATED
|
||||
def zip(target, source, env):
|
||||
compression = env.get('ZIPCOMPRESSION', 0)
|
||||
zf = zipfile.ZipFile(str(target[0]), 'w', compression)
|
||||
for s in source:
|
||||
if s.isdir():
|
||||
for dirpath, dirnames, filenames in os.walk(str(s)):
|
||||
for fname in filenames:
|
||||
path = os.path.join(dirpath, fname)
|
||||
if os.path.isfile(path):
|
||||
|
||||
zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))))
|
||||
else:
|
||||
zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', ''))))
|
||||
zf.close()
|
||||
|
||||
zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION'])
|
||||
|
||||
ZipBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'),
|
||||
source_factory = SCons.Node.FS.Entry,
|
||||
source_scanner = SCons.Defaults.DirScanner,
|
||||
suffix = '$ZIPSUFFIX',
|
||||
multi = 1)
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for zip to an Environment."""
|
||||
try:
|
||||
bld = env['BUILDERS']['Zip']
|
||||
except KeyError:
|
||||
bld = ZipBuilder
|
||||
env['BUILDERS']['Zip'] = bld
|
||||
|
||||
env['ZIP'] = 'zip'
|
||||
env['ZIPFLAGS'] = SCons.Util.CLVar('')
|
||||
env['ZIPCOM'] = zipAction
|
||||
env['ZIPCOMPRESSION'] = zipcompression
|
||||
env['ZIPSUFFIX'] = '.zip'
|
||||
env['ZIPROOT'] = SCons.Util.CLVar('')
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,212 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
__doc__ = """
|
||||
SCons compatibility package for old Python versions
|
||||
|
||||
This subpackage holds modules that provide backwards-compatible
|
||||
implementations of various things that we'd like to use in SCons but which
|
||||
only show up in later versions of Python than the early, old version(s)
|
||||
we still support.
|
||||
|
||||
Other code will not generally reference things in this package through
|
||||
the SCons.compat namespace. The modules included here add things to
|
||||
the builtins namespace or the global module list so that the rest
|
||||
of our code can use the objects and names imported here regardless of
|
||||
Python version.
|
||||
|
||||
The rest of the things here will be in individual compatibility modules
|
||||
that are either: 1) suitably modified copies of the future modules that
|
||||
we want to use; or 2) backwards compatible re-implementations of the
|
||||
specific portions of a future module's API that we want to use.
|
||||
|
||||
GENERAL WARNINGS: Implementations of functions in the SCons.compat
|
||||
modules are *NOT* guaranteed to be fully compliant with these functions in
|
||||
later versions of Python. We are only concerned with adding functionality
|
||||
that we actually use in SCons, so be wary if you lift this code for
|
||||
other uses. (That said, making these more nearly the same as later,
|
||||
official versions is still a desirable goal, we just don't need to be
|
||||
obsessive about it.)
|
||||
|
||||
We name the compatibility modules with an initial '_scons_' (for example,
|
||||
_scons_subprocess.py is our compatibility module for subprocess) so
|
||||
that we can still try to import the real module name and fall back to
|
||||
our compatibility module if we get an ImportError. The import_as()
|
||||
function defined below loads the module as the "real" name (without the
|
||||
'_scons'), after which all of the "import {module}" statements in the
|
||||
rest of our code will find our pre-loaded compatibility module.
|
||||
"""
|
||||
|
||||
__revision__ = "src/engine/SCons/compat/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import imp # Use the "imp" module to protect imports from fixers.
|
||||
|
||||
PYPY = hasattr(sys, 'pypy_translation_info')
|
||||
|
||||
|
||||
def import_as(module, name):
|
||||
"""
|
||||
Imports the specified module (from our local directory) as the
|
||||
specified name, returning the loaded module object.
|
||||
"""
|
||||
dir = os.path.split(__file__)[0]
|
||||
return imp.load_module(name, *imp.find_module(module, [dir]))
|
||||
|
||||
|
||||
def rename_module(new, old):
|
||||
"""
|
||||
Attempts to import the old module and load it under the new name.
|
||||
Used for purely cosmetic name changes in Python 3.x.
|
||||
"""
|
||||
try:
|
||||
sys.modules[new] = imp.load_module(old, *imp.find_module(old))
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
# TODO: FIXME
|
||||
# In 3.x, 'pickle' automatically loads the fast version if available.
|
||||
rename_module('pickle', 'cPickle')
|
||||
|
||||
# Default pickle protocol. Higher protocols are more efficient/featureful
|
||||
# but incompatible with older Python versions. On Python 2.7 this is 2.
|
||||
# Negative numbers choose the highest available protocol.
|
||||
import pickle
|
||||
|
||||
# Was pickle.HIGHEST_PROTOCOL
|
||||
# Changed to 2 so py3.5+'s pickle will be compatible with py2.7.
|
||||
PICKLE_PROTOCOL = 2
|
||||
|
||||
# TODO: FIXME
|
||||
# In 3.x, 'profile' automatically loads the fast version if available.
|
||||
rename_module('profile', 'cProfile')
|
||||
|
||||
# TODO: FIXME
|
||||
# Before Python 3.0, the 'queue' module was named 'Queue'.
|
||||
rename_module('queue', 'Queue')
|
||||
|
||||
# TODO: FIXME
|
||||
# Before Python 3.0, the 'winreg' module was named '_winreg'
|
||||
rename_module('winreg', '_winreg')
|
||||
|
||||
# Python 3 moved builtin intern() to sys package
|
||||
# To make porting easier, make intern always live
|
||||
# in sys package (for python 2.7.x)
|
||||
try:
|
||||
sys.intern
|
||||
except AttributeError:
|
||||
# We must be using python 2.7.x so monkey patch
|
||||
# intern into the sys package
|
||||
sys.intern = intern
|
||||
|
||||
# Preparing for 3.x. UserDict, UserList, UserString are in
|
||||
# collections for 3.x, but standalone in 2.7.x
|
||||
import collections
|
||||
|
||||
try:
|
||||
collections.UserDict
|
||||
except AttributeError:
|
||||
exec ('from UserDict import UserDict as _UserDict')
|
||||
collections.UserDict = _UserDict
|
||||
del _UserDict
|
||||
|
||||
try:
|
||||
collections.UserList
|
||||
except AttributeError:
|
||||
exec ('from UserList import UserList as _UserList')
|
||||
collections.UserList = _UserList
|
||||
del _UserList
|
||||
|
||||
try:
|
||||
collections.UserString
|
||||
except AttributeError:
|
||||
exec ('from UserString import UserString as _UserString')
|
||||
collections.UserString = _UserString
|
||||
del _UserString
|
||||
|
||||
|
||||
import shutil
|
||||
try:
|
||||
shutil.SameFileError
|
||||
except AttributeError:
|
||||
class SameFileError(Exception):
|
||||
pass
|
||||
|
||||
shutil.SameFileError = SameFileError
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""
|
||||
Function from jinja2/_compat.py. License: BSD.
|
||||
|
||||
Use it like this::
|
||||
|
||||
class BaseForm(object):
|
||||
pass
|
||||
|
||||
class FormType(type):
|
||||
pass
|
||||
|
||||
class Form(with_metaclass(FormType, BaseForm)):
|
||||
pass
|
||||
|
||||
This requires a bit of explanation: the basic idea is to make a
|
||||
dummy metaclass for one level of class instantiation that replaces
|
||||
itself with the actual metaclass. Because of internal type checks
|
||||
we also need to make sure that we downgrade the custom metaclass
|
||||
for one level to something closer to type (that's why __call__ and
|
||||
__init__ comes back from type etc.).
|
||||
|
||||
This has the advantage over six.with_metaclass of not introducing
|
||||
dummy classes into the final MRO.
|
||||
"""
|
||||
|
||||
class metaclass(meta):
|
||||
__call__ = type.__call__
|
||||
__init__ = type.__init__
|
||||
|
||||
def __new__(cls, name, this_bases, d):
|
||||
if this_bases is None:
|
||||
return type.__new__(cls, name, (), d)
|
||||
return meta(name, bases, d)
|
||||
|
||||
return metaclass('temporary_class', None, {})
|
||||
|
||||
|
||||
class NoSlotsPyPy(type):
|
||||
"""
|
||||
Workaround for PyPy not working well with __slots__ and __class__ assignment.
|
||||
"""
|
||||
|
||||
def __new__(meta, name, bases, dct):
|
||||
if PYPY and '__slots__' in dct:
|
||||
dct.pop('__slots__')
|
||||
return super(NoSlotsPyPy, meta).__new__(meta, name, bases, dct)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,13 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: scons
|
||||
Version: 3.0.1
|
||||
Summary: Open Source next-generation build tool.
|
||||
Home-page: http://www.scons.org/
|
||||
Author: Steven Knight
|
||||
Author-email: knight@baldmt.com
|
||||
License: UNKNOWN
|
||||
Description: Open Source next-generation build tool.
|
||||
Improved, cross-platform substitute for the classic Make
|
||||
utility. In short, SCons is an easier, more reliable
|
||||
and faster way to build software.
|
||||
Platform: UNKNOWN
|
|
@ -1,11 +1,34 @@
|
|||
"""SCons.Action
|
||||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
This encapsulates information about executing any sort of action that
|
||||
"""SCons Actions.
|
||||
|
||||
Information about executing any sort of action that
|
||||
can build one or more target Nodes (typically files) from one or more
|
||||
source Nodes (also typically files) given a specific Environment.
|
||||
|
||||
The base class here is ActionBase. The base class supplies just a few
|
||||
OO utility methods and some generic methods for displaying information
|
||||
utility methods and some generic methods for displaying information
|
||||
about an Action in response to the various commands that control printing.
|
||||
|
||||
A second-level base class is _ActionAction. This extends ActionBase
|
||||
|
@ -60,7 +83,7 @@ this module:
|
|||
get_presig()
|
||||
Fetches the "contents" of a subclass for signature calculation.
|
||||
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)
|
||||
TODO(?): Change this to always return bytes and not str?
|
||||
|
||||
strfunction()
|
||||
Returns a substituted string representation of the Action.
|
||||
|
@ -77,36 +100,15 @@ way for wrapping up the functions.
|
|||
|
||||
"""
|
||||
|
||||
# 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/Action.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
from subprocess import DEVNULL
|
||||
import itertools
|
||||
import inspect
|
||||
from collections import OrderedDict
|
||||
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
|
@ -115,10 +117,9 @@ import SCons.Util
|
|||
import SCons.Subst
|
||||
|
||||
# we use these a lot, so try to optimize them
|
||||
is_String = SCons.Util.is_String
|
||||
is_List = SCons.Util.is_List
|
||||
from SCons.Util import is_String, is_List
|
||||
|
||||
class _null(object):
|
||||
class _null:
|
||||
pass
|
||||
|
||||
print_actions = 1
|
||||
|
@ -211,7 +212,7 @@ def _object_contents(obj):
|
|||
|
||||
|
||||
def _code_contents(code, docstring=None):
|
||||
"""Return the signature contents of a code object.
|
||||
r"""Return the signature contents of a code object.
|
||||
|
||||
By providing direct access to the code object of the
|
||||
function, Python makes this extremely easy. Hooray!
|
||||
|
@ -258,8 +259,7 @@ def _code_contents(code, docstring=None):
|
|||
# function. Note that we have to call _object_contents on each
|
||||
# constants because the code object of nested functions can
|
||||
# show-up among the constants.
|
||||
|
||||
z = [_object_contents(cc) for cc in code.co_consts[1:]]
|
||||
z = [_object_contents(cc) for cc in code.co_consts if cc != docstring]
|
||||
contents.extend(b',(')
|
||||
contents.extend(bytearray(',', 'utf-8').join(z))
|
||||
contents.extend(b')')
|
||||
|
@ -515,7 +515,7 @@ def Action(act, *args, **kw):
|
|||
return _do_create_action(act, kw)
|
||||
|
||||
|
||||
class ActionBase(object):
|
||||
class ActionBase:
|
||||
"""Base class for all types of action objects that can be held by
|
||||
other objects (Builders, Executors, etc.) This provides the
|
||||
common methods for manipulating and combining those actions."""
|
||||
|
@ -535,7 +535,7 @@ class ActionBase(object):
|
|||
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 ])
|
||||
result = bytearray(result, 'utf-8')
|
||||
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
|
||||
|
@ -629,17 +629,9 @@ class _ActionAction(ActionBase):
|
|||
"""
|
||||
In python 3, and in some of our tests, sys.stdout is
|
||||
a String io object, and it takes unicode strings only
|
||||
In other cases it's a regular Python 2.x file object
|
||||
which takes strings (bytes), and if you pass those a
|
||||
unicode object they try to decode with 'ascii' codec
|
||||
which fails if the cmd line has any hi-bit-set chars.
|
||||
This code assumes s is a regular string, but should
|
||||
work if it's unicode too.
|
||||
This code assumes s is a regular string.
|
||||
"""
|
||||
try:
|
||||
sys.stdout.write(s + u"\n")
|
||||
except UnicodeDecodeError:
|
||||
sys.stdout.write(s + "\n")
|
||||
sys.stdout.write(s + "\n")
|
||||
|
||||
def __call__(self, target, source, env,
|
||||
exitstatfunc=_null,
|
||||
|
@ -657,10 +649,14 @@ class _ActionAction(ActionBase):
|
|||
presub = self.presub
|
||||
if presub is _null:
|
||||
presub = print_actions_presub
|
||||
if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
|
||||
if show is _null: show = print_actions
|
||||
if execute is _null: execute = execute_actions
|
||||
if chdir is _null: chdir = self.chdir
|
||||
if exitstatfunc is _null:
|
||||
exitstatfunc = self.exitstatfunc
|
||||
if show is _null:
|
||||
show = print_actions
|
||||
if execute is _null:
|
||||
execute = execute_actions
|
||||
if chdir is _null:
|
||||
chdir = self.chdir
|
||||
save_cwd = None
|
||||
if chdir:
|
||||
save_cwd = os.getcwd()
|
||||
|
@ -678,7 +674,7 @@ class _ActionAction(ActionBase):
|
|||
source = executor.get_all_sources()
|
||||
t = ' and '.join(map(str, target))
|
||||
l = '\n '.join(self.presub_lines(env))
|
||||
out = u"Building %s with action:\n %s\n" % (t, l)
|
||||
out = "Building %s with action:\n %s\n" % (t, l)
|
||||
sys.stdout.write(out)
|
||||
cmd = None
|
||||
if show and self.strfunction:
|
||||
|
@ -760,24 +756,20 @@ def get_default_ENV(env):
|
|||
return default_ENV
|
||||
|
||||
|
||||
def _subproc(scons_env, cmd, error = 'ignore', **kw):
|
||||
"""Do common setup for a subprocess.Popen() call
|
||||
def _subproc(scons_env, cmd, error='ignore', **kw):
|
||||
"""Wrapper for subprocess which pulls from construction 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.
|
||||
Use for calls to subprocess which need to interpolate values from
|
||||
an SCons construction environment into the environment passed to
|
||||
subprocess. Adds an an error-handling argument. Adds ability
|
||||
to specify std{in,out,err} with "'devnull'" tag.
|
||||
"""
|
||||
# allow std{in,out,err} to be "'devnull'"
|
||||
io = kw.get('stdin')
|
||||
if is_String(io) and io == 'devnull':
|
||||
kw['stdin'] = open(os.devnull)
|
||||
io = kw.get('stdout')
|
||||
if is_String(io) and io == 'devnull':
|
||||
kw['stdout'] = open(os.devnull, 'w')
|
||||
io = kw.get('stderr')
|
||||
if is_String(io) and io == 'devnull':
|
||||
kw['stderr'] = open(os.devnull, 'w')
|
||||
# TODO: just uses subprocess.DEVNULL now, we can drop the "devnull"
|
||||
# string now - it is a holdover from Py2, which didn't have DEVNULL.
|
||||
for stream in 'stdin', 'stdout', 'stderr':
|
||||
io = kw.get(stream)
|
||||
if is_String(io) and io == 'devnull':
|
||||
kw[stream] = DEVNULL
|
||||
|
||||
# Figure out what shell environment to use
|
||||
ENV = kw.get('env', None)
|
||||
|
@ -803,21 +795,28 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
|
|||
kw['env'] = new_env
|
||||
|
||||
try:
|
||||
return subprocess.Popen(cmd, **kw)
|
||||
pobj = subprocess.Popen(cmd, **kw)
|
||||
except EnvironmentError as e:
|
||||
if error == 'raise': raise
|
||||
# return a dummy Popen instance that only returns error
|
||||
class dummyPopen(object):
|
||||
class dummyPopen:
|
||||
def __init__(self, e): self.exception = e
|
||||
def communicate(self, input=None): return ('', '')
|
||||
def wait(self): return -self.exception.errno
|
||||
stdin = None
|
||||
class f(object):
|
||||
class f:
|
||||
def read(self): return ''
|
||||
def readline(self): return ''
|
||||
def __iter__(self): return iter(())
|
||||
stdout = stderr = f()
|
||||
return dummyPopen(e)
|
||||
pobj = dummyPopen(e)
|
||||
finally:
|
||||
# clean up open file handles stored in parent's kw
|
||||
for k, v in kw.items():
|
||||
if inspect.ismethod(getattr(v, 'close', None)):
|
||||
v.close()
|
||||
|
||||
return pobj
|
||||
|
||||
|
||||
class CommandAction(_ActionAction):
|
||||
|
@ -837,8 +836,8 @@ class CommandAction(_ActionAction):
|
|||
_ActionAction.__init__(self, **kw)
|
||||
if is_List(cmd):
|
||||
if [c for c in cmd if is_List(c)]:
|
||||
raise TypeError("CommandAction should be given only " \
|
||||
"a single command")
|
||||
raise TypeError("CommandAction should be given only "
|
||||
"a single command")
|
||||
self.cmd_list = cmd
|
||||
|
||||
def __str__(self):
|
||||
|
@ -964,11 +963,33 @@ class CommandAction(_ActionAction):
|
|||
return env.subst_target_source(cmd, SUBST_SIG, target, source)
|
||||
|
||||
def get_implicit_deps(self, target, source, env, executor=None):
|
||||
"""Return the implicit dependencies of this action's command line."""
|
||||
icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
|
||||
if is_String(icd) and icd[:1] == '$':
|
||||
icd = env.subst(icd)
|
||||
if not icd or icd in ('0', 'None'):
|
||||
|
||||
if not icd or str(icd).lower in ('0', 'none', 'false', 'no', 'off'):
|
||||
return []
|
||||
|
||||
try:
|
||||
icd_int = int(icd)
|
||||
except ValueError:
|
||||
icd_int = None
|
||||
|
||||
if (icd_int and icd_int > 1) or icd == 'all':
|
||||
# An integer value greater than 1 specifies the number of entries
|
||||
# to scan. "all" means to scan all.
|
||||
return self._get_implicit_deps_heavyweight(target, source, env, executor, icd_int)
|
||||
else:
|
||||
# Everything else (usually 1 or True) means that we want
|
||||
# lightweight dependency scanning.
|
||||
return self._get_implicit_deps_lightweight(target, source, env, executor)
|
||||
|
||||
def _get_implicit_deps_lightweight(self, target, source, env, executor):
|
||||
"""
|
||||
Lightweight dependency scanning involves only scanning the first entry
|
||||
in an action string, even if it contains &&.
|
||||
"""
|
||||
from SCons.Subst import SUBST_SIG
|
||||
if executor:
|
||||
cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
|
||||
|
@ -986,6 +1007,65 @@ class CommandAction(_ActionAction):
|
|||
res.append(env.fs.File(d))
|
||||
return res
|
||||
|
||||
def _get_implicit_deps_heavyweight(self, target, source, env, executor,
|
||||
icd_int):
|
||||
"""
|
||||
Heavyweight dependency scanning involves scanning more than just the
|
||||
first entry in an action string. The exact behavior depends on the
|
||||
value of icd_int. Only files are taken as implicit dependencies;
|
||||
directories are ignored.
|
||||
|
||||
If icd_int is an integer value, it specifies the number of entries to
|
||||
scan for implicit dependencies. Action strings are also scanned after
|
||||
a &&. So for example, if icd_int=2 and the action string is
|
||||
"cd <some_dir> && $PYTHON $SCRIPT_PATH <another_path>", the implicit
|
||||
dependencies would be the path to the python binary and the path to the
|
||||
script.
|
||||
|
||||
If icd_int is None, all entries are scanned for implicit dependencies.
|
||||
"""
|
||||
|
||||
# Avoid circular and duplicate dependencies by not providing source,
|
||||
# target, or executor to subst_list. This causes references to
|
||||
# $SOURCES, $TARGETS, and all related variables to disappear.
|
||||
from SCons.Subst import SUBST_SIG
|
||||
cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, conv=lambda x: x)
|
||||
res = []
|
||||
|
||||
for cmd_line in cmd_list:
|
||||
if cmd_line:
|
||||
entry_count = 0
|
||||
for entry in cmd_line:
|
||||
d = str(entry)
|
||||
if ((icd_int is None or entry_count < icd_int) and
|
||||
not d.startswith(('&', '-', '/') if os.name == 'nt'
|
||||
else ('&', '-'))):
|
||||
m = strip_quotes.match(d)
|
||||
if m:
|
||||
d = m.group(1)
|
||||
|
||||
if d:
|
||||
# Resolve the first entry in the command string using
|
||||
# PATH, which env.WhereIs() looks in.
|
||||
# For now, only match files, not directories.
|
||||
p = os.path.abspath(d) if os.path.isfile(d) else None
|
||||
if not p and entry_count == 0:
|
||||
p = env.WhereIs(d)
|
||||
|
||||
if p:
|
||||
res.append(env.fs.File(p))
|
||||
|
||||
entry_count = entry_count + 1
|
||||
else:
|
||||
entry_count = 0 if d == '&&' else entry_count + 1
|
||||
|
||||
# Despite not providing source and target to env.subst() above, we
|
||||
# can still end up with sources in this list. For example, files in
|
||||
# LIBS will still resolve in env.subst(). This won't result in
|
||||
# circular dependencies, but it causes problems with cache signatures
|
||||
# changing between full and incremental builds.
|
||||
return [r for r in res if r not in target and r not in source]
|
||||
|
||||
|
||||
class CommandGeneratorAction(ActionBase):
|
||||
"""Class for command-generator actions."""
|
||||
|
@ -1034,11 +1114,14 @@ class CommandGeneratorAction(ActionBase):
|
|||
show=_null, execute=_null, chdir=_null, executor=None):
|
||||
act = self._generate(target, source, env, 0, executor)
|
||||
if act is None:
|
||||
raise SCons.Errors.UserError("While building `%s': "
|
||||
"Cannot deduce file extension from source files: %s"
|
||||
% (repr(list(map(str, target))), repr(list(map(str, source)))))
|
||||
return act(target, source, env, exitstatfunc, presub,
|
||||
show, execute, chdir, executor)
|
||||
raise SCons.Errors.UserError(
|
||||
"While building `%s': "
|
||||
"Cannot deduce file extension from source files: %s"
|
||||
% (repr(list(map(str, target))), repr(list(map(str, source))))
|
||||
)
|
||||
return act(
|
||||
target, source, env, exitstatfunc, presub, show, execute, chdir, executor
|
||||
)
|
||||
|
||||
def get_presig(self, target, source, env, executor=None):
|
||||
"""Return the signature contents of this action's command line.
|
||||
|
@ -1086,7 +1169,7 @@ class LazyAction(CommandGeneratorAction, CommandAction):
|
|||
|
||||
def get_parent_class(self, env):
|
||||
c = env.get(self.var)
|
||||
if is_String(c) and not '\n' in c:
|
||||
if is_String(c) and '\n' not in c:
|
||||
return CommandAction
|
||||
return CommandGeneratorAction
|
||||
|
||||
|
@ -1289,14 +1372,14 @@ class ListAction(ActionBase):
|
|||
return result
|
||||
|
||||
def get_varlist(self, target, source, env, executor=None):
|
||||
result = SCons.Util.OrderedDict()
|
||||
result = OrderedDict()
|
||||
for act in self.list:
|
||||
for var in act.get_varlist(target, source, env, executor):
|
||||
result[var] = True
|
||||
return list(result.keys())
|
||||
|
||||
|
||||
class ActionCaller(object):
|
||||
class ActionCaller:
|
||||
"""A class for delaying calling an Action function with specific
|
||||
(positional and keyword) arguments until the Action is actually
|
||||
executed.
|
||||
|
@ -1367,7 +1450,7 @@ class ActionCaller(object):
|
|||
return self.parent.strfunc(*self.args, **self.kw)
|
||||
|
||||
|
||||
class ActionFactory(object):
|
||||
class ActionFactory:
|
||||
"""A factory class that will wrap up an arbitrary function
|
||||
as an SCons-executable Action object.
|
||||
|
|
@ -1,3 +1,26 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""
|
||||
SCons.Builder
|
||||
|
||||
|
@ -76,31 +99,7 @@ There are the following methods for internal use within this module:
|
|||
|
||||
"""
|
||||
|
||||
#
|
||||
# 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/Builder.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import collections
|
||||
from collections import UserDict, UserList
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Debug
|
||||
|
@ -111,7 +110,7 @@ import SCons.Memoize
|
|||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
class _Null(object):
|
||||
class _Null:
|
||||
pass
|
||||
|
||||
_null = _Null
|
||||
|
@ -197,7 +196,7 @@ class DictEmitter(SCons.Util.Selector):
|
|||
target, source = emitter(target, source, env)
|
||||
return (target, source)
|
||||
|
||||
class ListEmitter(collections.UserList):
|
||||
class ListEmitter(UserList):
|
||||
"""A callable list of emitters that calls each in sequence,
|
||||
returning the result.
|
||||
"""
|
||||
|
@ -215,7 +214,7 @@ misleading_keywords = {
|
|||
'sources' : 'source',
|
||||
}
|
||||
|
||||
class OverrideWarner(collections.UserDict):
|
||||
class OverrideWarner(UserDict):
|
||||
"""A class for warning about keyword arguments that we use as
|
||||
overrides in a Builder call.
|
||||
|
||||
|
@ -224,13 +223,13 @@ class OverrideWarner(collections.UserDict):
|
|||
warnings once, no matter how many Builders are invoked.
|
||||
"""
|
||||
def __init__(self, dict):
|
||||
collections.UserDict.__init__(self, dict)
|
||||
UserDict.__init__(self, dict)
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner')
|
||||
self.already_warned = None
|
||||
def warn(self):
|
||||
if self.already_warned:
|
||||
return
|
||||
for k in list(self.keys()):
|
||||
for k in self.keys():
|
||||
if k in misleading_keywords:
|
||||
alt = misleading_keywords[k]
|
||||
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
|
||||
|
@ -274,7 +273,7 @@ def Builder(**kw):
|
|||
|
||||
result = BuilderBase(**kw)
|
||||
|
||||
if not composite is None:
|
||||
if composite is not None:
|
||||
result = CompositeBuilder(result, composite)
|
||||
|
||||
return result
|
||||
|
@ -293,7 +292,7 @@ def _node_errors(builder, env, tlist, slist):
|
|||
if t.has_explicit_builder():
|
||||
# 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
|
||||
if (t.env is not None and t.env is not 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
|
||||
|
@ -309,7 +308,7 @@ def _node_errors(builder, env, tlist, slist):
|
|||
else:
|
||||
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:
|
||||
except UnicodeDecodeError:
|
||||
msg = "Two environments with different actions were specified for the same target: %s"%t
|
||||
raise UserError(msg)
|
||||
if builder.multi:
|
||||
|
@ -328,7 +327,7 @@ def _node_errors(builder, env, tlist, slist):
|
|||
if len(slist) > 1:
|
||||
raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist))))
|
||||
|
||||
class EmitterProxy(object):
|
||||
class EmitterProxy:
|
||||
"""This is a callable class that can act as a
|
||||
Builder emitter. It holds on to a string that
|
||||
is a key into an Environment dictionary, and will
|
||||
|
@ -361,7 +360,7 @@ class EmitterProxy(object):
|
|||
def __lt__(self, other):
|
||||
return self.var < other.var
|
||||
|
||||
class BuilderBase(object):
|
||||
class BuilderBase:
|
||||
"""Base class for Builders, objects that create output
|
||||
nodes (files) from input nodes (files).
|
||||
"""
|
||||
|
@ -396,16 +395,13 @@ class BuilderBase(object):
|
|||
self.env = env
|
||||
self.single_source = single_source
|
||||
if 'overrides' in overrides:
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning,
|
||||
"The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\
|
||||
"\tspecify the items as keyword arguments to the Builder() call instead.")
|
||||
overrides.update(overrides['overrides'])
|
||||
del overrides['overrides']
|
||||
msg = "The \"overrides\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tspecify the items as keyword arguments to the Builder() call instead."
|
||||
raise TypeError(msg)
|
||||
if 'scanner' in overrides:
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning,
|
||||
"The \"scanner\" keyword to Builder() creation has been deprecated;\n"
|
||||
"\tuse: source_scanner or target_scanner as appropriate.")
|
||||
del overrides['scanner']
|
||||
msg = "The \"scanner\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tuse: source_scanner or target_scanner as appropriate."
|
||||
raise TypeError(msg)
|
||||
self.overrides = overrides
|
||||
|
||||
self.set_suffix(suffix)
|
||||
|
@ -424,7 +420,7 @@ class BuilderBase(object):
|
|||
if name:
|
||||
self.name = name
|
||||
self.executor_kw = {}
|
||||
if not chdir is _null:
|
||||
if chdir is not _null:
|
||||
self.executor_kw['chdir'] = chdir
|
||||
self.is_explicit = is_explicit
|
||||
|
||||
|
@ -434,11 +430,8 @@ class BuilderBase(object):
|
|||
src_builder = [ src_builder ]
|
||||
self.src_builder = src_builder
|
||||
|
||||
def __nonzero__(self):
|
||||
raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
|
||||
|
||||
def __bool__(self):
|
||||
return self.__nonzero__()
|
||||
raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
|
||||
|
||||
def get_name(self, env):
|
||||
"""Attempts to get the name of the Builder.
|
||||
|
@ -507,6 +500,7 @@ class BuilderBase(object):
|
|||
splitext = lambda S: self.splitext(S,env)
|
||||
tlist = [ t_from_s(pre, suf, splitext) ]
|
||||
else:
|
||||
# orig_target = target
|
||||
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
|
||||
tlist = env.arg2nodes(target, target_factory, target=target, source=source)
|
||||
|
||||
|
@ -554,8 +548,10 @@ class BuilderBase(object):
|
|||
result = []
|
||||
if target is None: target = [None]*len(source)
|
||||
for tgt, src in zip(target, source):
|
||||
if not tgt is None: tgt = [tgt]
|
||||
if not src is None: src = [src]
|
||||
if tgt is not None:
|
||||
tgt = [tgt]
|
||||
if src is not None:
|
||||
src = [src]
|
||||
result.extend(self._execute(env, tgt, src, overwarn))
|
||||
return SCons.Node.NodeList(result)
|
||||
|
||||
|
@ -563,6 +559,13 @@ class BuilderBase(object):
|
|||
|
||||
tlist, slist = self._create_nodes(env, target, source)
|
||||
|
||||
# If there is more than one target ensure that if we need to reset
|
||||
# the implicit list to new scan of dependency all targets implicit lists
|
||||
# are cleared. (SCons GH Issue #2811 and MongoDB SERVER-33111)
|
||||
if len(tlist) > 1:
|
||||
for t in tlist:
|
||||
t.target_peers = tlist
|
||||
|
||||
# Check for errors with the specified target/source lists.
|
||||
_node_errors(self, env, tlist, slist)
|
||||
|
||||
|
@ -641,6 +644,8 @@ class BuilderBase(object):
|
|||
env_kw = kw
|
||||
else:
|
||||
env_kw = self.overrides
|
||||
|
||||
# TODO if env_kw: then the following line. there's no purpose in calling if no overrides.
|
||||
env = env.Override(env_kw)
|
||||
return self._execute(env, target, source, OverrideWarner(kw), ekw)
|
||||
|
||||
|
@ -744,7 +749,7 @@ class BuilderBase(object):
|
|||
for s in SCons.Util.flatten(source):
|
||||
if SCons.Util.is_String(s):
|
||||
match_suffix = match_src_suffix(env.subst(s))
|
||||
if not match_suffix and not '.' in s:
|
||||
if not match_suffix and '.' not in s:
|
||||
src_suf = self.get_src_suffix(env)
|
||||
s = self._adjustixes(s, None, src_suf)[0]
|
||||
else:
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,20 +20,18 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/CacheDir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """
|
||||
CacheDir support
|
||||
"""CacheDir support
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Errors
|
||||
import SCons.Warnings
|
||||
|
||||
cache_enabled = True
|
||||
|
@ -45,16 +44,22 @@ def CacheRetrieveFunc(target, source, env):
|
|||
t = target[0]
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cd.requests += 1
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if not fs.exists(cachefile):
|
||||
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
|
||||
return 1
|
||||
cd.hits += 1
|
||||
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
|
||||
if SCons.Action.execute_actions:
|
||||
if fs.islink(cachefile):
|
||||
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
|
||||
else:
|
||||
env.copy_from_cache(cachefile, t.get_internal_path())
|
||||
try:
|
||||
os.utime(cachefile, None)
|
||||
except OSError:
|
||||
pass
|
||||
st = fs.stat(cachefile)
|
||||
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
||||
return 0
|
||||
|
@ -106,7 +111,7 @@ def CachePushFunc(target, source, env):
|
|||
# has beaten us creating the directory.
|
||||
if not fs.isdir(cachedir):
|
||||
msg = errfmt % (str(target), cachefile)
|
||||
raise SCons.Errors.EnvironmentError(msg)
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
try:
|
||||
if fs.islink(t.get_internal_path()):
|
||||
|
@ -127,90 +132,96 @@ def CachePushFunc(target, source, env):
|
|||
|
||||
CachePush = SCons.Action.Action(CachePushFunc, None)
|
||||
|
||||
# Nasty hack to cut down to one warning for each cachedir path that needs
|
||||
# upgrading.
|
||||
warned = dict()
|
||||
|
||||
class CacheDir(object):
|
||||
class CacheDir:
|
||||
|
||||
def __init__(self, path):
|
||||
try:
|
||||
import hashlib
|
||||
except ImportError:
|
||||
msg = "No hashlib or MD5 module available, CacheDir() not supported"
|
||||
SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
|
||||
path = None
|
||||
"""
|
||||
Initialize a CacheDir object.
|
||||
|
||||
The cache configuration is stored in the object. It
|
||||
is read from the config file in the supplied path if
|
||||
one exists, if not the config file is created and
|
||||
the default config is written, as well as saved in the object.
|
||||
"""
|
||||
self.requests = 0
|
||||
self.hits = 0
|
||||
self.path = path
|
||||
self.current_cache_debug = None
|
||||
self.debugFP = None
|
||||
self.config = dict()
|
||||
if path is None:
|
||||
return
|
||||
# See if there's a config file in the cache directory. If there is,
|
||||
# use it. If there isn't, and the directory exists and isn't empty,
|
||||
# produce a warning. If the directory doesn't exist or is empty,
|
||||
# write a config file.
|
||||
config_file = os.path.join(path, 'config')
|
||||
if not os.path.exists(config_file):
|
||||
# A note: There is a race hazard here, if two processes start and
|
||||
# attempt to create the cache directory at the same time. However,
|
||||
# python doesn't really give you the option to do exclusive file
|
||||
# creation (it doesn't even give you the option to error on opening
|
||||
# an existing file for writing...). The ordering of events here
|
||||
# as an attempt to alleviate this, on the basis that it's a pretty
|
||||
# unlikely occurence (it'd require two builds with a brand new cache
|
||||
# directory)
|
||||
if os.path.isdir(path) and len(os.listdir(path)) != 0:
|
||||
self.config['prefix_len'] = 1
|
||||
# When building the project I was testing this on, the warning
|
||||
# was output over 20 times. That seems excessive
|
||||
global warned
|
||||
if self.path not in warned:
|
||||
msg = "Please upgrade your cache by running " +\
|
||||
" scons-configure-cache.py " + self.path
|
||||
SCons.Warnings.warn(SCons.Warnings.CacheVersionWarning, msg)
|
||||
warned[self.path] = True
|
||||
else:
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
# If someone else is trying to create the directory at
|
||||
# the same time as me, bad things will happen
|
||||
msg = "Failed to create cache directory " + path
|
||||
raise SCons.Errors.EnvironmentError(msg)
|
||||
|
||||
self._readconfig(path)
|
||||
|
||||
|
||||
def _readconfig(self, path):
|
||||
"""
|
||||
Read the cache config.
|
||||
|
||||
If directory or config file do not exist, create. Take advantage
|
||||
of Py3 capability in os.makedirs() and in file open(): just try
|
||||
the operation and handle failure appropriately.
|
||||
|
||||
Omit the check for old cache format, assume that's old enough
|
||||
there will be none of those left to worry about.
|
||||
|
||||
:param path: path to the cache directory
|
||||
"""
|
||||
config_file = os.path.join(path, 'config')
|
||||
try:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError:
|
||||
msg = "Failed to create cache directory " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
try:
|
||||
with open(config_file, 'x') as config:
|
||||
self.config['prefix_len'] = 2
|
||||
if not os.path.exists(config_file):
|
||||
try:
|
||||
with open(config_file, 'w') as config:
|
||||
json.dump(self.config, config)
|
||||
except:
|
||||
msg = "Failed to write cache configuration for " + path
|
||||
raise SCons.Errors.EnvironmentError(msg)
|
||||
else:
|
||||
try:
|
||||
json.dump(self.config, config)
|
||||
except Exception:
|
||||
msg = "Failed to write cache configuration for " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
except FileExistsError:
|
||||
try:
|
||||
with open(config_file) as config:
|
||||
self.config = json.load(config)
|
||||
except ValueError:
|
||||
msg = "Failed to read cache configuration for " + path
|
||||
raise SCons.Errors.EnvironmentError(msg)
|
||||
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
def CacheDebug(self, fmt, target, cachefile):
|
||||
if cache_debug != self.current_cache_debug:
|
||||
if cache_debug == '-':
|
||||
self.debugFP = sys.stdout
|
||||
elif cache_debug:
|
||||
def debug_cleanup(debugFP):
|
||||
debugFP.close()
|
||||
|
||||
self.debugFP = open(cache_debug, 'w')
|
||||
atexit.register(debug_cleanup, self.debugFP)
|
||||
else:
|
||||
self.debugFP = None
|
||||
self.current_cache_debug = cache_debug
|
||||
if self.debugFP:
|
||||
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
|
||||
self.debugFP.write("requests: %d, hits: %d, misses: %d, hit rate: %.2f%%\n" %
|
||||
(self.requests, self.hits, self.misses, self.hit_ratio))
|
||||
|
||||
@property
|
||||
def hit_ratio(self):
|
||||
return (100.0 * self.hits / self.requests if self.requests > 0 else 100)
|
||||
|
||||
@property
|
||||
def misses(self):
|
||||
return self.requests - self.hits
|
||||
|
||||
def is_enabled(self):
|
||||
return cache_enabled and not self.path is None
|
||||
return cache_enabled and self.path is not None
|
||||
|
||||
def is_readonly(self):
|
||||
return cache_readonly
|
||||
|
@ -222,7 +233,9 @@ class CacheDir(object):
|
|||
return None, None
|
||||
|
||||
sig = node.get_cachedir_bsig()
|
||||
|
||||
subdir = sig[:self.config['prefix_len']].upper()
|
||||
|
||||
dir = os.path.join(self.path, subdir)
|
||||
return dir, os.path.join(dir, sig)
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
"""SCons.Conftest
|
||||
|
||||
Autoconf-like configuration support; low level implementation of tests.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
# Copyright (c) 2003 Stichting NLnet Labs
|
||||
# Copyright (c) 2001, 2002, 2003 Steven Knight
|
||||
#
|
||||
|
@ -25,80 +22,72 @@ Autoconf-like configuration support; low level implementation of tests.
|
|||
# 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.
|
||||
#
|
||||
|
||||
#
|
||||
# The purpose of this module is to define how a check is to be performed.
|
||||
# Use one of the Check...() functions below.
|
||||
#
|
||||
"""Autoconf-like configuration support
|
||||
|
||||
#
|
||||
# A context class is used that defines functions for carrying out the tests,
|
||||
# logging and messages. The following methods and members must be present:
|
||||
#
|
||||
# context.Display(msg) Function called to print messages that are normally
|
||||
# displayed for the user. Newlines are explicitly used.
|
||||
# The text should also be written to the logfile!
|
||||
#
|
||||
# context.Log(msg) Function called to write to a log file.
|
||||
#
|
||||
# context.BuildProg(text, ext)
|
||||
# Function called to build a program, using "ext" for the
|
||||
# file extention. Must return an empty string for
|
||||
# success, an error message for failure.
|
||||
# For reliable test results building should be done just
|
||||
# like an actual program would be build, using the same
|
||||
# command and arguments (including configure results so
|
||||
# far).
|
||||
#
|
||||
# context.CompileProg(text, ext)
|
||||
# Function called to compile a program, using "ext" for
|
||||
# the file extention. Must return an empty string for
|
||||
# success, an error message for failure.
|
||||
# For reliable test results compiling should be done just
|
||||
# like an actual source file would be compiled, using the
|
||||
# same command and arguments (including configure results
|
||||
# so far).
|
||||
#
|
||||
# context.AppendLIBS(lib_name_list)
|
||||
# Append "lib_name_list" to the value of LIBS.
|
||||
# "lib_namelist" is a list of strings.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.PrependLIBS(lib_name_list)
|
||||
# Prepend "lib_name_list" to the value of LIBS.
|
||||
# "lib_namelist" is a list of strings.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.SetLIBS(value)
|
||||
# Set LIBS to "value". The type of "value" is what
|
||||
# AppendLIBS() returned.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.headerfilename
|
||||
# Name of file to append configure results to, usually
|
||||
# "confdefs.h".
|
||||
# The file must not exist or be empty when starting.
|
||||
# Empty or None to skip this (some tests will not work!).
|
||||
#
|
||||
# context.config_h (may be missing). If present, must be a string, which
|
||||
# will be filled with the contents of a config_h file.
|
||||
#
|
||||
# context.vardict Dictionary holding variables used for the tests and
|
||||
# stores results from the tests, used for the build
|
||||
# commands.
|
||||
# Normally contains "CC", "LIBS", "CPPFLAGS", etc.
|
||||
#
|
||||
# context.havedict Dictionary holding results from the tests that are to
|
||||
# be used inside a program.
|
||||
# Names often start with "HAVE_". These are zero
|
||||
# (feature not present) or one (feature present). Other
|
||||
# variables may have any value, e.g., "PERLVERSION" can
|
||||
# be a number and "SYSTEMNAME" a string.
|
||||
#
|
||||
The purpose of this module is to define how a check is to be performed.
|
||||
|
||||
A context class is used that defines functions for carrying out the tests,
|
||||
logging and messages. The following methods and members must be present:
|
||||
|
||||
context.Display(msg)
|
||||
Function called to print messages that are normally displayed
|
||||
for the user. Newlines are explicitly used. The text should
|
||||
also be written to the logfile!
|
||||
|
||||
context.Log(msg)
|
||||
Function called to write to a log file.
|
||||
|
||||
context.BuildProg(text, ext)
|
||||
Function called to build a program, using "ext" for the file
|
||||
extension. Must return an empty string for success, an error
|
||||
message for failure. For reliable test results building should
|
||||
be done just like an actual program would be build, using the
|
||||
same command and arguments (including configure results so far).
|
||||
|
||||
context.CompileProg(text, ext)
|
||||
Function called to compile a program, using "ext" for the file
|
||||
extension. Must return an empty string for success, an error
|
||||
message for failure. For reliable test results compiling should be
|
||||
done just like an actual source file would be compiled, using the
|
||||
same command and arguments (including configure results so far).
|
||||
|
||||
context.AppendLIBS(lib_name_list)
|
||||
Append "lib_name_list" to the value of LIBS. "lib_namelist" is
|
||||
a list of strings. Return the value of LIBS before changing it
|
||||
(any type can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.PrependLIBS(lib_name_list)
|
||||
Prepend "lib_name_list" to the value of LIBS. "lib_namelist" is
|
||||
a list of strings. Return the value of LIBS before changing it
|
||||
(any type can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.SetLIBS(value)
|
||||
Set LIBS to "value". The type of "value" is what AppendLIBS()
|
||||
returned. Return the value of LIBS before changing it (any type
|
||||
can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.headerfilename
|
||||
Name of file to append configure results to, usually "confdefs.h".
|
||||
The file must not exist or be empty when starting. Empty or None
|
||||
to skip this (some tests will not work!).
|
||||
|
||||
context.config_h (may be missing).
|
||||
If present, must be a string, which will be filled with the
|
||||
contents of a config_h file.
|
||||
|
||||
context.vardict
|
||||
Dictionary holding variables used for the tests and stores results
|
||||
from the tests, used for the build commands. Normally contains
|
||||
"CC", "LIBS", "CPPFLAGS", etc.
|
||||
|
||||
context.havedict
|
||||
Dictionary holding results from the tests that are to be used
|
||||
inside a program. Names often start with "HAVE_". These are zero
|
||||
(feature not present) or one (feature present). Other variables
|
||||
may have any value, e.g., "PERLVERSION" can be a number and
|
||||
"SYSTEMNAME" a string.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
|
@ -136,7 +125,7 @@ def CheckBuilder(context, text = None, language = None):
|
|||
|
||||
if not text:
|
||||
text = """
|
||||
int main() {
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
@ -157,7 +146,7 @@ def CheckCC(context):
|
|||
"""
|
||||
context.Display("Checking whether the C compiler works... ")
|
||||
text = """
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -177,7 +166,7 @@ def CheckSHCC(context):
|
|||
"""
|
||||
context.Display("Checking whether the (shared) C compiler works... ")
|
||||
text = """
|
||||
int foo()
|
||||
int foo(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -197,7 +186,7 @@ def CheckCXX(context):
|
|||
"""
|
||||
context.Display("Checking whether the C++ compiler works... ")
|
||||
text = """
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -217,7 +206,7 @@ def CheckSHCXX(context):
|
|||
"""
|
||||
context.Display("Checking whether the (shared) C++ compiler works... ")
|
||||
text = """
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -290,7 +279,11 @@ char %s();""" % function_name
|
|||
#include <assert.h>
|
||||
%(hdr)s
|
||||
|
||||
int main() {
|
||||
#if _MSC_VER && !__INTEL_COMPILER
|
||||
#pragma function(%(name)s)
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
|
||||
fail fail fail
|
||||
#else
|
||||
|
@ -311,8 +304,8 @@ int main() {
|
|||
return ret
|
||||
|
||||
|
||||
def CheckHeader(context, header_name, header = None, language = None,
|
||||
include_quotes = None):
|
||||
def CheckHeader(context, header_name, header=None, language=None,
|
||||
include_quotes=None):
|
||||
"""
|
||||
Configure check for a C or C++ header file "header_name".
|
||||
Optional "header" can be defined to do something before including the
|
||||
|
@ -400,7 +393,7 @@ def CheckType(context, type_name, fallback = None,
|
|||
%(include)s
|
||||
%(header)s
|
||||
|
||||
int main() {
|
||||
int main(void) {
|
||||
if ((%(name)s *) 0)
|
||||
return 0;
|
||||
if (sizeof (%(name)s))
|
||||
|
@ -455,7 +448,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
|
|||
return msg
|
||||
|
||||
src = includetext + header
|
||||
if not expect is None:
|
||||
if expect is not None:
|
||||
# Only check if the given size is the right one
|
||||
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
|
||||
|
||||
|
@ -465,7 +458,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
|
|||
src = src + r"""
|
||||
typedef %s scons_check_type;
|
||||
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
|
||||
test_array[0] = 0;
|
||||
|
@ -498,7 +491,7 @@ int main()
|
|||
src = src + """
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
int main(void) {
|
||||
printf("%d", (int)sizeof(""" + type_name + """));
|
||||
return 0;
|
||||
}
|
||||
|
@ -560,7 +553,7 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
|
|||
context.Display('Checking whether %s is declared... ' % symbol)
|
||||
|
||||
src = src + r"""
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
#ifndef %s
|
||||
(void) %s;
|
||||
|
@ -704,7 +697,7 @@ def CheckProg(context, prog_name):
|
|||
#
|
||||
|
||||
def _YesNoResult(context, ret, key, text, comment = None):
|
||||
"""
|
||||
r"""
|
||||
Handle the result of a test with a "yes" or "no" result.
|
||||
|
||||
:Parameters:
|
||||
|
@ -723,7 +716,7 @@ def _YesNoResult(context, ret, key, text, comment = None):
|
|||
|
||||
|
||||
def _Have(context, key, have, comment = None):
|
||||
"""
|
||||
r"""
|
||||
Store result of a test in context.havedict and context.headerfilename.
|
||||
|
||||
:Parameters:
|
|
@ -1,15 +1,6 @@
|
|||
"""SCons.Debug
|
||||
|
||||
Code for debugging SCons internal things. Shouldn't be
|
||||
needed by most users. Quick shortcuts:
|
||||
|
||||
from SCons.Debug import caller_trace
|
||||
caller_trace()
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -29,10 +20,16 @@ caller_trace()
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Debug.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Code for debugging SCons internal things.
|
||||
|
||||
Shouldn't be needed by most users. Quick shortcuts:
|
||||
|
||||
from SCons.Debug import caller_trace
|
||||
caller_trace()
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
@ -93,7 +90,6 @@ def dumpLoggedInstances(classes, file=sys.stdout):
|
|||
file.write(' %20s : %s\n' % (key, value))
|
||||
|
||||
|
||||
|
||||
if sys.platform[:5] == "linux":
|
||||
# Linux doesn't actually support memory usage stats from getrusage().
|
||||
def memory():
|
||||
|
@ -105,28 +101,23 @@ elif sys.platform[:6] == 'darwin':
|
|||
#TODO really get memory stats for OS X
|
||||
def memory():
|
||||
return 0
|
||||
elif sys.platform == 'win32':
|
||||
from SCons.compat.win32 import get_peak_memory_usage
|
||||
memory = get_peak_memory_usage
|
||||
else:
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
try:
|
||||
import win32process
|
||||
import win32api
|
||||
except ImportError:
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
def memory():
|
||||
process_handle = win32api.GetCurrentProcess()
|
||||
memory_info = win32process.GetProcessMemoryInfo( process_handle )
|
||||
return memory_info['PeakWorkingSetSize']
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
def memory():
|
||||
res = resource.getrusage(resource.RUSAGE_SELF)
|
||||
return res[4]
|
||||
|
||||
# returns caller's stack
|
||||
|
||||
def caller_stack():
|
||||
"""return caller's stack"""
|
||||
import traceback
|
||||
tb = traceback.extract_stack()
|
||||
# strip itself and the caller from the output
|
||||
|
@ -201,40 +192,57 @@ if sys.platform == 'win32':
|
|||
TraceDefault = 'con'
|
||||
else:
|
||||
TraceDefault = '/dev/tty'
|
||||
|
||||
TimeStampDefault = None
|
||||
TimeStampDefault = False
|
||||
StartTime = time.time()
|
||||
PreviousTime = StartTime
|
||||
|
||||
def Trace(msg, file=None, mode='w', tstamp=None):
|
||||
"""Write a trace message to a file. Whenever a file is specified,
|
||||
it becomes the default for the next call to Trace()."""
|
||||
def Trace(msg, tracefile=None, mode='w', tstamp=False):
|
||||
"""Write a trace message.
|
||||
|
||||
Write messages when debugging which do not interfere with stdout.
|
||||
Useful in tests, which monitor stdout and would break with
|
||||
unexpected output. Trace messages can go to the console (which is
|
||||
opened as a file), or to a disk file; the tracefile argument persists
|
||||
across calls unless overridden.
|
||||
|
||||
Args:
|
||||
tracefile: file to write trace message to. If omitted,
|
||||
write to the previous trace file (default: console).
|
||||
mode: file open mode (default: 'w')
|
||||
tstamp: write relative timestamps with trace. Outputs time since
|
||||
scons was started, and time since last trace (default: False)
|
||||
|
||||
"""
|
||||
global TraceDefault
|
||||
global TimeStampDefault
|
||||
global PreviousTime
|
||||
if file is None:
|
||||
file = TraceDefault
|
||||
|
||||
def trace_cleanup(traceFP):
|
||||
traceFP.close()
|
||||
|
||||
if tracefile is None:
|
||||
tracefile = TraceDefault
|
||||
else:
|
||||
TraceDefault = file
|
||||
if tstamp is None:
|
||||
TraceDefault = tracefile
|
||||
if not tstamp:
|
||||
tstamp = TimeStampDefault
|
||||
else:
|
||||
TimeStampDefault = tstamp
|
||||
try:
|
||||
fp = TraceFP[file]
|
||||
fp = TraceFP[tracefile]
|
||||
except KeyError:
|
||||
try:
|
||||
fp = TraceFP[file] = open(file, mode)
|
||||
fp = TraceFP[tracefile] = open(tracefile, mode)
|
||||
atexit.register(trace_cleanup, fp)
|
||||
except TypeError:
|
||||
# Assume we were passed an open file pointer.
|
||||
fp = file
|
||||
fp = tracefile
|
||||
if tstamp:
|
||||
now = time.time()
|
||||
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
||||
PreviousTime = now
|
||||
fp.write(msg)
|
||||
fp.flush()
|
||||
fp.close()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
|
@ -1,16 +1,6 @@
|
|||
"""SCons.Defaults
|
||||
|
||||
Builders and other things for the local site. Here's where we'll
|
||||
duplicate the functionality of autoconf until we move it into the
|
||||
installation procedure or use something like qmconf.
|
||||
|
||||
The code that reads the registry to find MSVC components was borrowed
|
||||
from distutils.msvccompiler.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,17 +21,22 @@ from distutils.msvccompiler.
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import division
|
||||
|
||||
__revision__ = "src/engine/SCons/Defaults.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Builders and other things for the local site.
|
||||
|
||||
Here's where we'll duplicate the functionality of autoconf until we
|
||||
move it into the installation procedure or use something like qmconf.
|
||||
|
||||
The code that reads the registry to find MSVC components was borrowed
|
||||
from distutils.msvccompiler.
|
||||
"""
|
||||
|
||||
import os
|
||||
import errno
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import time
|
||||
import sys
|
||||
import time
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
|
@ -50,6 +45,7 @@ import SCons.Environment
|
|||
import SCons.PathList
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
import SCons.Scanner.Dir
|
||||
|
||||
# A placeholder for a default Environment (for fetching source files
|
||||
# from source code management systems and the like). This must be
|
||||
|
@ -57,15 +53,15 @@ import SCons.Tool
|
|||
# interface.
|
||||
_default_env = None
|
||||
|
||||
|
||||
# Lazily instantiate the default environment so the overhead of creating
|
||||
# it doesn't apply when it's not needed.
|
||||
def _fetch_DefaultEnvironment(*args, **kw):
|
||||
"""
|
||||
Returns the already-created default construction environment.
|
||||
"""
|
||||
"""Returns the already-created default construction environment."""
|
||||
global _default_env
|
||||
return _default_env
|
||||
|
||||
|
||||
def DefaultEnvironment(*args, **kw):
|
||||
"""
|
||||
Initial public entry point for creating the default construction
|
||||
|
@ -95,6 +91,7 @@ def DefaultEnvironment(*args, **kw):
|
|||
_default_env._CacheDir_path = None
|
||||
return _default_env
|
||||
|
||||
|
||||
# Emitters for setting the shared attribute on object files,
|
||||
# and an action for checking that all of the source files
|
||||
# going into a shared library are, in fact, shared.
|
||||
|
@ -103,11 +100,13 @@ def StaticObjectEmitter(target, source, env):
|
|||
tgt.attributes.shared = None
|
||||
return (target, source)
|
||||
|
||||
|
||||
def SharedObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return (target, source)
|
||||
|
||||
|
||||
def SharedFlagChecker(source, target, env):
|
||||
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
||||
if same == '0' or same == '' or same == 'False':
|
||||
|
@ -117,7 +116,9 @@ def SharedFlagChecker(source, target, env):
|
|||
except AttributeError:
|
||||
shared = None
|
||||
if not shared:
|
||||
raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
||||
raise SCons.Errors.UserError(
|
||||
"Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
||||
|
||||
|
||||
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
|
||||
|
||||
|
@ -134,7 +135,7 @@ ProgScan = SCons.Tool.ProgramScanner
|
|||
# These aren't really tool scanners, so they don't quite belong with
|
||||
# the rest of those in Tool/__init__.py, but I'm not sure where else
|
||||
# they should go. Leave them here for now.
|
||||
import SCons.Scanner.Dir
|
||||
|
||||
DirScanner = SCons.Scanner.Dir.DirScanner()
|
||||
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
||||
|
||||
|
@ -159,6 +160,7 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
|||
# ways by creating ActionFactory instances.
|
||||
ActionFactory = SCons.Action.ActionFactory
|
||||
|
||||
|
||||
def get_paths_str(dest):
|
||||
# If dest is a list, we need to manually call str() on each element
|
||||
if SCons.Util.is_List(dest):
|
||||
|
@ -169,31 +171,33 @@ def get_paths_str(dest):
|
|||
else:
|
||||
return '"' + str(dest) + '"'
|
||||
|
||||
|
||||
permission_dic = {
|
||||
'u':{
|
||||
'r':stat.S_IRUSR,
|
||||
'w':stat.S_IWUSR,
|
||||
'x':stat.S_IXUSR
|
||||
'u': {
|
||||
'r': stat.S_IRUSR,
|
||||
'w': stat.S_IWUSR,
|
||||
'x': stat.S_IXUSR
|
||||
},
|
||||
'g':{
|
||||
'r':stat.S_IRGRP,
|
||||
'w':stat.S_IWGRP,
|
||||
'x':stat.S_IXGRP
|
||||
'g': {
|
||||
'r': stat.S_IRGRP,
|
||||
'w': stat.S_IWGRP,
|
||||
'x': stat.S_IXGRP
|
||||
},
|
||||
'o':{
|
||||
'r':stat.S_IROTH,
|
||||
'w':stat.S_IWOTH,
|
||||
'x':stat.S_IXOTH
|
||||
'o': {
|
||||
'r': stat.S_IROTH,
|
||||
'w': stat.S_IWOTH,
|
||||
'x': stat.S_IXOTH
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def chmod_func(dest, mode):
|
||||
import SCons.Util
|
||||
from string import digits
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
if SCons.Util.is_String(mode) and not 0 in [i in digits for i in mode]:
|
||||
if SCons.Util.is_String(mode) and 0 not in [i in digits for i in mode]:
|
||||
mode = int(mode, 8)
|
||||
if not SCons.Util.is_String(mode):
|
||||
for element in dest:
|
||||
|
@ -210,7 +214,7 @@ def chmod_func(dest, mode):
|
|||
else:
|
||||
raise SyntaxError("Could not find +, - or =")
|
||||
operation_list = operation.split(operator)
|
||||
if len(operation_list) is not 2:
|
||||
if len(operation_list) != 2:
|
||||
raise SyntaxError("More than one operator found")
|
||||
user = operation_list[0].strip().replace("a", "ugo")
|
||||
permission = operation_list[1].strip()
|
||||
|
@ -230,6 +234,7 @@ def chmod_func(dest, mode):
|
|||
elif operator == "-":
|
||||
os.chmod(str(element), curr_perm & ~new_perm)
|
||||
|
||||
|
||||
def chmod_strfunc(dest, mode):
|
||||
import SCons.Util
|
||||
if not SCons.Util.is_String(mode):
|
||||
|
@ -237,8 +242,10 @@ def chmod_strfunc(dest, mode):
|
|||
else:
|
||||
return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
|
||||
|
||||
|
||||
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
||||
|
||||
|
||||
def copy_func(dest, src, symlinks=True):
|
||||
"""
|
||||
If symlinks (is true), then a symbolic link will be
|
||||
|
@ -269,11 +276,13 @@ def copy_func(dest, src, symlinks=True):
|
|||
# A error is raised in both cases, so we can just return 0 for success
|
||||
return 0
|
||||
|
||||
|
||||
Copy = ActionFactory(
|
||||
copy_func,
|
||||
lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
|
||||
)
|
||||
|
||||
|
||||
def delete_func(dest, must_exist=0):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
|
@ -290,11 +299,14 @@ def delete_func(dest, must_exist=0):
|
|||
continue
|
||||
os.unlink(entry)
|
||||
|
||||
|
||||
def delete_strfunc(dest, must_exist=0):
|
||||
return 'Delete(%s)' % get_paths_str(dest)
|
||||
|
||||
|
||||
Delete = ActionFactory(delete_func, delete_strfunc)
|
||||
|
||||
|
||||
def mkdir_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
|
@ -305,24 +317,28 @@ def mkdir_func(dest):
|
|||
except os.error as e:
|
||||
p = str(entry)
|
||||
if (e.args[0] == errno.EEXIST or
|
||||
(sys.platform=='win32' and e.args[0]==183)) \
|
||||
(sys.platform == 'win32' and e.args[0] == 183)) \
|
||||
and os.path.isdir(str(entry)):
|
||||
pass # not an error if already exists
|
||||
pass # not an error if already exists
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
Mkdir = ActionFactory(mkdir_func,
|
||||
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
||||
|
||||
|
||||
def move_func(dest, src):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
SCons.Node.FS.invalidate_node_memos(src)
|
||||
shutil.move(src, dest)
|
||||
|
||||
|
||||
Move = ActionFactory(move_func,
|
||||
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
||||
convert=str)
|
||||
|
||||
|
||||
def touch_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
|
@ -333,15 +349,18 @@ def touch_func(dest):
|
|||
if os.path.exists(file):
|
||||
atime = os.path.getatime(file)
|
||||
else:
|
||||
open(file, 'w')
|
||||
atime = mtime
|
||||
with open(file, 'w'):
|
||||
atime = mtime
|
||||
os.utime(file, (atime, mtime))
|
||||
|
||||
|
||||
Touch = ActionFactory(touch_func,
|
||||
lambda file: 'Touch(%s)' % get_paths_str(file))
|
||||
|
||||
|
||||
# Internal utility functions
|
||||
|
||||
|
||||
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
||||
"""
|
||||
Creates a new list from 'list' by first interpolating each element
|
||||
|
@ -358,6 +377,7 @@ def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
|||
|
||||
return _concat_ixes(prefix, list, suffix, env)
|
||||
|
||||
|
||||
def _concat_ixes(prefix, list, suffix, env):
|
||||
"""
|
||||
Creates a new list from 'list' by concatenating the 'prefix' and
|
||||
|
@ -391,10 +411,11 @@ def _concat_ixes(prefix, list, suffix, env):
|
|||
if suffix[0] == ' ':
|
||||
result.append(suffix[1:])
|
||||
elif x[-len(suffix):] != suffix:
|
||||
result[-1] = result[-1]+suffix
|
||||
result[-1] = result[-1] + suffix
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
||||
"""
|
||||
This is a wrapper around _concat()/_concat_ixes() that checks for
|
||||
|
@ -447,6 +468,7 @@ def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
|||
|
||||
return c(prefix, stripped, suffix, env)
|
||||
|
||||
|
||||
def processDefines(defs):
|
||||
"""process defines, resolving strings, lists, dictionaries, into a list of
|
||||
strings
|
||||
|
@ -462,7 +484,7 @@ def processDefines(defs):
|
|||
else:
|
||||
l.append(str(d[0]))
|
||||
elif SCons.Util.is_Dict(d):
|
||||
for macro,value in d.items():
|
||||
for macro, value in d.items():
|
||||
if value is not None:
|
||||
l.append(str(macro) + '=' + str(value))
|
||||
else:
|
||||
|
@ -470,7 +492,7 @@ def processDefines(defs):
|
|||
elif SCons.Util.is_String(d):
|
||||
l.append(str(d))
|
||||
else:
|
||||
raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d))
|
||||
raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None." % repr(d))
|
||||
elif SCons.Util.is_Dict(defs):
|
||||
# The items in a dictionary are stored in random order, but
|
||||
# if the order of the command-line options changes from
|
||||
|
@ -479,7 +501,7 @@ def processDefines(defs):
|
|||
# Consequently, we have to sort the keys to ensure a
|
||||
# consistent order...
|
||||
l = []
|
||||
for k,v in sorted(defs.items()):
|
||||
for k, v in sorted(defs.items()):
|
||||
if v is None:
|
||||
l.append(str(k))
|
||||
else:
|
||||
|
@ -497,7 +519,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
|
|||
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
||||
|
||||
|
||||
class NullCmdGenerator(object):
|
||||
class NullCmdGenerator:
|
||||
"""This is a callable class that can be used in place of other
|
||||
command generators if you don't want them to do anything.
|
||||
|
||||
|
@ -516,7 +538,7 @@ class NullCmdGenerator(object):
|
|||
return self.cmd
|
||||
|
||||
|
||||
class Variable_Method_Caller(object):
|
||||
class Variable_Method_Caller:
|
||||
"""A class for finding a construction variable on the stack and
|
||||
calling one of its methods.
|
||||
|
||||
|
@ -528,11 +550,14 @@ class Variable_Method_Caller(object):
|
|||
the way of Memoizing construction environments, because we had to
|
||||
create new environment objects to hold the variables.)
|
||||
"""
|
||||
|
||||
def __init__(self, variable, method):
|
||||
self.variable = variable
|
||||
self.method = method
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
try: 1//0
|
||||
try:
|
||||
1 // 0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
|
@ -547,43 +572,69 @@ class Variable_Method_Caller(object):
|
|||
frame = frame.f_back
|
||||
return None
|
||||
|
||||
# if $version_var is not empty, returns env[flags_var], otherwise returns None
|
||||
|
||||
def __libversionflags(env, version_var, flags_var):
|
||||
"""
|
||||
if version_var is not empty, returns env[flags_var], otherwise returns None
|
||||
:param env:
|
||||
:param version_var:
|
||||
:param flags_var:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if env.subst('$'+version_var):
|
||||
if env.subst('$' + version_var):
|
||||
return env[flags_var]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def __lib_either_version_flag(env, version_var1, version_var2, flags_var):
|
||||
"""
|
||||
if $version_var1 or $version_var2 is not empty, returns env[flags_var], otherwise returns None
|
||||
:param env:
|
||||
:param version_var1:
|
||||
:param version_var2:
|
||||
:param flags_var:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if env.subst('$' + version_var1) or env.subst('$' + version_var2):
|
||||
return env[flags_var]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
ConstructionEnvironment = {
|
||||
'BUILDERS' : {},
|
||||
'SCANNERS' : [ SCons.Tool.SourceFileScanner ],
|
||||
'CONFIGUREDIR' : '#/.sconf_temp',
|
||||
'CONFIGURELOG' : '#/config.log',
|
||||
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
|
||||
'DSUFFIXES' : SCons.Tool.DSuffixes,
|
||||
'ENV' : {},
|
||||
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
|
||||
# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
|
||||
'_concat' : _concat,
|
||||
'_defines' : _defines,
|
||||
'_stripixes' : _stripixes,
|
||||
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
||||
'BUILDERS': {},
|
||||
'SCANNERS': [SCons.Tool.SourceFileScanner],
|
||||
'CONFIGUREDIR': '#/.sconf_temp',
|
||||
'CONFIGURELOG': '#/config.log',
|
||||
'CPPSUFFIXES': SCons.Tool.CSuffixes,
|
||||
'DSUFFIXES': SCons.Tool.DSuffixes,
|
||||
'ENV': {},
|
||||
'IDLSUFFIXES': SCons.Tool.IDLSuffixes,
|
||||
'_concat': _concat,
|
||||
'_defines': _defines,
|
||||
'_stripixes': _stripixes,
|
||||
'_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||
'_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
||||
|
||||
'__libversionflags' : __libversionflags,
|
||||
'__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
||||
'__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
||||
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||
'__libversionflags': __libversionflags,
|
||||
'__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
||||
'__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
||||
'__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||
'__lib_either_version_flag': __lib_either_version_flag,
|
||||
|
||||
'TEMPFILE' : NullCmdGenerator,
|
||||
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
||||
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
||||
'File' : Variable_Method_Caller('TARGET', 'File'),
|
||||
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
|
||||
'TEMPFILE': NullCmdGenerator,
|
||||
'TEMPFILEARGJOIN': ' ',
|
||||
'Dir': Variable_Method_Caller('TARGET', 'Dir'),
|
||||
'Dirs': Variable_Method_Caller('TARGET', 'Dirs'),
|
||||
'File': Variable_Method_Caller('TARGET', 'File'),
|
||||
'RDirs': Variable_Method_Caller('TARGET', 'RDirs'),
|
||||
}
|
||||
|
||||
# Local Variables:
|
File diff suppressed because it is too large
Load diff
119
scons/scons-local-4.1.0/SCons/EnvironmentValues.py
Normal file
119
scons/scons-local-4.1.0/SCons/EnvironmentValues.py
Normal file
|
@ -0,0 +1,119 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
import re
|
||||
|
||||
_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
|
||||
|
||||
_rm = re.compile(r'\$[()]')
|
||||
_remove = re.compile(r'\$\([^$]*(\$[^)][^$]*)*\$\)')
|
||||
|
||||
# Regular expressions for splitting strings and handling substitutions,
|
||||
# for use by the scons_subst() and scons_subst_list() functions:
|
||||
#
|
||||
# The first expression compiled matches all of the $-introduced tokens
|
||||
# that we need to process in some way, and is used for substitutions.
|
||||
# The expressions it matches are:
|
||||
#
|
||||
# "$$"
|
||||
# "$("
|
||||
# "$)"
|
||||
# "$variable" [must begin with alphabetic or underscore]
|
||||
# "${any stuff}"
|
||||
#
|
||||
# The second expression compiled is used for splitting strings into tokens
|
||||
# to be processed, and it matches all of the tokens listed above, plus
|
||||
# the following that affect how arguments do or don't get joined together:
|
||||
#
|
||||
# " " [white space]
|
||||
# "non-white-space" [without any dollar signs]
|
||||
# "$" [single dollar sign]
|
||||
#
|
||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str)
|
||||
|
||||
# This regular expression is used to replace strings of multiple white
|
||||
# space characters in the string result from the scons_subst() function.
|
||||
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
|
||||
|
||||
class ValueTypes:
|
||||
"""
|
||||
Enum to store what type of value the variable holds.
|
||||
"""
|
||||
UNKNOWN = 0
|
||||
STRING = 1
|
||||
CALLABLE = 2
|
||||
VARIABLE = 3
|
||||
|
||||
|
||||
class EnvironmentValue:
|
||||
"""
|
||||
Hold a single value. We're going to cache parsed version of the file
|
||||
We're going to keep track of variables which feed into this values evaluation
|
||||
"""
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.var_type = ValueTypes.UNKNOWN
|
||||
|
||||
if callable(self.value):
|
||||
self.var_type = ValueTypes.CALLABLE
|
||||
else:
|
||||
self.parse_value()
|
||||
|
||||
|
||||
def parse_value(self):
|
||||
"""
|
||||
Scan the string and break into component values
|
||||
"""
|
||||
|
||||
try:
|
||||
if '$' not in self.value:
|
||||
self._parsed = self.value
|
||||
self.var_type = ValueTypes.STRING
|
||||
else:
|
||||
# Now we need to parse the specified string
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
print(result)
|
||||
except TypeError:
|
||||
# likely callable? either way we don't parse
|
||||
self._parsed = self.value
|
||||
|
||||
def parse_trial(self):
|
||||
"""
|
||||
Try alternate parsing methods.
|
||||
:return:
|
||||
"""
|
||||
parts = []
|
||||
for c in self.value:
|
||||
pass
|
||||
|
||||
|
||||
class EnvironmentValues:
|
||||
"""
|
||||
A class to hold all the environment variables
|
||||
"""
|
||||
def __init__(self, **kw):
|
||||
self._dict = {}
|
||||
for k in kw:
|
||||
self._dict[k] = EnvironmentValue(kw[k])
|
39
scons/scons-local-4.1.0/SCons/EnvironmentValuesTest.py
Normal file
39
scons/scons-local-4.1.0/SCons/EnvironmentValuesTest.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
import unittest
|
||||
|
||||
from SCons.EnvironmentValues import EnvironmentValues
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple_environmentValues(self):
|
||||
"""Test comparing SubstitutionEnvironments
|
||||
"""
|
||||
|
||||
env1 = EnvironmentValues(XXX='x')
|
||||
env2 = EnvironmentValues(XXX='x',XX="$X", X1="${X}", X2="$($X$)")
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,73 +20,65 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
"""SCons.Errors
|
||||
"""SCons exception classes.
|
||||
|
||||
This file contains the exception classes used to handle internal
|
||||
and user errors in SCons.
|
||||
Used to handle internal and user errors in SCons.
|
||||
|
||||
"""
|
||||
|
||||
__revision__ = "src/engine/SCons/Errors.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import shutil
|
||||
import SCons.Util
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
""" Errors occurring while building.
|
||||
"""SCons Errors that can occur while building.
|
||||
|
||||
BuildError have the following attributes:
|
||||
=========================================
|
||||
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 error.
|
||||
Must be set to a non-zero value even if the build error is not due
|
||||
to an action returning a non-zero returned code.
|
||||
|
||||
status : the return code of the action that caused the build error.
|
||||
Must be set to a non-zero value even if the build error is not due
|
||||
to an action returning a non-zero returned code.
|
||||
exitstatus: SCons exit status due to this build error.
|
||||
Must be nonzero unless due to an explicit Exit()
|
||||
call. Not always the same as status, since
|
||||
actions return a status code that should be
|
||||
respected, but SCons typically exits with 2
|
||||
irrespective of the return value of the failed
|
||||
action.
|
||||
|
||||
exitstatus : SCons exit status due to this build error.
|
||||
Must be nonzero unless due to an explicit Exit()
|
||||
call. Not always the same as status, since
|
||||
actions return a status code that should be
|
||||
respected, but SCons typically exits with 2
|
||||
irrespective of the return value of the failed
|
||||
action.
|
||||
filename: The name of the file or directory that caused the
|
||||
build error. Set to None if no files are associated with
|
||||
this error. This might be different from the target
|
||||
being built. For example, failure to create the
|
||||
directory in which the target file will appear. It
|
||||
can be None if the error is not due to a particular
|
||||
filename.
|
||||
|
||||
filename : The name of the file or directory that caused the
|
||||
build error. Set to None if no files are associated with
|
||||
this error. This might be different from the target
|
||||
being built. For example, failure to create the
|
||||
directory in which the target file will appear. It
|
||||
can be None if the error is not due to a particular
|
||||
filename.
|
||||
exc_info: Info about exception that caused the build
|
||||
error. Set to (None, None, None) if this build
|
||||
error is not due to an exception.
|
||||
|
||||
exc_info : Info about exception that caused the build
|
||||
error. Set to (None, None, None) if this build
|
||||
error is not due to an exception.
|
||||
Information about the what caused the build error :
|
||||
|
||||
node: the error occurred while building this target node(s)
|
||||
|
||||
Information about the cause of the location of the error:
|
||||
---------------------------------------------------------
|
||||
executor: the executor that caused the build to fail (might
|
||||
be None if the build failures is not due to the
|
||||
executor failing)
|
||||
|
||||
node : the error occured while building this target node(s)
|
||||
action: the action that caused the build to fail (might be
|
||||
None if the build failures is not due to the an
|
||||
action failure)
|
||||
|
||||
executor : the executor that caused the build to fail (might
|
||||
be None if the build failures is not due to the
|
||||
executor failing)
|
||||
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)
|
||||
|
||||
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,
|
||||
|
@ -95,7 +88,7 @@ class BuildError(Exception):
|
|||
|
||||
# py3: errstr should be string and not bytes.
|
||||
|
||||
self.errstr = SCons.Util.to_str(errstr)
|
||||
self.errstr = SCons.Util.to_String(errstr)
|
||||
self.status = status
|
||||
self.exitstatus = exitstatus
|
||||
self.filename = filename
|
||||
|
@ -124,7 +117,7 @@ class UserError(Exception):
|
|||
class StopError(Exception):
|
||||
pass
|
||||
|
||||
class EnvironmentError(Exception):
|
||||
class SConsEnvironmentError(Exception):
|
||||
pass
|
||||
|
||||
class MSVCError(IOError):
|
||||
|
@ -138,14 +131,15 @@ class ExplicitExit(Exception):
|
|||
Exception.__init__(self, *args)
|
||||
|
||||
def convert_to_BuildError(status, exc_info=None):
|
||||
"""
|
||||
Convert any return code a BuildError Exception.
|
||||
"""Convert a return code to a BuildError 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.
|
||||
|
||||
Args:
|
||||
status: can either be a return code or an Exception.
|
||||
exc_info (tuple, optional): explicit exception information.
|
||||
|
||||
"""
|
||||
|
||||
if not exc_info and isinstance(status, Exception):
|
||||
|
@ -184,20 +178,19 @@ def convert_to_BuildError(status, exc_info=None):
|
|||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
|
||||
elif isinstance(status, (EnvironmentError, OSError, IOError)):
|
||||
elif isinstance(status, (SConsEnvironmentError, OSError, IOError)):
|
||||
# If an IOError/OSError happens, raise a BuildError.
|
||||
# Report the name of the file or directory that caused the
|
||||
# error, which might be different from the target being built
|
||||
# (for example, failure to create the directory in which the
|
||||
# target file will appear).
|
||||
try:
|
||||
filename = status.filename
|
||||
except AttributeError:
|
||||
filename = None
|
||||
filename = getattr(status, 'filename', None)
|
||||
strerror = getattr(status, 'strerror', str(status))
|
||||
errno = getattr(status, 'errno', 2)
|
||||
|
||||
buildError = BuildError(
|
||||
errstr=status.strerror,
|
||||
status=status.errno,
|
||||
errstr=strerror,
|
||||
status=errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
|
@ -1,12 +1,6 @@
|
|||
"""SCons.Executor
|
||||
|
||||
A module for executing actions with specific lists of target and source
|
||||
Nodes.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -26,9 +20,8 @@ Nodes.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Executor.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Execute actions with specific lists of target and source Nodes."""
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -36,9 +29,10 @@ import SCons.Debug
|
|||
from SCons.Debug import logInstanceCreation
|
||||
import SCons.Errors
|
||||
import SCons.Memoize
|
||||
from SCons.compat import with_metaclass, NoSlotsPyPy
|
||||
import SCons.Util
|
||||
from SCons.compat import NoSlotsPyPy
|
||||
|
||||
class Batch(object):
|
||||
class Batch:
|
||||
"""Remembers exact association between targets
|
||||
and sources of executor."""
|
||||
|
||||
|
@ -71,7 +65,7 @@ class TSList(collections.UserList):
|
|||
return nl[i]
|
||||
def __getslice__(self, i, j):
|
||||
nl = self.func()
|
||||
i = max(i, 0); j = max(j, 0)
|
||||
i, j = max(i, 0), max(j, 0)
|
||||
return nl[i:j]
|
||||
def __str__(self):
|
||||
nl = self.func()
|
||||
|
@ -80,7 +74,7 @@ class TSList(collections.UserList):
|
|||
nl = self.func()
|
||||
return repr(nl)
|
||||
|
||||
class TSObject(object):
|
||||
class TSObject:
|
||||
"""A class that implements $TARGET or $SOURCE expansions by wrapping
|
||||
an Executor method.
|
||||
"""
|
||||
|
@ -127,7 +121,7 @@ def execute_action_list(obj, target, kw):
|
|||
status = act(*args, **kw)
|
||||
if isinstance(status, SCons.Errors.BuildError):
|
||||
status.executor = obj
|
||||
raise status
|
||||
raise status # TODO pylint E0702: raising int not allowed
|
||||
elif status:
|
||||
msg = "Error %s" % status
|
||||
raise SCons.Errors.BuildError(
|
||||
|
@ -155,7 +149,7 @@ _execute_str_map = {0 : execute_null_str,
|
|||
1 : execute_actions_str}
|
||||
|
||||
|
||||
class Executor(object, with_metaclass(NoSlotsPyPy)):
|
||||
class Executor(object, metaclass=NoSlotsPyPy):
|
||||
"""A class for controlling instances of executing an action.
|
||||
|
||||
This largely exists to hold a single association of an action,
|
||||
|
@ -450,6 +444,8 @@ class Executor(object, with_metaclass(NoSlotsPyPy)):
|
|||
"""Fetch the signature contents. This is the main reason this
|
||||
class exists, so we can compute this once and cache it regardless
|
||||
of how many target or source Nodes there are.
|
||||
|
||||
Returns bytes
|
||||
"""
|
||||
try:
|
||||
return self._memo['get_contents']
|
||||
|
@ -570,7 +566,6 @@ def AddBatchExecutor(key, executor):
|
|||
nullenv = None
|
||||
|
||||
|
||||
import SCons.Util
|
||||
class NullEnvironment(SCons.Util.Null):
|
||||
import SCons.CacheDir
|
||||
_CacheDir_path = None
|
||||
|
@ -587,7 +582,7 @@ def get_NullEnvironment():
|
|||
nullenv = NullEnvironment()
|
||||
return nullenv
|
||||
|
||||
class Null(object, with_metaclass(NoSlotsPyPy)):
|
||||
class Null(object, metaclass=NoSlotsPyPy):
|
||||
"""A null Executor, with a null build Environment, that does
|
||||
nothing when the rest of the methods call it.
|
||||
|
||||
|
@ -613,7 +608,8 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
|
|||
'_execute_str')
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Null')
|
||||
if SCons.Debug.track_instances:
|
||||
logInstanceCreation(self, 'Executor.Null')
|
||||
self.batches = [Batch(kw['targets'][:], [])]
|
||||
def get_build_env(self):
|
||||
return get_NullEnvironment()
|
|
@ -1,13 +1,6 @@
|
|||
"""SCons.Job
|
||||
|
||||
This module defines the Serial and Parallel classes that execute tasks to
|
||||
complete a build. The Jobs class provides a higher level interface to start,
|
||||
stop, and wait on jobs.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -27,9 +20,12 @@ stop, and wait on jobs.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Job.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Serial and Parallel classes to execute build tasks.
|
||||
|
||||
The Jobs class provides a higher level interface to start,
|
||||
stop, and wait on jobs.
|
||||
"""
|
||||
|
||||
import SCons.compat
|
||||
|
||||
|
@ -52,18 +48,18 @@ default_stack_size = 256
|
|||
interrupt_msg = 'Build interrupted.'
|
||||
|
||||
|
||||
class InterruptState(object):
|
||||
def __init__(self):
|
||||
self.interrupted = False
|
||||
class InterruptState:
|
||||
def __init__(self):
|
||||
self.interrupted = False
|
||||
|
||||
def set(self):
|
||||
self.interrupted = True
|
||||
def set(self):
|
||||
self.interrupted = True
|
||||
|
||||
def __call__(self):
|
||||
return self.interrupted
|
||||
def __call__(self):
|
||||
return self.interrupted
|
||||
|
||||
|
||||
class Jobs(object):
|
||||
class Jobs:
|
||||
"""An instance of this class initializes N jobs, and provides
|
||||
methods for starting, stopping, and waiting on all N jobs.
|
||||
"""
|
||||
|
@ -163,7 +159,7 @@ class Jobs(object):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
class Serial(object):
|
||||
class Serial:
|
||||
"""This class is used to execute tasks in series, and is more efficient
|
||||
than Parallel, but is only appropriate for non-parallel builds. Only
|
||||
one instance of this class should be in existence at a time.
|
||||
|
@ -199,7 +195,7 @@ class Serial(object):
|
|||
task.prepare()
|
||||
if task.needs_execute():
|
||||
task.execute()
|
||||
except:
|
||||
except Exception:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
|
@ -264,7 +260,7 @@ else:
|
|||
|
||||
self.resultsQueue.put((task, ok))
|
||||
|
||||
class ThreadPool(object):
|
||||
class ThreadPool:
|
||||
"""This class is responsible for spawning and managing worker threads."""
|
||||
|
||||
def __init__(self, num, stack_size, interrupted):
|
||||
|
@ -281,7 +277,7 @@ else:
|
|||
except AttributeError as e:
|
||||
# Only print a warning if the stack size has been
|
||||
# explicitly set.
|
||||
if not explicit_stack_size is None:
|
||||
if explicit_stack_size is not None:
|
||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||
e.args[0]
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
|
@ -338,7 +334,7 @@ else:
|
|||
worker.join(1.0)
|
||||
self.workers = []
|
||||
|
||||
class Parallel(object):
|
||||
class Parallel:
|
||||
"""This class is used to execute tasks in parallel, and is somewhat
|
||||
less efficient than Serial, but is appropriate for parallel builds.
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,12 +20,8 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Memoize.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """Memoizer
|
||||
"""Decorator-based memoizer to count caching stats.
|
||||
|
||||
A decorator-based implementation to count hits and misses of the computed
|
||||
values that various methods cache in memory.
|
||||
|
@ -106,7 +103,7 @@ use_memoizer = None
|
|||
# Global list of counter objects
|
||||
CounterList = {}
|
||||
|
||||
class Counter(object):
|
||||
class Counter:
|
||||
"""
|
||||
Base class for counting memoization hits and misses.
|
||||
|
|
@ -1,14 +1,6 @@
|
|||
|
||||
"""scons.Node.Alias
|
||||
|
||||
Alias nodes.
|
||||
|
||||
This creates a hash of global Aliases (dummy targets).
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,15 +20,18 @@ This creates a hash of global Aliases (dummy targets).
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Node/Alias.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Alias nodes.
|
||||
|
||||
This creates a hash of global Aliases (dummy targets).
|
||||
"""
|
||||
|
||||
import collections
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
from SCons.Util import MD5signature
|
||||
|
||||
class AliasNameSpace(collections.UserDict):
|
||||
def Alias(self, name, **kw):
|
||||
|
@ -166,7 +161,7 @@ class Alias(SCons.Node.Node):
|
|||
pass
|
||||
|
||||
contents = self.get_contents()
|
||||
csig = SCons.Util.MD5signature(contents)
|
||||
csig = MD5signature(contents)
|
||||
self.get_ninfo().csig = csig
|
||||
return csig
|
||||
|
|
@ -1,17 +1,6 @@
|
|||
"""scons.Node.FS
|
||||
|
||||
File system nodes.
|
||||
|
||||
These Nodes represent the canonical external objects that people think
|
||||
of when they think of building software: files and directories.
|
||||
|
||||
This holds a "default_fs" variable that should be initialized with an FS
|
||||
that can be used by scripts or modules looking for the canonical default.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,9 +20,15 @@ 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
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Node/FS.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""File system nodes.
|
||||
|
||||
These Nodes represent the canonical external objects that people think
|
||||
of when they think of building software: files and directories.
|
||||
|
||||
This holds a "default_fs" variable that should be initialized with an FS
|
||||
that can be used by scripts or modules looking for the canonical default.
|
||||
"""
|
||||
|
||||
import fnmatch
|
||||
import os
|
||||
|
@ -43,22 +38,25 @@ import stat
|
|||
import sys
|
||||
import time
|
||||
import codecs
|
||||
from itertools import chain
|
||||
import importlib.util
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
from SCons.Debug import logInstanceCreation, Trace
|
||||
import SCons.Errors
|
||||
import SCons.Memoize
|
||||
import SCons.Node
|
||||
import SCons.Node.Alias
|
||||
import SCons.Subst
|
||||
import SCons.Util
|
||||
from SCons.Util import MD5signature, MD5filesignature, MD5collect
|
||||
import SCons.Warnings
|
||||
|
||||
from SCons.Debug import Trace
|
||||
|
||||
print_duplicate = 0
|
||||
|
||||
MD5_TIMESTAMP_DEBUG = False
|
||||
|
||||
|
||||
def sconsign_none(node):
|
||||
raise NotImplementedError
|
||||
|
@ -74,6 +72,9 @@ def sconsign_dir(node):
|
|||
_sconsign_map = {0 : sconsign_none,
|
||||
1 : sconsign_dir}
|
||||
|
||||
class FileBuildInfoFileToCsigMappingError(Exception):
|
||||
pass
|
||||
|
||||
class EntryProxyAttributeError(AttributeError):
|
||||
"""
|
||||
An AttributeError subclass for recording and displaying the name
|
||||
|
@ -132,7 +133,10 @@ def initialize_do_splitdrive():
|
|||
global do_splitdrive
|
||||
global has_unc
|
||||
drive, path = os.path.splitdrive('X:/foo')
|
||||
has_unc = hasattr(os.path, 'splitunc')
|
||||
# splitunc is removed from python 3.7 and newer
|
||||
# so we can also just test if splitdrive works with UNC
|
||||
has_unc = (hasattr(os.path, 'splitunc')
|
||||
or os.path.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive')
|
||||
|
||||
do_splitdrive = not not drive or has_unc
|
||||
|
||||
|
@ -272,7 +276,7 @@ def set_duplicate(duplicate):
|
|||
'copy' : _copy_func
|
||||
}
|
||||
|
||||
if not duplicate in Valid_Duplicates:
|
||||
if duplicate not in Valid_Duplicates:
|
||||
raise SCons.Errors.InternalError("The argument of set_duplicate "
|
||||
"should be in Valid_Duplicates")
|
||||
global Link_Funcs
|
||||
|
@ -282,11 +286,13 @@ def set_duplicate(duplicate):
|
|||
Link_Funcs.append(link_dict[func])
|
||||
|
||||
def LinkFunc(target, source, env):
|
||||
# Relative paths cause problems with symbolic links, so
|
||||
# we use absolute paths, which may be a problem for people
|
||||
# who want to move their soft-linked src-trees around. Those
|
||||
# people should use the 'hard-copy' mode, softlinks cannot be
|
||||
# used for that; at least I have no idea how ...
|
||||
"""
|
||||
Relative paths cause problems with symbolic links, so
|
||||
we use absolute paths, which may be a problem for people
|
||||
who want to move their soft-linked src-trees around. Those
|
||||
people should use the 'hard-copy' mode, softlinks cannot be
|
||||
used for that; at least I have no idea how ...
|
||||
"""
|
||||
src = source[0].get_abspath()
|
||||
dest = target[0].get_abspath()
|
||||
dir, file = os.path.split(dest)
|
||||
|
@ -328,7 +334,12 @@ Unlink = SCons.Action.Action(UnlinkFunc, None)
|
|||
|
||||
def MkdirFunc(target, source, env):
|
||||
t = target[0]
|
||||
if not t.exists():
|
||||
# This os.path.exists test looks redundant, but it's possible
|
||||
# when using Install() to install multiple dirs outside the
|
||||
# source tree to get a case where t.exists() is true but
|
||||
# the path does already exist, so this prevents spurious
|
||||
# build failures in that case. See test/Install/multi-dir.
|
||||
if not t.exists() and not os.path.exists(t.get_abspath()):
|
||||
t.fs.mkdir(t.get_abspath())
|
||||
return 0
|
||||
|
||||
|
@ -351,7 +362,7 @@ def get_MkdirBuilder():
|
|||
name = "MkdirBuilder")
|
||||
return MkdirBuilder
|
||||
|
||||
class _Null(object):
|
||||
class _Null:
|
||||
pass
|
||||
|
||||
_null = _Null()
|
||||
|
@ -367,7 +378,7 @@ else:
|
|||
|
||||
|
||||
|
||||
class DiskChecker(object):
|
||||
class DiskChecker:
|
||||
def __init__(self, type, do, ignore):
|
||||
self.type = type
|
||||
self.do = do
|
||||
|
@ -423,7 +434,7 @@ class EntryProxy(SCons.Util.Proxy):
|
|||
|
||||
# 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__
|
||||
# see: https://docs.python.org/3/reference/datamodel.html#object.__hash__
|
||||
__hash__ = SCons.Util.Delegate('__hash__')
|
||||
|
||||
def __get_abspath(self):
|
||||
|
@ -463,7 +474,7 @@ class EntryProxy(SCons.Util.Proxy):
|
|||
return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
|
||||
|
||||
def __get_windows_path(self):
|
||||
"""Return the path with \ as the path separator,
|
||||
r"""Return the path with \ as the path separator,
|
||||
regardless of platform."""
|
||||
if OS_SEP == '\\':
|
||||
return self
|
||||
|
@ -514,7 +525,7 @@ class EntryProxy(SCons.Util.Proxy):
|
|||
except KeyError:
|
||||
try:
|
||||
attr = SCons.Util.Proxy.__getattr__(self, name)
|
||||
except AttributeError as e:
|
||||
except AttributeError:
|
||||
# Raise our own AttributeError subclass with an
|
||||
# overridden __str__() method that identifies the
|
||||
# name of the entry that caused the exception.
|
||||
|
@ -682,13 +693,32 @@ class Base(SCons.Node.Node):
|
|||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def stat(self):
|
||||
try: return self._memo['stat']
|
||||
except KeyError: pass
|
||||
try: result = self.fs.stat(self.get_abspath())
|
||||
except os.error: result = None
|
||||
try:
|
||||
return self._memo['stat']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
result = self.fs.stat(self.get_abspath())
|
||||
except os.error:
|
||||
result = None
|
||||
|
||||
self._memo['stat'] = result
|
||||
return result
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def lstat(self):
|
||||
try:
|
||||
return self._memo['lstat']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
result = self.fs.lstat(self.get_abspath())
|
||||
except os.error:
|
||||
result = None
|
||||
|
||||
self._memo['lstat'] = result
|
||||
return result
|
||||
|
||||
def exists(self):
|
||||
return SCons.Node._exists_map[self._func_exists](self)
|
||||
|
||||
|
@ -696,14 +726,26 @@ class Base(SCons.Node.Node):
|
|||
return SCons.Node._rexists_map[self._func_rexists](self)
|
||||
|
||||
def getmtime(self):
|
||||
st = self.stat()
|
||||
if st: return st[stat.ST_MTIME]
|
||||
else: return None
|
||||
if self.islink():
|
||||
st = self.lstat()
|
||||
else:
|
||||
st = self.stat()
|
||||
|
||||
if st:
|
||||
return st[stat.ST_MTIME]
|
||||
else:
|
||||
return None
|
||||
|
||||
def getsize(self):
|
||||
st = self.stat()
|
||||
if st: return st[stat.ST_SIZE]
|
||||
else: return None
|
||||
if self.islink():
|
||||
st = self.lstat()
|
||||
else:
|
||||
st = self.stat()
|
||||
|
||||
if st:
|
||||
return st[stat.ST_SIZE]
|
||||
else:
|
||||
return None
|
||||
|
||||
def isdir(self):
|
||||
st = self.stat()
|
||||
|
@ -939,13 +981,13 @@ class Entry(Base):
|
|||
def disambiguate(self, must_exist=None):
|
||||
"""
|
||||
"""
|
||||
if self.isdir():
|
||||
self.__class__ = Dir
|
||||
self._morph()
|
||||
elif self.isfile():
|
||||
if self.isfile():
|
||||
self.__class__ = File
|
||||
self._morph()
|
||||
self.clear()
|
||||
elif self.isdir():
|
||||
self.__class__ = Dir
|
||||
self._morph()
|
||||
else:
|
||||
# There was nothing on-disk at this location, so look in
|
||||
# the src directory.
|
||||
|
@ -1047,22 +1089,23 @@ class Entry(Base):
|
|||
_classEntry = Entry
|
||||
|
||||
|
||||
class LocalFS(object):
|
||||
class LocalFS:
|
||||
"""
|
||||
This class implements an abstraction layer for operations involving
|
||||
a local file system. Essentially, this wraps any function in
|
||||
the os, os.path or shutil modules that we use to actually go do
|
||||
anything with or to the local file system.
|
||||
|
||||
# This class implements an abstraction layer for operations involving
|
||||
# a local file system. Essentially, this wraps any function in
|
||||
# the os, os.path or shutil modules that we use to actually go do
|
||||
# anything with or to the local file system.
|
||||
#
|
||||
# Note that there's a very good chance we'll refactor this part of
|
||||
# the architecture in some way as we really implement the interface(s)
|
||||
# for remote file system Nodes. For example, the right architecture
|
||||
# might be to have this be a subclass instead of a base class.
|
||||
# Nevertheless, we're using this as a first step in that direction.
|
||||
#
|
||||
# We're not using chdir() yet because the calling subclass method
|
||||
# needs to use os.chdir() directly to avoid recursion. Will we
|
||||
# really need this one?
|
||||
Note that there's a very good chance we'll refactor this part of
|
||||
the architecture in some way as we really implement the interface(s)
|
||||
for remote file system Nodes. For example, the right architecture
|
||||
might be to have this be a subclass instead of a base class.
|
||||
Nevertheless, we're using this as a first step in that direction.
|
||||
|
||||
We're not using chdir() yet because the calling subclass method
|
||||
needs to use os.chdir() directly to avoid recursion. Will we
|
||||
really need this one?
|
||||
"""
|
||||
#def chdir(self, path):
|
||||
# return os.chdir(path)
|
||||
def chmod(self, path, mode):
|
||||
|
@ -1391,7 +1434,7 @@ class FS(LocalFS):
|
|||
self.Top.addRepository(d)
|
||||
|
||||
def PyPackageDir(self, modulename):
|
||||
"""Locate the directory of a given python module name
|
||||
r"""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
|
||||
|
@ -1400,22 +1443,10 @@ class FS(LocalFS):
|
|||
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)
|
||||
|
||||
# Python3 Code
|
||||
modspec = importlib.util.find_spec(modulename)
|
||||
dirpath = os.path.dirname(modspec.origin)
|
||||
return self._lookup(dirpath, None, Dir, True)
|
||||
|
||||
|
||||
|
@ -1522,9 +1553,7 @@ class Dir(Base):
|
|||
self.repositories = []
|
||||
self.srcdir = None
|
||||
|
||||
self.entries = {}
|
||||
self.entries['.'] = self
|
||||
self.entries['..'] = self.dir
|
||||
self.entries = {'.': self, '..': self.dir}
|
||||
self.cwd = self
|
||||
self.searched = 0
|
||||
self._sconsign = None
|
||||
|
@ -1585,7 +1614,7 @@ class Dir(Base):
|
|||
This clears any cached information that is invalidated by changing
|
||||
the repository."""
|
||||
|
||||
for node in list(self.entries.values()):
|
||||
for node in self.entries.values():
|
||||
if node != self.dir:
|
||||
if node != self and isinstance(node, Dir):
|
||||
node.__clearRepositoryCache(duplicate)
|
||||
|
@ -1596,7 +1625,7 @@ class Dir(Base):
|
|||
except AttributeError:
|
||||
pass
|
||||
if duplicate is not None:
|
||||
node.duplicate=duplicate
|
||||
node.duplicate = duplicate
|
||||
|
||||
def __resetDuplicate(self, node):
|
||||
if node != self:
|
||||
|
@ -1662,7 +1691,7 @@ class Dir(Base):
|
|||
return result
|
||||
|
||||
def addRepository(self, dir):
|
||||
if dir != self and not dir in self.repositories:
|
||||
if dir != self and dir not in self.repositories:
|
||||
self.repositories.append(dir)
|
||||
dir._tpath = '.'
|
||||
self.__clearRepositoryCache()
|
||||
|
@ -1702,7 +1731,7 @@ class Dir(Base):
|
|||
if self is other:
|
||||
result = '.'
|
||||
|
||||
elif not other in self._path_elements:
|
||||
elif other not in self._path_elements:
|
||||
try:
|
||||
other_dir = other.get_dir()
|
||||
except AttributeError:
|
||||
|
@ -1836,7 +1865,7 @@ class Dir(Base):
|
|||
node is called which has a child directory, the child
|
||||
directory should return the hash of its contents."""
|
||||
contents = self.get_contents()
|
||||
return SCons.Util.MD5signature(contents)
|
||||
return MD5signature(contents)
|
||||
|
||||
def do_duplicate(self, src):
|
||||
pass
|
||||
|
@ -2234,7 +2263,7 @@ class RootDir(Dir):
|
|||
this directory.
|
||||
"""
|
||||
|
||||
__slots__ = ['_lookupDict']
|
||||
__slots__ = ('_lookupDict', 'abspath', 'path')
|
||||
|
||||
def __init__(self, drive, fs):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
|
||||
|
@ -2276,13 +2305,17 @@ class RootDir(Dir):
|
|||
self._tpath = dirname
|
||||
self.dirname = dirname
|
||||
|
||||
# EntryProxy interferes with this class and turns drive paths on
|
||||
# Windows such as "C:" into "C:\C:". Avoid this problem by setting
|
||||
# commonly-accessed attributes directly.
|
||||
self.abspath = self._abspath
|
||||
self.path = self._path
|
||||
|
||||
self._morph()
|
||||
|
||||
self.duplicate = 0
|
||||
self._lookupDict = {}
|
||||
self._lookupDict = {'': self, '/': self}
|
||||
|
||||
self._lookupDict[''] = self
|
||||
self._lookupDict['/'] = self
|
||||
self.root = self
|
||||
# The // entry is necessary because os.path.normpath()
|
||||
# preserves double slashes at the beginning of a path on Posix
|
||||
|
@ -2302,9 +2335,7 @@ class RootDir(Dir):
|
|||
self.repositories = []
|
||||
self.srcdir = None
|
||||
|
||||
self.entries = {}
|
||||
self.entries['.'] = self
|
||||
self.entries['..'] = self.dir
|
||||
self.entries = {'.': self, '..': self.dir}
|
||||
self.cwd = self
|
||||
self.searched = 0
|
||||
self._sconsign = None
|
||||
|
@ -2440,7 +2471,7 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
|
|||
"""
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj,'__slots__',()):
|
||||
for name in getattr(obj, '__slots__', ()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
|
@ -2462,11 +2493,42 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
|
|||
if key not in ('__weakref__',):
|
||||
setattr(self, key, value)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.csig == other.csig and self.timestamp == other.timestamp and self.size == other.size
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class FileBuildInfo(SCons.Node.BuildInfoBase):
|
||||
__slots__ = ()
|
||||
"""
|
||||
This is info loaded from sconsign.
|
||||
|
||||
Attributes unique to FileBuildInfo:
|
||||
dependency_map : Caches file->csig mapping
|
||||
for all dependencies. Currently this is only used when using
|
||||
MD5-timestamp decider.
|
||||
It's used to ensure that we copy the correct csig from the
|
||||
previous build to be written to .sconsign when current build
|
||||
is done. Previously the matching of csig to file was strictly
|
||||
by order they appeared in bdepends, bsources, or bimplicit,
|
||||
and so a change in order or count of any of these could
|
||||
yield writing wrong csig, and then false positive rebuilds
|
||||
"""
|
||||
__slots__ = ['dependency_map', ]
|
||||
current_version_id = 2
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
|
||||
# If any attributes are changed in FileBuildInfo, we need to
|
||||
# invalidate the cached map of file name to content signature
|
||||
# heald in dependency_map. Currently only used with
|
||||
# MD5-timestamp decider
|
||||
if key != 'dependency_map' and hasattr(self, 'dependency_map'):
|
||||
del self.dependency_map
|
||||
|
||||
return super(FileBuildInfo, self).__setattr__(key, value)
|
||||
|
||||
def convert_to_sconsign(self):
|
||||
"""
|
||||
Converts this FileBuildInfo object for writing to a .sconsign file
|
||||
|
@ -2567,7 +2629,8 @@ class File(Base):
|
|||
NodeInfo = FileNodeInfo
|
||||
BuildInfo = FileBuildInfo
|
||||
|
||||
md5_chunksize = 64
|
||||
# Although the command-line argument is in kilobytes, this is in bytes.
|
||||
md5_chunksize = 65536
|
||||
|
||||
def diskcheck_match(self):
|
||||
diskcheck_match(self, self.isdir,
|
||||
|
@ -2630,11 +2693,13 @@ class File(Base):
|
|||
def scanner_key(self):
|
||||
return self.get_suffix()
|
||||
|
||||
def get_contents(self):
|
||||
def get_contents(self) -> bytes:
|
||||
"""Return the contents of the file as bytes."""
|
||||
return SCons.Node._get_contents_map[self._func_get_contents](self)
|
||||
|
||||
def get_text_contents(self):
|
||||
"""
|
||||
def get_text_contents(self) -> str:
|
||||
"""Return the contents of the file in text form.
|
||||
|
||||
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.
|
||||
|
@ -2658,19 +2723,16 @@ class File(Base):
|
|||
try:
|
||||
return contents.decode('latin-1')
|
||||
except UnicodeDecodeError as e:
|
||||
return contents.decode('utf-8', error='backslashreplace')
|
||||
return contents.decode('utf-8', errors='backslashreplace')
|
||||
|
||||
|
||||
def get_content_hash(self):
|
||||
"""
|
||||
Compute and return the MD5 hash for this file.
|
||||
"""
|
||||
def get_content_hash(self) -> str:
|
||||
"""Compute and return the hash of the file contents."""
|
||||
if not self.rexists():
|
||||
return SCons.Util.MD5signature('')
|
||||
return MD5signature(SCons.Util.NOFILE)
|
||||
fname = self.rfile().get_abspath()
|
||||
try:
|
||||
cs = SCons.Util.MD5filesignature(fname,
|
||||
chunksize=SCons.Node.FS.File.md5_chunksize*1024)
|
||||
cs = MD5filesignature(fname, chunksize=File.md5_chunksize)
|
||||
except EnvironmentError as e:
|
||||
if not e.filename:
|
||||
e.filename = fname
|
||||
|
@ -2678,7 +2740,7 @@ class File(Base):
|
|||
return cs
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_size(self):
|
||||
def get_size(self) -> int:
|
||||
try:
|
||||
return self._memo['get_size']
|
||||
except KeyError:
|
||||
|
@ -2687,14 +2749,14 @@ class File(Base):
|
|||
if self.rexists():
|
||||
size = self.rfile().getsize()
|
||||
else:
|
||||
size = 0
|
||||
# sentinel value for doesn't exist, even in repository
|
||||
size = -1
|
||||
|
||||
self._memo['get_size'] = size
|
||||
|
||||
return size
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_timestamp(self):
|
||||
def get_timestamp(self) -> int:
|
||||
try:
|
||||
return self._memo['get_timestamp']
|
||||
except KeyError:
|
||||
|
@ -2706,7 +2768,6 @@ class File(Base):
|
|||
timestamp = 0
|
||||
|
||||
self._memo['get_timestamp'] = timestamp
|
||||
|
||||
return timestamp
|
||||
|
||||
convert_copy_attrs = [
|
||||
|
@ -2718,7 +2779,6 @@ class File(Base):
|
|||
'ninfo',
|
||||
]
|
||||
|
||||
|
||||
convert_sig_attrs = [
|
||||
'bsourcesigs',
|
||||
'bimplicitsigs',
|
||||
|
@ -2971,7 +3031,7 @@ class File(Base):
|
|||
|
||||
@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
|
||||
|
||||
if not hasattr(self.attributes, 'keep_targetinfo'):
|
||||
|
@ -3059,7 +3119,10 @@ class File(Base):
|
|||
SCons.Node.Node.prepare(self)
|
||||
|
||||
if self.get_state() != SCons.Node.up_to_date:
|
||||
if self.exists():
|
||||
# Exists will report False for dangling symlinks so if it
|
||||
# exists or is a link (which would mean it's a dangling
|
||||
# link) then we should remove it as appropriate.
|
||||
if self.exists() or self.islink():
|
||||
if self.is_derived() and not self.precious:
|
||||
self._rmv_existing()
|
||||
else:
|
||||
|
@ -3108,7 +3171,7 @@ class File(Base):
|
|||
# SIGNATURE SUBSYSTEM
|
||||
#
|
||||
|
||||
def get_max_drift_csig(self):
|
||||
def get_max_drift_csig(self) -> str:
|
||||
"""
|
||||
Returns the content signature currently stored for this node
|
||||
if it's been unmodified longer than the max_drift value, or the
|
||||
|
@ -3134,15 +3197,8 @@ class File(Base):
|
|||
|
||||
return None
|
||||
|
||||
def get_csig(self):
|
||||
"""
|
||||
Generate a node's content signature, the digested signature
|
||||
of its content.
|
||||
|
||||
node - the node
|
||||
cache - alternate node to use for the signature cache
|
||||
returns - the content signature
|
||||
"""
|
||||
def get_csig(self) -> str:
|
||||
"""Generate a node's content signature."""
|
||||
ninfo = self.get_ninfo()
|
||||
try:
|
||||
return ninfo.csig
|
||||
|
@ -3151,9 +3207,11 @@ class File(Base):
|
|||
|
||||
csig = self.get_max_drift_csig()
|
||||
if csig is None:
|
||||
|
||||
try:
|
||||
if self.get_size() < SCons.Node.FS.File.md5_chunksize:
|
||||
size = self.get_size()
|
||||
if size == -1:
|
||||
contents = SCons.Util.NOFILE
|
||||
elif size < File.md5_chunksize:
|
||||
contents = self.get_contents()
|
||||
else:
|
||||
csig = self.get_content_hash()
|
||||
|
@ -3225,46 +3283,232 @@ class File(Base):
|
|||
self._memo['changed'] = has_changed
|
||||
return has_changed
|
||||
|
||||
def changed_content(self, target, prev_ni):
|
||||
def changed_content(self, target, prev_ni, repo_node=None):
|
||||
cur_csig = self.get_csig()
|
||||
try:
|
||||
return cur_csig != prev_ni.csig
|
||||
except AttributeError:
|
||||
return 1
|
||||
|
||||
def changed_state(self, target, prev_ni):
|
||||
def changed_state(self, target, prev_ni, repo_node=None):
|
||||
return self.state != SCons.Node.up_to_date
|
||||
|
||||
def changed_timestamp_then_content(self, target, prev_ni):
|
||||
if not self.changed_timestamp_match(target, prev_ni):
|
||||
|
||||
# Caching node -> string mapping for the below method
|
||||
__dmap_cache = {}
|
||||
__dmap_sig_cache = {}
|
||||
|
||||
|
||||
def _build_dependency_map(self, binfo):
|
||||
"""
|
||||
Build mapping from file -> signature
|
||||
|
||||
Args:
|
||||
self - self
|
||||
binfo - buildinfo from node being considered
|
||||
|
||||
Returns:
|
||||
dictionary of file->signature mappings
|
||||
"""
|
||||
|
||||
# For an "empty" binfo properties like bsources
|
||||
# do not exist: check this to avoid exception.
|
||||
if (len(binfo.bsourcesigs) + len(binfo.bdependsigs) +
|
||||
len(binfo.bimplicitsigs)) == 0:
|
||||
return {}
|
||||
|
||||
binfo.dependency_map = { child:signature for child, signature in zip(chain(binfo.bsources, binfo.bdepends, binfo.bimplicit),
|
||||
chain(binfo.bsourcesigs, binfo.bdependsigs, binfo.bimplicitsigs))}
|
||||
|
||||
return binfo.dependency_map
|
||||
|
||||
# @profile
|
||||
def _add_strings_to_dependency_map(self, dmap):
|
||||
"""
|
||||
In the case comparing node objects isn't sufficient, we'll add the strings for the nodes to the dependency map
|
||||
:return:
|
||||
"""
|
||||
|
||||
first_string = str(next(iter(dmap)))
|
||||
|
||||
# print("DMAP:%s"%id(dmap))
|
||||
if first_string not in dmap:
|
||||
string_dict = {str(child): signature for child, signature in dmap.items()}
|
||||
dmap.update(string_dict)
|
||||
return dmap
|
||||
|
||||
def _get_previous_signatures(self, dmap):
|
||||
"""
|
||||
Return a list of corresponding csigs from previous
|
||||
build in order of the node/files in children.
|
||||
|
||||
Args:
|
||||
self - self
|
||||
dmap - Dictionary of file -> csig
|
||||
|
||||
Returns:
|
||||
List of csigs for provided list of children
|
||||
"""
|
||||
prev = []
|
||||
# MD5_TIMESTAMP_DEBUG = False
|
||||
|
||||
if len(dmap) == 0:
|
||||
if MD5_TIMESTAMP_DEBUG: print("Nothing dmap shortcutting")
|
||||
return None
|
||||
elif MD5_TIMESTAMP_DEBUG: print("len(dmap):%d"%len(dmap))
|
||||
|
||||
|
||||
# First try retrieving via Node
|
||||
if MD5_TIMESTAMP_DEBUG: print("Checking if self is in map:%s id:%s type:%s"%(str(self), id(self), type(self)))
|
||||
df = dmap.get(self, False)
|
||||
if df:
|
||||
return df
|
||||
|
||||
# Now check if self's repository file is in map.
|
||||
rf = self.rfile()
|
||||
if MD5_TIMESTAMP_DEBUG: print("Checking if self.rfile is in map:%s id:%s type:%s"%(str(rf), id(rf), type(rf)))
|
||||
rfm = dmap.get(rf, False)
|
||||
if rfm:
|
||||
return rfm
|
||||
|
||||
# get default string for node and then also string swapping os.altsep for os.sep (/ for \)
|
||||
c_strs = [str(self)]
|
||||
|
||||
if os.altsep:
|
||||
c_strs.append(c_strs[0].replace(os.sep, os.altsep))
|
||||
|
||||
# In some cases the dependency_maps' keys are already strings check.
|
||||
# Check if either string is now in dmap.
|
||||
for s in c_strs:
|
||||
if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map :%s" % s)
|
||||
df = dmap.get(s, False)
|
||||
if df:
|
||||
return df
|
||||
|
||||
# Strings don't exist in map, add them and try again
|
||||
# If there are no strings in this dmap, then add them.
|
||||
# This may not be necessary, we could walk the nodes in the dmap and check each string
|
||||
# rather than adding ALL the strings to dmap. In theory that would be n/2 vs 2n str() calls on node
|
||||
# if not dmap.has_strings:
|
||||
dmap = self._add_strings_to_dependency_map(dmap)
|
||||
|
||||
# In some cases the dependency_maps' keys are already strings check.
|
||||
# Check if either string is now in dmap.
|
||||
for s in c_strs:
|
||||
if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map (now with strings) :%s" % s)
|
||||
df = dmap.get(s, False)
|
||||
if df:
|
||||
return df
|
||||
|
||||
# Lastly use nodes get_path() to generate string and see if that's in dmap
|
||||
if not df:
|
||||
try:
|
||||
self.get_ninfo().csig = prev_ni.csig
|
||||
# this should yield a path which matches what's in the sconsign
|
||||
c_str = self.get_path()
|
||||
if os.altsep:
|
||||
c_str = c_str.replace(os.sep, os.altsep)
|
||||
|
||||
if MD5_TIMESTAMP_DEBUG: print("Checking if self.get_path is in map (now with strings) :%s" % s)
|
||||
|
||||
df = dmap.get(c_str, None)
|
||||
|
||||
except AttributeError as e:
|
||||
raise FileBuildInfoFileToCsigMappingError("No mapping from file name to content signature for :%s"%c_str)
|
||||
|
||||
return df
|
||||
|
||||
def changed_timestamp_then_content(self, target, prev_ni, node=None):
|
||||
"""
|
||||
Used when decider for file is Timestamp-MD5
|
||||
|
||||
NOTE: If the timestamp hasn't changed this will skip md5'ing the
|
||||
file and just copy the prev_ni provided. If the prev_ni
|
||||
is wrong. It will propagate it.
|
||||
See: https://github.com/SCons/scons/issues/2980
|
||||
|
||||
Args:
|
||||
self - dependency
|
||||
target - target
|
||||
prev_ni - The NodeInfo object loaded from previous builds .sconsign
|
||||
node - Node instance. Check this node for file existence/timestamp
|
||||
if specified.
|
||||
|
||||
Returns:
|
||||
Boolean - Indicates if node(File) has changed.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self
|
||||
# Now get sconsign name -> csig map and then get proper prev_ni if possible
|
||||
bi = node.get_stored_info().binfo
|
||||
rebuilt = False
|
||||
try:
|
||||
dependency_map = bi.dependency_map
|
||||
except AttributeError as e:
|
||||
dependency_map = self._build_dependency_map(bi)
|
||||
rebuilt = True
|
||||
|
||||
if len(dependency_map) == 0:
|
||||
# If there's no dependency map, there's no need to find the
|
||||
# prev_ni as there aren't any
|
||||
# shortcut the rest of the logic
|
||||
if MD5_TIMESTAMP_DEBUG: print("Skipping checks len(dmap)=0")
|
||||
|
||||
# We still need to get the current file's csig
|
||||
# This should be slightly faster than calling self.changed_content(target, new_prev_ni)
|
||||
self.get_csig()
|
||||
return True
|
||||
|
||||
new_prev_ni = self._get_previous_signatures(dependency_map)
|
||||
new = self.changed_timestamp_match(target, new_prev_ni)
|
||||
|
||||
if MD5_TIMESTAMP_DEBUG:
|
||||
old = self.changed_timestamp_match(target, prev_ni)
|
||||
|
||||
if old != new:
|
||||
print("Mismatch self.changed_timestamp_match(%s, prev_ni) old:%s new:%s"%(str(target), old, new))
|
||||
new_prev_ni = self._get_previous_signatures(dependency_map)
|
||||
|
||||
if not new:
|
||||
try:
|
||||
# NOTE: We're modifying the current node's csig in a query.
|
||||
self.get_ninfo().csig = new_prev_ni.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
return False
|
||||
return self.changed_content(target, prev_ni)
|
||||
return self.changed_content(target, new_prev_ni)
|
||||
|
||||
def changed_timestamp_newer(self, target, prev_ni):
|
||||
def changed_timestamp_newer(self, target, prev_ni, repo_node=None):
|
||||
try:
|
||||
return self.get_timestamp() > target.get_timestamp()
|
||||
except AttributeError:
|
||||
return 1
|
||||
|
||||
def changed_timestamp_match(self, target, prev_ni):
|
||||
def changed_timestamp_match(self, target, prev_ni, repo_node=None):
|
||||
"""
|
||||
Return True if the timestamps don't match or if there is no previous timestamp
|
||||
:param target:
|
||||
:param prev_ni: Information about the node from the previous build
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
return self.get_timestamp() != prev_ni.timestamp
|
||||
except AttributeError:
|
||||
return 1
|
||||
|
||||
def is_up_to_date(self):
|
||||
"""Check for whether the Node is current
|
||||
In all cases self is the target we're checking to see if it's up to date
|
||||
"""
|
||||
|
||||
T = 0
|
||||
if T: Trace('is_up_to_date(%s):' % self)
|
||||
if not self.exists():
|
||||
if T: Trace(' not self.exists():')
|
||||
# The file doesn't exist locally...
|
||||
# The file (always a target) doesn't exist locally...
|
||||
r = self.rfile()
|
||||
if r != self:
|
||||
# ...but there is one in a Repository...
|
||||
# ...but there is one (always a target) in a Repository...
|
||||
if not self.changed(r):
|
||||
if T: Trace(' changed(%s):' % r)
|
||||
# ...and it's even up-to-date...
|
||||
|
@ -3272,7 +3516,9 @@ class File(Base):
|
|||
# ...and they'd like a local copy.
|
||||
e = LocalCopy(self, r, None)
|
||||
if isinstance(e, SCons.Errors.BuildError):
|
||||
raise
|
||||
# Likely this should be re-raising exception e
|
||||
# (which would be BuildError)
|
||||
raise e
|
||||
SCons.Node.store_info_map[self.store_info](self)
|
||||
if T: Trace(' 1\n')
|
||||
return 1
|
||||
|
@ -3293,11 +3539,14 @@ class File(Base):
|
|||
result = self
|
||||
if not self.exists():
|
||||
norm_name = _my_normcase(self.name)
|
||||
for dir in self.dir.get_all_rdirs():
|
||||
try: node = dir.entries[norm_name]
|
||||
except KeyError: node = dir.file_on_disk(self.name)
|
||||
for repo_dir in self.dir.get_all_rdirs():
|
||||
try:
|
||||
node = repo_dir.entries[norm_name]
|
||||
except KeyError:
|
||||
node = repo_dir.file_on_disk(self.name)
|
||||
|
||||
if node and node.exists() and \
|
||||
(isinstance(node, File) or isinstance(node, Entry) \
|
||||
(isinstance(node, File) or isinstance(node, Entry)
|
||||
or not node.is_derived()):
|
||||
result = node
|
||||
# Copy over our local attributes to the repository
|
||||
|
@ -3317,6 +3566,28 @@ class File(Base):
|
|||
self._memo['rfile'] = result
|
||||
return result
|
||||
|
||||
def find_repo_file(self):
|
||||
"""
|
||||
For this node, find if there exists a corresponding file in one or more repositories
|
||||
:return: list of corresponding files in repositories
|
||||
"""
|
||||
retvals = []
|
||||
|
||||
norm_name = _my_normcase(self.name)
|
||||
for repo_dir in self.dir.get_all_rdirs():
|
||||
try:
|
||||
node = repo_dir.entries[norm_name]
|
||||
except KeyError:
|
||||
node = repo_dir.file_on_disk(self.name)
|
||||
|
||||
if node and node.exists() and \
|
||||
(isinstance(node, File) or isinstance(node, Entry)
|
||||
or not node.is_derived()):
|
||||
retvals.append(node)
|
||||
|
||||
return retvals
|
||||
|
||||
|
||||
def rstr(self):
|
||||
return str(self.rfile())
|
||||
|
||||
|
@ -3341,8 +3612,7 @@ class File(Base):
|
|||
|
||||
cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self)
|
||||
if not self.exists() and cachefile and os.path.exists(cachefile):
|
||||
self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \
|
||||
SCons.Node.FS.File.md5_chunksize * 1024)
|
||||
self.cachedir_csig = MD5filesignature(cachefile, File.md5_chunksize)
|
||||
else:
|
||||
self.cachedir_csig = self.get_csig()
|
||||
return self.cachedir_csig
|
||||
|
@ -3362,7 +3632,7 @@ class File(Base):
|
|||
|
||||
executor = self.get_executor()
|
||||
|
||||
result = self.contentsig = SCons.Util.MD5signature(executor.get_contents())
|
||||
result = self.contentsig = MD5signature(executor.get_contents())
|
||||
return result
|
||||
|
||||
def get_cachedir_bsig(self):
|
||||
|
@ -3374,6 +3644,8 @@ class File(Base):
|
|||
because multiple targets built by the same action will all
|
||||
have the same build signature, and we have to differentiate
|
||||
them somehow.
|
||||
|
||||
Signature should normally be string of hex digits.
|
||||
"""
|
||||
try:
|
||||
return self.cachesig
|
||||
|
@ -3383,12 +3655,15 @@ class File(Base):
|
|||
# Collect signatures for all children
|
||||
children = self.children()
|
||||
sigs = [n.get_cachedir_csig() for n in children]
|
||||
|
||||
# Append this node's signature...
|
||||
sigs.append(self.get_contents_sig())
|
||||
|
||||
# ...and it's path
|
||||
sigs.append(self.get_internal_path())
|
||||
|
||||
# Merge this all into a single signature
|
||||
result = self.cachesig = SCons.Util.MD5collect(sigs)
|
||||
result = self.cachesig = MD5collect(sigs)
|
||||
return result
|
||||
|
||||
default_fs = None
|
||||
|
@ -3399,7 +3674,7 @@ def get_default_fs():
|
|||
default_fs = FS()
|
||||
return default_fs
|
||||
|
||||
class FileFinder(object):
|
||||
class FileFinder:
|
||||
"""
|
||||
"""
|
||||
|
||||
|
@ -3472,7 +3747,7 @@ class FileFinder(object):
|
|||
if verbose and not callable(verbose):
|
||||
if not SCons.Util.is_String(verbose):
|
||||
verbose = "find_file"
|
||||
_verbose = u' %s: ' % verbose
|
||||
_verbose = ' %s: ' % verbose
|
||||
verbose = lambda s: sys.stdout.write(_verbose + s)
|
||||
|
||||
filedir, filename = os.path.split(filename)
|
|
@ -1,11 +1,6 @@
|
|||
"""scons.Node.Python
|
||||
|
||||
Python nodes.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,12 +20,14 @@ Python nodes.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Node/Python.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Python nodes."""
|
||||
|
||||
import SCons.Node
|
||||
|
||||
_memo_lookup_map = {}
|
||||
|
||||
|
||||
class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
||||
__slots__ = ('csig',)
|
||||
current_version_id = 2
|
||||
|
@ -38,18 +35,18 @@ class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
|||
field_list = ['csig']
|
||||
|
||||
def str_to_node(self, s):
|
||||
return Value(s)
|
||||
return ValueWithMemo(s)
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Return all fields that shall be pickled. Walk the slots in the class
|
||||
hierarchy and add those to the state dictionary. If a '__dict__' slot is
|
||||
available, copy all entries to the dictionary. Also include the version
|
||||
id, which is fixed for all instances of a class.
|
||||
hierarchy and add those to the state dictionary. If a '__dict__' slot
|
||||
is available, copy all entries to the dictionary. Also include the
|
||||
version id, which is fixed for all instances of a class.
|
||||
"""
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj,'__slots__',()):
|
||||
for name in getattr(obj, '__slots__', ()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
|
@ -76,6 +73,7 @@ class ValueBuildInfo(SCons.Node.BuildInfoBase):
|
|||
__slots__ = ()
|
||||
current_version_id = 2
|
||||
|
||||
|
||||
class Value(SCons.Node.Node):
|
||||
"""A class for Python variables, typically passed on the command line
|
||||
or generated by a script, but not from a file or some other source.
|
||||
|
@ -84,7 +82,7 @@ class Value(SCons.Node.Node):
|
|||
NodeInfo = ValueNodeInfo
|
||||
BuildInfo = ValueBuildInfo
|
||||
|
||||
def __init__(self, value, built_value=None):
|
||||
def __init__(self, value, built_value=None, name=None):
|
||||
SCons.Node.Node.__init__(self)
|
||||
self.value = value
|
||||
self.changed_since_last_build = 6
|
||||
|
@ -92,6 +90,13 @@ class Value(SCons.Node.Node):
|
|||
if built_value is not None:
|
||||
self.built_value = built_value
|
||||
|
||||
# Set a name so it can be a child of a node and not break
|
||||
# its parent's implementation of Node.get_contents.
|
||||
if name:
|
||||
self.name = name
|
||||
else:
|
||||
self.name = str(value)
|
||||
|
||||
def str_for_display(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
@ -124,7 +129,7 @@ class Value(SCons.Node.Node):
|
|||
self.built_value = self.value
|
||||
return self.built_value
|
||||
|
||||
def get_text_contents(self):
|
||||
def get_text_contents(self) -> str:
|
||||
"""By the assumption that the node.built_value is a
|
||||
deterministic product of the sources, the contents of a Value
|
||||
are the concatenation of all the contents of its sources. As
|
||||
|
@ -133,37 +138,63 @@ class Value(SCons.Node.Node):
|
|||
###TODO: something reasonable about universal newlines
|
||||
contents = str(self.value)
|
||||
for kid in self.children(None):
|
||||
contents = contents + kid.get_contents().decode()
|
||||
# Get csig() value of child as this is more efficent
|
||||
contents = contents + kid.get_csig()
|
||||
return contents
|
||||
|
||||
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 get_contents(self) -> bytes:
|
||||
"""Get contents for signature calculations."""
|
||||
return self.get_text_contents().encode()
|
||||
|
||||
def changed_since_last_build(self, target, prev_ni):
|
||||
cur_csig = self.get_csig()
|
||||
try:
|
||||
return cur_csig != prev_ni.csig
|
||||
except AttributeError:
|
||||
return 1
|
||||
return True
|
||||
|
||||
def get_csig(self, calc=None):
|
||||
"""Because we're a Python value node and don't have a real
|
||||
timestamp, we get to ignore the calculator and just use the
|
||||
value contents."""
|
||||
value contents.
|
||||
|
||||
Returns string. Ideally string of hex digits. (Not bytes)
|
||||
"""
|
||||
try:
|
||||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
contents = self.get_contents()
|
||||
|
||||
contents = self.get_text_contents()
|
||||
|
||||
self.get_ninfo().csig = contents
|
||||
return contents
|
||||
|
||||
|
||||
def ValueWithMemo(value, built_value=None, name=None):
|
||||
"""
|
||||
Memoized Value() node factory.
|
||||
"""
|
||||
global _memo_lookup_map
|
||||
|
||||
# No current support for memoizing a value that needs to be built.
|
||||
if built_value:
|
||||
return Value(value, built_value, name=name)
|
||||
|
||||
try:
|
||||
memo_lookup_key = hash((value, name))
|
||||
except TypeError:
|
||||
# Non-primitive types will hit this codepath.
|
||||
return Value(value, name=name)
|
||||
|
||||
try:
|
||||
return _memo_lookup_map[memo_lookup_key]
|
||||
except KeyError:
|
||||
v = Value(value, built_value, name)
|
||||
_memo_lookup_map[memo_lookup_key] = v
|
||||
return v
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
|
@ -1,28 +1,6 @@
|
|||
"""SCons.Node
|
||||
|
||||
The Node package for the SCons software construction utility.
|
||||
|
||||
This is, in many ways, the heart of SCons.
|
||||
|
||||
A Node is where we encapsulate all of the dependency information about
|
||||
any thing that SCons can build, or about any thing which SCons can use
|
||||
to build some other thing. The canonical "thing," of course, is a file,
|
||||
but a Node can also represent something remote (like a web page) or
|
||||
something completely abstract (like an Alias).
|
||||
|
||||
Each specific type of "thing" is specifically represented by a subclass
|
||||
of the Node base class: Node.FS.File for files, Node.Alias for aliases,
|
||||
etc. Dependency information is kept here in the base class, and
|
||||
information specific to files/aliases/etc. is in the subclass. The
|
||||
goal, if we've done this correctly, is that any type of "thing" should
|
||||
be able to depend on any other type of "thing."
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -43,21 +21,36 @@ from __future__ import print_function
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Node/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""The Node package for the SCons software construction utility.
|
||||
|
||||
This is, in many ways, the heart of SCons.
|
||||
|
||||
A Node is where we encapsulate all of the dependency information about
|
||||
any thing that SCons can build, or about any thing which SCons can use
|
||||
to build some other thing. The canonical "thing," of course, is a file,
|
||||
but a Node can also represent something remote (like a web page) or
|
||||
something completely abstract (like an Alias).
|
||||
|
||||
Each specific type of "thing" is specifically represented by a subclass
|
||||
of the Node base class: Node.FS.File for files, Node.Alias for aliases,
|
||||
etc. Dependency information is kept here in the base class, and
|
||||
information specific to files/aliases/etc. is in the subclass. The
|
||||
goal, if we've done this correctly, is that any type of "thing" should
|
||||
be able to depend on any other type of "thing."
|
||||
|
||||
"""
|
||||
|
||||
import collections
|
||||
import copy
|
||||
from itertools import chain
|
||||
from itertools import chain, zip_longest
|
||||
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
import SCons.Executor
|
||||
import SCons.Memoize
|
||||
import SCons.Util
|
||||
|
||||
from SCons.Debug import Trace
|
||||
|
||||
from SCons.compat import with_metaclass, NoSlotsPyPy
|
||||
from SCons.compat import NoSlotsPyPy
|
||||
from SCons.Debug import logInstanceCreation, Trace
|
||||
from SCons.Util import MD5signature
|
||||
|
||||
print_duplicate = 0
|
||||
|
||||
|
@ -102,9 +95,12 @@ implicit_deps_changed = 0
|
|||
|
||||
# A variable that can be set to an interface-specific function be called
|
||||
# to annotate a Node with information about its creation.
|
||||
def do_nothing(node): pass
|
||||
def do_nothing_node(node): pass
|
||||
|
||||
Annotate = do_nothing
|
||||
Annotate = do_nothing_node
|
||||
|
||||
# global set for recording all processed SContruct/SConscript nodes
|
||||
SConscriptNodes = set()
|
||||
|
||||
# Gets set to 'True' if we're running in interactive mode. Is
|
||||
# currently used to release parts of a target's info during
|
||||
|
@ -139,6 +135,7 @@ def exists_entry(node):
|
|||
node.disambiguate()
|
||||
return _exists_map[node._func_exists](node)
|
||||
|
||||
|
||||
def exists_file(node):
|
||||
# Duplicate from source path if we are set up to do this.
|
||||
if node.duplicate and not node.is_derived() and not node.linked:
|
||||
|
@ -155,7 +152,7 @@ def exists_file(node):
|
|||
# The source file does not exist. Make sure no old
|
||||
# copy remains in the variant directory.
|
||||
if print_duplicate:
|
||||
print("dup: no src for %s, unlinking old variant copy"%self)
|
||||
print("dup: no src for %s, unlinking old variant copy" % node)
|
||||
if exists_base(node) or node.islink():
|
||||
node.fs.unlink(node.get_internal_path())
|
||||
# Return None explicitly because the Base.exists() call
|
||||
|
@ -249,7 +246,7 @@ _target_from_source_map = {0 : target_from_source_none,
|
|||
#
|
||||
# First, the single decider functions
|
||||
#
|
||||
def changed_since_last_build_node(node, target, prev_ni):
|
||||
def changed_since_last_build_node(node, target, prev_ni, repo_node=None):
|
||||
"""
|
||||
|
||||
Must be overridden in a specific subclass to return True if this
|
||||
|
@ -269,27 +266,33 @@ def changed_since_last_build_node(node, target, prev_ni):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def changed_since_last_build_alias(node, target, prev_ni):
|
||||
|
||||
def changed_since_last_build_alias(node, target, prev_ni, repo_node=None):
|
||||
cur_csig = node.get_csig()
|
||||
try:
|
||||
return cur_csig != prev_ni.csig
|
||||
except AttributeError:
|
||||
return 1
|
||||
|
||||
def changed_since_last_build_entry(node, target, prev_ni):
|
||||
|
||||
def changed_since_last_build_entry(node, target, prev_ni, repo_node=None):
|
||||
node.disambiguate()
|
||||
return _decider_map[node.changed_since_last_build](node, target, prev_ni)
|
||||
return _decider_map[node.changed_since_last_build](node, target, prev_ni, repo_node)
|
||||
|
||||
def changed_since_last_build_state_changed(node, target, prev_ni):
|
||||
return (node.state != SCons.Node.up_to_date)
|
||||
|
||||
def decide_source(node, target, prev_ni):
|
||||
return target.get_build_env().decide_source(node, target, prev_ni)
|
||||
def changed_since_last_build_state_changed(node, target, prev_ni, repo_node=None):
|
||||
return node.state != SCons.Node.up_to_date
|
||||
|
||||
def decide_target(node, target, prev_ni):
|
||||
return target.get_build_env().decide_target(node, target, prev_ni)
|
||||
|
||||
def changed_since_last_build_python(node, target, prev_ni):
|
||||
def decide_source(node, target, prev_ni, repo_node=None):
|
||||
return target.get_build_env().decide_source(node, target, prev_ni, repo_node)
|
||||
|
||||
|
||||
def decide_target(node, target, prev_ni, repo_node=None):
|
||||
return target.get_build_env().decide_target(node, target, prev_ni, repo_node)
|
||||
|
||||
|
||||
def changed_since_last_build_python(node, target, prev_ni, repo_node=None):
|
||||
cur_csig = node.get_csig()
|
||||
try:
|
||||
return cur_csig != prev_ni.csig
|
||||
|
@ -341,7 +344,7 @@ store_info_map = {0 : store_info_pass,
|
|||
|
||||
# Classes for signature info for Nodes.
|
||||
|
||||
class NodeInfoBase(object):
|
||||
class NodeInfoBase:
|
||||
"""
|
||||
The generic base class for signature information for a Node.
|
||||
|
||||
|
@ -380,6 +383,7 @@ class NodeInfoBase(object):
|
|||
"""
|
||||
state = other.__getstate__()
|
||||
self.__setstate__(state)
|
||||
|
||||
def format(self, field_list=None, names=0):
|
||||
if field_list is None:
|
||||
try:
|
||||
|
@ -435,7 +439,7 @@ class NodeInfoBase(object):
|
|||
setattr(self, key, value)
|
||||
|
||||
|
||||
class BuildInfoBase(object):
|
||||
class BuildInfoBase:
|
||||
"""
|
||||
The generic base class for build information for a Node.
|
||||
|
||||
|
@ -498,13 +502,14 @@ class BuildInfoBase(object):
|
|||
setattr(self, key, value)
|
||||
|
||||
|
||||
class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||
class Node(object, metaclass=NoSlotsPyPy):
|
||||
"""The base Node class, for entities that we know how to
|
||||
build, or use to build other Nodes.
|
||||
"""
|
||||
|
||||
__slots__ = ['sources',
|
||||
'sources_set',
|
||||
'target_peers',
|
||||
'_specific_sources',
|
||||
'depends',
|
||||
'depends_set',
|
||||
|
@ -545,7 +550,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
'_func_get_contents',
|
||||
'_func_target_from_source']
|
||||
|
||||
class Attrs(object):
|
||||
class Attrs:
|
||||
__slots__ = ('shared', '__dict__')
|
||||
|
||||
|
||||
|
@ -599,6 +604,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
self._func_rexists = 1
|
||||
self._func_get_contents = 0
|
||||
self._func_target_from_source = 0
|
||||
self.ninfo = None
|
||||
|
||||
self.clear_memoized_values()
|
||||
|
||||
|
@ -665,7 +671,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
executor.cleanup()
|
||||
|
||||
def reset_executor(self):
|
||||
"Remove cached executor; forces recompute when needed."
|
||||
"""Remove cached executor; forces recompute when needed."""
|
||||
try:
|
||||
delattr(self, 'executor')
|
||||
except AttributeError:
|
||||
|
@ -760,6 +766,25 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
for parent in self.waiting_parents:
|
||||
parent.implicit = None
|
||||
|
||||
# Handle issue where builder emits more than one target and
|
||||
# the source file for the builder is generated.
|
||||
# in that case only the first target was getting it's .implicit
|
||||
# cleared when the source file is built (second scan).
|
||||
# leaving only partial implicits from scan before source file is generated
|
||||
# typically the compiler only. Then scanned files are appended
|
||||
# This is persisted to sconsign and rebuild causes false rebuilds
|
||||
# because the ordering of the implicit list then changes to what it
|
||||
# should have been.
|
||||
# This is at least the following bugs
|
||||
# https://github.com/SCons/scons/issues/2811
|
||||
# https://jira.mongodb.org/browse/SERVER-33111
|
||||
try:
|
||||
for peer in parent.target_peers:
|
||||
peer.implicit = None
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
self.clear()
|
||||
|
||||
if self.pseudo:
|
||||
|
@ -786,25 +811,21 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
|
||||
def release_target_info(self):
|
||||
"""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
|
||||
as possible for clean builds and update runs, in order
|
||||
to minimize the overall memory consumption.
|
||||
This is where we try to release as many target node infos
|
||||
as possible for clean builds and update runs, in order
|
||||
to minimize the overall memory consumption.
|
||||
|
||||
By purging attributes that aren't needed any longer after
|
||||
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
|
||||
the memory shortly afterwards.
|
||||
By purging attributes that aren't needed any longer after
|
||||
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
|
||||
the memory shortly afterwards.
|
||||
|
||||
@see: built() and File.release_target_info()
|
||||
"""
|
||||
@see: built() and File.release_target_info()
|
||||
"""
|
||||
pass
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def add_to_waiting_s_e(self, node):
|
||||
self.waiting_s_e.add(node)
|
||||
|
||||
|
@ -840,10 +861,12 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
self.clear_memoized_values()
|
||||
self.ninfo = self.new_ninfo()
|
||||
self.executor_cleanup()
|
||||
try:
|
||||
delattr(self, '_calculated_sig')
|
||||
except AttributeError:
|
||||
pass
|
||||
for attr in ['cachedir_csig', 'cachesig', 'contentsig']:
|
||||
try:
|
||||
delattr(self, attr)
|
||||
except AttributeError:
|
||||
pass
|
||||
self.cached = 0
|
||||
self.includes = None
|
||||
|
||||
def clear_memoized_values(self):
|
||||
|
@ -863,7 +886,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
than simply examining the builder attribute directly ("if
|
||||
node.builder: ..."). When the builder attribute is examined
|
||||
directly, it ends up calling __getattr__ for both the __len__
|
||||
and __nonzero__ attributes on instances of our Builder Proxy
|
||||
and __bool__ attributes on instances of our Builder Proxy
|
||||
class(es), generating a bazillion extra calls and slowing
|
||||
things down immensely.
|
||||
"""
|
||||
|
@ -912,6 +935,18 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
"""
|
||||
return _is_derived_map[self._func_is_derived](self)
|
||||
|
||||
def is_sconscript(self):
|
||||
""" Returns true if this node is an sconscript """
|
||||
return self in SConscriptNodes
|
||||
|
||||
def is_conftest(self):
|
||||
""" Returns true if this node is an conftest node"""
|
||||
try:
|
||||
self.attributes.conftest_node
|
||||
except AttributeError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def alter_targets(self):
|
||||
"""Return a list of alternate targets for this Node.
|
||||
"""
|
||||
|
@ -1097,11 +1132,10 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
return ninfo
|
||||
|
||||
def get_ninfo(self):
|
||||
try:
|
||||
return self.ninfo
|
||||
except AttributeError:
|
||||
self.ninfo = self.new_ninfo()
|
||||
if self.ninfo is not None:
|
||||
return self.ninfo
|
||||
self.ninfo = self.new_ninfo()
|
||||
return self.ninfo
|
||||
|
||||
def new_binfo(self):
|
||||
binfo = self.BuildInfo()
|
||||
|
@ -1133,10 +1167,10 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
|
||||
if self.has_builder():
|
||||
binfo.bact = str(executor)
|
||||
binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
|
||||
binfo.bactsig = MD5signature(executor.get_contents())
|
||||
|
||||
if self._specific_sources:
|
||||
sources = [ s for s in self.sources if not s in ignore_set]
|
||||
sources = [s for s in self.sources if s not in ignore_set]
|
||||
|
||||
else:
|
||||
sources = executor.get_unignored_sources(self, self.ignore)
|
||||
|
@ -1145,13 +1179,17 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
binfo.bsources = [s for s in sources if s not in seen and not seen.add(s)]
|
||||
binfo.bsourcesigs = [s.get_ninfo() for s in binfo.bsources]
|
||||
|
||||
binfo.bdepends = [d for d in self.depends if d not in ignore_set]
|
||||
binfo.bdependsigs = [d.get_ninfo() for d in self.depends]
|
||||
|
||||
binfo.bdepends = self.depends
|
||||
binfo.bdependsigs = [d.get_ninfo() for d in self.depends if d not in ignore_set]
|
||||
|
||||
binfo.bimplicit = self.implicit or []
|
||||
binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit if i not in ignore_set]
|
||||
|
||||
# Because self.implicit is initialized to None (and not empty list [])
|
||||
# we have to handle this case
|
||||
if not self.implicit:
|
||||
binfo.bimplicit = []
|
||||
binfo.bimplicitsigs = []
|
||||
else:
|
||||
binfo.bimplicit = [i for i in self.implicit if i not in ignore_set]
|
||||
binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit]
|
||||
|
||||
return binfo
|
||||
|
||||
|
@ -1167,7 +1205,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
ninfo = self.get_ninfo()
|
||||
ninfo.csig = SCons.Util.MD5signature(self.get_contents())
|
||||
ninfo.csig = MD5signature(self.get_contents())
|
||||
return self.ninfo.csig
|
||||
|
||||
def get_cachedir_csig(self):
|
||||
|
@ -1213,7 +1251,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
return _exists_map[self._func_exists](self)
|
||||
|
||||
def rexists(self):
|
||||
"""Does this node exist locally or in a repositiory?"""
|
||||
"""Does this node exist locally or in a repository?"""
|
||||
# There are no repositories by default:
|
||||
return _rexists_map[self._func_rexists](self)
|
||||
|
||||
|
@ -1452,14 +1490,13 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
result = True
|
||||
|
||||
for child, prev_ni in zip(children, then):
|
||||
if _decider_map[child.changed_since_last_build](child, self, prev_ni):
|
||||
if _decider_map[child.changed_since_last_build](child, self, prev_ni, node):
|
||||
if t: Trace(': %s changed' % child)
|
||||
result = True
|
||||
|
||||
contents = self.get_executor().get_contents()
|
||||
if self.has_builder():
|
||||
import SCons.Util
|
||||
newsig = SCons.Util.MD5signature(contents)
|
||||
contents = self.get_executor().get_contents()
|
||||
newsig = MD5signature(contents)
|
||||
if bi.bactsig != newsig:
|
||||
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
|
||||
result = True
|
||||
|
@ -1607,29 +1644,39 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
|||
# so we only print them after running them through this lambda
|
||||
# to turn them into the right relative Node and then return
|
||||
# its string.
|
||||
def stringify( s, E=self.dir.Entry ) :
|
||||
def stringify( s, E=self.dir.Entry):
|
||||
if hasattr( s, 'dir' ) :
|
||||
return str(E(s))
|
||||
return str(s)
|
||||
|
||||
lines = []
|
||||
|
||||
removed = [x for x in old_bkids if not x in new_bkids]
|
||||
removed = [x for x in old_bkids if x not in new_bkids]
|
||||
if removed:
|
||||
removed = list(map(stringify, removed))
|
||||
removed = [stringify(r) for r in removed]
|
||||
fmt = "`%s' is no longer a dependency\n"
|
||||
lines.extend([fmt % s for s in removed])
|
||||
|
||||
for k in new_bkids:
|
||||
if not k in old_bkids:
|
||||
if k not in old_bkids:
|
||||
lines.append("`%s' is a new dependency\n" % stringify(k))
|
||||
elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
|
||||
lines.append("`%s' changed\n" % stringify(k))
|
||||
else:
|
||||
changed = _decider_map[k.changed_since_last_build](k, self, osig[k])
|
||||
|
||||
if changed:
|
||||
lines.append("`%s' changed\n" % stringify(k))
|
||||
|
||||
if len(lines) == 0 and old_bkids != new_bkids:
|
||||
lines.append("the dependency order changed:\n" +
|
||||
"%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) +
|
||||
"%snew: %s\n" % (' '*15, list(map(stringify, new_bkids))))
|
||||
lines.append("the dependency order changed:\n")
|
||||
lines.append("->Sources\n")
|
||||
for (o,n) in zip_longest(old.bsources, new.bsources, fillvalue=None):
|
||||
lines.append("Old:%s\tNew:%s\n"%(o,n))
|
||||
lines.append("->Depends\n")
|
||||
for (o,n) in zip_longest(old.bdepends, new.bdepends, fillvalue=None):
|
||||
lines.append("Old:%s\tNew:%s\n"%(o,n))
|
||||
lines.append("->Implicit\n")
|
||||
for (o,n) in zip_longest(old.bimplicit, new.bimplicit, fillvalue=None):
|
||||
lines.append("Old:%s\tNew:%s\n"%(o,n))
|
||||
|
||||
if len(lines) == 0:
|
||||
def fmt_with_title(title, strlines):
|
||||
|
@ -1666,13 +1713,12 @@ def get_children(node, parent): return node.children()
|
|||
def ignore_cycle(node, stack): pass
|
||||
def do_nothing(node, parent): pass
|
||||
|
||||
class Walker(object):
|
||||
class Walker:
|
||||
"""An iterator for walking a Node tree.
|
||||
|
||||
This is depth-first, children are visited before the parent.
|
||||
The Walker object can be initialized with any node, and
|
||||
returns the next node on the descent with each get_next() call.
|
||||
'kids_func' is an optional function that will be called to
|
||||
get the children of a node instead of calling 'children'.
|
||||
'cycle_func' is an optional function that will be called
|
||||
when a cycle is detected.
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,17 +20,13 @@
|
|||
# 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/PathList.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """SCons.PathList
|
||||
|
||||
A module for handling lists of directory paths (the sort of things
|
||||
that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
|
||||
efficiency as we can, while still keeping the evaluation delayed so that we
|
||||
Do the Right Thing (almost) regardless of how the variable is specified.
|
||||
"""Handle lists of directory paths.
|
||||
|
||||
These are the path lists that get set as CPPPATH, LIBPATH,
|
||||
etc.) with as much caching of data and efficiency as we can, while
|
||||
still keeping the evaluation delayed so that we Do the Right Thing
|
||||
(almost) regardless of how the variable is specified.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -66,7 +63,7 @@ def node_conv(obj):
|
|||
result = get()
|
||||
return result
|
||||
|
||||
class _PathList(object):
|
||||
class _PathList:
|
||||
"""
|
||||
An actual PathList object.
|
||||
"""
|
||||
|
@ -143,7 +140,7 @@ class _PathList(object):
|
|||
return tuple(result)
|
||||
|
||||
|
||||
class PathListCache(object):
|
||||
class PathListCache:
|
||||
"""
|
||||
A class to handle caching of PathList lookups.
|
||||
|
|
@ -1,26 +1,6 @@
|
|||
"""SCons.Platform
|
||||
|
||||
SCons platform selection.
|
||||
|
||||
This looks for modules that define a callable object that can modify a
|
||||
construction environment as appropriate for a given platform.
|
||||
|
||||
Note that we take a more simplistic view of "platform" than Python does.
|
||||
We're looking for a single string that determines a set of
|
||||
tool-independent variables with which to initialize a construction
|
||||
environment. Consequently, we'll examine both sys.platform and os.name
|
||||
(and anything else that might come in to play) in order to return some
|
||||
specification which is unique enough for our purposes.
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "platform specification" in an arbitrary callable function.
|
||||
No one needs to use or tie in to this subsystem in order to roll
|
||||
their own platform definition.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -40,14 +20,29 @@ their own platform definition.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Platform/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""SCons platform selection.
|
||||
|
||||
Looks for modules that define a callable object that can modify a
|
||||
construction environment as appropriate for a given platform.
|
||||
|
||||
Note that we take a more simplistic view of "platform" than Python does.
|
||||
We're looking for a single string that determines a set of
|
||||
tool-independent variables with which to initialize a construction
|
||||
environment. Consequently, we'll examine both sys.platform and os.name
|
||||
(and anything else that might come in to play) in order to return some
|
||||
specification which is unique enough for our purposes.
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "platform specification" in an arbitrary callable function.
|
||||
No one needs to use or tie in to this subsystem in order to roll
|
||||
their own platform definition.
|
||||
"""
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import imp
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
@ -60,8 +55,8 @@ import SCons.Tool
|
|||
def platform_default():
|
||||
"""Return the platform string for our execution environment.
|
||||
|
||||
The returned value should map to one of the SCons/Platform/*.py
|
||||
files. Since we're architecture independent, though, we don't
|
||||
The returned value should map to one of the SCons/Platform/\*.py
|
||||
files. Since scons is architecture independent, though, we don't
|
||||
care about the machine architecture.
|
||||
"""
|
||||
osname = os.name
|
||||
|
@ -87,6 +82,7 @@ def platform_default():
|
|||
else:
|
||||
return sys.platform
|
||||
|
||||
|
||||
def platform_module(name = platform_default()):
|
||||
"""Return the imported module for the platform.
|
||||
|
||||
|
@ -100,13 +96,8 @@ def platform_module(name = platform_default()):
|
|||
eval(full_name)
|
||||
else:
|
||||
try:
|
||||
file, path, desc = imp.find_module(name,
|
||||
sys.modules['SCons.Platform'].__path__)
|
||||
try:
|
||||
mod = imp.load_module(full_name, file, path, desc)
|
||||
finally:
|
||||
if file:
|
||||
file.close()
|
||||
# the specific platform module is a relative import
|
||||
mod = importlib.import_module("." + name, __name__)
|
||||
except ImportError:
|
||||
try:
|
||||
import zipimport
|
||||
|
@ -117,12 +108,14 @@ def platform_module(name = platform_default()):
|
|||
setattr(SCons.Platform, name, mod)
|
||||
return sys.modules[full_name]
|
||||
|
||||
|
||||
def DefaultToolList(platform, env):
|
||||
"""Select a default tool list for the specified platform.
|
||||
"""
|
||||
return SCons.Tool.tool_list(platform, env)
|
||||
|
||||
class PlatformSpec(object):
|
||||
|
||||
class PlatformSpec:
|
||||
def __init__(self, name, generate):
|
||||
self.name = name
|
||||
self.generate = generate
|
||||
|
@ -133,22 +126,35 @@ class PlatformSpec(object):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class TempFileMunge(object):
|
||||
"""A callable class. You can set an Environment variable to this,
|
||||
then call it with a string argument, then it will perform temporary
|
||||
file substitution on it. This is used to circumvent the long command
|
||||
line limitation.
|
||||
|
||||
Example usage:
|
||||
env["TEMPFILE"] = TempFileMunge
|
||||
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
|
||||
class TempFileMunge:
|
||||
"""Convert long command lines to use a temporary file.
|
||||
|
||||
You can set an Environment variable (usually `TEMPFILE`) to this,
|
||||
then call it with a string argument, and it will perform temporary
|
||||
file substitution on it. This is used to circumvent limitations on
|
||||
the length of command lines. Example::
|
||||
|
||||
env["TEMPFILE"] = TempFileMunge
|
||||
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
|
||||
|
||||
By default, the name of the temporary file used begins with a
|
||||
prefix of '@'. This may be configred for other tool chains by
|
||||
setting '$TEMPFILEPREFIX'.
|
||||
prefix of '@'. This may be configured for other tool chains by
|
||||
setting the TEMPFILEPREFIX variable. Example::
|
||||
|
||||
env["TEMPFILEPREFIX"] = '-@' # diab compiler
|
||||
env["TEMPFILEPREFIX"] = '-via' # arm tool chain
|
||||
env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint
|
||||
|
||||
You can configure the extension of the temporary file through the
|
||||
TEMPFILESUFFIX variable, which defaults to '.lnk' (see comments
|
||||
in the code below). Example::
|
||||
|
||||
env["TEMPFILESUFFIX"] = '.lnt' # PC Lint
|
||||
|
||||
Entries in the temporary file are separated by the value of the
|
||||
TEMPFILEARGJOIN variable, which defaults to an OS-appropriate value.
|
||||
|
||||
env["TEMPFILEPREFIX"] = '-@' # diab compiler
|
||||
env["TEMPFILEPREFIX"] = '-via' # arm tool chain
|
||||
"""
|
||||
def __init__(self, cmd, cmdstr = None):
|
||||
self.cmd = cmd
|
||||
|
@ -182,24 +188,41 @@ class TempFileMunge(object):
|
|||
|
||||
# Check if we already created the temporary file for this target
|
||||
# It should have been previously done by Action.strfunction() call
|
||||
node = target[0] if SCons.Util.is_List(target) else target
|
||||
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
|
||||
if node is not None else None
|
||||
if cmdlist is not None :
|
||||
if SCons.Util.is_List(target):
|
||||
node = target[0]
|
||||
else:
|
||||
node = target
|
||||
|
||||
cmdlist = None
|
||||
|
||||
if SCons.Util.is_List(self.cmd):
|
||||
cmdlist_key = tuple(self.cmd)
|
||||
else:
|
||||
cmdlist_key = self.cmd
|
||||
|
||||
if node and hasattr(node.attributes, 'tempfile_cmdlist'):
|
||||
cmdlist = node.attributes.tempfile_cmdlist.get(cmdlist_key, None)
|
||||
if cmdlist is not None:
|
||||
return cmdlist
|
||||
|
||||
# We do a normpath because mktemp() has what appears to be
|
||||
# a bug in Windows that will use a forward slash as a path
|
||||
# delimiter. Windows's link mistakes that for a command line
|
||||
# switch and barfs.
|
||||
#
|
||||
# We use the .lnk suffix for the benefit of the Phar Lap
|
||||
# Default to the .lnk suffix for the benefit of the Phar Lap
|
||||
# linkloc linker, which likes to append an .lnk suffix if
|
||||
# none is given.
|
||||
(fd, tmp) = tempfile.mkstemp('.lnk', text=True)
|
||||
native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp))
|
||||
if 'TEMPFILESUFFIX' in env:
|
||||
suffix = env.subst('$TEMPFILESUFFIX')
|
||||
else:
|
||||
suffix = '.lnk'
|
||||
|
||||
if env.get('SHELL',None) == 'sh':
|
||||
if 'TEMPFILEDIR' in env:
|
||||
tempfile_dir = env.subst('$TEMPFILEDIR')
|
||||
os.makedirs(tempfile_dir, exist_ok=True)
|
||||
else:
|
||||
tempfile_dir = None
|
||||
|
||||
fd, tmp = tempfile.mkstemp(suffix, dir=tempfile_dir, text=True)
|
||||
native_tmp = SCons.Util.get_native_path(tmp)
|
||||
|
||||
if env.get('SHELL', None) == 'sh':
|
||||
# The sh shell will try to escape the backslashes in the
|
||||
# path, so unescape them.
|
||||
native_tmp = native_tmp.replace('\\', r'\\\\')
|
||||
|
@ -217,8 +240,10 @@ class TempFileMunge(object):
|
|||
prefix = '@'
|
||||
|
||||
args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
|
||||
os.write(fd, bytearray(" ".join(args) + "\n",'utf-8'))
|
||||
join_char = env.get('TEMPFILEARGJOIN',' ')
|
||||
os.write(fd, bytearray(join_char.join(args) + "\n",'utf-8'))
|
||||
os.close(fd)
|
||||
|
||||
# XXX Using the SCons.Action.print_actions value directly
|
||||
# like this is bogus, but expedient. This class should
|
||||
# really be rewritten as an Action that defines the
|
||||
|
@ -239,19 +264,41 @@ class TempFileMunge(object):
|
|||
source) if self.cmdstr is not None else ''
|
||||
# Print our message only if XXXCOMSTR returns an empty string
|
||||
if len(cmdstr) == 0 :
|
||||
print("Using tempfile "+native_tmp+" for command line:\n"+
|
||||
str(cmd[0]) + " " + " ".join(args))
|
||||
cmdstr = ("Using tempfile "+native_tmp+" for command line:\n"+
|
||||
str(cmd[0]) + " " + " ".join(args))
|
||||
self._print_cmd_str(target, source, env, cmdstr)
|
||||
|
||||
cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
|
||||
|
||||
# Store the temporary file command list into the target Node.attributes
|
||||
# to avoid creating two temporary files one for print and one for execute.
|
||||
cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
|
||||
if node is not None:
|
||||
try :
|
||||
setattr(node.attributes, 'tempfile_cmdlist', cmdlist)
|
||||
try:
|
||||
# Storing in tempfile_cmdlist by self.cmd provided when intializing
|
||||
# $TEMPFILE{} fixes issue raised in PR #3140 and #3553
|
||||
node.attributes.tempfile_cmdlist[cmdlist_key] = cmdlist
|
||||
except AttributeError:
|
||||
pass
|
||||
node.attributes.tempfile_cmdlist = {cmdlist_key:cmdlist}
|
||||
|
||||
return cmdlist
|
||||
|
||||
def _print_cmd_str(self, target, source, env, cmdstr):
|
||||
# check if the user has specified a cmd line print function
|
||||
print_func = None
|
||||
try:
|
||||
get = env.get
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
print_func = get('PRINT_CMD_LINE_FUNC')
|
||||
|
||||
# use the default action cmd line print if user did not supply one
|
||||
if not print_func:
|
||||
action = SCons.Action._ActionAction()
|
||||
action.print_cmd_line(cmdstr, target, source, env)
|
||||
else:
|
||||
print_func(cmdstr, target, source, env)
|
||||
|
||||
|
||||
def Platform(name = platform_default()):
|
||||
"""Select a canned Platform specification.
|
|
@ -1,14 +1,6 @@
|
|||
"""engine.SCons.Platform.aix
|
||||
|
||||
Platform-specific initialization for IBM AIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,11 +20,14 @@ selection method.
|
|||
# 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/Platform/aix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for IBM AIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from . import posix
|
||||
|
@ -55,6 +50,7 @@ def get_xlc(env, xlc=None, packages=[]):
|
|||
pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package],
|
||||
stdin = 'devnull',
|
||||
stderr = 'devnull',
|
||||
universal_newlines=True,
|
||||
stdout = subprocess.PIPE)
|
||||
# output of lslpp is something like this:
|
||||
# #Path:Fileset:File
|
||||
|
@ -69,14 +65,13 @@ def get_xlc(env, xlc=None, packages=[]):
|
|||
or ('/' not in xlc and filename.endswith('/' + xlc)):
|
||||
xlcVersion = fileset.split()[1]
|
||||
xlcPath, sep, xlc = filename.rpartition('/')
|
||||
pass
|
||||
pass
|
||||
return (xlcPath, xlc, xlcVersion)
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 21576
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Platform.cygwin
|
||||
|
||||
Platform-specific initialization for Cygwin systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,13 +20,26 @@ selection method.
|
|||
# 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/Platform/cygwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for Cygwin systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from . import posix
|
||||
from SCons.Platform import TempFileMunge
|
||||
|
||||
CYGWIN_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
CYGWIN_DEFAULT_PATHS = [
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\cygwin\bin'
|
||||
]
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
|
|
@ -1,14 +1,6 @@
|
|||
"""engine.SCons.Platform.darwin
|
||||
|
||||
Platform-specific initialization for Mac OS X systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,13 @@ selection method.
|
|||
# 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/Platform/darwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for Mac OS X systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
import os
|
||||
|
@ -56,12 +52,11 @@ def generate(env):
|
|||
|
||||
for file in filelist:
|
||||
if os.path.isfile(file):
|
||||
f = open(file, 'r')
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line:
|
||||
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
||||
f.close()
|
||||
with open(file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line:
|
||||
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
||||
|
||||
# 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):
|
|
@ -1,14 +1,6 @@
|
|||
"""engine.SCons.Platform.hpux
|
||||
|
||||
Platform-specific initialization for HP-UX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,13 @@ selection method.
|
|||
# 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/Platform/hpux.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for HP-UX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
|
||||
|
@ -39,6 +35,8 @@ def generate(env):
|
|||
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 2045000
|
||||
|
||||
env['SHLIBSUFFIX'] = '.sl'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Platform.irix
|
||||
|
||||
Platform-specific initialization for SGI IRIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,13 @@ selection method.
|
|||
# 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/Platform/irix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for SGI IRIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
|
33
scons/scons-local-4.1.0/SCons/Platform/mingw.py
Normal file
33
scons/scons-local-4.1.0/SCons/Platform/mingw.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
"""Platform-specific initialization for the MinGW system."""
|
||||
|
||||
import sys
|
||||
|
||||
MINGW_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
MINGW_DEFAULT_PATHS = [
|
||||
r'C:\msys64',
|
||||
r'C:\msys'
|
||||
]
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Platform.os2
|
||||
|
||||
Platform-specific initialization for OS/2 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,14 @@ selection method.
|
|||
# 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/Platform/os2.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for OS/2 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import win32
|
||||
|
||||
def generate(env):
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Platform.posix
|
||||
|
||||
Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,19 +20,22 @@ selection method.
|
|||
# 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/Platform/posix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
import select
|
||||
|
||||
import SCons.Util
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
|
||||
exitvalmap = {
|
||||
2 : 127,
|
||||
|
@ -48,7 +43,7 @@ exitvalmap = {
|
|||
}
|
||||
|
||||
def escape(arg):
|
||||
"escape shell special characters"
|
||||
"""escape shell special characters"""
|
||||
slash = '\\'
|
||||
special = '"$'
|
||||
|
||||
|
@ -89,7 +84,7 @@ def generate(env):
|
|||
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin'
|
||||
env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin:/snap/bin'
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.o'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
|
@ -119,6 +114,9 @@ def generate(env):
|
|||
# Must be able to have GCC and DMD work in the same build, so:
|
||||
env['__DRPATH'] = '$_DRPATH'
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
|||
"""engine.SCons.Platform.sunos
|
||||
|
||||
Platform-specific initialization for Sun systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,13 @@ selection method.
|
|||
# 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/Platform/sunos.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for Sun systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
|
115
scons/scons-local-4.1.0/SCons/Platform/virtualenv.py
Normal file
115
scons/scons-local-4.1.0/SCons/Platform/virtualenv.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
"""'Platform" support for a Python virtualenv."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import SCons.Util
|
||||
|
||||
|
||||
virtualenv_enabled_by_default = False
|
||||
|
||||
|
||||
def _enable_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default)
|
||||
|
||||
|
||||
def _ignore_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_IGNORE_VIRTUALENV', False)
|
||||
|
||||
|
||||
enable_virtualenv = _enable_virtualenv_default()
|
||||
ignore_virtualenv = _ignore_virtualenv_default()
|
||||
virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
|
||||
|
||||
|
||||
def _running_in_virtualenv():
|
||||
"""Returns True if scons is executed within a virtualenv"""
|
||||
# see https://stackoverflow.com/a/42580137
|
||||
return (hasattr(sys, 'real_prefix') or
|
||||
(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
|
||||
|
||||
|
||||
def _is_path_in(path, base):
|
||||
"""Returns true if **path** is located under the **base** directory."""
|
||||
if not path or not base: # empty path may happen, base too
|
||||
return False
|
||||
rp = os.path.relpath(path, base)
|
||||
return (not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir)
|
||||
|
||||
|
||||
def _inject_venv_variables(env):
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
ENV = env['ENV']
|
||||
for name in virtualenv_variables:
|
||||
try:
|
||||
ENV[name] = os.environ[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _inject_venv_path(env, path_list=None):
|
||||
"""Modify environment such that SCons will take into account its virtualenv
|
||||
when running external tools."""
|
||||
if path_list is None:
|
||||
path_list = os.getenv('PATH')
|
||||
env.PrependENVPath('PATH', select_paths_in_venv(path_list))
|
||||
|
||||
|
||||
def select_paths_in_venv(path_list):
|
||||
"""Returns a list of paths from **path_list** which are under virtualenv's
|
||||
home directory."""
|
||||
if SCons.Util.is_String(path_list):
|
||||
path_list = path_list.split(os.path.pathsep)
|
||||
# Find in path_list the paths under the virtualenv's home
|
||||
return [path for path in path_list if IsInVirtualenv(path)]
|
||||
|
||||
|
||||
def ImportVirtualenv(env):
|
||||
"""Copies virtualenv-related environment variables from OS environment
|
||||
to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``.
|
||||
"""
|
||||
_inject_venv_variables(env)
|
||||
_inject_venv_path(env)
|
||||
|
||||
|
||||
def Virtualenv():
|
||||
"""Returns path to the virtualenv home if scons is executing within a
|
||||
virtualenv or None, if not."""
|
||||
if _running_in_virtualenv():
|
||||
return sys.prefix
|
||||
return None
|
||||
|
||||
|
||||
def IsInVirtualenv(path):
|
||||
"""Returns True, if **path** is under virtualenv's home directory. If not,
|
||||
or if we don't use virtualenv, returns False."""
|
||||
return _is_path_in(path, Virtualenv())
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Platform.win32
|
||||
|
||||
Platform-specific initialization for Win32 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,13 @@ selection method.
|
|||
# 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/Platform/win32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Platform-specific initialization for Win32 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
@ -39,59 +35,13 @@ import tempfile
|
|||
|
||||
from SCons.Platform.posix import exitvalmap
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
import SCons.Util
|
||||
|
||||
try:
|
||||
import msvcrt
|
||||
import win32api
|
||||
import win32con
|
||||
|
||||
msvcrt.get_osfhandle
|
||||
win32api.SetHandleInformation
|
||||
win32con.HANDLE_FLAG_INHERIT
|
||||
except ImportError:
|
||||
parallel_msg = \
|
||||
"you do not seem to have the pywin32 extensions installed;\n" + \
|
||||
"\tparallel (-j) builds may not work reliably with open Python files."
|
||||
except AttributeError:
|
||||
parallel_msg = \
|
||||
"your pywin32 extensions do not support file handle operations;\n" + \
|
||||
"\tparallel (-j) builds may not work reliably with open Python files."
|
||||
else:
|
||||
parallel_msg = None
|
||||
|
||||
_builtin_open = open
|
||||
|
||||
def _scons_open(*args, **kw):
|
||||
fp = _builtin_open(*args, **kw)
|
||||
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
|
||||
win32con.HANDLE_FLAG_INHERIT,
|
||||
0)
|
||||
return fp
|
||||
|
||||
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)
|
||||
|
||||
|
||||
CHOCO_DEFAULT_PATH = [
|
||||
r'C:\ProgramData\chocolatey\bin'
|
||||
]
|
||||
|
||||
if False:
|
||||
# Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile
|
||||
|
@ -132,7 +82,7 @@ try:
|
|||
# Without this, python can randomly crash while using -jN.
|
||||
# See the python bug at http://bugs.python.org/issue6476
|
||||
# and SCons issue at
|
||||
# http://scons.tigris.org/issues/show_bug.cgi?id=2449
|
||||
# https://github.com/SCons/scons/issues/2449
|
||||
def spawnve(mode, file, args, env):
|
||||
spawn_lock.acquire()
|
||||
try:
|
||||
|
@ -168,59 +118,68 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
|||
# we redirect it into a temporary file tmpFileStdout
|
||||
# (tmpFileStderr) and copy the contents of this file
|
||||
# to stdout (stderr) given in the argument
|
||||
# Note that because this will paste shell redirection syntax
|
||||
# into the cmdline, we have to call a shell to run the command,
|
||||
# even though that's a bit of a performance hit.
|
||||
if not sh:
|
||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||
return 127
|
||||
else:
|
||||
# one temporary file for stdout and stderr
|
||||
tmpFileStdout = os.path.normpath(tempfile.mktemp())
|
||||
tmpFileStderr = os.path.normpath(tempfile.mktemp())
|
||||
|
||||
# check if output is redirected
|
||||
stdoutRedirected = 0
|
||||
stderrRedirected = 0
|
||||
for arg in args:
|
||||
# are there more possibilities to redirect stdout ?
|
||||
if arg.find( ">", 0, 1 ) != -1 or arg.find( "1>", 0, 2 ) != -1:
|
||||
stdoutRedirected = 1
|
||||
# are there more possibilities to redirect stderr ?
|
||||
if arg.find( "2>", 0, 2 ) != -1:
|
||||
stderrRedirected = 1
|
||||
# one temporary file for stdout and stderr
|
||||
tmpFileStdout, tmpFileStdoutName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStdout) # don't need open until the subproc is done
|
||||
tmpFileStderr, tmpFileStderrName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStderr)
|
||||
|
||||
# redirect output of non-redirected streams to our tempfiles
|
||||
if stdoutRedirected == 0:
|
||||
args.append(">" + str(tmpFileStdout))
|
||||
if stderrRedirected == 0:
|
||||
args.append("2>" + str(tmpFileStderr))
|
||||
# check if output is redirected
|
||||
stdoutRedirected = False
|
||||
stderrRedirected = False
|
||||
for arg in args:
|
||||
# are there more possibilities to redirect stdout ?
|
||||
if arg.find(">", 0, 1) != -1 or arg.find("1>", 0, 2) != -1:
|
||||
stdoutRedirected = True
|
||||
# are there more possibilities to redirect stderr ?
|
||||
if arg.find("2>", 0, 2) != -1:
|
||||
stderrRedirected = True
|
||||
|
||||
# actually do the spawn
|
||||
# redirect output of non-redirected streams to our tempfiles
|
||||
if not stdoutRedirected:
|
||||
args.append(">" + tmpFileStdoutName)
|
||||
if not stderrRedirected:
|
||||
args.append("2>" + tmpFileStderrName)
|
||||
|
||||
# actually do the spawn
|
||||
try:
|
||||
args = [sh, '/C', escape(' '.join(args))]
|
||||
ret = spawnve(os.P_WAIT, sh, args, env)
|
||||
except OSError as e:
|
||||
# catch any error
|
||||
try:
|
||||
args = [sh, '/C', escape(' '.join(args)) ]
|
||||
ret = spawnve(os.P_WAIT, sh, args, env)
|
||||
except OSError as e:
|
||||
# catch any error
|
||||
try:
|
||||
ret = exitvalmap[e[0]]
|
||||
except KeyError:
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1]))
|
||||
if stderr is not None:
|
||||
stderr.write("scons: %s: %s\n" % (cmd, e[1]))
|
||||
# copy child output from tempfiles to our streams
|
||||
# and do clean up stuff
|
||||
if stdout is not None and stdoutRedirected == 0:
|
||||
try:
|
||||
stdout.write(open( tmpFileStdout, "r" ).read())
|
||||
os.remove( tmpFileStdout )
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
ret = exitvalmap[e.errno]
|
||||
except KeyError:
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror))
|
||||
if stderr is not None:
|
||||
stderr.write("scons: %s: %s\n" % (cmd, e.strerror))
|
||||
|
||||
if stderr is not None and stderrRedirected == 0:
|
||||
try:
|
||||
stderr.write(open( tmpFileStderr, "r" ).read())
|
||||
os.remove( tmpFileStderr )
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
return ret
|
||||
# copy child output from tempfiles to our streams
|
||||
# and do clean up stuff
|
||||
if stdout is not None and not stdoutRedirected:
|
||||
try:
|
||||
with open(tmpFileStdoutName, "r") as tmpFileStdout:
|
||||
stdout.write(tmpFileStdout.read())
|
||||
os.remove(tmpFileStdoutName)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
if stderr is not None and not stderrRedirected:
|
||||
try:
|
||||
with open(tmpFileStderrName, "r") as tmpFileStderr:
|
||||
stderr.write(tmpFileStderr.read())
|
||||
os.remove(tmpFileStderrName)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def exec_spawn(l, env):
|
||||
|
@ -288,9 +247,6 @@ def get_system_root():
|
|||
except:
|
||||
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
|
||||
return val
|
||||
|
||||
|
@ -312,7 +268,6 @@ def get_program_files_dir():
|
|||
val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
|
||||
except SCons.Util.RegError:
|
||||
val = ''
|
||||
pass
|
||||
|
||||
if val == '':
|
||||
# A reasonable default if we can't read the registry
|
||||
|
@ -322,7 +277,7 @@ def get_program_files_dir():
|
|||
return val
|
||||
|
||||
|
||||
class ArchDefinition(object):
|
||||
class ArchDefinition:
|
||||
"""
|
||||
Determine which windows CPU were running on.
|
||||
A class for defining architecture-specific settings and logic.
|
||||
|
@ -436,7 +391,7 @@ def generate(env):
|
|||
if v:
|
||||
env['ENV']['COMSPEC'] = v
|
||||
|
||||
env.AppendENVPath('PATH', get_system_root() + '\System32')
|
||||
env.AppendENVPath('PATH', get_system_root() + '\\System32')
|
||||
|
||||
env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
|
||||
env['OBJPREFIX'] = ''
|
||||
|
@ -462,6 +417,9 @@ def generate(env):
|
|||
env['HOST_OS'] = 'win32'
|
||||
env['HOST_ARCH'] = get_architecture().arch
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
|
@ -1,18 +1,6 @@
|
|||
"""SCons.SConf
|
||||
|
||||
Autoconf-like configuration support.
|
||||
|
||||
In other words, SConf allows to run tests on the build machine to detect
|
||||
capabilities of system and do some things based on result: generate config
|
||||
files, header files for C/C++, update variables in environment.
|
||||
|
||||
Tests on the build system can detect if compiler sees header files, if
|
||||
libraries are installed, if some command line options are supported etc.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -32,13 +20,20 @@ libraries are installed, if some command line options are supported etc.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/SConf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Autoconf-like configuration support.
|
||||
|
||||
In other words, SConf allows to run tests on the build machine to detect
|
||||
capabilities of system and do some things based on result: generate config
|
||||
files, header files for C/C++, update variables in environment.
|
||||
|
||||
Tests on the build system can detect if compiler sees header files, if
|
||||
libraries are installed, if some command line options are supported etc.
|
||||
"""
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import atexit
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
|
@ -56,6 +51,7 @@ import SCons.Warnings
|
|||
import SCons.Conftest
|
||||
|
||||
from SCons.Debug import Trace
|
||||
from collections import defaultdict
|
||||
|
||||
# Turn off the Conftest error logging
|
||||
SCons.Conftest.LogInputFiles = 0
|
||||
|
@ -65,9 +61,9 @@ SCons.Conftest.LogErrorMessages = 0
|
|||
build_type = None
|
||||
build_types = ['clean', 'help']
|
||||
|
||||
def SetBuildType(type):
|
||||
def SetBuildType(buildtype):
|
||||
global build_type
|
||||
build_type = type
|
||||
build_type = buildtype
|
||||
|
||||
# to be set, if we are in dry-run mode
|
||||
dryrun = 0
|
||||
|
@ -98,7 +94,7 @@ def SetProgressDisplay(display):
|
|||
|
||||
SConfFS = None
|
||||
|
||||
_ac_build_counter = 0 # incremented, whenever TryBuild is called
|
||||
_ac_build_counter = defaultdict(int)
|
||||
_ac_config_logs = {} # all config.log files created in this build
|
||||
_ac_config_hs = {} # all config.h files created in this build
|
||||
sconf_global = None # current sconf object
|
||||
|
@ -132,11 +128,11 @@ def CreateConfigHBuilder(env):
|
|||
_stringConfigH)
|
||||
sconfigHBld = SCons.Builder.Builder(action=action)
|
||||
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
|
||||
for k in list(_ac_config_hs.keys()):
|
||||
env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
|
||||
for k, v in _ac_config_hs.items():
|
||||
env.SConfigHBuilder(k, env.Value(v))
|
||||
|
||||
|
||||
class SConfWarning(SCons.Warnings.Warning):
|
||||
class SConfWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
SCons.Warnings.enableWarningClass(SConfWarning)
|
||||
|
||||
|
@ -161,11 +157,14 @@ class ConfigureCacheError(SConfError):
|
|||
def __init__(self,target):
|
||||
SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
|
||||
|
||||
|
||||
# define actions for building text files
|
||||
def _createSource( target, source, env ):
|
||||
def _createSource(target, source, env):
|
||||
fd = open(str(target[0]), "w")
|
||||
fd.write(source[0].get_contents().decode())
|
||||
fd.close()
|
||||
|
||||
|
||||
def _stringSource( target, source, env ):
|
||||
return (str(target[0]) + ' <-\n |' +
|
||||
source[0].get_contents().decode().replace( '\n', "\n |" ) )
|
||||
|
@ -187,7 +186,7 @@ class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
|
|||
self.string = string
|
||||
|
||||
|
||||
class Streamer(object):
|
||||
class Streamer:
|
||||
"""
|
||||
'Sniffer' for a file-like writable object. Similar to the unix tool tee.
|
||||
"""
|
||||
|
@ -246,6 +245,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
|||
# ConfigureCacheError and if yes, reraise the exception
|
||||
exc_type = self.exc_info()[0]
|
||||
if issubclass(exc_type, SConfError):
|
||||
# TODO pylint E0704: bare raise not inside except
|
||||
raise
|
||||
elif issubclass(exc_type, SCons.Errors.BuildError):
|
||||
# we ignore Build Errors (occurs, when a test doesn't pass)
|
||||
|
@ -269,7 +269,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
|||
cached_error = False
|
||||
cachable = True
|
||||
for t in self.targets:
|
||||
if T: Trace('%s' % (t))
|
||||
if T: Trace('%s' % t)
|
||||
bi = t.get_stored_info().binfo
|
||||
if isinstance(bi, SConfBuildInfo):
|
||||
if T: Trace(': SConfBuildInfo')
|
||||
|
@ -279,7 +279,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
|||
else:
|
||||
if T: Trace(': get_state() %s' % t.get_state())
|
||||
if T: Trace(': changed() %s' % t.changed())
|
||||
if (t.get_state() != SCons.Node.up_to_date and t.changed()):
|
||||
if t.get_state() != SCons.Node.up_to_date and t.changed():
|
||||
changed = True
|
||||
if T: Trace(': changed %s' % changed)
|
||||
cached_error = cached_error or bi.result
|
||||
|
@ -323,18 +323,6 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
|||
s = sys.stdout = sys.stderr = Streamer(sys.stdout)
|
||||
try:
|
||||
env = self.targets[0].get_build_env()
|
||||
if cache_mode == FORCE:
|
||||
# Set up the Decider() to force rebuilds by saying
|
||||
# that every source has changed. Note that we still
|
||||
# call the environment's underlying source decider so
|
||||
# that the correct .sconsign info will get calculated
|
||||
# and keep the build state consistent.
|
||||
def force_build(dependency, target, prev_ni,
|
||||
env_decider=env.decide_source):
|
||||
env_decider(dependency, target, prev_ni)
|
||||
return True
|
||||
if env.decide_source.__code__ is not force_build.__code__:
|
||||
env.Decider(force_build)
|
||||
env['PSTDOUT'] = env['PSTDERR'] = s
|
||||
try:
|
||||
sconf.cached = 0
|
||||
|
@ -383,7 +371,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
|||
sconsign.set_entry(t.name, sconsign_entry)
|
||||
sconsign.merge()
|
||||
|
||||
class SConfBase(object):
|
||||
class SConfBase:
|
||||
"""This is simply a class to represent a configure context. After
|
||||
creating a SConf object, you can call any tests. After finished with your
|
||||
tests, be sure to call the Finish() method, which returns the modified
|
||||
|
@ -405,12 +393,41 @@ class SConfBase(object):
|
|||
build tests in the VariantDir, not in the SourceDir)
|
||||
"""
|
||||
global SConfFS
|
||||
|
||||
# Now create isolated override so setting source_decider doesn't affect parent Environment
|
||||
if cache_mode == FORCE:
|
||||
self.original_env = env
|
||||
self.env = env.Clone()
|
||||
|
||||
# Set up the Decider() to force rebuilds by saying
|
||||
# that every source has changed. Note that we still
|
||||
# call the environment's underlying source decider so
|
||||
# that the correct .sconsign info will get calculated
|
||||
# and keep the build state consistent.
|
||||
def force_build(dependency, target, prev_ni,
|
||||
repo_node=None,
|
||||
env_decider=env.decide_source):
|
||||
try:
|
||||
env_decider(dependency, target, prev_ni, repo_node)
|
||||
except Exception as e:
|
||||
raise e
|
||||
return True
|
||||
|
||||
if self.env.decide_source.__code__ is not force_build.__code__:
|
||||
self.env.Decider(force_build)
|
||||
|
||||
else:
|
||||
self.env = env
|
||||
|
||||
# print("Override env:%s"%env)
|
||||
|
||||
if not SConfFS:
|
||||
SConfFS = SCons.Node.FS.default_fs or \
|
||||
SCons.Node.FS.FS(env.fs.pathTop)
|
||||
if sconf_global is not None:
|
||||
raise SCons.Errors.UserError
|
||||
self.env = env
|
||||
raise SCons.Errors.UserError("""Configure() called while another Configure() exists.
|
||||
Please call .Finish() before creating and second Configure() context""")
|
||||
|
||||
if log_file is not None:
|
||||
log_file = SConfFS.File(env.subst(log_file))
|
||||
self.logfile = log_file
|
||||
|
@ -449,6 +466,7 @@ class SConfBase(object):
|
|||
env = sconf.Finish()
|
||||
"""
|
||||
self._shutdown()
|
||||
|
||||
return self.env
|
||||
|
||||
def Define(self, name, value = None, comment = None):
|
||||
|
@ -498,11 +516,27 @@ class SConfBase(object):
|
|||
# we override the store_info() method with a null place-holder
|
||||
# so we really control how it gets written.
|
||||
for n in nodes:
|
||||
self._set_conftest_node(n)
|
||||
n.store_info = 0
|
||||
if not hasattr(n, 'attributes'):
|
||||
n.attributes = SCons.Node.Node.Attrs()
|
||||
n.attributes.keep_targetinfo = 1
|
||||
|
||||
if True:
|
||||
# Some checkers have intermediate files (for example anything that compiles a c file into a program to run
|
||||
# Those files need to be set to not release their target info, otherwise taskmaster will throw a
|
||||
# Nonetype not callable
|
||||
for c in n.children(scan=False):
|
||||
# Keep debug code here.
|
||||
# print("Checking [%s] for builders and then setting keep_targetinfo"%c)
|
||||
self._set_conftest_node(c)
|
||||
if c.has_builder():
|
||||
n.store_info = 0
|
||||
if not hasattr(c, 'attributes'):
|
||||
c.attributes = SCons.Node.Node.Attrs()
|
||||
c.attributes.keep_targetinfo = 1
|
||||
# pass
|
||||
|
||||
ret = 1
|
||||
|
||||
try:
|
||||
|
@ -541,8 +575,7 @@ class SConfBase(object):
|
|||
"""
|
||||
return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream)
|
||||
|
||||
|
||||
def TryBuild(self, builder, text = None, extension = ""):
|
||||
def TryBuild(self, builder, text=None, extension=""):
|
||||
"""Low level TryBuild implementation. Normally you don't need to
|
||||
call that - you can use TryCompile / TryLink / TryRun instead
|
||||
"""
|
||||
|
@ -560,8 +593,33 @@ class SConfBase(object):
|
|||
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
|
||||
|
||||
nodesToBeBuilt = []
|
||||
sourcetext = self.env.Value(text)
|
||||
self._set_conftest_node(sourcetext)
|
||||
f = "conftest"
|
||||
|
||||
if text is not None:
|
||||
textSig = SCons.Util.MD5signature(sourcetext)
|
||||
textSigCounter = str(_ac_build_counter[textSig])
|
||||
_ac_build_counter[textSig] += 1
|
||||
|
||||
f = "_".join([f, textSig, textSigCounter])
|
||||
textFile = self.confdir.File(f + extension)
|
||||
self._set_conftest_node(sourcetext)
|
||||
textFileNode = self.env.SConfSourceBuilder(target=textFile,
|
||||
source=sourcetext)
|
||||
nodesToBeBuilt.extend(textFileNode)
|
||||
|
||||
source = textFile
|
||||
target = textFile.File(f + "SConfActionsContentDummyTarget")
|
||||
self._set_conftest_node(target)
|
||||
else:
|
||||
source = None
|
||||
target = None
|
||||
|
||||
action = builder.builder.action.get_contents(target=target, source=[source], env=self.env)
|
||||
actionsig = SCons.Util.MD5signature(action)
|
||||
f = "_".join([f, actionsig])
|
||||
|
||||
f = "conftest_" + str(_ac_build_counter)
|
||||
pref = self.env.subst( builder.builder.prefix )
|
||||
suff = self.env.subst( builder.builder.suffix )
|
||||
target = self.confdir.File(pref + f + suff)
|
||||
|
@ -570,16 +628,6 @@ class SConfBase(object):
|
|||
# Slide our wrapper into the construction environment as
|
||||
# the SPAWN function.
|
||||
self.env['SPAWN'] = self.pspawn_wrapper
|
||||
sourcetext = self.env.Value(text)
|
||||
|
||||
if text is not None:
|
||||
textFile = self.confdir.File(f + extension)
|
||||
textFileNode = self.env.SConfSourceBuilder(target=textFile,
|
||||
source=sourcetext)
|
||||
nodesToBeBuilt.extend(textFileNode)
|
||||
source = textFileNode
|
||||
else:
|
||||
source = None
|
||||
|
||||
nodes = builder(target = target, source = source)
|
||||
if not SCons.Util.is_List(nodes):
|
||||
|
@ -590,7 +638,6 @@ class SConfBase(object):
|
|||
finally:
|
||||
self.env['SPAWN'] = save_spawn
|
||||
|
||||
_ac_build_counter = _ac_build_counter + 1
|
||||
if result:
|
||||
self.lastTarget = nodes[0]
|
||||
else:
|
||||
|
@ -609,7 +656,7 @@ class SConfBase(object):
|
|||
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
|
||||
del self.env['BUILDERS']['SConfActionBuilder']
|
||||
if ok:
|
||||
outputStr = self.lastTarget.get_contents().decode()
|
||||
outputStr = self.lastTarget.get_text_contents()
|
||||
return (1, outputStr)
|
||||
return (0, "")
|
||||
|
||||
|
@ -636,7 +683,7 @@ class SConfBase(object):
|
|||
is saved in self.lastTarget (for further processing).
|
||||
"""
|
||||
ok = self.TryLink(text, extension)
|
||||
if( ok ):
|
||||
if ok:
|
||||
prog = self.lastTarget
|
||||
pname = prog.get_internal_path()
|
||||
output = self.confdir.File(os.path.basename(pname)+'.out')
|
||||
|
@ -647,7 +694,7 @@ class SConfBase(object):
|
|||
return( 1, outputStr)
|
||||
return (0, "")
|
||||
|
||||
class TestWrapper(object):
|
||||
class TestWrapper:
|
||||
"""A wrapper around Tests (to ensure sanity)"""
|
||||
def __init__(self, test, sconf):
|
||||
self.test = test
|
||||
|
@ -671,7 +718,7 @@ class SConfBase(object):
|
|||
"""Adds all the tests given in the tests dictionary to this SConf
|
||||
instance
|
||||
"""
|
||||
for name in list(tests.keys()):
|
||||
for name in tests.keys():
|
||||
self.AddTest(name, tests[name])
|
||||
|
||||
def _createDir( self, node ):
|
||||
|
@ -683,6 +730,9 @@ class SConfBase(object):
|
|||
if not os.path.isdir( dirName ):
|
||||
os.makedirs( dirName )
|
||||
|
||||
def _set_conftest_node(self, node):
|
||||
node.attributes.conftest_node = 1
|
||||
|
||||
def _startup(self):
|
||||
"""Private method. Set up logstream, and set the environment
|
||||
variables necessary for a piped build
|
||||
|
@ -705,11 +755,16 @@ class SConfBase(object):
|
|||
_ac_config_logs[self.logfile] = None
|
||||
log_mode = "w"
|
||||
fp = open(str(self.logfile), log_mode)
|
||||
|
||||
def conflog_cleanup(logf):
|
||||
logf.close()
|
||||
|
||||
atexit.register(conflog_cleanup, fp)
|
||||
self.logstream = SCons.Util.Unbuffered(fp)
|
||||
# logfile may stay in a build directory, so we tell
|
||||
# the build system not to override it with a eventually
|
||||
# the build system not to override it with an eventually
|
||||
# existing file with the same name in the source directory
|
||||
self.logfile.dir.add_ignore( [self.logfile] )
|
||||
self.logfile.dir.add_ignore([self.logfile])
|
||||
|
||||
tb = traceback.extract_stack()[-3-self.depth]
|
||||
old_fs_dir = SConfFS.getcwd()
|
||||
|
@ -739,17 +794,25 @@ class SConfBase(object):
|
|||
self.logstream.write("\n")
|
||||
self.logstream.close()
|
||||
self.logstream = None
|
||||
# remove the SConfSourceBuilder from the environment
|
||||
blds = self.env['BUILDERS']
|
||||
del blds['SConfSourceBuilder']
|
||||
self.env.Replace( BUILDERS=blds )
|
||||
|
||||
# Now reset the decider if we changed it due to --config=force
|
||||
# We saved original Environment passed in and cloned it to isolate
|
||||
# it from being changed.
|
||||
if cache_mode == FORCE:
|
||||
self.env.Decider(self.original_env.decide_source)
|
||||
|
||||
# remove the SConfSourceBuilder from the environment
|
||||
blds = self.env['BUILDERS']
|
||||
del blds['SConfSourceBuilder']
|
||||
self.env.Replace( BUILDERS=blds )
|
||||
|
||||
self.active = 0
|
||||
sconf_global = None
|
||||
if not self.config_h is None:
|
||||
if self.config_h is not None:
|
||||
_ac_config_hs[self.config_h] = self.config_h_text
|
||||
self.env.fs = self.lastEnvFs
|
||||
|
||||
class CheckContext(object):
|
||||
class CheckContext:
|
||||
"""Provides a context for configure tests. Defines how a test writes to the
|
||||
screen and log file.
|
||||
|
||||
|
@ -826,9 +889,9 @@ class CheckContext(object):
|
|||
return self.sconf.TryRun(*args, **kw)
|
||||
|
||||
def __getattr__( self, attr ):
|
||||
if( attr == 'env' ):
|
||||
if attr == 'env':
|
||||
return self.sconf.env
|
||||
elif( attr == 'lastTarget' ):
|
||||
elif attr == 'lastTarget':
|
||||
return self.sconf.lastTarget
|
||||
else:
|
||||
raise AttributeError("CheckContext instance has no attribute '%s'" % attr)
|
||||
|
@ -1000,7 +1063,7 @@ def CheckLib(context, library = None, symbol = "main",
|
|||
compiles without flags.
|
||||
"""
|
||||
|
||||
if library == []:
|
||||
if not library:
|
||||
library = [None]
|
||||
|
||||
if not SCons.Util.is_List(library):
|
||||
|
@ -1027,7 +1090,7 @@ def CheckLibWithHeader(context, libs, header, language,
|
|||
"""
|
||||
prog_prefix, dummy = \
|
||||
createIncludesFromHeaders(header, 0)
|
||||
if libs == []:
|
||||
if not libs:
|
||||
libs = [None]
|
||||
|
||||
if not SCons.Util.is_List(libs):
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.SConsign
|
||||
|
||||
Writing and reading information to the .sconsign file or files.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,11 +20,8 @@ Writing and reading information to the .sconsign file or files.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/SConsign.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Operations on signature database files (.sconsign). """
|
||||
|
||||
import SCons.compat
|
||||
|
||||
|
@ -43,10 +35,12 @@ from SCons.compat import PICKLE_PROTOCOL
|
|||
|
||||
|
||||
def corrupt_dblite_warning(filename):
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s"%filename)
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s" % filename,
|
||||
)
|
||||
|
||||
SCons.dblite.ignore_corrupt_dbfiles = 1
|
||||
SCons.dblite.IGNORE_CORRUPT_DBFILES = True
|
||||
SCons.dblite.corruption_warning = corrupt_dblite_warning
|
||||
|
||||
# XXX Get rid of the global array so this becomes re-entrant.
|
||||
|
@ -76,7 +70,8 @@ def Get_DataBase(dir):
|
|||
except KeyError:
|
||||
path = d.entry_abspath(DB_Name)
|
||||
try: db = DataBase[d] = DB_Module.open(path, mode)
|
||||
except (IOError, OSError): pass
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
else:
|
||||
if mode != "r":
|
||||
DB_sync_list.append(db)
|
||||
|
@ -122,7 +117,7 @@ def write():
|
|||
closemethod()
|
||||
|
||||
|
||||
class SConsignEntry(object):
|
||||
class SConsignEntry:
|
||||
"""
|
||||
Wrapper class for the generic entry in a .sconsign file.
|
||||
The Node subclass populates it with attributes as it pleases.
|
||||
|
@ -148,7 +143,7 @@ class SConsignEntry(object):
|
|||
def __getstate__(self):
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj,'__slots__',()):
|
||||
for name in getattr(obj, '__slots__', ()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
|
@ -161,11 +156,11 @@ class SConsignEntry(object):
|
|||
|
||||
def __setstate__(self, state):
|
||||
for key, value in state.items():
|
||||
if key not in ('_version_id','__weakref__'):
|
||||
if key not in ('_version_id', '__weakref__'):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class Base(object):
|
||||
class Base:
|
||||
"""
|
||||
This is the controlling class for the signatures for the collection of
|
||||
entries associated with a specific directory. The actual directory
|
||||
|
@ -334,10 +329,15 @@ class DirFile(Dir):
|
|||
Dir.__init__(self, fp, dir)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
except Exception:
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
|
||||
|
||||
try:
|
||||
fp.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
global sig_files
|
||||
sig_files.append(self)
|
||||
|
||||
|
@ -394,7 +394,8 @@ class DirFile(Dir):
|
|||
# here, or in any of the following calls, would get
|
||||
# raised, indicating something like a potentially
|
||||
# serious disk or network issue.
|
||||
open(self.sconsign, 'wb').write(open(fname, 'rb').read())
|
||||
with open(self.sconsign, 'wb') as f, open(fname, 'rb') as f2:
|
||||
f.write(f2.read())
|
||||
os.chmod(self.sconsign, mode)
|
||||
try:
|
||||
os.unlink(temp)
|
||||
|
@ -416,7 +417,7 @@ def File(name, dbm_module=None):
|
|||
else:
|
||||
ForDirectory = DB
|
||||
DB_Name = name
|
||||
if not dbm_module is None:
|
||||
if dbm_module is not None:
|
||||
DB_Module = dbm_module
|
||||
|
||||
# Local Variables:
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Scanner.C
|
||||
|
||||
This module implements the dependency scanner for C/C++ code.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,9 +20,8 @@ This module implements the dependency scanner for C/C++ code.
|
|||
# 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/Scanner/C.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for C/C++ code."""
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
@ -36,8 +30,7 @@ import SCons.Util
|
|||
import SCons.cpp
|
||||
|
||||
class SConsCPPScanner(SCons.cpp.PreProcessor):
|
||||
"""
|
||||
SCons-specific subclass of the cpp.py module's processing.
|
||||
"""SCons-specific subclass of the cpp.py module's processing.
|
||||
|
||||
We subclass this so that: 1) we can deal with files represented
|
||||
by Nodes, not strings; 2) we can keep track of the files that are
|
||||
|
@ -80,9 +73,8 @@ def dictify_CPPDEFINES(env):
|
|||
return {cppdefines : None}
|
||||
return cppdefines
|
||||
|
||||
class SConsCPPScannerWrapper(object):
|
||||
"""
|
||||
The SCons wrapper around a cpp.py scanner.
|
||||
class SConsCPPScannerWrapper:
|
||||
"""The SCons wrapper around a cpp.py scanner.
|
||||
|
||||
This is the actual glue between the calling conventions of generic
|
||||
SCons scanners, and the (subclass of) cpp.py class that knows how
|
||||
|
@ -116,14 +108,109 @@ def CScanner():
|
|||
# knows how to evaluate #if/#ifdef/#else/#elif lines when searching
|
||||
# for #includes. This is commented out for now until we add the
|
||||
# right configurability to let users pick between the scanners.
|
||||
#return SConsCPPScannerWrapper("CScanner", "CPPPATH")
|
||||
# return SConsCPPScannerWrapper("CScanner", "CPPPATH")
|
||||
|
||||
cs = SCons.Scanner.ClassicCPP("CScanner",
|
||||
"$CPPSUFFIXES",
|
||||
"CPPPATH",
|
||||
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")')
|
||||
cs = SCons.Scanner.ClassicCPP(
|
||||
"CScanner",
|
||||
"$CPPSUFFIXES",
|
||||
"CPPPATH",
|
||||
r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")',
|
||||
)
|
||||
return cs
|
||||
|
||||
|
||||
#
|
||||
# ConditionalScanner
|
||||
#
|
||||
|
||||
|
||||
class SConsCPPConditionalScanner(SCons.cpp.PreProcessor):
|
||||
"""SCons-specific subclass of the cpp.py module's processing.
|
||||
|
||||
We subclass this so that: 1) we can deal with files represented
|
||||
by Nodes, not strings; 2) we can keep track of the files that are
|
||||
missing.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
SCons.cpp.PreProcessor.__init__(self, *args, **kw)
|
||||
self.missing = []
|
||||
self._known_paths = []
|
||||
|
||||
def initialize_result(self, fname):
|
||||
self.result = SCons.Util.UniqueList([fname])
|
||||
|
||||
def find_include_file(self, t):
|
||||
keyword, quote, fname = t
|
||||
paths = tuple(self._known_paths) + self.searchpath[quote]
|
||||
if quote == '"':
|
||||
paths = (self.current_file.dir,) + paths
|
||||
result = SCons.Node.FS.find_file(fname, paths)
|
||||
if result:
|
||||
result_path = result.get_abspath()
|
||||
for p in self.searchpath[quote]:
|
||||
if result_path.startswith(p.get_abspath()):
|
||||
self._known_paths.append(p)
|
||||
break
|
||||
else:
|
||||
self.missing.append((fname, self.current_file))
|
||||
return result
|
||||
|
||||
def read_file(self, file):
|
||||
try:
|
||||
with open(str(file.rfile())) as fp:
|
||||
return fp.read()
|
||||
except EnvironmentError:
|
||||
self.missing.append((file, self.current_file))
|
||||
return ""
|
||||
|
||||
|
||||
class SConsCPPConditionalScannerWrapper:
|
||||
"""
|
||||
The SCons wrapper around a cpp.py scanner.
|
||||
|
||||
This is the actual glue between the calling conventions of generic
|
||||
SCons scanners, and the (subclass of) cpp.py class that knows how
|
||||
to look for #include lines with reasonably real C-preprocessor-like
|
||||
evaluation of #if/#ifdef/#else/#elif lines.
|
||||
"""
|
||||
|
||||
def __init__(self, name, variable):
|
||||
self.name = name
|
||||
self.path = SCons.Scanner.FindPathDirs(variable)
|
||||
|
||||
def __call__(self, node, env, path=(), depth=-1):
|
||||
cpp = SConsCPPConditionalScanner(
|
||||
current=node.get_dir(),
|
||||
cpppath=path,
|
||||
dict=dictify_CPPDEFINES(env),
|
||||
depth=depth,
|
||||
)
|
||||
result = cpp(node)
|
||||
for included, includer in cpp.missing:
|
||||
fmt = "No dependency generated for file: %s (included from: %s) -- file not found"
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DependencyWarning, fmt % (included, includer)
|
||||
)
|
||||
return result
|
||||
|
||||
def recurse_nodes(self, nodes):
|
||||
return nodes
|
||||
|
||||
def select(self, node):
|
||||
return self
|
||||
|
||||
|
||||
def CConditionalScanner():
|
||||
"""
|
||||
Return an advanced conditional Scanner instance for scanning source files
|
||||
|
||||
Interprets C/C++ Preprocessor conditional syntax
|
||||
(#ifdef, #if, defined, #else, #elif, etc.).
|
||||
"""
|
||||
return SConsCPPConditionalScannerWrapper("CConditionalScanner", "CPPPATH")
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
|||
"""SCons.Scanner.D
|
||||
|
||||
Scanner for the Digital Mars "D" programming language.
|
||||
|
||||
Coded by Andy Friesen
|
||||
17 Nov 2003
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -28,9 +20,11 @@ Coded by Andy Friesen
|
|||
# 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/Scanner/D.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Scanner for the Digital Mars "D" programming language.
|
||||
|
||||
Coded by Andy Friesen, 17 Nov 2003
|
||||
"""
|
||||
|
||||
import SCons.Scanner
|
||||
|
||||
|
@ -46,7 +40,7 @@ class D(SCons.Scanner.Classic):
|
|||
name = "DScanner",
|
||||
suffixes = '$DSUFFIXES',
|
||||
path_variable = 'DPATH',
|
||||
regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
|
||||
regex = r'(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
|
||||
)
|
||||
|
||||
def find_include(self, include, source_dir, path):
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -20,8 +21,6 @@
|
|||
# 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/Scanner/Dir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Scanner.Fortran
|
||||
|
||||
This module implements the dependency scanner for Fortran code.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -26,7 +21,7 @@ This module implements the dependency scanner for Fortran code.
|
|||
# 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/Scanner/Fortran.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for Fortran code."""
|
||||
|
||||
import re
|
||||
|
||||
|
@ -78,7 +73,7 @@ class F90Scanner(SCons.Scanner.Classic):
|
|||
def scan(self, node, env, path=()):
|
||||
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes != None:
|
||||
if node.includes is not None:
|
||||
mods_and_includes = node.includes
|
||||
else:
|
||||
# retrieve all included filenames
|
||||
|
@ -187,7 +182,7 @@ def FortranScan(path_variable="FORTRANPATH"):
|
|||
# (\w+) : match the module name that is being USE'd
|
||||
#
|
||||
#
|
||||
use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"
|
||||
use_regex = r"(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"
|
||||
|
||||
|
||||
# The INCLUDE statement regex matches the following:
|
||||
|
@ -275,7 +270,7 @@ def FortranScan(path_variable="FORTRANPATH"):
|
|||
# set of semicolon-separated INCLUDE statements
|
||||
# (as allowed by the F2003 standard)
|
||||
|
||||
include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
|
||||
include_regex = r"""(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
|
||||
|
||||
# The MODULE statement regex finds module definitions by matching
|
||||
# the following:
|
||||
|
@ -285,21 +280,29 @@ def FortranScan(path_variable="FORTRANPATH"):
|
|||
# but *not* the following:
|
||||
#
|
||||
# MODULE PROCEDURE procedure_name
|
||||
# MODULE SUBROUTINE subroutine_name
|
||||
# MODULE FUNCTION function_name
|
||||
# MODULE PURE SUBROUTINE|FUNCTION subroutine_name|function_name
|
||||
# MODULE ELEMENTAL SUBROUTINE|FUNCTION subroutine_name|function_name
|
||||
#
|
||||
# Here is a breakdown of the regex:
|
||||
#
|
||||
# (?i) : regex is case insensitive
|
||||
# ^\s* : any amount of white space
|
||||
# MODULE : match the string MODULE, case insensitive
|
||||
# \s+ : match one or more white space characters
|
||||
# (?!PROCEDURE) : but *don't* match if the next word matches
|
||||
# PROCEDURE (negative lookahead assertion),
|
||||
# case insensitive
|
||||
# (\w+) : match one or more alphanumeric characters
|
||||
# that make up the defined module name and
|
||||
# save it in a group
|
||||
# (?i) : regex is case insensitive
|
||||
# ^\s* : any amount of white space
|
||||
# MODULE : match the string MODULE, case
|
||||
# insensitive
|
||||
# \s+ : match one or more white space
|
||||
# characters
|
||||
# (?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)
|
||||
# : but *don't* match if the next word
|
||||
# matches PROCEDURE, SUBROUTINE,
|
||||
# FUNCTION, PURE or ELEMENTAL (negative
|
||||
# lookahead assertion), case insensitive
|
||||
# (\w+) : match one or more alphanumeric
|
||||
# characters that make up the defined
|
||||
# module name and save it in a group
|
||||
|
||||
def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
|
||||
def_regex = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\w+)"""
|
||||
|
||||
scanner = F90Scanner("FortranScan",
|
||||
"$FORTRANSUFFIXES",
|
|
@ -1,12 +1,6 @@
|
|||
"""SCons.Scanner.IDL
|
||||
|
||||
This module implements the dependency scanner for IDL (Interface
|
||||
Definition Language) files.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -26,19 +20,20 @@ Definition Language) files.
|
|||
# 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/Scanner/IDL.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for IDL (Interface Definition Language) files."""
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
||||
def IDLScan():
|
||||
"""Return a prototype Scanner instance for scanning IDL source files"""
|
||||
cs = SCons.Scanner.ClassicCPP("IDLScan",
|
||||
"$IDLSUFFIXES",
|
||||
"CPPPATH",
|
||||
'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")')
|
||||
cs = SCons.Scanner.ClassicCPP(
|
||||
"IDLScan",
|
||||
"$IDLSUFFIXES",
|
||||
"CPPPATH",
|
||||
r'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")',
|
||||
)
|
||||
return cs
|
||||
|
||||
# Local Variables:
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Scanner.LaTeX
|
||||
|
||||
This module implements the dependency scanner for LaTeX code.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,9 +20,8 @@ This module implements the dependency scanner for LaTeX code.
|
|||
# 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/Scanner/LaTeX.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for LaTeX code."""
|
||||
|
||||
import os.path
|
||||
import re
|
||||
|
@ -42,7 +36,7 @@ LatexGraphics = [ '.png', '.jpg', '.gif', '.tif']
|
|||
|
||||
|
||||
# Used as a return value of modify_env_var if the variable is not set.
|
||||
class _Null(object):
|
||||
class _Null:
|
||||
pass
|
||||
_null = _Null
|
||||
|
||||
|
@ -77,7 +71,7 @@ def modify_env_var(env, var, abspath):
|
|||
|
||||
return save
|
||||
|
||||
class FindENVPathDirs(object):
|
||||
class FindENVPathDirs:
|
||||
"""
|
||||
A class to bind a specific E{*}PATH variable name to a function that
|
||||
will return all of the E{*}path directories.
|
||||
|
@ -96,7 +90,6 @@ class FindENVPathDirs(object):
|
|||
return tuple(dir.Rfindalldirs(path))
|
||||
|
||||
|
||||
|
||||
def LaTeXScanner():
|
||||
"""
|
||||
Return a prototype Scanner instance for scanning LaTeX source files
|
||||
|
@ -109,6 +102,7 @@ def LaTeXScanner():
|
|||
recursive = 0)
|
||||
return ds
|
||||
|
||||
|
||||
def PDFLaTeXScanner():
|
||||
"""
|
||||
Return a prototype Scanner instance for scanning LaTeX source files
|
||||
|
@ -121,9 +115,9 @@ def PDFLaTeXScanner():
|
|||
recursive = 0)
|
||||
return ds
|
||||
|
||||
|
||||
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
|
||||
return the included file name, this returns a tuple consisting
|
||||
|
@ -179,15 +173,7 @@ class LaTeX(SCons.Scanner.Base):
|
|||
'inputfrom', 'subinputfrom']
|
||||
|
||||
def __init__(self, name, suffixes, graphics_extensions, *args, **kw):
|
||||
|
||||
# We have to include \n with the % we exclude from the first part
|
||||
# part of the regex because the expression is compiled with re.M.
|
||||
# Without the \n, the ^ could match the beginning of a *previous*
|
||||
# line followed by one or more newline characters (i.e. blank
|
||||
# lines), interfering with a match on the next line.
|
||||
# add option for whitespace before the '[options]' or the '{filename}'
|
||||
regex = r'''
|
||||
^[^%\n]*
|
||||
\\(
|
||||
include
|
||||
| includegraphics(?:\s*\[[^\]]+\])?
|
||||
|
@ -219,7 +205,7 @@ class LaTeX(SCons.Scanner.Base):
|
|||
return []
|
||||
return self.scan_recurse(node, path)
|
||||
|
||||
class FindMultiPathDirs(object):
|
||||
class FindMultiPathDirs:
|
||||
"""The stock FindPathDirs function has the wrong granularity:
|
||||
it is called once per target, while we need the path that depends
|
||||
on what kind of included files is being searched. This wrapper
|
||||
|
@ -247,7 +233,7 @@ class LaTeX(SCons.Scanner.Base):
|
|||
# To prevent "dict is not hashable error"
|
||||
return tuple(di.items())
|
||||
|
||||
class LaTeXScanCheck(object):
|
||||
class LaTeXScanCheck:
|
||||
"""Skip all but LaTeX source files, i.e., do not scan *.eps,
|
||||
*.pdf, *.jpg, etc.
|
||||
"""
|
||||
|
@ -333,7 +319,7 @@ class LaTeX(SCons.Scanner.Base):
|
|||
line_continues_a_comment = False
|
||||
for line in text.splitlines():
|
||||
line,comment = self.comment_re.findall(line)[0]
|
||||
if line_continues_a_comment == True:
|
||||
if line_continues_a_comment:
|
||||
out[-1] = out[-1] + line.lstrip()
|
||||
else:
|
||||
out.append(line)
|
||||
|
@ -348,8 +334,8 @@ class LaTeX(SCons.Scanner.Base):
|
|||
# Cache the includes list in node so we only scan it once:
|
||||
# path_dict = dict(list(path))
|
||||
# add option for whitespace (\s) before the '['
|
||||
noopt_cre = re.compile('\s*\[.*$')
|
||||
if node.includes != None:
|
||||
noopt_cre = re.compile(r'\s*\[.*$')
|
||||
if node.includes is not None:
|
||||
includes = node.includes
|
||||
else:
|
||||
text = self.canonical_text(node.get_text_contents())
|
||||
|
@ -372,9 +358,9 @@ class LaTeX(SCons.Scanner.Base):
|
|||
inc_list = include[2].split(',')
|
||||
else:
|
||||
inc_list = include[1].split(',')
|
||||
for j in range(len(inc_list)):
|
||||
split_includes.append( (inc_type, inc_subdir, inc_list[j]) )
|
||||
#
|
||||
for inc in inc_list:
|
||||
split_includes.append((inc_type, inc_subdir, inc))
|
||||
|
||||
includes = split_includes
|
||||
node.includes = includes
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,9 +20,8 @@
|
|||
# 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/Scanner/Prog.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for program files."""
|
||||
|
||||
import SCons.Node
|
||||
import SCons.Node.FS
|
||||
|
@ -39,9 +39,7 @@ def ProgramScanner(**kw):
|
|||
return ps
|
||||
|
||||
def _subst_libs(env, libs):
|
||||
"""
|
||||
Substitute environment variables and split into list.
|
||||
"""
|
||||
"""Substitute environment variables and split into list."""
|
||||
if SCons.Util.is_String(libs):
|
||||
libs = env.subst(libs)
|
||||
if SCons.Util.is_String(libs):
|
||||
|
@ -57,9 +55,9 @@ def _subst_libs(env, libs):
|
|||
return libs
|
||||
|
||||
def scan(node, env, libpath = ()):
|
||||
"""
|
||||
This scanner scans program files for static-library
|
||||
dependencies. It will search the LIBPATH environment variable
|
||||
"""Scans program files for static-library dependencies.
|
||||
|
||||
It will search the LIBPATH environment variable
|
||||
for libraries specified in the LIBS variable, returning any
|
||||
files it finds as dependencies.
|
||||
"""
|
166
scons/scons-local-4.1.0/SCons/Scanner/Python.py
Normal file
166
scons/scons-local-4.1.0/SCons/Scanner/Python.py
Normal file
|
@ -0,0 +1,166 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
|
||||
"""Dependency scanner for Python code.
|
||||
|
||||
One important note about the design is that this does not take any dependencies
|
||||
upon packages or binaries in the Python installation unless they are listed in
|
||||
PYTHONPATH. To do otherwise would have required code to determine where the
|
||||
Python installation is, which is outside of the scope of a scanner like this.
|
||||
If consumers want to pick up dependencies upon these packages, they must put
|
||||
those directories in PYTHONPATH.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import SCons.Scanner
|
||||
|
||||
# Capture python "from a import b" and "import a" statements.
|
||||
from_cre = re.compile(r'^\s*from\s+([^\s]+)\s+import\s+(.*)', re.M)
|
||||
import_cre = re.compile(r'^\s*import\s+([^\s]+)', re.M)
|
||||
|
||||
|
||||
def path_function(env, dir=None, target=None, source=None, argument=None):
|
||||
"""Retrieves a tuple with all search paths."""
|
||||
paths = env['ENV'].get('PYTHONPATH', '').split(os.pathsep)
|
||||
if source:
|
||||
paths.append(source[0].dir.abspath)
|
||||
return tuple(paths)
|
||||
|
||||
|
||||
def find_include_names(node):
|
||||
"""Scans the node for all imports.
|
||||
|
||||
Returns a list of tuples. Each tuple has two elements:
|
||||
1. The main import (e.g. module, module.file, module.module2)
|
||||
2. Additional optional imports that could be functions or files
|
||||
in the case of a "from X import Y" statement. In the case of a
|
||||
normal "import" statement, this is None.
|
||||
"""
|
||||
text = node.get_text_contents()
|
||||
all_matches = []
|
||||
matches = from_cre.findall(text)
|
||||
if matches:
|
||||
for match in matches:
|
||||
imports = [i.strip() for i in match[1].split(',')]
|
||||
|
||||
# Add some custom logic to strip out "as" because the regex
|
||||
# includes it.
|
||||
last_import_split = imports[-1].split()
|
||||
if len(last_import_split) > 1:
|
||||
imports[-1] = last_import_split[0]
|
||||
|
||||
all_matches.append((match[0], imports))
|
||||
|
||||
matches = import_cre.findall(text)
|
||||
if matches:
|
||||
for match in matches:
|
||||
all_matches.append((match, None))
|
||||
|
||||
return all_matches
|
||||
|
||||
|
||||
def scan(node, env, path=()):
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes is not None:
|
||||
includes = node.includes
|
||||
else:
|
||||
includes = find_include_names(node)
|
||||
# Intern the names of the include files. Saves some memory
|
||||
# if the same header is included many times.
|
||||
node.includes = list(map(SCons.Util.silent_intern, includes))
|
||||
|
||||
# XXX TODO: Sort?
|
||||
nodes = []
|
||||
if callable(path):
|
||||
path = path()
|
||||
for module, imports in includes:
|
||||
is_relative = module.startswith('.')
|
||||
if is_relative:
|
||||
# This is a relative include, so we must ignore PYTHONPATH.
|
||||
module_lstripped = module.lstrip('.')
|
||||
# One dot is current directory, two is parent, three is
|
||||
# grandparent, etc.
|
||||
num_parents = len(module) - len(module_lstripped) - 1
|
||||
current_dir = node.get_dir()
|
||||
for i in itertools.repeat(None, num_parents):
|
||||
current_dir = current_dir.up()
|
||||
|
||||
search_paths = [current_dir.abspath]
|
||||
search_string = module_lstripped
|
||||
else:
|
||||
search_paths = path
|
||||
search_string = module
|
||||
|
||||
module_components = search_string.split('.')
|
||||
for search_path in search_paths:
|
||||
candidate_path = os.path.join(search_path, *module_components)
|
||||
# The import stored in "module" could refer to a directory or file.
|
||||
import_dirs = []
|
||||
if os.path.isdir(candidate_path):
|
||||
import_dirs = module_components
|
||||
|
||||
# Because this resolved to a directory, there is a chance that
|
||||
# additional imports (e.g. from module import A, B) could refer
|
||||
# to files to import.
|
||||
if imports:
|
||||
for imp in imports:
|
||||
file = os.path.join(candidate_path, imp + '.py')
|
||||
if os.path.isfile(file):
|
||||
nodes.append(file)
|
||||
elif os.path.isfile(candidate_path + '.py'):
|
||||
nodes.append(candidate_path + '.py')
|
||||
import_dirs = module_components[:-1]
|
||||
|
||||
# We can ignore imports because this resolved to a file. Any
|
||||
# additional imports (e.g. from module.file import A, B) would
|
||||
# only refer to functions in this file.
|
||||
|
||||
# Take a dependency on all __init__.py files from all imported
|
||||
# packages unless it's a relative import. If it's a relative
|
||||
# import, we don't need to take the dependency because Python
|
||||
# requires that all referenced packages have already been imported,
|
||||
# which means that the dependency has already been established.
|
||||
if import_dirs and not is_relative:
|
||||
for i in range(len(import_dirs)):
|
||||
init_components = module_components[:i+1] + ['__init__.py']
|
||||
init_path = os.path.join(search_path, *(init_components))
|
||||
if os.path.isfile(init_path):
|
||||
nodes.append(init_path)
|
||||
break
|
||||
|
||||
return sorted(nodes)
|
||||
|
||||
|
||||
PythonSuffixes = ['.py']
|
||||
PythonScanner = SCons.Scanner.Base(scan, name='PythonScanner',
|
||||
skeys=PythonSuffixes,
|
||||
path_function=path_function, recursive=1)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -1,12 +1,6 @@
|
|||
"""SCons.Scanner.RC
|
||||
|
||||
This module implements the dependency scanner for RC (Interface
|
||||
Definition Language) files.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -26,20 +20,17 @@ Definition Language) files.
|
|||
# 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/Scanner/RC.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for RC (Interface Definition Language) files."""
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
||||
|
||||
def no_tlb(nodes):
|
||||
"""
|
||||
Filter out .tlb files as they are binary and shouldn't be scanned
|
||||
"""
|
||||
"""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']
|
||||
|
||||
|
@ -47,15 +38,15 @@ def no_tlb(nodes):
|
|||
def RCScan():
|
||||
"""Return a prototype Scanner instance for scanning RC source files"""
|
||||
|
||||
res_re= r'^(?:\s*#\s*(?:include)|' \
|
||||
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
||||
'\s*.*?)' \
|
||||
'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
|
||||
"$RCSUFFIXES",
|
||||
"CPPPATH",
|
||||
res_re,
|
||||
recursive=no_tlb)
|
||||
res_re = (
|
||||
r'^(?:\s*#\s*(?:include)|'
|
||||
r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)'
|
||||
r'\s*.*?)'
|
||||
r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||
)
|
||||
resScanner = SCons.Scanner.ClassicCPP(
|
||||
"ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re, recursive=no_tlb
|
||||
)
|
||||
|
||||
return resScanner
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Scanner.SWIG
|
||||
|
||||
This module implements the dependency scanner for SWIG code.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,16 +20,15 @@ This module implements the dependency scanner for SWIG code.
|
|||
# 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/Scanner/SWIG.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""Dependency scanner for SWIG code."""
|
||||
|
||||
import SCons.Scanner
|
||||
|
||||
SWIGSuffixes = [ '.i' ]
|
||||
|
||||
def SWIGScanner():
|
||||
expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)'
|
||||
expr = r'^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)'
|
||||
scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr)
|
||||
return scanner
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Scanner
|
||||
|
||||
The Scanner package for the SCons software construction utility.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,9 +20,8 @@ The Scanner package for the SCons software construction utility.
|
|||
# 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/Scanner/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""The Scanner package for the SCons software construction utility."""
|
||||
|
||||
import re
|
||||
|
||||
|
@ -35,7 +29,7 @@ import SCons.Node.FS
|
|||
import SCons.Util
|
||||
|
||||
|
||||
class _Null(object):
|
||||
class _Null:
|
||||
pass
|
||||
|
||||
# This is used instead of None as a default argument value so None can be
|
||||
|
@ -43,16 +37,16 @@ class _Null(object):
|
|||
_null = _Null
|
||||
|
||||
def Scanner(function, *args, **kw):
|
||||
"""
|
||||
Public interface factory function for creating different types
|
||||
of Scanners based on the different types of "functions" that may
|
||||
be supplied.
|
||||
"""Factory function to create a Scanner Object.
|
||||
|
||||
Creates the appropriate Scanner based on the type of "function".
|
||||
|
||||
TODO: Deprecate this some day. We've moved the functionality
|
||||
inside the Base class and really don't need this factory function
|
||||
any more. It was, however, used by some of our Tool modules, so
|
||||
the call probably ended up in various people's custom modules
|
||||
patterned on SCons code.
|
||||
|
||||
"""
|
||||
if SCons.Util.is_Dict(function):
|
||||
return Selector(function, *args, **kw)
|
||||
|
@ -60,10 +54,8 @@ def Scanner(function, *args, **kw):
|
|||
return Base(function, *args, **kw)
|
||||
|
||||
|
||||
|
||||
class FindPathDirs(object):
|
||||
"""
|
||||
A class to bind a specific E{*}PATH variable name to a function that
|
||||
class FindPathDirs:
|
||||
"""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):
|
||||
|
@ -81,67 +73,26 @@ class FindPathDirs(object):
|
|||
|
||||
|
||||
|
||||
class Base(object):
|
||||
class Base:
|
||||
"""Base class for dependency scanners.
|
||||
|
||||
This implements straightforward, single-pass scanning of a single file.
|
||||
"""
|
||||
The base class for dependency scanners. This implements
|
||||
straightforward, single-pass scanning of a single file.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
function,
|
||||
name = "NONE",
|
||||
argument = _null,
|
||||
skeys = _null,
|
||||
path_function = None,
|
||||
# Node.FS.Base so that, by default, it's okay for a
|
||||
# scanner to return a Dir, File or Entry.
|
||||
node_class = SCons.Node.FS.Base,
|
||||
node_factory = None,
|
||||
scan_check = None,
|
||||
recursive = None):
|
||||
"""
|
||||
Construct a new scanner object given a scanner function.
|
||||
|
||||
'function' - a scanner function taking two or three
|
||||
arguments and returning a list of strings.
|
||||
|
||||
'name' - a name for identifying this scanner object.
|
||||
|
||||
'argument' - an optional argument that, if specified, will be
|
||||
passed to both the scanner function and the path_function.
|
||||
|
||||
'skeys' - an optional list argument that can be used to determine
|
||||
which scanner should be used for a given Node. In the case of File
|
||||
nodes, for example, the 'skeys' would be file suffixes.
|
||||
|
||||
'path_function' - a function that takes four or five arguments
|
||||
(a construction environment, Node for the directory containing
|
||||
the SConscript file that defined the primary target, list of
|
||||
target nodes, list of source nodes, and optional argument for
|
||||
this instance) and returns a tuple of the directories that can
|
||||
be searched for implicit dependency files. May also return a
|
||||
callable() which is called with no args and returns the tuple
|
||||
(supporting Bindable class).
|
||||
|
||||
'node_class' - the class of Nodes which this scan will return.
|
||||
If node_class is None, then this scanner will not enforce any
|
||||
Node conversion and will return the raw results from the
|
||||
underlying scanner function.
|
||||
|
||||
'node_factory' - the factory function to be called to translate
|
||||
the raw results returned by the scanner function into the
|
||||
expected node_class objects.
|
||||
|
||||
'scan_check' - a function to be called to first check whether
|
||||
this node really needs to be scanned.
|
||||
|
||||
'recursive' - specifies that this scanner should be invoked
|
||||
recursively on all of the implicit dependencies it returns
|
||||
(the canonical example being #include lines in C source files).
|
||||
May be a callable, which will be called to filter the list
|
||||
of nodes found to select a subset for recursive scanning
|
||||
(the canonical example being only recursively scanning
|
||||
subdirectories within a directory).
|
||||
def __init__(
|
||||
self,
|
||||
function,
|
||||
name="NONE",
|
||||
argument=_null,
|
||||
skeys=_null,
|
||||
path_function=None,
|
||||
# Node.FS.Base so that, by default, it's okay for a
|
||||
# scanner to return a Dir, File or Entry.
|
||||
node_class=SCons.Node.FS.Base,
|
||||
node_factory=None,
|
||||
scan_check=None,
|
||||
recursive=None,
|
||||
):
|
||||
"""Construct a new scanner object given a scanner function.
|
||||
|
||||
The scanner function's first argument will be a Node that should
|
||||
be scanned for dependencies, the second argument will be an
|
||||
|
@ -152,14 +103,55 @@ class Base(object):
|
|||
|
||||
Examples:
|
||||
|
||||
s = Scanner(my_scanner_function)
|
||||
s = Scanner(my_scanner_function)
|
||||
s = Scanner(function = my_scanner_function)
|
||||
s = Scanner(function = my_scanner_function, argument = 'foo')
|
||||
|
||||
s = Scanner(function = my_scanner_function)
|
||||
Args:
|
||||
function: a scanner function taking two or three arguments
|
||||
and returning a list of strings.
|
||||
|
||||
s = Scanner(function = my_scanner_function, argument = 'foo')
|
||||
name: a name for identifying this scanner object.
|
||||
|
||||
argument: an optional argument that, if specified, will be
|
||||
passed to both the scanner function and the path_function.
|
||||
|
||||
skeys: an optional list argument that can be used
|
||||
to determine which scanner should be used for a given
|
||||
Node. In the case of File nodes, for example, the 'skeys'
|
||||
would be file suffixes.
|
||||
|
||||
path_function: a function that takes four or five arguments
|
||||
(a construction environment, Node for the directory
|
||||
containing the SConscript file that defined the primary
|
||||
target, list of target nodes, list of source nodes, and
|
||||
optional argument for this instance) and returns a tuple
|
||||
of the directories that can be searched for implicit
|
||||
dependency files. May also return a callable() which
|
||||
is called with no args and returns the tuple (supporting
|
||||
Bindable class).
|
||||
|
||||
node_class: the class of Nodes which this scan will return.
|
||||
If node_class is None, then this scanner will not enforce
|
||||
any Node conversion and will return the raw results from
|
||||
the underlying scanner function.
|
||||
|
||||
node_factory: the factory function to be called to
|
||||
translate the raw results returned by the scanner function
|
||||
into the expected node_class objects.
|
||||
|
||||
scan_check: a function to be called to first check whether
|
||||
this node really needs to be scanned.
|
||||
|
||||
recursive: specifies that this scanner should be invoked
|
||||
recursively on all of the implicit dependencies it returns
|
||||
(the canonical example being #include lines in C source
|
||||
files). May be a callable, which will be called to filter
|
||||
the list of nodes found to select a subset for recursive
|
||||
scanning (the canonical example being only recursively
|
||||
scanning subdirectories within a directory).
|
||||
|
||||
"""
|
||||
|
||||
# Note: this class could easily work with scanner functions that take
|
||||
# something other than a filename as an argument (e.g. a database
|
||||
# node) and a dependencies list that aren't file names. All that
|
||||
|
@ -196,18 +188,22 @@ class Base(object):
|
|||
return self.path_function(env, dir, target, source)
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
"""
|
||||
This method scans a single object. 'node' is the node
|
||||
that will be passed to the scanner function, and 'env' is the
|
||||
environment that will be passed to the scanner function. A list of
|
||||
direct dependency nodes for the specified node will be returned.
|
||||
"""Scans a single object.
|
||||
|
||||
Args:
|
||||
node: the node that will be passed to the scanner function
|
||||
env: the environment that will be passed to the scanner function.
|
||||
|
||||
Returns:
|
||||
A list of direct dependency nodes for the specified node.
|
||||
|
||||
"""
|
||||
if self.scan_check and not self.scan_check(node, env):
|
||||
return []
|
||||
|
||||
self = self.select(node)
|
||||
|
||||
if not self.argument is _null:
|
||||
if self.argument is not _null:
|
||||
node_list = self.function(node, env, path, self.argument)
|
||||
else:
|
||||
node_list = self.function(node, env, path)
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,13 +20,8 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Script/Interactive.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
__doc__ = """
|
||||
SCons interactive mode
|
||||
"""
|
||||
"""SCons interactive mode. """
|
||||
|
||||
# TODO:
|
||||
#
|
||||
|
@ -247,7 +243,7 @@ version Prints SCons version information.
|
|||
while n:
|
||||
n = walker.get_next()
|
||||
|
||||
for node in list(seen_nodes.keys()):
|
||||
for node in seen_nodes.keys():
|
||||
# Call node.clear() to clear most of the state
|
||||
node.clear()
|
||||
# node.clear() doesn't reset node.state, so call
|
|
@ -1,23 +1,6 @@
|
|||
"""SCons.Script
|
||||
|
||||
This file implements the main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
unsupported_python_version = (2, 6, 0)
|
||||
deprecated_python_version = (2, 7, 0)
|
||||
|
||||
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -38,16 +21,32 @@ deprecated_python_version = (2, 7, 0)
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Script/Main.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""The main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
"""
|
||||
|
||||
# these define the range of versions SCons supports
|
||||
unsupported_python_version = (3, 4, 0)
|
||||
deprecated_python_version = (3, 4, 0)
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import atexit
|
||||
import importlib.util
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import sysconfig
|
||||
import platform
|
||||
import threading
|
||||
|
||||
import SCons.CacheDir
|
||||
import SCons.Debug
|
||||
|
@ -58,24 +57,28 @@ import SCons.Job
|
|||
import SCons.Node
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.SConf
|
||||
import SCons.Script
|
||||
import SCons.Taskmaster
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
import SCons.Script.Interactive
|
||||
|
||||
|
||||
def fetch_win32_parallel_msg():
|
||||
# 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
|
||||
# in-line "import" statement in the _main() function below doesn't
|
||||
# cause warnings about local names shadowing use of the 'SCons'
|
||||
# global in nest scopes and UnboundLocalErrors and the like in some
|
||||
# versions (2.1) of Python.
|
||||
import SCons.Platform.win32
|
||||
return SCons.Platform.win32.parallel_msg
|
||||
# Global variables
|
||||
first_command_start = None
|
||||
last_command_end = None
|
||||
print_objects = 0
|
||||
print_memoizer = 0
|
||||
print_stacktrace = 0
|
||||
print_time = 0
|
||||
print_action_timestamps = 0
|
||||
sconscript_time = 0
|
||||
cumulative_command_time = 0
|
||||
exit_status = 0 # final exit status, assume success by default
|
||||
this_build_status = 0 # "exit status" of an individual build
|
||||
num_jobs = None
|
||||
delayed_warnings = []
|
||||
|
||||
|
||||
def revert_io():
|
||||
|
@ -85,17 +88,16 @@ def revert_io():
|
|||
sys.stderr = sys.__stderr__
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
|
||||
class SConsPrintHelpException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
display = SCons.Util.display
|
||||
progress_display = SCons.Util.DisplayEngine()
|
||||
|
||||
first_command_start = None
|
||||
last_command_end = None
|
||||
|
||||
|
||||
class Progressor(object):
|
||||
class Progressor:
|
||||
prev = ''
|
||||
count = 0
|
||||
target_string = '$TARGET'
|
||||
|
@ -194,6 +196,9 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
|
|||
finish_time = time.time()
|
||||
last_command_end = finish_time
|
||||
cumulative_command_time = cumulative_command_time+finish_time-start_time
|
||||
if print_action_timestamps:
|
||||
sys.stdout.write("Command execution start timestamp: %s: %f\n"%(str(self.node), start_time))
|
||||
sys.stdout.write("Command execution end timestamp: %s: %f\n"%(str(self.node), finish_time))
|
||||
sys.stdout.write("Command execution time: %s: %f seconds\n"%(str(self.node), finish_time-start_time))
|
||||
|
||||
def do_failed(self, status=2):
|
||||
|
@ -336,7 +341,7 @@ class CleanTask(SCons.Taskmaster.AlwaysTask):
|
|||
display("Removed directory " + pathstr)
|
||||
else:
|
||||
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 as e:
|
||||
print(e)
|
||||
except (IOError, OSError) as e:
|
||||
|
@ -412,11 +417,12 @@ class QuestionTask(SCons.Taskmaster.AlwaysTask):
|
|||
pass
|
||||
|
||||
|
||||
class TreePrinter(object):
|
||||
def __init__(self, derived=False, prune=False, status=False):
|
||||
class TreePrinter:
|
||||
def __init__(self, derived=False, prune=False, status=False, sLineDraw=False):
|
||||
self.derived = derived
|
||||
self.prune = prune
|
||||
self.status = status
|
||||
self.sLineDraw = sLineDraw
|
||||
def get_all_children(self, node):
|
||||
return node.all_children()
|
||||
def get_derived_children(self, node):
|
||||
|
@ -428,7 +434,7 @@ class TreePrinter(object):
|
|||
else:
|
||||
func = self.get_all_children
|
||||
s = self.status and 2 or 0
|
||||
SCons.Util.print_tree(t, func, prune=self.prune, showtags=s)
|
||||
SCons.Util.print_tree(t, func, prune=self.prune, showtags=s, lastChild=True, singleLineDraw=self.sLineDraw)
|
||||
|
||||
|
||||
def python_version_string():
|
||||
|
@ -441,20 +447,7 @@ def python_version_deprecated(version=sys.version_info):
|
|||
return version < deprecated_python_version
|
||||
|
||||
|
||||
# Global variables
|
||||
|
||||
print_objects = 0
|
||||
print_memoizer = 0
|
||||
print_stacktrace = 0
|
||||
print_time = 0
|
||||
sconscript_time = 0
|
||||
cumulative_command_time = 0
|
||||
exit_status = 0 # final exit status, assume success by default
|
||||
this_build_status = 0 # "exit status" of an individual build
|
||||
num_jobs = None
|
||||
delayed_warnings = []
|
||||
|
||||
class FakeOptionParser(object):
|
||||
class FakeOptionParser:
|
||||
"""
|
||||
A do-nothing option parser, used for the initial OptionsParser variable.
|
||||
|
||||
|
@ -466,7 +459,7 @@ class FakeOptionParser(object):
|
|||
without blowing up.
|
||||
|
||||
"""
|
||||
class FakeOptionValues(object):
|
||||
class FakeOptionValues:
|
||||
def __getattr__(self, attr):
|
||||
return None
|
||||
values = FakeOptionValues()
|
||||
|
@ -490,7 +483,7 @@ def SetOption(name, value):
|
|||
def PrintHelp(file=None):
|
||||
OptionsParser.print_help(file=file)
|
||||
|
||||
class Stats(object):
|
||||
class Stats:
|
||||
def __init__(self):
|
||||
self.stats = []
|
||||
self.labels = []
|
||||
|
@ -622,7 +615,7 @@ def _SConstruct_exists(dirname='', repositories=[], filelist=None):
|
|||
current directory.
|
||||
"""
|
||||
if not filelist:
|
||||
filelist = ['SConstruct', 'Sconstruct', 'sconstruct']
|
||||
filelist = ['SConstruct', 'Sconstruct', 'sconstruct', 'SConstruct.py', 'Sconstruct.py', 'sconstruct.py']
|
||||
for file in filelist:
|
||||
sfile = os.path.join(dirname, file)
|
||||
if os.path.isfile(sfile):
|
||||
|
@ -634,7 +627,7 @@ def _SConstruct_exists(dirname='', repositories=[], filelist=None):
|
|||
return None
|
||||
|
||||
def _set_debug_values(options):
|
||||
global print_memoizer, print_objects, print_stacktrace, print_time
|
||||
global print_memoizer, print_objects, print_stacktrace, print_time, print_action_timestamps
|
||||
|
||||
debug_values = options.debug
|
||||
|
||||
|
@ -672,6 +665,9 @@ def _set_debug_values(options):
|
|||
options.tree_printers.append(TreePrinter(status=True))
|
||||
if "time" in debug_values:
|
||||
print_time = 1
|
||||
if "action-timestamps" in debug_values:
|
||||
print_time = 1
|
||||
print_action_timestamps = 1
|
||||
if "tree" in debug_values:
|
||||
options.tree_printers.append(TreePrinter())
|
||||
if "prepare" in debug_values:
|
||||
|
@ -689,80 +685,87 @@ def _create_path(plist):
|
|||
return path
|
||||
|
||||
def _load_site_scons_dir(topdir, site_dir_name=None):
|
||||
"""Load the site_scons dir under topdir.
|
||||
Prepends site_scons to sys.path, imports site_scons/site_init.py,
|
||||
and prepends site_scons/site_tools to default toolpath."""
|
||||
"""Load the site directory under topdir.
|
||||
|
||||
If a site dir name is supplied use it, else use default "site_scons"
|
||||
Prepend site dir to sys.path.
|
||||
If a "site_tools" subdir exists, prepend to toolpath.
|
||||
Import "site_init.py" from site dir if it exists.
|
||||
"""
|
||||
if site_dir_name:
|
||||
err_if_not_found = True # user specified: err if missing
|
||||
else:
|
||||
site_dir_name = "site_scons"
|
||||
err_if_not_found = False
|
||||
|
||||
err_if_not_found = False # scons default: okay to be missing
|
||||
site_dir = os.path.join(topdir, site_dir_name)
|
||||
|
||||
if not os.path.exists(site_dir):
|
||||
if err_if_not_found:
|
||||
raise SCons.Errors.UserError("site dir %s not found."%site_dir)
|
||||
raise SCons.Errors.UserError("site dir %s not found." % site_dir)
|
||||
return
|
||||
sys.path.insert(0, os.path.abspath(site_dir))
|
||||
|
||||
site_init_filename = "site_init.py"
|
||||
site_init_modname = "site_init"
|
||||
site_tools_dirname = "site_tools"
|
||||
# prepend to sys.path
|
||||
sys.path = [os.path.abspath(site_dir)] + sys.path
|
||||
site_init_file = os.path.join(site_dir, site_init_filename)
|
||||
site_tools_dir = os.path.join(site_dir, site_tools_dirname)
|
||||
if os.path.exists(site_init_file):
|
||||
import imp, re
|
||||
try:
|
||||
try:
|
||||
fp, pathname, description = imp.find_module(site_init_modname,
|
||||
[site_dir])
|
||||
# Load the file into SCons.Script namespace. This is
|
||||
# opaque and clever; m is the module object for the
|
||||
# SCons.Script module, and the exec ... in call executes a
|
||||
# file (or string containing code) in the context of the
|
||||
# module's dictionary, so anything that code defines ends
|
||||
# up adding to that module. This is really short, but all
|
||||
# the error checking makes it longer.
|
||||
try:
|
||||
m = sys.modules['SCons.Script']
|
||||
except Exception as e:
|
||||
fmt = 'cannot import site_init.py: missing SCons.Script module %s'
|
||||
raise SCons.Errors.InternalError(fmt % repr(e))
|
||||
try:
|
||||
sfx = description[0]
|
||||
modname = os.path.basename(pathname)[:-len(sfx)]
|
||||
site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
|
||||
re_special = re.compile("__[^_]+__")
|
||||
for k in list(m.__dict__.keys()):
|
||||
if not re_special.match(k):
|
||||
site_m[k] = m.__dict__[k]
|
||||
|
||||
# This is the magic.
|
||||
exec(compile(fp.read(), fp.name, 'exec'), site_m)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
fmt = '*** Error loading site_init file %s:\n'
|
||||
sys.stderr.write(fmt % repr(site_init_file))
|
||||
raise
|
||||
else:
|
||||
for k in site_m:
|
||||
if not re_special.match(k):
|
||||
m.__dict__[k] = site_m[k]
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except ImportError as e:
|
||||
fmt = '*** cannot import site init file %s:\n'
|
||||
sys.stderr.write(fmt % repr(site_init_file))
|
||||
raise
|
||||
finally:
|
||||
if fp:
|
||||
fp.close()
|
||||
if os.path.exists(site_tools_dir):
|
||||
# prepend to DefaultToolpath
|
||||
SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir))
|
||||
|
||||
if not os.path.exists(site_init_file):
|
||||
return
|
||||
|
||||
# "import" the site_init.py file into the SCons.Script namespace.
|
||||
# This is a variant on the basic Python import flow in that the globals
|
||||
# dict for the compile step is prepopulated from the SCons.Script
|
||||
# module object; on success the SCons.Script globals are refilled
|
||||
# from the site_init globals so it all appears in SCons.Script
|
||||
# instead of as a separate module.
|
||||
try:
|
||||
try:
|
||||
m = sys.modules['SCons.Script']
|
||||
except KeyError:
|
||||
fmt = 'cannot import {}: missing SCons.Script module'
|
||||
raise SCons.Errors.InternalError(fmt.format(site_init_file))
|
||||
|
||||
spec = importlib.util.spec_from_file_location(site_init_modname, site_init_file)
|
||||
site_m = {
|
||||
"__file__": spec.origin,
|
||||
"__name__": spec.name,
|
||||
"__doc__": None,
|
||||
}
|
||||
re_dunder = re.compile(r"__[^_]+__")
|
||||
# update site dict with all but magic (dunder) methods
|
||||
for k, v in m.__dict__.items():
|
||||
if not re_dunder.match(k):
|
||||
site_m[k] = v
|
||||
|
||||
with open(spec.origin, 'r') as f:
|
||||
code = f.read()
|
||||
try:
|
||||
codeobj = compile(code, spec.name, "exec")
|
||||
exec(codeobj, site_m)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception:
|
||||
fmt = "*** Error loading site_init file {}:\n"
|
||||
sys.stderr.write(fmt.format(site_init_file))
|
||||
raise
|
||||
else:
|
||||
# now refill globals with site_init's symbols
|
||||
for k, v in site_m.items():
|
||||
if not re_dunder.match(k):
|
||||
m.__dict__[k] = v
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception:
|
||||
fmt = "*** cannot import site init file {}:\n"
|
||||
sys.stderr.write(fmt.format(site_init_file))
|
||||
raise
|
||||
|
||||
|
||||
def _load_all_site_scons_dirs(topdir, verbose=None):
|
||||
"""Load all of the predefined site_scons dir.
|
||||
Order is significant; we load them in order from most generic
|
||||
|
@ -801,7 +804,7 @@ def _load_all_site_scons_dirs(topdir, verbose=None):
|
|||
sysdirs=['/usr/share/scons',
|
||||
homedir('.scons')]
|
||||
|
||||
dirs=sysdirs + [topdir]
|
||||
dirs = sysdirs + [topdir]
|
||||
for d in dirs:
|
||||
if verbose: # this is used by unit tests.
|
||||
print("Loading site dir ", d)
|
||||
|
@ -862,6 +865,13 @@ def _main(parser):
|
|||
for warning_type, message in delayed_warnings:
|
||||
SCons.Warnings.warn(warning_type, message)
|
||||
|
||||
if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
|
||||
if options.enable_virtualenv:
|
||||
SCons.Platform.virtualenv.enable_virtualenv = True
|
||||
|
||||
if options.ignore_virtualenv:
|
||||
SCons.Platform.virtualenv.ignore_virtualenv = True
|
||||
|
||||
if options.diskcheck:
|
||||
SCons.Node.FS.set_diskcheck(options.diskcheck)
|
||||
|
||||
|
@ -1089,7 +1099,7 @@ def _main(parser):
|
|||
SCons.Job.explicit_stack_size = options.stack_size
|
||||
|
||||
if options.md5_chunksize:
|
||||
SCons.Node.FS.File.md5_chunksize = options.md5_chunksize
|
||||
SCons.Node.FS.File.md5_chunksize = options.md5_chunksize * 1024
|
||||
|
||||
platform = SCons.Platform.platform_module()
|
||||
|
||||
|
@ -1161,7 +1171,7 @@ def _build_targets(fs, options, targets, target_top):
|
|||
# -U, local SConscript Default() targets
|
||||
target_top = fs.Dir(target_top)
|
||||
def check_dir(x, target_top=target_top):
|
||||
if hasattr(x, 'cwd') and not x.cwd is None:
|
||||
if hasattr(x, 'cwd') and x.cwd is not None:
|
||||
cwd = x.cwd.srcnode()
|
||||
return cwd == target_top
|
||||
else:
|
||||
|
@ -1240,10 +1250,14 @@ def _build_targets(fs, options, targets, target_top):
|
|||
"""Leave the order of dependencies alone."""
|
||||
return dependencies
|
||||
|
||||
def tmtrace_cleanup(tfile):
|
||||
tfile.close()
|
||||
|
||||
if options.taskmastertrace_file == '-':
|
||||
tmtrace = sys.stdout
|
||||
elif options.taskmastertrace_file:
|
||||
tmtrace = open(options.taskmastertrace_file, 'w')
|
||||
atexit.register(tmtrace_cleanup, tmtrace)
|
||||
else:
|
||||
tmtrace = None
|
||||
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
|
||||
|
@ -1253,16 +1267,23 @@ def _build_targets(fs, options, targets, target_top):
|
|||
BuildTask.options = options
|
||||
|
||||
|
||||
python_has_threads = sysconfig.get_config_var('WITH_THREAD')
|
||||
is_pypy = platform.python_implementation() == 'PyPy'
|
||||
# As of 3.7, python removed support for threadless platforms.
|
||||
# See https://www.python.org/dev/peps/pep-0011/
|
||||
is_37_or_later = sys.version_info >= (3, 7)
|
||||
# python_has_threads = sysconfig.get_config_var('WITH_THREAD') or is_pypy or is_37_or_later
|
||||
|
||||
# As of python 3.4 threading has a dummy_threading module for use when there is no threading
|
||||
# it's get_ident() will allways return -1, while real threading modules get_ident() will
|
||||
# always return a positive integer
|
||||
python_has_threads = threading.get_ident() != -1
|
||||
# to check if python configured with threads.
|
||||
global num_jobs
|
||||
num_jobs = options.num_jobs
|
||||
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
|
||||
if num_jobs > 1:
|
||||
msg = None
|
||||
if sys.platform == 'win32':
|
||||
msg = fetch_win32_parallel_msg()
|
||||
elif jobs.num_jobs == 1 or not python_has_threads:
|
||||
if jobs.num_jobs == 1 or not python_has_threads:
|
||||
msg = "parallel builds are unsupported by this version of Python;\n" + \
|
||||
"\tignoring -j or num_jobs option.\n"
|
||||
if msg:
|
||||
|
@ -1312,8 +1333,7 @@ def _exec_main(parser, values):
|
|||
import pdb
|
||||
pdb.Pdb().runcall(_main, parser)
|
||||
elif options.profile_file:
|
||||
# compat layer imports "cProfile" for us if it's available.
|
||||
from profile import Profile
|
||||
from cProfile import Profile
|
||||
|
||||
prof = Profile()
|
||||
try:
|
||||
|
@ -1339,15 +1359,14 @@ def main():
|
|||
|
||||
parts = ["SCons by Steven Knight et al.:\n"]
|
||||
try:
|
||||
import __main__
|
||||
parts.append(version_string("script", __main__))
|
||||
import SCons
|
||||
parts.append(version_string("SCons", SCons))
|
||||
except (ImportError, AttributeError):
|
||||
# On Windows there is no scons.py, so there is no
|
||||
# __main__.__version__, hence there is no script version.
|
||||
pass
|
||||
parts.append(version_string("engine", SCons))
|
||||
parts.append(path_string("engine", SCons))
|
||||
parts.append("Copyright (c) 2001 - 2017 The SCons Foundation")
|
||||
parts.append(path_string("SCons", SCons))
|
||||
parts.append(SCons.__copyright__)
|
||||
version = ''.join(parts)
|
||||
|
||||
from . import SConsOptions
|
||||
|
@ -1363,7 +1382,7 @@ def main():
|
|||
revert_io()
|
||||
except SystemExit as s:
|
||||
if s:
|
||||
exit_status = s
|
||||
exit_status = s.code
|
||||
except KeyboardInterrupt:
|
||||
print("scons: Build interrupted.")
|
||||
sys.exit(2)
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -19,25 +20,19 @@
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Script/SConsOptions.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import optparse
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))')
|
||||
no_hyphen_re = re.compile(r'(\s+|(?<=[\w!\"\'&.,?])-{2,}(?=\w))')
|
||||
|
||||
try:
|
||||
from gettext import gettext
|
||||
except ImportError:
|
||||
def gettext(message):
|
||||
return message
|
||||
_ = gettext
|
||||
import gettext
|
||||
_ = gettext.gettext
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.Warnings
|
||||
|
||||
OptionValueError = optparse.OptionValueError
|
||||
|
@ -125,7 +120,8 @@ class SConsValues(optparse.Values):
|
|||
# is not available.
|
||||
raise AttributeError(attr)
|
||||
|
||||
|
||||
# keep this list in sync with the SetOption doc in SCons/Script/Main.xml
|
||||
# search for UPDATE_SETOPTION_DOCS there.
|
||||
settable = [
|
||||
'clean',
|
||||
'diskcheck',
|
||||
|
@ -139,14 +135,15 @@ class SConsValues(optparse.Values):
|
|||
'random',
|
||||
'stack_size',
|
||||
'warn',
|
||||
'silent'
|
||||
'silent',
|
||||
'no_progress'
|
||||
]
|
||||
|
||||
def set_option(self, name, value):
|
||||
"""
|
||||
Sets an option from an SConscript file.
|
||||
"""
|
||||
if not name in self.settable:
|
||||
if name not in self.settable:
|
||||
raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name)
|
||||
|
||||
if name == 'num_jobs':
|
||||
|
@ -166,7 +163,7 @@ class SConsValues(optparse.Values):
|
|||
value = str(value)
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("A string is required: %s"%repr(value))
|
||||
if not value in SCons.Node.FS.Valid_Duplicates:
|
||||
if value not in SCons.Node.FS.Valid_Duplicates:
|
||||
raise SCons.Errors.UserError("Not a valid duplication style: %s" % value)
|
||||
# Set the duplicate style right away so it can affect linking
|
||||
# of SConscript files.
|
||||
|
@ -196,6 +193,9 @@ class SConsValues(optparse.Values):
|
|||
value = [value]
|
||||
value = self.__SConscript_settings__.get(name, []) + value
|
||||
SCons.Warnings.process_warn_strings(value)
|
||||
elif name == 'no_progress':
|
||||
SCons.Script.Main.progress_display.set_mode(False)
|
||||
|
||||
|
||||
self.__SConscript_settings__[name] = value
|
||||
|
||||
|
@ -225,39 +225,8 @@ class SConsOption(optparse.Option):
|
|||
fmt = "option %s: nargs='?' is incompatible with short options"
|
||||
raise SCons.Errors.UserError(fmt % self._short_opts[0])
|
||||
|
||||
try:
|
||||
_orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS
|
||||
|
||||
_orig_CHECK_METHODS = optparse.Option.CHECK_METHODS
|
||||
|
||||
except AttributeError:
|
||||
# optparse.Option had no CONST_ACTIONS before Python 2.5.
|
||||
|
||||
_orig_CONST_ACTIONS = ("store_const",)
|
||||
|
||||
def _check_const(self):
|
||||
if self.action not in self.CONST_ACTIONS and self.const is not None:
|
||||
raise OptionError(
|
||||
"'const' must not be supplied for action %r" % self.action,
|
||||
self)
|
||||
|
||||
# optparse.Option collects its list of unbound check functions
|
||||
# up front. This sucks because it means we can't just override
|
||||
# the _check_const() function like a normal method, we have to
|
||||
# actually replace it in the list. This seems to be the most
|
||||
# straightforward way to do that.
|
||||
|
||||
_orig_CHECK_METHODS = [optparse.Option._check_action,
|
||||
optparse.Option._check_type,
|
||||
optparse.Option._check_choice,
|
||||
optparse.Option._check_dest,
|
||||
_check_const,
|
||||
optparse.Option._check_nargs,
|
||||
optparse.Option._check_callback]
|
||||
|
||||
CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional]
|
||||
|
||||
CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
|
||||
CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_nargs_optional]
|
||||
CONST_ACTIONS = optparse.Option.CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
|
||||
|
||||
class SConsOptionGroup(optparse.OptionGroup):
|
||||
"""
|
||||
|
@ -299,8 +268,7 @@ class SConsOptionParser(optparse.OptionParser):
|
|||
"""
|
||||
arg = rargs.pop(0)
|
||||
|
||||
# Value explicitly attached to arg? Pretend it's the next
|
||||
# argument.
|
||||
# Value explicitly attached to arg? Pretend it's the next argument.
|
||||
if "=" in arg:
|
||||
(opt, next_arg) = arg.split("=", 1)
|
||||
rargs.insert(0, next_arg)
|
||||
|
@ -310,7 +278,11 @@ class SConsOptionParser(optparse.OptionParser):
|
|||
had_explicit_value = False
|
||||
|
||||
try:
|
||||
opt = self._match_long_opt(opt)
|
||||
if opt != self._match_long_opt(opt):
|
||||
raise optparse.BadOptionError(
|
||||
"'%s'. Did you mean '%s'?"
|
||||
% (opt, self._match_long_opt(opt))
|
||||
)
|
||||
except optparse.BadOptionError:
|
||||
if self.preserve_unknown_options:
|
||||
# SCons-specific: if requested, add unknown options to
|
||||
|
@ -358,29 +330,27 @@ class SConsOptionParser(optparse.OptionParser):
|
|||
option.process(opt, value, values, self)
|
||||
|
||||
def reparse_local_options(self):
|
||||
"""
|
||||
Re-parse the leftover command-line options stored
|
||||
in self.largs, so that any value overridden on the
|
||||
command line is immediately available if the user turns
|
||||
around and does a GetOption() right away.
|
||||
""" Re-parse the leftover command-line options.
|
||||
|
||||
Parse options stored in `self.largs`, so that any value
|
||||
overridden on the command line is immediately available
|
||||
if the user turns around and does a :func:`GetOption` right away.
|
||||
|
||||
We mimic the processing of the single args
|
||||
in the original OptionParser._process_args(), but here we
|
||||
allow exact matches for long-opts only (no partial
|
||||
argument names!).
|
||||
|
||||
Else, this would lead to problems in add_local_option()
|
||||
in the original OptionParser :func:`_process_args`, but here we
|
||||
allow exact matches for long-opts only (no partial argument names!).
|
||||
Otherwise there could be problems in :func:`add_local_option`
|
||||
below. When called from there, we try to reparse the
|
||||
command-line arguments that
|
||||
1. haven't been processed so far (self.largs), but
|
||||
2. are possibly not added to the list of options yet.
|
||||
|
||||
So, when we only have a value for "--myargument" yet,
|
||||
a command-line argument of "--myarg=test" would set it.
|
||||
Responsible for this behaviour is the method
|
||||
_match_long_opt(), which allows for partial matches of
|
||||
the option name, as long as the common prefix appears to
|
||||
be unique.
|
||||
1. haven't been processed so far (`self.largs`), but
|
||||
2. are possibly not added to the list of options yet.
|
||||
|
||||
So, when we only have a value for "--myargument" so far,
|
||||
a command-line argument of "--myarg=test" would set it,
|
||||
per the behaviour of :func:`_match_long_opt`,
|
||||
which allows for partial matches of the option name,
|
||||
as long as the common prefix appears to be unique.
|
||||
This would lead to further confusion, because we might want
|
||||
to add another option "--myarg" later on (see issue #2929).
|
||||
|
||||
|
@ -426,7 +396,7 @@ class SConsOptionParser(optparse.OptionParser):
|
|||
"""
|
||||
Adds a local option to the parser.
|
||||
|
||||
This is initiated by a SetOption() call to add a user-defined
|
||||
This is initiated by an AddOption() call to add a user-defined
|
||||
command-line option. We add the option to a separate option
|
||||
group for the local options, creating the group if necessary.
|
||||
"""
|
||||
|
@ -614,9 +584,15 @@ def Parser(version):
|
|||
help="Print build actions for files from CacheDir.")
|
||||
|
||||
def opt_invalid(group, value, options):
|
||||
"""report an invalid option from a group"""
|
||||
errmsg = "`%s' is not a valid %s option type, try:\n" % (value, group)
|
||||
return errmsg + " %s" % ", ".join(options)
|
||||
|
||||
def opt_invalid_rm(group, value, msg):
|
||||
"""report an invalid option from a group: recognized but removed"""
|
||||
errmsg = "`%s' is not a valid %s option type " % (value, group)
|
||||
return errmsg + msg
|
||||
|
||||
config_options = ["auto", "force" ,"cache"]
|
||||
|
||||
opt_config_help = "Controls Configure subsystem: %s." \
|
||||
|
@ -634,9 +610,11 @@ def Parser(version):
|
|||
help="Search up directory tree for SConstruct, "
|
||||
"build all Default() targets.")
|
||||
|
||||
deprecated_debug_options = {
|
||||
deprecated_debug_options = {}
|
||||
|
||||
removed_debug_options = {
|
||||
"dtree" : '; please use --tree=derived instead',
|
||||
"nomemoizer" : ' and has no effect',
|
||||
"nomemoizer" : '; there is no replacement',
|
||||
"stree" : '; please use --tree=all,status instead',
|
||||
"tree" : '; please use --tree=all instead',
|
||||
}
|
||||
|
@ -644,15 +622,16 @@ def Parser(version):
|
|||
debug_options = ["count", "duplicate", "explain", "findlibs",
|
||||
"includes", "memoizer", "memory", "objects",
|
||||
"pdb", "prepare", "presub", "stacktrace",
|
||||
"time"]
|
||||
"time", "action-timestamps"]
|
||||
|
||||
def opt_debug(option, opt, value__, parser,
|
||||
debug_options=debug_options,
|
||||
deprecated_debug_options=deprecated_debug_options):
|
||||
deprecated_debug_options=deprecated_debug_options,
|
||||
removed_debug_options=removed_debug_options):
|
||||
for value in value__.split(','):
|
||||
if value in debug_options:
|
||||
parser.values.debug.append(value)
|
||||
elif value in list(deprecated_debug_options.keys()):
|
||||
elif value in deprecated_debug_options:
|
||||
parser.values.debug.append(value)
|
||||
try:
|
||||
parser.values.delayed_warnings
|
||||
|
@ -662,6 +641,9 @@ def Parser(version):
|
|||
w = "The --debug=%s option is deprecated%s." % (value, msg)
|
||||
t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w)
|
||||
parser.values.delayed_warnings.append(t)
|
||||
elif value in removed_debug_options:
|
||||
msg = removed_debug_options[value]
|
||||
raise OptionValueError(opt_invalid_rm('debug', value, msg))
|
||||
else:
|
||||
raise OptionValueError(opt_invalid('debug', value, debug_options))
|
||||
|
||||
|
@ -689,7 +671,7 @@ def Parser(version):
|
|||
metavar="TYPE")
|
||||
|
||||
def opt_duplicate(option, opt, value, parser):
|
||||
if not value in SCons.Node.FS.Valid_Duplicates:
|
||||
if value not in SCons.Node.FS.Valid_Duplicates:
|
||||
raise OptionValueError(opt_invalid('duplication', value,
|
||||
SCons.Node.FS.Valid_Duplicates))
|
||||
setattr(parser.values, option.dest, value)
|
||||
|
@ -706,6 +688,12 @@ def Parser(version):
|
|||
action="callback", callback=opt_duplicate,
|
||||
help=opt_duplicate_help)
|
||||
|
||||
if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
|
||||
op.add_option('--enable-virtualenv',
|
||||
dest="enable_virtualenv",
|
||||
action="store_true",
|
||||
help="Import certain virtualenv variables to SCons")
|
||||
|
||||
op.add_option('-f', '--file', '--makefile', '--sconstruct',
|
||||
nargs=1, type="string",
|
||||
dest="file", default=[],
|
||||
|
@ -733,6 +721,11 @@ def Parser(version):
|
|||
help="Search DIR for imported Python modules.",
|
||||
metavar="DIR")
|
||||
|
||||
op.add_option('--ignore-virtualenv',
|
||||
dest="ignore_virtualenv",
|
||||
action="store_true",
|
||||
help="Do not import virtualenv variables to SCons")
|
||||
|
||||
op.add_option('--implicit-cache',
|
||||
dest='implicit_cache', default=False,
|
||||
action="store_true",
|
||||
|
@ -841,7 +834,7 @@ def Parser(version):
|
|||
help="Trace Node evaluation to FILE.",
|
||||
metavar="FILE")
|
||||
|
||||
tree_options = ["all", "derived", "prune", "status"]
|
||||
tree_options = ["all", "derived", "prune", "status", "linedraw"]
|
||||
|
||||
def opt_tree(option, opt, value, parser, tree_options=tree_options):
|
||||
from . import Main
|
||||
|
@ -855,6 +848,8 @@ def Parser(version):
|
|||
tp.prune = True
|
||||
elif o == 'status':
|
||||
tp.status = True
|
||||
elif o == 'linedraw':
|
||||
tp.sLineDraw = True
|
||||
else:
|
||||
raise OptionValueError(opt_invalid('--tree', o, tree_options))
|
||||
parser.values.tree_printers.append(tp)
|
||||
|
@ -906,6 +901,7 @@ def Parser(version):
|
|||
action="append",
|
||||
help="Search REPOSITORY for source and target files.")
|
||||
|
||||
|
||||
# Options from Make and Cons classic that we do not yet support,
|
||||
# but which we may support someday and whose (potential) meanings
|
||||
# we don't want to change. These all get a "the -X option is not
|
||||
|
@ -978,7 +974,6 @@ def Parser(version):
|
|||
action="callback", callback=opt_not_yet,
|
||||
# help="Warn when an undefined variable is referenced."
|
||||
help=SUPPRESS_HELP)
|
||||
|
||||
return op
|
||||
|
||||
# Local Variables:
|
|
@ -1,12 +1,6 @@
|
|||
"""SCons.Script.SConscript
|
||||
|
||||
This module defines the Python API provided to SConscript and SConstruct
|
||||
files.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -27,7 +21,7 @@ files.
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Script/SConscript.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""This module defines the Python API provided to SConscript files."""
|
||||
|
||||
import SCons
|
||||
import SCons.Action
|
||||
|
@ -42,11 +36,10 @@ import SCons.Platform
|
|||
import SCons.SConf
|
||||
import SCons.Script.Main
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
from SCons.Util import is_List, is_String, is_Dict, flatten
|
||||
from SCons.Node import SConscriptNodes
|
||||
from . import Main
|
||||
|
||||
import collections
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
|
@ -98,7 +91,7 @@ def compute_exports(exports):
|
|||
retval = {}
|
||||
try:
|
||||
for export in exports:
|
||||
if SCons.Util.is_Dict(export):
|
||||
if is_Dict(export):
|
||||
retval.update(export)
|
||||
else:
|
||||
try:
|
||||
|
@ -110,7 +103,7 @@ def compute_exports(exports):
|
|||
|
||||
return retval
|
||||
|
||||
class Frame(object):
|
||||
class Frame:
|
||||
"""A frame on the SConstruct/SConscript call stack"""
|
||||
def __init__(self, fs, exports, sconscript):
|
||||
self.globals = BuildDefaultGlobals()
|
||||
|
@ -133,7 +126,7 @@ call_stack = []
|
|||
def Return(*vars, **kw):
|
||||
retval = []
|
||||
try:
|
||||
fvars = SCons.Util.flatten(vars)
|
||||
fvars = flatten(vars)
|
||||
for var in fvars:
|
||||
for v in var.split():
|
||||
retval.append(call_stack[-1].globals[v])
|
||||
|
@ -153,6 +146,35 @@ def Return(*vars, **kw):
|
|||
|
||||
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
|
||||
|
||||
def handle_missing_SConscript(f, must_exist=None):
|
||||
"""Take appropriate action on missing file in SConscript() call.
|
||||
|
||||
Print a warning or raise an exception on missing file.
|
||||
On first warning, print a deprecation message.
|
||||
|
||||
Args:
|
||||
f (str): path of missing configuration file
|
||||
must_exist (bool): raise exception if file does not exist
|
||||
|
||||
Raises:
|
||||
UserError if 'must_exist' is True or if global
|
||||
SCons.Script._no_missing_sconscript is True.
|
||||
"""
|
||||
|
||||
if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False):
|
||||
msg = "Fatal: missing SConscript '%s'" % f.get_internal_path()
|
||||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
if SCons.Script._warn_missing_sconscript_deprecated and must_exist is None:
|
||||
msg = "Calling missing SConscript without error is deprecated.\n" + \
|
||||
"Transition by adding must_exist=0 to SConscript calls.\n" + \
|
||||
"Missing SConscript '%s'" % f.get_internal_path()
|
||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
|
||||
SCons.Script._warn_missing_sconscript_deprecated = False
|
||||
else:
|
||||
msg = "Ignoring missing SConscript '%s'" % f.get_internal_path()
|
||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
|
||||
|
||||
def _SConscript(fs, *files, **kw):
|
||||
top = fs.Top
|
||||
sd = fs.SConstruct_dir.rdir()
|
||||
|
@ -173,6 +195,7 @@ def _SConscript(fs, *files, **kw):
|
|||
else:
|
||||
f = fs.File(str(fn))
|
||||
_file_ = None
|
||||
SConscriptNodes.add(f)
|
||||
|
||||
# Change directory to the top of the source
|
||||
# tree to make sure the os's cwd and the cwd of
|
||||
|
@ -249,11 +272,12 @@ def _SConscript(fs, *files, **kw):
|
|||
pass
|
||||
try:
|
||||
try:
|
||||
# _file_ = SCons.Util.to_str(_file_)
|
||||
if Main.print_time:
|
||||
time1 = time.time()
|
||||
exec(compile(_file_.read(), _file_.name, 'exec'),
|
||||
call_stack[-1].globals)
|
||||
scriptdata = _file_.read()
|
||||
scriptname = _file_.name
|
||||
_file_.close()
|
||||
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
|
||||
except SConscriptReturn:
|
||||
pass
|
||||
finally:
|
||||
|
@ -264,8 +288,7 @@ def _SConscript(fs, *files, **kw):
|
|||
if old_file is not None:
|
||||
call_stack[-1].globals.update({__file__:old_file})
|
||||
else:
|
||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning,
|
||||
"Ignoring missing SConscript '%s'" % f.get_internal_path())
|
||||
handle_missing_SConscript(f, kw.get('must_exist', None))
|
||||
|
||||
finally:
|
||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
|
||||
|
@ -369,9 +392,9 @@ class SConsEnvironment(SCons.Environment.Base):
|
|||
something like 3.2b1."""
|
||||
version = version_string.split(' ')[0].split('.')
|
||||
v_major = int(version[0])
|
||||
v_minor = int(re.match('\d+', version[1]).group())
|
||||
v_minor = int(re.match(r'\d+', version[1]).group())
|
||||
if len(version) >= 3:
|
||||
v_revision = int(re.match('\d+', version[2]).group())
|
||||
v_revision = int(re.match(r'\d+', version[2]).group())
|
||||
else:
|
||||
v_revision = 0
|
||||
return v_major, v_minor, v_revision
|
||||
|
@ -391,7 +414,7 @@ class SConsEnvironment(SCons.Environment.Base):
|
|||
except KeyError:
|
||||
raise SCons.Errors.UserError("Invalid SConscript usage - no parameters")
|
||||
|
||||
if not SCons.Util.is_List(dirs):
|
||||
if not is_List(dirs):
|
||||
dirs = [ dirs ]
|
||||
dirs = list(map(str, dirs))
|
||||
|
||||
|
@ -412,13 +435,13 @@ class SConsEnvironment(SCons.Environment.Base):
|
|||
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments")
|
||||
|
||||
if not SCons.Util.is_List(files):
|
||||
if not is_List(files):
|
||||
files = [ files ]
|
||||
|
||||
if kw.get('exports'):
|
||||
exports.extend(self.Split(kw['exports']))
|
||||
|
||||
variant_dir = kw.get('variant_dir') or kw.get('build_dir')
|
||||
variant_dir = kw.get('variant_dir')
|
||||
if variant_dir:
|
||||
if len(files) != 1:
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir")
|
||||
|
@ -523,9 +546,31 @@ class SConsEnvironment(SCons.Environment.Base):
|
|||
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
|
||||
|
||||
def SConscript(self, *ls, **kw):
|
||||
if 'build_dir' in kw:
|
||||
msg = """The build_dir keyword has been deprecated; use the variant_dir keyword instead."""
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg)
|
||||
"""Execute SCons configuration files.
|
||||
|
||||
Parameters:
|
||||
*ls (str or list): configuration file(s) to execute.
|
||||
|
||||
Keyword arguments:
|
||||
dirs (list): execute SConscript in each listed directory.
|
||||
name (str): execute script 'name' (used only with 'dirs').
|
||||
exports (list or dict): locally export variables the
|
||||
called script(s) can import.
|
||||
variant_dir (str): mirror sources needed for the build in
|
||||
a variant directory to allow building in it.
|
||||
duplicate (bool): physically duplicate sources instead of just
|
||||
adjusting paths of derived files (used only with 'variant_dir')
|
||||
(default is True).
|
||||
must_exist (bool): fail if a requested script is missing
|
||||
(default is False, default is deprecated).
|
||||
|
||||
Returns:
|
||||
list of variables returned by the called script
|
||||
|
||||
Raises:
|
||||
UserError: a script is not found and such exceptions are enabled.
|
||||
"""
|
||||
|
||||
def subst_element(x, subst=self.subst):
|
||||
if SCons.Util.is_List(x):
|
||||
x = list(map(subst, x))
|
||||
|
@ -535,15 +580,10 @@ class SConsEnvironment(SCons.Environment.Base):
|
|||
ls = list(map(subst_element, ls))
|
||||
subst_kw = {}
|
||||
for key, val in kw.items():
|
||||
if SCons.Util.is_String(val):
|
||||
if is_String(val):
|
||||
val = self.subst(val)
|
||||
elif SCons.Util.is_List(val):
|
||||
result = []
|
||||
for v in val:
|
||||
if SCons.Util.is_String(v):
|
||||
v = self.subst(v)
|
||||
result.append(v)
|
||||
val = result
|
||||
val = [self.subst(v) if is_String(v) else v for v in val]
|
||||
subst_kw[key] = val
|
||||
|
||||
files, exports = self._get_SConscript_filenames(ls, subst_kw)
|
||||
|
@ -593,7 +633,7 @@ def get_DefaultEnvironmentProxy():
|
|||
_DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env)
|
||||
return _DefaultEnvironmentProxy
|
||||
|
||||
class DefaultEnvironmentCall(object):
|
||||
class DefaultEnvironmentCall:
|
||||
"""A class that implements "global function" calls of
|
||||
Environment methods by fetching the specified method from the
|
||||
DefaultEnvironment's class. Note that this uses an intermediate
|
|
@ -1,18 +1,6 @@
|
|||
"""SCons.Script
|
||||
|
||||
This file implements the main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -32,20 +20,23 @@ it goes here.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Script/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""The main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
"""
|
||||
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
import collections
|
||||
import os
|
||||
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
from io import StringIO
|
||||
|
||||
import sys
|
||||
|
||||
|
@ -69,7 +60,7 @@ if "--debug=memoizer" in _args:
|
|||
import SCons.Warnings
|
||||
try:
|
||||
SCons.Memoize.EnableMemoization()
|
||||
except SCons.Warnings.Warning:
|
||||
except SCons.Warnings.SConsWarning:
|
||||
# Some warning was thrown. Arrange for it to be displayed
|
||||
# or not after warnings are configured.
|
||||
from . import Main
|
||||
|
@ -81,8 +72,8 @@ import SCons.Action
|
|||
import SCons.Builder
|
||||
import SCons.Environment
|
||||
import SCons.Node.FS
|
||||
import SCons.Options
|
||||
import SCons.Platform
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.Scanner
|
||||
import SCons.SConf
|
||||
import SCons.Subst
|
||||
|
@ -134,7 +125,6 @@ GetBuildFailures = Main.GetBuildFailures
|
|||
#profiling = Main.profiling
|
||||
#repositories = Main.repositories
|
||||
|
||||
#
|
||||
from . import SConscript
|
||||
_SConscript = SConscript
|
||||
|
||||
|
@ -150,6 +140,7 @@ Environment = SCons.Environment.Environment
|
|||
#OptParser = SCons.SConsOptions.OptParser
|
||||
FindPathDirs = SCons.Scanner.FindPathDirs
|
||||
Platform = SCons.Platform.Platform
|
||||
Virtualenv = SCons.Platform.virtualenv.Virtualenv
|
||||
Return = _SConscript.Return
|
||||
Scanner = SCons.Scanner.Base
|
||||
Tool = SCons.Tool.Tool
|
||||
|
@ -162,12 +153,6 @@ ListVariable = SCons.Variables.ListVariable
|
|||
PackageVariable = SCons.Variables.PackageVariable
|
||||
PathVariable = SCons.Variables.PathVariable
|
||||
|
||||
# Deprecated names that will go away some day.
|
||||
BoolOption = SCons.Options.BoolOption
|
||||
EnumOption = SCons.Options.EnumOption
|
||||
ListOption = SCons.Options.ListOption
|
||||
PackageOption = SCons.Options.PackageOption
|
||||
PathOption = SCons.Options.PathOption
|
||||
|
||||
# Action factories.
|
||||
Chmod = SCons.Defaults.Chmod
|
||||
|
@ -283,12 +268,24 @@ def HelpFunction(text, append=False):
|
|||
# Will be non-zero if we are reading an SConscript file.
|
||||
sconscript_reading = 0
|
||||
|
||||
#
|
||||
def Variables(files=[], args=ARGUMENTS):
|
||||
_no_missing_sconscript = False
|
||||
_warn_missing_sconscript_deprecated = True
|
||||
|
||||
def set_missing_sconscript_error(flag=1):
|
||||
"""Set behavior on missing file in SConscript() call.
|
||||
|
||||
Returns:
|
||||
previous value
|
||||
"""
|
||||
global _no_missing_sconscript
|
||||
old = _no_missing_sconscript
|
||||
_no_missing_sconscript = flag
|
||||
return old
|
||||
|
||||
|
||||
def Variables(files=None, args=ARGUMENTS):
|
||||
return SCons.Variables.Variables(files, args)
|
||||
|
||||
def Options(files=[], args=ARGUMENTS):
|
||||
return SCons.Options.Options(files, args)
|
||||
|
||||
# The list of global functions to add to the SConscript name space
|
||||
# that end up calling corresponding methods or Builders in the
|
||||
|
@ -311,7 +308,6 @@ GlobalDefaultEnvironmentFunctions = [
|
|||
'AddPreAction',
|
||||
'Alias',
|
||||
'AlwaysBuild',
|
||||
'BuildDir',
|
||||
'CacheDir',
|
||||
'Clean',
|
||||
#The Command() method is handled separately, below.
|
||||
|
@ -342,11 +338,8 @@ GlobalDefaultEnvironmentFunctions = [
|
|||
'Requires',
|
||||
'SConsignFile',
|
||||
'SideEffect',
|
||||
'SourceCode',
|
||||
'SourceSignatures',
|
||||
'Split',
|
||||
'Tag',
|
||||
'TargetSignatures',
|
||||
'Value',
|
||||
'VariantDir',
|
||||
]
|
||||
|
@ -374,7 +367,9 @@ GlobalDefaultBuilders = [
|
|||
'SharedObject',
|
||||
'StaticLibrary',
|
||||
'StaticObject',
|
||||
'Substfile',
|
||||
'Tar',
|
||||
'Textfile',
|
||||
'TypeLibrary',
|
||||
'Zip',
|
||||
'Package',
|
|
@ -1,11 +1,6 @@
|
|||
"""SCons.Subst
|
||||
|
||||
SCons string substitution.
|
||||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -26,28 +21,30 @@ SCons string substitution.
|
|||
# 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/Subst.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""SCons string substitution."""
|
||||
|
||||
import collections
|
||||
import re
|
||||
|
||||
from inspect import signature
|
||||
import SCons.Errors
|
||||
|
||||
from SCons.Util import is_String, is_Sequence
|
||||
|
||||
# Indexed by the SUBST_* constants below.
|
||||
_strconv = [SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_signature]
|
||||
|
||||
|
||||
_strconv = [
|
||||
SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_signature,
|
||||
]
|
||||
|
||||
AllowableExceptions = (IndexError, NameError)
|
||||
|
||||
|
||||
def SetAllowableExceptions(*excepts):
|
||||
global AllowableExceptions
|
||||
AllowableExceptions = [_f for _f in excepts if _f]
|
||||
|
||||
|
||||
def raise_exception(exception, target, s):
|
||||
name = exception.__class__.__name__
|
||||
msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s)
|
||||
|
@ -57,8 +54,7 @@ def raise_exception(exception, target, s):
|
|||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
|
||||
|
||||
class Literal(object):
|
||||
class Literal:
|
||||
"""A wrapper for a string. If you use this object wrapped
|
||||
around a string, then it will be interpreted as literal.
|
||||
When passed to the command interpreter, all special
|
||||
|
@ -86,7 +82,10 @@ class Literal(object):
|
|||
def __neq__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
class SpecialAttrWrapper(object):
|
||||
def __hash__(self):
|
||||
return hash(self.lstr)
|
||||
|
||||
class SpecialAttrWrapper:
|
||||
"""This is a wrapper for what we call a 'Node special attribute.'
|
||||
This is any of the attributes of a Node that we can reference from
|
||||
Environment variable substitution, such as $TARGET.abspath or
|
||||
|
@ -168,7 +167,7 @@ def escape_list(mylist, escape_func):
|
|||
return e(escape_func)
|
||||
return list(map(escape, mylist))
|
||||
|
||||
class NLWrapper(object):
|
||||
class NLWrapper:
|
||||
"""A wrapper class that delays turning a list of sources or targets
|
||||
into a NodeList until it's needed. The specified function supplied
|
||||
when the object is initialized is responsible for turning raw nodes
|
||||
|
@ -229,7 +228,7 @@ class Targets_or_Sources(collections.UserList):
|
|||
nl = self.nl._create_nodelist()
|
||||
return repr(nl)
|
||||
|
||||
class Target_or_Source(object):
|
||||
class Target_or_Source:
|
||||
"""A class that implements $TARGET or $SOURCE expansions by in turn
|
||||
wrapping a NLWrapper. This class handles the different methods used
|
||||
to access an individual proxy Node, calling the NLWrapper to create
|
||||
|
@ -328,6 +327,407 @@ def subst_dict(target, source):
|
|||
|
||||
return dict
|
||||
|
||||
|
||||
class StringSubber:
|
||||
"""A class to construct the results of a scons_subst() call.
|
||||
|
||||
This binds a specific construction environment, mode, target and
|
||||
source with two methods (substitute() and expand()) that handle
|
||||
the expansion.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
def expand(self, s, lvars):
|
||||
"""Expand a single "token" as necessary, returning an
|
||||
appropriate string containing the expansion.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
return s
|
||||
if s0 != '$':
|
||||
return s
|
||||
if s1 == '$':
|
||||
# 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 '()':
|
||||
return s
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or '.' in key:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
|
||||
# Store for error messages if we fail to expand the
|
||||
# value
|
||||
old_s = s
|
||||
s = None
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
else:
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return ''
|
||||
raise_exception(e, lvars['TARGETS'], old_s)
|
||||
|
||||
if s is None and NameError not in AllowableExceptions:
|
||||
raise_exception(NameError(key), lvars['TARGETS'], old_s)
|
||||
elif s is None:
|
||||
return ''
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
#
|
||||
# This could potentially be optimized by only
|
||||
# copying lvars when s contains more expansions,
|
||||
# but lvars is usually supposed to be pretty
|
||||
# small, and deeply nested variable expansions
|
||||
# are probably more the exception than the norm,
|
||||
# so it should be tolerable for now.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
return self.substitute(s, lv)
|
||||
elif is_Sequence(s):
|
||||
def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
|
||||
return conv(substitute(l, lvars))
|
||||
return list(map(func, s))
|
||||
elif callable(s):
|
||||
# SCons has the unusual Null class where any __getattr__ call returns it's self,
|
||||
# which does not work the signature module, and the Null class returns an empty
|
||||
# string if called on, so we make an exception in this condition for Null class
|
||||
if (isinstance(s, SCons.Util.Null) or
|
||||
set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])):
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
else:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
return s
|
||||
s = self.conv(s)
|
||||
return self.substitute(s, lvars)
|
||||
elif s is None:
|
||||
return ''
|
||||
else:
|
||||
return s
|
||||
|
||||
def substitute(self, args, lvars):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
try:
|
||||
def sub_match(match):
|
||||
return self.conv(self.expand(match.group(1), lvars))
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
except TypeError:
|
||||
# If the internal conversion routine doesn't return
|
||||
# strings (it could be overridden to return Nodes, for
|
||||
# example), then the 1.5.2 re module will throw this
|
||||
# exception. Back off to a slower, general-purpose
|
||||
# algorithm that works for all data types.
|
||||
args = _separate_args.findall(args)
|
||||
result = []
|
||||
for a in args:
|
||||
result.append(self.conv(self.expand(a, lvars)))
|
||||
if len(result) == 1:
|
||||
result = result[0]
|
||||
else:
|
||||
result = ''.join(map(str, result))
|
||||
return result
|
||||
else:
|
||||
return self.expand(args, lvars)
|
||||
|
||||
|
||||
class ListSubber(collections.UserList):
|
||||
"""A class to construct the results of a scons_subst_list() call.
|
||||
|
||||
Like StringSubber, this class binds a specific construction
|
||||
environment, mode, target and source with two methods
|
||||
(substitute() and expand()) that handle the expansion.
|
||||
|
||||
In addition, however, this class is used to track the state of
|
||||
the result(s) we're gathering so we can do the appropriate thing
|
||||
whenever we have to append another word to the result--start a new
|
||||
line, start a new word, append to the current word, etc. We do
|
||||
this by setting the "append" attribute to the right method so
|
||||
that our wrapper methods only need ever call ListSubber.append(),
|
||||
and the rest of the object takes care of doing the right thing
|
||||
internally.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
collections.UserList.__init__(self, [])
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
if self.mode == SUBST_RAW:
|
||||
self.add_strip = lambda x: self.append(x)
|
||||
else:
|
||||
self.add_strip = lambda x: None
|
||||
self.in_strip = None
|
||||
self.next_line()
|
||||
|
||||
def expanded(self, s):
|
||||
"""Determines if the string s requires further expansion.
|
||||
|
||||
Due to the implementation of ListSubber expand will call
|
||||
itself 2 additional times for an already expanded string. This
|
||||
method is used to determine if a string is already fully
|
||||
expanded and if so exit the loop early to prevent these
|
||||
recursive calls.
|
||||
"""
|
||||
if not is_String(s) or isinstance(s, CmdStringHolder):
|
||||
return False
|
||||
|
||||
s = str(s) # in case it's a UserString
|
||||
return _separate_args.findall(s) is None
|
||||
|
||||
def expand(self, s, lvars, within_list):
|
||||
"""Expand a single "token" as necessary, appending the
|
||||
expansion to the current result.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
self.append(s)
|
||||
return
|
||||
if s0 != '$':
|
||||
self.append(s)
|
||||
return
|
||||
if s1 == '$':
|
||||
self.append('$')
|
||||
elif s1 == '(':
|
||||
self.open_strip('$(')
|
||||
elif s1 == ')':
|
||||
self.close_strip('$)')
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or key.find('.') >= 0:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
|
||||
# Store for error messages if we fail to expand the
|
||||
# value
|
||||
old_s = s
|
||||
s = None
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
else:
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return
|
||||
raise_exception(e, lvars['TARGETS'], old_s)
|
||||
|
||||
if s is None and NameError not in AllowableExceptions:
|
||||
raise_exception(NameError(), lvars['TARGETS'], old_s)
|
||||
elif s is None:
|
||||
return
|
||||
|
||||
# If the string is already full expanded there's no
|
||||
# need to continue recursion.
|
||||
if self.expanded(s):
|
||||
self.append(s)
|
||||
return
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
self.substitute(s, lv, 0)
|
||||
self.this_word()
|
||||
elif is_Sequence(s):
|
||||
for a in s:
|
||||
self.substitute(a, lvars, 1)
|
||||
self.next_word()
|
||||
elif callable(s):
|
||||
# SCons has the unusual Null class where any __getattr__ call returns it's self,
|
||||
# which does not work the signature module, and the Null class returns an empty
|
||||
# string if called on, so we make an exception in this condition for Null class
|
||||
if (isinstance(s, SCons.Util.Null) or
|
||||
set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])):
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
else:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
self.append(s)
|
||||
return
|
||||
s = self.conv(s)
|
||||
self.substitute(s, lvars, within_list)
|
||||
elif s is None:
|
||||
self.this_word()
|
||||
else:
|
||||
self.append(s)
|
||||
|
||||
def substitute(self, args, lvars, within_list):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
args = _separate_args.findall(args)
|
||||
for a in args:
|
||||
if a[0] in ' \t\n\r\f\v':
|
||||
if '\n' in a:
|
||||
self.next_line()
|
||||
elif within_list:
|
||||
self.append(a)
|
||||
else:
|
||||
self.next_word()
|
||||
else:
|
||||
self.expand(a, lvars, within_list)
|
||||
else:
|
||||
self.expand(args, lvars, within_list)
|
||||
|
||||
def next_line(self):
|
||||
"""Arrange for the next word to start a new line. This
|
||||
is like starting a new word, except that we have to append
|
||||
another line to the result."""
|
||||
collections.UserList.append(self, [])
|
||||
self.next_word()
|
||||
|
||||
def this_word(self):
|
||||
"""Arrange for the next word to append to the end of the
|
||||
current last word in the result."""
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def next_word(self):
|
||||
"""Arrange for the next word to start a new word."""
|
||||
self.append = self.add_new_word
|
||||
|
||||
def add_to_current_word(self, x):
|
||||
"""Append the string x to the end of the current last word
|
||||
in the result. If that is not possible, then just add
|
||||
it as a new word. Make sure the entire concatenated string
|
||||
inherits the object attributes of x (in particular, the
|
||||
escape function) by wrapping it as CmdStringHolder."""
|
||||
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
try:
|
||||
current_word = self[-1][-1]
|
||||
except IndexError:
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
# All right, this is a hack and it should probably
|
||||
# be refactored out of existence in the future.
|
||||
# The issue is that we want to smoosh words together
|
||||
# and make one file name that gets escaped if
|
||||
# we're expanding something like foo$EXTENSION,
|
||||
# but we don't want to smoosh them together if
|
||||
# it's something like >$TARGET, because then we'll
|
||||
# treat the '>' like it's part of the file name.
|
||||
# So for now, just hard-code looking for the special
|
||||
# command-line redirection characters...
|
||||
try:
|
||||
last_char = str(current_word)[-1]
|
||||
except IndexError:
|
||||
last_char = '\0'
|
||||
if last_char in '<>|':
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
y = current_word + x
|
||||
|
||||
# We used to treat a word appended to a literal
|
||||
# as a literal itself, but this caused problems
|
||||
# with interpreting quotes around space-separated
|
||||
# targets on command lines. Removing this makes
|
||||
# none of the "substantive" end-to-end tests fail,
|
||||
# so we'll take this out but leave it commented
|
||||
# for now in case there's a problem not covered
|
||||
# by the test cases and we need to resurrect this.
|
||||
#literal1 = self.literal(self[-1][-1])
|
||||
#literal2 = self.literal(x)
|
||||
y = self.conv(y)
|
||||
if is_String(y):
|
||||
#y = CmdStringHolder(y, literal1 or literal2)
|
||||
y = CmdStringHolder(y, None)
|
||||
self[-1][-1] = y
|
||||
|
||||
def add_new_word(self, x):
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
literal = self.literal(x)
|
||||
x = self.conv(x)
|
||||
if is_String(x):
|
||||
x = CmdStringHolder(x, literal)
|
||||
self[-1].append(x)
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def literal(self, x):
|
||||
try:
|
||||
l = x.is_literal
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
return l()
|
||||
|
||||
def open_strip(self, x):
|
||||
"""Handle the "open strip" $( token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = 1
|
||||
|
||||
def close_strip(self, x):
|
||||
"""Handle the "close strip" $) token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = None
|
||||
|
||||
|
||||
# Constants for the "mode" parameter to scons_subst_list() and
|
||||
# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
|
||||
# gives a command line suitable for passing to a shell. SUBST_SIG
|
||||
|
@ -347,7 +747,7 @@ _rm_split = re.compile(r'(?<!\$)(\$[()])')
|
|||
_regex_remove = [ _rm, None, _rm_split ]
|
||||
|
||||
def _rm_list(list):
|
||||
return [l for l in list if not l in ('$(', '$)')]
|
||||
return [l for l in list if l not in ('$(', '$)')]
|
||||
|
||||
def _remove_list(list):
|
||||
result = []
|
||||
|
@ -391,7 +791,7 @@ _list_remove = [ _rm_list, None, _remove_list ]
|
|||
#
|
||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s\$]+|\$)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str)
|
||||
|
||||
# This regular expression is used to replace strings of multiple white
|
||||
# space characters in the string result from the scons_subst() function.
|
||||
|
@ -406,139 +806,9 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
|
|||
handles separating command lines into lists of arguments, so see
|
||||
that function if that's what you're looking for.
|
||||
"""
|
||||
if isinstance(strSubst, str) and strSubst.find('$') < 0:
|
||||
if (isinstance(strSubst, str) and '$' not in strSubst) or isinstance(strSubst, CmdStringHolder):
|
||||
return strSubst
|
||||
|
||||
class StringSubber(object):
|
||||
"""A class to construct the results of a scons_subst() call.
|
||||
|
||||
This binds a specific construction environment, mode, target and
|
||||
source with two methods (substitute() and expand()) that handle
|
||||
the expansion.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
def expand(self, s, lvars):
|
||||
"""Expand a single "token" as necessary, returning an
|
||||
appropriate string containing the expansion.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
return s
|
||||
if s0 != '$':
|
||||
return s
|
||||
if s1 == '$':
|
||||
# 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 '()':
|
||||
return s
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or '.' in key:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return ''
|
||||
raise_exception(e, lvars['TARGETS'], s)
|
||||
else:
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
elif not NameError in AllowableExceptions:
|
||||
raise_exception(NameError(key), lvars['TARGETS'], s)
|
||||
else:
|
||||
return ''
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
#
|
||||
# This could potentially be optimized by only
|
||||
# copying lvars when s contains more expansions,
|
||||
# but lvars is usually supposed to be pretty
|
||||
# small, and deeply nested variable expansions
|
||||
# are probably more the exception than the norm,
|
||||
# so it should be tolerable for now.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
return self.substitute(s, lv)
|
||||
elif is_Sequence(s):
|
||||
def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
|
||||
return conv(substitute(l, lvars))
|
||||
return list(map(func, s))
|
||||
elif callable(s):
|
||||
try:
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
except TypeError:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
return s
|
||||
s = self.conv(s)
|
||||
return self.substitute(s, lvars)
|
||||
elif s is None:
|
||||
return ''
|
||||
else:
|
||||
return s
|
||||
|
||||
def substitute(self, args, lvars):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
try:
|
||||
def sub_match(match):
|
||||
return self.conv(self.expand(match.group(1), lvars))
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
except TypeError:
|
||||
# If the internal conversion routine doesn't return
|
||||
# strings (it could be overridden to return Nodes, for
|
||||
# example), then the 1.5.2 re module will throw this
|
||||
# exception. Back off to a slower, general-purpose
|
||||
# algorithm that works for all data types.
|
||||
args = _separate_args.findall(args)
|
||||
result = []
|
||||
for a in args:
|
||||
result.append(self.conv(self.expand(a, lvars)))
|
||||
if len(result) == 1:
|
||||
result = result[0]
|
||||
else:
|
||||
result = ''.join(map(str, result))
|
||||
return result
|
||||
else:
|
||||
return self.expand(args, lvars)
|
||||
|
||||
if conv is None:
|
||||
conv = _strconv[mode]
|
||||
|
||||
|
@ -613,233 +883,6 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv
|
|||
substitutions within strings, so see that function instead
|
||||
if that's what you're looking for.
|
||||
"""
|
||||
class ListSubber(collections.UserList):
|
||||
"""A class to construct the results of a scons_subst_list() call.
|
||||
|
||||
Like StringSubber, this class binds a specific construction
|
||||
environment, mode, target and source with two methods
|
||||
(substitute() and expand()) that handle the expansion.
|
||||
|
||||
In addition, however, this class is used to track the state of
|
||||
the result(s) we're gathering so we can do the appropriate thing
|
||||
whenever we have to append another word to the result--start a new
|
||||
line, start a new word, append to the current word, etc. We do
|
||||
this by setting the "append" attribute to the right method so
|
||||
that our wrapper methods only need ever call ListSubber.append(),
|
||||
and the rest of the object takes care of doing the right thing
|
||||
internally.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
collections.UserList.__init__(self, [])
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
if self.mode == SUBST_RAW:
|
||||
self.add_strip = lambda x: self.append(x)
|
||||
else:
|
||||
self.add_strip = lambda x: None
|
||||
self.in_strip = None
|
||||
self.next_line()
|
||||
|
||||
def expand(self, s, lvars, within_list):
|
||||
"""Expand a single "token" as necessary, appending the
|
||||
expansion to the current result.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
self.append(s)
|
||||
return
|
||||
if s0 != '$':
|
||||
self.append(s)
|
||||
return
|
||||
if s1 == '$':
|
||||
self.append('$')
|
||||
elif s1 == '(':
|
||||
self.open_strip('$(')
|
||||
elif s1 == ')':
|
||||
self.close_strip('$)')
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or key.find('.') >= 0:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return
|
||||
raise_exception(e, lvars['TARGETS'], s)
|
||||
else:
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
elif not NameError in AllowableExceptions:
|
||||
raise_exception(NameError(), lvars['TARGETS'], s)
|
||||
else:
|
||||
return
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
self.substitute(s, lv, 0)
|
||||
self.this_word()
|
||||
elif is_Sequence(s):
|
||||
for a in s:
|
||||
self.substitute(a, lvars, 1)
|
||||
self.next_word()
|
||||
elif callable(s):
|
||||
try:
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
except TypeError:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
self.append(s)
|
||||
return
|
||||
s = self.conv(s)
|
||||
self.substitute(s, lvars, within_list)
|
||||
elif s is None:
|
||||
self.this_word()
|
||||
else:
|
||||
self.append(s)
|
||||
|
||||
def substitute(self, args, lvars, within_list):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
args = _separate_args.findall(args)
|
||||
for a in args:
|
||||
if a[0] in ' \t\n\r\f\v':
|
||||
if '\n' in a:
|
||||
self.next_line()
|
||||
elif within_list:
|
||||
self.append(a)
|
||||
else:
|
||||
self.next_word()
|
||||
else:
|
||||
self.expand(a, lvars, within_list)
|
||||
else:
|
||||
self.expand(args, lvars, within_list)
|
||||
|
||||
def next_line(self):
|
||||
"""Arrange for the next word to start a new line. This
|
||||
is like starting a new word, except that we have to append
|
||||
another line to the result."""
|
||||
collections.UserList.append(self, [])
|
||||
self.next_word()
|
||||
|
||||
def this_word(self):
|
||||
"""Arrange for the next word to append to the end of the
|
||||
current last word in the result."""
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def next_word(self):
|
||||
"""Arrange for the next word to start a new word."""
|
||||
self.append = self.add_new_word
|
||||
|
||||
def add_to_current_word(self, x):
|
||||
"""Append the string x to the end of the current last word
|
||||
in the result. If that is not possible, then just add
|
||||
it as a new word. Make sure the entire concatenated string
|
||||
inherits the object attributes of x (in particular, the
|
||||
escape function) by wrapping it as CmdStringHolder."""
|
||||
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
try:
|
||||
current_word = self[-1][-1]
|
||||
except IndexError:
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
# All right, this is a hack and it should probably
|
||||
# be refactored out of existence in the future.
|
||||
# The issue is that we want to smoosh words together
|
||||
# and make one file name that gets escaped if
|
||||
# we're expanding something like foo$EXTENSION,
|
||||
# but we don't want to smoosh them together if
|
||||
# it's something like >$TARGET, because then we'll
|
||||
# treat the '>' like it's part of the file name.
|
||||
# So for now, just hard-code looking for the special
|
||||
# command-line redirection characters...
|
||||
try:
|
||||
last_char = str(current_word)[-1]
|
||||
except IndexError:
|
||||
last_char = '\0'
|
||||
if last_char in '<>|':
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
y = current_word + x
|
||||
|
||||
# We used to treat a word appended to a literal
|
||||
# as a literal itself, but this caused problems
|
||||
# with interpreting quotes around space-separated
|
||||
# targets on command lines. Removing this makes
|
||||
# none of the "substantive" end-to-end tests fail,
|
||||
# so we'll take this out but leave it commented
|
||||
# for now in case there's a problem not covered
|
||||
# by the test cases and we need to resurrect this.
|
||||
#literal1 = self.literal(self[-1][-1])
|
||||
#literal2 = self.literal(x)
|
||||
y = self.conv(y)
|
||||
if is_String(y):
|
||||
#y = CmdStringHolder(y, literal1 or literal2)
|
||||
y = CmdStringHolder(y, None)
|
||||
self[-1][-1] = y
|
||||
|
||||
def add_new_word(self, x):
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
literal = self.literal(x)
|
||||
x = self.conv(x)
|
||||
if is_String(x):
|
||||
x = CmdStringHolder(x, literal)
|
||||
self[-1].append(x)
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def literal(self, x):
|
||||
try:
|
||||
l = x.is_literal
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
return l()
|
||||
|
||||
def open_strip(self, x):
|
||||
"""Handle the "open strip" $( token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = 1
|
||||
|
||||
def close_strip(self, x):
|
||||
"""Handle the "close strip" $) token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = None
|
||||
|
||||
if conv is None:
|
||||
conv = _strconv[mode]
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -20,46 +21,35 @@
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from __future__ import print_function
|
||||
"""Generic Taskmaster module for the SCons build engine.
|
||||
|
||||
import sys
|
||||
This module contains the primary interface(s) between a wrapping user
|
||||
interface and the SCons build engine. There are two key classes here:
|
||||
|
||||
__doc__ = """
|
||||
Generic Taskmaster module for the SCons build engine.
|
||||
=====================================================
|
||||
Taskmaster
|
||||
This is the main engine for walking the dependency graph and
|
||||
calling things to decide what does or doesn't need to be built.
|
||||
|
||||
This module contains the primary interface(s) between a wrapping user
|
||||
interface and the SCons build engine. There are two key classes here:
|
||||
Task
|
||||
This is the base class for allowing a wrapping interface to
|
||||
decide what does or doesn't actually need to be done. The
|
||||
intention is for a wrapping interface to subclass this as
|
||||
appropriate for different types of behavior it may need.
|
||||
|
||||
Taskmaster
|
||||
----------
|
||||
This is the main engine for walking the dependency graph and
|
||||
calling things to decide what does or doesn't need to be built.
|
||||
The canonical example is the SCons native Python interface,
|
||||
which has Task subclasses that handle its specific behavior,
|
||||
like printing "'foo' is up to date" when a top-level target
|
||||
doesn't need to be built, and handling the -c option by removing
|
||||
targets as its "build" action. There is also a separate subclass
|
||||
for suppressing this output when the -q option is used.
|
||||
|
||||
Task
|
||||
----
|
||||
This is the base class for allowing a wrapping interface to
|
||||
decide what does or doesn't actually need to be done. The
|
||||
intention is for a wrapping interface to subclass this as
|
||||
appropriate for different types of behavior it may need.
|
||||
|
||||
The canonical example is the SCons native Python interface,
|
||||
which has Task subclasses that handle its specific behavior,
|
||||
like printing "'foo' is up to date" when a top-level target
|
||||
doesn't need to be built, and handling the -c option by removing
|
||||
targets as its "build" action. There is also a separate subclass
|
||||
for suppressing this output when the -q option is used.
|
||||
|
||||
The Taskmaster instantiates a Task object for each (set of)
|
||||
target(s) that it decides need to be evaluated and/or built.
|
||||
The Taskmaster instantiates a Task object for each (set of)
|
||||
target(s) that it decides need to be evaluated and/or built.
|
||||
"""
|
||||
|
||||
__revision__ = "src/engine/SCons/Taskmaster.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
from itertools import chain
|
||||
import operator
|
||||
import sys
|
||||
import traceback
|
||||
from abc import ABC, abstractmethod
|
||||
from itertools import chain
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
|
@ -81,7 +71,7 @@ print_prepare = 0 # set by option --debug=prepare
|
|||
|
||||
CollectStats = None
|
||||
|
||||
class Stats(object):
|
||||
class Stats:
|
||||
"""
|
||||
A simple class for holding statistics about the disposition of a
|
||||
Node by the Taskmaster. If we're collecting statistics, each Node
|
||||
|
@ -117,10 +107,8 @@ def dump_stats():
|
|||
print((fmt % n.attributes.stats.__dict__) + str(n))
|
||||
|
||||
|
||||
|
||||
class Task(object):
|
||||
"""
|
||||
Default SCons build engine task.
|
||||
class Task(ABC):
|
||||
""" SCons build engine abstract task class.
|
||||
|
||||
This controls the interaction of the actual building of node
|
||||
and the rest of the engine.
|
||||
|
@ -171,7 +159,7 @@ class Task(object):
|
|||
"""
|
||||
global print_prepare
|
||||
T = self.tm.trace
|
||||
if T: T.write(self.trace_message(u'Task.prepare()', self.node))
|
||||
if T: T.write(self.trace_message('Task.prepare()', self.node))
|
||||
|
||||
# Now that it's the appropriate time, give the TaskMaster a
|
||||
# chance to raise any exceptions it encountered while preparing
|
||||
|
@ -212,17 +200,9 @@ class Task(object):
|
|||
"""
|
||||
return self.node
|
||||
|
||||
@abstractmethod
|
||||
def needs_execute(self):
|
||||
# TODO(deprecate): "return True" is the old default behavior;
|
||||
# change it to NotImplementedError (after running through the
|
||||
# Deprecation Cycle) so the desired behavior is explicitly
|
||||
# determined by which concrete subclass is used.
|
||||
#raise NotImplementedError
|
||||
msg = ('Taskmaster.Task is an abstract base class; instead of\n'
|
||||
'\tusing it directly, '
|
||||
'derive from it and override the abstract methods.')
|
||||
SCons.Warnings.warn(SCons.Warnings.TaskmasterNeedsExecuteWarning, msg)
|
||||
return True
|
||||
return
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
|
@ -233,7 +213,7 @@ class Task(object):
|
|||
prepare(), executed() or failed().
|
||||
"""
|
||||
T = self.tm.trace
|
||||
if T: T.write(self.trace_message(u'Task.execute()', self.node))
|
||||
if T: T.write(self.trace_message('Task.execute()', self.node))
|
||||
|
||||
try:
|
||||
cached_targets = []
|
||||
|
@ -399,7 +379,7 @@ class Task(object):
|
|||
"""
|
||||
global print_prepare
|
||||
T = self.tm.trace
|
||||
if T: T.write(self.trace_message(u'Task.make_ready_current()',
|
||||
if T: T.write(self.trace_message('Task.make_ready_current()',
|
||||
self.node))
|
||||
|
||||
self.out_of_date = []
|
||||
|
@ -447,7 +427,7 @@ class Task(object):
|
|||
that can be put back on the candidates list.
|
||||
"""
|
||||
T = self.tm.trace
|
||||
if T: T.write(self.trace_message(u'Task.postprocess()', self.node))
|
||||
if T: T.write(self.trace_message('Task.postprocess()', self.node))
|
||||
|
||||
# We may have built multiple targets, some of which may have
|
||||
# common parents waiting for this build. Count up how many
|
||||
|
@ -464,27 +444,36 @@ class Task(object):
|
|||
# A node can only be in the pending_children set if it has
|
||||
# some waiting_parents.
|
||||
if t.waiting_parents:
|
||||
if T: T.write(self.trace_message(u'Task.postprocess()',
|
||||
if T: T.write(self.trace_message('Task.postprocess()',
|
||||
t,
|
||||
'removing'))
|
||||
pending_children.discard(t)
|
||||
for p in t.waiting_parents:
|
||||
parents[p] = parents.get(p, 0) + 1
|
||||
t.waiting_parents = set()
|
||||
|
||||
for t in targets:
|
||||
if t.side_effects is not None:
|
||||
for s in t.side_effects:
|
||||
if s.get_state() == NODE_EXECUTING:
|
||||
s.set_state(NODE_NO_STATE)
|
||||
|
||||
# The side-effects may have been transferred to
|
||||
# NODE_NO_STATE by executed_with{,out}_callbacks, but was
|
||||
# not taken out of the waiting parents/pending children
|
||||
# data structures. Check for that now.
|
||||
if s.get_state() == NODE_NO_STATE and s.waiting_parents:
|
||||
pending_children.discard(s)
|
||||
for p in s.waiting_parents:
|
||||
parents[p] = parents.get(p, 0) + 1
|
||||
s.waiting_parents = set()
|
||||
for p in s.waiting_s_e:
|
||||
if p.ref_count == 0:
|
||||
self.tm.candidates.append(p)
|
||||
|
||||
for p, subtract in parents.items():
|
||||
p.ref_count = p.ref_count - subtract
|
||||
if T: T.write(self.trace_message(u'Task.postprocess()',
|
||||
if T: T.write(self.trace_message('Task.postprocess()',
|
||||
p,
|
||||
'adjusted parent ref count'))
|
||||
if p.ref_count == 0:
|
||||
|
@ -542,19 +531,16 @@ class Task(object):
|
|||
try:
|
||||
exc_type, exc_value, exc_traceback = exc
|
||||
except ValueError:
|
||||
exc_type, exc_value = exc
|
||||
exc_type, exc_value = exc # pylint: disable=unbalanced-tuple-unpacking
|
||||
exc_traceback = None
|
||||
|
||||
# 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)")
|
||||
if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'):
|
||||
# If exc_value is an exception, then just reraise
|
||||
raise exc_value.with_traceback(exc_traceback)
|
||||
else:
|
||||
# else we'll create an exception using the value and raise that
|
||||
raise exc_type(exc_value).with_traceback(exc_traceback)
|
||||
|
||||
|
||||
# raise e.__class__, e.__class__(e), sys.exc_info()[2]
|
||||
|
@ -573,7 +559,7 @@ class AlwaysTask(Task):
|
|||
dependencies) can use this as follows:
|
||||
|
||||
class MyTaskSubclass(SCons.Taskmaster.Task):
|
||||
needs_execute = SCons.Taskmaster.Task.execute_always
|
||||
needs_execute = SCons.Taskmaster.AlwaysTask.needs_execute
|
||||
"""
|
||||
return True
|
||||
|
||||
|
@ -601,7 +587,7 @@ def find_cycle(stack, visited):
|
|||
return None
|
||||
|
||||
|
||||
class Taskmaster(object):
|
||||
class Taskmaster:
|
||||
"""
|
||||
The Taskmaster for walking the dependency DAG.
|
||||
"""
|
||||
|
@ -783,12 +769,12 @@ class Taskmaster(object):
|
|||
self.ready_exc = None
|
||||
|
||||
T = self.trace
|
||||
if T: T.write(SCons.Util.UnicodeType('\n') + self.trace_message('Looking for a node to evaluate'))
|
||||
if T: T.write('\n' + self.trace_message('Looking for a node to evaluate'))
|
||||
|
||||
while True:
|
||||
node = self.next_candidate()
|
||||
if node is None:
|
||||
if T: T.write(self.trace_message('No candidate anymore.') + u'\n')
|
||||
if T: T.write(self.trace_message('No candidate anymore.') + '\n')
|
||||
return None
|
||||
|
||||
node = node.disambiguate()
|
||||
|
@ -811,7 +797,7 @@ class Taskmaster(object):
|
|||
else:
|
||||
S = None
|
||||
|
||||
if T: T.write(self.trace_message(u' Considering node %s and its children:' % self.trace_node(node)))
|
||||
if T: T.write(self.trace_message(' Considering node %s and its children:' % self.trace_node(node)))
|
||||
|
||||
if state == NODE_NO_STATE:
|
||||
# Mark this node as being on the execution stack:
|
||||
|
@ -819,7 +805,7 @@ class Taskmaster(object):
|
|||
elif state > NODE_PENDING:
|
||||
# Skip this node if it has already been evaluated:
|
||||
if S: S.already_handled = S.already_handled + 1
|
||||
if T: T.write(self.trace_message(u' already handled (executed)'))
|
||||
if T: T.write(self.trace_message(' already handled (executed)'))
|
||||
continue
|
||||
|
||||
executor = node.get_executor()
|
||||
|
@ -850,7 +836,7 @@ class Taskmaster(object):
|
|||
for child in chain(executor.get_all_prerequisites(), children):
|
||||
childstate = child.get_state()
|
||||
|
||||
if T: T.write(self.trace_message(u' ' + self.trace_node(child)))
|
||||
if T: T.write(self.trace_message(' ' + self.trace_node(child)))
|
||||
|
||||
if childstate == NODE_NO_STATE:
|
||||
children_not_visited.append(child)
|
||||
|
@ -865,8 +851,10 @@ class Taskmaster(object):
|
|||
# These nodes have not even been visited yet. Add
|
||||
# them to the list so that on some next pass we can
|
||||
# take a stab at evaluating them (or their children).
|
||||
children_not_visited.reverse()
|
||||
self.candidates.extend(self.order(children_not_visited))
|
||||
if children_not_visited:
|
||||
if len(children_not_visited) > 1:
|
||||
children_not_visited.reverse()
|
||||
self.candidates.extend(self.order(children_not_visited))
|
||||
|
||||
# if T and children_not_visited:
|
||||
# T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited)))
|
||||
|
@ -909,7 +897,7 @@ class Taskmaster(object):
|
|||
# count so we can be put back on the list for
|
||||
# re-evaluation when they've all finished.
|
||||
node.ref_count = node.ref_count + child.add_to_waiting_parents(node)
|
||||
if T: T.write(self.trace_message(u' adjusted ref count: %s, child %s' %
|
||||
if T: T.write(self.trace_message(' adjusted ref count: %s, child %s' %
|
||||
(self.trace_node(node), repr(str(child)))))
|
||||
|
||||
if T:
|
||||
|
@ -935,7 +923,7 @@ class Taskmaster(object):
|
|||
# The default when we've gotten through all of the checks above:
|
||||
# this node is ready to be built.
|
||||
if S: S.build = S.build + 1
|
||||
if T: T.write(self.trace_message(u'Evaluating %s\n' %
|
||||
if T: T.write(self.trace_message('Evaluating %s\n' %
|
||||
self.trace_node(node)))
|
||||
|
||||
# For debugging only:
|
|
@ -10,7 +10,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -32,7 +32,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/386asm.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from SCons.Tool.PharLapCommon import addPharLapPaths
|
||||
import SCons.Util
|
|
@ -1,15 +1,6 @@
|
|||
from __future__ import print_function
|
||||
|
||||
"""SCons.Tool.DCommon
|
||||
|
||||
Common code for the various D tools.
|
||||
|
||||
Coded by Russel Winder (russel@winder.org.uk)
|
||||
2012-09-06
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -29,9 +20,14 @@ Coded by Russel Winder (russel@winder.org.uk)
|
|||
# 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/DCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
"""SCons.Tool.DCommon
|
||||
|
||||
Common code for the various D tools.
|
||||
|
||||
Coded by Russel Winder (russel@winder.org.uk)
|
||||
2012-09-06
|
||||
"""
|
||||
|
||||
import os.path
|
||||
|
||||
|
@ -61,7 +57,6 @@ def allAtOnceEmitter(target, source, env):
|
|||
env.Clean(target[0], str(target[0]) + '.o')
|
||||
return target, source
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
|
@ -4,8 +4,9 @@ Stuff for processing Fortran, common to all fortran dialects.
|
|||
|
||||
"""
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -25,16 +26,11 @@ Stuff for processing Fortran, common to all fortran dialects.
|
|||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/FortranCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import re
|
||||
import os.path
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Defaults
|
||||
import SCons.Scanner.Fortran
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
@ -64,7 +60,8 @@ def _fortranEmitter(target, source, env):
|
|||
if not node.exists() and not node.is_derived():
|
||||
print("Could not locate " + str(node.name))
|
||||
return ([], [])
|
||||
mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
|
||||
# This has to match the def_regex in the Fortran scanner
|
||||
mod_regex = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\w+)"""
|
||||
cre = re.compile(mod_regex,re.M)
|
||||
# Retrieve all USE'd module names
|
||||
modules = cre.findall(node.get_text_contents())
|
||||
|
@ -79,10 +76,12 @@ def _fortranEmitter(target, source, env):
|
|||
return (target, source)
|
||||
|
||||
def FortranEmitter(target, source, env):
|
||||
import SCons.Defaults
|
||||
target, source = _fortranEmitter(target, source, env)
|
||||
return SCons.Defaults.StaticObjectEmitter(target, source, env)
|
||||
|
||||
def ShFortranEmitter(target, source, env):
|
||||
import SCons.Defaults
|
||||
target, source = _fortranEmitter(target, source, env)
|
||||
return SCons.Defaults.SharedObjectEmitter(target, source, env)
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
Used by several tools of `gettext` toolset.
|
||||
"""
|
||||
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -24,32 +24,32 @@ Used by several tools of `gettext` toolset.
|
|||
# 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"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Warnings
|
||||
import re
|
||||
|
||||
|
||||
#############################################################################
|
||||
class XgettextToolWarning(SCons.Warnings.Warning): pass
|
||||
class XgettextToolWarning(SCons.Warnings.SConsWarning): pass
|
||||
|
||||
|
||||
class XgettextNotFound(XgettextToolWarning): pass
|
||||
|
||||
|
||||
class MsginitToolWarning(SCons.Warnings.Warning): pass
|
||||
class MsginitToolWarning(SCons.Warnings.SConsWarning): pass
|
||||
|
||||
|
||||
class MsginitNotFound(MsginitToolWarning): pass
|
||||
|
||||
|
||||
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
|
||||
class MsgmergeToolWarning(SCons.Warnings.SConsWarning): pass
|
||||
|
||||
|
||||
class MsgmergeNotFound(MsgmergeToolWarning): pass
|
||||
|
||||
|
||||
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
|
||||
class MsgfmtToolWarning(SCons.Warnings.SConsWarning): pass
|
||||
|
||||
|
||||
class MsgfmtNotFound(MsgfmtToolWarning): pass
|
||||
|
@ -69,7 +69,7 @@ SCons.Warnings.enableWarningClass(MsgfmtNotFound)
|
|||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
class _POTargetFactory(object):
|
||||
class _POTargetFactory:
|
||||
""" A factory of `PO` target files.
|
||||
|
||||
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
|
||||
|
@ -198,19 +198,19 @@ class _POFileBuilder(BuilderBase):
|
|||
# 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:
|
||||
if 'suffix' not in kw:
|
||||
kw['suffix'] = '$POSUFFIX'
|
||||
if not 'src_suffix' in kw:
|
||||
if 'src_suffix' not in kw:
|
||||
kw['src_suffix'] = '$POTSUFFIX'
|
||||
if not 'src_builder' in kw:
|
||||
if 'src_builder' not in kw:
|
||||
kw['src_builder'] = '_POTUpdateBuilder'
|
||||
if not 'single_source' in kw:
|
||||
if 'single_source' not 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:
|
||||
if 'target_factory' not in kw:
|
||||
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
|
||||
BuilderBase.__init__(self, **kw)
|
||||
|
||||
|
@ -269,7 +269,7 @@ def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
|
|||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
class RPaths(object):
|
||||
class RPaths:
|
||||
""" Callable object, which returns pathnames relative to SCons current
|
||||
working directory.
|
||||
|
||||
|
@ -390,7 +390,7 @@ def _detect_xgettext(env):
|
|||
""" Detects *xgettext(1)* binary """
|
||||
if 'XGETTEXT' in env:
|
||||
return env['XGETTEXT']
|
||||
xgettext = env.Detect('xgettext');
|
||||
xgettext = env.Detect('xgettext')
|
||||
if xgettext:
|
||||
return xgettext
|
||||
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
|
||||
|
@ -409,7 +409,7 @@ def _detect_msginit(env):
|
|||
""" Detects *msginit(1)* program. """
|
||||
if 'MSGINIT' in env:
|
||||
return env['MSGINIT']
|
||||
msginit = env.Detect('msginit');
|
||||
msginit = env.Detect('msginit')
|
||||
if msginit:
|
||||
return msginit
|
||||
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
|
||||
|
@ -428,7 +428,7 @@ def _detect_msgmerge(env):
|
|||
""" Detects *msgmerge(1)* program. """
|
||||
if 'MSGMERGE' in env:
|
||||
return env['MSGMERGE']
|
||||
msgmerge = env.Detect('msgmerge');
|
||||
msgmerge = env.Detect('msgmerge')
|
||||
if msgmerge:
|
||||
return msgmerge
|
||||
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
|
||||
|
@ -447,7 +447,7 @@ def _detect_msgfmt(env):
|
|||
""" Detects *msgmfmt(1)* program. """
|
||||
if 'MSGFMT' in env:
|
||||
return env['MSGFMT']
|
||||
msgfmt = env.Detect('msgfmt');
|
||||
msgfmt = env.Detect('msgfmt')
|
||||
if msgfmt:
|
||||
return msgfmt
|
||||
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
|
|
@ -5,7 +5,7 @@ Stuff for processing Java.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -27,16 +27,48 @@ Stuff for processing Java.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/JavaCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import glob
|
||||
|
||||
java_parsing = 1
|
||||
|
||||
default_java_version = '1.4'
|
||||
|
||||
# a switch for which jdk versions to use the Scope state for smarter
|
||||
# anonymous inner class parsing.
|
||||
scopeStateVersions = ('1.8',)
|
||||
|
||||
# Glob patterns for use in finding where the JDK is.
|
||||
# These are pairs, *dir_glob used in the general case,
|
||||
# *version_dir_glob if matching only a specific version.
|
||||
# For now only used for Windows.
|
||||
java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin'
|
||||
# On windows, since Java 9, there is a dash between 'jdk' and the version
|
||||
# string that wasn't there before. this glob should catch either way.
|
||||
java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk*%s*/bin'
|
||||
|
||||
# Glob patterns for use in finding where the JDK headers are.
|
||||
# These are pairs, *dir_glob used in the general case,
|
||||
# *version_dir_glob if matching only a specific version.
|
||||
java_macos_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Headers/'
|
||||
java_macos_version_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/'
|
||||
|
||||
java_linux_include_dirs_glob = [
|
||||
'/usr/lib/jvm/default-java/include',
|
||||
'/usr/lib/jvm/java-*/include'
|
||||
]
|
||||
# Need to match path like below (from Centos 7)
|
||||
# /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/
|
||||
java_linux_version_include_dirs_glob = [
|
||||
'/usr/lib/jvm/java-*-sun-%s*/include',
|
||||
'/usr/lib/jvm/java-%s*-openjdk*/include',
|
||||
'/usr/java/jdk%s*/include'
|
||||
]
|
||||
|
||||
if java_parsing:
|
||||
# Parse Java files for class names.
|
||||
#
|
||||
|
@ -55,17 +87,20 @@ if java_parsing:
|
|||
# any alphanumeric token surrounded by angle brackets (generics);
|
||||
# the multi-line comment begin and end tokens /* and */;
|
||||
# array declarations "[]".
|
||||
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
|
||||
r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' +
|
||||
r'/\*|\*/|\[\])')
|
||||
# Lambda function symbols: ->
|
||||
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' +
|
||||
r'\d*\.\d*|[A-Za-z_][\w$.]*|<[A-Za-z_]\w+>|' +
|
||||
r'/\*|\*/|\[\]|->)')
|
||||
|
||||
class OuterState(object):
|
||||
|
||||
class OuterState:
|
||||
"""The initial state for parsing a Java file for classes,
|
||||
interfaces, and anonymous inner classes."""
|
||||
|
||||
def __init__(self, version=default_java_version):
|
||||
|
||||
if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '1.7',
|
||||
'1.8', '5', '6'):
|
||||
if version not in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7',
|
||||
'1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
|
||||
msg = "Java version %s not supported" % version
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
@ -116,7 +151,7 @@ if java_parsing:
|
|||
self.skipState = ret
|
||||
return ret
|
||||
|
||||
def __getAnonStack(self):
|
||||
def _getAnonStack(self):
|
||||
return self.anonStacksStack[-1]
|
||||
|
||||
def openBracket(self):
|
||||
|
@ -125,15 +160,16 @@ if java_parsing:
|
|||
def closeBracket(self):
|
||||
self.brackets = self.brackets - 1
|
||||
if len(self.stackBrackets) and \
|
||||
self.brackets == self.stackBrackets[-1]:
|
||||
self.brackets == self.stackBrackets[-1]:
|
||||
self.listOutputs.append('$'.join(self.listClasses))
|
||||
self.localClasses.pop()
|
||||
self.listClasses.pop()
|
||||
self.anonStacksStack.pop()
|
||||
self.stackBrackets.pop()
|
||||
if len(self.stackAnonClassBrackets) and \
|
||||
self.brackets == self.stackAnonClassBrackets[-1]:
|
||||
self.__getAnonStack().pop()
|
||||
self.brackets == self.stackAnonClassBrackets[-1] and \
|
||||
self.version not in scopeStateVersions:
|
||||
self._getAnonStack().pop()
|
||||
self.stackAnonClassBrackets.pop()
|
||||
|
||||
def parseToken(self, token):
|
||||
|
@ -145,13 +181,13 @@ if java_parsing:
|
|||
self.openBracket()
|
||||
elif token == '}':
|
||||
self.closeBracket()
|
||||
elif token in [ '"', "'" ]:
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == "new":
|
||||
# anonymous inner class
|
||||
if len(self.listClasses) > 0:
|
||||
return self.__getAnonClassState()
|
||||
return self.__getSkipState() # Skip the class name
|
||||
return self.__getSkipState() # Skip the class name
|
||||
elif token in ['class', 'interface', 'enum']:
|
||||
if len(self.listClasses) == 0:
|
||||
self.nextAnon = 1
|
||||
|
@ -171,28 +207,99 @@ if java_parsing:
|
|||
if self.version in ('1.1', '1.2', '1.3', '1.4'):
|
||||
clazz = self.listClasses[0]
|
||||
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
|
||||
elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6'):
|
||||
elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
|
||||
self.stackAnonClassBrackets.append(self.brackets)
|
||||
className = []
|
||||
className.extend(self.listClasses)
|
||||
self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1
|
||||
for anon in self.__getAnonStack():
|
||||
self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1
|
||||
for anon in self._getAnonStack():
|
||||
className.append(str(anon))
|
||||
self.listOutputs.append('$'.join(className))
|
||||
|
||||
self.nextAnon = self.nextAnon + 1
|
||||
self.__getAnonStack().append(0)
|
||||
self._getAnonStack().append(0)
|
||||
|
||||
def setPackage(self, package):
|
||||
self.package = package
|
||||
|
||||
class AnonClassState(object):
|
||||
|
||||
class ScopeState:
|
||||
"""
|
||||
A state that parses code within a scope normally,
|
||||
within the confines of a scope.
|
||||
"""
|
||||
|
||||
def __init__(self, old_state):
|
||||
self.outer_state = old_state.outer_state
|
||||
self.old_state = old_state
|
||||
self.brackets = 0
|
||||
|
||||
def __getClassState(self):
|
||||
try:
|
||||
return self.classState
|
||||
except AttributeError:
|
||||
ret = ClassState(self)
|
||||
self.classState = ret
|
||||
return ret
|
||||
|
||||
def __getAnonClassState(self):
|
||||
try:
|
||||
return self.anonState
|
||||
except AttributeError:
|
||||
ret = SkipState(1, AnonClassState(self))
|
||||
self.anonState = ret
|
||||
return ret
|
||||
|
||||
def __getSkipState(self):
|
||||
try:
|
||||
return self.skipState
|
||||
except AttributeError:
|
||||
ret = SkipState(1, self)
|
||||
self.skipState = ret
|
||||
return ret
|
||||
|
||||
def openBracket(self):
|
||||
self.brackets = self.brackets + 1
|
||||
|
||||
def closeBracket(self):
|
||||
self.brackets = self.brackets - 1
|
||||
|
||||
def parseToken(self, token):
|
||||
# if self.brackets == 0:
|
||||
# return self.old_state.parseToken(token)
|
||||
if token[:2] == '//':
|
||||
return IgnoreState('\n', self)
|
||||
elif token == '/*':
|
||||
return IgnoreState('*/', self)
|
||||
elif token == '{':
|
||||
self.openBracket()
|
||||
elif token == '}':
|
||||
self.closeBracket()
|
||||
if self.brackets == 0:
|
||||
self.outer_state._getAnonStack().pop()
|
||||
return self.old_state
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == "new":
|
||||
# anonymous inner class
|
||||
return self.__getAnonClassState()
|
||||
elif token == '.':
|
||||
# Skip the attribute, it might be named "class", in which
|
||||
# case we don't want to treat the following token as
|
||||
# an inner class name...
|
||||
return self.__getSkipState()
|
||||
return self
|
||||
|
||||
|
||||
class AnonClassState:
|
||||
"""A state that looks for anonymous inner classes."""
|
||||
|
||||
def __init__(self, old_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = old_state.outer_state
|
||||
self.old_state = old_state
|
||||
self.brace_level = 0
|
||||
|
||||
def parseToken(self, token):
|
||||
# This is an anonymous class if and only if the next
|
||||
# non-whitespace token is a bracket. Everything between
|
||||
|
@ -212,32 +319,40 @@ if java_parsing:
|
|||
if token == 'new':
|
||||
# look further for anonymous inner class
|
||||
return SkipState(1, AnonClassState(self))
|
||||
elif token in [ '"', "'" ]:
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == ')':
|
||||
self.brace_level = self.brace_level - 1
|
||||
return self
|
||||
if token == '{':
|
||||
self.outer_state.addAnonClass()
|
||||
if self.outer_state.version in scopeStateVersions:
|
||||
return ScopeState(old_state=self.old_state).parseToken(token)
|
||||
return self.old_state.parseToken(token)
|
||||
|
||||
class SkipState(object):
|
||||
|
||||
class SkipState:
|
||||
"""A state that will skip a specified number of tokens before
|
||||
reverting to the previous state."""
|
||||
|
||||
def __init__(self, tokens_to_skip, old_state):
|
||||
self.tokens_to_skip = tokens_to_skip
|
||||
self.old_state = old_state
|
||||
|
||||
def parseToken(self, token):
|
||||
self.tokens_to_skip = self.tokens_to_skip - 1
|
||||
if self.tokens_to_skip < 1:
|
||||
return self.old_state
|
||||
return self
|
||||
|
||||
class ClassState(object):
|
||||
|
||||
class ClassState:
|
||||
"""A state we go into when we hit a class or interface keyword."""
|
||||
|
||||
def __init__(self, outer_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = outer_state
|
||||
|
||||
def parseToken(self, token):
|
||||
# the next non-whitespace token should be the name of the class
|
||||
if token == '\n':
|
||||
|
@ -245,14 +360,14 @@ if java_parsing:
|
|||
# If that's an inner class which is declared in a method, it
|
||||
# requires an index prepended to the class-name, e.g.
|
||||
# 'Foo$1Inner'
|
||||
# http://scons.tigris.org/issues/show_bug.cgi?id=2087
|
||||
# https://github.com/SCons/scons/issues/2087
|
||||
if self.outer_state.localClasses and \
|
||||
self.outer_state.stackBrackets[-1] > \
|
||||
self.outer_state.stackBrackets[-2]+1:
|
||||
self.outer_state.stackBrackets[-1] > \
|
||||
self.outer_state.stackBrackets[-2] + 1:
|
||||
locals = self.outer_state.localClasses[-1]
|
||||
try:
|
||||
idx = locals[token]
|
||||
locals[token] = locals[token]+1
|
||||
locals[token] = locals[token] + 1
|
||||
except KeyError:
|
||||
locals[token] = 1
|
||||
token = str(locals[token]) + token
|
||||
|
@ -261,29 +376,39 @@ if java_parsing:
|
|||
self.outer_state.anonStacksStack.append([0])
|
||||
return self.outer_state
|
||||
|
||||
class IgnoreState(object):
|
||||
|
||||
class IgnoreState:
|
||||
"""A state that will ignore all tokens until it gets to a
|
||||
specified token."""
|
||||
|
||||
def __init__(self, ignore_until, old_state):
|
||||
self.ignore_until = ignore_until
|
||||
self.old_state = old_state
|
||||
|
||||
def parseToken(self, token):
|
||||
if self.ignore_until == token:
|
||||
return self.old_state
|
||||
return self
|
||||
|
||||
class PackageState(object):
|
||||
|
||||
class PackageState:
|
||||
"""The state we enter when we encounter the package keyword.
|
||||
We assume the next token will be the package name."""
|
||||
|
||||
def __init__(self, outer_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = outer_state
|
||||
|
||||
def parseToken(self, token):
|
||||
self.outer_state.setPackage(token)
|
||||
return self.outer_state
|
||||
|
||||
|
||||
def parse_java_file(fn, version=default_java_version):
|
||||
return parse_java(open(fn, 'r').read(), version)
|
||||
with open(fn, 'r', encoding='utf-8') as f:
|
||||
data = f.read()
|
||||
return parse_java(data, version)
|
||||
|
||||
|
||||
def parse_java(contents, version=default_java_version, trace=None):
|
||||
"""Parse a .java file and return a double of package directory,
|
||||
|
@ -315,7 +440,71 @@ else:
|
|||
is that the file name matches the public class name, and that
|
||||
the path to the file is the same as the package name.
|
||||
"""
|
||||
return os.path.split(file)
|
||||
return os.path.split(fn)
|
||||
|
||||
|
||||
def get_java_install_dirs(platform, version=None):
|
||||
"""
|
||||
Find the java jdk installation directories.
|
||||
|
||||
This list is intended to supply as "default paths" for use when looking
|
||||
up actual java binaries.
|
||||
|
||||
:param platform: selector for search algorithm.
|
||||
:param version: If specified, only look for java sdk's of this version
|
||||
:return: list of default paths for java.
|
||||
"""
|
||||
|
||||
paths = []
|
||||
if platform == 'win32':
|
||||
if version:
|
||||
paths = glob.glob(java_win32_version_dir_glob % version)
|
||||
else:
|
||||
paths = glob.glob(java_win32_dir_glob)
|
||||
else:
|
||||
# other platforms, do nothing for now
|
||||
pass
|
||||
|
||||
return sorted(paths)
|
||||
|
||||
|
||||
def get_java_include_paths(env, javac, version):
|
||||
"""
|
||||
Find java include paths for JNI building.
|
||||
|
||||
:param env: construction environment, used to extract platform.
|
||||
:param javac: path to detected javac.
|
||||
:return: list of paths.
|
||||
"""
|
||||
|
||||
paths = []
|
||||
if not javac:
|
||||
# there are no paths if we've not detected javac.
|
||||
pass
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
# on Windows, we have the right path to javac, so look locally
|
||||
javac_bin_dir = os.path.dirname(javac)
|
||||
java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include'))
|
||||
paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')]
|
||||
elif env['PLATFORM'] == 'darwin':
|
||||
if not version:
|
||||
paths = [java_macos_include_dir_glob]
|
||||
else:
|
||||
paths = sorted(glob.glob(java_macos_version_include_dir_glob % version))
|
||||
else:
|
||||
base_paths = []
|
||||
if not version:
|
||||
for p in java_linux_include_dirs_glob:
|
||||
base_paths.extend(glob.glob(p))
|
||||
else:
|
||||
for p in java_linux_version_include_dirs_glob:
|
||||
base_paths.extend(glob.glob(p % version))
|
||||
|
||||
for p in base_paths:
|
||||
paths.extend([p, os.path.join(p, 'linux')])
|
||||
|
||||
# print("PATHS:%s"%paths)
|
||||
return paths
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
107
scons/scons-local-4.1.0/SCons/Tool/MSCommon/README
Normal file
107
scons/scons-local-4.1.0/SCons/Tool/MSCommon/README
Normal file
|
@ -0,0 +1,107 @@
|
|||
This is the flow of the compiler detection logic:
|
||||
|
||||
External to MSCommon:
|
||||
|
||||
The Tool init modules, in their exists() routines, call -> msvc_exists(env)
|
||||
|
||||
At the moment, those modules are:
|
||||
SCons/Tool/midl.py
|
||||
SCons/Tool/mslib.py
|
||||
SCons/Tool/mslink.py
|
||||
SCons/Tool/msvc.py
|
||||
SCons/Tool/msvs.py
|
||||
|
||||
env may contain a version request in MSVC_VERSION, but this is not used
|
||||
in the detection that follows from msvc_exists(), only in the later
|
||||
batch that starts with a call to msvc_setup_env().
|
||||
|
||||
Internal to MSCommon/vc.py:
|
||||
|
||||
+ MSCommon/vc.py:msvc_exists:
|
||||
| vcs = cached_get_installed_vcs(env)
|
||||
| returns True if vcs > 0
|
||||
|
|
||||
+-> MSCommon/vc.py:cached_get_installed_vcs:
|
||||
| checks global if we've run previously, if so return it
|
||||
| populate the global from -> get_installed_vcs(env)
|
||||
|
|
||||
+-> MSCommon/vc.py:get_installed_vcs:
|
||||
| loop through "known" versions of msvc, granularity is maj.min
|
||||
| check for product dir -> find_vc_pdir(env, ver)
|
||||
|
|
||||
+-> MSCommon/vc.py:find_vc_pdir:
|
||||
| From the msvc-version to pdir mapping dict, get reg key base and value
|
||||
| If value is none -> find_vc_pdir_vswhere(ver, env)
|
||||
|
|
||||
+-> MSCommon/vc.py:find_vc_pdir_vswhere:
|
||||
| From the vc-version to VS-version mapping table get string
|
||||
| Figure out where vswhere is -> msvc_find_vswhere()
|
||||
| Use subprocess to call vswhere, return first line of match
|
||||
/
|
||||
| else get product directory from registry (<= 14.0)
|
||||
/
|
||||
| if we found one -> _check_cl_exists_in_vc_dir(env, pdir, ver)
|
||||
|
|
||||
+-> MSCommon/vc.py:_check_cl_exists_in_vc_dir:
|
||||
| Figure out host/target pair
|
||||
| if version > 14.0 get specific version by looking in
|
||||
| pdir + Auxiliary/Build/Microsoft/VCToolsVersion/default.txt
|
||||
| look for pdir + Tools/MSVC/{specver}/bin/host/target/cl.exe
|
||||
| if 14.0 or less, "do older stuff"
|
||||
|
||||
All of this just got us a yes-no answer on whether /some/ msvc version
|
||||
exists, but does populate __INSTALLED_VCS_RUN with all of the top-level
|
||||
versions as noted for get_installed_vcs
|
||||
|
||||
Externally:
|
||||
|
||||
Once a module's exists() has been called (or, in the case of
|
||||
clang/clangxx, after the compiler has been detected by other means -
|
||||
those still expect the rest of the msvc chain but not cl.exe)
|
||||
the module's generate() function calls -> msvc_setup_env_once(env)
|
||||
|
||||
Internally:
|
||||
|
||||
+ MSCommon/vc.py:msvc_setup_env_once:
|
||||
| checks for environment flag MSVC_SETUP_RUN
|
||||
| if not, -> msvc_setup_env(env) and set flag
|
||||
|
|
||||
+-+ MSCommon/vc.py:msvc_setup_env:
|
||||
| set ver from -> get_default_version(env)
|
||||
|
|
||||
+-+ MSCommon/vc.py:get_default_version:
|
||||
| if no version specified in env.MSVC_VERSION:
|
||||
| return first entry from -> cached_get_installed_vcs(env)
|
||||
| else return requested version
|
||||
/
|
||||
| get script from MSVC_USE_SCRIPT if set to a filename
|
||||
| -> script_env(script)
|
||||
|
|
||||
+-+ MSCommon/vc.py:script_env:
|
||||
| return (possibly cached) script variables matching script arg
|
||||
/
|
||||
| else -> msvc_find_valid_batch_script(env, version)
|
||||
|
|
||||
+-+ MSCommon/vc.py:msvc_find_valid_batch_script:
|
||||
| Build a list of plausible target values, and loop through
|
||||
| look for host + target -> find_batch_file(env, ver, host, target)
|
||||
|
|
||||
+-+ MSCommon/vc.py:find_batch_file:
|
||||
| call -> find_vc_pdir (see above)
|
||||
| use the return to construct a version-biased batfile path, check
|
||||
/
|
||||
| if not found, try sdk scripts (unknown if this is still useful)
|
||||
|
||||
|
||||
Problems:
|
||||
- For VS >= 2017, VS and VS are not 1:1, there can be many VC for one VS
|
||||
- For vswhere-ready versions, detection does not proceed beyond the
|
||||
product level ("2019") into individual "features" (individual msvc)
|
||||
- As documented for MSVC_VERSION, compilers can only be requested if versions
|
||||
are from the set in _VCVER, so 14.1 but not 14.16 or 14.16.27023
|
||||
- Information found in the first pass (msvs_exists) isn't really
|
||||
available anywhere except the cached version list, since we just
|
||||
return true/false.
|
||||
- Since msvc_exists chain of calls does not look at version, we
|
||||
can proceed to compiler setup if *any* msvc was found, even if the
|
||||
one requested wasn't found.
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -21,16 +21,12 @@
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
Common functions for Microsoft Visual Studio and Visual C/C++.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Platform.win32
|
||||
|
@ -42,7 +38,8 @@ from SCons.Tool.MSCommon.sdk import mssdk_exists, \
|
|||
from SCons.Tool.MSCommon.vc import msvc_exists, \
|
||||
msvc_setup_env, \
|
||||
msvc_setup_env_once, \
|
||||
msvc_version_to_maj_min
|
||||
msvc_version_to_maj_min, \
|
||||
msvc_find_vswhere
|
||||
|
||||
from SCons.Tool.MSCommon.vs import get_default_version, \
|
||||
get_vs_by_version, \
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -21,14 +21,13 @@
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to define supported Windows chip architectures.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
class ArchDefinition(object):
|
||||
class ArchDefinition:
|
||||
"""
|
||||
A class for defining architecture-specific settings and logic.
|
||||
"""
|
||||
|
@ -37,22 +36,22 @@ class ArchDefinition(object):
|
|||
self.synonyms = synonyms
|
||||
|
||||
SupportedArchitectureList = [
|
||||
ArchitectureDefinition(
|
||||
ArchDefinition(
|
||||
'x86',
|
||||
['i386', 'i486', 'i586', 'i686'],
|
||||
),
|
||||
|
||||
ArchitectureDefinition(
|
||||
ArchDefinition(
|
||||
'x86_64',
|
||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||
),
|
||||
|
||||
ArchitectureDefinition(
|
||||
ArchDefinition(
|
||||
'ia64',
|
||||
['IA64'],
|
||||
),
|
||||
|
||||
ArchitectureDefinition(
|
||||
ArchDefinition(
|
||||
'arm',
|
||||
['ARM'],
|
||||
),
|
|
@ -2,7 +2,7 @@
|
|||
Common helper functions for working with the Microsoft tool chain.
|
||||
"""
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -23,36 +23,105 @@ Common helper functions for working with the Microsoft tool chain.
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/common.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import SCons.Util
|
||||
|
||||
|
||||
# SCONS_MSCOMMON_DEBUG is internal-use so undocumented:
|
||||
# set to '-' to print to console, else set to filename to log to
|
||||
LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG')
|
||||
if LOGFILE == '-':
|
||||
def debug(message):
|
||||
print(message)
|
||||
elif LOGFILE:
|
||||
try:
|
||||
import logging
|
||||
except ImportError:
|
||||
debug = lambda message: open(LOGFILE, 'a').write(message + '\n')
|
||||
else:
|
||||
logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
|
||||
debug = logging.debug
|
||||
import logging
|
||||
modulelist = (
|
||||
# root module and parent/root module
|
||||
'MSCommon', 'Tool',
|
||||
# python library and below: correct iff scons does not have a lib folder
|
||||
'lib',
|
||||
# scons modules
|
||||
'SCons', 'test', 'scons'
|
||||
)
|
||||
def get_relative_filename(filename, module_list):
|
||||
if not filename:
|
||||
return filename
|
||||
for module in module_list:
|
||||
try:
|
||||
ind = filename.rindex(module)
|
||||
return filename[ind:]
|
||||
except ValueError:
|
||||
pass
|
||||
return filename
|
||||
class _Debug_Filter(logging.Filter):
|
||||
# custom filter for module relative filename
|
||||
def filter(self, record):
|
||||
relfilename = get_relative_filename(record.pathname, modulelist)
|
||||
relfilename = relfilename.replace('\\', '/')
|
||||
record.relfilename = relfilename
|
||||
return True
|
||||
logging.basicConfig(
|
||||
# This looks like:
|
||||
# 00109ms:MSCommon/vc.py:find_vc_pdir#447:
|
||||
format=(
|
||||
'%(relativeCreated)05dms'
|
||||
':%(relfilename)s'
|
||||
':%(funcName)s'
|
||||
'#%(lineno)s'
|
||||
':%(message)s: '
|
||||
),
|
||||
filename=LOGFILE,
|
||||
level=logging.DEBUG)
|
||||
logger = logging.getLogger(name=__name__)
|
||||
logger.addFilter(_Debug_Filter())
|
||||
debug = logger.debug
|
||||
else:
|
||||
debug = lambda x: None
|
||||
def debug(x): return None
|
||||
|
||||
|
||||
# SCONS_CACHE_MSVC_CONFIG is public, and is documented.
|
||||
CONFIG_CACHE = os.environ.get('SCONS_CACHE_MSVC_CONFIG')
|
||||
if CONFIG_CACHE in ('1', 'true', 'True'):
|
||||
CONFIG_CACHE = os.path.join(os.path.expanduser('~'), '.scons_msvc_cache')
|
||||
|
||||
|
||||
def read_script_env_cache():
|
||||
""" fetch cached msvc env vars if requested, else return empty dict """
|
||||
envcache = {}
|
||||
if CONFIG_CACHE:
|
||||
try:
|
||||
with open(CONFIG_CACHE, 'r') as f:
|
||||
envcache = json.load(f)
|
||||
except FileNotFoundError:
|
||||
# don't fail if no cache file, just proceed without it
|
||||
pass
|
||||
return envcache
|
||||
|
||||
|
||||
def write_script_env_cache(cache):
|
||||
""" write out cache of msvc env vars if requested """
|
||||
if CONFIG_CACHE:
|
||||
try:
|
||||
with open(CONFIG_CACHE, 'w') as f:
|
||||
json.dump(cache, f, indent=2)
|
||||
except TypeError:
|
||||
# data can't serialize to json, don't leave partial file
|
||||
os.remove(CONFIG_CACHE)
|
||||
except IOError:
|
||||
# can't write the file, just skip
|
||||
pass
|
||||
|
||||
|
||||
_is_win64 = None
|
||||
|
||||
|
||||
def is_win64():
|
||||
"""Return true if running on windows 64 bits.
|
||||
|
||||
|
@ -87,6 +156,7 @@ def is_win64():
|
|||
def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE):
|
||||
return SCons.Util.RegGetValue(hkroot, value)[0]
|
||||
|
||||
|
||||
def has_reg(value):
|
||||
"""Return True if the given key exists in HKEY_LOCAL_MACHINE, False
|
||||
otherwise."""
|
||||
|
@ -99,6 +169,7 @@ def has_reg(value):
|
|||
|
||||
# Functions for fetching environment variable settings from batch files.
|
||||
|
||||
|
||||
def normalize_env(env, keys, force=False):
|
||||
"""Given a dictionary representing a shell environment, add the variables
|
||||
from os.environ needed for the processing of .bat files; the keys are
|
||||
|
@ -113,22 +184,21 @@ def normalize_env(env, keys, force=False):
|
|||
Note: the environment is copied."""
|
||||
normenv = {}
|
||||
if env:
|
||||
for k in list(env.keys()):
|
||||
normenv[k] = copy.deepcopy(env[k])
|
||||
for k, v in env.items():
|
||||
normenv[k] = copy.deepcopy(v)
|
||||
|
||||
for k in keys:
|
||||
if k in os.environ and (force or not k in normenv):
|
||||
if k in os.environ and (force or k not in normenv):
|
||||
normenv[k] = os.environ[k]
|
||||
|
||||
# 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
|
||||
# bat scripts use.
|
||||
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']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir
|
||||
# add some things to PATH to prevent problems:
|
||||
# Shouldn't be necessary to add system32, since the default environment
|
||||
# should include it, but keep this here to be safe (needed for reg.exe)
|
||||
sys32_dir = os.path.join(
|
||||
os.environ.get("SystemRoot", os.environ.get("windir", r"C:\Windows")), "System32"
|
||||
)
|
||||
if sys32_dir not in normenv["PATH"]:
|
||||
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
|
||||
|
@ -137,27 +207,39 @@ def normalize_env(env, keys, force=False):
|
|||
if sys32_wbem_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
|
||||
|
||||
debug("PATH: %s"%normenv['PATH'])
|
||||
# Without Powershell in PATH, an internal call to a telemetry
|
||||
# function (starting with a VS2019 update) can fail
|
||||
# Note can also set VSCMD_SKIP_SENDTELEMETRY to avoid this.
|
||||
sys32_ps_dir = os.path.join(sys32_dir, r'WindowsPowerShell\v1.0')
|
||||
if sys32_ps_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_ps_dir
|
||||
|
||||
debug("PATH: %s" % normenv['PATH'])
|
||||
return normenv
|
||||
|
||||
def get_output(vcbat, args = None, env = None):
|
||||
|
||||
def get_output(vcbat, args=None, env=None):
|
||||
"""Parse the output of given bat file, with given args."""
|
||||
|
||||
if env is None:
|
||||
# Create a blank environment, for use in launching the tools
|
||||
env = SCons.Environment.Environment(tools=[])
|
||||
|
||||
# TODO: This is a hard-coded list of the variables that (may) need
|
||||
# to be imported from os.environ[] for v[sc]*vars*.bat file
|
||||
# execution to work. This list should really be either directly
|
||||
# controlled by vc.py, or else derived from the common_tools_var
|
||||
# settings in vs.py.
|
||||
# TODO: Hard-coded list of the variables that (may) need to be
|
||||
# imported from os.environ[] for the chain of development batch
|
||||
# files to execute correctly. One call to vcvars*.bat may
|
||||
# end up running a dozen or more scripts, changes not only with
|
||||
# each release but with what is installed at the time. We think
|
||||
# in modern installations most are set along the way and don't
|
||||
# need to be picked from the env, but include these for safety's sake.
|
||||
# Any VSCMD variables definitely are picked from the env and
|
||||
# control execution in interesting ways.
|
||||
# Note these really should be unified - either controlled by vs.py,
|
||||
# or synced with the the common_tools_var # settings in vs.py.
|
||||
vs_vc_vars = [
|
||||
'COMSPEC',
|
||||
# VS100 and VS110: Still set, but modern MSVC setup scripts will
|
||||
# discard these if registry has values. However Intel compiler setup
|
||||
# script still requires these as of 2013/2014.
|
||||
'COMSPEC', # path to "shell"
|
||||
'VS160COMNTOOLS', # path to common tools for given version
|
||||
'VS150COMNTOOLS',
|
||||
'VS140COMNTOOLS',
|
||||
'VS120COMNTOOLS',
|
||||
'VS110COMNTOOLS',
|
||||
|
@ -167,6 +249,8 @@ def get_output(vcbat, args = None, env = None):
|
|||
'VS71COMNTOOLS',
|
||||
'VS70COMNTOOLS',
|
||||
'VS60COMNTOOLS',
|
||||
'VSCMD_DEBUG', # enable logging and other debug aids
|
||||
'VSCMD_SKIP_SENDTELEMETRY',
|
||||
]
|
||||
env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False)
|
||||
|
||||
|
@ -188,32 +272,54 @@ def get_output(vcbat, args = None, env = None):
|
|||
# Use the .stdout and .stderr attributes directly because the
|
||||
# .communicate() method uses the threading module on Windows
|
||||
# and won't work under Pythons not built with threading.
|
||||
stdout = popen.stdout.read()
|
||||
stderr = popen.stderr.read()
|
||||
with popen.stdout:
|
||||
stdout = popen.stdout.read()
|
||||
with popen.stderr:
|
||||
stderr = popen.stderr.read()
|
||||
|
||||
# Extra debug logic, uncomment if necessary
|
||||
# debug('get_output():stdout:%s'%stdout)
|
||||
# debug('get_output():stderr:%s'%stderr)
|
||||
# debug('stdout:%s' % stdout)
|
||||
# debug('stderr:%s' % stderr)
|
||||
|
||||
# Ongoing problems getting non-corrupted text led to this
|
||||
# changing to "oem" from "mbcs" - the scripts run presumably
|
||||
# attached to a console, so some particular rules apply.
|
||||
# Unfortunately, "oem" not defined in Python 3.5, so get another way
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
from ctypes import windll
|
||||
|
||||
OEM = "cp{}".format(windll.kernel32.GetConsoleOutputCP())
|
||||
else:
|
||||
OEM = "oem"
|
||||
if stderr:
|
||||
# TODO: find something better to do with stderr;
|
||||
# this at least prevents errors from getting swallowed.
|
||||
import sys
|
||||
sys.stderr.write(stderr)
|
||||
sys.stderr.write(stderr.decode(OEM))
|
||||
if popen.wait() != 0:
|
||||
raise IOError(stderr.decode("mbcs"))
|
||||
raise IOError(stderr.decode(OEM))
|
||||
|
||||
output = stdout.decode("mbcs")
|
||||
return output
|
||||
return stdout.decode(OEM)
|
||||
|
||||
def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH")):
|
||||
|
||||
KEEPLIST = (
|
||||
"INCLUDE",
|
||||
"LIB",
|
||||
"LIBPATH",
|
||||
"PATH",
|
||||
"VSCMD_ARG_app_plat",
|
||||
"VCINSTALLDIR", # needed by clang -VS 2017 and newer
|
||||
"VCToolsInstallDir", # needed by clang - VS 2015 and older
|
||||
)
|
||||
|
||||
|
||||
def parse_output(output, keep=KEEPLIST):
|
||||
"""
|
||||
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
|
||||
# keep, and pat_list the associated list of paths
|
||||
# keep, and path_list the associated list of paths
|
||||
dkeep = dict([(i, []) for i in keep])
|
||||
|
||||
# rdk will keep the regex to match the .bat file output line starts
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# 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
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
"""
|
||||
|
@ -68,7 +68,7 @@ def query_versions():
|
|||
# sequence comparison in python is lexicographical
|
||||
# which is exactly what we want.
|
||||
# Note we sort backwards so the highest version is first.
|
||||
return cmp(bbl,aal)
|
||||
return (aal > bbl) - (aal < bbl)
|
||||
|
||||
versions.sort(versrt)
|
||||
else:
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -21,7 +21,7 @@
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to detect the Platform/Windows SDK
|
||||
|
||||
|
@ -33,9 +33,7 @@ import os
|
|||
import SCons.Errors
|
||||
import SCons.Util
|
||||
|
||||
from . import common
|
||||
|
||||
debug = common.debug
|
||||
from .common import debug, read_reg
|
||||
|
||||
# SDK Checks. This is of course a mess as everything else on MS platforms. Here
|
||||
# is what we do to detect the SDK:
|
||||
|
@ -58,7 +56,7 @@ _CURINSTALLED_SDK_HKEY_ROOT = \
|
|||
r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
|
||||
|
||||
|
||||
class SDKDefinition(object):
|
||||
class SDKDefinition:
|
||||
"""
|
||||
An abstract base class for trying to find installed SDK directories.
|
||||
"""
|
||||
|
@ -79,7 +77,7 @@ class SDKDefinition(object):
|
|||
debug('find_sdk_dir(): checking registry:{}'.format(hkey))
|
||||
|
||||
try:
|
||||
sdk_dir = common.read_reg(hkey)
|
||||
sdk_dir = read_reg(hkey)
|
||||
except SCons.Util.WinError as e:
|
||||
debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
|
||||
return None
|
||||
|
@ -110,19 +108,19 @@ class SDKDefinition(object):
|
|||
""" Return the script to initialize the VC compiler installed by SDK
|
||||
"""
|
||||
|
||||
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
|
||||
host_arch=target_arch
|
||||
|
||||
arch_string=target_arch
|
||||
if (host_arch != target_arch):
|
||||
if 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("get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
|
||||
host_arch,
|
||||
target_arch))
|
||||
file=self.vc_setup_scripts.get(arch_string,None)
|
||||
debug("sdk.py: get_sdk_vc_script():file:%s"%file)
|
||||
debug("get_sdk_vc_script():file:%s"%file)
|
||||
return file
|
||||
|
||||
class WindowsSDK(SDKDefinition):
|
||||
|
@ -178,6 +176,16 @@ SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
|
|||
#
|
||||
# If you update this list, update the documentation in Tool/mssdk.xml.
|
||||
SupportedSDKList = [
|
||||
WindowsSDK('10.0A',
|
||||
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('10.0',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
|
@ -276,14 +284,14 @@ InstalledSDKMap = None
|
|||
def get_installed_sdks():
|
||||
global InstalledSDKList
|
||||
global InstalledSDKMap
|
||||
debug('sdk.py:get_installed_sdks()')
|
||||
debug('get_installed_sdks()')
|
||||
if InstalledSDKList is None:
|
||||
InstalledSDKList = []
|
||||
InstalledSDKMap = {}
|
||||
for sdk in SupportedSDKList:
|
||||
debug('MSCommon/sdk.py: trying to find SDK %s' % sdk.version)
|
||||
debug('trying to find SDK %s' % sdk.version)
|
||||
if sdk.get_sdk_dir():
|
||||
debug('MSCommon/sdk.py:found SDK %s' % sdk.version)
|
||||
debug('found SDK %s' % sdk.version)
|
||||
InstalledSDKList.append(sdk)
|
||||
InstalledSDKMap[sdk.version] = sdk
|
||||
return InstalledSDKList
|
||||
|
@ -336,13 +344,13 @@ def get_default_sdk():
|
|||
return InstalledSDKList[0]
|
||||
|
||||
def mssdk_setup_env(env):
|
||||
debug('sdk.py:mssdk_setup_env()')
|
||||
debug('mssdk_setup_env()')
|
||||
if 'MSSDK_DIR' in env:
|
||||
sdk_dir = env['MSSDK_DIR']
|
||||
if sdk_dir is None:
|
||||
return
|
||||
sdk_dir = env.subst(sdk_dir)
|
||||
debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
|
||||
debug('mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
|
||||
elif 'MSSDK_VERSION' in env:
|
||||
sdk_version = env['MSSDK_VERSION']
|
||||
if sdk_version is None:
|
||||
|
@ -354,22 +362,22 @@ def mssdk_setup_env(env):
|
|||
msg = "SDK version %s is not installed" % sdk_version
|
||||
raise SCons.Errors.UserError(msg)
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
|
||||
debug('mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
|
||||
elif 'MSVS_VERSION' in env:
|
||||
msvs_version = env['MSVS_VERSION']
|
||||
debug('sdk.py:mssdk_setup_env:Getting MSVS_VERSION from env:%s'%msvs_version)
|
||||
debug('mssdk_setup_env:Getting MSVS_VERSION from env:%s'%msvs_version)
|
||||
if msvs_version is None:
|
||||
debug('sdk.py:mssdk_setup_env thinks msvs_version is None')
|
||||
debug('mssdk_setup_env thinks msvs_version is None')
|
||||
return
|
||||
msvs_version = env.subst(msvs_version)
|
||||
from . import vs
|
||||
msvs = vs.get_vs_by_version(msvs_version)
|
||||
debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs)
|
||||
debug('mssdk_setup_env:msvs is :%s'%msvs)
|
||||
if not msvs:
|
||||
debug('sdk.py:mssdk_setup_env: no VS version detected, bailingout:%s'%msvs)
|
||||
debug('mssdk_setup_env: no VS version detected, bailingout:%s'%msvs)
|
||||
return
|
||||
sdk_version = msvs.sdk_version
|
||||
debug('sdk.py:msvs.sdk_version is %s'%sdk_version)
|
||||
debug('msvs.sdk_version is %s'%sdk_version)
|
||||
if not sdk_version:
|
||||
return
|
||||
mssdk = get_sdk_by_version(sdk_version)
|
||||
|
@ -378,13 +386,13 @@ def mssdk_setup_env(env):
|
|||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('sdk.py:mssdk_setup_env: Using MSVS_VERSION:%s'%sdk_dir)
|
||||
debug('mssdk_setup_env: Using MSVS_VERSION:%s'%sdk_dir)
|
||||
else:
|
||||
mssdk = get_default_sdk()
|
||||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('sdk.py:mssdk_setup_env: not using any env values. sdk_dir:%s'%sdk_dir)
|
||||
debug('mssdk_setup_env: not using any env values. sdk_dir:%s'%sdk_dir)
|
||||
|
||||
set_sdk_by_directory(env, sdk_dir)
|
||||
|
955
scons/scons-local-4.1.0/SCons/Tool/MSCommon/vc.py
Normal file
955
scons/scons-local-4.1.0/SCons/Tool/MSCommon/vc.py
Normal file
|
@ -0,0 +1,955 @@
|
|||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
#
|
||||
"""Module for Visual C/C++ detection and configuration.
|
||||
|
||||
# TODO:
|
||||
# * gather all the information from a single vswhere call instead
|
||||
# of calling repeatedly (use json format?)
|
||||
# * support passing/setting location for vswhere in env.
|
||||
# * supported arch for versions: for old versions of batch file without
|
||||
# argument, giving bogus argument cannot be detected, so we have to hardcode
|
||||
# this here
|
||||
# * print warning when msvc version specified but not found
|
||||
# * find out why warning do not print
|
||||
# * test on 64 bits XP + VS 2005 (and VS 6 if possible)
|
||||
# * SDK
|
||||
# * Assembly
|
||||
"""
|
||||
|
||||
import SCons.compat
|
||||
import SCons.Util
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import platform
|
||||
from string import digits as string_digits
|
||||
from subprocess import PIPE
|
||||
|
||||
import SCons.Warnings
|
||||
from SCons.Tool import find_program_path
|
||||
|
||||
from . import common
|
||||
from .common import CONFIG_CACHE, debug
|
||||
from .sdk import get_installed_sdks
|
||||
|
||||
|
||||
class VisualCException(Exception):
|
||||
pass
|
||||
|
||||
class UnsupportedVersion(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCUnsupportedHostArch(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCUnsupportedTargetArch(VisualCException):
|
||||
pass
|
||||
|
||||
class MissingConfiguration(VisualCException):
|
||||
pass
|
||||
|
||||
class NoVersionFound(VisualCException):
|
||||
pass
|
||||
|
||||
class BatchFileExecutionError(VisualCException):
|
||||
pass
|
||||
|
||||
# Dict to 'canonalize' the arch
|
||||
_ARCH_TO_CANONICAL = {
|
||||
"amd64" : "amd64",
|
||||
"emt64" : "amd64",
|
||||
"i386" : "x86",
|
||||
"i486" : "x86",
|
||||
"i586" : "x86",
|
||||
"i686" : "x86",
|
||||
"ia64" : "ia64", # deprecated
|
||||
"itanium" : "ia64", # deprecated
|
||||
"x86" : "x86",
|
||||
"x86_64" : "amd64",
|
||||
"arm" : "arm",
|
||||
"arm64" : "arm64",
|
||||
"aarch64" : "arm64",
|
||||
}
|
||||
|
||||
# Starting with 14.1 (aka VS2017), the tools are organized by host directory.
|
||||
# subdirs for each target. They are now in .../VC/Auxuiliary/Build.
|
||||
# Note 2017 Express uses Hostx86 even if it's on 64-bit Windows,
|
||||
# not reflected in this table.
|
||||
_HOST_TARGET_TO_CL_DIR_GREATER_THAN_14 = {
|
||||
("amd64","amd64") : ("Hostx64","x64"),
|
||||
("amd64","x86") : ("Hostx64","x86"),
|
||||
("amd64","arm") : ("Hostx64","arm"),
|
||||
("amd64","arm64") : ("Hostx64","arm64"),
|
||||
("x86","amd64") : ("Hostx86","x64"),
|
||||
("x86","x86") : ("Hostx86","x86"),
|
||||
("x86","arm") : ("Hostx86","arm"),
|
||||
("x86","arm64") : ("Hostx86","arm64"),
|
||||
}
|
||||
|
||||
# before 14.1 (VS2017): the original x86 tools are in the tools dir,
|
||||
# any others are in a subdir named by the host/target pair,
|
||||
# or just a single word if host==target
|
||||
_HOST_TARGET_TO_CL_DIR = {
|
||||
("amd64","amd64") : "amd64",
|
||||
("amd64","x86") : "amd64_x86",
|
||||
("amd64","arm") : "amd64_arm",
|
||||
("amd64","arm64") : "amd64_arm64",
|
||||
("x86","amd64") : "x86_amd64",
|
||||
("x86","x86") : "",
|
||||
("x86","arm") : "x86_arm",
|
||||
("x86","arm64") : "x86_arm64",
|
||||
("arm","arm") : "arm",
|
||||
}
|
||||
|
||||
# 14.1 (VS2017) and later:
|
||||
# Given a (host, target) tuple, return the batch file to look for.
|
||||
# We can't rely on returning an arg to use for vcvarsall.bat,
|
||||
# because that script will run even if given a pair that isn't installed.
|
||||
# Targets that already look like a pair are pseudo targets that
|
||||
# effectively mean to skip whatever the host was specified as.
|
||||
_HOST_TARGET_TO_BAT_ARCH_GT14 = {
|
||||
("amd64", "amd64"): "vcvars64.bat",
|
||||
("amd64", "x86"): "vcvarsamd64_x86.bat",
|
||||
("amd64", "x86_amd64"): "vcvarsx86_amd64.bat",
|
||||
("amd64", "x86_x86"): "vcvars32.bat",
|
||||
("amd64", "arm"): "vcvarsamd64_arm.bat",
|
||||
("amd64", "x86_arm"): "vcvarsx86_arm.bat",
|
||||
("amd64", "arm64"): "vcvarsamd64_arm64.bat",
|
||||
("amd64", "x86_arm64"): "vcvarsx86_arm64.bat",
|
||||
("x86", "x86"): "vcvars32.bat",
|
||||
("x86", "amd64"): "vcvarsx86_amd64.bat",
|
||||
("x86", "x86_amd64"): "vcvarsx86_amd64.bat",
|
||||
("x86", "arm"): "vcvarsx86_arm.bat",
|
||||
("x86", "x86_arm"): "vcvarsx86_arm.bat",
|
||||
("x86", "arm64"): "vcvarsx86_arm64.bat",
|
||||
("x86", "x86_arm64"): "vcvarsx86_arm64.bat",
|
||||
}
|
||||
|
||||
# before 14.1 (VS2017):
|
||||
# Given a (host, target) tuple, return the argument for the bat file;
|
||||
# Both host and target should be canoncalized.
|
||||
# If the target already looks like a pair, return it - these are
|
||||
# pseudo targets (mainly used by Express versions)
|
||||
_HOST_TARGET_ARCH_TO_BAT_ARCH = {
|
||||
("x86", "x86"): "x86",
|
||||
("x86", "amd64"): "x86_amd64",
|
||||
("x86", "x86_amd64"): "x86_amd64",
|
||||
("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express
|
||||
("amd64", "amd64"): "amd64",
|
||||
("amd64", "x86"): "x86",
|
||||
("amd64", "x86_x86"): "x86",
|
||||
("x86", "ia64"): "x86_ia64", # gone since 14.0
|
||||
("x86", "arm"): "x86_arm", # since 14.0
|
||||
("x86", "arm64"): "x86_arm64", # since 14.1
|
||||
("amd64", "arm"): "amd64_arm", # since 14.0
|
||||
("amd64", "arm64"): "amd64_arm64", # since 14.1
|
||||
("x86", "x86_arm"): "x86_arm", # since 14.0
|
||||
("x86", "x86_arm64"): "x86_arm64", # since 14.1
|
||||
("amd64", "x86_arm"): "x86_arm", # since 14.0
|
||||
("amd64", "x86_arm64"): "x86_arm64", # since 14.1
|
||||
}
|
||||
|
||||
_CL_EXE_NAME = 'cl.exe'
|
||||
|
||||
def get_msvc_version_numeric(msvc_version):
|
||||
"""Get the raw version numbers from a MSVC_VERSION string, so it
|
||||
could be cast to float or other numeric values. For example, '14.0Exp'
|
||||
would get converted to '14.0'.
|
||||
|
||||
Args:
|
||||
msvc_version: str
|
||||
string representing the version number, could contain non
|
||||
digit characters
|
||||
|
||||
Returns:
|
||||
str: the value converted to a numeric only string
|
||||
|
||||
"""
|
||||
return ''.join([x for x in msvc_version if x in string_digits + '.'])
|
||||
|
||||
def get_host_target(env):
|
||||
host_platform = env.get('HOST_ARCH')
|
||||
debug("HOST_ARCH:" + str(host_platform))
|
||||
if not host_platform:
|
||||
host_platform = platform.machine()
|
||||
|
||||
# Solaris returns i86pc for both 32 and 64 bit architectures
|
||||
if host_platform == "i86pc":
|
||||
if platform.architecture()[0] == "64bit":
|
||||
host_platform = "amd64"
|
||||
else:
|
||||
host_platform = "x86"
|
||||
|
||||
# Retain user requested TARGET_ARCH
|
||||
req_target_platform = env.get('TARGET_ARCH')
|
||||
debug("TARGET_ARCH:" + str(req_target_platform))
|
||||
if req_target_platform:
|
||||
# If user requested a specific platform then only try that one.
|
||||
target_platform = req_target_platform
|
||||
else:
|
||||
target_platform = host_platform
|
||||
|
||||
try:
|
||||
host = _ARCH_TO_CANONICAL[host_platform.lower()]
|
||||
except KeyError:
|
||||
msg = "Unrecognized host architecture %s"
|
||||
raise MSVCUnsupportedHostArch(msg % repr(host_platform))
|
||||
|
||||
try:
|
||||
target = _ARCH_TO_CANONICAL[target_platform.lower()]
|
||||
except KeyError:
|
||||
all_archs = str(list(_ARCH_TO_CANONICAL.keys()))
|
||||
raise MSVCUnsupportedTargetArch(
|
||||
"Unrecognized target architecture %s\n\tValid architectures: %s"
|
||||
% (target_platform, all_archs)
|
||||
)
|
||||
|
||||
return (host, target, req_target_platform)
|
||||
|
||||
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
|
||||
# MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
_VCVER = ["14.2", "14.1", "14.1Exp", "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"]
|
||||
|
||||
# if using vswhere, configure command line arguments to probe for installed VC editions
|
||||
_VCVER_TO_VSWHERE_VER = {
|
||||
'14.2': [
|
||||
["-version", "[16.0, 17.0)", ], # default: Enterprise, Professional, Community (order unpredictable?)
|
||||
["-version", "[16.0, 17.0)", "-products", "Microsoft.VisualStudio.Product.BuildTools"], # BuildTools
|
||||
],
|
||||
'14.1': [
|
||||
["-version", "[15.0, 16.0)", ], # default: Enterprise, Professional, Community (order unpredictable?)
|
||||
["-version", "[15.0, 16.0)", "-products", "Microsoft.VisualStudio.Product.BuildTools"], # BuildTools
|
||||
],
|
||||
'14.1Exp': [
|
||||
["-version", "[15.0, 16.0)", "-products", "Microsoft.VisualStudio.Product.WDExpress"], # Express
|
||||
],
|
||||
}
|
||||
|
||||
_VCVER_TO_PRODUCT_DIR = {
|
||||
'14.2': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.1': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.1Exp': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
|
||||
'14.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\14.0\Setup\VC\ProductDir')],
|
||||
'12.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'12.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'9.0': [
|
||||
(SCons.Util.HKEY_CURRENT_USER, r'Microsoft\DevDiv\VCForPython\9.0\installdir',),
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',),
|
||||
],
|
||||
'9.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0Exp': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.1': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'6.0': [
|
||||
(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 = get_msvc_version_numeric(msvc_version)
|
||||
|
||||
t = msvc_version_numeric.split(".")
|
||||
if not len(t) == 2:
|
||||
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
|
||||
try:
|
||||
maj = int(t[0])
|
||||
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):
|
||||
"""Check if (host, target) pair is supported for a VC version.
|
||||
|
||||
Only checks whether a given version *may* support the given
|
||||
(host, target) pair, not that the toolchain is actually on the machine.
|
||||
|
||||
Args:
|
||||
host_target: canonalized host-target pair, e.g.
|
||||
("x86", "amd64") for cross compilation from 32- to 64-bit Windows.
|
||||
msvc_version: Visual C++ version (major.minor), e.g. "10.0"
|
||||
|
||||
Returns:
|
||||
True or False
|
||||
|
||||
"""
|
||||
# We assume that any Visual Studio version supports x86 as a target
|
||||
if host_target[1] != "x86":
|
||||
maj, min = msvc_version_to_maj_min(msvc_version)
|
||||
if maj < 8:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
VSWHERE_PATHS = [os.path.join(p,'vswhere.exe') for p in [
|
||||
os.path.expandvars(r"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer"),
|
||||
os.path.expandvars(r"%ProgramFiles%\Microsoft Visual Studio\Installer"),
|
||||
os.path.expandvars(r"%ChocolateyInstall%\bin"),
|
||||
]]
|
||||
|
||||
def msvc_find_vswhere():
|
||||
""" Find the location of vswhere """
|
||||
# For bug 3333: support default location of vswhere for both
|
||||
# 64 and 32 bit windows installs.
|
||||
# For bug 3542: also accommodate not being on C: drive.
|
||||
# NB: this gets called from testsuite on non-Windows platforms.
|
||||
# Whether that makes sense or not, don't break it for those.
|
||||
vswhere_path = None
|
||||
for pf in VSWHERE_PATHS:
|
||||
if os.path.exists(pf):
|
||||
vswhere_path = pf
|
||||
break
|
||||
|
||||
return vswhere_path
|
||||
|
||||
def find_vc_pdir_vswhere(msvc_version, env=None):
|
||||
""" Find the MSVC product directory using the vswhere program.
|
||||
|
||||
Args:
|
||||
msvc_version: MSVC version to search for
|
||||
env: optional to look up VSWHERE variable
|
||||
|
||||
Returns:
|
||||
MSVC install dir or None
|
||||
|
||||
Raises:
|
||||
UnsupportedVersion: if the version is not known by this file
|
||||
|
||||
"""
|
||||
try:
|
||||
vswhere_version = _VCVER_TO_VSWHERE_VER[msvc_version]
|
||||
except KeyError:
|
||||
debug("Unknown version of MSVC: %s" % msvc_version)
|
||||
raise UnsupportedVersion("Unknown version %s" % msvc_version)
|
||||
|
||||
if env is None or not env.get('VSWHERE'):
|
||||
vswhere_path = msvc_find_vswhere()
|
||||
else:
|
||||
vswhere_path = env.subst('$VSWHERE')
|
||||
|
||||
if vswhere_path is None:
|
||||
return None
|
||||
|
||||
debug('VSWHERE: %s' % vswhere_path)
|
||||
for vswhere_version_args in vswhere_version:
|
||||
|
||||
vswhere_cmd = [vswhere_path] + vswhere_version_args + ["-property", "installationPath"]
|
||||
|
||||
debug("running: %s" % vswhere_cmd)
|
||||
|
||||
#cp = subprocess.run(vswhere_cmd, capture_output=True) # 3.7+ only
|
||||
cp = subprocess.run(vswhere_cmd, stdout=PIPE, stderr=PIPE)
|
||||
|
||||
if cp.stdout:
|
||||
# vswhere could return multiple lines, e.g. if Build Tools
|
||||
# and {Community,Professional,Enterprise} are both installed.
|
||||
# We could define a way to pick the one we prefer, but since
|
||||
# this data is currently only used to make a check for existence,
|
||||
# returning the first hit should be good enough.
|
||||
lines = cp.stdout.decode("mbcs").splitlines()
|
||||
return os.path.join(lines[0], 'VC')
|
||||
else:
|
||||
# We found vswhere, but no install info available for this version
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def find_vc_pdir(env, msvc_version):
|
||||
"""Find the MSVC product directory for the given version.
|
||||
|
||||
Tries to look up the path using a registry key from the table
|
||||
_VCVER_TO_PRODUCT_DIR; if there is no key, calls find_vc_pdir_wshere
|
||||
for help instead.
|
||||
|
||||
Args:
|
||||
msvc_version: str
|
||||
msvc version (major.minor, e.g. 10.0)
|
||||
|
||||
Returns:
|
||||
str: Path found in registry, or None
|
||||
|
||||
Raises:
|
||||
UnsupportedVersion: if the version is not known by this file.
|
||||
MissingConfiguration: found version but the directory is missing.
|
||||
|
||||
Both exceptions inherit from VisualCException.
|
||||
|
||||
"""
|
||||
root = 'Software\\'
|
||||
try:
|
||||
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
|
||||
except KeyError:
|
||||
debug("Unknown version of MSVC: %s" % msvc_version)
|
||||
raise UnsupportedVersion("Unknown version %s" % msvc_version)
|
||||
|
||||
for hkroot, key in hkeys:
|
||||
try:
|
||||
comps = None
|
||||
if not key:
|
||||
comps = find_vc_pdir_vswhere(msvc_version, env)
|
||||
if not comps:
|
||||
debug('no VC found for version {}'.format(repr(msvc_version)))
|
||||
raise SCons.Util.WinError
|
||||
debug('VC found: {}'.format(repr(msvc_version)))
|
||||
return comps
|
||||
else:
|
||||
if common.is_win64():
|
||||
try:
|
||||
# ordinarily at win64, try Wow6432Node first.
|
||||
comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
|
||||
except SCons.Util.WinError as e:
|
||||
# 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('no VC registry key {}'.format(repr(key)))
|
||||
else:
|
||||
debug('found VC in registry: {}'.format(comps))
|
||||
if os.path.exists(comps):
|
||||
return comps
|
||||
else:
|
||||
debug('reg says dir is {}, but it does not exist. (ignoring)'.format(comps))
|
||||
raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps))
|
||||
return None
|
||||
|
||||
def find_batch_file(env,msvc_version,host_arch,target_arch):
|
||||
"""
|
||||
Find the location of the batch script which should set up the compiler
|
||||
for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
|
||||
|
||||
In newer (2017+) compilers, make use of the fact there are vcvars
|
||||
scripts named with a host_target pair that calls vcvarsall.bat properly,
|
||||
so use that and return an indication we don't need the argument
|
||||
we would have computed to run vcvarsall.bat.
|
||||
"""
|
||||
pdir = find_vc_pdir(env, msvc_version)
|
||||
if pdir is None:
|
||||
raise NoVersionFound("No version of Visual Studio found")
|
||||
debug('looking in {}'.format(pdir))
|
||||
|
||||
# filter out e.g. "Exp" from the version name
|
||||
msvc_ver_numeric = get_msvc_version_numeric(msvc_version)
|
||||
use_arg = True
|
||||
vernum = float(msvc_ver_numeric)
|
||||
if 7 <= vernum < 8:
|
||||
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
|
||||
batfilename = os.path.join(pdir, "vsvars32.bat")
|
||||
elif vernum < 7:
|
||||
pdir = os.path.join(pdir, "Bin")
|
||||
batfilename = os.path.join(pdir, "vcvars32.bat")
|
||||
elif 8 <= vernum <= 14:
|
||||
batfilename = os.path.join(pdir, "vcvarsall.bat")
|
||||
else: # vernum >= 14.1 VS2017 and above
|
||||
batfiledir = os.path.join(pdir, "Auxiliary", "Build")
|
||||
targ = _HOST_TARGET_TO_BAT_ARCH_GT14[(host_arch, target_arch)]
|
||||
batfilename = os.path.join(batfiledir, targ)
|
||||
use_arg = False
|
||||
|
||||
if not os.path.exists(batfilename):
|
||||
debug("Not found: %s" % batfilename)
|
||||
batfilename = None
|
||||
|
||||
installed_sdks = get_installed_sdks()
|
||||
for _sdk in installed_sdks:
|
||||
sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch)
|
||||
if not sdk_bat_file:
|
||||
debug("batch file not found:%s" % _sdk)
|
||||
else:
|
||||
sdk_bat_file_path = os.path.join(pdir,sdk_bat_file)
|
||||
if os.path.exists(sdk_bat_file_path):
|
||||
debug('sdk_bat_file_path:%s' % sdk_bat_file_path)
|
||||
return (batfilename, use_arg, sdk_bat_file_path)
|
||||
return (batfilename, use_arg, None)
|
||||
|
||||
|
||||
__INSTALLED_VCS_RUN = None
|
||||
_VC_TOOLS_VERSION_FILE_PATH = ['Auxiliary', 'Build', 'Microsoft.VCToolsVersion.default.txt']
|
||||
_VC_TOOLS_VERSION_FILE = os.sep.join(_VC_TOOLS_VERSION_FILE_PATH)
|
||||
|
||||
def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version):
|
||||
"""Return status of finding a cl.exe to use.
|
||||
|
||||
Locates cl in the vc_dir depending on TARGET_ARCH, HOST_ARCH and the
|
||||
msvc version. TARGET_ARCH and HOST_ARCH can be extracted from the
|
||||
passed env, unless it is None, in which case the native platform is
|
||||
assumed for both host and target.
|
||||
|
||||
Args:
|
||||
env: Environment
|
||||
a construction environment, usually if this is passed its
|
||||
because there is a desired TARGET_ARCH to be used when searching
|
||||
for a cl.exe
|
||||
vc_dir: str
|
||||
the path to the VC dir in the MSVC installation
|
||||
msvc_version: str
|
||||
msvc version (major.minor, e.g. 10.0)
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
|
||||
"""
|
||||
|
||||
# determine if there is a specific target platform we want to build for and
|
||||
# use that to find a list of valid VCs, default is host platform == target platform
|
||||
# and same for if no env is specified to extract target platform from
|
||||
if env:
|
||||
(host_platform, target_platform, req_target_platform) = get_host_target(env)
|
||||
else:
|
||||
host_platform = platform.machine().lower()
|
||||
target_platform = host_platform
|
||||
|
||||
host_platform = _ARCH_TO_CANONICAL[host_platform]
|
||||
target_platform = _ARCH_TO_CANONICAL[target_platform]
|
||||
|
||||
debug('host platform %s, target platform %s for version %s' % (host_platform, target_platform, msvc_version))
|
||||
|
||||
ver_num = float(get_msvc_version_numeric(msvc_version))
|
||||
|
||||
# make sure the cl.exe exists meaning the tool is installed
|
||||
if ver_num > 14:
|
||||
# 2017 and newer allowed multiple versions of the VC toolset to be
|
||||
# installed at the same time. This changes the layout.
|
||||
# Just get the default tool version for now
|
||||
#TODO: support setting a specific minor VC version
|
||||
default_toolset_file = os.path.join(vc_dir, _VC_TOOLS_VERSION_FILE)
|
||||
try:
|
||||
with open(default_toolset_file) as f:
|
||||
vc_specific_version = f.readlines()[0].strip()
|
||||
except IOError:
|
||||
debug('failed to read ' + default_toolset_file)
|
||||
return False
|
||||
except IndexError:
|
||||
debug('failed to find MSVC version in ' + default_toolset_file)
|
||||
return False
|
||||
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR_GREATER_THAN_14.get((host_platform, target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
debug('unsupported host/target platform combo: (%s,%s)'%(host_platform, target_platform))
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'Tools','MSVC', vc_specific_version, 'bin', host_trgt_dir[0], host_trgt_dir[1], _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
if os.path.exists(cl_path):
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif host_platform == "amd64" and host_trgt_dir[0] == "Hostx64":
|
||||
# Special case: fallback to Hostx86 if Hostx64 was tried
|
||||
# and failed. This is because VS 2017 Express running on amd64
|
||||
# will look to our probe like the host dir should be Hostx64,
|
||||
# but Express uses Hostx86 anyway.
|
||||
# We should key this off the "x86_amd64" and related pseudo
|
||||
# targets, but we don't see those in this function.
|
||||
host_trgt_dir = ("Hostx86", host_trgt_dir[1])
|
||||
cl_path = os.path.join(vc_dir, 'Tools','MSVC', vc_specific_version, 'bin', host_trgt_dir[0], host_trgt_dir[1], _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
if os.path.exists(cl_path):
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif 14 >= ver_num >= 8:
|
||||
# Set default value to be -1 as "", which is the value for x86/x86,
|
||||
# yields true when tested if not host_trgt_dir
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get((host_platform, target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
debug('unsupported host/target platform combo')
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
|
||||
cl_path_exists = os.path.exists(cl_path)
|
||||
if not cl_path_exists and host_platform == 'amd64':
|
||||
# older versions of visual studio only had x86 binaries,
|
||||
# so if the host platform is amd64, we need to check cross
|
||||
# compile options (x86 binary compiles some other target on a 64 bit os)
|
||||
|
||||
# Set default value to be -1 as "" which is the value for x86/x86 yields true when tested
|
||||
# if not host_trgt_dir
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get(('x86', target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
cl_path_exists = os.path.exists(cl_path)
|
||||
|
||||
if cl_path_exists:
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif 8 > ver_num >= 6:
|
||||
# quick check for vc_dir/bin and vc_dir/ before walk
|
||||
# need to check root as the walk only considers subdirectories
|
||||
for cl_dir in ('bin', ''):
|
||||
cl_path = os.path.join(vc_dir, cl_dir, _CL_EXE_NAME)
|
||||
if os.path.exists(cl_path):
|
||||
debug(_CL_EXE_NAME + ' found %s' % cl_path)
|
||||
return True
|
||||
# not in bin or root: must be in a subdirectory
|
||||
for cl_root, cl_dirs, _ in os.walk(vc_dir):
|
||||
for cl_dir in cl_dirs:
|
||||
cl_path = os.path.join(cl_root, cl_dir, _CL_EXE_NAME)
|
||||
if os.path.exists(cl_path):
|
||||
debug(_CL_EXE_NAME + ' found %s' % cl_path)
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
# version not support return false
|
||||
debug('unsupported MSVC version: ' + str(ver_num))
|
||||
|
||||
return False
|
||||
|
||||
def get_installed_vcs(env=None):
|
||||
global __INSTALLED_VCS_RUN
|
||||
|
||||
if __INSTALLED_VCS_RUN is not None:
|
||||
return __INSTALLED_VCS_RUN
|
||||
|
||||
installed_versions = []
|
||||
|
||||
for ver in _VCVER:
|
||||
debug('trying to find VC %s' % ver)
|
||||
try:
|
||||
VC_DIR = find_vc_pdir(env, ver)
|
||||
if VC_DIR:
|
||||
debug('found VC %s' % ver)
|
||||
if _check_cl_exists_in_vc_dir(env, VC_DIR, ver):
|
||||
installed_versions.append(ver)
|
||||
else:
|
||||
debug('no compiler found %s' % ver)
|
||||
else:
|
||||
debug('return None for ver %s' % ver)
|
||||
except (MSVCUnsupportedTargetArch, MSVCUnsupportedHostArch):
|
||||
# Allow this exception to propagate further as it should cause
|
||||
# SCons to exit with an error code
|
||||
raise
|
||||
except VisualCException as e:
|
||||
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
|
||||
|
||||
__INSTALLED_VCS_RUN = installed_versions
|
||||
return __INSTALLED_VCS_RUN
|
||||
|
||||
def reset_installed_vcs():
|
||||
"""Make it try again to find VC. This is just for the tests."""
|
||||
global __INSTALLED_VCS_RUN
|
||||
__INSTALLED_VCS_RUN = None
|
||||
|
||||
# Running these batch files isn't cheap: most of the time spent in
|
||||
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
|
||||
# in multiple environments, for example:
|
||||
# env1 = Environment(tools='msvs')
|
||||
# env2 = Environment(tools='msvs')
|
||||
# we can greatly improve the speed of the second and subsequent Environment
|
||||
# (or Clone) calls by memoizing the environment variables set by vcvars*.bat.
|
||||
#
|
||||
# Updated: by 2018, vcvarsall.bat had gotten so expensive (vs2017 era)
|
||||
# it was breaking CI builds because the test suite starts scons so many
|
||||
# times and the existing memo logic only helped with repeated calls
|
||||
# within the same scons run. Windows builds on the CI system were split
|
||||
# into chunks to get around single-build time limits.
|
||||
# With VS2019 it got even slower and an optional persistent cache file
|
||||
# was introduced. The cache now also stores only the parsed vars,
|
||||
# not the entire output of running the batch file - saves a bit
|
||||
# of time not parsing every time.
|
||||
|
||||
script_env_cache = None
|
||||
|
||||
def script_env(script, args=None):
|
||||
global script_env_cache
|
||||
|
||||
if script_env_cache is None:
|
||||
script_env_cache = common.read_script_env_cache()
|
||||
cache_key = "{}--{}".format(script, args)
|
||||
cache_data = script_env_cache.get(cache_key, None)
|
||||
if cache_data is None:
|
||||
stdout = common.get_output(script, args)
|
||||
|
||||
# Stupid batch files do not set return code: we take a look at the
|
||||
# beginning of the output for an error message instead
|
||||
olines = stdout.splitlines()
|
||||
if olines[0].startswith("The specified configuration type is missing"):
|
||||
raise BatchFileExecutionError("\n".join(olines[:2]))
|
||||
|
||||
cache_data = common.parse_output(stdout)
|
||||
script_env_cache[cache_key] = cache_data
|
||||
# once we updated cache, give a chance to write out if user wanted
|
||||
common.write_script_env_cache(script_env_cache)
|
||||
|
||||
return cache_data
|
||||
|
||||
def get_default_version(env):
|
||||
msvc_version = env.get('MSVC_VERSION')
|
||||
msvs_version = env.get('MSVS_VERSION')
|
||||
debug('msvc_version:%s msvs_version:%s' % (msvc_version, msvs_version))
|
||||
|
||||
if msvs_version and not msvc_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DeprecatedWarning,
|
||||
"MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
|
||||
return msvs_version
|
||||
elif msvc_version and msvs_version:
|
||||
if not msvc_version == msvs_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.VisualVersionMismatch,
|
||||
"Requested msvc version (%s) and msvs version (%s) do " \
|
||||
"not match: please use MSVC_VERSION only to request a " \
|
||||
"visual studio version, MSVS_VERSION is deprecated" \
|
||||
% (msvc_version, msvs_version))
|
||||
return msvs_version
|
||||
|
||||
if not msvc_version:
|
||||
installed_vcs = get_installed_vcs(env)
|
||||
debug('installed_vcs:%s' % installed_vcs)
|
||||
if not installed_vcs:
|
||||
#msg = 'No installed VCs'
|
||||
#debug('msv %s' % repr(msg))
|
||||
#SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
|
||||
debug('No installed VCs')
|
||||
return None
|
||||
msvc_version = installed_vcs[0]
|
||||
debug('using default installed MSVC version %s' % repr(msvc_version))
|
||||
else:
|
||||
debug('using specified MSVC version %s' % repr(msvc_version))
|
||||
|
||||
return msvc_version
|
||||
|
||||
def msvc_setup_env_once(env):
|
||||
try:
|
||||
has_run = env["MSVC_SETUP_RUN"]
|
||||
except KeyError:
|
||||
has_run = False
|
||||
|
||||
if not has_run:
|
||||
msvc_setup_env(env)
|
||||
env["MSVC_SETUP_RUN"] = True
|
||||
|
||||
def msvc_find_valid_batch_script(env, version):
|
||||
"""Find and execute appropriate batch script to set up build env.
|
||||
|
||||
The MSVC build environment depends heavily on having the shell
|
||||
environment set. SCons does not inherit that, and does not count
|
||||
on that being set up correctly anyway, so it tries to find the right
|
||||
MSVC batch script, or the right arguments to the generic batch script
|
||||
vcvarsall.bat, and run that, so we have a valid environment to build in.
|
||||
There are dragons here: the batch scripts don't fail (see comments
|
||||
elsewhere), they just leave you with a bad setup, so try hard to
|
||||
get it right.
|
||||
"""
|
||||
|
||||
# Find the host, target, and if present the requested target:
|
||||
platforms = get_host_target(env)
|
||||
debug("host_platform %s, target_platform %s req_target_platform %s" % platforms)
|
||||
host_platform, target_platform, req_target_platform = platforms
|
||||
|
||||
# Most combinations of host + target are straightforward.
|
||||
# While all MSVC / Visual Studio tools are pysically 32-bit, they
|
||||
# make it look like there are 64-bit tools if the host is 64-bit,
|
||||
# so you can invoke the environment batch script to set up to build,
|
||||
# say, amd64 host -> x86 target. Express versions are an exception:
|
||||
# they always look 32-bit, so the batch scripts with 64-bit
|
||||
# host parts are absent. We try to fix that up in a couple of ways.
|
||||
# One is here: we make a table of "targets" to try, with the extra
|
||||
# targets being tags that tell us to try a different "host" instead
|
||||
# of the deduced host.
|
||||
try_target_archs = [target_platform]
|
||||
if req_target_platform in ('amd64', 'x86_64'):
|
||||
try_target_archs.append('x86_amd64')
|
||||
elif req_target_platform in ('x86',):
|
||||
try_target_archs.append('x86_x86')
|
||||
elif req_target_platform in ('arm',):
|
||||
try_target_archs.append('x86_arm')
|
||||
elif req_target_platform in ('arm64',):
|
||||
try_target_archs.append('x86_arm64')
|
||||
elif not req_target_platform:
|
||||
if target_platform in ('amd64', 'x86_64'):
|
||||
try_target_archs.append('x86_amd64')
|
||||
# If the user hasn't specifically requested a TARGET_ARCH,
|
||||
# and the TARGET_ARCH is amd64 then also try 32 bits
|
||||
# if there are no viable 64 bit tools installed
|
||||
try_target_archs.append('x86')
|
||||
|
||||
debug("host_platform: %s, try_target_archs: %s"%(host_platform, try_target_archs))
|
||||
|
||||
d = None
|
||||
for tp in try_target_archs:
|
||||
# Set to current arch.
|
||||
env['TARGET_ARCH'] = tp
|
||||
|
||||
debug("trying target_platform:%s" % tp)
|
||||
host_target = (host_platform, tp)
|
||||
if not is_host_target_supported(host_target, version):
|
||||
warn_msg = "host, target = %s not supported for MSVC version %s" % \
|
||||
(host_target, version)
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
|
||||
|
||||
# Try to locate a batch file for this host/target platform combo
|
||||
try:
|
||||
(vc_script, use_arg, sdk_script) = find_batch_file(env, version, host_platform, tp)
|
||||
debug('vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
|
||||
except VisualCException as e:
|
||||
msg = str(e)
|
||||
debug('Caught exception while looking for batch file (%s)' % msg)
|
||||
warn_msg = "VC version %s not installed. " + \
|
||||
"C/C++ compilers are most likely not set correctly.\n" + \
|
||||
" Installed versions are: %s"
|
||||
warn_msg = warn_msg % (version, get_installed_vcs(env))
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
continue
|
||||
|
||||
# Try to use the located batch file for this host/target platform combo
|
||||
debug('use_script 2 %s, args:%s' % (repr(vc_script), arg))
|
||||
found = None
|
||||
if vc_script:
|
||||
if not use_arg:
|
||||
arg = '' # bat file will supply platform type
|
||||
# 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/UWP paths
|
||||
arg = (arg + ' store').lstrip()
|
||||
|
||||
try:
|
||||
d = script_env(vc_script, args=arg)
|
||||
found = vc_script
|
||||
except BatchFileExecutionError as e:
|
||||
debug('use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
|
||||
vc_script=None
|
||||
continue
|
||||
if not vc_script and sdk_script:
|
||||
debug('use_script 4: trying sdk script: %s' % sdk_script)
|
||||
try:
|
||||
d = script_env(sdk_script)
|
||||
found = sdk_script
|
||||
except BatchFileExecutionError as e:
|
||||
debug('use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script), e))
|
||||
continue
|
||||
elif not vc_script and not sdk_script:
|
||||
debug('use_script 6: Neither VC script nor SDK script found')
|
||||
continue
|
||||
|
||||
debug("Found a working script/target: %s/%s"%(repr(found),arg))
|
||||
break # We've found a working target_platform, so stop looking
|
||||
|
||||
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
|
||||
# To it's initial value
|
||||
if not d:
|
||||
env['TARGET_ARCH']=req_target_platform
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def msvc_setup_env(env):
|
||||
debug('called')
|
||||
version = get_default_version(env)
|
||||
if version is None:
|
||||
warn_msg = "No version of Visual Studio compiler found - C/C++ " \
|
||||
"compilers most likely not set correctly"
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
|
||||
# XXX: we set-up both MSVS version for backward
|
||||
# compatibility with the msvs tool
|
||||
env['MSVC_VERSION'] = version
|
||||
env['MSVS_VERSION'] = version
|
||||
env['MSVS'] = {}
|
||||
|
||||
|
||||
use_script = env.get('MSVC_USE_SCRIPT', True)
|
||||
if SCons.Util.is_String(use_script):
|
||||
debug('use_script 1 %s' % repr(use_script))
|
||||
d = script_env(use_script)
|
||||
elif use_script:
|
||||
d = msvc_find_valid_batch_script(env,version)
|
||||
debug('use_script 2 %s' % d)
|
||||
if not d:
|
||||
return d
|
||||
else:
|
||||
debug('MSVC_USE_SCRIPT set to False')
|
||||
warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
|
||||
"set correctly."
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
|
||||
for k, v in d.items():
|
||||
env.PrependENVPath(k, v, delete_existing=True)
|
||||
debug("env['ENV']['%s'] = %s" % (k, env['ENV'][k]))
|
||||
|
||||
# final check to issue a warning if the compiler is not present
|
||||
if not find_program_path(env, 'cl'):
|
||||
debug("did not find " + _CL_EXE_NAME)
|
||||
if CONFIG_CACHE:
|
||||
propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE)
|
||||
else:
|
||||
propose = "It may need to be installed separately with Visual Studio."
|
||||
warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose)
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
|
||||
def msvc_exists(env=None, version=None):
|
||||
vcs = get_installed_vcs(env)
|
||||
if version is None:
|
||||
return len(vcs) > 0
|
||||
return version in vcs
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -21,7 +21,7 @@
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to detect Visual Studio and/or Visual C/C++
|
||||
"""
|
||||
|
@ -40,7 +40,7 @@ from .common import debug, \
|
|||
|
||||
import SCons.Tool.MSCommon.vc
|
||||
|
||||
class VisualStudio(object):
|
||||
class VisualStudio:
|
||||
"""
|
||||
An abstract base class for trying to find installed versions of
|
||||
Visual Studio.
|
||||
|
@ -55,62 +55,61 @@ class VisualStudio(object):
|
|||
def find_batch_file(self):
|
||||
vs_dir = self.get_vs_dir()
|
||||
if not vs_dir:
|
||||
debug('find_executable(): no vs_dir')
|
||||
debug('no vs_dir')
|
||||
return None
|
||||
batch_file = os.path.join(vs_dir, self.batch_file_path)
|
||||
batch_file = os.path.normpath(batch_file)
|
||||
if not os.path.isfile(batch_file):
|
||||
debug('find_batch_file(): %s not on file system' % batch_file)
|
||||
debug('%s not on file system' % batch_file)
|
||||
return None
|
||||
return batch_file
|
||||
|
||||
def find_vs_dir_by_vc(self):
|
||||
SCons.Tool.MSCommon.vc.get_installed_vcs()
|
||||
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version)
|
||||
def find_vs_dir_by_vc(self, env):
|
||||
SCons.Tool.MSCommon.vc.get_installed_vcs(env)
|
||||
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(env, self.vc_version)
|
||||
if not dir:
|
||||
debug('find_vs_dir(): no installed VC %s' % self.vc_version)
|
||||
debug('no installed VC %s' % self.vc_version)
|
||||
return None
|
||||
return dir
|
||||
return os.path.abspath(os.path.join(dir, os.pardir))
|
||||
|
||||
def find_vs_dir_by_reg(self):
|
||||
def find_vs_dir_by_reg(self, env):
|
||||
root = 'Software\\'
|
||||
|
||||
if is_win64():
|
||||
root = root + 'Wow6432Node\\'
|
||||
for key in self.hkeys:
|
||||
if key=='use_dir':
|
||||
return self.find_vs_dir_by_vc()
|
||||
return self.find_vs_dir_by_vc(env)
|
||||
key = root + key
|
||||
try:
|
||||
comps = read_reg(key)
|
||||
except SCons.Util.WinError as e:
|
||||
debug('find_vs_dir_by_reg(): no VS registry key {}'.format(repr(key)))
|
||||
debug('no VS registry key {}'.format(repr(key)))
|
||||
else:
|
||||
debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps))
|
||||
debug('found VS in registry: {}'.format(comps))
|
||||
return comps
|
||||
return None
|
||||
|
||||
def find_vs_dir(self):
|
||||
def find_vs_dir(self, env):
|
||||
""" Can use registry or location of VC to find vs dir
|
||||
First try to find by registry, and if that fails find via VC dir
|
||||
"""
|
||||
|
||||
|
||||
if True:
|
||||
vs_dir=self.find_vs_dir_by_reg()
|
||||
return vs_dir
|
||||
else:
|
||||
return self.find_vs_dir_by_vc()
|
||||
|
||||
def find_executable(self):
|
||||
vs_dir = self.get_vs_dir()
|
||||
vs_dir=self.find_vs_dir_by_reg(env)
|
||||
if not vs_dir:
|
||||
debug('find_executable(): no vs_dir ({})'.format(vs_dir))
|
||||
vs_dir = self.find_vs_dir_by_vc(env)
|
||||
debug('found VS in ' + str(vs_dir ))
|
||||
return vs_dir
|
||||
|
||||
def find_executable(self, env):
|
||||
vs_dir = self.get_vs_dir(env)
|
||||
if not vs_dir:
|
||||
debug('no vs_dir ({})'.format(vs_dir))
|
||||
return None
|
||||
executable = os.path.join(vs_dir, self.executable_path)
|
||||
executable = os.path.normpath(executable)
|
||||
if not os.path.isfile(executable):
|
||||
debug('find_executable(): {} not on file system'.format(executable))
|
||||
debug('{} not on file system'.format(executable))
|
||||
return None
|
||||
return executable
|
||||
|
||||
|
@ -122,21 +121,21 @@ class VisualStudio(object):
|
|||
self._cache['batch_file'] = batch_file
|
||||
return batch_file
|
||||
|
||||
def get_executable(self):
|
||||
def get_executable(self, env=None):
|
||||
try:
|
||||
debug('get_executable using cache:%s'%self._cache['executable'])
|
||||
debug('using cache:%s'%self._cache['executable'])
|
||||
return self._cache['executable']
|
||||
except KeyError:
|
||||
executable = self.find_executable()
|
||||
executable = self.find_executable(env)
|
||||
self._cache['executable'] = executable
|
||||
debug('get_executable not in cache:%s'%executable)
|
||||
debug('not in cache:%s'%executable)
|
||||
return executable
|
||||
|
||||
def get_vs_dir(self):
|
||||
def get_vs_dir(self, env):
|
||||
try:
|
||||
return self._cache['vs_dir']
|
||||
except KeyError:
|
||||
vs_dir = self.find_vs_dir()
|
||||
vs_dir = self.find_vs_dir(env)
|
||||
self._cache['vs_dir'] = vs_dir
|
||||
return vs_dir
|
||||
|
||||
|
@ -199,6 +198,18 @@ class VisualStudio(object):
|
|||
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
|
||||
SupportedVSList = [
|
||||
# Visual Studio 2019
|
||||
VisualStudio('14.2',
|
||||
vc_version='14.2',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS160COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2017
|
||||
VisualStudio('14.1',
|
||||
vc_version='14.1',
|
||||
|
@ -206,10 +217,23 @@ SupportedVSList = [
|
|||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual C++ 2017 Express Edition (for Desktop)
|
||||
VisualStudio('14.1Exp',
|
||||
vc_version='14.1',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2015
|
||||
VisualStudio('14.0',
|
||||
vc_version='14.0',
|
||||
|
@ -356,7 +380,7 @@ SupportedVSList = [
|
|||
sdk_version='2003R2',
|
||||
hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS70COMNTOOLS',
|
||||
executable_path=r'IDE\devenv.com',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio .NET',
|
||||
supported_arch=['x86'],
|
||||
|
@ -389,7 +413,7 @@ for vs in SupportedVSList:
|
|||
InstalledVSList = None
|
||||
InstalledVSMap = None
|
||||
|
||||
def get_installed_visual_studios():
|
||||
def get_installed_visual_studios(env=None):
|
||||
global InstalledVSList
|
||||
global InstalledVSMap
|
||||
if InstalledVSList is None:
|
||||
|
@ -397,7 +421,7 @@ def get_installed_visual_studios():
|
|||
InstalledVSMap = {}
|
||||
for vs in SupportedVSList:
|
||||
debug('trying to find VS %s' % vs.version)
|
||||
if vs.get_executable():
|
||||
if vs.get_executable(env):
|
||||
debug('found VS %s' % vs.version)
|
||||
InstalledVSList.append(vs)
|
||||
InstalledVSMap[vs.version] = vs
|
||||
|
@ -448,21 +472,21 @@ def reset_installed_visual_studios():
|
|||
# for variable, directory in env_tuple_list:
|
||||
# env.PrependENVPath(variable, directory)
|
||||
|
||||
def msvs_exists():
|
||||
return (len(get_installed_visual_studios()) > 0)
|
||||
def msvs_exists(env=None):
|
||||
return (len(get_installed_visual_studios(env)) > 0)
|
||||
|
||||
def get_vs_by_version(msvs):
|
||||
global InstalledVSMap
|
||||
global SupportedVSMap
|
||||
|
||||
debug('vs.py:get_vs_by_version()')
|
||||
debug('called')
|
||||
if msvs not in SupportedVSMap:
|
||||
msg = "Visual Studio version %s is not supported" % repr(msvs)
|
||||
raise SCons.Errors.UserError(msg)
|
||||
get_installed_visual_studios()
|
||||
vs = InstalledVSMap.get(msvs)
|
||||
debug('InstalledVSMap:%s'%InstalledVSMap)
|
||||
debug('vs.py:get_vs_by_version: found vs:%s'%vs)
|
||||
debug('InstalledVSMap:%s' % InstalledVSMap)
|
||||
debug('found vs:%s' % vs)
|
||||
# Some check like this would let us provide a useful error message
|
||||
# if they try to set a Visual Studio version that's not installed.
|
||||
# However, we also want to be able to run tests (like the unit
|
||||
|
@ -497,8 +521,8 @@ def get_default_version(env):
|
|||
if versions:
|
||||
env['MSVS_VERSION'] = versions[0] #use highest version by default
|
||||
else:
|
||||
debug('get_default_version: WARNING: no installed versions found, '
|
||||
'using first in SupportedVSList (%s)'%SupportedVSList[0].version)
|
||||
debug('WARNING: no installed versions found, '
|
||||
'using first in SupportedVSList (%s)' % SupportedVSList[0].version)
|
||||
env['MSVS_VERSION'] = SupportedVSList[0].version
|
||||
|
||||
env['MSVS']['VERSION'] = env['MSVS_VERSION']
|
||||
|
@ -521,7 +545,7 @@ def get_default_arch(env):
|
|||
|
||||
if not msvs:
|
||||
arch = 'x86'
|
||||
elif not arch in msvs.get_supported_arch():
|
||||
elif arch not in msvs.get_supported_arch():
|
||||
fmt = "Visual Studio version %s does not support architecture %s"
|
||||
raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
|
||||
|
|
@ -7,7 +7,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -29,7 +29,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/PharLapCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
@ -79,7 +79,8 @@ def getPharLapVersion():
|
|||
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
|
||||
if not os.path.exists(include_path):
|
||||
raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?")
|
||||
mo = REGEX_ETS_VER.search(open(include_path, 'r').read())
|
||||
with open(include_path, 'r') as f:
|
||||
mo = REGEX_ETS_VER.search(f.read())
|
||||
if mo:
|
||||
return int(mo.group(1))
|
||||
# Default return for Phar Lap 9.1
|
868
scons/scons-local-4.1.0/SCons/Tool/__init__.py
Normal file
868
scons/scons-local-4.1.0/SCons/Tool/__init__.py
Normal file
|
@ -0,0 +1,868 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""SCons.Tool
|
||||
|
||||
SCons tool selection.
|
||||
|
||||
This looks for modules that define a callable object that can modify
|
||||
a construction environment as appropriate for a given tool (or tool
|
||||
chain).
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "tool specification" in an arbitrary callable function. No
|
||||
one needs to use or tie in to this subsystem in order to roll their own
|
||||
tool specifications.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import importlib.util
|
||||
|
||||
import SCons.Builder
|
||||
import SCons.Errors
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
import SCons.Scanner.C
|
||||
import SCons.Scanner.D
|
||||
import SCons.Scanner.LaTeX
|
||||
import SCons.Scanner.Prog
|
||||
import SCons.Scanner.SWIG
|
||||
from SCons.Tool.linkCommon import LibSymlinksActionFunction, LibSymlinksStrFun
|
||||
|
||||
DefaultToolpath = []
|
||||
|
||||
CScanner = SCons.Scanner.C.CScanner()
|
||||
DScanner = SCons.Scanner.D.DScanner()
|
||||
LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
|
||||
PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner()
|
||||
ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
|
||||
SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
|
||||
SWIGScanner = SCons.Scanner.SWIG.SWIGScanner()
|
||||
|
||||
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
|
||||
".h", ".H", ".hxx", ".hpp", ".hh",
|
||||
".F", ".fpp", ".FPP",
|
||||
".m", ".mm",
|
||||
".S", ".spp", ".SPP", ".sx"]
|
||||
|
||||
DSuffixes = ['.d']
|
||||
|
||||
IDLSuffixes = [".idl", ".IDL"]
|
||||
|
||||
LaTeXSuffixes = [".tex", ".ltx", ".latex"]
|
||||
|
||||
SWIGSuffixes = ['.i']
|
||||
|
||||
for suffix in CSuffixes:
|
||||
SourceFileScanner.add_scanner(suffix, CScanner)
|
||||
|
||||
for suffix in DSuffixes:
|
||||
SourceFileScanner.add_scanner(suffix, DScanner)
|
||||
|
||||
for suffix in SWIGSuffixes:
|
||||
SourceFileScanner.add_scanner(suffix, SWIGScanner)
|
||||
|
||||
# FIXME: what should be done here? Two scanners scan the same extensions,
|
||||
# but look for different files, e.g., "picture.eps" vs. "picture.pdf".
|
||||
# The builders for DVI and PDF explicitly reference their scanners
|
||||
# I think that means this is not needed???
|
||||
for suffix in LaTeXSuffixes:
|
||||
SourceFileScanner.add_scanner(suffix, LaTeXScanner)
|
||||
SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
|
||||
|
||||
# Tool aliases are needed for those tools whose module names also
|
||||
# occur in the python standard library (This causes module shadowing and
|
||||
# can break using python library functions under python3) or if the current tool/file names
|
||||
# are not legal module names (violate python's identifier rules or are
|
||||
# python language keywords).
|
||||
TOOL_ALIASES = {
|
||||
'gettext': 'gettext_tool',
|
||||
'clang++': 'clangxx',
|
||||
'as': 'asm',
|
||||
}
|
||||
|
||||
|
||||
class Tool:
|
||||
def __init__(self, name, toolpath=None, **kw):
|
||||
if toolpath is None:
|
||||
toolpath = []
|
||||
|
||||
# Rename if there's a TOOL_ALIAS for this tool
|
||||
self.name = TOOL_ALIASES.get(name, name)
|
||||
self.toolpath = toolpath + DefaultToolpath
|
||||
# remember these so we can merge them into the call
|
||||
self.init_kw = kw
|
||||
|
||||
module = self._tool_module()
|
||||
self.generate = module.generate
|
||||
self.exists = module.exists
|
||||
if hasattr(module, 'options'):
|
||||
self.options = module.options
|
||||
|
||||
def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None):
|
||||
import imp
|
||||
|
||||
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):
|
||||
oldpythonpath = sys.path
|
||||
sys.path = self.toolpath + sys.path
|
||||
# sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path))
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# 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:
|
||||
continue
|
||||
|
||||
if spec is None:
|
||||
if debug: sys.stderr.write("NO SPEC :%s\n" % self.name)
|
||||
spec = importlib.util.find_spec("." + self.name, package='SCons.Tool')
|
||||
if spec:
|
||||
found_name = 'SCons.Tool.' + self.name
|
||||
add_to_scons_tools_namespace = True
|
||||
if debug: sys.stderr.write("Spec Found? .%s :%s\n" % (self.name, spec))
|
||||
|
||||
if spec is None:
|
||||
sconstools = os.path.normpath(sys.modules['SCons.Tool'].__path__[0])
|
||||
if self.toolpath:
|
||||
sconstools = ", ".join(self.toolpath) + ", " + sconstools
|
||||
error_string = "No tool module '%s' found in %s" % (self.name, sconstools)
|
||||
raise SCons.Errors.UserError(error_string)
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
if module is None:
|
||||
if debug: print("MODULE IS NONE:%s" % self.name)
|
||||
error_string = "Tool module '%s' failed import" % self.name
|
||||
raise SCons.Errors.SConsEnvironmentError(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
|
||||
try:
|
||||
return sys.modules[full_name]
|
||||
except KeyError:
|
||||
try:
|
||||
smpath = sys.modules['SCons.Tool'].__path__
|
||||
try:
|
||||
module, file = self._load_dotted_module_py2(self.name, full_name, smpath)
|
||||
setattr(SCons.Tool, self.name, module)
|
||||
if file:
|
||||
file.close()
|
||||
return module
|
||||
except ImportError as e:
|
||||
if str(e) != "No module named %s" % self.name:
|
||||
raise SCons.Errors.SConsEnvironmentError(e)
|
||||
try:
|
||||
import zipimport
|
||||
importer = zipimport.zipimporter(sys.modules['SCons.Tool'].__path__[0])
|
||||
module = importer.load_module(full_name)
|
||||
setattr(SCons.Tool, self.name, module)
|
||||
return module
|
||||
except ImportError as e:
|
||||
m = "No tool named '%s': %s" % (self.name, e)
|
||||
raise SCons.Errors.SConsEnvironmentError(m)
|
||||
except ImportError as e:
|
||||
m = "No tool named '%s': %s" % (self.name, e)
|
||||
raise SCons.Errors.SConsEnvironmentError(m)
|
||||
|
||||
def __call__(self, env, *args, **kw):
|
||||
if self.init_kw is not None:
|
||||
# Merge call kws into init kws;
|
||||
# but don't bash self.init_kw.
|
||||
if kw is not None:
|
||||
call_kw = kw
|
||||
kw = self.init_kw.copy()
|
||||
kw.update(call_kw)
|
||||
else:
|
||||
kw = self.init_kw
|
||||
env.Append(TOOLS=[self.name])
|
||||
if hasattr(self, 'options'):
|
||||
import SCons.Variables
|
||||
if 'options' not in env:
|
||||
from SCons.Script import ARGUMENTS
|
||||
env['options'] = SCons.Variables.Variables(args=ARGUMENTS)
|
||||
opts = env['options']
|
||||
|
||||
self.options(opts)
|
||||
opts.Update(env)
|
||||
|
||||
self.generate(env, *args, **kw)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Create common executable program / library / object builders
|
||||
|
||||
def createProgBuilder(env):
|
||||
"""This is a utility function that creates the Program
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
"""
|
||||
|
||||
try:
|
||||
program = env['BUILDERS']['Program']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
program = SCons.Builder.Builder(action=SCons.Defaults.LinkAction,
|
||||
emitter='$PROGEMITTER',
|
||||
prefix='$PROGPREFIX',
|
||||
suffix='$PROGSUFFIX',
|
||||
src_suffix='$OBJSUFFIX',
|
||||
src_builder='Object',
|
||||
target_scanner=ProgramScanner)
|
||||
env['BUILDERS']['Program'] = program
|
||||
|
||||
return program
|
||||
|
||||
|
||||
def createStaticLibBuilder(env):
|
||||
"""This is a utility function that creates the StaticLibrary
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
"""
|
||||
|
||||
try:
|
||||
static_lib = env['BUILDERS']['StaticLibrary']
|
||||
except KeyError:
|
||||
action_list = [SCons.Action.Action("$ARCOM", "$ARCOMSTR")]
|
||||
if env.get('RANLIB', False) or env.Detect('ranlib'):
|
||||
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
|
||||
action_list.append(ranlib_action)
|
||||
|
||||
static_lib = SCons.Builder.Builder(action=action_list,
|
||||
emitter='$LIBEMITTER',
|
||||
prefix='$LIBPREFIX',
|
||||
suffix='$LIBSUFFIX',
|
||||
src_suffix='$OBJSUFFIX',
|
||||
src_builder='StaticObject')
|
||||
env['BUILDERS']['StaticLibrary'] = static_lib
|
||||
env['BUILDERS']['Library'] = static_lib
|
||||
|
||||
return static_lib
|
||||
|
||||
|
||||
def createSharedLibBuilder(env, shlib_suffix='$_SHLIBSUFFIX'):
|
||||
"""This is a utility function that creates the SharedLibrary
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
|
||||
Args:
|
||||
shlib_suffix: The suffix specified for the shared library builder
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
shared_lib = env['BUILDERS']['SharedLibrary']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
action_list = [SCons.Defaults.SharedCheck,
|
||||
SCons.Defaults.ShLinkAction,
|
||||
LibSymlinksAction]
|
||||
shared_lib = SCons.Builder.Builder(action=action_list,
|
||||
emitter="$SHLIBEMITTER",
|
||||
prefix="$SHLIBPREFIX",
|
||||
suffix=shlib_suffix,
|
||||
target_scanner=ProgramScanner,
|
||||
src_suffix='$SHOBJSUFFIX',
|
||||
src_builder='SharedObject')
|
||||
env['BUILDERS']['SharedLibrary'] = shared_lib
|
||||
|
||||
return shared_lib
|
||||
|
||||
|
||||
def createLoadableModuleBuilder(env, loadable_module_suffix='$_LDMODULESUFFIX'):
|
||||
"""This is a utility function that creates the LoadableModule
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
|
||||
Args:
|
||||
loadable_module_suffix: The suffix specified for the loadable module builder
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
ld_module = env['BUILDERS']['LoadableModule']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
action_list = [SCons.Defaults.SharedCheck,
|
||||
SCons.Defaults.LdModuleLinkAction,
|
||||
LibSymlinksAction]
|
||||
ld_module = SCons.Builder.Builder(action=action_list,
|
||||
emitter="$LDMODULEEMITTER",
|
||||
prefix="$LDMODULEPREFIX",
|
||||
suffix=loadable_module_suffix,
|
||||
target_scanner=ProgramScanner,
|
||||
src_suffix='$SHOBJSUFFIX',
|
||||
src_builder='SharedObject')
|
||||
env['BUILDERS']['LoadableModule'] = ld_module
|
||||
|
||||
return ld_module
|
||||
|
||||
|
||||
def createObjBuilders(env):
|
||||
"""This is a utility function that creates the StaticObject
|
||||
and SharedObject Builders in an Environment if they
|
||||
are not there already.
|
||||
|
||||
If they are there already, we return the existing ones.
|
||||
|
||||
This is a separate function because soooo many Tools
|
||||
use this functionality.
|
||||
|
||||
The return is a 2-tuple of (StaticObject, SharedObject)
|
||||
"""
|
||||
|
||||
try:
|
||||
static_obj = env['BUILDERS']['StaticObject']
|
||||
except KeyError:
|
||||
static_obj = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
prefix='$OBJPREFIX',
|
||||
suffix='$OBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=1)
|
||||
env['BUILDERS']['StaticObject'] = static_obj
|
||||
env['BUILDERS']['Object'] = static_obj
|
||||
|
||||
try:
|
||||
shared_obj = env['BUILDERS']['SharedObject']
|
||||
except KeyError:
|
||||
shared_obj = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
prefix='$SHOBJPREFIX',
|
||||
suffix='$SHOBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=1)
|
||||
env['BUILDERS']['SharedObject'] = shared_obj
|
||||
|
||||
return (static_obj, shared_obj)
|
||||
|
||||
|
||||
def createCFileBuilders(env):
|
||||
"""This is a utility function that creates the CFile/CXXFile
|
||||
Builders in an Environment if they
|
||||
are not there already.
|
||||
|
||||
If they are there already, we return the existing ones.
|
||||
|
||||
This is a separate function because soooo many Tools
|
||||
use this functionality.
|
||||
|
||||
The return is a 2-tuple of (CFile, CXXFile)
|
||||
"""
|
||||
|
||||
try:
|
||||
c_file = env['BUILDERS']['CFile']
|
||||
except KeyError:
|
||||
c_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$CFILESUFFIX'})
|
||||
env['BUILDERS']['CFile'] = c_file
|
||||
|
||||
env.SetDefault(CFILESUFFIX='.c')
|
||||
|
||||
try:
|
||||
cxx_file = env['BUILDERS']['CXXFile']
|
||||
except KeyError:
|
||||
cxx_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$CXXFILESUFFIX'})
|
||||
env['BUILDERS']['CXXFile'] = cxx_file
|
||||
env.SetDefault(CXXFILESUFFIX='.cc')
|
||||
|
||||
return (c_file, cxx_file)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Create common Java builders
|
||||
|
||||
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:
|
||||
java_jar = env['BUILDERS']['JarFile']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
|
||||
java_jar = SCons.Builder.Builder(action=jar_com,
|
||||
suffix='$JARSUFFIX',
|
||||
src_suffix='$JAVACLASSSUFFIX',
|
||||
src_builder='JavaClassFile',
|
||||
source_factory=fs.Entry)
|
||||
env['BUILDERS']['JarFile'] = java_jar
|
||||
return java_jar
|
||||
|
||||
|
||||
def CreateJavaHBuilder(env):
|
||||
try:
|
||||
java_javah = env['BUILDERS']['JavaH']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
|
||||
java_javah = SCons.Builder.Builder(action=java_javah_com,
|
||||
src_suffix='$JAVACLASSSUFFIX',
|
||||
target_factory=fs.Entry,
|
||||
source_factory=fs.File,
|
||||
src_builder='JavaClassFile')
|
||||
env['BUILDERS']['JavaH'] = java_javah
|
||||
return java_javah
|
||||
|
||||
|
||||
def CreateJavaClassFileBuilder(env):
|
||||
try:
|
||||
java_class_file = env['BUILDERS']['JavaClassFile']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
|
||||
java_class_file = SCons.Builder.Builder(action=javac_com,
|
||||
emitter={},
|
||||
# suffix = '$JAVACLASSSUFFIX',
|
||||
src_suffix='$JAVASUFFIX',
|
||||
src_builder=['JavaFile'],
|
||||
target_factory=fs.Entry,
|
||||
source_factory=fs.File)
|
||||
env['BUILDERS']['JavaClassFile'] = java_class_file
|
||||
return java_class_file
|
||||
|
||||
|
||||
def CreateJavaClassDirBuilder(env):
|
||||
try:
|
||||
java_class_dir = env['BUILDERS']['JavaClassDir']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
|
||||
java_class_dir = SCons.Builder.Builder(action=javac_com,
|
||||
emitter={},
|
||||
target_factory=fs.Dir,
|
||||
source_factory=fs.Dir)
|
||||
env['BUILDERS']['JavaClassDir'] = java_class_dir
|
||||
return java_class_dir
|
||||
|
||||
|
||||
def CreateJavaFileBuilder(env):
|
||||
try:
|
||||
java_file = env['BUILDERS']['JavaFile']
|
||||
except KeyError:
|
||||
java_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$JAVASUFFIX'})
|
||||
env['BUILDERS']['JavaFile'] = java_file
|
||||
env['JAVASUFFIX'] = '.java'
|
||||
return java_file
|
||||
|
||||
|
||||
class ToolInitializerMethod:
|
||||
"""
|
||||
This is added to a construction environment in place of a
|
||||
method(s) normally called for a Builder (env.Object, env.StaticObject,
|
||||
etc.). When called, it has its associated ToolInitializer
|
||||
object search the specified list of tools and apply the first
|
||||
one that exists to the construction environment. It then calls
|
||||
whatever builder was (presumably) added to the construction
|
||||
environment in place of this particular instance.
|
||||
"""
|
||||
|
||||
def __init__(self, name, initializer):
|
||||
"""
|
||||
Note: we store the tool name as __name__ so it can be used by
|
||||
the class that attaches this to a construction environment.
|
||||
"""
|
||||
self.__name__ = name
|
||||
self.initializer = initializer
|
||||
|
||||
def get_builder(self, env):
|
||||
"""
|
||||
Returns the appropriate real Builder for this method name
|
||||
after having the associated ToolInitializer object apply
|
||||
the appropriate Tool module.
|
||||
"""
|
||||
builder = getattr(env, self.__name__)
|
||||
|
||||
self.initializer.apply_tools(env)
|
||||
|
||||
builder = getattr(env, self.__name__)
|
||||
if builder is self:
|
||||
# There was no Builder added, which means no valid Tool
|
||||
# for this name was found (or possibly there's a mismatch
|
||||
# between the name we were called by and the Builder name
|
||||
# added by the Tool module).
|
||||
return None
|
||||
|
||||
self.initializer.remove_methods(env)
|
||||
|
||||
return builder
|
||||
|
||||
def __call__(self, env, *args, **kw):
|
||||
"""
|
||||
"""
|
||||
builder = self.get_builder(env)
|
||||
if builder is None:
|
||||
return [], []
|
||||
return builder(*args, **kw)
|
||||
|
||||
|
||||
class ToolInitializer:
|
||||
"""
|
||||
A class for delayed initialization of Tools modules.
|
||||
|
||||
Instances of this class associate a list of Tool modules with
|
||||
a list of Builder method names that will be added by those Tool
|
||||
modules. As part of instantiating this object for a particular
|
||||
construction environment, we also add the appropriate
|
||||
ToolInitializerMethod objects for the various Builder methods
|
||||
that we want to use to delay Tool searches until necessary.
|
||||
"""
|
||||
|
||||
def __init__(self, env, tools, names):
|
||||
if not SCons.Util.is_List(tools):
|
||||
tools = [tools]
|
||||
if not SCons.Util.is_List(names):
|
||||
names = [names]
|
||||
self.env = env
|
||||
self.tools = tools
|
||||
self.names = names
|
||||
self.methods = {}
|
||||
for name in names:
|
||||
method = ToolInitializerMethod(name, self)
|
||||
self.methods[name] = method
|
||||
env.AddMethod(method)
|
||||
|
||||
def remove_methods(self, env):
|
||||
"""
|
||||
Removes the methods that were added by the tool initialization
|
||||
so we no longer copy and re-bind them when the construction
|
||||
environment gets cloned.
|
||||
"""
|
||||
for method in self.methods.values():
|
||||
env.RemoveMethod(method)
|
||||
|
||||
def apply_tools(self, env):
|
||||
"""
|
||||
Searches the list of associated Tool modules for one that
|
||||
exists, and applies that to the construction environment.
|
||||
"""
|
||||
for t in self.tools:
|
||||
tool = SCons.Tool.Tool(t)
|
||||
if tool.exists(env):
|
||||
env.Tool(tool)
|
||||
return
|
||||
|
||||
# If we fall through here, there was no tool module found.
|
||||
# This is where we can put an informative error message
|
||||
# about the inability to find the tool. We'll start doing
|
||||
# this as we cut over more pre-defined Builder+Tools to use
|
||||
# the ToolInitializer class.
|
||||
|
||||
|
||||
def Initializers(env):
|
||||
ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib'])
|
||||
|
||||
def Install(self, *args, **kw):
|
||||
return self._InternalInstall(*args, **kw)
|
||||
|
||||
def InstallAs(self, *args, **kw):
|
||||
return self._InternalInstallAs(*args, **kw)
|
||||
|
||||
def InstallVersionedLib(self, *args, **kw):
|
||||
return self._InternalInstallVersionedLib(*args, **kw)
|
||||
|
||||
env.AddMethod(Install)
|
||||
env.AddMethod(InstallAs)
|
||||
env.AddMethod(InstallVersionedLib)
|
||||
|
||||
|
||||
def FindTool(tools, env):
|
||||
for tool in tools:
|
||||
t = Tool(tool)
|
||||
if t.exists(env):
|
||||
return tool
|
||||
return None
|
||||
|
||||
|
||||
def FindAllTools(tools, env):
|
||||
def ToolExists(tool, env=env):
|
||||
return Tool(tool).exists(env)
|
||||
|
||||
return list(filter(ToolExists, tools))
|
||||
|
||||
|
||||
def tool_list(platform, env):
|
||||
other_plat_tools = []
|
||||
# XXX this logic about what tool to prefer on which platform
|
||||
# should be moved into either the platform files or
|
||||
# the tool files themselves.
|
||||
# The search orders here are described in the man page. If you
|
||||
# change these search orders, update the man page as well.
|
||||
if str(platform) == 'win32':
|
||||
"prefer Microsoft tools on Windows"
|
||||
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32']
|
||||
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32']
|
||||
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32']
|
||||
assemblers = ['masm', 'nasm', 'gas', '386asm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
|
||||
ars = ['mslib', 'ar', 'tlib']
|
||||
other_plat_tools = ['msvs', 'midl', 'wix']
|
||||
elif str(platform) == 'os2':
|
||||
"prefer IBM tools on OS/2"
|
||||
linkers = ['ilink', 'gnulink', ] # 'mslink']
|
||||
c_compilers = ['icc', 'gcc', ] # 'msvc', 'cc']
|
||||
cxx_compilers = ['icc', 'g++', ] # 'msvc', 'cxx']
|
||||
assemblers = ['nasm', ] # 'masm', 'gas']
|
||||
fortran_compilers = ['ifl', 'g77']
|
||||
ars = ['ar', ] # 'mslib']
|
||||
elif str(platform) == 'irix':
|
||||
"prefer MIPSPro on IRIX"
|
||||
linkers = ['sgilink', 'gnulink']
|
||||
c_compilers = ['sgicc', 'gcc', 'cc']
|
||||
cxx_compilers = ['sgicxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
|
||||
ars = ['sgiar']
|
||||
elif str(platform) == 'sunos':
|
||||
"prefer Forte tools on SunOS"
|
||||
linkers = ['sunlink', 'gnulink']
|
||||
c_compilers = ['suncc', 'gcc', 'cc']
|
||||
cxx_compilers = ['suncxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
|
||||
'gfortran', 'g77', 'fortran']
|
||||
ars = ['sunar']
|
||||
elif str(platform) == 'hpux':
|
||||
"prefer aCC tools on HP-UX"
|
||||
linkers = ['hplink', 'gnulink']
|
||||
c_compilers = ['hpcc', 'gcc', 'cc']
|
||||
cxx_compilers = ['hpcxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'aix':
|
||||
"prefer AIX Visual Age tools on AIX"
|
||||
linkers = ['aixlink', 'gnulink']
|
||||
c_compilers = ['aixcc', 'gcc', 'cc']
|
||||
cxx_compilers = ['aixcxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'darwin':
|
||||
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
|
||||
linkers = ['applelink', 'gnulink']
|
||||
c_compilers = ['gcc', 'cc']
|
||||
cxx_compilers = ['g++', 'cxx']
|
||||
assemblers = ['as']
|
||||
fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'cygwin':
|
||||
"prefer GNU tools on Cygwin, except for a platform-specific linker"
|
||||
linkers = ['cyglink', 'mslink', 'ilink']
|
||||
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
|
||||
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx']
|
||||
assemblers = ['gas', 'nasm', 'masm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
|
||||
ars = ['ar', 'mslib']
|
||||
else:
|
||||
"prefer GNU tools on all other platforms"
|
||||
linkers = ['gnulink', 'ilink']
|
||||
c_compilers = ['gcc', 'intelc', 'icc', 'cc']
|
||||
cxx_compilers = ['g++', 'intelc', 'icc', 'cxx']
|
||||
assemblers = ['gas', 'nasm', 'masm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
|
||||
ars = ['ar', ]
|
||||
|
||||
if not str(platform) == 'win32':
|
||||
other_plat_tools += ['m4', 'rpm']
|
||||
|
||||
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
|
||||
|
||||
# XXX this logic about what tool provides what should somehow be
|
||||
# moved into the tool files themselves.
|
||||
if c_compiler and c_compiler == 'mingw':
|
||||
# MinGW contains a linker, C compiler, C++ compiler,
|
||||
# Fortran compiler, archiver and assembler:
|
||||
cxx_compiler = None
|
||||
linker = None
|
||||
assembler = None
|
||||
fortran_compiler = None
|
||||
ar = None
|
||||
else:
|
||||
# Don't use g++ if the C compiler has built-in C++ support:
|
||||
if c_compiler in ('msvc', 'intelc', 'icc'):
|
||||
cxx_compiler = None
|
||||
else:
|
||||
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
|
||||
linker = FindTool(linkers, env) or linkers[0]
|
||||
assembler = FindTool(assemblers, env) or assemblers[0]
|
||||
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
|
||||
ar = FindTool(ars, env) or ars[0]
|
||||
|
||||
d_compilers = ['dmd', 'ldc', 'gdc']
|
||||
d_compiler = FindTool(d_compilers, env) or d_compilers[0]
|
||||
|
||||
other_tools = FindAllTools(other_plat_tools + [
|
||||
# TODO: merge 'install' into 'filesystem' and
|
||||
# make 'filesystem' the default
|
||||
'filesystem',
|
||||
# Parser generators
|
||||
'lex', 'yacc',
|
||||
# Foreign function interface
|
||||
'rpcgen', 'swig',
|
||||
# Java
|
||||
'jar', 'javac', 'javah', 'rmic',
|
||||
# TeX
|
||||
'dvipdf', 'dvips', 'gs',
|
||||
'tex', 'latex', 'pdflatex', 'pdftex',
|
||||
# Archivers
|
||||
'tar', 'zip',
|
||||
# File builders (text)
|
||||
'textfile',
|
||||
], env)
|
||||
|
||||
tools = [
|
||||
linker,
|
||||
c_compiler,
|
||||
cxx_compiler,
|
||||
fortran_compiler,
|
||||
assembler,
|
||||
ar,
|
||||
d_compiler,
|
||||
] + other_tools
|
||||
|
||||
return [x for x in tools if x]
|
||||
|
||||
|
||||
def find_program_path(env, key_program, default_paths=None):
|
||||
"""
|
||||
Find the location of a tool using various means.
|
||||
|
||||
Mainly for windows where tools aren't all installed in /usr/bin, etc.
|
||||
|
||||
:param env: Current Construction Environment.
|
||||
:param key_program: Tool to locate.
|
||||
:param default_paths: List of additional paths this tool might be found in.
|
||||
"""
|
||||
# First search in the SCons path
|
||||
path = env.WhereIs(key_program)
|
||||
if path:
|
||||
return path
|
||||
|
||||
# Then in the OS path
|
||||
path = SCons.Util.WhereIs(key_program)
|
||||
if path:
|
||||
return path
|
||||
|
||||
# Finally, add the defaults and check again. Do not change
|
||||
# ['ENV']['PATH'] permananetly, the caller can do that if needed.
|
||||
if default_paths is None:
|
||||
return path
|
||||
save_path = env['ENV']['PATH']
|
||||
for p in default_paths:
|
||||
env.AppendENVPath('PATH', p)
|
||||
path = env.WhereIs(key_program)
|
||||
env['ENV']['PATH'] = save_path
|
||||
return path
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -9,7 +9,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,7 +31,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/aixc++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.aixcxx import *
|
|
@ -8,7 +8,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -30,7 +30,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/aixcc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
|
@ -9,7 +9,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,7 +31,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/aixcxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
"""engine.SCons.Tool.aixf77
|
||||
"""SCons.Tool.aixf77
|
||||
|
||||
Tool-specific initialization for IBM Visual Age f77 Fortran compiler.
|
||||
|
||||
|
@ -8,7 +8,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -30,7 +30,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/aixf77.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
|
@ -7,8 +7,6 @@ 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
|
||||
|
@ -30,8 +28,6 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/aixlink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
|
@ -42,7 +38,6 @@ from . import link
|
|||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
||||
|
||||
|
||||
def smart_linkflags(source, target, env, for_signature):
|
||||
|
@ -52,6 +47,7 @@ def smart_linkflags(source, target, env, for_signature):
|
|||
return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
|
||||
return ''
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age linker to
|
||||
|
@ -64,12 +60,13 @@ def generate(env):
|
|||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218')
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
|
||||
|
||||
def exists(env):
|
||||
# TODO: sync with link.smart_link() to choose a linker
|
||||
linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
|
||||
alltools = []
|
||||
for langvar, linktools in linkers.items():
|
||||
if langvar in env: # use CC over CXX when user specified CC but not CXX
|
||||
if langvar in env: # use CC over CXX when user specified CC but not CXX
|
||||
return SCons.Tool.FindTool(linktools, env)
|
||||
alltools.extend(linktools)
|
||||
return SCons.Tool.FindTool(alltools, env)
|
189
scons/scons-local-4.1.0/SCons/Tool/applelink.py
Normal file
189
scons/scons-local-4.1.0/SCons/Tool/applelink.py
Normal file
|
@ -0,0 +1,189 @@
|
|||
"""SCons.Tool.applelink
|
||||
|
||||
Tool-specific initialization for Apple's gnu-like linker.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright 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.
|
||||
#
|
||||
|
||||
# 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".
|
||||
from SCons.Util import CLVar
|
||||
|
||||
from . import link
|
||||
|
||||
# User programmatically describes how SHLIBVERSION maps to values for compat/current.
|
||||
_APPLELIB_MAX_VERSION_VALUES = (65535, 255, 255)
|
||||
|
||||
|
||||
class AppleLinkInvalidCurrentVersionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AppleLinkInvalidCompatibilityVersionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _applelib_check_valid_version(version_string):
|
||||
"""
|
||||
Check that the version # is valid.
|
||||
X[.Y[.Z]]
|
||||
where X 0-65535
|
||||
where Y either not specified or 0-255
|
||||
where Z either not specified or 0-255
|
||||
:param version_string:
|
||||
:return:
|
||||
"""
|
||||
parts = version_string.split('.')
|
||||
if len(parts) > 3:
|
||||
return False, "Version string has too many periods [%s]" % version_string
|
||||
if len(parts) <= 0:
|
||||
return False, "Version string unspecified [%s]" % version_string
|
||||
|
||||
for (i, p) in enumerate(parts):
|
||||
try:
|
||||
p_i = int(p)
|
||||
except ValueError:
|
||||
return False, "Version component %s (from %s) is not a number" % (p, version_string)
|
||||
if p_i < 0 or p_i > _APPLELIB_MAX_VERSION_VALUES[i]:
|
||||
return False, "Version component %s (from %s) is not valid value should be between 0 and %d" % (
|
||||
p, version_string, _APPLELIB_MAX_VERSION_VALUES[i])
|
||||
|
||||
return True, ""
|
||||
|
||||
|
||||
def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-current_version flag if needed.
|
||||
If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
|
||||
will be used.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the current_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_CURRENT_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_CURRENT_VERSION', False):
|
||||
version_string = env['APPLELINK_CURRENT_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = env['SHLIBVERSION']
|
||||
else:
|
||||
return ""
|
||||
|
||||
version_string = ".".join(version_string.split('.')[:3])
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCurrentVersionException(reason)
|
||||
|
||||
return "-Wl,-current_version,%s" % version_string
|
||||
|
||||
|
||||
def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-compatibility_version flag if needed.
|
||||
If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
|
||||
the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the compatibility_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
|
||||
version_string = env['APPLELINK_COMPATIBILITY_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
|
||||
else:
|
||||
return ""
|
||||
|
||||
if version_string is None:
|
||||
return ""
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCompatibilityVersionException(reason)
|
||||
|
||||
return "-Wl,-compatibility_version,%s" % version_string
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for applelink to an
|
||||
Environment."""
|
||||
link.generate(env)
|
||||
|
||||
env['FRAMEWORKPATHPREFIX'] = '-F'
|
||||
env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
|
||||
|
||||
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
|
||||
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
env['SHLINKFLAGS'] = CLVar('$LINKFLAGS -dynamiclib')
|
||||
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
|
||||
env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
|
||||
env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
|
||||
# override the default for loadable modules, which are different
|
||||
# on OS X than dynamic shared libs. echoing what XCode does for
|
||||
# pre/suffixes:
|
||||
env['LDMODULEPREFIX'] = ''
|
||||
env['LDMODULESUFFIX'] = ''
|
||||
env['LDMODULEFLAGS'] = CLVar('$LINKFLAGS -bundle')
|
||||
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS' \
|
||||
' $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
# New stuff
|
||||
#
|
||||
env['_SHLIBSUFFIX'] = '${_SHLIBVERSION}${SHLIBSUFFIX}'
|
||||
|
||||
env['__SHLIBVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
|
||||
'"SHLIBVERSION","_APPLELINK_CURRENT_VERSION", "_SHLIBVERSIONFLAGS")}'
|
||||
env['__LDMODULEVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
|
||||
'"LDMODULEVERSION","_APPLELINK_CURRENT_VERSION", "_LDMODULEVERSIONFLAGS")}'
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env['PLATFORM'] == 'darwin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
@ -9,7 +9,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,7 +31,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/ar.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
|
@ -1,5 +1,14 @@
|
|||
"""SCons.Tool.as
|
||||
|
||||
Tool-specific initialization for generic assembler.
|
||||
|
||||
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
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -21,27 +30,17 @@
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Options/ListOption.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Place-holder for the old SCons.Options module hierarchy
|
||||
#
|
||||
# forward proxy to the preferred asm version
|
||||
#
|
||||
import SCons.Tool.asm
|
||||
|
||||
This is for backwards compatibility. The new equivalent is the Variables/
|
||||
class hierarchy. These will have deprecation warnings added (some day),
|
||||
and will then be removed entirely (some day).
|
||||
"""
|
||||
# Resolve FLAKE8 F401 (make sider happy)
|
||||
generate = SCons.Tool.asm.generate
|
||||
exists = SCons.Tool.asm.exists
|
||||
|
||||
import SCons.Variables
|
||||
import SCons.Warnings
|
||||
|
||||
warned = False
|
||||
|
||||
def ListOption(*args, **kw):
|
||||
global warned
|
||||
if not warned:
|
||||
msg = "The ListOption() function is deprecated; use the ListVariable() function instead."
|
||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
|
||||
warned = True
|
||||
return SCons.Variables.ListVariable(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
|
@ -9,7 +9,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -31,7 +31,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/as.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
|
@ -5,7 +5,7 @@ XXX
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -27,7 +27,7 @@ XXX
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/bcc32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
|
@ -8,7 +8,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -30,7 +30,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/c++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
#forward proxy to the preffered cxx version
|
|
@ -8,7 +8,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -30,7 +30,7 @@ selection method.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/cc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Defaults
|
|
@ -1,17 +1,8 @@
|
|||
# -*- 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
|
||||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -32,8 +23,16 @@ selection method.
|
|||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
"""SCons.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.
|
||||
|
||||
"""
|
||||
|
||||
# __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.
|
||||
|
@ -45,6 +44,9 @@ import sys
|
|||
|
||||
import SCons.Util
|
||||
import SCons.Tool.cc
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang']
|
||||
|
||||
|
@ -52,11 +54,24 @@ def generate(env):
|
|||
"""Add Builders and construction variables for clang to an Environment."""
|
||||
SCons.Tool.cc.generate(env)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang
|
||||
clang = SCons.Tool.find_program_path(env, compilers[0],
|
||||
default_paths=get_clang_install_dirs(env['PLATFORM']))
|
||||
if clang:
|
||||
clang_bin_dir = os.path.dirname(clang)
|
||||
env.AppendENVPath('PATH', clang_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(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'],
|
||||
|
@ -66,9 +81,9 @@ def generate(env):
|
|||
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()
|
||||
with pipe.stdout:
|
||||
line = pipe.stdout.readline()
|
||||
line = line.decode()
|
||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||
if match:
|
||||
env['CCVERSION'] = match.group(1)
|
18
scons/scons-local-4.1.0/SCons/Tool/clangCommon/__init__.py
Normal file
18
scons/scons-local-4.1.0/SCons/Tool/clangCommon/__init__.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""
|
||||
Common routines and data for clang tools
|
||||
"""
|
||||
|
||||
clang_win32_dirs = [
|
||||
r'C:\Program Files\LLVM\bin',
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\msys64',
|
||||
r'C:\msys64\mingw64\bin',
|
||||
r'C:\cygwin\bin',
|
||||
r'C:\msys',
|
||||
]
|
||||
|
||||
def get_clang_install_dirs(platform):
|
||||
if platform == 'win32':
|
||||
return clang_win32_dirs
|
||||
else:
|
||||
return []
|
|
@ -11,7 +11,7 @@ selection method.
|
|||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -33,7 +33,7 @@ selection method.
|
|||
# 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"
|
||||
# __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
|
||||
# Brought into the SCons mainline by Russel Winder 2017.
|
||||
|
@ -46,6 +46,9 @@ import sys
|
|||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Tool.cxx
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang++']
|
||||
|
||||
|
@ -66,17 +69,30 @@ def generate(env):
|
|||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'sunos':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang++
|
||||
clangxx = SCons.Tool.find_program_path(env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM']))
|
||||
if clangxx:
|
||||
clangxx_bin_dir = os.path.dirname(clangxx)
|
||||
env.AppendENVPath('PATH', clangxx_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(env)
|
||||
|
||||
|
||||
# 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
|
||||
if pipe.wait() != 0:
|
||||
return
|
||||
|
||||
# clang -dumpversion is of no use
|
||||
line = pipe.stdout.readline()
|
||||
if sys.version_info[0] > 2:
|
||||
line = line.decode()
|
||||
with pipe.stdout:
|
||||
line = pipe.stdout.readline()
|
||||
line = line.decode()
|
||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||
if match:
|
||||
env['CXXVERSION'] = match.group(1)
|
255
scons/scons-local-4.1.0/SCons/Tool/compilation_db.py
Normal file
255
scons/scons-local-4.1.0/SCons/Tool/compilation_db.py
Normal file
|
@ -0,0 +1,255 @@
|
|||
"""
|
||||
Implements the ability for SCons to emit a compilation database for the MongoDB project. See
|
||||
http://clang.llvm.org/docs/JSONCompilationDatabase.html for details on what a compilation
|
||||
database is, and why you might want one. The only user visible entry point here is
|
||||
'env.CompilationDatabase'. This method takes an optional 'target' to name the file that
|
||||
should hold the compilation database, otherwise, the file defaults to compile_commands.json,
|
||||
which is the name that most clang tools search for by default.
|
||||
"""
|
||||
|
||||
# Copyright 2020 MongoDB Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import json
|
||||
import itertools
|
||||
import fnmatch
|
||||
import SCons
|
||||
|
||||
from .cxx import CXXSuffixes
|
||||
from .cc import CSuffixes
|
||||
from .asm import ASSuffixes, ASPPSuffixes
|
||||
|
||||
# TODO: Is there a better way to do this than this global? Right now this exists so that the
|
||||
# emitter we add can record all of the things it emits, so that the scanner for the top level
|
||||
# compilation database can access the complete list, and also so that the writer has easy
|
||||
# access to write all of the files. But it seems clunky. How can the emitter and the scanner
|
||||
# communicate more gracefully?
|
||||
__COMPILATION_DB_ENTRIES = []
|
||||
|
||||
|
||||
# We make no effort to avoid rebuilding the entries. Someday, perhaps we could and even
|
||||
# integrate with the cache, but there doesn't seem to be much call for it.
|
||||
class __CompilationDbNode(SCons.Node.Python.Value):
|
||||
def __init__(self, value):
|
||||
SCons.Node.Python.Value.__init__(self, value)
|
||||
self.Decider(changed_since_last_build_node)
|
||||
|
||||
def changed_since_last_build_node(child, target, prev_ni, node):
|
||||
""" Dummy decider to force always building"""
|
||||
return True
|
||||
|
||||
|
||||
def make_emit_compilation_DB_entry(comstr):
|
||||
"""
|
||||
Effectively this creates a lambda function to capture:
|
||||
* command line
|
||||
* source
|
||||
* target
|
||||
:param comstr: unevaluated command line
|
||||
:return: an emitter which has captured the above
|
||||
"""
|
||||
user_action = SCons.Action.Action(comstr)
|
||||
|
||||
def emit_compilation_db_entry(target, source, env):
|
||||
"""
|
||||
This emitter will be added to each c/c++ object build to capture the info needed
|
||||
for clang tools
|
||||
:param target: target node(s)
|
||||
:param source: source node(s)
|
||||
:param env: Environment for use building this node
|
||||
:return: target(s), source(s)
|
||||
"""
|
||||
|
||||
dbtarget = __CompilationDbNode(source)
|
||||
|
||||
entry = env.__COMPILATIONDB_Entry(
|
||||
target=dbtarget,
|
||||
source=[],
|
||||
__COMPILATIONDB_UOUTPUT=target,
|
||||
__COMPILATIONDB_USOURCE=source,
|
||||
__COMPILATIONDB_UACTION=user_action,
|
||||
__COMPILATIONDB_ENV=env,
|
||||
)
|
||||
|
||||
# TODO: Technically, these next two lines should not be required: it should be fine to
|
||||
# cache the entries. However, they don't seem to update properly. Since they are quick
|
||||
# to re-generate disable caching and sidestep this problem.
|
||||
env.AlwaysBuild(entry)
|
||||
env.NoCache(entry)
|
||||
|
||||
__COMPILATION_DB_ENTRIES.append(dbtarget)
|
||||
|
||||
return target, source
|
||||
|
||||
return emit_compilation_db_entry
|
||||
|
||||
|
||||
def compilation_db_entry_action(target, source, env, **kw):
|
||||
"""
|
||||
Create a dictionary with evaluated command line, target, source
|
||||
and store that info as an attribute on the target
|
||||
(Which has been stored in __COMPILATION_DB_ENTRIES array
|
||||
:param target: target node(s)
|
||||
:param source: source node(s)
|
||||
:param env: Environment for use building this node
|
||||
:param kw:
|
||||
:return: None
|
||||
"""
|
||||
|
||||
command = env["__COMPILATIONDB_UACTION"].strfunction(
|
||||
target=env["__COMPILATIONDB_UOUTPUT"],
|
||||
source=env["__COMPILATIONDB_USOURCE"],
|
||||
env=env["__COMPILATIONDB_ENV"],
|
||||
)
|
||||
|
||||
entry = {
|
||||
"directory": env.Dir("#").abspath,
|
||||
"command": command,
|
||||
"file": env["__COMPILATIONDB_USOURCE"][0],
|
||||
"output": env['__COMPILATIONDB_UOUTPUT'][0]
|
||||
}
|
||||
|
||||
target[0].write(entry)
|
||||
|
||||
|
||||
def write_compilation_db(target, source, env):
|
||||
entries = []
|
||||
|
||||
use_abspath = env['COMPILATIONDB_USE_ABSPATH'] in [True, 1, 'True', 'true']
|
||||
use_path_filter = env.subst('$COMPILATIONDB_PATH_FILTER')
|
||||
|
||||
for s in __COMPILATION_DB_ENTRIES:
|
||||
entry = s.read()
|
||||
source_file = entry['file']
|
||||
output_file = entry['output']
|
||||
|
||||
if use_abspath:
|
||||
source_file = source_file.srcnode().abspath
|
||||
output_file = output_file.abspath
|
||||
else:
|
||||
source_file = source_file.srcnode().path
|
||||
output_file = output_file.path
|
||||
|
||||
if use_path_filter and not fnmatch.fnmatch(output_file, use_path_filter):
|
||||
continue
|
||||
|
||||
path_entry = {'directory': entry['directory'],
|
||||
'command': entry['command'],
|
||||
'file': source_file,
|
||||
'output': output_file}
|
||||
|
||||
entries.append(path_entry)
|
||||
|
||||
with open(target[0].path, "w") as output_file:
|
||||
json.dump(
|
||||
entries, output_file, sort_keys=True, indent=4, separators=(",", ": ")
|
||||
)
|
||||
|
||||
|
||||
def scan_compilation_db(node, env, path):
|
||||
return __COMPILATION_DB_ENTRIES
|
||||
|
||||
|
||||
def compilation_db_emitter(target, source, env):
|
||||
""" fix up the source/targets """
|
||||
|
||||
# Someone called env.CompilationDatabase('my_targetname.json')
|
||||
if not target and len(source) == 1:
|
||||
target = source
|
||||
|
||||
# Default target name is compilation_db.json
|
||||
if not target:
|
||||
target = ['compile_commands.json', ]
|
||||
|
||||
# No source should have been passed. Drop it.
|
||||
if source:
|
||||
source = []
|
||||
|
||||
return target, source
|
||||
|
||||
|
||||
def generate(env, **kwargs):
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
env["COMPILATIONDB_COMSTR"] = kwargs.get(
|
||||
"COMPILATIONDB_COMSTR", "Building compilation database $TARGET"
|
||||
)
|
||||
|
||||
components_by_suffix = itertools.chain(
|
||||
itertools.product(
|
||||
CSuffixes,
|
||||
[
|
||||
(static_obj, SCons.Defaults.StaticObjectEmitter, "$CCCOM"),
|
||||
(shared_obj, SCons.Defaults.SharedObjectEmitter, "$SHCCCOM"),
|
||||
],
|
||||
),
|
||||
itertools.product(
|
||||
CXXSuffixes,
|
||||
[
|
||||
(static_obj, SCons.Defaults.StaticObjectEmitter, "$CXXCOM"),
|
||||
(shared_obj, SCons.Defaults.SharedObjectEmitter, "$SHCXXCOM"),
|
||||
],
|
||||
),
|
||||
itertools.product(
|
||||
ASSuffixes,
|
||||
[(static_obj, SCons.Defaults.StaticObjectEmitter, "$ASCOM")],
|
||||
[(shared_obj, SCons.Defaults.SharedObjectEmitter, "$ASCOM")],
|
||||
),
|
||||
itertools.product(
|
||||
ASPPSuffixes,
|
||||
[(static_obj, SCons.Defaults.StaticObjectEmitter, "$ASPPCOM")],
|
||||
[(shared_obj, SCons.Defaults.SharedObjectEmitter, "$ASPPCOM")],
|
||||
),
|
||||
)
|
||||
|
||||
for entry in components_by_suffix:
|
||||
suffix = entry[0]
|
||||
builder, base_emitter, command = entry[1]
|
||||
|
||||
# Assumes a dictionary emitter
|
||||
emitter = builder.emitter.get(suffix, False)
|
||||
if emitter:
|
||||
# We may not have tools installed which initialize all or any of
|
||||
# cxx, cc, or assembly. If not skip resetting the respective emitter.
|
||||
builder.emitter[suffix] = SCons.Builder.ListEmitter(
|
||||
[emitter, make_emit_compilation_DB_entry(command), ]
|
||||
)
|
||||
|
||||
env["BUILDERS"]["__COMPILATIONDB_Entry"] = SCons.Builder.Builder(
|
||||
action=SCons.Action.Action(compilation_db_entry_action, None),
|
||||
)
|
||||
|
||||
env["BUILDERS"]["CompilationDatabase"] = SCons.Builder.Builder(
|
||||
action=SCons.Action.Action(write_compilation_db, "$COMPILATIONDB_COMSTR"),
|
||||
target_scanner=SCons.Scanner.Scanner(
|
||||
function=scan_compilation_db, node_class=None
|
||||
),
|
||||
emitter=compilation_db_emitter,
|
||||
suffix='json',
|
||||
)
|
||||
|
||||
env['COMPILATIONDB_USE_ABSPATH'] = False
|
||||
env['COMPILATIONDB_PATH_FILTER'] = ''
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
|
@ -1,11 +1,11 @@
|
|||
"""engine.SCons.Tool.cvf
|
||||
"""SCons.Tool.cvf
|
||||
|
||||
Tool-specific initialization for the Compaq Visual Fortran compiler.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
@ -27,7 +27,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
|
|||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Tool/cvf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import fortran
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue