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:
|
git:
|
||||||
depth: 10
|
depth: 10
|
||||||
|
@ -9,6 +9,7 @@ env:
|
||||||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||||
- CCACHE_COMPRESS=1
|
- CCACHE_COMPRESS=1
|
||||||
- PREFIX=/tmp/mapnik
|
- PREFIX=/tmp/mapnik
|
||||||
|
- PYTHON=python3
|
||||||
- secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
|
- secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
|
@ -28,7 +29,7 @@ matrix:
|
||||||
postgresql: "9.5"
|
postgresql: "9.5"
|
||||||
apt:
|
apt:
|
||||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
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
|
- os: linux
|
||||||
name: Linux clang + coverage
|
name: Linux clang + coverage
|
||||||
env: >-
|
env: >-
|
||||||
|
@ -42,13 +43,14 @@ matrix:
|
||||||
postgresql: "9.5"
|
postgresql: "9.5"
|
||||||
apt:
|
apt:
|
||||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
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
|
- os: osx
|
||||||
name: OSX clang
|
name: OSX clang
|
||||||
# https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
|
#https://docs.travis-ci.com/user/reference/osx#macos-version
|
||||||
osx_image: xcode7.3 # upgrades clang from 6 -> 7
|
osx_image: xcode12.2
|
||||||
env: >-
|
env: >-
|
||||||
CXX="ccache clang++ -Qunused-arguments"
|
CXX="ccache clang++ -Qunused-arguments"
|
||||||
|
before_install:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- source scripts/travis-common.sh
|
- source scripts/travis-common.sh
|
||||||
|
@ -81,6 +83,8 @@ before_script:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- git_submodule_update --init deps/
|
- 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}
|
- 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
|
#- cat config.log => comment out to reduce log size limit on travis-ci
|
||||||
# we limit the `make` to 40 min
|
# 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
|
# License along with this library; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from __future__ import print_function # support python2
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
@ -34,19 +32,8 @@ try:
|
||||||
except:
|
except:
|
||||||
HAS_DISTUTILS = False
|
HAS_DISTUTILS = False
|
||||||
|
|
||||||
try:
|
from shlex import quote as shquote
|
||||||
# Python 3.3+
|
from subprocess import DEVNULL
|
||||||
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')
|
|
||||||
|
|
||||||
LIBDIR_SCHEMA_DEFAULT='lib'
|
LIBDIR_SCHEMA_DEFAULT='lib'
|
||||||
severities = ['debug', 'warn', 'error', 'none']
|
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',
|
'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',
|
'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',
|
'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',
|
'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',
|
'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',
|
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
|
||||||
|
@ -142,7 +129,6 @@ PLUGINS = { # plugins with external dependencies
|
||||||
|
|
||||||
def init_environment(env):
|
def init_environment(env):
|
||||||
env.Decider('MD5-timestamp')
|
env.Decider('MD5-timestamp')
|
||||||
env.SourceCode(".", None)
|
|
||||||
env['ORIGIN'] = Literal('$ORIGIN')
|
env['ORIGIN'] = Literal('$ORIGIN')
|
||||||
env['ENV']['ORIGIN'] = '$ORIGIN'
|
env['ENV']['ORIGIN'] = '$ORIGIN'
|
||||||
if os.environ.get('RANLIB'):
|
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'),
|
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://www.scons.org/wiki/GoFastButton
|
||||||
# http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script
|
# 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'),
|
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)),
|
('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
|
# and thus breaks knowledge below that gdal worked
|
||||||
# TODO - upgrade our scons logic to support Framework linking
|
# TODO - upgrade our scons logic to support Framework linking
|
||||||
if env['PLATFORM'] == 'Darwin':
|
if env['PLATFORM'] == 'Darwin':
|
||||||
if value and b'-framework GDAL' in value:
|
if value and '-framework GDAL' in value:
|
||||||
env['LIBS'].append('gdal')
|
env['LIBS'].append('gdal')
|
||||||
if os.path.exists('/Library/Frameworks/GDAL.framework/unix/lib'):
|
if os.path.exists('/Library/Frameworks/GDAL.framework/unix/lib'):
|
||||||
env['LIBPATH'].insert(0,'/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
|
return version_string
|
||||||
|
|
||||||
if not preconfigured:
|
if not preconfigured:
|
||||||
|
|
||||||
color_print(4,'Configuring build environment...')
|
color_print(4,'Configuring build environment...')
|
||||||
|
|
||||||
if not env['FAST']:
|
|
||||||
SetCacheMode('force')
|
|
||||||
|
|
||||||
if env['USE_CONFIG']:
|
if env['USE_CONFIG']:
|
||||||
if not env['CONFIG'].endswith('.py'):
|
if not env['CONFIG'].endswith('.py'):
|
||||||
color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
|
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')
|
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
|
# Build agg first, doesn't need anything special
|
||||||
if env['RUNTIME_LINK'] == 'shared':
|
if env['RUNTIME_LINK'] == 'shared':
|
||||||
SConscript('deps/agg/build.py')
|
SConscript('deps/agg/build.py')
|
||||||
|
|
|
@ -8,7 +8,7 @@ todo
|
||||||
- shrink icu data
|
- shrink icu data
|
||||||
'
|
'
|
||||||
|
|
||||||
MASON_VERSION="fde1d9f5"
|
MASON_VERSION="edb620c7"
|
||||||
|
|
||||||
function setup_mason() {
|
function setup_mason() {
|
||||||
if [[ ! -d ./.mason ]]; then
|
if [[ ! -d ./.mason ]]; then
|
||||||
|
@ -44,7 +44,7 @@ function install() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ICU_VERSION="57.1"
|
ICU_VERSION="57.1"
|
||||||
BOOST_VERSION="1.73.0"
|
BOOST_VERSION="1.75.0"
|
||||||
|
|
||||||
function install_mason_deps() {
|
function install_mason_deps() {
|
||||||
install ccache 3.3.1
|
install ccache 3.3.1
|
||||||
|
@ -54,7 +54,6 @@ function install_mason_deps() {
|
||||||
install libtiff 4.0.7 libtiff
|
install libtiff 4.0.7 libtiff
|
||||||
install libpq 9.6.2
|
install libpq 9.6.2
|
||||||
install sqlite 3.17.0 libsqlite3
|
install sqlite 3.17.0 libsqlite3
|
||||||
install expat 2.2.0 libexpat
|
|
||||||
install icu ${ICU_VERSION}
|
install icu ${ICU_VERSION}
|
||||||
install proj 4.9.3 libproj
|
install proj 4.9.3 libproj
|
||||||
install pixman 0.34.0 libpixman-1
|
install pixman 0.34.0 libpixman-1
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
This copyright and license do not apply to any other software
|
This copyright and license do not apply to any other software
|
||||||
with which this software may have been included.
|
with which this software may have been included.
|
||||||
|
|
||||||
Copyright (c) 2001 - 2017 The SCons Foundation
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2001 - 2021 The SCons Foundation
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright (c) 2001 - 2021 The SCons Foundation
|
||||||
|
|
||||||
SCons - a software construction tool
|
SCons - a software construction tool
|
||||||
|
|
||||||
|
@ -38,19 +38,20 @@ LATEST VERSION
|
||||||
Before going further, you can check for the latest version of the
|
Before going further, you can check for the latest version of the
|
||||||
scons-local package, or any SCons package, at the SCons download page:
|
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
|
EXECUTION REQUIREMENTS
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Running SCons requires Python version 2.4 or later. There should be
|
Running SCons requires Python 3.5 or higher.
|
||||||
no other dependencies or requirements to run SCons.
|
There should be no other dependencies or requirements to run SCons.
|
||||||
|
|
||||||
The default SCons configuration assumes use of the Microsoft Visual C++
|
The default SCons configuration assumes use of the Microsoft Visual C++
|
||||||
compiler suite on WIN32 systems, and assumes a C compiler named 'cc',
|
compiler suite on WIN32 systems (either through the Visual Studio
|
||||||
a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such
|
product, or through the separate Build Tools), and assumes a C compiler
|
||||||
as found in the GNU C compiler suite) on any other type of system.
|
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
|
You may, of course, override these default values by appropriate
|
||||||
configuration of Environment construction variables.
|
configuration of Environment construction variables.
|
||||||
|
|
||||||
|
@ -157,14 +158,23 @@ available at:
|
||||||
REPORTING BUGS
|
REPORTING BUGS
|
||||||
==============
|
==============
|
||||||
|
|
||||||
You can report bugs either by following the "Tracker - Bugs" link
|
The SCons project welcomes bug reports and feature requests.
|
||||||
on the SCons project page:
|
|
||||||
|
|
||||||
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
|
MAILING LISTS
|
||||||
|
@ -173,11 +183,29 @@ MAILING LISTS
|
||||||
A mailing list for users of SCons is available. You may send questions
|
A mailing list for users of SCons is available. You may send questions
|
||||||
or comments to the list at:
|
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:
|
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
|
FOR MORE INFORMATION
|
||||||
|
@ -188,18 +216,29 @@ Check the SCons web site at:
|
||||||
http://www.scons.org/
|
http://www.scons.org/
|
||||||
|
|
||||||
|
|
||||||
AUTHOR INFO
|
Author Info
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Steven Knight
|
SCons was originally written by Steven Knight, knight at baldmt dot com.
|
||||||
knight at baldmt dot com
|
Since around 2010 it has been maintained by the SCons
|
||||||
http://www.baldmt.com/~knight/
|
development team, co-managed by Bill Deegan and Gary Oberbrunner, with
|
||||||
|
many contributors, including but not at all limited to:
|
||||||
With plenty of help from the SCons Development team:
|
|
||||||
Chad Austin
|
|
||||||
Charles Crain
|
|
||||||
Steve Leblanc
|
|
||||||
Anthony Roach
|
|
||||||
Terrel Shumway
|
|
||||||
|
|
||||||
|
- 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
|
can build one or more target Nodes (typically files) from one or more
|
||||||
source Nodes (also typically files) given a specific Environment.
|
source Nodes (also typically files) given a specific Environment.
|
||||||
|
|
||||||
The base class here is ActionBase. The base class supplies just a few
|
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.
|
about an Action in response to the various commands that control printing.
|
||||||
|
|
||||||
A second-level base class is _ActionAction. This extends ActionBase
|
A second-level base class is _ActionAction. This extends ActionBase
|
||||||
|
@ -60,7 +83,7 @@ this module:
|
||||||
get_presig()
|
get_presig()
|
||||||
Fetches the "contents" of a subclass for signature calculation.
|
Fetches the "contents" of a subclass for signature calculation.
|
||||||
The varlist is added to this to produce the Action's contents.
|
The varlist is added to this to produce the Action's contents.
|
||||||
TODO(?): Change this to always return ascii/bytes and not unicode (or py3 strings)
|
TODO(?): Change this to always return bytes and not str?
|
||||||
|
|
||||||
strfunction()
|
strfunction()
|
||||||
Returns a substituted string representation of the Action.
|
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 os
|
||||||
import pickle
|
import pickle
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from subprocess import DEVNULL
|
||||||
import itertools
|
import itertools
|
||||||
import inspect
|
import inspect
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
from SCons.Debug import logInstanceCreation
|
||||||
|
@ -115,10 +117,9 @@ import SCons.Util
|
||||||
import SCons.Subst
|
import SCons.Subst
|
||||||
|
|
||||||
# we use these a lot, so try to optimize them
|
# we use these a lot, so try to optimize them
|
||||||
is_String = SCons.Util.is_String
|
from SCons.Util import is_String, is_List
|
||||||
is_List = SCons.Util.is_List
|
|
||||||
|
|
||||||
class _null(object):
|
class _null:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
print_actions = 1
|
print_actions = 1
|
||||||
|
@ -211,7 +212,7 @@ def _object_contents(obj):
|
||||||
|
|
||||||
|
|
||||||
def _code_contents(code, docstring=None):
|
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
|
By providing direct access to the code object of the
|
||||||
function, Python makes this extremely easy. Hooray!
|
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
|
# function. Note that we have to call _object_contents on each
|
||||||
# constants because the code object of nested functions can
|
# constants because the code object of nested functions can
|
||||||
# show-up among the constants.
|
# show-up among the constants.
|
||||||
|
z = [_object_contents(cc) for cc in code.co_consts if cc != docstring]
|
||||||
z = [_object_contents(cc) for cc in code.co_consts[1:]]
|
|
||||||
contents.extend(b',(')
|
contents.extend(b',(')
|
||||||
contents.extend(bytearray(',', 'utf-8').join(z))
|
contents.extend(bytearray(',', 'utf-8').join(z))
|
||||||
contents.extend(b')')
|
contents.extend(b')')
|
||||||
|
@ -515,7 +515,7 @@ def Action(act, *args, **kw):
|
||||||
return _do_create_action(act, 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
|
"""Base class for all types of action objects that can be held by
|
||||||
other objects (Builders, Executors, etc.) This provides the
|
other objects (Builders, Executors, etc.) This provides the
|
||||||
common methods for manipulating and combining those actions."""
|
common methods for manipulating and combining those actions."""
|
||||||
|
@ -535,7 +535,7 @@ class ActionBase(object):
|
||||||
result = self.get_presig(target, source, env)
|
result = self.get_presig(target, source, env)
|
||||||
|
|
||||||
if not isinstance(result,(bytes, bytearray)):
|
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:
|
else:
|
||||||
# Make a copy and put in bytearray, without this the contents returned by get_presig
|
# 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
|
# 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
|
In python 3, and in some of our tests, sys.stdout is
|
||||||
a String io object, and it takes unicode strings only
|
a String io object, and it takes unicode strings only
|
||||||
In other cases it's a regular Python 2.x file object
|
This code assumes s is a regular string.
|
||||||
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.
|
|
||||||
"""
|
"""
|
||||||
try:
|
sys.stdout.write(s + "\n")
|
||||||
sys.stdout.write(s + u"\n")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
sys.stdout.write(s + "\n")
|
|
||||||
|
|
||||||
def __call__(self, target, source, env,
|
def __call__(self, target, source, env,
|
||||||
exitstatfunc=_null,
|
exitstatfunc=_null,
|
||||||
|
@ -657,10 +649,14 @@ class _ActionAction(ActionBase):
|
||||||
presub = self.presub
|
presub = self.presub
|
||||||
if presub is _null:
|
if presub is _null:
|
||||||
presub = print_actions_presub
|
presub = print_actions_presub
|
||||||
if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
|
if exitstatfunc is _null:
|
||||||
if show is _null: show = print_actions
|
exitstatfunc = self.exitstatfunc
|
||||||
if execute is _null: execute = execute_actions
|
if show is _null:
|
||||||
if chdir is _null: chdir = self.chdir
|
show = print_actions
|
||||||
|
if execute is _null:
|
||||||
|
execute = execute_actions
|
||||||
|
if chdir is _null:
|
||||||
|
chdir = self.chdir
|
||||||
save_cwd = None
|
save_cwd = None
|
||||||
if chdir:
|
if chdir:
|
||||||
save_cwd = os.getcwd()
|
save_cwd = os.getcwd()
|
||||||
|
@ -678,7 +674,7 @@ class _ActionAction(ActionBase):
|
||||||
source = executor.get_all_sources()
|
source = executor.get_all_sources()
|
||||||
t = ' and '.join(map(str, target))
|
t = ' and '.join(map(str, target))
|
||||||
l = '\n '.join(self.presub_lines(env))
|
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)
|
sys.stdout.write(out)
|
||||||
cmd = None
|
cmd = None
|
||||||
if show and self.strfunction:
|
if show and self.strfunction:
|
||||||
|
@ -760,24 +756,20 @@ def get_default_ENV(env):
|
||||||
return default_ENV
|
return default_ENV
|
||||||
|
|
||||||
|
|
||||||
def _subproc(scons_env, cmd, error = 'ignore', **kw):
|
def _subproc(scons_env, cmd, error='ignore', **kw):
|
||||||
"""Do common setup for a subprocess.Popen() call
|
"""Wrapper for subprocess which pulls from construction env.
|
||||||
|
|
||||||
This function is still in draft mode. We're going to need something like
|
Use for calls to subprocess which need to interpolate values from
|
||||||
it in the long run as more and more places use subprocess, but I'm sure
|
an SCons construction environment into the environment passed to
|
||||||
it'll have to be tweaked to get the full desired functionality.
|
subprocess. Adds an an error-handling argument. Adds ability
|
||||||
one special arg (so far?), 'error', to tell what to do with exceptions.
|
to specify std{in,out,err} with "'devnull'" tag.
|
||||||
"""
|
"""
|
||||||
# allow std{in,out,err} to be "'devnull'"
|
# TODO: just uses subprocess.DEVNULL now, we can drop the "devnull"
|
||||||
io = kw.get('stdin')
|
# string now - it is a holdover from Py2, which didn't have DEVNULL.
|
||||||
if is_String(io) and io == 'devnull':
|
for stream in 'stdin', 'stdout', 'stderr':
|
||||||
kw['stdin'] = open(os.devnull)
|
io = kw.get(stream)
|
||||||
io = kw.get('stdout')
|
if is_String(io) and io == 'devnull':
|
||||||
if is_String(io) and io == 'devnull':
|
kw[stream] = DEVNULL
|
||||||
kw['stdout'] = open(os.devnull, 'w')
|
|
||||||
io = kw.get('stderr')
|
|
||||||
if is_String(io) and io == 'devnull':
|
|
||||||
kw['stderr'] = open(os.devnull, 'w')
|
|
||||||
|
|
||||||
# Figure out what shell environment to use
|
# Figure out what shell environment to use
|
||||||
ENV = kw.get('env', None)
|
ENV = kw.get('env', None)
|
||||||
|
@ -803,21 +795,28 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
|
||||||
kw['env'] = new_env
|
kw['env'] = new_env
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return subprocess.Popen(cmd, **kw)
|
pobj = subprocess.Popen(cmd, **kw)
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
if error == 'raise': raise
|
if error == 'raise': raise
|
||||||
# return a dummy Popen instance that only returns error
|
# return a dummy Popen instance that only returns error
|
||||||
class dummyPopen(object):
|
class dummyPopen:
|
||||||
def __init__(self, e): self.exception = e
|
def __init__(self, e): self.exception = e
|
||||||
def communicate(self, input=None): return ('', '')
|
def communicate(self, input=None): return ('', '')
|
||||||
def wait(self): return -self.exception.errno
|
def wait(self): return -self.exception.errno
|
||||||
stdin = None
|
stdin = None
|
||||||
class f(object):
|
class f:
|
||||||
def read(self): return ''
|
def read(self): return ''
|
||||||
def readline(self): return ''
|
def readline(self): return ''
|
||||||
def __iter__(self): return iter(())
|
def __iter__(self): return iter(())
|
||||||
stdout = stderr = f()
|
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):
|
class CommandAction(_ActionAction):
|
||||||
|
@ -837,8 +836,8 @@ class CommandAction(_ActionAction):
|
||||||
_ActionAction.__init__(self, **kw)
|
_ActionAction.__init__(self, **kw)
|
||||||
if is_List(cmd):
|
if is_List(cmd):
|
||||||
if [c for c in cmd if is_List(c)]:
|
if [c for c in cmd if is_List(c)]:
|
||||||
raise TypeError("CommandAction should be given only " \
|
raise TypeError("CommandAction should be given only "
|
||||||
"a single command")
|
"a single command")
|
||||||
self.cmd_list = cmd
|
self.cmd_list = cmd
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -964,11 +963,33 @@ class CommandAction(_ActionAction):
|
||||||
return env.subst_target_source(cmd, SUBST_SIG, target, source)
|
return env.subst_target_source(cmd, SUBST_SIG, target, source)
|
||||||
|
|
||||||
def get_implicit_deps(self, target, source, env, executor=None):
|
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)
|
icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
|
||||||
if is_String(icd) and icd[:1] == '$':
|
if is_String(icd) and icd[:1] == '$':
|
||||||
icd = env.subst(icd)
|
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 []
|
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
|
from SCons.Subst import SUBST_SIG
|
||||||
if executor:
|
if executor:
|
||||||
cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=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))
|
res.append(env.fs.File(d))
|
||||||
return res
|
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 CommandGeneratorAction(ActionBase):
|
||||||
"""Class for command-generator actions."""
|
"""Class for command-generator actions."""
|
||||||
|
@ -1034,11 +1114,14 @@ class CommandGeneratorAction(ActionBase):
|
||||||
show=_null, execute=_null, chdir=_null, executor=None):
|
show=_null, execute=_null, chdir=_null, executor=None):
|
||||||
act = self._generate(target, source, env, 0, executor)
|
act = self._generate(target, source, env, 0, executor)
|
||||||
if act is None:
|
if act is None:
|
||||||
raise SCons.Errors.UserError("While building `%s': "
|
raise SCons.Errors.UserError(
|
||||||
"Cannot deduce file extension from source files: %s"
|
"While building `%s': "
|
||||||
% (repr(list(map(str, target))), repr(list(map(str, source)))))
|
"Cannot deduce file extension from source files: %s"
|
||||||
return act(target, source, env, exitstatfunc, presub,
|
% (repr(list(map(str, target))), repr(list(map(str, source))))
|
||||||
show, execute, chdir, executor)
|
)
|
||||||
|
return act(
|
||||||
|
target, source, env, exitstatfunc, presub, show, execute, chdir, executor
|
||||||
|
)
|
||||||
|
|
||||||
def get_presig(self, target, source, env, executor=None):
|
def get_presig(self, target, source, env, executor=None):
|
||||||
"""Return the signature contents of this action's command line.
|
"""Return the signature contents of this action's command line.
|
||||||
|
@ -1086,7 +1169,7 @@ class LazyAction(CommandGeneratorAction, CommandAction):
|
||||||
|
|
||||||
def get_parent_class(self, env):
|
def get_parent_class(self, env):
|
||||||
c = env.get(self.var)
|
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 CommandAction
|
||||||
return CommandGeneratorAction
|
return CommandGeneratorAction
|
||||||
|
|
||||||
|
@ -1289,14 +1372,14 @@ class ListAction(ActionBase):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_varlist(self, target, source, env, executor=None):
|
def get_varlist(self, target, source, env, executor=None):
|
||||||
result = SCons.Util.OrderedDict()
|
result = OrderedDict()
|
||||||
for act in self.list:
|
for act in self.list:
|
||||||
for var in act.get_varlist(target, source, env, executor):
|
for var in act.get_varlist(target, source, env, executor):
|
||||||
result[var] = True
|
result[var] = True
|
||||||
return list(result.keys())
|
return list(result.keys())
|
||||||
|
|
||||||
|
|
||||||
class ActionCaller(object):
|
class ActionCaller:
|
||||||
"""A class for delaying calling an Action function with specific
|
"""A class for delaying calling an Action function with specific
|
||||||
(positional and keyword) arguments until the Action is actually
|
(positional and keyword) arguments until the Action is actually
|
||||||
executed.
|
executed.
|
||||||
|
@ -1367,7 +1450,7 @@ class ActionCaller(object):
|
||||||
return self.parent.strfunc(*self.args, **self.kw)
|
return self.parent.strfunc(*self.args, **self.kw)
|
||||||
|
|
||||||
|
|
||||||
class ActionFactory(object):
|
class ActionFactory:
|
||||||
"""A factory class that will wrap up an arbitrary function
|
"""A factory class that will wrap up an arbitrary function
|
||||||
as an SCons-executable Action object.
|
as an SCons-executable Action object.
|
||||||
|
|
|
@ -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
|
SCons.Builder
|
||||||
|
|
||||||
|
@ -76,31 +99,7 @@ There are the following methods for internal use within this module:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
from collections import UserDict, UserList
|
||||||
# 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
|
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
|
@ -111,7 +110,7 @@ import SCons.Memoize
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
class _Null(object):
|
class _Null:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_null = _Null
|
_null = _Null
|
||||||
|
@ -197,7 +196,7 @@ class DictEmitter(SCons.Util.Selector):
|
||||||
target, source = emitter(target, source, env)
|
target, source = emitter(target, source, env)
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
class ListEmitter(collections.UserList):
|
class ListEmitter(UserList):
|
||||||
"""A callable list of emitters that calls each in sequence,
|
"""A callable list of emitters that calls each in sequence,
|
||||||
returning the result.
|
returning the result.
|
||||||
"""
|
"""
|
||||||
|
@ -215,7 +214,7 @@ misleading_keywords = {
|
||||||
'sources' : 'source',
|
'sources' : 'source',
|
||||||
}
|
}
|
||||||
|
|
||||||
class OverrideWarner(collections.UserDict):
|
class OverrideWarner(UserDict):
|
||||||
"""A class for warning about keyword arguments that we use as
|
"""A class for warning about keyword arguments that we use as
|
||||||
overrides in a Builder call.
|
overrides in a Builder call.
|
||||||
|
|
||||||
|
@ -224,13 +223,13 @@ class OverrideWarner(collections.UserDict):
|
||||||
warnings once, no matter how many Builders are invoked.
|
warnings once, no matter how many Builders are invoked.
|
||||||
"""
|
"""
|
||||||
def __init__(self, dict):
|
def __init__(self, dict):
|
||||||
collections.UserDict.__init__(self, dict)
|
UserDict.__init__(self, dict)
|
||||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner')
|
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner')
|
||||||
self.already_warned = None
|
self.already_warned = None
|
||||||
def warn(self):
|
def warn(self):
|
||||||
if self.already_warned:
|
if self.already_warned:
|
||||||
return
|
return
|
||||||
for k in list(self.keys()):
|
for k in self.keys():
|
||||||
if k in misleading_keywords:
|
if k in misleading_keywords:
|
||||||
alt = misleading_keywords[k]
|
alt = misleading_keywords[k]
|
||||||
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
|
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
|
||||||
|
@ -274,7 +273,7 @@ def Builder(**kw):
|
||||||
|
|
||||||
result = BuilderBase(**kw)
|
result = BuilderBase(**kw)
|
||||||
|
|
||||||
if not composite is None:
|
if composite is not None:
|
||||||
result = CompositeBuilder(result, composite)
|
result = CompositeBuilder(result, composite)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -293,7 +292,7 @@ def _node_errors(builder, env, tlist, slist):
|
||||||
if t.has_explicit_builder():
|
if t.has_explicit_builder():
|
||||||
# Check for errors when the environments are different
|
# Check for errors when the environments are different
|
||||||
# No error if environments are the same Environment instance
|
# 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
|
# Check OverrideEnvironment case - no error if wrapped Environments
|
||||||
# are the same instance, and overrides lists match
|
# are the same instance, and overrides lists match
|
||||||
not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
|
not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
|
||||||
|
@ -309,7 +308,7 @@ def _node_errors(builder, env, tlist, slist):
|
||||||
else:
|
else:
|
||||||
try:
|
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'))
|
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
|
msg = "Two environments with different actions were specified for the same target: %s"%t
|
||||||
raise UserError(msg)
|
raise UserError(msg)
|
||||||
if builder.multi:
|
if builder.multi:
|
||||||
|
@ -328,7 +327,7 @@ def _node_errors(builder, env, tlist, slist):
|
||||||
if len(slist) > 1:
|
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))))
|
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
|
"""This is a callable class that can act as a
|
||||||
Builder emitter. It holds on to a string that
|
Builder emitter. It holds on to a string that
|
||||||
is a key into an Environment dictionary, and will
|
is a key into an Environment dictionary, and will
|
||||||
|
@ -361,7 +360,7 @@ class EmitterProxy(object):
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return self.var < other.var
|
return self.var < other.var
|
||||||
|
|
||||||
class BuilderBase(object):
|
class BuilderBase:
|
||||||
"""Base class for Builders, objects that create output
|
"""Base class for Builders, objects that create output
|
||||||
nodes (files) from input nodes (files).
|
nodes (files) from input nodes (files).
|
||||||
"""
|
"""
|
||||||
|
@ -396,16 +395,13 @@ class BuilderBase(object):
|
||||||
self.env = env
|
self.env = env
|
||||||
self.single_source = single_source
|
self.single_source = single_source
|
||||||
if 'overrides' in overrides:
|
if 'overrides' in overrides:
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning,
|
msg = "The \"overrides\" keyword to Builder() creation has been removed;\n" +\
|
||||||
"The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\
|
"\tspecify the items as keyword arguments to the Builder() call instead."
|
||||||
"\tspecify the items as keyword arguments to the Builder() call instead.")
|
raise TypeError(msg)
|
||||||
overrides.update(overrides['overrides'])
|
|
||||||
del overrides['overrides']
|
|
||||||
if 'scanner' in overrides:
|
if 'scanner' in overrides:
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning,
|
msg = "The \"scanner\" keyword to Builder() creation has been removed;\n" +\
|
||||||
"The \"scanner\" keyword to Builder() creation has been deprecated;\n"
|
"\tuse: source_scanner or target_scanner as appropriate."
|
||||||
"\tuse: source_scanner or target_scanner as appropriate.")
|
raise TypeError(msg)
|
||||||
del overrides['scanner']
|
|
||||||
self.overrides = overrides
|
self.overrides = overrides
|
||||||
|
|
||||||
self.set_suffix(suffix)
|
self.set_suffix(suffix)
|
||||||
|
@ -424,7 +420,7 @@ class BuilderBase(object):
|
||||||
if name:
|
if name:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.executor_kw = {}
|
self.executor_kw = {}
|
||||||
if not chdir is _null:
|
if chdir is not _null:
|
||||||
self.executor_kw['chdir'] = chdir
|
self.executor_kw['chdir'] = chdir
|
||||||
self.is_explicit = is_explicit
|
self.is_explicit = is_explicit
|
||||||
|
|
||||||
|
@ -434,11 +430,8 @@ class BuilderBase(object):
|
||||||
src_builder = [ src_builder ]
|
src_builder = [ src_builder ]
|
||||||
self.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):
|
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):
|
def get_name(self, env):
|
||||||
"""Attempts to get the name of the Builder.
|
"""Attempts to get the name of the Builder.
|
||||||
|
@ -507,6 +500,7 @@ class BuilderBase(object):
|
||||||
splitext = lambda S: self.splitext(S,env)
|
splitext = lambda S: self.splitext(S,env)
|
||||||
tlist = [ t_from_s(pre, suf, splitext) ]
|
tlist = [ t_from_s(pre, suf, splitext) ]
|
||||||
else:
|
else:
|
||||||
|
# orig_target = target
|
||||||
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
|
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
|
||||||
tlist = env.arg2nodes(target, target_factory, target=target, source=source)
|
tlist = env.arg2nodes(target, target_factory, target=target, source=source)
|
||||||
|
|
||||||
|
@ -554,8 +548,10 @@ class BuilderBase(object):
|
||||||
result = []
|
result = []
|
||||||
if target is None: target = [None]*len(source)
|
if target is None: target = [None]*len(source)
|
||||||
for tgt, src in zip(target, source):
|
for tgt, src in zip(target, source):
|
||||||
if not tgt is None: tgt = [tgt]
|
if tgt is not None:
|
||||||
if not src is None: src = [src]
|
tgt = [tgt]
|
||||||
|
if src is not None:
|
||||||
|
src = [src]
|
||||||
result.extend(self._execute(env, tgt, src, overwarn))
|
result.extend(self._execute(env, tgt, src, overwarn))
|
||||||
return SCons.Node.NodeList(result)
|
return SCons.Node.NodeList(result)
|
||||||
|
|
||||||
|
@ -563,6 +559,13 @@ class BuilderBase(object):
|
||||||
|
|
||||||
tlist, slist = self._create_nodes(env, target, source)
|
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.
|
# Check for errors with the specified target/source lists.
|
||||||
_node_errors(self, env, tlist, slist)
|
_node_errors(self, env, tlist, slist)
|
||||||
|
|
||||||
|
@ -641,6 +644,8 @@ class BuilderBase(object):
|
||||||
env_kw = kw
|
env_kw = kw
|
||||||
else:
|
else:
|
||||||
env_kw = self.overrides
|
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)
|
env = env.Override(env_kw)
|
||||||
return self._execute(env, target, source, OverrideWarner(kw), ekw)
|
return self._execute(env, target, source, OverrideWarner(kw), ekw)
|
||||||
|
|
||||||
|
@ -744,7 +749,7 @@ class BuilderBase(object):
|
||||||
for s in SCons.Util.flatten(source):
|
for s in SCons.Util.flatten(source):
|
||||||
if SCons.Util.is_String(s):
|
if SCons.Util.is_String(s):
|
||||||
match_suffix = match_src_suffix(env.subst(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)
|
src_suf = self.get_src_suffix(env)
|
||||||
s = self._adjustixes(s, None, src_suf)[0]
|
s = self._adjustixes(s, None, src_suf)[0]
|
||||||
else:
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,20 +20,18 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/CacheDir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""CacheDir support
|
||||||
|
|
||||||
__doc__ = """
|
|
||||||
CacheDir support
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import atexit
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
|
import SCons.Errors
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
cache_enabled = True
|
cache_enabled = True
|
||||||
|
@ -45,16 +44,22 @@ def CacheRetrieveFunc(target, source, env):
|
||||||
t = target[0]
|
t = target[0]
|
||||||
fs = t.fs
|
fs = t.fs
|
||||||
cd = env.get_CacheDir()
|
cd = env.get_CacheDir()
|
||||||
|
cd.requests += 1
|
||||||
cachedir, cachefile = cd.cachepath(t)
|
cachedir, cachefile = cd.cachepath(t)
|
||||||
if not fs.exists(cachefile):
|
if not fs.exists(cachefile):
|
||||||
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
|
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
|
||||||
return 1
|
return 1
|
||||||
|
cd.hits += 1
|
||||||
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
|
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
|
||||||
if SCons.Action.execute_actions:
|
if SCons.Action.execute_actions:
|
||||||
if fs.islink(cachefile):
|
if fs.islink(cachefile):
|
||||||
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
|
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
|
||||||
else:
|
else:
|
||||||
env.copy_from_cache(cachefile, t.get_internal_path())
|
env.copy_from_cache(cachefile, t.get_internal_path())
|
||||||
|
try:
|
||||||
|
os.utime(cachefile, None)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
st = fs.stat(cachefile)
|
st = fs.stat(cachefile)
|
||||||
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
||||||
return 0
|
return 0
|
||||||
|
@ -106,7 +111,7 @@ def CachePushFunc(target, source, env):
|
||||||
# has beaten us creating the directory.
|
# has beaten us creating the directory.
|
||||||
if not fs.isdir(cachedir):
|
if not fs.isdir(cachedir):
|
||||||
msg = errfmt % (str(target), cachefile)
|
msg = errfmt % (str(target), cachefile)
|
||||||
raise SCons.Errors.EnvironmentError(msg)
|
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if fs.islink(t.get_internal_path()):
|
if fs.islink(t.get_internal_path()):
|
||||||
|
@ -127,90 +132,96 @@ def CachePushFunc(target, source, env):
|
||||||
|
|
||||||
CachePush = SCons.Action.Action(CachePushFunc, None)
|
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):
|
def __init__(self, path):
|
||||||
try:
|
"""
|
||||||
import hashlib
|
Initialize a CacheDir object.
|
||||||
except ImportError:
|
|
||||||
msg = "No hashlib or MD5 module available, CacheDir() not supported"
|
The cache configuration is stored in the object. It
|
||||||
SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
|
is read from the config file in the supplied path if
|
||||||
path = None
|
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.path = path
|
||||||
self.current_cache_debug = None
|
self.current_cache_debug = None
|
||||||
self.debugFP = None
|
self.debugFP = None
|
||||||
self.config = dict()
|
self.config = dict()
|
||||||
if path is None:
|
if path is None:
|
||||||
return
|
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
|
self.config['prefix_len'] = 2
|
||||||
if not os.path.exists(config_file):
|
try:
|
||||||
try:
|
json.dump(self.config, config)
|
||||||
with open(config_file, 'w') as config:
|
except Exception:
|
||||||
json.dump(self.config, config)
|
msg = "Failed to write cache configuration for " + path
|
||||||
except:
|
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||||
msg = "Failed to write cache configuration for " + path
|
except FileExistsError:
|
||||||
raise SCons.Errors.EnvironmentError(msg)
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
with open(config_file) as config:
|
with open(config_file) as config:
|
||||||
self.config = json.load(config)
|
self.config = json.load(config)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = "Failed to read cache configuration for " + path
|
msg = "Failed to read cache configuration for " + path
|
||||||
raise SCons.Errors.EnvironmentError(msg)
|
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||||
|
|
||||||
|
|
||||||
def CacheDebug(self, fmt, target, cachefile):
|
def CacheDebug(self, fmt, target, cachefile):
|
||||||
if cache_debug != self.current_cache_debug:
|
if cache_debug != self.current_cache_debug:
|
||||||
if cache_debug == '-':
|
if cache_debug == '-':
|
||||||
self.debugFP = sys.stdout
|
self.debugFP = sys.stdout
|
||||||
elif cache_debug:
|
elif cache_debug:
|
||||||
|
def debug_cleanup(debugFP):
|
||||||
|
debugFP.close()
|
||||||
|
|
||||||
self.debugFP = open(cache_debug, 'w')
|
self.debugFP = open(cache_debug, 'w')
|
||||||
|
atexit.register(debug_cleanup, self.debugFP)
|
||||||
else:
|
else:
|
||||||
self.debugFP = None
|
self.debugFP = None
|
||||||
self.current_cache_debug = cache_debug
|
self.current_cache_debug = cache_debug
|
||||||
if self.debugFP:
|
if self.debugFP:
|
||||||
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
|
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):
|
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):
|
def is_readonly(self):
|
||||||
return cache_readonly
|
return cache_readonly
|
||||||
|
@ -222,7 +233,9 @@ class CacheDir(object):
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
sig = node.get_cachedir_bsig()
|
sig = node.get_cachedir_bsig()
|
||||||
|
|
||||||
subdir = sig[:self.config['prefix_len']].upper()
|
subdir = sig[:self.config['prefix_len']].upper()
|
||||||
|
|
||||||
dir = os.path.join(self.path, subdir)
|
dir = os.path.join(self.path, subdir)
|
||||||
return dir, os.path.join(dir, sig)
|
return dir, os.path.join(dir, sig)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
"""SCons.Conftest
|
# MIT License
|
||||||
|
|
||||||
Autoconf-like configuration support; low level implementation of tests.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
# Copyright The SCons Foundation
|
||||||
# Copyright (c) 2003 Stichting NLnet Labs
|
# Copyright (c) 2003 Stichting NLnet Labs
|
||||||
# Copyright (c) 2001, 2002, 2003 Steven Knight
|
# 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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
#
|
"""Autoconf-like configuration support
|
||||||
# The purpose of this module is to define how a check is to be performed.
|
|
||||||
# Use one of the Check...() functions below.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
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:
|
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.
|
context.Display(msg)
|
||||||
# The text should also be written to the logfile!
|
Function called to print messages that are normally displayed
|
||||||
#
|
for the user. Newlines are explicitly used. The text should
|
||||||
# context.Log(msg) Function called to write to a log file.
|
also be written to the logfile!
|
||||||
#
|
|
||||||
# context.BuildProg(text, ext)
|
context.Log(msg)
|
||||||
# Function called to build a program, using "ext" for the
|
Function called to write to a log file.
|
||||||
# file extention. Must return an empty string for
|
|
||||||
# success, an error message for failure.
|
context.BuildProg(text, ext)
|
||||||
# For reliable test results building should be done just
|
Function called to build a program, using "ext" for the file
|
||||||
# like an actual program would be build, using the same
|
extension. Must return an empty string for success, an error
|
||||||
# command and arguments (including configure results so
|
message for failure. For reliable test results building should
|
||||||
# far).
|
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
|
context.CompileProg(text, ext)
|
||||||
# the file extention. Must return an empty string for
|
Function called to compile a program, using "ext" for the file
|
||||||
# success, an error message for failure.
|
extension. Must return an empty string for success, an error
|
||||||
# For reliable test results compiling should be done just
|
message for failure. For reliable test results compiling should be
|
||||||
# like an actual source file would be compiled, using the
|
done just like an actual source file would be compiled, using the
|
||||||
# same command and arguments (including configure results
|
same command and arguments (including configure results so far).
|
||||||
# so far).
|
|
||||||
#
|
context.AppendLIBS(lib_name_list)
|
||||||
# context.AppendLIBS(lib_name_list)
|
Append "lib_name_list" to the value of LIBS. "lib_namelist" is
|
||||||
# Append "lib_name_list" to the value of LIBS.
|
a list of strings. Return the value of LIBS before changing it
|
||||||
# "lib_namelist" is a list of strings.
|
(any type can be used, it is passed to SetLIBS() later.)
|
||||||
# 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
|
||||||
# context.PrependLIBS(lib_name_list)
|
a list of strings. Return the value of LIBS before changing it
|
||||||
# Prepend "lib_name_list" to the value of LIBS.
|
(any type can be used, it is passed to SetLIBS() later.)
|
||||||
# "lib_namelist" is a list of strings.
|
|
||||||
# Return the value of LIBS before changing it (any type
|
context.SetLIBS(value)
|
||||||
# can be used, it is passed to SetLIBS() later.)
|
Set LIBS to "value". The type of "value" is what AppendLIBS()
|
||||||
#
|
returned. Return the value of LIBS before changing it (any type
|
||||||
# context.SetLIBS(value)
|
can be used, it is passed to SetLIBS() later.)
|
||||||
# Set LIBS to "value". The type of "value" is what
|
|
||||||
# AppendLIBS() returned.
|
context.headerfilename
|
||||||
# Return the value of LIBS before changing it (any type
|
Name of file to append configure results to, usually "confdefs.h".
|
||||||
# can be used, it is passed to SetLIBS() later.)
|
The file must not exist or be empty when starting. Empty or None
|
||||||
#
|
to skip this (some tests will not work!).
|
||||||
# context.headerfilename
|
|
||||||
# Name of file to append configure results to, usually
|
context.config_h (may be missing).
|
||||||
# "confdefs.h".
|
If present, must be a string, which will be filled with the
|
||||||
# The file must not exist or be empty when starting.
|
contents of a config_h file.
|
||||||
# Empty or None to skip this (some tests will not work!).
|
|
||||||
#
|
context.vardict
|
||||||
# context.config_h (may be missing). If present, must be a string, which
|
Dictionary holding variables used for the tests and stores results
|
||||||
# will be filled with the contents of a config_h file.
|
from the tests, used for the build commands. Normally contains
|
||||||
#
|
"CC", "LIBS", "CPPFLAGS", etc.
|
||||||
# context.vardict Dictionary holding variables used for the tests and
|
|
||||||
# stores results from the tests, used for the build
|
context.havedict
|
||||||
# commands.
|
Dictionary holding results from the tests that are to be used
|
||||||
# Normally contains "CC", "LIBS", "CPPFLAGS", etc.
|
inside a program. Names often start with "HAVE_". These are zero
|
||||||
#
|
(feature not present) or one (feature present). Other variables
|
||||||
# context.havedict Dictionary holding results from the tests that are to
|
may have any value, e.g., "PERLVERSION" can be a number and
|
||||||
# be used inside a program.
|
"SYSTEMNAME" a string.
|
||||||
# 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
|
import re
|
||||||
|
|
||||||
|
@ -136,7 +125,7 @@ def CheckBuilder(context, text = None, language = None):
|
||||||
|
|
||||||
if not text:
|
if not text:
|
||||||
text = """
|
text = """
|
||||||
int main() {
|
int main(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -157,7 +146,7 @@ def CheckCC(context):
|
||||||
"""
|
"""
|
||||||
context.Display("Checking whether the C compiler works... ")
|
context.Display("Checking whether the C compiler works... ")
|
||||||
text = """
|
text = """
|
||||||
int main()
|
int main(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +166,7 @@ def CheckSHCC(context):
|
||||||
"""
|
"""
|
||||||
context.Display("Checking whether the (shared) C compiler works... ")
|
context.Display("Checking whether the (shared) C compiler works... ")
|
||||||
text = """
|
text = """
|
||||||
int foo()
|
int foo(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +186,7 @@ def CheckCXX(context):
|
||||||
"""
|
"""
|
||||||
context.Display("Checking whether the C++ compiler works... ")
|
context.Display("Checking whether the C++ compiler works... ")
|
||||||
text = """
|
text = """
|
||||||
int main()
|
int main(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +206,7 @@ def CheckSHCXX(context):
|
||||||
"""
|
"""
|
||||||
context.Display("Checking whether the (shared) C++ compiler works... ")
|
context.Display("Checking whether the (shared) C++ compiler works... ")
|
||||||
text = """
|
text = """
|
||||||
int main()
|
int main(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -290,7 +279,11 @@ char %s();""" % function_name
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
%(hdr)s
|
%(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)
|
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
|
||||||
fail fail fail
|
fail fail fail
|
||||||
#else
|
#else
|
||||||
|
@ -311,8 +304,8 @@ int main() {
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def CheckHeader(context, header_name, header = None, language = None,
|
def CheckHeader(context, header_name, header=None, language=None,
|
||||||
include_quotes = None):
|
include_quotes=None):
|
||||||
"""
|
"""
|
||||||
Configure check for a C or C++ header file "header_name".
|
Configure check for a C or C++ header file "header_name".
|
||||||
Optional "header" can be defined to do something before including the
|
Optional "header" can be defined to do something before including the
|
||||||
|
@ -400,7 +393,7 @@ def CheckType(context, type_name, fallback = None,
|
||||||
%(include)s
|
%(include)s
|
||||||
%(header)s
|
%(header)s
|
||||||
|
|
||||||
int main() {
|
int main(void) {
|
||||||
if ((%(name)s *) 0)
|
if ((%(name)s *) 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (sizeof (%(name)s))
|
if (sizeof (%(name)s))
|
||||||
|
@ -455,7 +448,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
src = includetext + header
|
src = includetext + header
|
||||||
if not expect is None:
|
if expect is not None:
|
||||||
# Only check if the given size is the right one
|
# Only check if the given size is the right one
|
||||||
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
|
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"""
|
src = src + r"""
|
||||||
typedef %s scons_check_type;
|
typedef %s scons_check_type;
|
||||||
|
|
||||||
int main()
|
int main(void)
|
||||||
{
|
{
|
||||||
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
|
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
|
||||||
test_array[0] = 0;
|
test_array[0] = 0;
|
||||||
|
@ -498,7 +491,7 @@ int main()
|
||||||
src = src + """
|
src = src + """
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
int main() {
|
int main(void) {
|
||||||
printf("%d", (int)sizeof(""" + type_name + """));
|
printf("%d", (int)sizeof(""" + type_name + """));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -560,7 +553,7 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
|
||||||
context.Display('Checking whether %s is declared... ' % symbol)
|
context.Display('Checking whether %s is declared... ' % symbol)
|
||||||
|
|
||||||
src = src + r"""
|
src = src + r"""
|
||||||
int main()
|
int main(void)
|
||||||
{
|
{
|
||||||
#ifndef %s
|
#ifndef %s
|
||||||
(void) %s;
|
(void) %s;
|
||||||
|
@ -704,7 +697,7 @@ def CheckProg(context, prog_name):
|
||||||
#
|
#
|
||||||
|
|
||||||
def _YesNoResult(context, ret, key, text, comment = None):
|
def _YesNoResult(context, ret, key, text, comment = None):
|
||||||
"""
|
r"""
|
||||||
Handle the result of a test with a "yes" or "no" result.
|
Handle the result of a test with a "yes" or "no" result.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
|
@ -723,7 +716,7 @@ def _YesNoResult(context, ret, key, text, comment = None):
|
||||||
|
|
||||||
|
|
||||||
def _Have(context, key, have, comment = None):
|
def _Have(context, key, have, comment = None):
|
||||||
"""
|
r"""
|
||||||
Store result of a test in context.havedict and context.headerfilename.
|
Store result of a test in context.havedict and context.headerfilename.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
|
@ -1,15 +1,6 @@
|
||||||
"""SCons.Debug
|
# MIT License
|
||||||
|
|
||||||
Code for debugging SCons internal things. Shouldn't be
|
|
||||||
needed by most users. Quick shortcuts:
|
|
||||||
|
|
||||||
from SCons.Debug import caller_trace
|
|
||||||
caller_trace()
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -29,10 +20,16 @@ caller_trace()
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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 os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -93,7 +90,6 @@ def dumpLoggedInstances(classes, file=sys.stdout):
|
||||||
file.write(' %20s : %s\n' % (key, value))
|
file.write(' %20s : %s\n' % (key, value))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if sys.platform[:5] == "linux":
|
if sys.platform[:5] == "linux":
|
||||||
# Linux doesn't actually support memory usage stats from getrusage().
|
# Linux doesn't actually support memory usage stats from getrusage().
|
||||||
def memory():
|
def memory():
|
||||||
|
@ -105,28 +101,23 @@ elif sys.platform[:6] == 'darwin':
|
||||||
#TODO really get memory stats for OS X
|
#TODO really get memory stats for OS X
|
||||||
def memory():
|
def memory():
|
||||||
return 0
|
return 0
|
||||||
|
elif sys.platform == 'win32':
|
||||||
|
from SCons.compat.win32 import get_peak_memory_usage
|
||||||
|
memory = get_peak_memory_usage
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
import resource
|
import resource
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
def memory():
|
||||||
import win32process
|
return 0
|
||||||
import win32api
|
|
||||||
except ImportError:
|
|
||||||
def memory():
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
def memory():
|
|
||||||
process_handle = win32api.GetCurrentProcess()
|
|
||||||
memory_info = win32process.GetProcessMemoryInfo( process_handle )
|
|
||||||
return memory_info['PeakWorkingSetSize']
|
|
||||||
else:
|
else:
|
||||||
def memory():
|
def memory():
|
||||||
res = resource.getrusage(resource.RUSAGE_SELF)
|
res = resource.getrusage(resource.RUSAGE_SELF)
|
||||||
return res[4]
|
return res[4]
|
||||||
|
|
||||||
# returns caller's stack
|
|
||||||
def caller_stack():
|
def caller_stack():
|
||||||
|
"""return caller's stack"""
|
||||||
import traceback
|
import traceback
|
||||||
tb = traceback.extract_stack()
|
tb = traceback.extract_stack()
|
||||||
# strip itself and the caller from the output
|
# strip itself and the caller from the output
|
||||||
|
@ -201,40 +192,57 @@ if sys.platform == 'win32':
|
||||||
TraceDefault = 'con'
|
TraceDefault = 'con'
|
||||||
else:
|
else:
|
||||||
TraceDefault = '/dev/tty'
|
TraceDefault = '/dev/tty'
|
||||||
|
TimeStampDefault = False
|
||||||
TimeStampDefault = None
|
|
||||||
StartTime = time.time()
|
StartTime = time.time()
|
||||||
PreviousTime = StartTime
|
PreviousTime = StartTime
|
||||||
|
|
||||||
def Trace(msg, file=None, mode='w', tstamp=None):
|
def Trace(msg, tracefile=None, mode='w', tstamp=False):
|
||||||
"""Write a trace message to a file. Whenever a file is specified,
|
"""Write a trace message.
|
||||||
it becomes the default for the next call to Trace()."""
|
|
||||||
|
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 TraceDefault
|
||||||
global TimeStampDefault
|
global TimeStampDefault
|
||||||
global PreviousTime
|
global PreviousTime
|
||||||
if file is None:
|
|
||||||
file = TraceDefault
|
def trace_cleanup(traceFP):
|
||||||
|
traceFP.close()
|
||||||
|
|
||||||
|
if tracefile is None:
|
||||||
|
tracefile = TraceDefault
|
||||||
else:
|
else:
|
||||||
TraceDefault = file
|
TraceDefault = tracefile
|
||||||
if tstamp is None:
|
if not tstamp:
|
||||||
tstamp = TimeStampDefault
|
tstamp = TimeStampDefault
|
||||||
else:
|
else:
|
||||||
TimeStampDefault = tstamp
|
TimeStampDefault = tstamp
|
||||||
try:
|
try:
|
||||||
fp = TraceFP[file]
|
fp = TraceFP[tracefile]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
try:
|
||||||
fp = TraceFP[file] = open(file, mode)
|
fp = TraceFP[tracefile] = open(tracefile, mode)
|
||||||
|
atexit.register(trace_cleanup, fp)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# Assume we were passed an open file pointer.
|
# Assume we were passed an open file pointer.
|
||||||
fp = file
|
fp = tracefile
|
||||||
if tstamp:
|
if tstamp:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
||||||
PreviousTime = now
|
PreviousTime = now
|
||||||
fp.write(msg)
|
fp.write(msg)
|
||||||
fp.flush()
|
fp.flush()
|
||||||
fp.close()
|
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
|
@ -1,16 +1,6 @@
|
||||||
"""SCons.Defaults
|
# MIT License
|
||||||
|
|
||||||
Builders and other things for the local site. Here's where we'll
|
|
||||||
duplicate the functionality of autoconf until we move it into the
|
|
||||||
installation procedure or use something like qmconf.
|
|
||||||
|
|
||||||
The code that reads the registry to find MSVC components was borrowed
|
|
||||||
from distutils.msvccompiler.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,17 +21,22 @@ from distutils.msvccompiler.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/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 errno
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
import SCons.Builder
|
import SCons.Builder
|
||||||
|
@ -50,6 +45,7 @@ import SCons.Environment
|
||||||
import SCons.PathList
|
import SCons.PathList
|
||||||
import SCons.Subst
|
import SCons.Subst
|
||||||
import SCons.Tool
|
import SCons.Tool
|
||||||
|
import SCons.Scanner.Dir
|
||||||
|
|
||||||
# A placeholder for a default Environment (for fetching source files
|
# A placeholder for a default Environment (for fetching source files
|
||||||
# from source code management systems and the like). This must be
|
# from source code management systems and the like). This must be
|
||||||
|
@ -57,15 +53,15 @@ import SCons.Tool
|
||||||
# interface.
|
# interface.
|
||||||
_default_env = None
|
_default_env = None
|
||||||
|
|
||||||
|
|
||||||
# Lazily instantiate the default environment so the overhead of creating
|
# Lazily instantiate the default environment so the overhead of creating
|
||||||
# it doesn't apply when it's not needed.
|
# it doesn't apply when it's not needed.
|
||||||
def _fetch_DefaultEnvironment(*args, **kw):
|
def _fetch_DefaultEnvironment(*args, **kw):
|
||||||
"""
|
"""Returns the already-created default construction environment."""
|
||||||
Returns the already-created default construction environment.
|
|
||||||
"""
|
|
||||||
global _default_env
|
global _default_env
|
||||||
return _default_env
|
return _default_env
|
||||||
|
|
||||||
|
|
||||||
def DefaultEnvironment(*args, **kw):
|
def DefaultEnvironment(*args, **kw):
|
||||||
"""
|
"""
|
||||||
Initial public entry point for creating the default construction
|
Initial public entry point for creating the default construction
|
||||||
|
@ -95,6 +91,7 @@ def DefaultEnvironment(*args, **kw):
|
||||||
_default_env._CacheDir_path = None
|
_default_env._CacheDir_path = None
|
||||||
return _default_env
|
return _default_env
|
||||||
|
|
||||||
|
|
||||||
# Emitters for setting the shared attribute on object files,
|
# Emitters for setting the shared attribute on object files,
|
||||||
# and an action for checking that all of the source files
|
# and an action for checking that all of the source files
|
||||||
# going into a shared library are, in fact, shared.
|
# going into a shared library are, in fact, shared.
|
||||||
|
@ -103,11 +100,13 @@ def StaticObjectEmitter(target, source, env):
|
||||||
tgt.attributes.shared = None
|
tgt.attributes.shared = None
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
|
|
||||||
def SharedObjectEmitter(target, source, env):
|
def SharedObjectEmitter(target, source, env):
|
||||||
for tgt in target:
|
for tgt in target:
|
||||||
tgt.attributes.shared = 1
|
tgt.attributes.shared = 1
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
|
|
||||||
def SharedFlagChecker(source, target, env):
|
def SharedFlagChecker(source, target, env):
|
||||||
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
||||||
if same == '0' or same == '' or same == 'False':
|
if same == '0' or same == '' or same == 'False':
|
||||||
|
@ -117,7 +116,9 @@ def SharedFlagChecker(source, target, env):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
shared = None
|
shared = None
|
||||||
if not shared:
|
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)
|
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
|
# 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
|
# the rest of those in Tool/__init__.py, but I'm not sure where else
|
||||||
# they should go. Leave them here for now.
|
# they should go. Leave them here for now.
|
||||||
import SCons.Scanner.Dir
|
|
||||||
DirScanner = SCons.Scanner.Dir.DirScanner()
|
DirScanner = SCons.Scanner.Dir.DirScanner()
|
||||||
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
||||||
|
|
||||||
|
@ -159,6 +160,7 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
||||||
# ways by creating ActionFactory instances.
|
# ways by creating ActionFactory instances.
|
||||||
ActionFactory = SCons.Action.ActionFactory
|
ActionFactory = SCons.Action.ActionFactory
|
||||||
|
|
||||||
|
|
||||||
def get_paths_str(dest):
|
def get_paths_str(dest):
|
||||||
# If dest is a list, we need to manually call str() on each element
|
# If dest is a list, we need to manually call str() on each element
|
||||||
if SCons.Util.is_List(dest):
|
if SCons.Util.is_List(dest):
|
||||||
|
@ -169,31 +171,33 @@ def get_paths_str(dest):
|
||||||
else:
|
else:
|
||||||
return '"' + str(dest) + '"'
|
return '"' + str(dest) + '"'
|
||||||
|
|
||||||
|
|
||||||
permission_dic = {
|
permission_dic = {
|
||||||
'u':{
|
'u': {
|
||||||
'r':stat.S_IRUSR,
|
'r': stat.S_IRUSR,
|
||||||
'w':stat.S_IWUSR,
|
'w': stat.S_IWUSR,
|
||||||
'x':stat.S_IXUSR
|
'x': stat.S_IXUSR
|
||||||
},
|
},
|
||||||
'g':{
|
'g': {
|
||||||
'r':stat.S_IRGRP,
|
'r': stat.S_IRGRP,
|
||||||
'w':stat.S_IWGRP,
|
'w': stat.S_IWGRP,
|
||||||
'x':stat.S_IXGRP
|
'x': stat.S_IXGRP
|
||||||
},
|
},
|
||||||
'o':{
|
'o': {
|
||||||
'r':stat.S_IROTH,
|
'r': stat.S_IROTH,
|
||||||
'w':stat.S_IWOTH,
|
'w': stat.S_IWOTH,
|
||||||
'x':stat.S_IXOTH
|
'x': stat.S_IXOTH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def chmod_func(dest, mode):
|
def chmod_func(dest, mode):
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
from string import digits
|
from string import digits
|
||||||
SCons.Node.FS.invalidate_node_memos(dest)
|
SCons.Node.FS.invalidate_node_memos(dest)
|
||||||
if not SCons.Util.is_List(dest):
|
if not SCons.Util.is_List(dest):
|
||||||
dest = [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)
|
mode = int(mode, 8)
|
||||||
if not SCons.Util.is_String(mode):
|
if not SCons.Util.is_String(mode):
|
||||||
for element in dest:
|
for element in dest:
|
||||||
|
@ -210,7 +214,7 @@ def chmod_func(dest, mode):
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("Could not find +, - or =")
|
raise SyntaxError("Could not find +, - or =")
|
||||||
operation_list = operation.split(operator)
|
operation_list = operation.split(operator)
|
||||||
if len(operation_list) is not 2:
|
if len(operation_list) != 2:
|
||||||
raise SyntaxError("More than one operator found")
|
raise SyntaxError("More than one operator found")
|
||||||
user = operation_list[0].strip().replace("a", "ugo")
|
user = operation_list[0].strip().replace("a", "ugo")
|
||||||
permission = operation_list[1].strip()
|
permission = operation_list[1].strip()
|
||||||
|
@ -230,6 +234,7 @@ def chmod_func(dest, mode):
|
||||||
elif operator == "-":
|
elif operator == "-":
|
||||||
os.chmod(str(element), curr_perm & ~new_perm)
|
os.chmod(str(element), curr_perm & ~new_perm)
|
||||||
|
|
||||||
|
|
||||||
def chmod_strfunc(dest, mode):
|
def chmod_strfunc(dest, mode):
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
if not SCons.Util.is_String(mode):
|
if not SCons.Util.is_String(mode):
|
||||||
|
@ -237,8 +242,10 @@ def chmod_strfunc(dest, mode):
|
||||||
else:
|
else:
|
||||||
return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
|
return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
|
||||||
|
|
||||||
|
|
||||||
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
||||||
|
|
||||||
|
|
||||||
def copy_func(dest, src, symlinks=True):
|
def copy_func(dest, src, symlinks=True):
|
||||||
"""
|
"""
|
||||||
If symlinks (is true), then a symbolic link will be
|
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
|
# A error is raised in both cases, so we can just return 0 for success
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
Copy = ActionFactory(
|
Copy = ActionFactory(
|
||||||
copy_func,
|
copy_func,
|
||||||
lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
|
lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def delete_func(dest, must_exist=0):
|
def delete_func(dest, must_exist=0):
|
||||||
SCons.Node.FS.invalidate_node_memos(dest)
|
SCons.Node.FS.invalidate_node_memos(dest)
|
||||||
if not SCons.Util.is_List(dest):
|
if not SCons.Util.is_List(dest):
|
||||||
|
@ -290,11 +299,14 @@ def delete_func(dest, must_exist=0):
|
||||||
continue
|
continue
|
||||||
os.unlink(entry)
|
os.unlink(entry)
|
||||||
|
|
||||||
|
|
||||||
def delete_strfunc(dest, must_exist=0):
|
def delete_strfunc(dest, must_exist=0):
|
||||||
return 'Delete(%s)' % get_paths_str(dest)
|
return 'Delete(%s)' % get_paths_str(dest)
|
||||||
|
|
||||||
|
|
||||||
Delete = ActionFactory(delete_func, delete_strfunc)
|
Delete = ActionFactory(delete_func, delete_strfunc)
|
||||||
|
|
||||||
|
|
||||||
def mkdir_func(dest):
|
def mkdir_func(dest):
|
||||||
SCons.Node.FS.invalidate_node_memos(dest)
|
SCons.Node.FS.invalidate_node_memos(dest)
|
||||||
if not SCons.Util.is_List(dest):
|
if not SCons.Util.is_List(dest):
|
||||||
|
@ -305,24 +317,28 @@ def mkdir_func(dest):
|
||||||
except os.error as e:
|
except os.error as e:
|
||||||
p = str(entry)
|
p = str(entry)
|
||||||
if (e.args[0] == errno.EEXIST or
|
if (e.args[0] == errno.EEXIST or
|
||||||
(sys.platform=='win32' and e.args[0]==183)) \
|
(sys.platform == 'win32' and e.args[0] == 183)) \
|
||||||
and os.path.isdir(str(entry)):
|
and os.path.isdir(str(entry)):
|
||||||
pass # not an error if already exists
|
pass # not an error if already exists
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
Mkdir = ActionFactory(mkdir_func,
|
Mkdir = ActionFactory(mkdir_func,
|
||||||
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
||||||
|
|
||||||
|
|
||||||
def move_func(dest, src):
|
def move_func(dest, src):
|
||||||
SCons.Node.FS.invalidate_node_memos(dest)
|
SCons.Node.FS.invalidate_node_memos(dest)
|
||||||
SCons.Node.FS.invalidate_node_memos(src)
|
SCons.Node.FS.invalidate_node_memos(src)
|
||||||
shutil.move(src, dest)
|
shutil.move(src, dest)
|
||||||
|
|
||||||
|
|
||||||
Move = ActionFactory(move_func,
|
Move = ActionFactory(move_func,
|
||||||
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
||||||
convert=str)
|
convert=str)
|
||||||
|
|
||||||
|
|
||||||
def touch_func(dest):
|
def touch_func(dest):
|
||||||
SCons.Node.FS.invalidate_node_memos(dest)
|
SCons.Node.FS.invalidate_node_memos(dest)
|
||||||
if not SCons.Util.is_List(dest):
|
if not SCons.Util.is_List(dest):
|
||||||
|
@ -333,15 +349,18 @@ def touch_func(dest):
|
||||||
if os.path.exists(file):
|
if os.path.exists(file):
|
||||||
atime = os.path.getatime(file)
|
atime = os.path.getatime(file)
|
||||||
else:
|
else:
|
||||||
open(file, 'w')
|
with open(file, 'w'):
|
||||||
atime = mtime
|
atime = mtime
|
||||||
os.utime(file, (atime, mtime))
|
os.utime(file, (atime, mtime))
|
||||||
|
|
||||||
|
|
||||||
Touch = ActionFactory(touch_func,
|
Touch = ActionFactory(touch_func,
|
||||||
lambda file: 'Touch(%s)' % get_paths_str(file))
|
lambda file: 'Touch(%s)' % get_paths_str(file))
|
||||||
|
|
||||||
|
|
||||||
# Internal utility functions
|
# Internal utility functions
|
||||||
|
|
||||||
|
|
||||||
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
||||||
"""
|
"""
|
||||||
Creates a new list from 'list' by first interpolating each element
|
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)
|
return _concat_ixes(prefix, list, suffix, env)
|
||||||
|
|
||||||
|
|
||||||
def _concat_ixes(prefix, list, suffix, env):
|
def _concat_ixes(prefix, list, suffix, env):
|
||||||
"""
|
"""
|
||||||
Creates a new list from 'list' by concatenating the 'prefix' and
|
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] == ' ':
|
if suffix[0] == ' ':
|
||||||
result.append(suffix[1:])
|
result.append(suffix[1:])
|
||||||
elif x[-len(suffix):] != suffix:
|
elif x[-len(suffix):] != suffix:
|
||||||
result[-1] = result[-1]+suffix
|
result[-1] = result[-1] + suffix
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
||||||
"""
|
"""
|
||||||
This is a wrapper around _concat()/_concat_ixes() that checks for
|
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)
|
return c(prefix, stripped, suffix, env)
|
||||||
|
|
||||||
|
|
||||||
def processDefines(defs):
|
def processDefines(defs):
|
||||||
"""process defines, resolving strings, lists, dictionaries, into a list of
|
"""process defines, resolving strings, lists, dictionaries, into a list of
|
||||||
strings
|
strings
|
||||||
|
@ -462,7 +484,7 @@ def processDefines(defs):
|
||||||
else:
|
else:
|
||||||
l.append(str(d[0]))
|
l.append(str(d[0]))
|
||||||
elif SCons.Util.is_Dict(d):
|
elif SCons.Util.is_Dict(d):
|
||||||
for macro,value in d.items():
|
for macro, value in d.items():
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append(str(macro) + '=' + str(value))
|
l.append(str(macro) + '=' + str(value))
|
||||||
else:
|
else:
|
||||||
|
@ -470,7 +492,7 @@ def processDefines(defs):
|
||||||
elif SCons.Util.is_String(d):
|
elif SCons.Util.is_String(d):
|
||||||
l.append(str(d))
|
l.append(str(d))
|
||||||
else:
|
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):
|
elif SCons.Util.is_Dict(defs):
|
||||||
# The items in a dictionary are stored in random order, but
|
# The items in a dictionary are stored in random order, but
|
||||||
# if the order of the command-line options changes from
|
# 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
|
# Consequently, we have to sort the keys to ensure a
|
||||||
# consistent order...
|
# consistent order...
|
||||||
l = []
|
l = []
|
||||||
for k,v in sorted(defs.items()):
|
for k, v in sorted(defs.items()):
|
||||||
if v is None:
|
if v is None:
|
||||||
l.append(str(k))
|
l.append(str(k))
|
||||||
else:
|
else:
|
||||||
|
@ -497,7 +519,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
|
||||||
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
||||||
|
|
||||||
|
|
||||||
class NullCmdGenerator(object):
|
class NullCmdGenerator:
|
||||||
"""This is a callable class that can be used in place of other
|
"""This is a callable class that can be used in place of other
|
||||||
command generators if you don't want them to do anything.
|
command generators if you don't want them to do anything.
|
||||||
|
|
||||||
|
@ -516,7 +538,7 @@ class NullCmdGenerator(object):
|
||||||
return self.cmd
|
return self.cmd
|
||||||
|
|
||||||
|
|
||||||
class Variable_Method_Caller(object):
|
class Variable_Method_Caller:
|
||||||
"""A class for finding a construction variable on the stack and
|
"""A class for finding a construction variable on the stack and
|
||||||
calling one of its methods.
|
calling one of its methods.
|
||||||
|
|
||||||
|
@ -528,11 +550,14 @@ class Variable_Method_Caller(object):
|
||||||
the way of Memoizing construction environments, because we had to
|
the way of Memoizing construction environments, because we had to
|
||||||
create new environment objects to hold the variables.)
|
create new environment objects to hold the variables.)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, variable, method):
|
def __init__(self, variable, method):
|
||||||
self.variable = variable
|
self.variable = variable
|
||||||
self.method = method
|
self.method = method
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
def __call__(self, *args, **kw):
|
||||||
try: 1//0
|
try:
|
||||||
|
1 // 0
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
# Don't start iterating with the current stack-frame to
|
# Don't start iterating with the current stack-frame to
|
||||||
# prevent creating reference cycles (f_back is safe).
|
# prevent creating reference cycles (f_back is safe).
|
||||||
|
@ -547,43 +572,69 @@ class Variable_Method_Caller(object):
|
||||||
frame = frame.f_back
|
frame = frame.f_back
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# if $version_var is not empty, returns env[flags_var], otherwise returns None
|
|
||||||
def __libversionflags(env, version_var, flags_var):
|
def __libversionflags(env, version_var, flags_var):
|
||||||
|
"""
|
||||||
|
if version_var is not empty, returns env[flags_var], otherwise returns None
|
||||||
|
:param env:
|
||||||
|
:param version_var:
|
||||||
|
:param flags_var:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if env.subst('$'+version_var):
|
if env.subst('$' + version_var):
|
||||||
return env[flags_var]
|
return env[flags_var]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return None
|
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 = {
|
ConstructionEnvironment = {
|
||||||
'BUILDERS' : {},
|
'BUILDERS': {},
|
||||||
'SCANNERS' : [ SCons.Tool.SourceFileScanner ],
|
'SCANNERS': [SCons.Tool.SourceFileScanner],
|
||||||
'CONFIGUREDIR' : '#/.sconf_temp',
|
'CONFIGUREDIR': '#/.sconf_temp',
|
||||||
'CONFIGURELOG' : '#/config.log',
|
'CONFIGURELOG': '#/config.log',
|
||||||
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
|
'CPPSUFFIXES': SCons.Tool.CSuffixes,
|
||||||
'DSUFFIXES' : SCons.Tool.DSuffixes,
|
'DSUFFIXES': SCons.Tool.DSuffixes,
|
||||||
'ENV' : {},
|
'ENV': {},
|
||||||
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
|
'IDLSUFFIXES': SCons.Tool.IDLSuffixes,
|
||||||
# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
|
'_concat': _concat,
|
||||||
'_concat' : _concat,
|
'_defines': _defines,
|
||||||
'_defines' : _defines,
|
'_stripixes': _stripixes,
|
||||||
'_stripixes' : _stripixes,
|
'_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||||
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
'_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||||
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
'_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||||
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
||||||
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
|
||||||
|
|
||||||
'__libversionflags' : __libversionflags,
|
'__libversionflags': __libversionflags,
|
||||||
'__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
'__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
||||||
'__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
'__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
||||||
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
'__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||||
|
'__lib_either_version_flag': __lib_either_version_flag,
|
||||||
|
|
||||||
'TEMPFILE' : NullCmdGenerator,
|
'TEMPFILE': NullCmdGenerator,
|
||||||
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
'TEMPFILEARGJOIN': ' ',
|
||||||
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
'Dir': Variable_Method_Caller('TARGET', 'Dir'),
|
||||||
'File' : Variable_Method_Caller('TARGET', 'File'),
|
'Dirs': Variable_Method_Caller('TARGET', 'Dirs'),
|
||||||
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
|
'File': Variable_Method_Caller('TARGET', 'File'),
|
||||||
|
'RDirs': Variable_Method_Caller('TARGET', 'RDirs'),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Local Variables:
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,73 +20,65 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
"""SCons.Errors
|
"""SCons exception classes.
|
||||||
|
|
||||||
This file contains the exception classes used to handle internal
|
Used to handle internal and user errors in SCons.
|
||||||
and user errors in SCons.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Errors.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
|
||||||
|
|
||||||
class BuildError(Exception):
|
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.
|
exitstatus: SCons exit status due to this build error.
|
||||||
Must be set to a non-zero value even if the build error is not due
|
Must be nonzero unless due to an explicit Exit()
|
||||||
to an action returning a non-zero returned code.
|
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.
|
filename: The name of the file or directory that caused the
|
||||||
Must be nonzero unless due to an explicit Exit()
|
build error. Set to None if no files are associated with
|
||||||
call. Not always the same as status, since
|
this error. This might be different from the target
|
||||||
actions return a status code that should be
|
being built. For example, failure to create the
|
||||||
respected, but SCons typically exits with 2
|
directory in which the target file will appear. It
|
||||||
irrespective of the return value of the failed
|
can be None if the error is not due to a particular
|
||||||
action.
|
filename.
|
||||||
|
|
||||||
filename : The name of the file or directory that caused the
|
exc_info: Info about exception that caused the build
|
||||||
build error. Set to None if no files are associated with
|
error. Set to (None, None, None) if this build
|
||||||
this error. This might be different from the target
|
error is not due to an exception.
|
||||||
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
|
Information about the what caused the build error :
|
||||||
error. Set to (None, None, None) if this build
|
|
||||||
error is not due to an exception.
|
|
||||||
|
|
||||||
|
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
|
command: the command line for the action that caused the
|
||||||
be None if the build failures is not due to the
|
build to fail (might be None if the build failures
|
||||||
executor failing)
|
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,
|
def __init__(self,
|
||||||
|
@ -95,7 +88,7 @@ class BuildError(Exception):
|
||||||
|
|
||||||
# py3: errstr should be string and not bytes.
|
# 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.status = status
|
||||||
self.exitstatus = exitstatus
|
self.exitstatus = exitstatus
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
@ -124,7 +117,7 @@ class UserError(Exception):
|
||||||
class StopError(Exception):
|
class StopError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class EnvironmentError(Exception):
|
class SConsEnvironmentError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class MSVCError(IOError):
|
class MSVCError(IOError):
|
||||||
|
@ -138,14 +131,15 @@ class ExplicitExit(Exception):
|
||||||
Exception.__init__(self, *args)
|
Exception.__init__(self, *args)
|
||||||
|
|
||||||
def convert_to_BuildError(status, exc_info=None):
|
def convert_to_BuildError(status, exc_info=None):
|
||||||
"""
|
"""Convert a return code to a BuildError Exception.
|
||||||
Convert any return code a BuildError Exception.
|
|
||||||
|
|
||||||
:Parameters:
|
The `buildError.status` we set here will normally be
|
||||||
- `status`: can either be a return code or an Exception.
|
|
||||||
|
|
||||||
The buildError.status we set here will normally be
|
|
||||||
used as the exit status of the "scons" process.
|
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):
|
if not exc_info and isinstance(status, Exception):
|
||||||
|
@ -184,20 +178,19 @@ def convert_to_BuildError(status, exc_info=None):
|
||||||
filename=filename,
|
filename=filename,
|
||||||
exc_info=exc_info)
|
exc_info=exc_info)
|
||||||
|
|
||||||
elif isinstance(status, (EnvironmentError, OSError, IOError)):
|
elif isinstance(status, (SConsEnvironmentError, OSError, IOError)):
|
||||||
# If an IOError/OSError happens, raise a BuildError.
|
# If an IOError/OSError happens, raise a BuildError.
|
||||||
# Report the name of the file or directory that caused the
|
# Report the name of the file or directory that caused the
|
||||||
# error, which might be different from the target being built
|
# error, which might be different from the target being built
|
||||||
# (for example, failure to create the directory in which the
|
# (for example, failure to create the directory in which the
|
||||||
# target file will appear).
|
# target file will appear).
|
||||||
try:
|
filename = getattr(status, 'filename', None)
|
||||||
filename = status.filename
|
strerror = getattr(status, 'strerror', str(status))
|
||||||
except AttributeError:
|
errno = getattr(status, 'errno', 2)
|
||||||
filename = None
|
|
||||||
|
|
||||||
buildError = BuildError(
|
buildError = BuildError(
|
||||||
errstr=status.strerror,
|
errstr=strerror,
|
||||||
status=status.errno,
|
status=errno,
|
||||||
exitstatus=2,
|
exitstatus=2,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
exc_info=exc_info)
|
exc_info=exc_info)
|
|
@ -1,12 +1,6 @@
|
||||||
"""SCons.Executor
|
# MIT License
|
||||||
|
|
||||||
A module for executing actions with specific lists of target and source
|
|
||||||
Nodes.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -26,9 +20,8 @@ Nodes.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Executor.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Execute actions with specific lists of target and source Nodes."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
@ -36,9 +29,10 @@ import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
from SCons.Debug import logInstanceCreation
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Memoize
|
import SCons.Memoize
|
||||||
from SCons.compat import with_metaclass, NoSlotsPyPy
|
import SCons.Util
|
||||||
|
from SCons.compat import NoSlotsPyPy
|
||||||
|
|
||||||
class Batch(object):
|
class Batch:
|
||||||
"""Remembers exact association between targets
|
"""Remembers exact association between targets
|
||||||
and sources of executor."""
|
and sources of executor."""
|
||||||
|
|
||||||
|
@ -71,7 +65,7 @@ class TSList(collections.UserList):
|
||||||
return nl[i]
|
return nl[i]
|
||||||
def __getslice__(self, i, j):
|
def __getslice__(self, i, j):
|
||||||
nl = self.func()
|
nl = self.func()
|
||||||
i = max(i, 0); j = max(j, 0)
|
i, j = max(i, 0), max(j, 0)
|
||||||
return nl[i:j]
|
return nl[i:j]
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
nl = self.func()
|
nl = self.func()
|
||||||
|
@ -80,7 +74,7 @@ class TSList(collections.UserList):
|
||||||
nl = self.func()
|
nl = self.func()
|
||||||
return repr(nl)
|
return repr(nl)
|
||||||
|
|
||||||
class TSObject(object):
|
class TSObject:
|
||||||
"""A class that implements $TARGET or $SOURCE expansions by wrapping
|
"""A class that implements $TARGET or $SOURCE expansions by wrapping
|
||||||
an Executor method.
|
an Executor method.
|
||||||
"""
|
"""
|
||||||
|
@ -127,7 +121,7 @@ def execute_action_list(obj, target, kw):
|
||||||
status = act(*args, **kw)
|
status = act(*args, **kw)
|
||||||
if isinstance(status, SCons.Errors.BuildError):
|
if isinstance(status, SCons.Errors.BuildError):
|
||||||
status.executor = obj
|
status.executor = obj
|
||||||
raise status
|
raise status # TODO pylint E0702: raising int not allowed
|
||||||
elif status:
|
elif status:
|
||||||
msg = "Error %s" % status
|
msg = "Error %s" % status
|
||||||
raise SCons.Errors.BuildError(
|
raise SCons.Errors.BuildError(
|
||||||
|
@ -155,7 +149,7 @@ _execute_str_map = {0 : execute_null_str,
|
||||||
1 : execute_actions_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.
|
"""A class for controlling instances of executing an action.
|
||||||
|
|
||||||
This largely exists to hold a single association of an action,
|
This largely exists to hold a single association of an action,
|
||||||
|
@ -450,6 +444,8 @@ class Executor(object, with_metaclass(NoSlotsPyPy)):
|
||||||
"""Fetch the signature contents. This is the main reason this
|
"""Fetch the signature contents. This is the main reason this
|
||||||
class exists, so we can compute this once and cache it regardless
|
class exists, so we can compute this once and cache it regardless
|
||||||
of how many target or source Nodes there are.
|
of how many target or source Nodes there are.
|
||||||
|
|
||||||
|
Returns bytes
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self._memo['get_contents']
|
return self._memo['get_contents']
|
||||||
|
@ -570,7 +566,6 @@ def AddBatchExecutor(key, executor):
|
||||||
nullenv = None
|
nullenv = None
|
||||||
|
|
||||||
|
|
||||||
import SCons.Util
|
|
||||||
class NullEnvironment(SCons.Util.Null):
|
class NullEnvironment(SCons.Util.Null):
|
||||||
import SCons.CacheDir
|
import SCons.CacheDir
|
||||||
_CacheDir_path = None
|
_CacheDir_path = None
|
||||||
|
@ -587,7 +582,7 @@ def get_NullEnvironment():
|
||||||
nullenv = NullEnvironment()
|
nullenv = NullEnvironment()
|
||||||
return nullenv
|
return nullenv
|
||||||
|
|
||||||
class Null(object, with_metaclass(NoSlotsPyPy)):
|
class Null(object, metaclass=NoSlotsPyPy):
|
||||||
"""A null Executor, with a null build Environment, that does
|
"""A null Executor, with a null build Environment, that does
|
||||||
nothing when the rest of the methods call it.
|
nothing when the rest of the methods call it.
|
||||||
|
|
||||||
|
@ -613,7 +608,8 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
|
||||||
'_execute_str')
|
'_execute_str')
|
||||||
|
|
||||||
def __init__(self, *args, **kw):
|
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'][:], [])]
|
self.batches = [Batch(kw['targets'][:], [])]
|
||||||
def get_build_env(self):
|
def get_build_env(self):
|
||||||
return get_NullEnvironment()
|
return get_NullEnvironment()
|
|
@ -1,13 +1,6 @@
|
||||||
"""SCons.Job
|
# MIT License
|
||||||
|
|
||||||
This module defines the Serial and Parallel classes that execute tasks to
|
|
||||||
complete a build. The Jobs class provides a higher level interface to start,
|
|
||||||
stop, and wait on jobs.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -27,9 +20,12 @@ stop, and wait on jobs.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import SCons.compat
|
||||||
|
|
||||||
|
@ -52,18 +48,18 @@ default_stack_size = 256
|
||||||
interrupt_msg = 'Build interrupted.'
|
interrupt_msg = 'Build interrupted.'
|
||||||
|
|
||||||
|
|
||||||
class InterruptState(object):
|
class InterruptState:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.interrupted = False
|
self.interrupted = False
|
||||||
|
|
||||||
def set(self):
|
def set(self):
|
||||||
self.interrupted = True
|
self.interrupted = True
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
return self.interrupted
|
return self.interrupted
|
||||||
|
|
||||||
|
|
||||||
class Jobs(object):
|
class Jobs:
|
||||||
"""An instance of this class initializes N jobs, and provides
|
"""An instance of this class initializes N jobs, and provides
|
||||||
methods for starting, stopping, and waiting on all N jobs.
|
methods for starting, stopping, and waiting on all N jobs.
|
||||||
"""
|
"""
|
||||||
|
@ -163,7 +159,7 @@ class Jobs(object):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Serial(object):
|
class Serial:
|
||||||
"""This class is used to execute tasks in series, and is more efficient
|
"""This class is used to execute tasks in series, and is more efficient
|
||||||
than Parallel, but is only appropriate for non-parallel builds. Only
|
than Parallel, but is only appropriate for non-parallel builds. Only
|
||||||
one instance of this class should be in existence at a time.
|
one instance of this class should be in existence at a time.
|
||||||
|
@ -199,7 +195,7 @@ class Serial(object):
|
||||||
task.prepare()
|
task.prepare()
|
||||||
if task.needs_execute():
|
if task.needs_execute():
|
||||||
task.execute()
|
task.execute()
|
||||||
except:
|
except Exception:
|
||||||
if self.interrupted():
|
if self.interrupted():
|
||||||
try:
|
try:
|
||||||
raise SCons.Errors.BuildError(
|
raise SCons.Errors.BuildError(
|
||||||
|
@ -264,7 +260,7 @@ else:
|
||||||
|
|
||||||
self.resultsQueue.put((task, ok))
|
self.resultsQueue.put((task, ok))
|
||||||
|
|
||||||
class ThreadPool(object):
|
class ThreadPool:
|
||||||
"""This class is responsible for spawning and managing worker threads."""
|
"""This class is responsible for spawning and managing worker threads."""
|
||||||
|
|
||||||
def __init__(self, num, stack_size, interrupted):
|
def __init__(self, num, stack_size, interrupted):
|
||||||
|
@ -281,7 +277,7 @@ else:
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
# Only print a warning if the stack size has been
|
# Only print a warning if the stack size has been
|
||||||
# explicitly set.
|
# explicitly set.
|
||||||
if not explicit_stack_size is None:
|
if explicit_stack_size is not None:
|
||||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||||
e.args[0]
|
e.args[0]
|
||||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||||
|
@ -338,7 +334,7 @@ else:
|
||||||
worker.join(1.0)
|
worker.join(1.0)
|
||||||
self.workers = []
|
self.workers = []
|
||||||
|
|
||||||
class Parallel(object):
|
class Parallel:
|
||||||
"""This class is used to execute tasks in parallel, and is somewhat
|
"""This class is used to execute tasks in parallel, and is somewhat
|
||||||
less efficient than Serial, but is appropriate for parallel builds.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,12 +20,8 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Memoize.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Decorator-based memoizer to count caching stats.
|
||||||
|
|
||||||
__doc__ = """Memoizer
|
|
||||||
|
|
||||||
A decorator-based implementation to count hits and misses of the computed
|
A decorator-based implementation to count hits and misses of the computed
|
||||||
values that various methods cache in memory.
|
values that various methods cache in memory.
|
||||||
|
@ -106,7 +103,7 @@ use_memoizer = None
|
||||||
# Global list of counter objects
|
# Global list of counter objects
|
||||||
CounterList = {}
|
CounterList = {}
|
||||||
|
|
||||||
class Counter(object):
|
class Counter:
|
||||||
"""
|
"""
|
||||||
Base class for counting memoization hits and misses.
|
Base class for counting memoization hits and misses.
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
|
# MIT License
|
||||||
"""scons.Node.Alias
|
|
||||||
|
|
||||||
Alias nodes.
|
|
||||||
|
|
||||||
This creates a hash of global Aliases (dummy targets).
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,15 +20,18 @@ This creates a hash of global Aliases (dummy targets).
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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 collections
|
||||||
|
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
from SCons.Util import MD5signature
|
||||||
|
|
||||||
class AliasNameSpace(collections.UserDict):
|
class AliasNameSpace(collections.UserDict):
|
||||||
def Alias(self, name, **kw):
|
def Alias(self, name, **kw):
|
||||||
|
@ -166,7 +161,7 @@ class Alias(SCons.Node.Node):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
contents = self.get_contents()
|
contents = self.get_contents()
|
||||||
csig = SCons.Util.MD5signature(contents)
|
csig = MD5signature(contents)
|
||||||
self.get_ninfo().csig = csig
|
self.get_ninfo().csig = csig
|
||||||
return csig
|
return csig
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
"""scons.Node.FS
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/FS.py 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 fnmatch
|
||||||
import os
|
import os
|
||||||
|
@ -43,22 +38,25 @@ import stat
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import codecs
|
import codecs
|
||||||
|
from itertools import chain
|
||||||
|
import importlib.util
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
from SCons.Debug import logInstanceCreation, Trace
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Memoize
|
import SCons.Memoize
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
import SCons.Node.Alias
|
import SCons.Node.Alias
|
||||||
import SCons.Subst
|
import SCons.Subst
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
from SCons.Util import MD5signature, MD5filesignature, MD5collect
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
from SCons.Debug import Trace
|
|
||||||
|
|
||||||
print_duplicate = 0
|
print_duplicate = 0
|
||||||
|
|
||||||
|
MD5_TIMESTAMP_DEBUG = False
|
||||||
|
|
||||||
|
|
||||||
def sconsign_none(node):
|
def sconsign_none(node):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -74,6 +72,9 @@ def sconsign_dir(node):
|
||||||
_sconsign_map = {0 : sconsign_none,
|
_sconsign_map = {0 : sconsign_none,
|
||||||
1 : sconsign_dir}
|
1 : sconsign_dir}
|
||||||
|
|
||||||
|
class FileBuildInfoFileToCsigMappingError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class EntryProxyAttributeError(AttributeError):
|
class EntryProxyAttributeError(AttributeError):
|
||||||
"""
|
"""
|
||||||
An AttributeError subclass for recording and displaying the name
|
An AttributeError subclass for recording and displaying the name
|
||||||
|
@ -132,7 +133,10 @@ def initialize_do_splitdrive():
|
||||||
global do_splitdrive
|
global do_splitdrive
|
||||||
global has_unc
|
global has_unc
|
||||||
drive, path = os.path.splitdrive('X:/foo')
|
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
|
do_splitdrive = not not drive or has_unc
|
||||||
|
|
||||||
|
@ -272,7 +276,7 @@ def set_duplicate(duplicate):
|
||||||
'copy' : _copy_func
|
'copy' : _copy_func
|
||||||
}
|
}
|
||||||
|
|
||||||
if not duplicate in Valid_Duplicates:
|
if duplicate not in Valid_Duplicates:
|
||||||
raise SCons.Errors.InternalError("The argument of set_duplicate "
|
raise SCons.Errors.InternalError("The argument of set_duplicate "
|
||||||
"should be in Valid_Duplicates")
|
"should be in Valid_Duplicates")
|
||||||
global Link_Funcs
|
global Link_Funcs
|
||||||
|
@ -282,11 +286,13 @@ def set_duplicate(duplicate):
|
||||||
Link_Funcs.append(link_dict[func])
|
Link_Funcs.append(link_dict[func])
|
||||||
|
|
||||||
def LinkFunc(target, source, env):
|
def LinkFunc(target, source, env):
|
||||||
# Relative paths cause problems with symbolic links, so
|
"""
|
||||||
# we use absolute paths, which may be a problem for people
|
Relative paths cause problems with symbolic links, so
|
||||||
# who want to move their soft-linked src-trees around. Those
|
we use absolute paths, which may be a problem for people
|
||||||
# people should use the 'hard-copy' mode, softlinks cannot be
|
who want to move their soft-linked src-trees around. Those
|
||||||
# used for that; at least I have no idea how ...
|
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()
|
src = source[0].get_abspath()
|
||||||
dest = target[0].get_abspath()
|
dest = target[0].get_abspath()
|
||||||
dir, file = os.path.split(dest)
|
dir, file = os.path.split(dest)
|
||||||
|
@ -328,7 +334,12 @@ Unlink = SCons.Action.Action(UnlinkFunc, None)
|
||||||
|
|
||||||
def MkdirFunc(target, source, env):
|
def MkdirFunc(target, source, env):
|
||||||
t = target[0]
|
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())
|
t.fs.mkdir(t.get_abspath())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -351,7 +362,7 @@ def get_MkdirBuilder():
|
||||||
name = "MkdirBuilder")
|
name = "MkdirBuilder")
|
||||||
return MkdirBuilder
|
return MkdirBuilder
|
||||||
|
|
||||||
class _Null(object):
|
class _Null:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_null = _Null()
|
_null = _Null()
|
||||||
|
@ -367,7 +378,7 @@ else:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DiskChecker(object):
|
class DiskChecker:
|
||||||
def __init__(self, type, do, ignore):
|
def __init__(self, type, do, ignore):
|
||||||
self.type = type
|
self.type = type
|
||||||
self.do = do
|
self.do = do
|
||||||
|
@ -423,7 +434,7 @@ class EntryProxy(SCons.Util.Proxy):
|
||||||
|
|
||||||
# In PY3 if a class defines __eq__, then it must explicitly provide
|
# In PY3 if a class defines __eq__, then it must explicitly provide
|
||||||
# __hash__. Since SCons.Util.Proxy provides __eq__ we need the following
|
# __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__')
|
__hash__ = SCons.Util.Delegate('__hash__')
|
||||||
|
|
||||||
def __get_abspath(self):
|
def __get_abspath(self):
|
||||||
|
@ -463,7 +474,7 @@ class EntryProxy(SCons.Util.Proxy):
|
||||||
return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
|
return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
|
||||||
|
|
||||||
def __get_windows_path(self):
|
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."""
|
regardless of platform."""
|
||||||
if OS_SEP == '\\':
|
if OS_SEP == '\\':
|
||||||
return self
|
return self
|
||||||
|
@ -514,7 +525,7 @@ class EntryProxy(SCons.Util.Proxy):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
try:
|
||||||
attr = SCons.Util.Proxy.__getattr__(self, name)
|
attr = SCons.Util.Proxy.__getattr__(self, name)
|
||||||
except AttributeError as e:
|
except AttributeError:
|
||||||
# Raise our own AttributeError subclass with an
|
# Raise our own AttributeError subclass with an
|
||||||
# overridden __str__() method that identifies the
|
# overridden __str__() method that identifies the
|
||||||
# name of the entry that caused the exception.
|
# name of the entry that caused the exception.
|
||||||
|
@ -682,13 +693,32 @@ class Base(SCons.Node.Node):
|
||||||
|
|
||||||
@SCons.Memoize.CountMethodCall
|
@SCons.Memoize.CountMethodCall
|
||||||
def stat(self):
|
def stat(self):
|
||||||
try: return self._memo['stat']
|
try:
|
||||||
except KeyError: pass
|
return self._memo['stat']
|
||||||
try: result = self.fs.stat(self.get_abspath())
|
except KeyError:
|
||||||
except os.error: result = None
|
pass
|
||||||
|
try:
|
||||||
|
result = self.fs.stat(self.get_abspath())
|
||||||
|
except os.error:
|
||||||
|
result = None
|
||||||
|
|
||||||
self._memo['stat'] = result
|
self._memo['stat'] = result
|
||||||
return 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):
|
def exists(self):
|
||||||
return SCons.Node._exists_map[self._func_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)
|
return SCons.Node._rexists_map[self._func_rexists](self)
|
||||||
|
|
||||||
def getmtime(self):
|
def getmtime(self):
|
||||||
st = self.stat()
|
if self.islink():
|
||||||
if st: return st[stat.ST_MTIME]
|
st = self.lstat()
|
||||||
else: return None
|
else:
|
||||||
|
st = self.stat()
|
||||||
|
|
||||||
|
if st:
|
||||||
|
return st[stat.ST_MTIME]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def getsize(self):
|
def getsize(self):
|
||||||
st = self.stat()
|
if self.islink():
|
||||||
if st: return st[stat.ST_SIZE]
|
st = self.lstat()
|
||||||
else: return None
|
else:
|
||||||
|
st = self.stat()
|
||||||
|
|
||||||
|
if st:
|
||||||
|
return st[stat.ST_SIZE]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def isdir(self):
|
def isdir(self):
|
||||||
st = self.stat()
|
st = self.stat()
|
||||||
|
@ -939,13 +981,13 @@ class Entry(Base):
|
||||||
def disambiguate(self, must_exist=None):
|
def disambiguate(self, must_exist=None):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
if self.isdir():
|
if self.isfile():
|
||||||
self.__class__ = Dir
|
|
||||||
self._morph()
|
|
||||||
elif self.isfile():
|
|
||||||
self.__class__ = File
|
self.__class__ = File
|
||||||
self._morph()
|
self._morph()
|
||||||
self.clear()
|
self.clear()
|
||||||
|
elif self.isdir():
|
||||||
|
self.__class__ = Dir
|
||||||
|
self._morph()
|
||||||
else:
|
else:
|
||||||
# There was nothing on-disk at this location, so look in
|
# There was nothing on-disk at this location, so look in
|
||||||
# the src directory.
|
# the src directory.
|
||||||
|
@ -1047,22 +1089,23 @@ class Entry(Base):
|
||||||
_classEntry = Entry
|
_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
|
Note that there's a very good chance we'll refactor this part of
|
||||||
# a local file system. Essentially, this wraps any function in
|
the architecture in some way as we really implement the interface(s)
|
||||||
# the os, os.path or shutil modules that we use to actually go do
|
for remote file system Nodes. For example, the right architecture
|
||||||
# anything with or to the local file system.
|
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.
|
||||||
# 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)
|
We're not using chdir() yet because the calling subclass method
|
||||||
# for remote file system Nodes. For example, the right architecture
|
needs to use os.chdir() directly to avoid recursion. Will we
|
||||||
# might be to have this be a subclass instead of a base class.
|
really need this one?
|
||||||
# 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):
|
#def chdir(self, path):
|
||||||
# return os.chdir(path)
|
# return os.chdir(path)
|
||||||
def chmod(self, path, mode):
|
def chmod(self, path, mode):
|
||||||
|
@ -1391,7 +1434,7 @@ class FS(LocalFS):
|
||||||
self.Top.addRepository(d)
|
self.Top.addRepository(d)
|
||||||
|
|
||||||
def PyPackageDir(self, modulename):
|
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
|
For example scons might resolve to
|
||||||
Windows: C:\Python27\Lib\site-packages\scons-2.5.1
|
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"""
|
This can be useful when we want to determine a toolpath based on a python module name"""
|
||||||
|
|
||||||
dirpath = ''
|
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
|
# Python3 Code
|
||||||
import imp
|
modspec = importlib.util.find_spec(modulename)
|
||||||
splitname = modulename.split('.')
|
dirpath = os.path.dirname(modspec.origin)
|
||||||
srchpths = sys.path
|
|
||||||
for item in splitname:
|
|
||||||
file, path, desc = imp.find_module(item, srchpths)
|
|
||||||
if file is not None:
|
|
||||||
path = os.path.dirname(path)
|
|
||||||
srchpths = [path]
|
|
||||||
dirpath = path
|
|
||||||
else:
|
|
||||||
# Python3 Code
|
|
||||||
import importlib.util
|
|
||||||
modspec = importlib.util.find_spec(modulename)
|
|
||||||
dirpath = os.path.dirname(modspec.origin)
|
|
||||||
return self._lookup(dirpath, None, Dir, True)
|
return self._lookup(dirpath, None, Dir, True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1522,9 +1553,7 @@ class Dir(Base):
|
||||||
self.repositories = []
|
self.repositories = []
|
||||||
self.srcdir = None
|
self.srcdir = None
|
||||||
|
|
||||||
self.entries = {}
|
self.entries = {'.': self, '..': self.dir}
|
||||||
self.entries['.'] = self
|
|
||||||
self.entries['..'] = self.dir
|
|
||||||
self.cwd = self
|
self.cwd = self
|
||||||
self.searched = 0
|
self.searched = 0
|
||||||
self._sconsign = None
|
self._sconsign = None
|
||||||
|
@ -1585,7 +1614,7 @@ class Dir(Base):
|
||||||
This clears any cached information that is invalidated by changing
|
This clears any cached information that is invalidated by changing
|
||||||
the repository."""
|
the repository."""
|
||||||
|
|
||||||
for node in list(self.entries.values()):
|
for node in self.entries.values():
|
||||||
if node != self.dir:
|
if node != self.dir:
|
||||||
if node != self and isinstance(node, Dir):
|
if node != self and isinstance(node, Dir):
|
||||||
node.__clearRepositoryCache(duplicate)
|
node.__clearRepositoryCache(duplicate)
|
||||||
|
@ -1596,7 +1625,7 @@ class Dir(Base):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
if duplicate is not None:
|
if duplicate is not None:
|
||||||
node.duplicate=duplicate
|
node.duplicate = duplicate
|
||||||
|
|
||||||
def __resetDuplicate(self, node):
|
def __resetDuplicate(self, node):
|
||||||
if node != self:
|
if node != self:
|
||||||
|
@ -1662,7 +1691,7 @@ class Dir(Base):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def addRepository(self, dir):
|
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)
|
self.repositories.append(dir)
|
||||||
dir._tpath = '.'
|
dir._tpath = '.'
|
||||||
self.__clearRepositoryCache()
|
self.__clearRepositoryCache()
|
||||||
|
@ -1702,7 +1731,7 @@ class Dir(Base):
|
||||||
if self is other:
|
if self is other:
|
||||||
result = '.'
|
result = '.'
|
||||||
|
|
||||||
elif not other in self._path_elements:
|
elif other not in self._path_elements:
|
||||||
try:
|
try:
|
||||||
other_dir = other.get_dir()
|
other_dir = other.get_dir()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -1836,7 +1865,7 @@ class Dir(Base):
|
||||||
node is called which has a child directory, the child
|
node is called which has a child directory, the child
|
||||||
directory should return the hash of its contents."""
|
directory should return the hash of its contents."""
|
||||||
contents = self.get_contents()
|
contents = self.get_contents()
|
||||||
return SCons.Util.MD5signature(contents)
|
return MD5signature(contents)
|
||||||
|
|
||||||
def do_duplicate(self, src):
|
def do_duplicate(self, src):
|
||||||
pass
|
pass
|
||||||
|
@ -2234,7 +2263,7 @@ class RootDir(Dir):
|
||||||
this directory.
|
this directory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['_lookupDict']
|
__slots__ = ('_lookupDict', 'abspath', 'path')
|
||||||
|
|
||||||
def __init__(self, drive, fs):
|
def __init__(self, drive, fs):
|
||||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
|
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
|
||||||
|
@ -2276,13 +2305,17 @@ class RootDir(Dir):
|
||||||
self._tpath = dirname
|
self._tpath = dirname
|
||||||
self.dirname = 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._morph()
|
||||||
|
|
||||||
self.duplicate = 0
|
self.duplicate = 0
|
||||||
self._lookupDict = {}
|
self._lookupDict = {'': self, '/': self}
|
||||||
|
|
||||||
self._lookupDict[''] = self
|
|
||||||
self._lookupDict['/'] = self
|
|
||||||
self.root = self
|
self.root = self
|
||||||
# The // entry is necessary because os.path.normpath()
|
# The // entry is necessary because os.path.normpath()
|
||||||
# preserves double slashes at the beginning of a path on Posix
|
# preserves double slashes at the beginning of a path on Posix
|
||||||
|
@ -2302,9 +2335,7 @@ class RootDir(Dir):
|
||||||
self.repositories = []
|
self.repositories = []
|
||||||
self.srcdir = None
|
self.srcdir = None
|
||||||
|
|
||||||
self.entries = {}
|
self.entries = {'.': self, '..': self.dir}
|
||||||
self.entries['.'] = self
|
|
||||||
self.entries['..'] = self.dir
|
|
||||||
self.cwd = self
|
self.cwd = self
|
||||||
self.searched = 0
|
self.searched = 0
|
||||||
self._sconsign = None
|
self._sconsign = None
|
||||||
|
@ -2440,7 +2471,7 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
|
||||||
"""
|
"""
|
||||||
state = getattr(self, '__dict__', {}).copy()
|
state = getattr(self, '__dict__', {}).copy()
|
||||||
for obj in type(self).mro():
|
for obj in type(self).mro():
|
||||||
for name in getattr(obj,'__slots__',()):
|
for name in getattr(obj, '__slots__', ()):
|
||||||
if hasattr(self, name):
|
if hasattr(self, name):
|
||||||
state[name] = getattr(self, name)
|
state[name] = getattr(self, name)
|
||||||
|
|
||||||
|
@ -2462,11 +2493,42 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
|
||||||
if key not in ('__weakref__',):
|
if key not in ('__weakref__',):
|
||||||
setattr(self, key, value)
|
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):
|
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
|
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):
|
def convert_to_sconsign(self):
|
||||||
"""
|
"""
|
||||||
Converts this FileBuildInfo object for writing to a .sconsign file
|
Converts this FileBuildInfo object for writing to a .sconsign file
|
||||||
|
@ -2567,7 +2629,8 @@ class File(Base):
|
||||||
NodeInfo = FileNodeInfo
|
NodeInfo = FileNodeInfo
|
||||||
BuildInfo = FileBuildInfo
|
BuildInfo = FileBuildInfo
|
||||||
|
|
||||||
md5_chunksize = 64
|
# Although the command-line argument is in kilobytes, this is in bytes.
|
||||||
|
md5_chunksize = 65536
|
||||||
|
|
||||||
def diskcheck_match(self):
|
def diskcheck_match(self):
|
||||||
diskcheck_match(self, self.isdir,
|
diskcheck_match(self, self.isdir,
|
||||||
|
@ -2630,11 +2693,13 @@ class File(Base):
|
||||||
def scanner_key(self):
|
def scanner_key(self):
|
||||||
return self.get_suffix()
|
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)
|
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
|
This attempts to figure out what the encoding of the text is
|
||||||
based upon the BOM bytes, and then decodes the contents so that
|
based upon the BOM bytes, and then decodes the contents so that
|
||||||
it's a valid python string.
|
it's a valid python string.
|
||||||
|
@ -2658,19 +2723,16 @@ class File(Base):
|
||||||
try:
|
try:
|
||||||
return contents.decode('latin-1')
|
return contents.decode('latin-1')
|
||||||
except UnicodeDecodeError as e:
|
except UnicodeDecodeError as e:
|
||||||
return contents.decode('utf-8', error='backslashreplace')
|
return contents.decode('utf-8', errors='backslashreplace')
|
||||||
|
|
||||||
|
|
||||||
def get_content_hash(self):
|
def get_content_hash(self) -> str:
|
||||||
"""
|
"""Compute and return the hash of the file contents."""
|
||||||
Compute and return the MD5 hash for this file.
|
|
||||||
"""
|
|
||||||
if not self.rexists():
|
if not self.rexists():
|
||||||
return SCons.Util.MD5signature('')
|
return MD5signature(SCons.Util.NOFILE)
|
||||||
fname = self.rfile().get_abspath()
|
fname = self.rfile().get_abspath()
|
||||||
try:
|
try:
|
||||||
cs = SCons.Util.MD5filesignature(fname,
|
cs = MD5filesignature(fname, chunksize=File.md5_chunksize)
|
||||||
chunksize=SCons.Node.FS.File.md5_chunksize*1024)
|
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
if not e.filename:
|
if not e.filename:
|
||||||
e.filename = fname
|
e.filename = fname
|
||||||
|
@ -2678,7 +2740,7 @@ class File(Base):
|
||||||
return cs
|
return cs
|
||||||
|
|
||||||
@SCons.Memoize.CountMethodCall
|
@SCons.Memoize.CountMethodCall
|
||||||
def get_size(self):
|
def get_size(self) -> int:
|
||||||
try:
|
try:
|
||||||
return self._memo['get_size']
|
return self._memo['get_size']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -2687,14 +2749,14 @@ class File(Base):
|
||||||
if self.rexists():
|
if self.rexists():
|
||||||
size = self.rfile().getsize()
|
size = self.rfile().getsize()
|
||||||
else:
|
else:
|
||||||
size = 0
|
# sentinel value for doesn't exist, even in repository
|
||||||
|
size = -1
|
||||||
|
|
||||||
self._memo['get_size'] = size
|
self._memo['get_size'] = size
|
||||||
|
|
||||||
return size
|
return size
|
||||||
|
|
||||||
@SCons.Memoize.CountMethodCall
|
@SCons.Memoize.CountMethodCall
|
||||||
def get_timestamp(self):
|
def get_timestamp(self) -> int:
|
||||||
try:
|
try:
|
||||||
return self._memo['get_timestamp']
|
return self._memo['get_timestamp']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -2706,7 +2768,6 @@ class File(Base):
|
||||||
timestamp = 0
|
timestamp = 0
|
||||||
|
|
||||||
self._memo['get_timestamp'] = timestamp
|
self._memo['get_timestamp'] = timestamp
|
||||||
|
|
||||||
return timestamp
|
return timestamp
|
||||||
|
|
||||||
convert_copy_attrs = [
|
convert_copy_attrs = [
|
||||||
|
@ -2718,7 +2779,6 @@ class File(Base):
|
||||||
'ninfo',
|
'ninfo',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
convert_sig_attrs = [
|
convert_sig_attrs = [
|
||||||
'bsourcesigs',
|
'bsourcesigs',
|
||||||
'bimplicitsigs',
|
'bimplicitsigs',
|
||||||
|
@ -2971,7 +3031,7 @@ class File(Base):
|
||||||
|
|
||||||
@see: built() and Node.release_target_info()
|
@see: built() and Node.release_target_info()
|
||||||
"""
|
"""
|
||||||
if (self.released_target_info or SCons.Node.interactive):
|
if self.released_target_info or SCons.Node.interactive:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not hasattr(self.attributes, 'keep_targetinfo'):
|
if not hasattr(self.attributes, 'keep_targetinfo'):
|
||||||
|
@ -3059,7 +3119,10 @@ class File(Base):
|
||||||
SCons.Node.Node.prepare(self)
|
SCons.Node.Node.prepare(self)
|
||||||
|
|
||||||
if self.get_state() != SCons.Node.up_to_date:
|
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:
|
if self.is_derived() and not self.precious:
|
||||||
self._rmv_existing()
|
self._rmv_existing()
|
||||||
else:
|
else:
|
||||||
|
@ -3108,7 +3171,7 @@ class File(Base):
|
||||||
# SIGNATURE SUBSYSTEM
|
# SIGNATURE SUBSYSTEM
|
||||||
#
|
#
|
||||||
|
|
||||||
def get_max_drift_csig(self):
|
def get_max_drift_csig(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns the content signature currently stored for this node
|
Returns the content signature currently stored for this node
|
||||||
if it's been unmodified longer than the max_drift value, or the
|
if it's been unmodified longer than the max_drift value, or the
|
||||||
|
@ -3134,15 +3197,8 @@ class File(Base):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_csig(self):
|
def get_csig(self) -> str:
|
||||||
"""
|
"""Generate a node's content signature."""
|
||||||
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
|
|
||||||
"""
|
|
||||||
ninfo = self.get_ninfo()
|
ninfo = self.get_ninfo()
|
||||||
try:
|
try:
|
||||||
return ninfo.csig
|
return ninfo.csig
|
||||||
|
@ -3151,9 +3207,11 @@ class File(Base):
|
||||||
|
|
||||||
csig = self.get_max_drift_csig()
|
csig = self.get_max_drift_csig()
|
||||||
if csig is None:
|
if csig is None:
|
||||||
|
|
||||||
try:
|
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()
|
contents = self.get_contents()
|
||||||
else:
|
else:
|
||||||
csig = self.get_content_hash()
|
csig = self.get_content_hash()
|
||||||
|
@ -3225,46 +3283,232 @@ class File(Base):
|
||||||
self._memo['changed'] = has_changed
|
self._memo['changed'] = has_changed
|
||||||
return 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()
|
cur_csig = self.get_csig()
|
||||||
try:
|
try:
|
||||||
return cur_csig != prev_ni.csig
|
return cur_csig != prev_ni.csig
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 1
|
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
|
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:
|
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:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
return False
|
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:
|
try:
|
||||||
return self.get_timestamp() > target.get_timestamp()
|
return self.get_timestamp() > target.get_timestamp()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 1
|
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:
|
try:
|
||||||
return self.get_timestamp() != prev_ni.timestamp
|
return self.get_timestamp() != prev_ni.timestamp
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def is_up_to_date(self):
|
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
|
T = 0
|
||||||
if T: Trace('is_up_to_date(%s):' % self)
|
if T: Trace('is_up_to_date(%s):' % self)
|
||||||
if not self.exists():
|
if not self.exists():
|
||||||
if T: Trace(' 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()
|
r = self.rfile()
|
||||||
if r != self:
|
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 not self.changed(r):
|
||||||
if T: Trace(' changed(%s):' % r)
|
if T: Trace(' changed(%s):' % r)
|
||||||
# ...and it's even up-to-date...
|
# ...and it's even up-to-date...
|
||||||
|
@ -3272,7 +3516,9 @@ class File(Base):
|
||||||
# ...and they'd like a local copy.
|
# ...and they'd like a local copy.
|
||||||
e = LocalCopy(self, r, None)
|
e = LocalCopy(self, r, None)
|
||||||
if isinstance(e, SCons.Errors.BuildError):
|
if isinstance(e, SCons.Errors.BuildError):
|
||||||
raise
|
# Likely this should be re-raising exception e
|
||||||
|
# (which would be BuildError)
|
||||||
|
raise e
|
||||||
SCons.Node.store_info_map[self.store_info](self)
|
SCons.Node.store_info_map[self.store_info](self)
|
||||||
if T: Trace(' 1\n')
|
if T: Trace(' 1\n')
|
||||||
return 1
|
return 1
|
||||||
|
@ -3293,11 +3539,14 @@ class File(Base):
|
||||||
result = self
|
result = self
|
||||||
if not self.exists():
|
if not self.exists():
|
||||||
norm_name = _my_normcase(self.name)
|
norm_name = _my_normcase(self.name)
|
||||||
for dir in self.dir.get_all_rdirs():
|
for repo_dir in self.dir.get_all_rdirs():
|
||||||
try: node = dir.entries[norm_name]
|
try:
|
||||||
except KeyError: node = dir.file_on_disk(self.name)
|
node = repo_dir.entries[norm_name]
|
||||||
|
except KeyError:
|
||||||
|
node = repo_dir.file_on_disk(self.name)
|
||||||
|
|
||||||
if node and node.exists() and \
|
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()):
|
or not node.is_derived()):
|
||||||
result = node
|
result = node
|
||||||
# Copy over our local attributes to the repository
|
# Copy over our local attributes to the repository
|
||||||
|
@ -3317,6 +3566,28 @@ class File(Base):
|
||||||
self._memo['rfile'] = result
|
self._memo['rfile'] = result
|
||||||
return 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):
|
def rstr(self):
|
||||||
return str(self.rfile())
|
return str(self.rfile())
|
||||||
|
|
||||||
|
@ -3341,8 +3612,7 @@ class File(Base):
|
||||||
|
|
||||||
cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self)
|
cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self)
|
||||||
if not self.exists() and cachefile and os.path.exists(cachefile):
|
if not self.exists() and cachefile and os.path.exists(cachefile):
|
||||||
self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \
|
self.cachedir_csig = MD5filesignature(cachefile, File.md5_chunksize)
|
||||||
SCons.Node.FS.File.md5_chunksize * 1024)
|
|
||||||
else:
|
else:
|
||||||
self.cachedir_csig = self.get_csig()
|
self.cachedir_csig = self.get_csig()
|
||||||
return self.cachedir_csig
|
return self.cachedir_csig
|
||||||
|
@ -3362,7 +3632,7 @@ class File(Base):
|
||||||
|
|
||||||
executor = self.get_executor()
|
executor = self.get_executor()
|
||||||
|
|
||||||
result = self.contentsig = SCons.Util.MD5signature(executor.get_contents())
|
result = self.contentsig = MD5signature(executor.get_contents())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_cachedir_bsig(self):
|
def get_cachedir_bsig(self):
|
||||||
|
@ -3374,6 +3644,8 @@ class File(Base):
|
||||||
because multiple targets built by the same action will all
|
because multiple targets built by the same action will all
|
||||||
have the same build signature, and we have to differentiate
|
have the same build signature, and we have to differentiate
|
||||||
them somehow.
|
them somehow.
|
||||||
|
|
||||||
|
Signature should normally be string of hex digits.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self.cachesig
|
return self.cachesig
|
||||||
|
@ -3383,12 +3655,15 @@ class File(Base):
|
||||||
# Collect signatures for all children
|
# Collect signatures for all children
|
||||||
children = self.children()
|
children = self.children()
|
||||||
sigs = [n.get_cachedir_csig() for n in children]
|
sigs = [n.get_cachedir_csig() for n in children]
|
||||||
|
|
||||||
# Append this node's signature...
|
# Append this node's signature...
|
||||||
sigs.append(self.get_contents_sig())
|
sigs.append(self.get_contents_sig())
|
||||||
|
|
||||||
# ...and it's path
|
# ...and it's path
|
||||||
sigs.append(self.get_internal_path())
|
sigs.append(self.get_internal_path())
|
||||||
|
|
||||||
# Merge this all into a single signature
|
# Merge this all into a single signature
|
||||||
result = self.cachesig = SCons.Util.MD5collect(sigs)
|
result = self.cachesig = MD5collect(sigs)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
default_fs = None
|
default_fs = None
|
||||||
|
@ -3399,7 +3674,7 @@ def get_default_fs():
|
||||||
default_fs = FS()
|
default_fs = FS()
|
||||||
return default_fs
|
return default_fs
|
||||||
|
|
||||||
class FileFinder(object):
|
class FileFinder:
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -3472,7 +3747,7 @@ class FileFinder(object):
|
||||||
if verbose and not callable(verbose):
|
if verbose and not callable(verbose):
|
||||||
if not SCons.Util.is_String(verbose):
|
if not SCons.Util.is_String(verbose):
|
||||||
verbose = "find_file"
|
verbose = "find_file"
|
||||||
_verbose = u' %s: ' % verbose
|
_verbose = ' %s: ' % verbose
|
||||||
verbose = lambda s: sys.stdout.write(_verbose + s)
|
verbose = lambda s: sys.stdout.write(_verbose + s)
|
||||||
|
|
||||||
filedir, filename = os.path.split(filename)
|
filedir, filename = os.path.split(filename)
|
|
@ -1,11 +1,6 @@
|
||||||
"""scons.Node.Python
|
# MIT License
|
||||||
|
|
||||||
Python nodes.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -25,12 +20,14 @@ Python nodes.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/Python.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Python nodes."""
|
||||||
|
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
|
|
||||||
|
_memo_lookup_map = {}
|
||||||
|
|
||||||
|
|
||||||
class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
||||||
__slots__ = ('csig',)
|
__slots__ = ('csig',)
|
||||||
current_version_id = 2
|
current_version_id = 2
|
||||||
|
@ -38,18 +35,18 @@ class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
||||||
field_list = ['csig']
|
field_list = ['csig']
|
||||||
|
|
||||||
def str_to_node(self, s):
|
def str_to_node(self, s):
|
||||||
return Value(s)
|
return ValueWithMemo(s)
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
"""
|
"""
|
||||||
Return all fields that shall be pickled. Walk the slots in the class
|
Return all fields that shall be pickled. Walk the slots in the class
|
||||||
hierarchy and add those to the state dictionary. If a '__dict__' slot is
|
hierarchy and add those to the state dictionary. If a '__dict__' slot
|
||||||
available, copy all entries to the dictionary. Also include the version
|
is available, copy all entries to the dictionary. Also include the
|
||||||
id, which is fixed for all instances of a class.
|
version id, which is fixed for all instances of a class.
|
||||||
"""
|
"""
|
||||||
state = getattr(self, '__dict__', {}).copy()
|
state = getattr(self, '__dict__', {}).copy()
|
||||||
for obj in type(self).mro():
|
for obj in type(self).mro():
|
||||||
for name in getattr(obj,'__slots__',()):
|
for name in getattr(obj, '__slots__', ()):
|
||||||
if hasattr(self, name):
|
if hasattr(self, name):
|
||||||
state[name] = getattr(self, name)
|
state[name] = getattr(self, name)
|
||||||
|
|
||||||
|
@ -76,6 +73,7 @@ class ValueBuildInfo(SCons.Node.BuildInfoBase):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
current_version_id = 2
|
current_version_id = 2
|
||||||
|
|
||||||
|
|
||||||
class Value(SCons.Node.Node):
|
class Value(SCons.Node.Node):
|
||||||
"""A class for Python variables, typically passed on the command line
|
"""A class for Python variables, typically passed on the command line
|
||||||
or generated by a script, but not from a file or some other source.
|
or generated by a script, but not from a file or some other source.
|
||||||
|
@ -84,7 +82,7 @@ class Value(SCons.Node.Node):
|
||||||
NodeInfo = ValueNodeInfo
|
NodeInfo = ValueNodeInfo
|
||||||
BuildInfo = ValueBuildInfo
|
BuildInfo = ValueBuildInfo
|
||||||
|
|
||||||
def __init__(self, value, built_value=None):
|
def __init__(self, value, built_value=None, name=None):
|
||||||
SCons.Node.Node.__init__(self)
|
SCons.Node.Node.__init__(self)
|
||||||
self.value = value
|
self.value = value
|
||||||
self.changed_since_last_build = 6
|
self.changed_since_last_build = 6
|
||||||
|
@ -92,6 +90,13 @@ class Value(SCons.Node.Node):
|
||||||
if built_value is not None:
|
if built_value is not None:
|
||||||
self.built_value = built_value
|
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):
|
def str_for_display(self):
|
||||||
return repr(self.value)
|
return repr(self.value)
|
||||||
|
|
||||||
|
@ -124,7 +129,7 @@ class Value(SCons.Node.Node):
|
||||||
self.built_value = self.value
|
self.built_value = self.value
|
||||||
return self.built_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
|
"""By the assumption that the node.built_value is a
|
||||||
deterministic product of the sources, the contents of a Value
|
deterministic product of the sources, the contents of a Value
|
||||||
are the concatenation of all the contents of its sources. As
|
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
|
###TODO: something reasonable about universal newlines
|
||||||
contents = str(self.value)
|
contents = str(self.value)
|
||||||
for kid in self.children(None):
|
for kid in self.children(None):
|
||||||
contents = contents + kid.get_contents().decode()
|
# Get csig() value of child as this is more efficent
|
||||||
|
contents = contents + kid.get_csig()
|
||||||
return contents
|
return contents
|
||||||
|
|
||||||
def get_contents(self):
|
def get_contents(self) -> bytes:
|
||||||
text_contents = self.get_text_contents()
|
"""Get contents for signature calculations."""
|
||||||
try:
|
return self.get_text_contents().encode()
|
||||||
return text_contents.encode()
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
# Already encoded as python2 str are bytes
|
|
||||||
return text_contents
|
|
||||||
|
|
||||||
|
|
||||||
def changed_since_last_build(self, target, prev_ni):
|
def changed_since_last_build(self, target, prev_ni):
|
||||||
cur_csig = self.get_csig()
|
cur_csig = self.get_csig()
|
||||||
try:
|
try:
|
||||||
return cur_csig != prev_ni.csig
|
return cur_csig != prev_ni.csig
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 1
|
return True
|
||||||
|
|
||||||
def get_csig(self, calc=None):
|
def get_csig(self, calc=None):
|
||||||
"""Because we're a Python value node and don't have a real
|
"""Because we're a Python value node and don't have a real
|
||||||
timestamp, we get to ignore the calculator and just use the
|
timestamp, we get to ignore the calculator and just use the
|
||||||
value contents."""
|
value contents.
|
||||||
|
|
||||||
|
Returns string. Ideally string of hex digits. (Not bytes)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self.ninfo.csig
|
return self.ninfo.csig
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
contents = self.get_contents()
|
|
||||||
|
contents = self.get_text_contents()
|
||||||
|
|
||||||
self.get_ninfo().csig = contents
|
self.get_ninfo().csig = contents
|
||||||
return 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:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
||||||
# indent-tabs-mode:nil
|
# indent-tabs-mode:nil
|
|
@ -1,28 +1,6 @@
|
||||||
"""SCons.Node
|
# MIT License
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -43,21 +21,36 @@ from __future__ import print_function
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/__init__.py 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 collections
|
||||||
import copy
|
import copy
|
||||||
from itertools import chain
|
from itertools import chain, zip_longest
|
||||||
|
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
|
||||||
import SCons.Executor
|
import SCons.Executor
|
||||||
import SCons.Memoize
|
import SCons.Memoize
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
from SCons.compat import NoSlotsPyPy
|
||||||
from SCons.Debug import Trace
|
from SCons.Debug import logInstanceCreation, Trace
|
||||||
|
from SCons.Util import MD5signature
|
||||||
from SCons.compat import with_metaclass, NoSlotsPyPy
|
|
||||||
|
|
||||||
print_duplicate = 0
|
print_duplicate = 0
|
||||||
|
|
||||||
|
@ -102,9 +95,12 @@ implicit_deps_changed = 0
|
||||||
|
|
||||||
# A variable that can be set to an interface-specific function be called
|
# A variable that can be set to an interface-specific function be called
|
||||||
# to annotate a Node with information about its creation.
|
# 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
|
# Gets set to 'True' if we're running in interactive mode. Is
|
||||||
# currently used to release parts of a target's info during
|
# currently used to release parts of a target's info during
|
||||||
|
@ -139,6 +135,7 @@ def exists_entry(node):
|
||||||
node.disambiguate()
|
node.disambiguate()
|
||||||
return _exists_map[node._func_exists](node)
|
return _exists_map[node._func_exists](node)
|
||||||
|
|
||||||
|
|
||||||
def exists_file(node):
|
def exists_file(node):
|
||||||
# Duplicate from source path if we are set up to do this.
|
# Duplicate from source path if we are set up to do this.
|
||||||
if node.duplicate and not node.is_derived() and not node.linked:
|
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
|
# The source file does not exist. Make sure no old
|
||||||
# copy remains in the variant directory.
|
# copy remains in the variant directory.
|
||||||
if print_duplicate:
|
if print_duplicate:
|
||||||
print("dup: no src for %s, unlinking old variant copy"%self)
|
print("dup: no src for %s, unlinking old variant copy" % node)
|
||||||
if exists_base(node) or node.islink():
|
if exists_base(node) or node.islink():
|
||||||
node.fs.unlink(node.get_internal_path())
|
node.fs.unlink(node.get_internal_path())
|
||||||
# Return None explicitly because the Base.exists() call
|
# Return None explicitly because the Base.exists() call
|
||||||
|
@ -249,7 +246,7 @@ _target_from_source_map = {0 : target_from_source_none,
|
||||||
#
|
#
|
||||||
# First, the single decider functions
|
# 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
|
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
|
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()
|
cur_csig = node.get_csig()
|
||||||
try:
|
try:
|
||||||
return cur_csig != prev_ni.csig
|
return cur_csig != prev_ni.csig
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 1
|
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()
|
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):
|
def changed_since_last_build_state_changed(node, target, prev_ni, repo_node=None):
|
||||||
return target.get_build_env().decide_source(node, target, prev_ni)
|
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()
|
cur_csig = node.get_csig()
|
||||||
try:
|
try:
|
||||||
return cur_csig != prev_ni.csig
|
return cur_csig != prev_ni.csig
|
||||||
|
@ -341,7 +344,7 @@ store_info_map = {0 : store_info_pass,
|
||||||
|
|
||||||
# Classes for signature info for Nodes.
|
# Classes for signature info for Nodes.
|
||||||
|
|
||||||
class NodeInfoBase(object):
|
class NodeInfoBase:
|
||||||
"""
|
"""
|
||||||
The generic base class for signature information for a Node.
|
The generic base class for signature information for a Node.
|
||||||
|
|
||||||
|
@ -380,6 +383,7 @@ class NodeInfoBase(object):
|
||||||
"""
|
"""
|
||||||
state = other.__getstate__()
|
state = other.__getstate__()
|
||||||
self.__setstate__(state)
|
self.__setstate__(state)
|
||||||
|
|
||||||
def format(self, field_list=None, names=0):
|
def format(self, field_list=None, names=0):
|
||||||
if field_list is None:
|
if field_list is None:
|
||||||
try:
|
try:
|
||||||
|
@ -435,7 +439,7 @@ class NodeInfoBase(object):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class BuildInfoBase(object):
|
class BuildInfoBase:
|
||||||
"""
|
"""
|
||||||
The generic base class for build information for a Node.
|
The generic base class for build information for a Node.
|
||||||
|
|
||||||
|
@ -498,13 +502,14 @@ class BuildInfoBase(object):
|
||||||
setattr(self, key, value)
|
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
|
"""The base Node class, for entities that we know how to
|
||||||
build, or use to build other Nodes.
|
build, or use to build other Nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['sources',
|
__slots__ = ['sources',
|
||||||
'sources_set',
|
'sources_set',
|
||||||
|
'target_peers',
|
||||||
'_specific_sources',
|
'_specific_sources',
|
||||||
'depends',
|
'depends',
|
||||||
'depends_set',
|
'depends_set',
|
||||||
|
@ -545,7 +550,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
'_func_get_contents',
|
'_func_get_contents',
|
||||||
'_func_target_from_source']
|
'_func_target_from_source']
|
||||||
|
|
||||||
class Attrs(object):
|
class Attrs:
|
||||||
__slots__ = ('shared', '__dict__')
|
__slots__ = ('shared', '__dict__')
|
||||||
|
|
||||||
|
|
||||||
|
@ -599,6 +604,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
self._func_rexists = 1
|
self._func_rexists = 1
|
||||||
self._func_get_contents = 0
|
self._func_get_contents = 0
|
||||||
self._func_target_from_source = 0
|
self._func_target_from_source = 0
|
||||||
|
self.ninfo = None
|
||||||
|
|
||||||
self.clear_memoized_values()
|
self.clear_memoized_values()
|
||||||
|
|
||||||
|
@ -665,7 +671,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
executor.cleanup()
|
executor.cleanup()
|
||||||
|
|
||||||
def reset_executor(self):
|
def reset_executor(self):
|
||||||
"Remove cached executor; forces recompute when needed."
|
"""Remove cached executor; forces recompute when needed."""
|
||||||
try:
|
try:
|
||||||
delattr(self, 'executor')
|
delattr(self, 'executor')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -760,6 +766,25 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
for parent in self.waiting_parents:
|
for parent in self.waiting_parents:
|
||||||
parent.implicit = None
|
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()
|
self.clear()
|
||||||
|
|
||||||
if self.pseudo:
|
if self.pseudo:
|
||||||
|
@ -786,25 +811,21 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
|
|
||||||
def release_target_info(self):
|
def release_target_info(self):
|
||||||
"""Called just after this node has been marked
|
"""Called just after this node has been marked
|
||||||
up-to-date or was built completely.
|
up-to-date or was built completely.
|
||||||
|
|
||||||
This is where we try to release as many target node infos
|
This is where we try to release as many target node infos
|
||||||
as possible for clean builds and update runs, in order
|
as possible for clean builds and update runs, in order
|
||||||
to minimize the overall memory consumption.
|
to minimize the overall memory consumption.
|
||||||
|
|
||||||
By purging attributes that aren't needed any longer after
|
By purging attributes that aren't needed any longer after
|
||||||
a Node (=File) got built, we don't have to care that much how
|
a Node (=File) got built, we don't have to care that much how
|
||||||
many KBytes a Node actually requires...as long as we free
|
many KBytes a Node actually requires...as long as we free
|
||||||
the memory shortly afterwards.
|
the memory shortly afterwards.
|
||||||
|
|
||||||
@see: built() and File.release_target_info()
|
@see: built() and File.release_target_info()
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
def add_to_waiting_s_e(self, node):
|
def add_to_waiting_s_e(self, node):
|
||||||
self.waiting_s_e.add(node)
|
self.waiting_s_e.add(node)
|
||||||
|
|
||||||
|
@ -840,10 +861,12 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
self.clear_memoized_values()
|
self.clear_memoized_values()
|
||||||
self.ninfo = self.new_ninfo()
|
self.ninfo = self.new_ninfo()
|
||||||
self.executor_cleanup()
|
self.executor_cleanup()
|
||||||
try:
|
for attr in ['cachedir_csig', 'cachesig', 'contentsig']:
|
||||||
delattr(self, '_calculated_sig')
|
try:
|
||||||
except AttributeError:
|
delattr(self, attr)
|
||||||
pass
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
self.cached = 0
|
||||||
self.includes = None
|
self.includes = None
|
||||||
|
|
||||||
def clear_memoized_values(self):
|
def clear_memoized_values(self):
|
||||||
|
@ -863,7 +886,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
than simply examining the builder attribute directly ("if
|
than simply examining the builder attribute directly ("if
|
||||||
node.builder: ..."). When the builder attribute is examined
|
node.builder: ..."). When the builder attribute is examined
|
||||||
directly, it ends up calling __getattr__ for both the __len__
|
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
|
class(es), generating a bazillion extra calls and slowing
|
||||||
things down immensely.
|
things down immensely.
|
||||||
"""
|
"""
|
||||||
|
@ -912,6 +935,18 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
"""
|
"""
|
||||||
return _is_derived_map[self._func_is_derived](self)
|
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):
|
def alter_targets(self):
|
||||||
"""Return a list of alternate targets for this Node.
|
"""Return a list of alternate targets for this Node.
|
||||||
"""
|
"""
|
||||||
|
@ -1097,11 +1132,10 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
return ninfo
|
return ninfo
|
||||||
|
|
||||||
def get_ninfo(self):
|
def get_ninfo(self):
|
||||||
try:
|
if self.ninfo is not None:
|
||||||
return self.ninfo
|
|
||||||
except AttributeError:
|
|
||||||
self.ninfo = self.new_ninfo()
|
|
||||||
return self.ninfo
|
return self.ninfo
|
||||||
|
self.ninfo = self.new_ninfo()
|
||||||
|
return self.ninfo
|
||||||
|
|
||||||
def new_binfo(self):
|
def new_binfo(self):
|
||||||
binfo = self.BuildInfo()
|
binfo = self.BuildInfo()
|
||||||
|
@ -1133,10 +1167,10 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
|
|
||||||
if self.has_builder():
|
if self.has_builder():
|
||||||
binfo.bact = str(executor)
|
binfo.bact = str(executor)
|
||||||
binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
|
binfo.bactsig = MD5signature(executor.get_contents())
|
||||||
|
|
||||||
if self._specific_sources:
|
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:
|
else:
|
||||||
sources = executor.get_unignored_sources(self, self.ignore)
|
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.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.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
|
# Because self.implicit is initialized to None (and not empty list [])
|
||||||
binfo.bdependsigs = [d.get_ninfo() for d in self.depends if d not in ignore_set]
|
# we have to handle this case
|
||||||
|
if not self.implicit:
|
||||||
binfo.bimplicit = self.implicit or []
|
binfo.bimplicit = []
|
||||||
binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit if i not in ignore_set]
|
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
|
return binfo
|
||||||
|
|
||||||
|
@ -1167,7 +1205,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
return self.ninfo.csig
|
return self.ninfo.csig
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
ninfo = self.get_ninfo()
|
ninfo = self.get_ninfo()
|
||||||
ninfo.csig = SCons.Util.MD5signature(self.get_contents())
|
ninfo.csig = MD5signature(self.get_contents())
|
||||||
return self.ninfo.csig
|
return self.ninfo.csig
|
||||||
|
|
||||||
def get_cachedir_csig(self):
|
def get_cachedir_csig(self):
|
||||||
|
@ -1213,7 +1251,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
return _exists_map[self._func_exists](self)
|
return _exists_map[self._func_exists](self)
|
||||||
|
|
||||||
def rexists(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:
|
# There are no repositories by default:
|
||||||
return _rexists_map[self._func_rexists](self)
|
return _rexists_map[self._func_rexists](self)
|
||||||
|
|
||||||
|
@ -1452,14 +1490,13 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
for child, prev_ni in zip(children, then):
|
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)
|
if t: Trace(': %s changed' % child)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
contents = self.get_executor().get_contents()
|
|
||||||
if self.has_builder():
|
if self.has_builder():
|
||||||
import SCons.Util
|
contents = self.get_executor().get_contents()
|
||||||
newsig = SCons.Util.MD5signature(contents)
|
newsig = MD5signature(contents)
|
||||||
if bi.bactsig != newsig:
|
if bi.bactsig != newsig:
|
||||||
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
|
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
|
||||||
result = True
|
result = True
|
||||||
|
@ -1607,29 +1644,39 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
|
||||||
# so we only print them after running them through this lambda
|
# so we only print them after running them through this lambda
|
||||||
# to turn them into the right relative Node and then return
|
# to turn them into the right relative Node and then return
|
||||||
# its string.
|
# its string.
|
||||||
def stringify( s, E=self.dir.Entry ) :
|
def stringify( s, E=self.dir.Entry):
|
||||||
if hasattr( s, 'dir' ) :
|
if hasattr( s, 'dir' ) :
|
||||||
return str(E(s))
|
return str(E(s))
|
||||||
return str(s)
|
return str(s)
|
||||||
|
|
||||||
lines = []
|
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:
|
if removed:
|
||||||
removed = list(map(stringify, removed))
|
removed = [stringify(r) for r in removed]
|
||||||
fmt = "`%s' is no longer a dependency\n"
|
fmt = "`%s' is no longer a dependency\n"
|
||||||
lines.extend([fmt % s for s in removed])
|
lines.extend([fmt % s for s in removed])
|
||||||
|
|
||||||
for k in new_bkids:
|
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))
|
lines.append("`%s' is a new dependency\n" % stringify(k))
|
||||||
elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
|
else:
|
||||||
lines.append("`%s' changed\n" % stringify(k))
|
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:
|
if len(lines) == 0 and old_bkids != new_bkids:
|
||||||
lines.append("the dependency order changed:\n" +
|
lines.append("the dependency order changed:\n")
|
||||||
"%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) +
|
lines.append("->Sources\n")
|
||||||
"%snew: %s\n" % (' '*15, list(map(stringify, new_bkids))))
|
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:
|
if len(lines) == 0:
|
||||||
def fmt_with_title(title, strlines):
|
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 ignore_cycle(node, stack): pass
|
||||||
def do_nothing(node, parent): pass
|
def do_nothing(node, parent): pass
|
||||||
|
|
||||||
class Walker(object):
|
class Walker:
|
||||||
"""An iterator for walking a Node tree.
|
"""An iterator for walking a Node tree.
|
||||||
|
|
||||||
This is depth-first, children are visited before the parent.
|
This is depth-first, children are visited before the parent.
|
||||||
The Walker object can be initialized with any node, and
|
The Walker object can be initialized with any node, and
|
||||||
returns the next node on the descent with each get_next() call.
|
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'.
|
get the children of a node instead of calling 'children'.
|
||||||
'cycle_func' is an optional function that will be called
|
'cycle_func' is an optional function that will be called
|
||||||
when a cycle is detected.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,17 +20,13 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/PathList.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Handle lists of directory paths.
|
||||||
|
|
||||||
__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.
|
|
||||||
|
|
||||||
|
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
|
import os
|
||||||
|
@ -66,7 +63,7 @@ def node_conv(obj):
|
||||||
result = get()
|
result = get()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class _PathList(object):
|
class _PathList:
|
||||||
"""
|
"""
|
||||||
An actual PathList object.
|
An actual PathList object.
|
||||||
"""
|
"""
|
||||||
|
@ -143,7 +140,7 @@ class _PathList(object):
|
||||||
return tuple(result)
|
return tuple(result)
|
||||||
|
|
||||||
|
|
||||||
class PathListCache(object):
|
class PathListCache:
|
||||||
"""
|
"""
|
||||||
A class to handle caching of PathList lookups.
|
A class to handle caching of PathList lookups.
|
||||||
|
|
|
@ -1,26 +1,6 @@
|
||||||
"""SCons.Platform
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -40,14 +20,29 @@ their own platform definition.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/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 SCons.compat
|
||||||
|
|
||||||
import imp
|
import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -60,8 +55,8 @@ import SCons.Tool
|
||||||
def platform_default():
|
def platform_default():
|
||||||
"""Return the platform string for our execution environment.
|
"""Return the platform string for our execution environment.
|
||||||
|
|
||||||
The returned value should map to one of the SCons/Platform/*.py
|
The returned value should map to one of the SCons/Platform/\*.py
|
||||||
files. Since we're architecture independent, though, we don't
|
files. Since scons is architecture independent, though, we don't
|
||||||
care about the machine architecture.
|
care about the machine architecture.
|
||||||
"""
|
"""
|
||||||
osname = os.name
|
osname = os.name
|
||||||
|
@ -87,6 +82,7 @@ def platform_default():
|
||||||
else:
|
else:
|
||||||
return sys.platform
|
return sys.platform
|
||||||
|
|
||||||
|
|
||||||
def platform_module(name = platform_default()):
|
def platform_module(name = platform_default()):
|
||||||
"""Return the imported module for the platform.
|
"""Return the imported module for the platform.
|
||||||
|
|
||||||
|
@ -100,13 +96,8 @@ def platform_module(name = platform_default()):
|
||||||
eval(full_name)
|
eval(full_name)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
file, path, desc = imp.find_module(name,
|
# the specific platform module is a relative import
|
||||||
sys.modules['SCons.Platform'].__path__)
|
mod = importlib.import_module("." + name, __name__)
|
||||||
try:
|
|
||||||
mod = imp.load_module(full_name, file, path, desc)
|
|
||||||
finally:
|
|
||||||
if file:
|
|
||||||
file.close()
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
import zipimport
|
import zipimport
|
||||||
|
@ -117,12 +108,14 @@ def platform_module(name = platform_default()):
|
||||||
setattr(SCons.Platform, name, mod)
|
setattr(SCons.Platform, name, mod)
|
||||||
return sys.modules[full_name]
|
return sys.modules[full_name]
|
||||||
|
|
||||||
|
|
||||||
def DefaultToolList(platform, env):
|
def DefaultToolList(platform, env):
|
||||||
"""Select a default tool list for the specified platform.
|
"""Select a default tool list for the specified platform.
|
||||||
"""
|
"""
|
||||||
return SCons.Tool.tool_list(platform, env)
|
return SCons.Tool.tool_list(platform, env)
|
||||||
|
|
||||||
class PlatformSpec(object):
|
|
||||||
|
class PlatformSpec:
|
||||||
def __init__(self, name, generate):
|
def __init__(self, name, generate):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.generate = generate
|
self.generate = generate
|
||||||
|
@ -133,22 +126,35 @@ class PlatformSpec(object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
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:
|
class TempFileMunge:
|
||||||
env["TEMPFILE"] = TempFileMunge
|
"""Convert long command lines to use a temporary file.
|
||||||
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
|
|
||||||
|
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
|
By default, the name of the temporary file used begins with a
|
||||||
prefix of '@'. This may be configred for other tool chains by
|
prefix of '@'. This may be configured for other tool chains by
|
||||||
setting '$TEMPFILEPREFIX'.
|
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):
|
def __init__(self, cmd, cmdstr = None):
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
|
@ -182,24 +188,41 @@ class TempFileMunge(object):
|
||||||
|
|
||||||
# Check if we already created the temporary file for this target
|
# Check if we already created the temporary file for this target
|
||||||
# It should have been previously done by Action.strfunction() call
|
# It should have been previously done by Action.strfunction() call
|
||||||
node = target[0] if SCons.Util.is_List(target) else target
|
if SCons.Util.is_List(target):
|
||||||
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
|
node = target[0]
|
||||||
if node is not None else None
|
else:
|
||||||
if cmdlist is not None :
|
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
|
return cmdlist
|
||||||
|
|
||||||
# We do a normpath because mktemp() has what appears to be
|
# Default to the .lnk suffix for the benefit of the Phar Lap
|
||||||
# a bug in Windows that will use a forward slash as a path
|
|
||||||
# delimiter. Windows's link mistakes that for a command line
|
|
||||||
# switch and barfs.
|
|
||||||
#
|
|
||||||
# We use the .lnk suffix for the benefit of the Phar Lap
|
|
||||||
# linkloc linker, which likes to append an .lnk suffix if
|
# linkloc linker, which likes to append an .lnk suffix if
|
||||||
# none is given.
|
# none is given.
|
||||||
(fd, tmp) = tempfile.mkstemp('.lnk', text=True)
|
if 'TEMPFILESUFFIX' in env:
|
||||||
native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp))
|
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
|
# The sh shell will try to escape the backslashes in the
|
||||||
# path, so unescape them.
|
# path, so unescape them.
|
||||||
native_tmp = native_tmp.replace('\\', r'\\\\')
|
native_tmp = native_tmp.replace('\\', r'\\\\')
|
||||||
|
@ -217,8 +240,10 @@ class TempFileMunge(object):
|
||||||
prefix = '@'
|
prefix = '@'
|
||||||
|
|
||||||
args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
|
args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
|
||||||
os.write(fd, 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)
|
os.close(fd)
|
||||||
|
|
||||||
# XXX Using the SCons.Action.print_actions value directly
|
# XXX Using the SCons.Action.print_actions value directly
|
||||||
# like this is bogus, but expedient. This class should
|
# like this is bogus, but expedient. This class should
|
||||||
# really be rewritten as an Action that defines the
|
# really be rewritten as an Action that defines the
|
||||||
|
@ -239,19 +264,41 @@ class TempFileMunge(object):
|
||||||
source) if self.cmdstr is not None else ''
|
source) if self.cmdstr is not None else ''
|
||||||
# Print our message only if XXXCOMSTR returns an empty string
|
# Print our message only if XXXCOMSTR returns an empty string
|
||||||
if len(cmdstr) == 0 :
|
if len(cmdstr) == 0 :
|
||||||
print("Using tempfile "+native_tmp+" for command line:\n"+
|
cmdstr = ("Using tempfile "+native_tmp+" for command line:\n"+
|
||||||
str(cmd[0]) + " " + " ".join(args))
|
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
|
# Store the temporary file command list into the target Node.attributes
|
||||||
# to avoid creating two temporary files one for print and one for execute.
|
# to avoid creating two temporary files one for print and one for execute.
|
||||||
cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
|
|
||||||
if node is not None:
|
if node is not None:
|
||||||
try :
|
try:
|
||||||
setattr(node.attributes, 'tempfile_cmdlist', cmdlist)
|
# 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:
|
except AttributeError:
|
||||||
pass
|
node.attributes.tempfile_cmdlist = {cmdlist_key:cmdlist}
|
||||||
|
|
||||||
return 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()):
|
def Platform(name = platform_default()):
|
||||||
"""Select a canned Platform specification.
|
"""Select a canned Platform specification.
|
|
@ -1,14 +1,6 @@
|
||||||
"""engine.SCons.Platform.aix
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,11 +20,14 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import subprocess
|
||||||
|
|
||||||
from . import posix
|
from . import posix
|
||||||
|
@ -55,6 +50,7 @@ def get_xlc(env, xlc=None, packages=[]):
|
||||||
pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package],
|
pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package],
|
||||||
stdin = 'devnull',
|
stdin = 'devnull',
|
||||||
stderr = 'devnull',
|
stderr = 'devnull',
|
||||||
|
universal_newlines=True,
|
||||||
stdout = subprocess.PIPE)
|
stdout = subprocess.PIPE)
|
||||||
# output of lslpp is something like this:
|
# output of lslpp is something like this:
|
||||||
# #Path:Fileset:File
|
# #Path:Fileset:File
|
||||||
|
@ -69,14 +65,13 @@ def get_xlc(env, xlc=None, packages=[]):
|
||||||
or ('/' not in xlc and filename.endswith('/' + xlc)):
|
or ('/' not in xlc and filename.endswith('/' + xlc)):
|
||||||
xlcVersion = fileset.split()[1]
|
xlcVersion = fileset.split()[1]
|
||||||
xlcPath, sep, xlc = filename.rpartition('/')
|
xlcPath, sep, xlc = filename.rpartition('/')
|
||||||
pass
|
|
||||||
pass
|
|
||||||
return (xlcPath, xlc, xlcVersion)
|
return (xlcPath, xlc, xlcVersion)
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
posix.generate(env)
|
posix.generate(env)
|
||||||
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
|
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
|
||||||
env['MAXLINELENGTH'] = 21576
|
env['MAXLINELENGTH'] = 21576
|
||||||
|
env['SHLIBSUFFIX'] = '.a'
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
|
@ -1,14 +1,6 @@
|
||||||
"""SCons.Platform.cygwin
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,13 +20,26 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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 . import posix
|
||||||
from SCons.Platform import TempFileMunge
|
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):
|
def generate(env):
|
||||||
posix.generate(env)
|
posix.generate(env)
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
"""engine.SCons.Platform.darwin
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,13 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
from . import posix
|
||||||
import os
|
import os
|
||||||
|
@ -56,12 +52,11 @@ def generate(env):
|
||||||
|
|
||||||
for file in filelist:
|
for file in filelist:
|
||||||
if os.path.isfile(file):
|
if os.path.isfile(file):
|
||||||
f = open(file, 'r')
|
with open(file, 'r') as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line:
|
if line:
|
||||||
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
||||||
f.close()
|
|
||||||
|
|
||||||
# Not sure why this wasn't the case all along?
|
# 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):
|
if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
|
|
@ -1,14 +1,6 @@
|
||||||
"""engine.SCons.Platform.hpux
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,13 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
from . import posix
|
||||||
|
|
||||||
|
@ -39,6 +35,8 @@ def generate(env):
|
||||||
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
|
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
|
||||||
env['MAXLINELENGTH'] = 2045000
|
env['MAXLINELENGTH'] = 2045000
|
||||||
|
|
||||||
|
env['SHLIBSUFFIX'] = '.sl'
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
||||||
# indent-tabs-mode:nil
|
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
||||||
"""SCons.Platform.irix
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,13 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
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
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,14 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
from . import win32
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
|
@ -1,14 +1,6 @@
|
||||||
"""SCons.Platform.posix
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,19 +20,22 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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 errno
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import select
|
import select
|
||||||
|
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
from SCons.Platform import TempFileMunge
|
from SCons.Platform import TempFileMunge
|
||||||
|
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||||
|
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||||
|
|
||||||
exitvalmap = {
|
exitvalmap = {
|
||||||
2 : 127,
|
2 : 127,
|
||||||
|
@ -48,7 +43,7 @@ exitvalmap = {
|
||||||
}
|
}
|
||||||
|
|
||||||
def escape(arg):
|
def escape(arg):
|
||||||
"escape shell special characters"
|
"""escape shell special characters"""
|
||||||
slash = '\\'
|
slash = '\\'
|
||||||
special = '"$'
|
special = '"$'
|
||||||
|
|
||||||
|
@ -89,7 +84,7 @@ def generate(env):
|
||||||
|
|
||||||
if 'ENV' not in env:
|
if 'ENV' not in env:
|
||||||
env['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['OBJPREFIX'] = ''
|
||||||
env['OBJSUFFIX'] = '.o'
|
env['OBJSUFFIX'] = '.o'
|
||||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||||
|
@ -119,6 +114,9 @@ def generate(env):
|
||||||
# Must be able to have GCC and DMD work in the same build, so:
|
# Must be able to have GCC and DMD work in the same build, so:
|
||||||
env['__DRPATH'] = '$_DRPATH'
|
env['__DRPATH'] = '$_DRPATH'
|
||||||
|
|
||||||
|
if enable_virtualenv and not ignore_virtualenv:
|
||||||
|
ImportVirtualenv(env)
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
||||||
# indent-tabs-mode:nil
|
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
||||||
"""engine.SCons.Platform.sunos
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,13 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
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
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,13 @@ selection method.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -39,59 +35,13 @@ import tempfile
|
||||||
|
|
||||||
from SCons.Platform.posix import exitvalmap
|
from SCons.Platform.posix import exitvalmap
|
||||||
from SCons.Platform import TempFileMunge
|
from SCons.Platform import TempFileMunge
|
||||||
|
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||||
|
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
|
||||||
try:
|
CHOCO_DEFAULT_PATH = [
|
||||||
import msvcrt
|
r'C:\ProgramData\chocolatey\bin'
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
# Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile
|
# 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.
|
# Without this, python can randomly crash while using -jN.
|
||||||
# See the python bug at http://bugs.python.org/issue6476
|
# See the python bug at http://bugs.python.org/issue6476
|
||||||
# and SCons issue at
|
# 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):
|
def spawnve(mode, file, args, env):
|
||||||
spawn_lock.acquire()
|
spawn_lock.acquire()
|
||||||
try:
|
try:
|
||||||
|
@ -168,59 +118,68 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||||
# we redirect it into a temporary file tmpFileStdout
|
# we redirect it into a temporary file tmpFileStdout
|
||||||
# (tmpFileStderr) and copy the contents of this file
|
# (tmpFileStderr) and copy the contents of this file
|
||||||
# to stdout (stderr) given in the argument
|
# 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:
|
if not sh:
|
||||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||||
return 127
|
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
|
# one temporary file for stdout and stderr
|
||||||
stdoutRedirected = 0
|
tmpFileStdout, tmpFileStdoutName = tempfile.mkstemp(text=True)
|
||||||
stderrRedirected = 0
|
os.close(tmpFileStdout) # don't need open until the subproc is done
|
||||||
for arg in args:
|
tmpFileStderr, tmpFileStderrName = tempfile.mkstemp(text=True)
|
||||||
# are there more possibilities to redirect stdout ?
|
os.close(tmpFileStderr)
|
||||||
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
|
|
||||||
|
|
||||||
# redirect output of non-redirected streams to our tempfiles
|
# check if output is redirected
|
||||||
if stdoutRedirected == 0:
|
stdoutRedirected = False
|
||||||
args.append(">" + str(tmpFileStdout))
|
stderrRedirected = False
|
||||||
if stderrRedirected == 0:
|
for arg in args:
|
||||||
args.append("2>" + str(tmpFileStderr))
|
# 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:
|
try:
|
||||||
args = [sh, '/C', escape(' '.join(args)) ]
|
ret = exitvalmap[e.errno]
|
||||||
ret = spawnve(os.P_WAIT, sh, args, env)
|
except KeyError:
|
||||||
except OSError as e:
|
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror))
|
||||||
# catch any error
|
if stderr is not None:
|
||||||
try:
|
stderr.write("scons: %s: %s\n" % (cmd, e.strerror))
|
||||||
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
|
|
||||||
|
|
||||||
if stderr is not None and stderrRedirected == 0:
|
# copy child output from tempfiles to our streams
|
||||||
try:
|
# and do clean up stuff
|
||||||
stderr.write(open( tmpFileStderr, "r" ).read())
|
if stdout is not None and not stdoutRedirected:
|
||||||
os.remove( tmpFileStderr )
|
try:
|
||||||
except (IOError, OSError):
|
with open(tmpFileStdoutName, "r") as tmpFileStdout:
|
||||||
pass
|
stdout.write(tmpFileStdout.read())
|
||||||
return ret
|
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):
|
def exec_spawn(l, env):
|
||||||
|
@ -288,9 +247,6 @@ def get_system_root():
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Ensure system root is a string and not unicode
|
|
||||||
# (This only matters for py27 were unicode in env passed to POpen fails)
|
|
||||||
val = str(val)
|
|
||||||
_system_root = val
|
_system_root = val
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
@ -312,7 +268,6 @@ def get_program_files_dir():
|
||||||
val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
|
val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
|
||||||
except SCons.Util.RegError:
|
except SCons.Util.RegError:
|
||||||
val = ''
|
val = ''
|
||||||
pass
|
|
||||||
|
|
||||||
if val == '':
|
if val == '':
|
||||||
# A reasonable default if we can't read the registry
|
# A reasonable default if we can't read the registry
|
||||||
|
@ -322,7 +277,7 @@ def get_program_files_dir():
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
class ArchDefinition(object):
|
class ArchDefinition:
|
||||||
"""
|
"""
|
||||||
Determine which windows CPU were running on.
|
Determine which windows CPU were running on.
|
||||||
A class for defining architecture-specific settings and logic.
|
A class for defining architecture-specific settings and logic.
|
||||||
|
@ -436,7 +391,7 @@ def generate(env):
|
||||||
if v:
|
if v:
|
||||||
env['ENV']['COMSPEC'] = 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['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
|
||||||
env['OBJPREFIX'] = ''
|
env['OBJPREFIX'] = ''
|
||||||
|
@ -462,6 +417,9 @@ def generate(env):
|
||||||
env['HOST_OS'] = 'win32'
|
env['HOST_OS'] = 'win32'
|
||||||
env['HOST_ARCH'] = get_architecture().arch
|
env['HOST_ARCH'] = get_architecture().arch
|
||||||
|
|
||||||
|
if enable_virtualenv and not ignore_virtualenv:
|
||||||
|
ImportVirtualenv(env)
|
||||||
|
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
|
@ -1,18 +1,6 @@
|
||||||
"""SCons.SConf
|
# MIT License
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -32,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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/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 SCons.compat
|
||||||
|
|
||||||
|
import atexit
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -56,6 +51,7 @@ import SCons.Warnings
|
||||||
import SCons.Conftest
|
import SCons.Conftest
|
||||||
|
|
||||||
from SCons.Debug import Trace
|
from SCons.Debug import Trace
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
# Turn off the Conftest error logging
|
# Turn off the Conftest error logging
|
||||||
SCons.Conftest.LogInputFiles = 0
|
SCons.Conftest.LogInputFiles = 0
|
||||||
|
@ -65,9 +61,9 @@ SCons.Conftest.LogErrorMessages = 0
|
||||||
build_type = None
|
build_type = None
|
||||||
build_types = ['clean', 'help']
|
build_types = ['clean', 'help']
|
||||||
|
|
||||||
def SetBuildType(type):
|
def SetBuildType(buildtype):
|
||||||
global build_type
|
global build_type
|
||||||
build_type = type
|
build_type = buildtype
|
||||||
|
|
||||||
# to be set, if we are in dry-run mode
|
# to be set, if we are in dry-run mode
|
||||||
dryrun = 0
|
dryrun = 0
|
||||||
|
@ -98,7 +94,7 @@ def SetProgressDisplay(display):
|
||||||
|
|
||||||
SConfFS = None
|
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_logs = {} # all config.log files created in this build
|
||||||
_ac_config_hs = {} # all config.h files created in this build
|
_ac_config_hs = {} # all config.h files created in this build
|
||||||
sconf_global = None # current sconf object
|
sconf_global = None # current sconf object
|
||||||
|
@ -132,11 +128,11 @@ def CreateConfigHBuilder(env):
|
||||||
_stringConfigH)
|
_stringConfigH)
|
||||||
sconfigHBld = SCons.Builder.Builder(action=action)
|
sconfigHBld = SCons.Builder.Builder(action=action)
|
||||||
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
|
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
|
||||||
for k in list(_ac_config_hs.keys()):
|
for k, v in _ac_config_hs.items():
|
||||||
env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
|
env.SConfigHBuilder(k, env.Value(v))
|
||||||
|
|
||||||
|
|
||||||
class SConfWarning(SCons.Warnings.Warning):
|
class SConfWarning(SCons.Warnings.SConsWarning):
|
||||||
pass
|
pass
|
||||||
SCons.Warnings.enableWarningClass(SConfWarning)
|
SCons.Warnings.enableWarningClass(SConfWarning)
|
||||||
|
|
||||||
|
@ -161,11 +157,14 @@ class ConfigureCacheError(SConfError):
|
||||||
def __init__(self,target):
|
def __init__(self,target):
|
||||||
SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
|
SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target))
|
||||||
|
|
||||||
|
|
||||||
# define actions for building text files
|
# define actions for building text files
|
||||||
def _createSource( target, source, env ):
|
def _createSource(target, source, env):
|
||||||
fd = open(str(target[0]), "w")
|
fd = open(str(target[0]), "w")
|
||||||
fd.write(source[0].get_contents().decode())
|
fd.write(source[0].get_contents().decode())
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
|
|
||||||
def _stringSource( target, source, env ):
|
def _stringSource( target, source, env ):
|
||||||
return (str(target[0]) + ' <-\n |' +
|
return (str(target[0]) + ' <-\n |' +
|
||||||
source[0].get_contents().decode().replace( '\n', "\n |" ) )
|
source[0].get_contents().decode().replace( '\n', "\n |" ) )
|
||||||
|
@ -187,7 +186,7 @@ class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
|
||||||
self.string = string
|
self.string = string
|
||||||
|
|
||||||
|
|
||||||
class Streamer(object):
|
class Streamer:
|
||||||
"""
|
"""
|
||||||
'Sniffer' for a file-like writable object. Similar to the unix tool tee.
|
'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
|
# ConfigureCacheError and if yes, reraise the exception
|
||||||
exc_type = self.exc_info()[0]
|
exc_type = self.exc_info()[0]
|
||||||
if issubclass(exc_type, SConfError):
|
if issubclass(exc_type, SConfError):
|
||||||
|
# TODO pylint E0704: bare raise not inside except
|
||||||
raise
|
raise
|
||||||
elif issubclass(exc_type, SCons.Errors.BuildError):
|
elif issubclass(exc_type, SCons.Errors.BuildError):
|
||||||
# we ignore Build Errors (occurs, when a test doesn't pass)
|
# we ignore Build Errors (occurs, when a test doesn't pass)
|
||||||
|
@ -269,7 +269,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
||||||
cached_error = False
|
cached_error = False
|
||||||
cachable = True
|
cachable = True
|
||||||
for t in self.targets:
|
for t in self.targets:
|
||||||
if T: Trace('%s' % (t))
|
if T: Trace('%s' % t)
|
||||||
bi = t.get_stored_info().binfo
|
bi = t.get_stored_info().binfo
|
||||||
if isinstance(bi, SConfBuildInfo):
|
if isinstance(bi, SConfBuildInfo):
|
||||||
if T: Trace(': SConfBuildInfo')
|
if T: Trace(': SConfBuildInfo')
|
||||||
|
@ -279,7 +279,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
||||||
else:
|
else:
|
||||||
if T: Trace(': get_state() %s' % t.get_state())
|
if T: Trace(': get_state() %s' % t.get_state())
|
||||||
if T: Trace(': changed() %s' % t.changed())
|
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
|
changed = True
|
||||||
if T: Trace(': changed %s' % changed)
|
if T: Trace(': changed %s' % changed)
|
||||||
cached_error = cached_error or bi.result
|
cached_error = cached_error or bi.result
|
||||||
|
@ -323,18 +323,6 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
||||||
s = sys.stdout = sys.stderr = Streamer(sys.stdout)
|
s = sys.stdout = sys.stderr = Streamer(sys.stdout)
|
||||||
try:
|
try:
|
||||||
env = self.targets[0].get_build_env()
|
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
|
env['PSTDOUT'] = env['PSTDERR'] = s
|
||||||
try:
|
try:
|
||||||
sconf.cached = 0
|
sconf.cached = 0
|
||||||
|
@ -383,7 +371,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
|
||||||
sconsign.set_entry(t.name, sconsign_entry)
|
sconsign.set_entry(t.name, sconsign_entry)
|
||||||
sconsign.merge()
|
sconsign.merge()
|
||||||
|
|
||||||
class SConfBase(object):
|
class SConfBase:
|
||||||
"""This is simply a class to represent a configure context. After
|
"""This is simply a class to represent a configure context. After
|
||||||
creating a SConf object, you can call any tests. After finished with your
|
creating a SConf object, you can call any tests. After finished with your
|
||||||
tests, be sure to call the Finish() method, which returns the modified
|
tests, be sure to call the Finish() method, which returns the modified
|
||||||
|
@ -405,12 +393,41 @@ class SConfBase(object):
|
||||||
build tests in the VariantDir, not in the SourceDir)
|
build tests in the VariantDir, not in the SourceDir)
|
||||||
"""
|
"""
|
||||||
global SConfFS
|
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:
|
if not SConfFS:
|
||||||
SConfFS = SCons.Node.FS.default_fs or \
|
SConfFS = SCons.Node.FS.default_fs or \
|
||||||
SCons.Node.FS.FS(env.fs.pathTop)
|
SCons.Node.FS.FS(env.fs.pathTop)
|
||||||
if sconf_global is not None:
|
if sconf_global is not None:
|
||||||
raise SCons.Errors.UserError
|
raise SCons.Errors.UserError("""Configure() called while another Configure() exists.
|
||||||
self.env = env
|
Please call .Finish() before creating and second Configure() context""")
|
||||||
|
|
||||||
if log_file is not None:
|
if log_file is not None:
|
||||||
log_file = SConfFS.File(env.subst(log_file))
|
log_file = SConfFS.File(env.subst(log_file))
|
||||||
self.logfile = log_file
|
self.logfile = log_file
|
||||||
|
@ -449,6 +466,7 @@ class SConfBase(object):
|
||||||
env = sconf.Finish()
|
env = sconf.Finish()
|
||||||
"""
|
"""
|
||||||
self._shutdown()
|
self._shutdown()
|
||||||
|
|
||||||
return self.env
|
return self.env
|
||||||
|
|
||||||
def Define(self, name, value = None, comment = None):
|
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
|
# we override the store_info() method with a null place-holder
|
||||||
# so we really control how it gets written.
|
# so we really control how it gets written.
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
|
self._set_conftest_node(n)
|
||||||
n.store_info = 0
|
n.store_info = 0
|
||||||
if not hasattr(n, 'attributes'):
|
if not hasattr(n, 'attributes'):
|
||||||
n.attributes = SCons.Node.Node.Attrs()
|
n.attributes = SCons.Node.Node.Attrs()
|
||||||
n.attributes.keep_targetinfo = 1
|
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
|
ret = 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -541,8 +575,7 @@ class SConfBase(object):
|
||||||
"""
|
"""
|
||||||
return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream)
|
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
|
"""Low level TryBuild implementation. Normally you don't need to
|
||||||
call that - you can use TryCompile / TryLink / TryRun instead
|
call that - you can use TryCompile / TryLink / TryRun instead
|
||||||
"""
|
"""
|
||||||
|
@ -560,8 +593,33 @@ class SConfBase(object):
|
||||||
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
|
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
|
||||||
|
|
||||||
nodesToBeBuilt = []
|
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 )
|
pref = self.env.subst( builder.builder.prefix )
|
||||||
suff = self.env.subst( builder.builder.suffix )
|
suff = self.env.subst( builder.builder.suffix )
|
||||||
target = self.confdir.File(pref + f + suff)
|
target = self.confdir.File(pref + f + suff)
|
||||||
|
@ -570,16 +628,6 @@ class SConfBase(object):
|
||||||
# Slide our wrapper into the construction environment as
|
# Slide our wrapper into the construction environment as
|
||||||
# the SPAWN function.
|
# the SPAWN function.
|
||||||
self.env['SPAWN'] = self.pspawn_wrapper
|
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)
|
nodes = builder(target = target, source = source)
|
||||||
if not SCons.Util.is_List(nodes):
|
if not SCons.Util.is_List(nodes):
|
||||||
|
@ -590,7 +638,6 @@ class SConfBase(object):
|
||||||
finally:
|
finally:
|
||||||
self.env['SPAWN'] = save_spawn
|
self.env['SPAWN'] = save_spawn
|
||||||
|
|
||||||
_ac_build_counter = _ac_build_counter + 1
|
|
||||||
if result:
|
if result:
|
||||||
self.lastTarget = nodes[0]
|
self.lastTarget = nodes[0]
|
||||||
else:
|
else:
|
||||||
|
@ -609,7 +656,7 @@ class SConfBase(object):
|
||||||
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
|
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
|
||||||
del self.env['BUILDERS']['SConfActionBuilder']
|
del self.env['BUILDERS']['SConfActionBuilder']
|
||||||
if ok:
|
if ok:
|
||||||
outputStr = self.lastTarget.get_contents().decode()
|
outputStr = self.lastTarget.get_text_contents()
|
||||||
return (1, outputStr)
|
return (1, outputStr)
|
||||||
return (0, "")
|
return (0, "")
|
||||||
|
|
||||||
|
@ -636,7 +683,7 @@ class SConfBase(object):
|
||||||
is saved in self.lastTarget (for further processing).
|
is saved in self.lastTarget (for further processing).
|
||||||
"""
|
"""
|
||||||
ok = self.TryLink(text, extension)
|
ok = self.TryLink(text, extension)
|
||||||
if( ok ):
|
if ok:
|
||||||
prog = self.lastTarget
|
prog = self.lastTarget
|
||||||
pname = prog.get_internal_path()
|
pname = prog.get_internal_path()
|
||||||
output = self.confdir.File(os.path.basename(pname)+'.out')
|
output = self.confdir.File(os.path.basename(pname)+'.out')
|
||||||
|
@ -647,7 +694,7 @@ class SConfBase(object):
|
||||||
return( 1, outputStr)
|
return( 1, outputStr)
|
||||||
return (0, "")
|
return (0, "")
|
||||||
|
|
||||||
class TestWrapper(object):
|
class TestWrapper:
|
||||||
"""A wrapper around Tests (to ensure sanity)"""
|
"""A wrapper around Tests (to ensure sanity)"""
|
||||||
def __init__(self, test, sconf):
|
def __init__(self, test, sconf):
|
||||||
self.test = test
|
self.test = test
|
||||||
|
@ -671,7 +718,7 @@ class SConfBase(object):
|
||||||
"""Adds all the tests given in the tests dictionary to this SConf
|
"""Adds all the tests given in the tests dictionary to this SConf
|
||||||
instance
|
instance
|
||||||
"""
|
"""
|
||||||
for name in list(tests.keys()):
|
for name in tests.keys():
|
||||||
self.AddTest(name, tests[name])
|
self.AddTest(name, tests[name])
|
||||||
|
|
||||||
def _createDir( self, node ):
|
def _createDir( self, node ):
|
||||||
|
@ -683,6 +730,9 @@ class SConfBase(object):
|
||||||
if not os.path.isdir( dirName ):
|
if not os.path.isdir( dirName ):
|
||||||
os.makedirs( dirName )
|
os.makedirs( dirName )
|
||||||
|
|
||||||
|
def _set_conftest_node(self, node):
|
||||||
|
node.attributes.conftest_node = 1
|
||||||
|
|
||||||
def _startup(self):
|
def _startup(self):
|
||||||
"""Private method. Set up logstream, and set the environment
|
"""Private method. Set up logstream, and set the environment
|
||||||
variables necessary for a piped build
|
variables necessary for a piped build
|
||||||
|
@ -705,11 +755,16 @@ class SConfBase(object):
|
||||||
_ac_config_logs[self.logfile] = None
|
_ac_config_logs[self.logfile] = None
|
||||||
log_mode = "w"
|
log_mode = "w"
|
||||||
fp = open(str(self.logfile), log_mode)
|
fp = open(str(self.logfile), log_mode)
|
||||||
|
|
||||||
|
def conflog_cleanup(logf):
|
||||||
|
logf.close()
|
||||||
|
|
||||||
|
atexit.register(conflog_cleanup, fp)
|
||||||
self.logstream = SCons.Util.Unbuffered(fp)
|
self.logstream = SCons.Util.Unbuffered(fp)
|
||||||
# logfile may stay in a build directory, so we tell
|
# 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
|
# 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]
|
tb = traceback.extract_stack()[-3-self.depth]
|
||||||
old_fs_dir = SConfFS.getcwd()
|
old_fs_dir = SConfFS.getcwd()
|
||||||
|
@ -739,17 +794,25 @@ class SConfBase(object):
|
||||||
self.logstream.write("\n")
|
self.logstream.write("\n")
|
||||||
self.logstream.close()
|
self.logstream.close()
|
||||||
self.logstream = None
|
self.logstream = None
|
||||||
# remove the SConfSourceBuilder from the environment
|
|
||||||
blds = self.env['BUILDERS']
|
# Now reset the decider if we changed it due to --config=force
|
||||||
del blds['SConfSourceBuilder']
|
# We saved original Environment passed in and cloned it to isolate
|
||||||
self.env.Replace( BUILDERS=blds )
|
# 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
|
self.active = 0
|
||||||
sconf_global = None
|
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
|
_ac_config_hs[self.config_h] = self.config_h_text
|
||||||
self.env.fs = self.lastEnvFs
|
self.env.fs = self.lastEnvFs
|
||||||
|
|
||||||
class CheckContext(object):
|
class CheckContext:
|
||||||
"""Provides a context for configure tests. Defines how a test writes to the
|
"""Provides a context for configure tests. Defines how a test writes to the
|
||||||
screen and log file.
|
screen and log file.
|
||||||
|
|
||||||
|
@ -826,9 +889,9 @@ class CheckContext(object):
|
||||||
return self.sconf.TryRun(*args, **kw)
|
return self.sconf.TryRun(*args, **kw)
|
||||||
|
|
||||||
def __getattr__( self, attr ):
|
def __getattr__( self, attr ):
|
||||||
if( attr == 'env' ):
|
if attr == 'env':
|
||||||
return self.sconf.env
|
return self.sconf.env
|
||||||
elif( attr == 'lastTarget' ):
|
elif attr == 'lastTarget':
|
||||||
return self.sconf.lastTarget
|
return self.sconf.lastTarget
|
||||||
else:
|
else:
|
||||||
raise AttributeError("CheckContext instance has no attribute '%s'" % attr)
|
raise AttributeError("CheckContext instance has no attribute '%s'" % attr)
|
||||||
|
@ -1000,7 +1063,7 @@ def CheckLib(context, library = None, symbol = "main",
|
||||||
compiles without flags.
|
compiles without flags.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if library == []:
|
if not library:
|
||||||
library = [None]
|
library = [None]
|
||||||
|
|
||||||
if not SCons.Util.is_List(library):
|
if not SCons.Util.is_List(library):
|
||||||
|
@ -1027,7 +1090,7 @@ def CheckLibWithHeader(context, libs, header, language,
|
||||||
"""
|
"""
|
||||||
prog_prefix, dummy = \
|
prog_prefix, dummy = \
|
||||||
createIncludesFromHeaders(header, 0)
|
createIncludesFromHeaders(header, 0)
|
||||||
if libs == []:
|
if not libs:
|
||||||
libs = [None]
|
libs = [None]
|
||||||
|
|
||||||
if not SCons.Util.is_List(libs):
|
if not SCons.Util.is_List(libs):
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.SConsign
|
# MIT License
|
||||||
|
|
||||||
Writing and reading information to the .sconsign file or files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
from __future__ import print_function
|
"""Operations on signature database files (.sconsign). """
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/SConsign.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import SCons.compat
|
import SCons.compat
|
||||||
|
|
||||||
|
@ -43,10 +35,12 @@ from SCons.compat import PICKLE_PROTOCOL
|
||||||
|
|
||||||
|
|
||||||
def corrupt_dblite_warning(filename):
|
def corrupt_dblite_warning(filename):
|
||||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
SCons.Warnings.warn(
|
||||||
"Ignoring corrupt .sconsign file: %s"%filename)
|
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
|
SCons.dblite.corruption_warning = corrupt_dblite_warning
|
||||||
|
|
||||||
# XXX Get rid of the global array so this becomes re-entrant.
|
# XXX Get rid of the global array so this becomes re-entrant.
|
||||||
|
@ -76,7 +70,8 @@ def Get_DataBase(dir):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
path = d.entry_abspath(DB_Name)
|
path = d.entry_abspath(DB_Name)
|
||||||
try: db = DataBase[d] = DB_Module.open(path, mode)
|
try: db = DataBase[d] = DB_Module.open(path, mode)
|
||||||
except (IOError, OSError): pass
|
except (IOError, OSError):
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
if mode != "r":
|
if mode != "r":
|
||||||
DB_sync_list.append(db)
|
DB_sync_list.append(db)
|
||||||
|
@ -122,7 +117,7 @@ def write():
|
||||||
closemethod()
|
closemethod()
|
||||||
|
|
||||||
|
|
||||||
class SConsignEntry(object):
|
class SConsignEntry:
|
||||||
"""
|
"""
|
||||||
Wrapper class for the generic entry in a .sconsign file.
|
Wrapper class for the generic entry in a .sconsign file.
|
||||||
The Node subclass populates it with attributes as it pleases.
|
The Node subclass populates it with attributes as it pleases.
|
||||||
|
@ -148,7 +143,7 @@ class SConsignEntry(object):
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
state = getattr(self, '__dict__', {}).copy()
|
state = getattr(self, '__dict__', {}).copy()
|
||||||
for obj in type(self).mro():
|
for obj in type(self).mro():
|
||||||
for name in getattr(obj,'__slots__',()):
|
for name in getattr(obj, '__slots__', ()):
|
||||||
if hasattr(self, name):
|
if hasattr(self, name):
|
||||||
state[name] = getattr(self, name)
|
state[name] = getattr(self, name)
|
||||||
|
|
||||||
|
@ -161,11 +156,11 @@ class SConsignEntry(object):
|
||||||
|
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
for key, value in state.items():
|
for key, value in state.items():
|
||||||
if key not in ('_version_id','__weakref__'):
|
if key not in ('_version_id', '__weakref__'):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base:
|
||||||
"""
|
"""
|
||||||
This is the controlling class for the signatures for the collection of
|
This is the controlling class for the signatures for the collection of
|
||||||
entries associated with a specific directory. The actual directory
|
entries associated with a specific directory. The actual directory
|
||||||
|
@ -334,10 +329,15 @@ class DirFile(Dir):
|
||||||
Dir.__init__(self, fp, dir)
|
Dir.__init__(self, fp, dir)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except:
|
except Exception:
|
||||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||||
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
|
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
|
||||||
|
|
||||||
|
try:
|
||||||
|
fp.close()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
global sig_files
|
global sig_files
|
||||||
sig_files.append(self)
|
sig_files.append(self)
|
||||||
|
|
||||||
|
@ -394,7 +394,8 @@ class DirFile(Dir):
|
||||||
# here, or in any of the following calls, would get
|
# here, or in any of the following calls, would get
|
||||||
# raised, indicating something like a potentially
|
# raised, indicating something like a potentially
|
||||||
# serious disk or network issue.
|
# 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)
|
os.chmod(self.sconsign, mode)
|
||||||
try:
|
try:
|
||||||
os.unlink(temp)
|
os.unlink(temp)
|
||||||
|
@ -416,7 +417,7 @@ def File(name, dbm_module=None):
|
||||||
else:
|
else:
|
||||||
ForDirectory = DB
|
ForDirectory = DB
|
||||||
DB_Name = name
|
DB_Name = name
|
||||||
if not dbm_module is None:
|
if dbm_module is not None:
|
||||||
DB_Module = dbm_module
|
DB_Module = dbm_module
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Scanner.C
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for C/C++ code.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
@ -36,8 +30,7 @@ import SCons.Util
|
||||||
import SCons.cpp
|
import SCons.cpp
|
||||||
|
|
||||||
class SConsCPPScanner(SCons.cpp.PreProcessor):
|
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
|
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
|
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 : None}
|
||||||
return cppdefines
|
return cppdefines
|
||||||
|
|
||||||
class SConsCPPScannerWrapper(object):
|
class SConsCPPScannerWrapper:
|
||||||
"""
|
"""The SCons wrapper around a cpp.py scanner.
|
||||||
The SCons wrapper around a cpp.py scanner.
|
|
||||||
|
|
||||||
This is the actual glue between the calling conventions of generic
|
This is the actual glue between the calling conventions of generic
|
||||||
SCons scanners, and the (subclass of) cpp.py class that knows how
|
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
|
# knows how to evaluate #if/#ifdef/#else/#elif lines when searching
|
||||||
# for #includes. This is commented out for now until we add the
|
# for #includes. This is commented out for now until we add the
|
||||||
# right configurability to let users pick between the scanners.
|
# right configurability to let users pick between the scanners.
|
||||||
#return SConsCPPScannerWrapper("CScanner", "CPPPATH")
|
# return SConsCPPScannerWrapper("CScanner", "CPPPATH")
|
||||||
|
|
||||||
cs = SCons.Scanner.ClassicCPP("CScanner",
|
cs = SCons.Scanner.ClassicCPP(
|
||||||
"$CPPSUFFIXES",
|
"CScanner",
|
||||||
"CPPPATH",
|
"$CPPSUFFIXES",
|
||||||
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")')
|
"CPPPATH",
|
||||||
|
r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")',
|
||||||
|
)
|
||||||
return cs
|
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:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
||||||
# indent-tabs-mode:nil
|
# indent-tabs-mode:nil
|
|
@ -1,14 +1,6 @@
|
||||||
"""SCons.Scanner.D
|
# MIT License
|
||||||
|
|
||||||
Scanner for the Digital Mars "D" programming language.
|
|
||||||
|
|
||||||
Coded by Andy Friesen
|
|
||||||
17 Nov 2003
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -28,9 +20,11 @@ Coded by Andy Friesen
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import SCons.Scanner
|
||||||
|
|
||||||
|
@ -46,7 +40,7 @@ class D(SCons.Scanner.Classic):
|
||||||
name = "DScanner",
|
name = "DScanner",
|
||||||
suffixes = '$DSUFFIXES',
|
suffixes = '$DSUFFIXES',
|
||||||
path_variable = 'DPATH',
|
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):
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -20,8 +21,6 @@
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/Dir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Scanner.Fortran
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for Fortran code.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -26,7 +21,7 @@ This module implements the dependency scanner for Fortran code.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/Fortran.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Dependency scanner for Fortran code."""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -78,7 +73,7 @@ class F90Scanner(SCons.Scanner.Classic):
|
||||||
def scan(self, node, env, path=()):
|
def scan(self, node, env, path=()):
|
||||||
|
|
||||||
# cache the includes list in node so we only scan it once:
|
# 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
|
mods_and_includes = node.includes
|
||||||
else:
|
else:
|
||||||
# retrieve all included filenames
|
# retrieve all included filenames
|
||||||
|
@ -187,7 +182,7 @@ def FortranScan(path_variable="FORTRANPATH"):
|
||||||
# (\w+) : match the module name that is being USE'd
|
# (\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:
|
# The INCLUDE statement regex matches the following:
|
||||||
|
@ -275,7 +270,7 @@ def FortranScan(path_variable="FORTRANPATH"):
|
||||||
# set of semicolon-separated INCLUDE statements
|
# set of semicolon-separated INCLUDE statements
|
||||||
# (as allowed by the F2003 standard)
|
# (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 MODULE statement regex finds module definitions by matching
|
||||||
# the following:
|
# the following:
|
||||||
|
@ -285,21 +280,29 @@ def FortranScan(path_variable="FORTRANPATH"):
|
||||||
# but *not* the following:
|
# but *not* the following:
|
||||||
#
|
#
|
||||||
# MODULE PROCEDURE procedure_name
|
# 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:
|
# Here is a breakdown of the regex:
|
||||||
#
|
#
|
||||||
# (?i) : regex is case insensitive
|
# (?i) : regex is case insensitive
|
||||||
# ^\s* : any amount of white space
|
# ^\s* : any amount of white space
|
||||||
# MODULE : match the string MODULE, case insensitive
|
# MODULE : match the string MODULE, case
|
||||||
# \s+ : match one or more white space characters
|
# insensitive
|
||||||
# (?!PROCEDURE) : but *don't* match if the next word matches
|
# \s+ : match one or more white space
|
||||||
# PROCEDURE (negative lookahead assertion),
|
# characters
|
||||||
# case insensitive
|
# (?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)
|
||||||
# (\w+) : match one or more alphanumeric characters
|
# : but *don't* match if the next word
|
||||||
# that make up the defined module name and
|
# matches PROCEDURE, SUBROUTINE,
|
||||||
# save it in a group
|
# 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",
|
scanner = F90Scanner("FortranScan",
|
||||||
"$FORTRANSUFFIXES",
|
"$FORTRANSUFFIXES",
|
|
@ -1,12 +1,6 @@
|
||||||
"""SCons.Scanner.IDL
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for IDL (Interface
|
|
||||||
Definition Language) files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -26,19 +20,20 @@ Definition Language) files.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
|
||||||
def IDLScan():
|
def IDLScan():
|
||||||
"""Return a prototype Scanner instance for scanning IDL source files"""
|
"""Return a prototype Scanner instance for scanning IDL source files"""
|
||||||
cs = SCons.Scanner.ClassicCPP("IDLScan",
|
cs = SCons.Scanner.ClassicCPP(
|
||||||
"$IDLSUFFIXES",
|
"IDLScan",
|
||||||
"CPPPATH",
|
"$IDLSUFFIXES",
|
||||||
'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")')
|
"CPPPATH",
|
||||||
|
r'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")',
|
||||||
|
)
|
||||||
return cs
|
return cs
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Scanner.LaTeX
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for LaTeX code.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/LaTeX.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Dependency scanner for LaTeX code."""
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
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.
|
# Used as a return value of modify_env_var if the variable is not set.
|
||||||
class _Null(object):
|
class _Null:
|
||||||
pass
|
pass
|
||||||
_null = _Null
|
_null = _Null
|
||||||
|
|
||||||
|
@ -77,7 +71,7 @@ def modify_env_var(env, var, abspath):
|
||||||
|
|
||||||
return save
|
return save
|
||||||
|
|
||||||
class FindENVPathDirs(object):
|
class FindENVPathDirs:
|
||||||
"""
|
"""
|
||||||
A class to bind a specific E{*}PATH variable name to a function that
|
A class to bind a specific E{*}PATH variable name to a function that
|
||||||
will return all of the E{*}path directories.
|
will return all of the E{*}path directories.
|
||||||
|
@ -96,7 +90,6 @@ class FindENVPathDirs(object):
|
||||||
return tuple(dir.Rfindalldirs(path))
|
return tuple(dir.Rfindalldirs(path))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def LaTeXScanner():
|
def LaTeXScanner():
|
||||||
"""
|
"""
|
||||||
Return a prototype Scanner instance for scanning LaTeX source files
|
Return a prototype Scanner instance for scanning LaTeX source files
|
||||||
|
@ -109,6 +102,7 @@ def LaTeXScanner():
|
||||||
recursive = 0)
|
recursive = 0)
|
||||||
return ds
|
return ds
|
||||||
|
|
||||||
|
|
||||||
def PDFLaTeXScanner():
|
def PDFLaTeXScanner():
|
||||||
"""
|
"""
|
||||||
Return a prototype Scanner instance for scanning LaTeX source files
|
Return a prototype Scanner instance for scanning LaTeX source files
|
||||||
|
@ -121,9 +115,9 @@ def PDFLaTeXScanner():
|
||||||
recursive = 0)
|
recursive = 0)
|
||||||
return ds
|
return ds
|
||||||
|
|
||||||
|
|
||||||
class LaTeX(SCons.Scanner.Base):
|
class LaTeX(SCons.Scanner.Base):
|
||||||
"""
|
"""Class for scanning LaTeX files for included files.
|
||||||
Class for scanning LaTeX files for included files.
|
|
||||||
|
|
||||||
Unlike most scanners, which use regular expressions that just
|
Unlike most scanners, which use regular expressions that just
|
||||||
return the included file name, this returns a tuple consisting
|
return the included file name, this returns a tuple consisting
|
||||||
|
@ -179,15 +173,7 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
'inputfrom', 'subinputfrom']
|
'inputfrom', 'subinputfrom']
|
||||||
|
|
||||||
def __init__(self, name, suffixes, graphics_extensions, *args, **kw):
|
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'''
|
regex = r'''
|
||||||
^[^%\n]*
|
|
||||||
\\(
|
\\(
|
||||||
include
|
include
|
||||||
| includegraphics(?:\s*\[[^\]]+\])?
|
| includegraphics(?:\s*\[[^\]]+\])?
|
||||||
|
@ -219,7 +205,7 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
return []
|
return []
|
||||||
return self.scan_recurse(node, path)
|
return self.scan_recurse(node, path)
|
||||||
|
|
||||||
class FindMultiPathDirs(object):
|
class FindMultiPathDirs:
|
||||||
"""The stock FindPathDirs function has the wrong granularity:
|
"""The stock FindPathDirs function has the wrong granularity:
|
||||||
it is called once per target, while we need the path that depends
|
it is called once per target, while we need the path that depends
|
||||||
on what kind of included files is being searched. This wrapper
|
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"
|
# To prevent "dict is not hashable error"
|
||||||
return tuple(di.items())
|
return tuple(di.items())
|
||||||
|
|
||||||
class LaTeXScanCheck(object):
|
class LaTeXScanCheck:
|
||||||
"""Skip all but LaTeX source files, i.e., do not scan *.eps,
|
"""Skip all but LaTeX source files, i.e., do not scan *.eps,
|
||||||
*.pdf, *.jpg, etc.
|
*.pdf, *.jpg, etc.
|
||||||
"""
|
"""
|
||||||
|
@ -333,7 +319,7 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
line_continues_a_comment = False
|
line_continues_a_comment = False
|
||||||
for line in text.splitlines():
|
for line in text.splitlines():
|
||||||
line,comment = self.comment_re.findall(line)[0]
|
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()
|
out[-1] = out[-1] + line.lstrip()
|
||||||
else:
|
else:
|
||||||
out.append(line)
|
out.append(line)
|
||||||
|
@ -348,8 +334,8 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
# Cache the includes list in node so we only scan it once:
|
# Cache the includes list in node so we only scan it once:
|
||||||
# path_dict = dict(list(path))
|
# path_dict = dict(list(path))
|
||||||
# add option for whitespace (\s) before the '['
|
# add option for whitespace (\s) before the '['
|
||||||
noopt_cre = re.compile('\s*\[.*$')
|
noopt_cre = re.compile(r'\s*\[.*$')
|
||||||
if node.includes != None:
|
if node.includes is not None:
|
||||||
includes = node.includes
|
includes = node.includes
|
||||||
else:
|
else:
|
||||||
text = self.canonical_text(node.get_text_contents())
|
text = self.canonical_text(node.get_text_contents())
|
||||||
|
@ -372,9 +358,9 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
inc_list = include[2].split(',')
|
inc_list = include[2].split(',')
|
||||||
else:
|
else:
|
||||||
inc_list = include[1].split(',')
|
inc_list = include[1].split(',')
|
||||||
for j in range(len(inc_list)):
|
for inc in inc_list:
|
||||||
split_includes.append( (inc_type, inc_subdir, inc_list[j]) )
|
split_includes.append((inc_type, inc_subdir, inc))
|
||||||
#
|
|
||||||
includes = split_includes
|
includes = split_includes
|
||||||
node.includes = 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,9 +20,8 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
|
@ -39,9 +39,7 @@ def ProgramScanner(**kw):
|
||||||
return ps
|
return ps
|
||||||
|
|
||||||
def _subst_libs(env, libs):
|
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):
|
if SCons.Util.is_String(libs):
|
||||||
libs = env.subst(libs)
|
libs = env.subst(libs)
|
||||||
if SCons.Util.is_String(libs):
|
if SCons.Util.is_String(libs):
|
||||||
|
@ -57,9 +55,9 @@ def _subst_libs(env, libs):
|
||||||
return libs
|
return libs
|
||||||
|
|
||||||
def scan(node, env, libpath = ()):
|
def scan(node, env, libpath = ()):
|
||||||
"""
|
"""Scans program files for static-library dependencies.
|
||||||
This scanner scans program files for static-library
|
|
||||||
dependencies. It will search the LIBPATH environment variable
|
It will search the LIBPATH environment variable
|
||||||
for libraries specified in the LIBS variable, returning any
|
for libraries specified in the LIBS variable, returning any
|
||||||
files it finds as dependencies.
|
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
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for RC (Interface
|
|
||||||
Definition Language) files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -26,20 +20,17 @@ Definition Language) files.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
|
||||||
|
|
||||||
def no_tlb(nodes):
|
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])
|
# print("Nodes:%s"%[str(n) for n in nodes])
|
||||||
return [n for n in nodes if str(n)[-4:] != '.tlb']
|
return [n for n in nodes if str(n)[-4:] != '.tlb']
|
||||||
|
|
||||||
|
@ -47,15 +38,15 @@ def no_tlb(nodes):
|
||||||
def RCScan():
|
def RCScan():
|
||||||
"""Return a prototype Scanner instance for scanning RC source files"""
|
"""Return a prototype Scanner instance for scanning RC source files"""
|
||||||
|
|
||||||
res_re= r'^(?:\s*#\s*(?:include)|' \
|
res_re = (
|
||||||
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
r'^(?:\s*#\s*(?:include)|'
|
||||||
'\s*.*?)' \
|
r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)'
|
||||||
'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
r'\s*.*?)'
|
||||||
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
|
r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||||
"$RCSUFFIXES",
|
)
|
||||||
"CPPPATH",
|
resScanner = SCons.Scanner.ClassicCPP(
|
||||||
res_re,
|
"ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re, recursive=no_tlb
|
||||||
recursive=no_tlb)
|
)
|
||||||
|
|
||||||
return resScanner
|
return resScanner
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Scanner.SWIG
|
# MIT License
|
||||||
|
|
||||||
This module implements the dependency scanner for SWIG code.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/SWIG.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""Dependency scanner for SWIG code."""
|
||||||
|
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
|
||||||
SWIGSuffixes = [ '.i' ]
|
SWIGSuffixes = [ '.i' ]
|
||||||
|
|
||||||
def SWIGScanner():
|
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)
|
scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr)
|
||||||
return scanner
|
return scanner
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Scanner
|
# MIT License
|
||||||
|
|
||||||
The Scanner package for the SCons software construction utility.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import re
|
||||||
|
|
||||||
|
@ -35,7 +29,7 @@ import SCons.Node.FS
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
|
||||||
|
|
||||||
class _Null(object):
|
class _Null:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# This is used instead of None as a default argument value so None can be
|
# This is used instead of None as a default argument value so None can be
|
||||||
|
@ -43,16 +37,16 @@ class _Null(object):
|
||||||
_null = _Null
|
_null = _Null
|
||||||
|
|
||||||
def Scanner(function, *args, **kw):
|
def Scanner(function, *args, **kw):
|
||||||
"""
|
"""Factory function to create a Scanner Object.
|
||||||
Public interface factory function for creating different types
|
|
||||||
of Scanners based on the different types of "functions" that may
|
Creates the appropriate Scanner based on the type of "function".
|
||||||
be supplied.
|
|
||||||
|
|
||||||
TODO: Deprecate this some day. We've moved the functionality
|
TODO: Deprecate this some day. We've moved the functionality
|
||||||
inside the Base class and really don't need this factory function
|
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
|
any more. It was, however, used by some of our Tool modules, so
|
||||||
the call probably ended up in various people's custom modules
|
the call probably ended up in various people's custom modules
|
||||||
patterned on SCons code.
|
patterned on SCons code.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if SCons.Util.is_Dict(function):
|
if SCons.Util.is_Dict(function):
|
||||||
return Selector(function, *args, **kw)
|
return Selector(function, *args, **kw)
|
||||||
|
@ -60,10 +54,8 @@ def Scanner(function, *args, **kw):
|
||||||
return Base(function, *args, **kw)
|
return Base(function, *args, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
class FindPathDirs:
|
||||||
class FindPathDirs(object):
|
"""Class to bind a specific E{*}PATH variable name to a function that
|
||||||
"""
|
|
||||||
A class to bind a specific E{*}PATH variable name to a function that
|
|
||||||
will return all of the E{*}path directories.
|
will return all of the E{*}path directories.
|
||||||
"""
|
"""
|
||||||
def __init__(self, variable):
|
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
|
def __init__(
|
||||||
straightforward, single-pass scanning of a single file.
|
self,
|
||||||
"""
|
function,
|
||||||
|
name="NONE",
|
||||||
def __init__(self,
|
argument=_null,
|
||||||
function,
|
skeys=_null,
|
||||||
name = "NONE",
|
path_function=None,
|
||||||
argument = _null,
|
# Node.FS.Base so that, by default, it's okay for a
|
||||||
skeys = _null,
|
# scanner to return a Dir, File or Entry.
|
||||||
path_function = None,
|
node_class=SCons.Node.FS.Base,
|
||||||
# Node.FS.Base so that, by default, it's okay for a
|
node_factory=None,
|
||||||
# scanner to return a Dir, File or Entry.
|
scan_check=None,
|
||||||
node_class = SCons.Node.FS.Base,
|
recursive=None,
|
||||||
node_factory = None,
|
):
|
||||||
scan_check = None,
|
"""Construct a new scanner object given a scanner function.
|
||||||
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).
|
|
||||||
|
|
||||||
The scanner function's first argument will be a Node that should
|
The scanner function's first argument will be a Node that should
|
||||||
be scanned for dependencies, the second argument will be an
|
be scanned for dependencies, the second argument will be an
|
||||||
|
@ -152,14 +103,55 @@ class Base(object):
|
||||||
|
|
||||||
Examples:
|
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
|
# Note: this class could easily work with scanner functions that take
|
||||||
# something other than a filename as an argument (e.g. a database
|
# something other than a filename as an argument (e.g. a database
|
||||||
# node) and a dependencies list that aren't file names. All that
|
# 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)
|
return self.path_function(env, dir, target, source)
|
||||||
|
|
||||||
def __call__(self, node, env, path=()):
|
def __call__(self, node, env, path=()):
|
||||||
"""
|
"""Scans a single object.
|
||||||
This method scans a single object. 'node' is the node
|
|
||||||
that will be passed to the scanner function, and 'env' is the
|
Args:
|
||||||
environment that will be passed to the scanner function. A list of
|
node: the node that will be passed to the scanner function
|
||||||
direct dependency nodes for the specified node will be returned.
|
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):
|
if self.scan_check and not self.scan_check(node, env):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
self = self.select(node)
|
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)
|
node_list = self.function(node, env, path, self.argument)
|
||||||
else:
|
else:
|
||||||
node_list = self.function(node, env, path)
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,13 +20,8 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/Interactive.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""SCons interactive mode. """
|
||||||
|
|
||||||
__doc__ = """
|
|
||||||
SCons interactive mode
|
|
||||||
"""
|
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
#
|
#
|
||||||
|
@ -247,7 +243,7 @@ version Prints SCons version information.
|
||||||
while n:
|
while n:
|
||||||
n = walker.get_next()
|
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
|
# Call node.clear() to clear most of the state
|
||||||
node.clear()
|
node.clear()
|
||||||
# node.clear() doesn't reset node.state, so call
|
# node.clear() doesn't reset node.state, so call
|
|
@ -1,23 +1,6 @@
|
||||||
"""SCons.Script
|
# MIT License
|
||||||
|
#
|
||||||
This file implements the main() function used by the scons script.
|
# Copyright The SCons Foundation
|
||||||
|
|
||||||
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
|
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -38,16 +21,32 @@ deprecated_python_version = (2, 7, 0)
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/Main.py 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 SCons.compat
|
||||||
|
|
||||||
|
import atexit
|
||||||
|
import importlib.util
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
import platform
|
||||||
|
import threading
|
||||||
|
|
||||||
import SCons.CacheDir
|
import SCons.CacheDir
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
|
@ -58,24 +57,28 @@ import SCons.Job
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Platform
|
import SCons.Platform
|
||||||
|
import SCons.Platform.virtualenv
|
||||||
import SCons.SConf
|
import SCons.SConf
|
||||||
import SCons.Script
|
import SCons.Script
|
||||||
import SCons.Taskmaster
|
import SCons.Taskmaster
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
import SCons.Script.Interactive
|
import SCons.Script.Interactive
|
||||||
|
|
||||||
|
# Global variables
|
||||||
def fetch_win32_parallel_msg():
|
first_command_start = None
|
||||||
# A subsidiary function that exists solely to isolate this import
|
last_command_end = None
|
||||||
# so we don't have to pull it in on all platforms, and so that an
|
print_objects = 0
|
||||||
# in-line "import" statement in the _main() function below doesn't
|
print_memoizer = 0
|
||||||
# cause warnings about local names shadowing use of the 'SCons'
|
print_stacktrace = 0
|
||||||
# global in nest scopes and UnboundLocalErrors and the like in some
|
print_time = 0
|
||||||
# versions (2.1) of Python.
|
print_action_timestamps = 0
|
||||||
import SCons.Platform.win32
|
sconscript_time = 0
|
||||||
return SCons.Platform.win32.parallel_msg
|
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():
|
def revert_io():
|
||||||
|
@ -85,17 +88,16 @@ def revert_io():
|
||||||
sys.stderr = sys.__stderr__
|
sys.stderr = sys.__stderr__
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = sys.__stdout__
|
||||||
|
|
||||||
|
|
||||||
class SConsPrintHelpException(Exception):
|
class SConsPrintHelpException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
display = SCons.Util.display
|
display = SCons.Util.display
|
||||||
progress_display = SCons.Util.DisplayEngine()
|
progress_display = SCons.Util.DisplayEngine()
|
||||||
|
|
||||||
first_command_start = None
|
|
||||||
last_command_end = None
|
|
||||||
|
|
||||||
|
class Progressor:
|
||||||
class Progressor(object):
|
|
||||||
prev = ''
|
prev = ''
|
||||||
count = 0
|
count = 0
|
||||||
target_string = '$TARGET'
|
target_string = '$TARGET'
|
||||||
|
@ -194,6 +196,9 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
|
||||||
finish_time = time.time()
|
finish_time = time.time()
|
||||||
last_command_end = finish_time
|
last_command_end = finish_time
|
||||||
cumulative_command_time = cumulative_command_time+finish_time-start_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))
|
sys.stdout.write("Command execution time: %s: %f seconds\n"%(str(self.node), finish_time-start_time))
|
||||||
|
|
||||||
def do_failed(self, status=2):
|
def do_failed(self, status=2):
|
||||||
|
@ -336,7 +341,7 @@ class CleanTask(SCons.Taskmaster.AlwaysTask):
|
||||||
display("Removed directory " + pathstr)
|
display("Removed directory " + pathstr)
|
||||||
else:
|
else:
|
||||||
errstr = "Path '%s' exists but isn't a file or directory."
|
errstr = "Path '%s' exists but isn't a file or directory."
|
||||||
raise SCons.Errors.UserError(errstr % (pathstr))
|
raise SCons.Errors.UserError(errstr % pathstr)
|
||||||
except SCons.Errors.UserError as e:
|
except SCons.Errors.UserError as e:
|
||||||
print(e)
|
print(e)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
|
@ -412,11 +417,12 @@ class QuestionTask(SCons.Taskmaster.AlwaysTask):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TreePrinter(object):
|
class TreePrinter:
|
||||||
def __init__(self, derived=False, prune=False, status=False):
|
def __init__(self, derived=False, prune=False, status=False, sLineDraw=False):
|
||||||
self.derived = derived
|
self.derived = derived
|
||||||
self.prune = prune
|
self.prune = prune
|
||||||
self.status = status
|
self.status = status
|
||||||
|
self.sLineDraw = sLineDraw
|
||||||
def get_all_children(self, node):
|
def get_all_children(self, node):
|
||||||
return node.all_children()
|
return node.all_children()
|
||||||
def get_derived_children(self, node):
|
def get_derived_children(self, node):
|
||||||
|
@ -428,7 +434,7 @@ class TreePrinter(object):
|
||||||
else:
|
else:
|
||||||
func = self.get_all_children
|
func = self.get_all_children
|
||||||
s = self.status and 2 or 0
|
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():
|
def python_version_string():
|
||||||
|
@ -441,20 +447,7 @@ def python_version_deprecated(version=sys.version_info):
|
||||||
return version < deprecated_python_version
|
return version < deprecated_python_version
|
||||||
|
|
||||||
|
|
||||||
# Global variables
|
class FakeOptionParser:
|
||||||
|
|
||||||
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):
|
|
||||||
"""
|
"""
|
||||||
A do-nothing option parser, used for the initial OptionsParser variable.
|
A do-nothing option parser, used for the initial OptionsParser variable.
|
||||||
|
|
||||||
|
@ -466,7 +459,7 @@ class FakeOptionParser(object):
|
||||||
without blowing up.
|
without blowing up.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
class FakeOptionValues(object):
|
class FakeOptionValues:
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
return None
|
return None
|
||||||
values = FakeOptionValues()
|
values = FakeOptionValues()
|
||||||
|
@ -490,7 +483,7 @@ def SetOption(name, value):
|
||||||
def PrintHelp(file=None):
|
def PrintHelp(file=None):
|
||||||
OptionsParser.print_help(file=file)
|
OptionsParser.print_help(file=file)
|
||||||
|
|
||||||
class Stats(object):
|
class Stats:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.stats = []
|
self.stats = []
|
||||||
self.labels = []
|
self.labels = []
|
||||||
|
@ -622,7 +615,7 @@ def _SConstruct_exists(dirname='', repositories=[], filelist=None):
|
||||||
current directory.
|
current directory.
|
||||||
"""
|
"""
|
||||||
if not filelist:
|
if not filelist:
|
||||||
filelist = ['SConstruct', 'Sconstruct', 'sconstruct']
|
filelist = ['SConstruct', 'Sconstruct', 'sconstruct', 'SConstruct.py', 'Sconstruct.py', 'sconstruct.py']
|
||||||
for file in filelist:
|
for file in filelist:
|
||||||
sfile = os.path.join(dirname, file)
|
sfile = os.path.join(dirname, file)
|
||||||
if os.path.isfile(sfile):
|
if os.path.isfile(sfile):
|
||||||
|
@ -634,7 +627,7 @@ def _SConstruct_exists(dirname='', repositories=[], filelist=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _set_debug_values(options):
|
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
|
debug_values = options.debug
|
||||||
|
|
||||||
|
@ -672,6 +665,9 @@ def _set_debug_values(options):
|
||||||
options.tree_printers.append(TreePrinter(status=True))
|
options.tree_printers.append(TreePrinter(status=True))
|
||||||
if "time" in debug_values:
|
if "time" in debug_values:
|
||||||
print_time = 1
|
print_time = 1
|
||||||
|
if "action-timestamps" in debug_values:
|
||||||
|
print_time = 1
|
||||||
|
print_action_timestamps = 1
|
||||||
if "tree" in debug_values:
|
if "tree" in debug_values:
|
||||||
options.tree_printers.append(TreePrinter())
|
options.tree_printers.append(TreePrinter())
|
||||||
if "prepare" in debug_values:
|
if "prepare" in debug_values:
|
||||||
|
@ -689,80 +685,87 @@ def _create_path(plist):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def _load_site_scons_dir(topdir, site_dir_name=None):
|
def _load_site_scons_dir(topdir, site_dir_name=None):
|
||||||
"""Load the site_scons dir under topdir.
|
"""Load the site directory under topdir.
|
||||||
Prepends site_scons to sys.path, imports site_scons/site_init.py,
|
|
||||||
and prepends site_scons/site_tools to default toolpath."""
|
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:
|
if site_dir_name:
|
||||||
err_if_not_found = True # user specified: err if missing
|
err_if_not_found = True # user specified: err if missing
|
||||||
else:
|
else:
|
||||||
site_dir_name = "site_scons"
|
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)
|
site_dir = os.path.join(topdir, site_dir_name)
|
||||||
|
|
||||||
if not os.path.exists(site_dir):
|
if not os.path.exists(site_dir):
|
||||||
if err_if_not_found:
|
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
|
return
|
||||||
|
sys.path.insert(0, os.path.abspath(site_dir))
|
||||||
|
|
||||||
site_init_filename = "site_init.py"
|
site_init_filename = "site_init.py"
|
||||||
site_init_modname = "site_init"
|
site_init_modname = "site_init"
|
||||||
site_tools_dirname = "site_tools"
|
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_init_file = os.path.join(site_dir, site_init_filename)
|
||||||
site_tools_dir = os.path.join(site_dir, site_tools_dirname)
|
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):
|
if os.path.exists(site_tools_dir):
|
||||||
# prepend to DefaultToolpath
|
|
||||||
SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir))
|
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):
|
def _load_all_site_scons_dirs(topdir, verbose=None):
|
||||||
"""Load all of the predefined site_scons dir.
|
"""Load all of the predefined site_scons dir.
|
||||||
Order is significant; we load them in order from most generic
|
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',
|
sysdirs=['/usr/share/scons',
|
||||||
homedir('.scons')]
|
homedir('.scons')]
|
||||||
|
|
||||||
dirs=sysdirs + [topdir]
|
dirs = sysdirs + [topdir]
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
if verbose: # this is used by unit tests.
|
if verbose: # this is used by unit tests.
|
||||||
print("Loading site dir ", d)
|
print("Loading site dir ", d)
|
||||||
|
@ -862,6 +865,13 @@ def _main(parser):
|
||||||
for warning_type, message in delayed_warnings:
|
for warning_type, message in delayed_warnings:
|
||||||
SCons.Warnings.warn(warning_type, message)
|
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:
|
if options.diskcheck:
|
||||||
SCons.Node.FS.set_diskcheck(options.diskcheck)
|
SCons.Node.FS.set_diskcheck(options.diskcheck)
|
||||||
|
|
||||||
|
@ -1089,7 +1099,7 @@ def _main(parser):
|
||||||
SCons.Job.explicit_stack_size = options.stack_size
|
SCons.Job.explicit_stack_size = options.stack_size
|
||||||
|
|
||||||
if options.md5_chunksize:
|
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()
|
platform = SCons.Platform.platform_module()
|
||||||
|
|
||||||
|
@ -1161,7 +1171,7 @@ def _build_targets(fs, options, targets, target_top):
|
||||||
# -U, local SConscript Default() targets
|
# -U, local SConscript Default() targets
|
||||||
target_top = fs.Dir(target_top)
|
target_top = fs.Dir(target_top)
|
||||||
def check_dir(x, target_top=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()
|
cwd = x.cwd.srcnode()
|
||||||
return cwd == target_top
|
return cwd == target_top
|
||||||
else:
|
else:
|
||||||
|
@ -1240,10 +1250,14 @@ def _build_targets(fs, options, targets, target_top):
|
||||||
"""Leave the order of dependencies alone."""
|
"""Leave the order of dependencies alone."""
|
||||||
return dependencies
|
return dependencies
|
||||||
|
|
||||||
|
def tmtrace_cleanup(tfile):
|
||||||
|
tfile.close()
|
||||||
|
|
||||||
if options.taskmastertrace_file == '-':
|
if options.taskmastertrace_file == '-':
|
||||||
tmtrace = sys.stdout
|
tmtrace = sys.stdout
|
||||||
elif options.taskmastertrace_file:
|
elif options.taskmastertrace_file:
|
||||||
tmtrace = open(options.taskmastertrace_file, 'w')
|
tmtrace = open(options.taskmastertrace_file, 'w')
|
||||||
|
atexit.register(tmtrace_cleanup, tmtrace)
|
||||||
else:
|
else:
|
||||||
tmtrace = None
|
tmtrace = None
|
||||||
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
|
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
|
||||||
|
@ -1253,16 +1267,23 @@ def _build_targets(fs, options, targets, target_top):
|
||||||
BuildTask.options = options
|
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.
|
# to check if python configured with threads.
|
||||||
global num_jobs
|
global num_jobs
|
||||||
num_jobs = options.num_jobs
|
num_jobs = options.num_jobs
|
||||||
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
|
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
|
||||||
if num_jobs > 1:
|
if num_jobs > 1:
|
||||||
msg = None
|
msg = None
|
||||||
if sys.platform == 'win32':
|
if jobs.num_jobs == 1 or not python_has_threads:
|
||||||
msg = fetch_win32_parallel_msg()
|
|
||||||
elif jobs.num_jobs == 1 or not python_has_threads:
|
|
||||||
msg = "parallel builds are unsupported by this version of Python;\n" + \
|
msg = "parallel builds are unsupported by this version of Python;\n" + \
|
||||||
"\tignoring -j or num_jobs option.\n"
|
"\tignoring -j or num_jobs option.\n"
|
||||||
if msg:
|
if msg:
|
||||||
|
@ -1312,8 +1333,7 @@ def _exec_main(parser, values):
|
||||||
import pdb
|
import pdb
|
||||||
pdb.Pdb().runcall(_main, parser)
|
pdb.Pdb().runcall(_main, parser)
|
||||||
elif options.profile_file:
|
elif options.profile_file:
|
||||||
# compat layer imports "cProfile" for us if it's available.
|
from cProfile import Profile
|
||||||
from profile import Profile
|
|
||||||
|
|
||||||
prof = Profile()
|
prof = Profile()
|
||||||
try:
|
try:
|
||||||
|
@ -1339,15 +1359,14 @@ def main():
|
||||||
|
|
||||||
parts = ["SCons by Steven Knight et al.:\n"]
|
parts = ["SCons by Steven Knight et al.:\n"]
|
||||||
try:
|
try:
|
||||||
import __main__
|
import SCons
|
||||||
parts.append(version_string("script", __main__))
|
parts.append(version_string("SCons", SCons))
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
# On Windows there is no scons.py, so there is no
|
# On Windows there is no scons.py, so there is no
|
||||||
# __main__.__version__, hence there is no script version.
|
# __main__.__version__, hence there is no script version.
|
||||||
pass
|
pass
|
||||||
parts.append(version_string("engine", SCons))
|
parts.append(path_string("SCons", SCons))
|
||||||
parts.append(path_string("engine", SCons))
|
parts.append(SCons.__copyright__)
|
||||||
parts.append("Copyright (c) 2001 - 2017 The SCons Foundation")
|
|
||||||
version = ''.join(parts)
|
version = ''.join(parts)
|
||||||
|
|
||||||
from . import SConsOptions
|
from . import SConsOptions
|
||||||
|
@ -1363,7 +1382,7 @@ def main():
|
||||||
revert_io()
|
revert_io()
|
||||||
except SystemExit as s:
|
except SystemExit as s:
|
||||||
if s:
|
if s:
|
||||||
exit_status = s
|
exit_status = s.code
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("scons: Build interrupted.")
|
print("scons: Build interrupted.")
|
||||||
sys.exit(2)
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -19,25 +20,19 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/SConsOptions.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))')
|
no_hyphen_re = re.compile(r'(\s+|(?<=[\w!\"\'&.,?])-{2,}(?=\w))')
|
||||||
|
|
||||||
try:
|
import gettext
|
||||||
from gettext import gettext
|
_ = gettext.gettext
|
||||||
except ImportError:
|
|
||||||
def gettext(message):
|
|
||||||
return message
|
|
||||||
_ = gettext
|
|
||||||
|
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
|
import SCons.Platform.virtualenv
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
OptionValueError = optparse.OptionValueError
|
OptionValueError = optparse.OptionValueError
|
||||||
|
@ -125,7 +120,8 @@ class SConsValues(optparse.Values):
|
||||||
# is not available.
|
# is not available.
|
||||||
raise AttributeError(attr)
|
raise AttributeError(attr)
|
||||||
|
|
||||||
|
# keep this list in sync with the SetOption doc in SCons/Script/Main.xml
|
||||||
|
# search for UPDATE_SETOPTION_DOCS there.
|
||||||
settable = [
|
settable = [
|
||||||
'clean',
|
'clean',
|
||||||
'diskcheck',
|
'diskcheck',
|
||||||
|
@ -139,14 +135,15 @@ class SConsValues(optparse.Values):
|
||||||
'random',
|
'random',
|
||||||
'stack_size',
|
'stack_size',
|
||||||
'warn',
|
'warn',
|
||||||
'silent'
|
'silent',
|
||||||
|
'no_progress'
|
||||||
]
|
]
|
||||||
|
|
||||||
def set_option(self, name, value):
|
def set_option(self, name, value):
|
||||||
"""
|
"""
|
||||||
Sets an option from an SConscript file.
|
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)
|
raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name)
|
||||||
|
|
||||||
if name == 'num_jobs':
|
if name == 'num_jobs':
|
||||||
|
@ -166,7 +163,7 @@ class SConsValues(optparse.Values):
|
||||||
value = str(value)
|
value = str(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise SCons.Errors.UserError("A string is required: %s"%repr(value))
|
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)
|
raise SCons.Errors.UserError("Not a valid duplication style: %s" % value)
|
||||||
# Set the duplicate style right away so it can affect linking
|
# Set the duplicate style right away so it can affect linking
|
||||||
# of SConscript files.
|
# of SConscript files.
|
||||||
|
@ -196,6 +193,9 @@ class SConsValues(optparse.Values):
|
||||||
value = [value]
|
value = [value]
|
||||||
value = self.__SConscript_settings__.get(name, []) + value
|
value = self.__SConscript_settings__.get(name, []) + value
|
||||||
SCons.Warnings.process_warn_strings(value)
|
SCons.Warnings.process_warn_strings(value)
|
||||||
|
elif name == 'no_progress':
|
||||||
|
SCons.Script.Main.progress_display.set_mode(False)
|
||||||
|
|
||||||
|
|
||||||
self.__SConscript_settings__[name] = value
|
self.__SConscript_settings__[name] = value
|
||||||
|
|
||||||
|
@ -225,39 +225,8 @@ class SConsOption(optparse.Option):
|
||||||
fmt = "option %s: nargs='?' is incompatible with short options"
|
fmt = "option %s: nargs='?' is incompatible with short options"
|
||||||
raise SCons.Errors.UserError(fmt % self._short_opts[0])
|
raise SCons.Errors.UserError(fmt % self._short_opts[0])
|
||||||
|
|
||||||
try:
|
CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_nargs_optional]
|
||||||
_orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS
|
CONST_ACTIONS = optparse.Option.CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
|
||||||
|
|
||||||
_orig_CHECK_METHODS = optparse.Option.CHECK_METHODS
|
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
# optparse.Option had no CONST_ACTIONS before Python 2.5.
|
|
||||||
|
|
||||||
_orig_CONST_ACTIONS = ("store_const",)
|
|
||||||
|
|
||||||
def _check_const(self):
|
|
||||||
if self.action not in self.CONST_ACTIONS and self.const is not None:
|
|
||||||
raise OptionError(
|
|
||||||
"'const' must not be supplied for action %r" % self.action,
|
|
||||||
self)
|
|
||||||
|
|
||||||
# optparse.Option collects its list of unbound check functions
|
|
||||||
# up front. This sucks because it means we can't just override
|
|
||||||
# the _check_const() function like a normal method, we have to
|
|
||||||
# actually replace it in the list. This seems to be the most
|
|
||||||
# straightforward way to do that.
|
|
||||||
|
|
||||||
_orig_CHECK_METHODS = [optparse.Option._check_action,
|
|
||||||
optparse.Option._check_type,
|
|
||||||
optparse.Option._check_choice,
|
|
||||||
optparse.Option._check_dest,
|
|
||||||
_check_const,
|
|
||||||
optparse.Option._check_nargs,
|
|
||||||
optparse.Option._check_callback]
|
|
||||||
|
|
||||||
CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional]
|
|
||||||
|
|
||||||
CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
|
|
||||||
|
|
||||||
class SConsOptionGroup(optparse.OptionGroup):
|
class SConsOptionGroup(optparse.OptionGroup):
|
||||||
"""
|
"""
|
||||||
|
@ -299,8 +268,7 @@ class SConsOptionParser(optparse.OptionParser):
|
||||||
"""
|
"""
|
||||||
arg = rargs.pop(0)
|
arg = rargs.pop(0)
|
||||||
|
|
||||||
# Value explicitly attached to arg? Pretend it's the next
|
# Value explicitly attached to arg? Pretend it's the next argument.
|
||||||
# argument.
|
|
||||||
if "=" in arg:
|
if "=" in arg:
|
||||||
(opt, next_arg) = arg.split("=", 1)
|
(opt, next_arg) = arg.split("=", 1)
|
||||||
rargs.insert(0, next_arg)
|
rargs.insert(0, next_arg)
|
||||||
|
@ -310,7 +278,11 @@ class SConsOptionParser(optparse.OptionParser):
|
||||||
had_explicit_value = False
|
had_explicit_value = False
|
||||||
|
|
||||||
try:
|
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:
|
except optparse.BadOptionError:
|
||||||
if self.preserve_unknown_options:
|
if self.preserve_unknown_options:
|
||||||
# SCons-specific: if requested, add unknown options to
|
# SCons-specific: if requested, add unknown options to
|
||||||
|
@ -358,29 +330,27 @@ class SConsOptionParser(optparse.OptionParser):
|
||||||
option.process(opt, value, values, self)
|
option.process(opt, value, values, self)
|
||||||
|
|
||||||
def reparse_local_options(self):
|
def reparse_local_options(self):
|
||||||
"""
|
""" Re-parse the leftover command-line options.
|
||||||
Re-parse the leftover command-line options stored
|
|
||||||
in self.largs, so that any value overridden on the
|
Parse options stored in `self.largs`, so that any value
|
||||||
command line is immediately available if the user turns
|
overridden on the command line is immediately available
|
||||||
around and does a GetOption() right away.
|
if the user turns around and does a :func:`GetOption` right away.
|
||||||
|
|
||||||
We mimic the processing of the single args
|
We mimic the processing of the single args
|
||||||
in the original OptionParser._process_args(), but here we
|
in the original OptionParser :func:`_process_args`, but here we
|
||||||
allow exact matches for long-opts only (no partial
|
allow exact matches for long-opts only (no partial argument names!).
|
||||||
argument names!).
|
Otherwise there could be problems in :func:`add_local_option`
|
||||||
|
|
||||||
Else, this would lead to problems in add_local_option()
|
|
||||||
below. When called from there, we try to reparse the
|
below. When called from there, we try to reparse the
|
||||||
command-line arguments that
|
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,
|
1. haven't been processed so far (`self.largs`), but
|
||||||
a command-line argument of "--myarg=test" would set it.
|
2. are possibly not added to the list of options yet.
|
||||||
Responsible for this behaviour is the method
|
|
||||||
_match_long_opt(), which allows for partial matches of
|
So, when we only have a value for "--myargument" so far,
|
||||||
the option name, as long as the common prefix appears to
|
a command-line argument of "--myarg=test" would set it,
|
||||||
be unique.
|
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
|
This would lead to further confusion, because we might want
|
||||||
to add another option "--myarg" later on (see issue #2929).
|
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.
|
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
|
command-line option. We add the option to a separate option
|
||||||
group for the local options, creating the group if necessary.
|
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.")
|
help="Print build actions for files from CacheDir.")
|
||||||
|
|
||||||
def opt_invalid(group, value, options):
|
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)
|
errmsg = "`%s' is not a valid %s option type, try:\n" % (value, group)
|
||||||
return errmsg + " %s" % ", ".join(options)
|
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"]
|
config_options = ["auto", "force" ,"cache"]
|
||||||
|
|
||||||
opt_config_help = "Controls Configure subsystem: %s." \
|
opt_config_help = "Controls Configure subsystem: %s." \
|
||||||
|
@ -634,9 +610,11 @@ def Parser(version):
|
||||||
help="Search up directory tree for SConstruct, "
|
help="Search up directory tree for SConstruct, "
|
||||||
"build all Default() targets.")
|
"build all Default() targets.")
|
||||||
|
|
||||||
deprecated_debug_options = {
|
deprecated_debug_options = {}
|
||||||
|
|
||||||
|
removed_debug_options = {
|
||||||
"dtree" : '; please use --tree=derived instead',
|
"dtree" : '; please use --tree=derived instead',
|
||||||
"nomemoizer" : ' and has no effect',
|
"nomemoizer" : '; there is no replacement',
|
||||||
"stree" : '; please use --tree=all,status instead',
|
"stree" : '; please use --tree=all,status instead',
|
||||||
"tree" : '; please use --tree=all instead',
|
"tree" : '; please use --tree=all instead',
|
||||||
}
|
}
|
||||||
|
@ -644,15 +622,16 @@ def Parser(version):
|
||||||
debug_options = ["count", "duplicate", "explain", "findlibs",
|
debug_options = ["count", "duplicate", "explain", "findlibs",
|
||||||
"includes", "memoizer", "memory", "objects",
|
"includes", "memoizer", "memory", "objects",
|
||||||
"pdb", "prepare", "presub", "stacktrace",
|
"pdb", "prepare", "presub", "stacktrace",
|
||||||
"time"]
|
"time", "action-timestamps"]
|
||||||
|
|
||||||
def opt_debug(option, opt, value__, parser,
|
def opt_debug(option, opt, value__, parser,
|
||||||
debug_options=debug_options,
|
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(','):
|
for value in value__.split(','):
|
||||||
if value in debug_options:
|
if value in debug_options:
|
||||||
parser.values.debug.append(value)
|
parser.values.debug.append(value)
|
||||||
elif value in list(deprecated_debug_options.keys()):
|
elif value in deprecated_debug_options:
|
||||||
parser.values.debug.append(value)
|
parser.values.debug.append(value)
|
||||||
try:
|
try:
|
||||||
parser.values.delayed_warnings
|
parser.values.delayed_warnings
|
||||||
|
@ -662,6 +641,9 @@ def Parser(version):
|
||||||
w = "The --debug=%s option is deprecated%s." % (value, msg)
|
w = "The --debug=%s option is deprecated%s." % (value, msg)
|
||||||
t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w)
|
t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w)
|
||||||
parser.values.delayed_warnings.append(t)
|
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:
|
else:
|
||||||
raise OptionValueError(opt_invalid('debug', value, debug_options))
|
raise OptionValueError(opt_invalid('debug', value, debug_options))
|
||||||
|
|
||||||
|
@ -689,7 +671,7 @@ def Parser(version):
|
||||||
metavar="TYPE")
|
metavar="TYPE")
|
||||||
|
|
||||||
def opt_duplicate(option, opt, value, parser):
|
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,
|
raise OptionValueError(opt_invalid('duplication', value,
|
||||||
SCons.Node.FS.Valid_Duplicates))
|
SCons.Node.FS.Valid_Duplicates))
|
||||||
setattr(parser.values, option.dest, value)
|
setattr(parser.values, option.dest, value)
|
||||||
|
@ -706,6 +688,12 @@ def Parser(version):
|
||||||
action="callback", callback=opt_duplicate,
|
action="callback", callback=opt_duplicate,
|
||||||
help=opt_duplicate_help)
|
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',
|
op.add_option('-f', '--file', '--makefile', '--sconstruct',
|
||||||
nargs=1, type="string",
|
nargs=1, type="string",
|
||||||
dest="file", default=[],
|
dest="file", default=[],
|
||||||
|
@ -733,6 +721,11 @@ def Parser(version):
|
||||||
help="Search DIR for imported Python modules.",
|
help="Search DIR for imported Python modules.",
|
||||||
metavar="DIR")
|
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',
|
op.add_option('--implicit-cache',
|
||||||
dest='implicit_cache', default=False,
|
dest='implicit_cache', default=False,
|
||||||
action="store_true",
|
action="store_true",
|
||||||
|
@ -841,7 +834,7 @@ def Parser(version):
|
||||||
help="Trace Node evaluation to FILE.",
|
help="Trace Node evaluation to FILE.",
|
||||||
metavar="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):
|
def opt_tree(option, opt, value, parser, tree_options=tree_options):
|
||||||
from . import Main
|
from . import Main
|
||||||
|
@ -855,6 +848,8 @@ def Parser(version):
|
||||||
tp.prune = True
|
tp.prune = True
|
||||||
elif o == 'status':
|
elif o == 'status':
|
||||||
tp.status = True
|
tp.status = True
|
||||||
|
elif o == 'linedraw':
|
||||||
|
tp.sLineDraw = True
|
||||||
else:
|
else:
|
||||||
raise OptionValueError(opt_invalid('--tree', o, tree_options))
|
raise OptionValueError(opt_invalid('--tree', o, tree_options))
|
||||||
parser.values.tree_printers.append(tp)
|
parser.values.tree_printers.append(tp)
|
||||||
|
@ -906,6 +901,7 @@ def Parser(version):
|
||||||
action="append",
|
action="append",
|
||||||
help="Search REPOSITORY for source and target files.")
|
help="Search REPOSITORY for source and target files.")
|
||||||
|
|
||||||
|
|
||||||
# Options from Make and Cons classic that we do not yet support,
|
# Options from Make and Cons classic that we do not yet support,
|
||||||
# but which we may support someday and whose (potential) meanings
|
# 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
|
# 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,
|
action="callback", callback=opt_not_yet,
|
||||||
# help="Warn when an undefined variable is referenced."
|
# help="Warn when an undefined variable is referenced."
|
||||||
help=SUPPRESS_HELP)
|
help=SUPPRESS_HELP)
|
||||||
|
|
||||||
return op
|
return op
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
|
@ -1,12 +1,6 @@
|
||||||
"""SCons.Script.SConscript
|
# MIT License
|
||||||
|
|
||||||
This module defines the Python API provided to SConscript and SConstruct
|
|
||||||
files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -27,7 +21,7 @@ files.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/SConscript.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""This module defines the Python API provided to SConscript files."""
|
||||||
|
|
||||||
import SCons
|
import SCons
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
|
@ -42,11 +36,10 @@ import SCons.Platform
|
||||||
import SCons.SConf
|
import SCons.SConf
|
||||||
import SCons.Script.Main
|
import SCons.Script.Main
|
||||||
import SCons.Tool
|
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
|
from . import Main
|
||||||
|
|
||||||
import collections
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
@ -98,7 +91,7 @@ def compute_exports(exports):
|
||||||
retval = {}
|
retval = {}
|
||||||
try:
|
try:
|
||||||
for export in exports:
|
for export in exports:
|
||||||
if SCons.Util.is_Dict(export):
|
if is_Dict(export):
|
||||||
retval.update(export)
|
retval.update(export)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -110,7 +103,7 @@ def compute_exports(exports):
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
class Frame(object):
|
class Frame:
|
||||||
"""A frame on the SConstruct/SConscript call stack"""
|
"""A frame on the SConstruct/SConscript call stack"""
|
||||||
def __init__(self, fs, exports, sconscript):
|
def __init__(self, fs, exports, sconscript):
|
||||||
self.globals = BuildDefaultGlobals()
|
self.globals = BuildDefaultGlobals()
|
||||||
|
@ -133,7 +126,7 @@ call_stack = []
|
||||||
def Return(*vars, **kw):
|
def Return(*vars, **kw):
|
||||||
retval = []
|
retval = []
|
||||||
try:
|
try:
|
||||||
fvars = SCons.Util.flatten(vars)
|
fvars = flatten(vars)
|
||||||
for var in fvars:
|
for var in fvars:
|
||||||
for v in var.split():
|
for v in var.split():
|
||||||
retval.append(call_stack[-1].globals[v])
|
retval.append(call_stack[-1].globals[v])
|
||||||
|
@ -153,6 +146,35 @@ def Return(*vars, **kw):
|
||||||
|
|
||||||
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
|
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):
|
def _SConscript(fs, *files, **kw):
|
||||||
top = fs.Top
|
top = fs.Top
|
||||||
sd = fs.SConstruct_dir.rdir()
|
sd = fs.SConstruct_dir.rdir()
|
||||||
|
@ -173,6 +195,7 @@ def _SConscript(fs, *files, **kw):
|
||||||
else:
|
else:
|
||||||
f = fs.File(str(fn))
|
f = fs.File(str(fn))
|
||||||
_file_ = None
|
_file_ = None
|
||||||
|
SConscriptNodes.add(f)
|
||||||
|
|
||||||
# Change directory to the top of the source
|
# Change directory to the top of the source
|
||||||
# tree to make sure the os's cwd and the cwd of
|
# tree to make sure the os's cwd and the cwd of
|
||||||
|
@ -249,11 +272,12 @@ def _SConscript(fs, *files, **kw):
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
# _file_ = SCons.Util.to_str(_file_)
|
|
||||||
if Main.print_time:
|
if Main.print_time:
|
||||||
time1 = time.time()
|
time1 = time.time()
|
||||||
exec(compile(_file_.read(), _file_.name, 'exec'),
|
scriptdata = _file_.read()
|
||||||
call_stack[-1].globals)
|
scriptname = _file_.name
|
||||||
|
_file_.close()
|
||||||
|
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
|
||||||
except SConscriptReturn:
|
except SConscriptReturn:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
|
@ -264,8 +288,7 @@ def _SConscript(fs, *files, **kw):
|
||||||
if old_file is not None:
|
if old_file is not None:
|
||||||
call_stack[-1].globals.update({__file__:old_file})
|
call_stack[-1].globals.update({__file__:old_file})
|
||||||
else:
|
else:
|
||||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning,
|
handle_missing_SConscript(f, kw.get('must_exist', None))
|
||||||
"Ignoring missing SConscript '%s'" % f.get_internal_path())
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
|
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
|
||||||
|
@ -369,9 +392,9 @@ class SConsEnvironment(SCons.Environment.Base):
|
||||||
something like 3.2b1."""
|
something like 3.2b1."""
|
||||||
version = version_string.split(' ')[0].split('.')
|
version = version_string.split(' ')[0].split('.')
|
||||||
v_major = int(version[0])
|
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:
|
if len(version) >= 3:
|
||||||
v_revision = int(re.match('\d+', version[2]).group())
|
v_revision = int(re.match(r'\d+', version[2]).group())
|
||||||
else:
|
else:
|
||||||
v_revision = 0
|
v_revision = 0
|
||||||
return v_major, v_minor, v_revision
|
return v_major, v_minor, v_revision
|
||||||
|
@ -391,7 +414,7 @@ class SConsEnvironment(SCons.Environment.Base):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise SCons.Errors.UserError("Invalid SConscript usage - no parameters")
|
raise SCons.Errors.UserError("Invalid SConscript usage - no parameters")
|
||||||
|
|
||||||
if not SCons.Util.is_List(dirs):
|
if not is_List(dirs):
|
||||||
dirs = [ dirs ]
|
dirs = [ dirs ]
|
||||||
dirs = list(map(str, 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")
|
raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments")
|
||||||
|
|
||||||
if not SCons.Util.is_List(files):
|
if not is_List(files):
|
||||||
files = [ files ]
|
files = [ files ]
|
||||||
|
|
||||||
if kw.get('exports'):
|
if kw.get('exports'):
|
||||||
exports.extend(self.Split(kw['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 variant_dir:
|
||||||
if len(files) != 1:
|
if len(files) != 1:
|
||||||
raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir")
|
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)
|
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
|
||||||
|
|
||||||
def SConscript(self, *ls, **kw):
|
def SConscript(self, *ls, **kw):
|
||||||
if 'build_dir' in kw:
|
"""Execute SCons configuration files.
|
||||||
msg = """The build_dir keyword has been deprecated; use the variant_dir keyword instead."""
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg)
|
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):
|
def subst_element(x, subst=self.subst):
|
||||||
if SCons.Util.is_List(x):
|
if SCons.Util.is_List(x):
|
||||||
x = list(map(subst, x))
|
x = list(map(subst, x))
|
||||||
|
@ -535,15 +580,10 @@ class SConsEnvironment(SCons.Environment.Base):
|
||||||
ls = list(map(subst_element, ls))
|
ls = list(map(subst_element, ls))
|
||||||
subst_kw = {}
|
subst_kw = {}
|
||||||
for key, val in kw.items():
|
for key, val in kw.items():
|
||||||
if SCons.Util.is_String(val):
|
if is_String(val):
|
||||||
val = self.subst(val)
|
val = self.subst(val)
|
||||||
elif SCons.Util.is_List(val):
|
elif SCons.Util.is_List(val):
|
||||||
result = []
|
val = [self.subst(v) if is_String(v) else v for v in val]
|
||||||
for v in val:
|
|
||||||
if SCons.Util.is_String(v):
|
|
||||||
v = self.subst(v)
|
|
||||||
result.append(v)
|
|
||||||
val = result
|
|
||||||
subst_kw[key] = val
|
subst_kw[key] = val
|
||||||
|
|
||||||
files, exports = self._get_SConscript_filenames(ls, subst_kw)
|
files, exports = self._get_SConscript_filenames(ls, subst_kw)
|
||||||
|
@ -593,7 +633,7 @@ def get_DefaultEnvironmentProxy():
|
||||||
_DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env)
|
_DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env)
|
||||||
return _DefaultEnvironmentProxy
|
return _DefaultEnvironmentProxy
|
||||||
|
|
||||||
class DefaultEnvironmentCall(object):
|
class DefaultEnvironmentCall:
|
||||||
"""A class that implements "global function" calls of
|
"""A class that implements "global function" calls of
|
||||||
Environment methods by fetching the specified method from the
|
Environment methods by fetching the specified method from the
|
||||||
DefaultEnvironment's class. Note that this uses an intermediate
|
DefaultEnvironment's class. Note that this uses an intermediate
|
|
@ -1,18 +1,6 @@
|
||||||
"""SCons.Script
|
# MIT License
|
||||||
|
|
||||||
This file implements the main() function used by the scons script.
|
|
||||||
|
|
||||||
Architecturally, this *is* the scons script, and will likely only be
|
|
||||||
called from the external "scons" wrapper. Consequently, anything here
|
|
||||||
should not be, or be considered, part of the build engine. If it's
|
|
||||||
something that we expect other software to want to use, it should go in
|
|
||||||
some other module. If it's specific to the "scons" script invocation,
|
|
||||||
it goes here.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -32,20 +20,23 @@ it goes here.
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import time
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import os
|
import os
|
||||||
|
from io import StringIO
|
||||||
try:
|
|
||||||
from StringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -69,7 +60,7 @@ if "--debug=memoizer" in _args:
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
try:
|
try:
|
||||||
SCons.Memoize.EnableMemoization()
|
SCons.Memoize.EnableMemoization()
|
||||||
except SCons.Warnings.Warning:
|
except SCons.Warnings.SConsWarning:
|
||||||
# Some warning was thrown. Arrange for it to be displayed
|
# Some warning was thrown. Arrange for it to be displayed
|
||||||
# or not after warnings are configured.
|
# or not after warnings are configured.
|
||||||
from . import Main
|
from . import Main
|
||||||
|
@ -81,8 +72,8 @@ import SCons.Action
|
||||||
import SCons.Builder
|
import SCons.Builder
|
||||||
import SCons.Environment
|
import SCons.Environment
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Options
|
|
||||||
import SCons.Platform
|
import SCons.Platform
|
||||||
|
import SCons.Platform.virtualenv
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
import SCons.SConf
|
import SCons.SConf
|
||||||
import SCons.Subst
|
import SCons.Subst
|
||||||
|
@ -134,7 +125,6 @@ GetBuildFailures = Main.GetBuildFailures
|
||||||
#profiling = Main.profiling
|
#profiling = Main.profiling
|
||||||
#repositories = Main.repositories
|
#repositories = Main.repositories
|
||||||
|
|
||||||
#
|
|
||||||
from . import SConscript
|
from . import SConscript
|
||||||
_SConscript = SConscript
|
_SConscript = SConscript
|
||||||
|
|
||||||
|
@ -150,6 +140,7 @@ Environment = SCons.Environment.Environment
|
||||||
#OptParser = SCons.SConsOptions.OptParser
|
#OptParser = SCons.SConsOptions.OptParser
|
||||||
FindPathDirs = SCons.Scanner.FindPathDirs
|
FindPathDirs = SCons.Scanner.FindPathDirs
|
||||||
Platform = SCons.Platform.Platform
|
Platform = SCons.Platform.Platform
|
||||||
|
Virtualenv = SCons.Platform.virtualenv.Virtualenv
|
||||||
Return = _SConscript.Return
|
Return = _SConscript.Return
|
||||||
Scanner = SCons.Scanner.Base
|
Scanner = SCons.Scanner.Base
|
||||||
Tool = SCons.Tool.Tool
|
Tool = SCons.Tool.Tool
|
||||||
|
@ -162,12 +153,6 @@ ListVariable = SCons.Variables.ListVariable
|
||||||
PackageVariable = SCons.Variables.PackageVariable
|
PackageVariable = SCons.Variables.PackageVariable
|
||||||
PathVariable = SCons.Variables.PathVariable
|
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.
|
# Action factories.
|
||||||
Chmod = SCons.Defaults.Chmod
|
Chmod = SCons.Defaults.Chmod
|
||||||
|
@ -283,12 +268,24 @@ def HelpFunction(text, append=False):
|
||||||
# Will be non-zero if we are reading an SConscript file.
|
# Will be non-zero if we are reading an SConscript file.
|
||||||
sconscript_reading = 0
|
sconscript_reading = 0
|
||||||
|
|
||||||
#
|
_no_missing_sconscript = False
|
||||||
def Variables(files=[], args=ARGUMENTS):
|
_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)
|
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
|
# The list of global functions to add to the SConscript name space
|
||||||
# that end up calling corresponding methods or Builders in the
|
# that end up calling corresponding methods or Builders in the
|
||||||
|
@ -311,7 +308,6 @@ GlobalDefaultEnvironmentFunctions = [
|
||||||
'AddPreAction',
|
'AddPreAction',
|
||||||
'Alias',
|
'Alias',
|
||||||
'AlwaysBuild',
|
'AlwaysBuild',
|
||||||
'BuildDir',
|
|
||||||
'CacheDir',
|
'CacheDir',
|
||||||
'Clean',
|
'Clean',
|
||||||
#The Command() method is handled separately, below.
|
#The Command() method is handled separately, below.
|
||||||
|
@ -342,11 +338,8 @@ GlobalDefaultEnvironmentFunctions = [
|
||||||
'Requires',
|
'Requires',
|
||||||
'SConsignFile',
|
'SConsignFile',
|
||||||
'SideEffect',
|
'SideEffect',
|
||||||
'SourceCode',
|
|
||||||
'SourceSignatures',
|
|
||||||
'Split',
|
'Split',
|
||||||
'Tag',
|
'Tag',
|
||||||
'TargetSignatures',
|
|
||||||
'Value',
|
'Value',
|
||||||
'VariantDir',
|
'VariantDir',
|
||||||
]
|
]
|
||||||
|
@ -374,7 +367,9 @@ GlobalDefaultBuilders = [
|
||||||
'SharedObject',
|
'SharedObject',
|
||||||
'StaticLibrary',
|
'StaticLibrary',
|
||||||
'StaticObject',
|
'StaticObject',
|
||||||
|
'Substfile',
|
||||||
'Tar',
|
'Tar',
|
||||||
|
'Textfile',
|
||||||
'TypeLibrary',
|
'TypeLibrary',
|
||||||
'Zip',
|
'Zip',
|
||||||
'Package',
|
'Package',
|
|
@ -1,11 +1,6 @@
|
||||||
"""SCons.Subst
|
# MIT License
|
||||||
|
|
||||||
SCons string substitution.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -26,28 +21,30 @@ SCons string substitution.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Subst.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
"""SCons string substitution."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import re
|
import re
|
||||||
|
from inspect import signature
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
|
|
||||||
from SCons.Util import is_String, is_Sequence
|
from SCons.Util import is_String, is_Sequence
|
||||||
|
|
||||||
# Indexed by the SUBST_* constants below.
|
# Indexed by the SUBST_* constants below.
|
||||||
_strconv = [SCons.Util.to_String_for_subst,
|
_strconv = [
|
||||||
SCons.Util.to_String_for_subst,
|
SCons.Util.to_String_for_subst,
|
||||||
SCons.Util.to_String_for_signature]
|
SCons.Util.to_String_for_subst,
|
||||||
|
SCons.Util.to_String_for_signature,
|
||||||
|
]
|
||||||
|
|
||||||
AllowableExceptions = (IndexError, NameError)
|
AllowableExceptions = (IndexError, NameError)
|
||||||
|
|
||||||
|
|
||||||
def SetAllowableExceptions(*excepts):
|
def SetAllowableExceptions(*excepts):
|
||||||
global AllowableExceptions
|
global AllowableExceptions
|
||||||
AllowableExceptions = [_f for _f in excepts if _f]
|
AllowableExceptions = [_f for _f in excepts if _f]
|
||||||
|
|
||||||
|
|
||||||
def raise_exception(exception, target, s):
|
def raise_exception(exception, target, s):
|
||||||
name = exception.__class__.__name__
|
name = exception.__class__.__name__
|
||||||
msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s)
|
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)
|
raise SCons.Errors.UserError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class Literal:
|
||||||
class Literal(object):
|
|
||||||
"""A wrapper for a string. If you use this object wrapped
|
"""A wrapper for a string. If you use this object wrapped
|
||||||
around a string, then it will be interpreted as literal.
|
around a string, then it will be interpreted as literal.
|
||||||
When passed to the command interpreter, all special
|
When passed to the command interpreter, all special
|
||||||
|
@ -86,7 +82,10 @@ class Literal(object):
|
||||||
def __neq__(self, other):
|
def __neq__(self, other):
|
||||||
return not self.__eq__(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 a wrapper for what we call a 'Node special attribute.'
|
||||||
This is any of the attributes of a Node that we can reference from
|
This is any of the attributes of a Node that we can reference from
|
||||||
Environment variable substitution, such as $TARGET.abspath or
|
Environment variable substitution, such as $TARGET.abspath or
|
||||||
|
@ -168,7 +167,7 @@ def escape_list(mylist, escape_func):
|
||||||
return e(escape_func)
|
return e(escape_func)
|
||||||
return list(map(escape, mylist))
|
return list(map(escape, mylist))
|
||||||
|
|
||||||
class NLWrapper(object):
|
class NLWrapper:
|
||||||
"""A wrapper class that delays turning a list of sources or targets
|
"""A wrapper class that delays turning a list of sources or targets
|
||||||
into a NodeList until it's needed. The specified function supplied
|
into a NodeList until it's needed. The specified function supplied
|
||||||
when the object is initialized is responsible for turning raw nodes
|
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()
|
nl = self.nl._create_nodelist()
|
||||||
return repr(nl)
|
return repr(nl)
|
||||||
|
|
||||||
class Target_or_Source(object):
|
class Target_or_Source:
|
||||||
"""A class that implements $TARGET or $SOURCE expansions by in turn
|
"""A class that implements $TARGET or $SOURCE expansions by in turn
|
||||||
wrapping a NLWrapper. This class handles the different methods used
|
wrapping a NLWrapper. This class handles the different methods used
|
||||||
to access an individual proxy Node, calling the NLWrapper to create
|
to access an individual proxy Node, calling the NLWrapper to create
|
||||||
|
@ -328,6 +327,407 @@ def subst_dict(target, source):
|
||||||
|
|
||||||
return dict
|
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
|
# Constants for the "mode" parameter to scons_subst_list() and
|
||||||
# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
|
# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
|
||||||
# gives a command line suitable for passing to a shell. SUBST_SIG
|
# gives a command line suitable for passing to a shell. SUBST_SIG
|
||||||
|
@ -347,7 +747,7 @@ _rm_split = re.compile(r'(?<!\$)(\$[()])')
|
||||||
_regex_remove = [ _rm, None, _rm_split ]
|
_regex_remove = [ _rm, None, _rm_split ]
|
||||||
|
|
||||||
def _rm_list(list):
|
def _rm_list(list):
|
||||||
return [l for l in list if not l in ('$(', '$)')]
|
return [l for l in list if l not in ('$(', '$)')]
|
||||||
|
|
||||||
def _remove_list(list):
|
def _remove_list(list):
|
||||||
result = []
|
result = []
|
||||||
|
@ -391,7 +791,7 @@ _list_remove = [ _rm_list, None, _remove_list ]
|
||||||
#
|
#
|
||||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
_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
|
# This regular expression is used to replace strings of multiple white
|
||||||
# space characters in the string result from the scons_subst() function.
|
# 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
|
handles separating command lines into lists of arguments, so see
|
||||||
that function if that's what you're looking for.
|
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
|
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:
|
if conv is None:
|
||||||
conv = _strconv[mode]
|
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
|
substitutions within strings, so see that function instead
|
||||||
if that's what you're looking for.
|
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:
|
if conv is None:
|
||||||
conv = _strconv[mode]
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -20,46 +21,35 @@
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
from __future__ import print_function
|
"""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__ = """
|
Taskmaster
|
||||||
Generic Taskmaster module for the SCons build engine.
|
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
|
Task
|
||||||
interface and the SCons build engine. There are two key classes here:
|
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
|
The canonical example is the SCons native Python interface,
|
||||||
----------
|
which has Task subclasses that handle its specific behavior,
|
||||||
This is the main engine for walking the dependency graph and
|
like printing "'foo' is up to date" when a top-level target
|
||||||
calling things to decide what does or doesn't need to be built.
|
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
|
The Taskmaster instantiates a Task object for each (set of)
|
||||||
----
|
target(s) that it decides need to be evaluated and/or built.
|
||||||
This is the base class for allowing a wrapping interface to
|
|
||||||
decide what does or doesn't actually need to be done. The
|
|
||||||
intention is for a wrapping interface to subclass this as
|
|
||||||
appropriate for different types of behavior it may need.
|
|
||||||
|
|
||||||
The canonical example is the SCons native Python interface,
|
|
||||||
which has Task subclasses that handle its specific behavior,
|
|
||||||
like printing "'foo' is up to date" when a top-level target
|
|
||||||
doesn't need to be built, and handling the -c option by removing
|
|
||||||
targets as its "build" action. There is also a separate subclass
|
|
||||||
for suppressing this output when the -q option is used.
|
|
||||||
|
|
||||||
The Taskmaster instantiates a Task object for each (set of)
|
|
||||||
target(s) that it decides need to be evaluated and/or built.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Taskmaster.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
from itertools import chain
|
|
||||||
import operator
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
from abc import ABC, abstractmethod
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
|
@ -81,7 +71,7 @@ print_prepare = 0 # set by option --debug=prepare
|
||||||
|
|
||||||
CollectStats = None
|
CollectStats = None
|
||||||
|
|
||||||
class Stats(object):
|
class Stats:
|
||||||
"""
|
"""
|
||||||
A simple class for holding statistics about the disposition of a
|
A simple class for holding statistics about the disposition of a
|
||||||
Node by the Taskmaster. If we're collecting statistics, each Node
|
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))
|
print((fmt % n.attributes.stats.__dict__) + str(n))
|
||||||
|
|
||||||
|
|
||||||
|
class Task(ABC):
|
||||||
class Task(object):
|
""" SCons build engine abstract task class.
|
||||||
"""
|
|
||||||
Default SCons build engine task.
|
|
||||||
|
|
||||||
This controls the interaction of the actual building of node
|
This controls the interaction of the actual building of node
|
||||||
and the rest of the engine.
|
and the rest of the engine.
|
||||||
|
@ -171,7 +159,7 @@ class Task(object):
|
||||||
"""
|
"""
|
||||||
global print_prepare
|
global print_prepare
|
||||||
T = self.tm.trace
|
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
|
# Now that it's the appropriate time, give the TaskMaster a
|
||||||
# chance to raise any exceptions it encountered while preparing
|
# chance to raise any exceptions it encountered while preparing
|
||||||
|
@ -212,17 +200,9 @@ class Task(object):
|
||||||
"""
|
"""
|
||||||
return self.node
|
return self.node
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
def needs_execute(self):
|
def needs_execute(self):
|
||||||
# TODO(deprecate): "return True" is the old default behavior;
|
return
|
||||||
# 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
|
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""
|
"""
|
||||||
|
@ -233,7 +213,7 @@ class Task(object):
|
||||||
prepare(), executed() or failed().
|
prepare(), executed() or failed().
|
||||||
"""
|
"""
|
||||||
T = self.tm.trace
|
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:
|
try:
|
||||||
cached_targets = []
|
cached_targets = []
|
||||||
|
@ -399,7 +379,7 @@ class Task(object):
|
||||||
"""
|
"""
|
||||||
global print_prepare
|
global print_prepare
|
||||||
T = self.tm.trace
|
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.node))
|
||||||
|
|
||||||
self.out_of_date = []
|
self.out_of_date = []
|
||||||
|
@ -447,7 +427,7 @@ class Task(object):
|
||||||
that can be put back on the candidates list.
|
that can be put back on the candidates list.
|
||||||
"""
|
"""
|
||||||
T = self.tm.trace
|
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
|
# We may have built multiple targets, some of which may have
|
||||||
# common parents waiting for this build. Count up how many
|
# 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
|
# A node can only be in the pending_children set if it has
|
||||||
# some waiting_parents.
|
# some waiting_parents.
|
||||||
if t.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,
|
t,
|
||||||
'removing'))
|
'removing'))
|
||||||
pending_children.discard(t)
|
pending_children.discard(t)
|
||||||
for p in t.waiting_parents:
|
for p in t.waiting_parents:
|
||||||
parents[p] = parents.get(p, 0) + 1
|
parents[p] = parents.get(p, 0) + 1
|
||||||
|
t.waiting_parents = set()
|
||||||
|
|
||||||
for t in targets:
|
for t in targets:
|
||||||
if t.side_effects is not None:
|
if t.side_effects is not None:
|
||||||
for s in t.side_effects:
|
for s in t.side_effects:
|
||||||
if s.get_state() == NODE_EXECUTING:
|
if s.get_state() == NODE_EXECUTING:
|
||||||
s.set_state(NODE_NO_STATE)
|
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:
|
for p in s.waiting_parents:
|
||||||
parents[p] = parents.get(p, 0) + 1
|
parents[p] = parents.get(p, 0) + 1
|
||||||
|
s.waiting_parents = set()
|
||||||
for p in s.waiting_s_e:
|
for p in s.waiting_s_e:
|
||||||
if p.ref_count == 0:
|
if p.ref_count == 0:
|
||||||
self.tm.candidates.append(p)
|
self.tm.candidates.append(p)
|
||||||
|
|
||||||
for p, subtract in parents.items():
|
for p, subtract in parents.items():
|
||||||
p.ref_count = p.ref_count - subtract
|
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,
|
p,
|
||||||
'adjusted parent ref count'))
|
'adjusted parent ref count'))
|
||||||
if p.ref_count == 0:
|
if p.ref_count == 0:
|
||||||
|
@ -542,19 +531,16 @@ class Task(object):
|
||||||
try:
|
try:
|
||||||
exc_type, exc_value, exc_traceback = exc
|
exc_type, exc_value, exc_traceback = exc
|
||||||
except ValueError:
|
except ValueError:
|
||||||
exc_type, exc_value = exc
|
exc_type, exc_value = exc # pylint: disable=unbalanced-tuple-unpacking
|
||||||
exc_traceback = None
|
exc_traceback = None
|
||||||
|
|
||||||
# raise exc_type(exc_value).with_traceback(exc_traceback)
|
# raise exc_type(exc_value).with_traceback(exc_traceback)
|
||||||
if sys.version_info[0] == 2:
|
if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'):
|
||||||
exec("raise exc_type, exc_value, exc_traceback")
|
# If exc_value is an exception, then just reraise
|
||||||
else: # sys.version_info[0] == 3:
|
raise exc_value.with_traceback(exc_traceback)
|
||||||
if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'):
|
else:
|
||||||
# If exc_value is an exception, then just reraise
|
# else we'll create an exception using the value and raise that
|
||||||
exec("raise exc_value.with_traceback(exc_traceback)")
|
raise exc_type(exc_value).with_traceback(exc_traceback)
|
||||||
else:
|
|
||||||
# else we'll create an exception using the value and raise that
|
|
||||||
exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
|
|
||||||
|
|
||||||
|
|
||||||
# raise e.__class__, e.__class__(e), sys.exc_info()[2]
|
# raise e.__class__, e.__class__(e), sys.exc_info()[2]
|
||||||
|
@ -573,7 +559,7 @@ class AlwaysTask(Task):
|
||||||
dependencies) can use this as follows:
|
dependencies) can use this as follows:
|
||||||
|
|
||||||
class MyTaskSubclass(SCons.Taskmaster.Task):
|
class MyTaskSubclass(SCons.Taskmaster.Task):
|
||||||
needs_execute = SCons.Taskmaster.Task.execute_always
|
needs_execute = SCons.Taskmaster.AlwaysTask.needs_execute
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -601,7 +587,7 @@ def find_cycle(stack, visited):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Taskmaster(object):
|
class Taskmaster:
|
||||||
"""
|
"""
|
||||||
The Taskmaster for walking the dependency DAG.
|
The Taskmaster for walking the dependency DAG.
|
||||||
"""
|
"""
|
||||||
|
@ -783,12 +769,12 @@ class Taskmaster(object):
|
||||||
self.ready_exc = None
|
self.ready_exc = None
|
||||||
|
|
||||||
T = self.trace
|
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:
|
while True:
|
||||||
node = self.next_candidate()
|
node = self.next_candidate()
|
||||||
if node is None:
|
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
|
return None
|
||||||
|
|
||||||
node = node.disambiguate()
|
node = node.disambiguate()
|
||||||
|
@ -811,7 +797,7 @@ class Taskmaster(object):
|
||||||
else:
|
else:
|
||||||
S = None
|
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:
|
if state == NODE_NO_STATE:
|
||||||
# Mark this node as being on the execution stack:
|
# Mark this node as being on the execution stack:
|
||||||
|
@ -819,7 +805,7 @@ class Taskmaster(object):
|
||||||
elif state > NODE_PENDING:
|
elif state > NODE_PENDING:
|
||||||
# Skip this node if it has already been evaluated:
|
# Skip this node if it has already been evaluated:
|
||||||
if S: S.already_handled = S.already_handled + 1
|
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
|
continue
|
||||||
|
|
||||||
executor = node.get_executor()
|
executor = node.get_executor()
|
||||||
|
@ -850,7 +836,7 @@ class Taskmaster(object):
|
||||||
for child in chain(executor.get_all_prerequisites(), children):
|
for child in chain(executor.get_all_prerequisites(), children):
|
||||||
childstate = child.get_state()
|
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:
|
if childstate == NODE_NO_STATE:
|
||||||
children_not_visited.append(child)
|
children_not_visited.append(child)
|
||||||
|
@ -865,8 +851,10 @@ class Taskmaster(object):
|
||||||
# These nodes have not even been visited yet. Add
|
# These nodes have not even been visited yet. Add
|
||||||
# them to the list so that on some next pass we can
|
# them to the list so that on some next pass we can
|
||||||
# take a stab at evaluating them (or their children).
|
# take a stab at evaluating them (or their children).
|
||||||
children_not_visited.reverse()
|
if children_not_visited:
|
||||||
self.candidates.extend(self.order(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:
|
# if T and children_not_visited:
|
||||||
# T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited)))
|
# T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited)))
|
||||||
|
@ -909,7 +897,7 @@ class Taskmaster(object):
|
||||||
# count so we can be put back on the list for
|
# count so we can be put back on the list for
|
||||||
# re-evaluation when they've all finished.
|
# re-evaluation when they've all finished.
|
||||||
node.ref_count = node.ref_count + child.add_to_waiting_parents(node)
|
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)))))
|
(self.trace_node(node), repr(str(child)))))
|
||||||
|
|
||||||
if T:
|
if T:
|
||||||
|
@ -935,7 +923,7 @@ class Taskmaster(object):
|
||||||
# The default when we've gotten through all of the checks above:
|
# The default when we've gotten through all of the checks above:
|
||||||
# this node is ready to be built.
|
# this node is ready to be built.
|
||||||
if S: S.build = S.build + 1
|
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)))
|
self.trace_node(node)))
|
||||||
|
|
||||||
# For debugging only:
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -32,7 +32,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "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
|
from SCons.Tool.PharLapCommon import addPharLapPaths
|
||||||
import SCons.Util
|
import SCons.Util
|
|
@ -1,15 +1,6 @@
|
||||||
from __future__ import print_function
|
# MIT License
|
||||||
|
|
||||||
"""SCons.Tool.DCommon
|
|
||||||
|
|
||||||
Common code for the various D tools.
|
|
||||||
|
|
||||||
Coded by Russel Winder (russel@winder.org.uk)
|
|
||||||
2012-09-06
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# Copyright The SCons Foundation
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -29,9 +20,14 @@ Coded by Russel Winder (russel@winder.org.uk)
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
|
|
||||||
__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
|
import os.path
|
||||||
|
|
||||||
|
@ -61,7 +57,6 @@ def allAtOnceEmitter(target, source, env):
|
||||||
env.Clean(target[0], str(target[0]) + '.o')
|
env.Clean(target[0], str(target[0]) + '.o')
|
||||||
return target, source
|
return target, source
|
||||||
|
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
||||||
# indent-tabs-mode:nil
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/FortranCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
import SCons.Defaults
|
|
||||||
import SCons.Scanner.Fortran
|
import SCons.Scanner.Fortran
|
||||||
import SCons.Tool
|
import SCons.Tool
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
@ -64,7 +60,8 @@ def _fortranEmitter(target, source, env):
|
||||||
if not node.exists() and not node.is_derived():
|
if not node.exists() and not node.is_derived():
|
||||||
print("Could not locate " + str(node.name))
|
print("Could not locate " + str(node.name))
|
||||||
return ([], [])
|
return ([], [])
|
||||||
mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
|
# 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)
|
cre = re.compile(mod_regex,re.M)
|
||||||
# Retrieve all USE'd module names
|
# Retrieve all USE'd module names
|
||||||
modules = cre.findall(node.get_text_contents())
|
modules = cre.findall(node.get_text_contents())
|
||||||
|
@ -79,10 +76,12 @@ def _fortranEmitter(target, source, env):
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
def FortranEmitter(target, source, env):
|
def FortranEmitter(target, source, env):
|
||||||
|
import SCons.Defaults
|
||||||
target, source = _fortranEmitter(target, source, env)
|
target, source = _fortranEmitter(target, source, env)
|
||||||
return SCons.Defaults.StaticObjectEmitter(target, source, env)
|
return SCons.Defaults.StaticObjectEmitter(target, source, env)
|
||||||
|
|
||||||
def ShFortranEmitter(target, source, env):
|
def ShFortranEmitter(target, source, env):
|
||||||
|
import SCons.Defaults
|
||||||
target, source = _fortranEmitter(target, source, env)
|
target, source = _fortranEmitter(target, source, env)
|
||||||
return SCons.Defaults.SharedObjectEmitter(target, source, env)
|
return SCons.Defaults.SharedObjectEmitter(target, source, env)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Used by several tools of `gettext` toolset.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -24,32 +24,32 @@ Used by several tools of `gettext` toolset.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/GettextCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
class XgettextToolWarning(SCons.Warnings.Warning): pass
|
class XgettextToolWarning(SCons.Warnings.SConsWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class XgettextNotFound(XgettextToolWarning): pass
|
class XgettextNotFound(XgettextToolWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsginitToolWarning(SCons.Warnings.Warning): pass
|
class MsginitToolWarning(SCons.Warnings.SConsWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsginitNotFound(MsginitToolWarning): pass
|
class MsginitNotFound(MsginitToolWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
|
class MsgmergeToolWarning(SCons.Warnings.SConsWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsgmergeNotFound(MsgmergeToolWarning): pass
|
class MsgmergeNotFound(MsgmergeToolWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
|
class MsgfmtToolWarning(SCons.Warnings.SConsWarning): pass
|
||||||
|
|
||||||
|
|
||||||
class MsgfmtNotFound(MsgfmtToolWarning): pass
|
class MsgfmtNotFound(MsgfmtToolWarning): pass
|
||||||
|
@ -69,7 +69,7 @@ SCons.Warnings.enableWarningClass(MsgfmtNotFound)
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
class _POTargetFactory(object):
|
class _POTargetFactory:
|
||||||
""" A factory of `PO` target files.
|
""" A factory of `PO` target files.
|
||||||
|
|
||||||
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
|
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
|
# After that it calls emitter (which is quite too late). The emitter is
|
||||||
# also called in each iteration, what makes things yet worse.
|
# also called in each iteration, what makes things yet worse.
|
||||||
def __init__(self, env, **kw):
|
def __init__(self, env, **kw):
|
||||||
if not 'suffix' in kw:
|
if 'suffix' not in kw:
|
||||||
kw['suffix'] = '$POSUFFIX'
|
kw['suffix'] = '$POSUFFIX'
|
||||||
if not 'src_suffix' in kw:
|
if 'src_suffix' not in kw:
|
||||||
kw['src_suffix'] = '$POTSUFFIX'
|
kw['src_suffix'] = '$POTSUFFIX'
|
||||||
if not 'src_builder' in kw:
|
if 'src_builder' not in kw:
|
||||||
kw['src_builder'] = '_POTUpdateBuilder'
|
kw['src_builder'] = '_POTUpdateBuilder'
|
||||||
if not 'single_source' in kw:
|
if 'single_source' not in kw:
|
||||||
kw['single_source'] = True
|
kw['single_source'] = True
|
||||||
alias = None
|
alias = None
|
||||||
if 'target_alias' in kw:
|
if 'target_alias' in kw:
|
||||||
alias = kw['target_alias']
|
alias = kw['target_alias']
|
||||||
del 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
|
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
|
||||||
BuilderBase.__init__(self, **kw)
|
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
|
""" Callable object, which returns pathnames relative to SCons current
|
||||||
working directory.
|
working directory.
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ def _detect_xgettext(env):
|
||||||
""" Detects *xgettext(1)* binary """
|
""" Detects *xgettext(1)* binary """
|
||||||
if 'XGETTEXT' in env:
|
if 'XGETTEXT' in env:
|
||||||
return env['XGETTEXT']
|
return env['XGETTEXT']
|
||||||
xgettext = env.Detect('xgettext');
|
xgettext = env.Detect('xgettext')
|
||||||
if xgettext:
|
if xgettext:
|
||||||
return xgettext
|
return xgettext
|
||||||
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
|
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
|
||||||
|
@ -409,7 +409,7 @@ def _detect_msginit(env):
|
||||||
""" Detects *msginit(1)* program. """
|
""" Detects *msginit(1)* program. """
|
||||||
if 'MSGINIT' in env:
|
if 'MSGINIT' in env:
|
||||||
return env['MSGINIT']
|
return env['MSGINIT']
|
||||||
msginit = env.Detect('msginit');
|
msginit = env.Detect('msginit')
|
||||||
if msginit:
|
if msginit:
|
||||||
return msginit
|
return msginit
|
||||||
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
|
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
|
||||||
|
@ -428,7 +428,7 @@ def _detect_msgmerge(env):
|
||||||
""" Detects *msgmerge(1)* program. """
|
""" Detects *msgmerge(1)* program. """
|
||||||
if 'MSGMERGE' in env:
|
if 'MSGMERGE' in env:
|
||||||
return env['MSGMERGE']
|
return env['MSGMERGE']
|
||||||
msgmerge = env.Detect('msgmerge');
|
msgmerge = env.Detect('msgmerge')
|
||||||
if msgmerge:
|
if msgmerge:
|
||||||
return msgmerge
|
return msgmerge
|
||||||
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
|
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
|
||||||
|
@ -447,7 +447,7 @@ def _detect_msgfmt(env):
|
||||||
""" Detects *msgmfmt(1)* program. """
|
""" Detects *msgmfmt(1)* program. """
|
||||||
if 'MSGFMT' in env:
|
if 'MSGFMT' in env:
|
||||||
return env['MSGFMT']
|
return env['MSGFMT']
|
||||||
msgfmt = env.Detect('msgfmt');
|
msgfmt = env.Detect('msgfmt')
|
||||||
if msgfmt:
|
if msgfmt:
|
||||||
return msgfmt
|
return msgfmt
|
||||||
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -27,16 +27,48 @@ Stuff for processing Java.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/JavaCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
import glob
|
||||||
|
|
||||||
java_parsing = 1
|
java_parsing = 1
|
||||||
|
|
||||||
default_java_version = '1.4'
|
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:
|
if java_parsing:
|
||||||
# Parse Java files for class names.
|
# Parse Java files for class names.
|
||||||
#
|
#
|
||||||
|
@ -55,17 +87,20 @@ if java_parsing:
|
||||||
# any alphanumeric token surrounded by angle brackets (generics);
|
# any alphanumeric token surrounded by angle brackets (generics);
|
||||||
# the multi-line comment begin and end tokens /* and */;
|
# the multi-line comment begin and end tokens /* and */;
|
||||||
# array declarations "[]".
|
# array declarations "[]".
|
||||||
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
|
# Lambda function symbols: ->
|
||||||
r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' +
|
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' +
|
||||||
r'/\*|\*/|\[\])')
|
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,
|
"""The initial state for parsing a Java file for classes,
|
||||||
interfaces, and anonymous inner classes."""
|
interfaces, and anonymous inner classes."""
|
||||||
|
|
||||||
def __init__(self, version=default_java_version):
|
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',
|
if version not in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7',
|
||||||
'1.8', '5', '6'):
|
'1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
|
||||||
msg = "Java version %s not supported" % version
|
msg = "Java version %s not supported" % version
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
|
@ -116,7 +151,7 @@ if java_parsing:
|
||||||
self.skipState = ret
|
self.skipState = ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __getAnonStack(self):
|
def _getAnonStack(self):
|
||||||
return self.anonStacksStack[-1]
|
return self.anonStacksStack[-1]
|
||||||
|
|
||||||
def openBracket(self):
|
def openBracket(self):
|
||||||
|
@ -125,15 +160,16 @@ if java_parsing:
|
||||||
def closeBracket(self):
|
def closeBracket(self):
|
||||||
self.brackets = self.brackets - 1
|
self.brackets = self.brackets - 1
|
||||||
if len(self.stackBrackets) and \
|
if len(self.stackBrackets) and \
|
||||||
self.brackets == self.stackBrackets[-1]:
|
self.brackets == self.stackBrackets[-1]:
|
||||||
self.listOutputs.append('$'.join(self.listClasses))
|
self.listOutputs.append('$'.join(self.listClasses))
|
||||||
self.localClasses.pop()
|
self.localClasses.pop()
|
||||||
self.listClasses.pop()
|
self.listClasses.pop()
|
||||||
self.anonStacksStack.pop()
|
self.anonStacksStack.pop()
|
||||||
self.stackBrackets.pop()
|
self.stackBrackets.pop()
|
||||||
if len(self.stackAnonClassBrackets) and \
|
if len(self.stackAnonClassBrackets) and \
|
||||||
self.brackets == self.stackAnonClassBrackets[-1]:
|
self.brackets == self.stackAnonClassBrackets[-1] and \
|
||||||
self.__getAnonStack().pop()
|
self.version not in scopeStateVersions:
|
||||||
|
self._getAnonStack().pop()
|
||||||
self.stackAnonClassBrackets.pop()
|
self.stackAnonClassBrackets.pop()
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
|
@ -145,13 +181,13 @@ if java_parsing:
|
||||||
self.openBracket()
|
self.openBracket()
|
||||||
elif token == '}':
|
elif token == '}':
|
||||||
self.closeBracket()
|
self.closeBracket()
|
||||||
elif token in [ '"', "'" ]:
|
elif token in ['"', "'"]:
|
||||||
return IgnoreState(token, self)
|
return IgnoreState(token, self)
|
||||||
elif token == "new":
|
elif token == "new":
|
||||||
# anonymous inner class
|
# anonymous inner class
|
||||||
if len(self.listClasses) > 0:
|
if len(self.listClasses) > 0:
|
||||||
return self.__getAnonClassState()
|
return self.__getAnonClassState()
|
||||||
return self.__getSkipState() # Skip the class name
|
return self.__getSkipState() # Skip the class name
|
||||||
elif token in ['class', 'interface', 'enum']:
|
elif token in ['class', 'interface', 'enum']:
|
||||||
if len(self.listClasses) == 0:
|
if len(self.listClasses) == 0:
|
||||||
self.nextAnon = 1
|
self.nextAnon = 1
|
||||||
|
@ -171,28 +207,99 @@ if java_parsing:
|
||||||
if self.version in ('1.1', '1.2', '1.3', '1.4'):
|
if self.version in ('1.1', '1.2', '1.3', '1.4'):
|
||||||
clazz = self.listClasses[0]
|
clazz = self.listClasses[0]
|
||||||
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
|
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)
|
self.stackAnonClassBrackets.append(self.brackets)
|
||||||
className = []
|
className = []
|
||||||
className.extend(self.listClasses)
|
className.extend(self.listClasses)
|
||||||
self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1
|
self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1
|
||||||
for anon in self.__getAnonStack():
|
for anon in self._getAnonStack():
|
||||||
className.append(str(anon))
|
className.append(str(anon))
|
||||||
self.listOutputs.append('$'.join(className))
|
self.listOutputs.append('$'.join(className))
|
||||||
|
|
||||||
self.nextAnon = self.nextAnon + 1
|
self.nextAnon = self.nextAnon + 1
|
||||||
self.__getAnonStack().append(0)
|
self._getAnonStack().append(0)
|
||||||
|
|
||||||
def setPackage(self, package):
|
def setPackage(self, package):
|
||||||
self.package = 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."""
|
"""A state that looks for anonymous inner classes."""
|
||||||
|
|
||||||
def __init__(self, old_state):
|
def __init__(self, old_state):
|
||||||
# outer_state is always an instance of OuterState
|
# outer_state is always an instance of OuterState
|
||||||
self.outer_state = old_state.outer_state
|
self.outer_state = old_state.outer_state
|
||||||
self.old_state = old_state
|
self.old_state = old_state
|
||||||
self.brace_level = 0
|
self.brace_level = 0
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
# This is an anonymous class if and only if the next
|
# This is an anonymous class if and only if the next
|
||||||
# non-whitespace token is a bracket. Everything between
|
# non-whitespace token is a bracket. Everything between
|
||||||
|
@ -212,32 +319,40 @@ if java_parsing:
|
||||||
if token == 'new':
|
if token == 'new':
|
||||||
# look further for anonymous inner class
|
# look further for anonymous inner class
|
||||||
return SkipState(1, AnonClassState(self))
|
return SkipState(1, AnonClassState(self))
|
||||||
elif token in [ '"', "'" ]:
|
elif token in ['"', "'"]:
|
||||||
return IgnoreState(token, self)
|
return IgnoreState(token, self)
|
||||||
elif token == ')':
|
elif token == ')':
|
||||||
self.brace_level = self.brace_level - 1
|
self.brace_level = self.brace_level - 1
|
||||||
return self
|
return self
|
||||||
if token == '{':
|
if token == '{':
|
||||||
self.outer_state.addAnonClass()
|
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)
|
return self.old_state.parseToken(token)
|
||||||
|
|
||||||
class SkipState(object):
|
|
||||||
|
class SkipState:
|
||||||
"""A state that will skip a specified number of tokens before
|
"""A state that will skip a specified number of tokens before
|
||||||
reverting to the previous state."""
|
reverting to the previous state."""
|
||||||
|
|
||||||
def __init__(self, tokens_to_skip, old_state):
|
def __init__(self, tokens_to_skip, old_state):
|
||||||
self.tokens_to_skip = tokens_to_skip
|
self.tokens_to_skip = tokens_to_skip
|
||||||
self.old_state = old_state
|
self.old_state = old_state
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
self.tokens_to_skip = self.tokens_to_skip - 1
|
self.tokens_to_skip = self.tokens_to_skip - 1
|
||||||
if self.tokens_to_skip < 1:
|
if self.tokens_to_skip < 1:
|
||||||
return self.old_state
|
return self.old_state
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class ClassState(object):
|
|
||||||
|
class ClassState:
|
||||||
"""A state we go into when we hit a class or interface keyword."""
|
"""A state we go into when we hit a class or interface keyword."""
|
||||||
|
|
||||||
def __init__(self, outer_state):
|
def __init__(self, outer_state):
|
||||||
# outer_state is always an instance of OuterState
|
# outer_state is always an instance of OuterState
|
||||||
self.outer_state = outer_state
|
self.outer_state = outer_state
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
# the next non-whitespace token should be the name of the class
|
# the next non-whitespace token should be the name of the class
|
||||||
if token == '\n':
|
if token == '\n':
|
||||||
|
@ -245,14 +360,14 @@ if java_parsing:
|
||||||
# If that's an inner class which is declared in a method, it
|
# If that's an inner class which is declared in a method, it
|
||||||
# requires an index prepended to the class-name, e.g.
|
# requires an index prepended to the class-name, e.g.
|
||||||
# 'Foo$1Inner'
|
# '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 \
|
if self.outer_state.localClasses and \
|
||||||
self.outer_state.stackBrackets[-1] > \
|
self.outer_state.stackBrackets[-1] > \
|
||||||
self.outer_state.stackBrackets[-2]+1:
|
self.outer_state.stackBrackets[-2] + 1:
|
||||||
locals = self.outer_state.localClasses[-1]
|
locals = self.outer_state.localClasses[-1]
|
||||||
try:
|
try:
|
||||||
idx = locals[token]
|
idx = locals[token]
|
||||||
locals[token] = locals[token]+1
|
locals[token] = locals[token] + 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
locals[token] = 1
|
locals[token] = 1
|
||||||
token = str(locals[token]) + token
|
token = str(locals[token]) + token
|
||||||
|
@ -261,29 +376,39 @@ if java_parsing:
|
||||||
self.outer_state.anonStacksStack.append([0])
|
self.outer_state.anonStacksStack.append([0])
|
||||||
return self.outer_state
|
return self.outer_state
|
||||||
|
|
||||||
class IgnoreState(object):
|
|
||||||
|
class IgnoreState:
|
||||||
"""A state that will ignore all tokens until it gets to a
|
"""A state that will ignore all tokens until it gets to a
|
||||||
specified token."""
|
specified token."""
|
||||||
|
|
||||||
def __init__(self, ignore_until, old_state):
|
def __init__(self, ignore_until, old_state):
|
||||||
self.ignore_until = ignore_until
|
self.ignore_until = ignore_until
|
||||||
self.old_state = old_state
|
self.old_state = old_state
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
if self.ignore_until == token:
|
if self.ignore_until == token:
|
||||||
return self.old_state
|
return self.old_state
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class PackageState(object):
|
|
||||||
|
class PackageState:
|
||||||
"""The state we enter when we encounter the package keyword.
|
"""The state we enter when we encounter the package keyword.
|
||||||
We assume the next token will be the package name."""
|
We assume the next token will be the package name."""
|
||||||
|
|
||||||
def __init__(self, outer_state):
|
def __init__(self, outer_state):
|
||||||
# outer_state is always an instance of OuterState
|
# outer_state is always an instance of OuterState
|
||||||
self.outer_state = outer_state
|
self.outer_state = outer_state
|
||||||
|
|
||||||
def parseToken(self, token):
|
def parseToken(self, token):
|
||||||
self.outer_state.setPackage(token)
|
self.outer_state.setPackage(token)
|
||||||
return self.outer_state
|
return self.outer_state
|
||||||
|
|
||||||
|
|
||||||
def parse_java_file(fn, version=default_java_version):
|
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):
|
def parse_java(contents, version=default_java_version, trace=None):
|
||||||
"""Parse a .java file and return a double of package directory,
|
"""Parse a .java file and return a double of package directory,
|
||||||
|
@ -315,7 +440,71 @@ else:
|
||||||
is that the file name matches the public class name, and that
|
is that the file name matches the public class name, and that
|
||||||
the path to the file is the same as the package name.
|
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:
|
# Local Variables:
|
||||||
# tab-width:4
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -21,16 +21,12 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
Common functions for Microsoft Visual Studio and Visual C/C++.
|
Common functions for Microsoft Visual Studio and Visual C/C++.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Platform.win32
|
import SCons.Platform.win32
|
||||||
|
@ -42,7 +38,8 @@ from SCons.Tool.MSCommon.sdk import mssdk_exists, \
|
||||||
from SCons.Tool.MSCommon.vc import msvc_exists, \
|
from SCons.Tool.MSCommon.vc import msvc_exists, \
|
||||||
msvc_setup_env, \
|
msvc_setup_env, \
|
||||||
msvc_setup_env_once, \
|
msvc_setup_env_once, \
|
||||||
msvc_version_to_maj_min
|
msvc_version_to_maj_min, \
|
||||||
|
msvc_find_vswhere
|
||||||
|
|
||||||
from SCons.Tool.MSCommon.vs import get_default_version, \
|
from SCons.Tool.MSCommon.vs import get_default_version, \
|
||||||
get_vs_by_version, \
|
get_vs_by_version, \
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# __COPYRIGHT__
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -21,14 +21,13 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """Module to define supported Windows chip architectures.
|
__doc__ = """Module to define supported Windows chip architectures.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
class ArchDefinition(object):
|
class ArchDefinition:
|
||||||
"""
|
"""
|
||||||
A class for defining architecture-specific settings and logic.
|
A class for defining architecture-specific settings and logic.
|
||||||
"""
|
"""
|
||||||
|
@ -37,22 +36,22 @@ class ArchDefinition(object):
|
||||||
self.synonyms = synonyms
|
self.synonyms = synonyms
|
||||||
|
|
||||||
SupportedArchitectureList = [
|
SupportedArchitectureList = [
|
||||||
ArchitectureDefinition(
|
ArchDefinition(
|
||||||
'x86',
|
'x86',
|
||||||
['i386', 'i486', 'i586', 'i686'],
|
['i386', 'i486', 'i586', 'i686'],
|
||||||
),
|
),
|
||||||
|
|
||||||
ArchitectureDefinition(
|
ArchDefinition(
|
||||||
'x86_64',
|
'x86_64',
|
||||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||||
),
|
),
|
||||||
|
|
||||||
ArchitectureDefinition(
|
ArchDefinition(
|
||||||
'ia64',
|
'ia64',
|
||||||
['IA64'],
|
['IA64'],
|
||||||
),
|
),
|
||||||
|
|
||||||
ArchitectureDefinition(
|
ArchDefinition(
|
||||||
'arm',
|
'arm',
|
||||||
['ARM'],
|
['ARM'],
|
||||||
),
|
),
|
|
@ -2,7 +2,7 @@
|
||||||
Common helper functions for working with the Microsoft tool chain.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -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
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/common.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
import SCons.Util
|
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')
|
LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG')
|
||||||
if LOGFILE == '-':
|
if LOGFILE == '-':
|
||||||
def debug(message):
|
def debug(message):
|
||||||
print(message)
|
print(message)
|
||||||
elif LOGFILE:
|
elif LOGFILE:
|
||||||
try:
|
import logging
|
||||||
import logging
|
modulelist = (
|
||||||
except ImportError:
|
# root module and parent/root module
|
||||||
debug = lambda message: open(LOGFILE, 'a').write(message + '\n')
|
'MSCommon', 'Tool',
|
||||||
else:
|
# python library and below: correct iff scons does not have a lib folder
|
||||||
logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
|
'lib',
|
||||||
debug = logging.debug
|
# 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:
|
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
|
_is_win64 = None
|
||||||
|
|
||||||
|
|
||||||
def is_win64():
|
def is_win64():
|
||||||
"""Return true if running on windows 64 bits.
|
"""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):
|
def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE):
|
||||||
return SCons.Util.RegGetValue(hkroot, value)[0]
|
return SCons.Util.RegGetValue(hkroot, value)[0]
|
||||||
|
|
||||||
|
|
||||||
def has_reg(value):
|
def has_reg(value):
|
||||||
"""Return True if the given key exists in HKEY_LOCAL_MACHINE, False
|
"""Return True if the given key exists in HKEY_LOCAL_MACHINE, False
|
||||||
otherwise."""
|
otherwise."""
|
||||||
|
@ -99,6 +169,7 @@ def has_reg(value):
|
||||||
|
|
||||||
# Functions for fetching environment variable settings from batch files.
|
# Functions for fetching environment variable settings from batch files.
|
||||||
|
|
||||||
|
|
||||||
def normalize_env(env, keys, force=False):
|
def normalize_env(env, keys, force=False):
|
||||||
"""Given a dictionary representing a shell environment, add the variables
|
"""Given a dictionary representing a shell environment, add the variables
|
||||||
from os.environ needed for the processing of .bat files; the keys are
|
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."""
|
Note: the environment is copied."""
|
||||||
normenv = {}
|
normenv = {}
|
||||||
if env:
|
if env:
|
||||||
for k in list(env.keys()):
|
for k, v in env.items():
|
||||||
normenv[k] = copy.deepcopy(env[k])
|
normenv[k] = copy.deepcopy(v)
|
||||||
|
|
||||||
for k in keys:
|
for k in keys:
|
||||||
if k in os.environ and (force or not k in normenv):
|
if k in os.environ and (force or k not in normenv):
|
||||||
normenv[k] = os.environ[k]
|
normenv[k] = os.environ[k]
|
||||||
|
|
||||||
# This shouldn't be necessary, since the default environment should include system32,
|
# add some things to PATH to prevent problems:
|
||||||
# but keep this here to be safe, since it's needed to find reg.exe which the MSVC
|
# Shouldn't be necessary to add system32, since the default environment
|
||||||
# bat scripts use.
|
# should include it, but keep this here to be safe (needed for reg.exe)
|
||||||
sys32_dir = os.path.join(os.environ.get("SystemRoot",
|
sys32_dir = os.path.join(
|
||||||
os.environ.get("windir", r"C:\Windows\system32")),
|
os.environ.get("SystemRoot", os.environ.get("windir", r"C:\Windows")), "System32"
|
||||||
"System32")
|
)
|
||||||
|
if sys32_dir not in normenv["PATH"]:
|
||||||
if sys32_dir not in normenv['PATH']:
|
normenv["PATH"] = normenv["PATH"] + os.pathsep + sys32_dir
|
||||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir
|
|
||||||
|
|
||||||
# Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
|
# Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
|
||||||
# error starting with Visual Studio 2017, although the script still
|
# 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']:
|
if sys32_wbem_dir not in normenv['PATH']:
|
||||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
|
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
|
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."""
|
"""Parse the output of given bat file, with given args."""
|
||||||
|
|
||||||
if env is None:
|
if env is None:
|
||||||
# Create a blank environment, for use in launching the tools
|
# Create a blank environment, for use in launching the tools
|
||||||
env = SCons.Environment.Environment(tools=[])
|
env = SCons.Environment.Environment(tools=[])
|
||||||
|
|
||||||
# TODO: This is a hard-coded list of the variables that (may) need
|
# TODO: Hard-coded list of the variables that (may) need to be
|
||||||
# to be imported from os.environ[] for v[sc]*vars*.bat file
|
# imported from os.environ[] for the chain of development batch
|
||||||
# execution to work. This list should really be either directly
|
# files to execute correctly. One call to vcvars*.bat may
|
||||||
# controlled by vc.py, or else derived from the common_tools_var
|
# end up running a dozen or more scripts, changes not only with
|
||||||
# settings in vs.py.
|
# 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 = [
|
vs_vc_vars = [
|
||||||
'COMSPEC',
|
'COMSPEC', # path to "shell"
|
||||||
# VS100 and VS110: Still set, but modern MSVC setup scripts will
|
'VS160COMNTOOLS', # path to common tools for given version
|
||||||
# discard these if registry has values. However Intel compiler setup
|
'VS150COMNTOOLS',
|
||||||
# script still requires these as of 2013/2014.
|
|
||||||
'VS140COMNTOOLS',
|
'VS140COMNTOOLS',
|
||||||
'VS120COMNTOOLS',
|
'VS120COMNTOOLS',
|
||||||
'VS110COMNTOOLS',
|
'VS110COMNTOOLS',
|
||||||
|
@ -167,6 +249,8 @@ def get_output(vcbat, args = None, env = None):
|
||||||
'VS71COMNTOOLS',
|
'VS71COMNTOOLS',
|
||||||
'VS70COMNTOOLS',
|
'VS70COMNTOOLS',
|
||||||
'VS60COMNTOOLS',
|
'VS60COMNTOOLS',
|
||||||
|
'VSCMD_DEBUG', # enable logging and other debug aids
|
||||||
|
'VSCMD_SKIP_SENDTELEMETRY',
|
||||||
]
|
]
|
||||||
env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False)
|
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
|
# Use the .stdout and .stderr attributes directly because the
|
||||||
# .communicate() method uses the threading module on Windows
|
# .communicate() method uses the threading module on Windows
|
||||||
# and won't work under Pythons not built with threading.
|
# and won't work under Pythons not built with threading.
|
||||||
stdout = popen.stdout.read()
|
with popen.stdout:
|
||||||
stderr = popen.stderr.read()
|
stdout = popen.stdout.read()
|
||||||
|
with popen.stderr:
|
||||||
|
stderr = popen.stderr.read()
|
||||||
|
|
||||||
# Extra debug logic, uncomment if necessary
|
# Extra debug logic, uncomment if necessary
|
||||||
# debug('get_output():stdout:%s'%stdout)
|
# debug('stdout:%s' % stdout)
|
||||||
# debug('get_output():stderr:%s'%stderr)
|
# 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:
|
if stderr:
|
||||||
# TODO: find something better to do with stderr;
|
# TODO: find something better to do with stderr;
|
||||||
# this at least prevents errors from getting swallowed.
|
# this at least prevents errors from getting swallowed.
|
||||||
import sys
|
sys.stderr.write(stderr.decode(OEM))
|
||||||
sys.stderr.write(stderr)
|
|
||||||
if popen.wait() != 0:
|
if popen.wait() != 0:
|
||||||
raise IOError(stderr.decode("mbcs"))
|
raise IOError(stderr.decode(OEM))
|
||||||
|
|
||||||
output = stdout.decode("mbcs")
|
return stdout.decode(OEM)
|
||||||
return output
|
|
||||||
|
|
||||||
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
|
Parse output from running visual c++/studios vcvarsall.bat and running set
|
||||||
To capture the values listed in keep
|
To capture the values listed in keep
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# dkeep is a dict associating key: path_list, where key is one item from
|
# dkeep is a dict associating key: path_list, where key is one item from
|
||||||
# keep, and pat_list the associated list of paths
|
# keep, and path_list the associated list of paths
|
||||||
dkeep = dict([(i, []) for i in keep])
|
dkeep = dict([(i, []) for i in keep])
|
||||||
|
|
||||||
# rdk will keep the regex to match the .bat file output line starts
|
# rdk will keep the regex to match the .bat file output line starts
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# __COPYRIGHT__
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
"""
|
"""
|
||||||
|
@ -68,7 +68,7 @@ def query_versions():
|
||||||
# sequence comparison in python is lexicographical
|
# sequence comparison in python is lexicographical
|
||||||
# which is exactly what we want.
|
# which is exactly what we want.
|
||||||
# Note we sort backwards so the highest version is first.
|
# Note we sort backwards so the highest version is first.
|
||||||
return cmp(bbl,aal)
|
return (aal > bbl) - (aal < bbl)
|
||||||
|
|
||||||
versions.sort(versrt)
|
versions.sort(versrt)
|
||||||
else:
|
else:
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
# __COPYRIGHT__
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """Module to detect the Platform/Windows SDK
|
__doc__ = """Module to detect the Platform/Windows SDK
|
||||||
|
|
||||||
|
@ -33,9 +33,7 @@ import os
|
||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
|
|
||||||
from . import common
|
from .common import debug, read_reg
|
||||||
|
|
||||||
debug = common.debug
|
|
||||||
|
|
||||||
# SDK Checks. This is of course a mess as everything else on MS platforms. Here
|
# SDK Checks. This is of course a mess as everything else on MS platforms. Here
|
||||||
# is what we do to detect the SDK:
|
# is what we do to detect the SDK:
|
||||||
|
@ -58,7 +56,7 @@ _CURINSTALLED_SDK_HKEY_ROOT = \
|
||||||
r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
|
r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
|
||||||
|
|
||||||
|
|
||||||
class SDKDefinition(object):
|
class SDKDefinition:
|
||||||
"""
|
"""
|
||||||
An abstract base class for trying to find installed SDK directories.
|
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))
|
debug('find_sdk_dir(): checking registry:{}'.format(hkey))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sdk_dir = common.read_reg(hkey)
|
sdk_dir = read_reg(hkey)
|
||||||
except SCons.Util.WinError as e:
|
except SCons.Util.WinError as e:
|
||||||
debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
|
debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
|
||||||
return None
|
return None
|
||||||
|
@ -110,19 +108,19 @@ class SDKDefinition(object):
|
||||||
""" Return the script to initialize the VC compiler installed by SDK
|
""" 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
|
# No cross tools needed compiling 32 bits on 64 bit machine
|
||||||
host_arch=target_arch
|
host_arch=target_arch
|
||||||
|
|
||||||
arch_string=target_arch
|
arch_string=target_arch
|
||||||
if (host_arch != target_arch):
|
if host_arch != target_arch:
|
||||||
arch_string='%s_%s'%(host_arch,target_arch)
|
arch_string='%s_%s'%(host_arch,target_arch)
|
||||||
|
|
||||||
debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
|
debug("get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
|
||||||
host_arch,
|
host_arch,
|
||||||
target_arch))
|
target_arch))
|
||||||
file=self.vc_setup_scripts.get(arch_string,None)
|
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
|
return file
|
||||||
|
|
||||||
class WindowsSDK(SDKDefinition):
|
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.
|
# If you update this list, update the documentation in Tool/mssdk.xml.
|
||||||
SupportedSDKList = [
|
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',
|
WindowsSDK('10.0',
|
||||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||||
include_subdir='include',
|
include_subdir='include',
|
||||||
|
@ -276,14 +284,14 @@ InstalledSDKMap = None
|
||||||
def get_installed_sdks():
|
def get_installed_sdks():
|
||||||
global InstalledSDKList
|
global InstalledSDKList
|
||||||
global InstalledSDKMap
|
global InstalledSDKMap
|
||||||
debug('sdk.py:get_installed_sdks()')
|
debug('get_installed_sdks()')
|
||||||
if InstalledSDKList is None:
|
if InstalledSDKList is None:
|
||||||
InstalledSDKList = []
|
InstalledSDKList = []
|
||||||
InstalledSDKMap = {}
|
InstalledSDKMap = {}
|
||||||
for sdk in SupportedSDKList:
|
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():
|
if sdk.get_sdk_dir():
|
||||||
debug('MSCommon/sdk.py:found SDK %s' % sdk.version)
|
debug('found SDK %s' % sdk.version)
|
||||||
InstalledSDKList.append(sdk)
|
InstalledSDKList.append(sdk)
|
||||||
InstalledSDKMap[sdk.version] = sdk
|
InstalledSDKMap[sdk.version] = sdk
|
||||||
return InstalledSDKList
|
return InstalledSDKList
|
||||||
|
@ -336,13 +344,13 @@ def get_default_sdk():
|
||||||
return InstalledSDKList[0]
|
return InstalledSDKList[0]
|
||||||
|
|
||||||
def mssdk_setup_env(env):
|
def mssdk_setup_env(env):
|
||||||
debug('sdk.py:mssdk_setup_env()')
|
debug('mssdk_setup_env()')
|
||||||
if 'MSSDK_DIR' in env:
|
if 'MSSDK_DIR' in env:
|
||||||
sdk_dir = env['MSSDK_DIR']
|
sdk_dir = env['MSSDK_DIR']
|
||||||
if sdk_dir is None:
|
if sdk_dir is None:
|
||||||
return
|
return
|
||||||
sdk_dir = env.subst(sdk_dir)
|
sdk_dir = env.subst(sdk_dir)
|
||||||
debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
|
debug('mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
|
||||||
elif 'MSSDK_VERSION' in env:
|
elif 'MSSDK_VERSION' in env:
|
||||||
sdk_version = env['MSSDK_VERSION']
|
sdk_version = env['MSSDK_VERSION']
|
||||||
if sdk_version is None:
|
if sdk_version is None:
|
||||||
|
@ -354,22 +362,22 @@ def mssdk_setup_env(env):
|
||||||
msg = "SDK version %s is not installed" % sdk_version
|
msg = "SDK version %s is not installed" % sdk_version
|
||||||
raise SCons.Errors.UserError(msg)
|
raise SCons.Errors.UserError(msg)
|
||||||
sdk_dir = mssdk.get_sdk_dir()
|
sdk_dir = mssdk.get_sdk_dir()
|
||||||
debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
|
debug('mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
|
||||||
elif 'MSVS_VERSION' in env:
|
elif 'MSVS_VERSION' in env:
|
||||||
msvs_version = env['MSVS_VERSION']
|
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:
|
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
|
return
|
||||||
msvs_version = env.subst(msvs_version)
|
msvs_version = env.subst(msvs_version)
|
||||||
from . import vs
|
from . import vs
|
||||||
msvs = vs.get_vs_by_version(msvs_version)
|
msvs = vs.get_vs_by_version(msvs_version)
|
||||||
debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs)
|
debug('mssdk_setup_env:msvs is :%s'%msvs)
|
||||||
if not 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
|
return
|
||||||
sdk_version = msvs.sdk_version
|
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:
|
if not sdk_version:
|
||||||
return
|
return
|
||||||
mssdk = get_sdk_by_version(sdk_version)
|
mssdk = get_sdk_by_version(sdk_version)
|
||||||
|
@ -378,13 +386,13 @@ def mssdk_setup_env(env):
|
||||||
if not mssdk:
|
if not mssdk:
|
||||||
return
|
return
|
||||||
sdk_dir = mssdk.get_sdk_dir()
|
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:
|
else:
|
||||||
mssdk = get_default_sdk()
|
mssdk = get_default_sdk()
|
||||||
if not mssdk:
|
if not mssdk:
|
||||||
return
|
return
|
||||||
sdk_dir = mssdk.get_sdk_dir()
|
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)
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """Module to detect Visual Studio and/or Visual C/C++
|
__doc__ = """Module to detect Visual Studio and/or Visual C/C++
|
||||||
"""
|
"""
|
||||||
|
@ -40,7 +40,7 @@ from .common import debug, \
|
||||||
|
|
||||||
import SCons.Tool.MSCommon.vc
|
import SCons.Tool.MSCommon.vc
|
||||||
|
|
||||||
class VisualStudio(object):
|
class VisualStudio:
|
||||||
"""
|
"""
|
||||||
An abstract base class for trying to find installed versions of
|
An abstract base class for trying to find installed versions of
|
||||||
Visual Studio.
|
Visual Studio.
|
||||||
|
@ -55,62 +55,61 @@ class VisualStudio(object):
|
||||||
def find_batch_file(self):
|
def find_batch_file(self):
|
||||||
vs_dir = self.get_vs_dir()
|
vs_dir = self.get_vs_dir()
|
||||||
if not vs_dir:
|
if not vs_dir:
|
||||||
debug('find_executable(): no vs_dir')
|
debug('no vs_dir')
|
||||||
return None
|
return None
|
||||||
batch_file = os.path.join(vs_dir, self.batch_file_path)
|
batch_file = os.path.join(vs_dir, self.batch_file_path)
|
||||||
batch_file = os.path.normpath(batch_file)
|
batch_file = os.path.normpath(batch_file)
|
||||||
if not os.path.isfile(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 None
|
||||||
return batch_file
|
return batch_file
|
||||||
|
|
||||||
def find_vs_dir_by_vc(self):
|
def find_vs_dir_by_vc(self, env):
|
||||||
SCons.Tool.MSCommon.vc.get_installed_vcs()
|
SCons.Tool.MSCommon.vc.get_installed_vcs(env)
|
||||||
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version)
|
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(env, self.vc_version)
|
||||||
if not dir:
|
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 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\\'
|
root = 'Software\\'
|
||||||
|
|
||||||
if is_win64():
|
if is_win64():
|
||||||
root = root + 'Wow6432Node\\'
|
root = root + 'Wow6432Node\\'
|
||||||
for key in self.hkeys:
|
for key in self.hkeys:
|
||||||
if key=='use_dir':
|
if key=='use_dir':
|
||||||
return self.find_vs_dir_by_vc()
|
return self.find_vs_dir_by_vc(env)
|
||||||
key = root + key
|
key = root + key
|
||||||
try:
|
try:
|
||||||
comps = read_reg(key)
|
comps = read_reg(key)
|
||||||
except SCons.Util.WinError as e:
|
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:
|
else:
|
||||||
debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps))
|
debug('found VS in registry: {}'.format(comps))
|
||||||
return comps
|
return comps
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def find_vs_dir(self):
|
def find_vs_dir(self, env):
|
||||||
""" Can use registry or location of VC to find vs dir
|
""" 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
|
First try to find by registry, and if that fails find via VC dir
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
vs_dir=self.find_vs_dir_by_reg(env)
|
||||||
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()
|
|
||||||
if not vs_dir:
|
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
|
return None
|
||||||
executable = os.path.join(vs_dir, self.executable_path)
|
executable = os.path.join(vs_dir, self.executable_path)
|
||||||
executable = os.path.normpath(executable)
|
executable = os.path.normpath(executable)
|
||||||
if not os.path.isfile(executable):
|
if not os.path.isfile(executable):
|
||||||
debug('find_executable(): {} not on file system'.format(executable))
|
debug('{} not on file system'.format(executable))
|
||||||
return None
|
return None
|
||||||
return executable
|
return executable
|
||||||
|
|
||||||
|
@ -122,21 +121,21 @@ class VisualStudio(object):
|
||||||
self._cache['batch_file'] = batch_file
|
self._cache['batch_file'] = batch_file
|
||||||
return batch_file
|
return batch_file
|
||||||
|
|
||||||
def get_executable(self):
|
def get_executable(self, env=None):
|
||||||
try:
|
try:
|
||||||
debug('get_executable using cache:%s'%self._cache['executable'])
|
debug('using cache:%s'%self._cache['executable'])
|
||||||
return self._cache['executable']
|
return self._cache['executable']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
executable = self.find_executable()
|
executable = self.find_executable(env)
|
||||||
self._cache['executable'] = executable
|
self._cache['executable'] = executable
|
||||||
debug('get_executable not in cache:%s'%executable)
|
debug('not in cache:%s'%executable)
|
||||||
return executable
|
return executable
|
||||||
|
|
||||||
def get_vs_dir(self):
|
def get_vs_dir(self, env):
|
||||||
try:
|
try:
|
||||||
return self._cache['vs_dir']
|
return self._cache['vs_dir']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
vs_dir = self.find_vs_dir()
|
vs_dir = self.find_vs_dir(env)
|
||||||
self._cache['vs_dir'] = vs_dir
|
self._cache['vs_dir'] = vs_dir
|
||||||
return 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.
|
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
|
||||||
|
|
||||||
SupportedVSList = [
|
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
|
# Visual Studio 2017
|
||||||
VisualStudio('14.1',
|
VisualStudio('14.1',
|
||||||
vc_version='14.1',
|
vc_version='14.1',
|
||||||
|
@ -206,10 +217,23 @@ SupportedVSList = [
|
||||||
hkeys=[],
|
hkeys=[],
|
||||||
common_tools_var='VS150COMNTOOLS',
|
common_tools_var='VS150COMNTOOLS',
|
||||||
executable_path=r'Common7\IDE\devenv.com',
|
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"],
|
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
|
# Visual Studio 2015
|
||||||
VisualStudio('14.0',
|
VisualStudio('14.0',
|
||||||
vc_version='14.0',
|
vc_version='14.0',
|
||||||
|
@ -356,7 +380,7 @@ SupportedVSList = [
|
||||||
sdk_version='2003R2',
|
sdk_version='2003R2',
|
||||||
hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
|
hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
|
||||||
common_tools_var='VS70COMNTOOLS',
|
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',
|
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||||
default_dirname='Microsoft Visual Studio .NET',
|
default_dirname='Microsoft Visual Studio .NET',
|
||||||
supported_arch=['x86'],
|
supported_arch=['x86'],
|
||||||
|
@ -389,7 +413,7 @@ for vs in SupportedVSList:
|
||||||
InstalledVSList = None
|
InstalledVSList = None
|
||||||
InstalledVSMap = None
|
InstalledVSMap = None
|
||||||
|
|
||||||
def get_installed_visual_studios():
|
def get_installed_visual_studios(env=None):
|
||||||
global InstalledVSList
|
global InstalledVSList
|
||||||
global InstalledVSMap
|
global InstalledVSMap
|
||||||
if InstalledVSList is None:
|
if InstalledVSList is None:
|
||||||
|
@ -397,7 +421,7 @@ def get_installed_visual_studios():
|
||||||
InstalledVSMap = {}
|
InstalledVSMap = {}
|
||||||
for vs in SupportedVSList:
|
for vs in SupportedVSList:
|
||||||
debug('trying to find VS %s' % vs.version)
|
debug('trying to find VS %s' % vs.version)
|
||||||
if vs.get_executable():
|
if vs.get_executable(env):
|
||||||
debug('found VS %s' % vs.version)
|
debug('found VS %s' % vs.version)
|
||||||
InstalledVSList.append(vs)
|
InstalledVSList.append(vs)
|
||||||
InstalledVSMap[vs.version] = vs
|
InstalledVSMap[vs.version] = vs
|
||||||
|
@ -448,21 +472,21 @@ def reset_installed_visual_studios():
|
||||||
# for variable, directory in env_tuple_list:
|
# for variable, directory in env_tuple_list:
|
||||||
# env.PrependENVPath(variable, directory)
|
# env.PrependENVPath(variable, directory)
|
||||||
|
|
||||||
def msvs_exists():
|
def msvs_exists(env=None):
|
||||||
return (len(get_installed_visual_studios()) > 0)
|
return (len(get_installed_visual_studios(env)) > 0)
|
||||||
|
|
||||||
def get_vs_by_version(msvs):
|
def get_vs_by_version(msvs):
|
||||||
global InstalledVSMap
|
global InstalledVSMap
|
||||||
global SupportedVSMap
|
global SupportedVSMap
|
||||||
|
|
||||||
debug('vs.py:get_vs_by_version()')
|
debug('called')
|
||||||
if msvs not in SupportedVSMap:
|
if msvs not in SupportedVSMap:
|
||||||
msg = "Visual Studio version %s is not supported" % repr(msvs)
|
msg = "Visual Studio version %s is not supported" % repr(msvs)
|
||||||
raise SCons.Errors.UserError(msg)
|
raise SCons.Errors.UserError(msg)
|
||||||
get_installed_visual_studios()
|
get_installed_visual_studios()
|
||||||
vs = InstalledVSMap.get(msvs)
|
vs = InstalledVSMap.get(msvs)
|
||||||
debug('InstalledVSMap:%s'%InstalledVSMap)
|
debug('InstalledVSMap:%s' % InstalledVSMap)
|
||||||
debug('vs.py:get_vs_by_version: found vs:%s'%vs)
|
debug('found vs:%s' % vs)
|
||||||
# Some check like this would let us provide a useful error message
|
# 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.
|
# 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
|
# However, we also want to be able to run tests (like the unit
|
||||||
|
@ -497,8 +521,8 @@ def get_default_version(env):
|
||||||
if versions:
|
if versions:
|
||||||
env['MSVS_VERSION'] = versions[0] #use highest version by default
|
env['MSVS_VERSION'] = versions[0] #use highest version by default
|
||||||
else:
|
else:
|
||||||
debug('get_default_version: WARNING: no installed versions found, '
|
debug('WARNING: no installed versions found, '
|
||||||
'using first in SupportedVSList (%s)'%SupportedVSList[0].version)
|
'using first in SupportedVSList (%s)' % SupportedVSList[0].version)
|
||||||
env['MSVS_VERSION'] = SupportedVSList[0].version
|
env['MSVS_VERSION'] = SupportedVSList[0].version
|
||||||
|
|
||||||
env['MSVS']['VERSION'] = env['MSVS_VERSION']
|
env['MSVS']['VERSION'] = env['MSVS_VERSION']
|
||||||
|
@ -521,7 +545,7 @@ def get_default_arch(env):
|
||||||
|
|
||||||
if not msvs:
|
if not msvs:
|
||||||
arch = 'x86'
|
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"
|
fmt = "Visual Studio version %s does not support architecture %s"
|
||||||
raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -29,7 +29,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/PharLapCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -79,7 +79,8 @@ def getPharLapVersion():
|
||||||
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
|
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
|
||||||
if not os.path.exists(include_path):
|
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?")
|
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:
|
if mo:
|
||||||
return int(mo.group(1))
|
return int(mo.group(1))
|
||||||
# Default return for Phar Lap 9.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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,7 +31,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/aixc++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
#forward proxy to the preffered cxx version
|
#forward proxy to the preffered cxx version
|
||||||
from SCons.Tool.aixcxx import *
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -30,7 +30,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/aixcc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,7 +31,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/aixcxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"""engine.SCons.Tool.aixf77
|
"""SCons.Tool.aixf77
|
||||||
|
|
||||||
Tool-specific initialization for IBM Visual Age f77 Fortran compiler.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -30,7 +30,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/aixf77.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
@ -7,8 +7,6 @@ It will usually be imported through the generic SCons.Tool.Tool()
|
||||||
selection method.
|
selection method.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -30,8 +28,6 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/aixlink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
@ -42,7 +38,6 @@ from . import link
|
||||||
|
|
||||||
import SCons.Tool.cxx
|
import SCons.Tool.cxx
|
||||||
cplusplus = SCons.Tool.cxx
|
cplusplus = SCons.Tool.cxx
|
||||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
|
||||||
|
|
||||||
|
|
||||||
def smart_linkflags(source, target, env, for_signature):
|
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 '-qtempinc=' + os.path.join(build_dir, 'tempinc')
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
"""
|
"""
|
||||||
Add Builders and construction variables for Visual Age linker to
|
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['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218')
|
||||||
env['SHLIBSUFFIX'] = '.a'
|
env['SHLIBSUFFIX'] = '.a'
|
||||||
|
|
||||||
|
|
||||||
def exists(env):
|
def exists(env):
|
||||||
# TODO: sync with link.smart_link() to choose a linker
|
# TODO: sync with link.smart_link() to choose a linker
|
||||||
linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
|
linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
|
||||||
alltools = []
|
alltools = []
|
||||||
for langvar, linktools in linkers.items():
|
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)
|
return SCons.Tool.FindTool(linktools, env)
|
||||||
alltools.extend(linktools)
|
alltools.extend(linktools)
|
||||||
return SCons.Tool.FindTool(alltools, env)
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,7 +31,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/ar.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Defaults
|
import SCons.Defaults
|
||||||
import SCons.Tool
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -21,27 +30,17 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Options/ListOption.py 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/
|
# Resolve FLAKE8 F401 (make sider happy)
|
||||||
class hierarchy. These will have deprecation warnings added (some day),
|
generate = SCons.Tool.asm.generate
|
||||||
and will then be removed entirely (some day).
|
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:
|
# Local Variables:
|
||||||
# tab-width:4
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -31,7 +31,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/as.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Defaults
|
import SCons.Defaults
|
||||||
import SCons.Tool
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -27,7 +27,7 @@ XXX
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/bcc32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -30,7 +30,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/c++.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
|
||||||
#forward proxy to the preffered cxx version
|
#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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -30,7 +30,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/cc.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Tool
|
import SCons.Tool
|
||||||
import SCons.Defaults
|
import SCons.Defaults
|
|
@ -1,17 +1,8 @@
|
||||||
# -*- coding: utf-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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -32,8 +23,16 @@ selection method.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
"""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.
|
# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
|
||||||
# Brought into the SCons mainline by Russel Winder 2017.
|
# Brought into the SCons mainline by Russel Winder 2017.
|
||||||
|
@ -45,6 +44,9 @@ import sys
|
||||||
|
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Tool.cc
|
import SCons.Tool.cc
|
||||||
|
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||||
|
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||||
|
|
||||||
|
|
||||||
compilers = ['clang']
|
compilers = ['clang']
|
||||||
|
|
||||||
|
@ -52,11 +54,24 @@ def generate(env):
|
||||||
"""Add Builders and construction variables for clang to an Environment."""
|
"""Add Builders and construction variables for clang to an Environment."""
|
||||||
SCons.Tool.cc.generate(env)
|
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'
|
env['CC'] = env.Detect(compilers) or 'clang'
|
||||||
if env['PLATFORM'] in ['cygwin', 'win32']:
|
if env['PLATFORM'] in ['cygwin', 'win32']:
|
||||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||||
else:
|
else:
|
||||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
||||||
|
|
||||||
# determine compiler version
|
# determine compiler version
|
||||||
if env['CC']:
|
if env['CC']:
|
||||||
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
|
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
|
||||||
|
@ -66,9 +81,9 @@ def generate(env):
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
if pipe.wait() != 0: return
|
if pipe.wait() != 0: return
|
||||||
# clang -dumpversion is of no use
|
# clang -dumpversion is of no use
|
||||||
line = pipe.stdout.readline()
|
with pipe.stdout:
|
||||||
if sys.version_info[0] > 2:
|
line = pipe.stdout.readline()
|
||||||
line = line.decode()
|
line = line.decode()
|
||||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||||
if match:
|
if match:
|
||||||
env['CCVERSION'] = match.group(1)
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -33,7 +33,7 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
# __revision__ = "src/engine/SCons/Tool/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.
|
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
|
||||||
# Brought into the SCons mainline by Russel Winder 2017.
|
# Brought into the SCons mainline by Russel Winder 2017.
|
||||||
|
@ -46,6 +46,9 @@ import sys
|
||||||
import SCons.Tool
|
import SCons.Tool
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Tool.cxx
|
import SCons.Tool.cxx
|
||||||
|
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||||
|
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||||
|
|
||||||
|
|
||||||
compilers = ['clang++']
|
compilers = ['clang++']
|
||||||
|
|
||||||
|
@ -66,17 +69,30 @@ def generate(env):
|
||||||
env['SHOBJSUFFIX'] = '.pic.o'
|
env['SHOBJSUFFIX'] = '.pic.o'
|
||||||
elif env['PLATFORM'] == 'sunos':
|
elif env['PLATFORM'] == 'sunos':
|
||||||
env['SHOBJSUFFIX'] = '.pic.o'
|
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
|
# determine compiler version
|
||||||
if env['CXX']:
|
if env['CXX']:
|
||||||
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
|
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
|
||||||
stdin='devnull',
|
stdin='devnull',
|
||||||
stderr='devnull',
|
stderr='devnull',
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
if pipe.wait() != 0: return
|
if pipe.wait() != 0:
|
||||||
|
return
|
||||||
|
|
||||||
# clang -dumpversion is of no use
|
# clang -dumpversion is of no use
|
||||||
line = pipe.stdout.readline()
|
with pipe.stdout:
|
||||||
if sys.version_info[0] > 2:
|
line = pipe.stdout.readline()
|
||||||
line = line.decode()
|
line = line.decode()
|
||||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||||
if match:
|
if match:
|
||||||
env['CXXVERSION'] = match.group(1)
|
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.
|
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
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
# a copy of this software and associated documentation files (the
|
# a copy of this software and associated documentation files (the
|
||||||
|
@ -27,7 +27,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/cvf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from . import fortran
|
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