Compare commits
9 commits
master
...
scons-4.0.
Author | SHA1 | Date | |
---|---|---|---|
|
9f31153229 | ||
|
03527f2d8c | ||
|
d3f81be01b | ||
|
e260186226 | ||
|
ad4ad235a7 | ||
|
aa228eb4f4 | ||
|
c5330bac32 | ||
|
d1a1bf27e9 | ||
|
e74be337b0 |
1513 changed files with 414113 additions and 5691 deletions
12
.travis.yml
12
.travis.yml
|
@ -9,13 +9,14 @@ 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:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.ccache
|
- $HOME/.ccache
|
||||||
|
|
||||||
dist: trusty
|
dist: xenial
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -29,7 +30,7 @@ matrix:
|
||||||
postgresql: "9.5"
|
postgresql: "9.5"
|
||||||
apt:
|
apt:
|
||||||
sources: [ 'ubuntu-toolchain-r-test']
|
sources: [ 'ubuntu-toolchain-r-test']
|
||||||
packages: [ 'libstdc++-6-dev', 'g++-6', 'xutils-dev', 'postgresql-9.5-postgis-2.3' ]
|
packages: [ 'libstdc++-6-dev', 'g++-6', 'xutils-dev', 'postgresql-9.5-postgis-2.4' ]
|
||||||
- os: linux
|
- os: linux
|
||||||
name: Linux clang-3.9
|
name: Linux clang-3.9
|
||||||
env: >-
|
env: >-
|
||||||
|
@ -42,7 +43,7 @@ matrix:
|
||||||
postgresql: "9.5"
|
postgresql: "9.5"
|
||||||
apt:
|
apt:
|
||||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
packages: [ 'clang-3.9', 'libstdc++-4.9-dev', 'xutils-dev', 'postgresql-9.5-postgis-2.3' ]
|
packages: [ 'clang-3.9', 'libstdc++-4.9-dev', 'xutils-dev', 'postgresql-9.5-postgis-2.4' ]
|
||||||
- os: linux
|
- os: linux
|
||||||
name: Linux clang-3.9 + coverage
|
name: Linux clang-3.9 + coverage
|
||||||
env: >-
|
env: >-
|
||||||
|
@ -57,11 +58,10 @@ matrix:
|
||||||
postgresql: "9.5"
|
postgresql: "9.5"
|
||||||
apt:
|
apt:
|
||||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
packages: [ 'clang-3.9', 'llvm-3.9', 'libstdc++-4.9-dev', 'xutils-dev', 'postgresql-9.5-postgis-2.3' ]
|
packages: [ 'clang-3.9', 'llvm-3.9', 'libstdc++-4.9-dev', 'xutils-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
|
osx_image: xcode12.2
|
||||||
osx_image: xcode7.3 # upgrades clang from 6 -> 7
|
|
||||||
env: >-
|
env: >-
|
||||||
CXX="ccache clang++ -Qunused-arguments"
|
CXX="ccache clang++ -Qunused-arguments"
|
||||||
|
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -11,7 +11,7 @@ endif
|
||||||
all: mapnik
|
all: mapnik
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 install
|
$(PYTHON) scons/scons.py -j$(JOBS) --config=auto --implicit-cache --max-drift=1 install
|
||||||
|
|
||||||
release:
|
release:
|
||||||
./scripts/publish_release.sh
|
./scripts/publish_release.sh
|
||||||
|
@ -22,7 +22,7 @@ test-release:
|
||||||
src/json/libmapnik-json.a:
|
src/json/libmapnik-json.a:
|
||||||
# we first build memory intensive files with -j$(HEAVY_JOBS)
|
# we first build memory intensive files with -j$(HEAVY_JOBS)
|
||||||
$(PYTHON) scons/scons.py -j$(HEAVY_JOBS) \
|
$(PYTHON) scons/scons.py -j$(HEAVY_JOBS) \
|
||||||
--config=cache --implicit-cache --max-drift=1 \
|
--config=auto --implicit-cache --max-drift=1 \
|
||||||
src/renderer_common/render_group_symbolizer.os \
|
src/renderer_common/render_group_symbolizer.os \
|
||||||
src/renderer_common/render_markers_symbolizer.os \
|
src/renderer_common/render_markers_symbolizer.os \
|
||||||
src/renderer_common/render_thunk_extractor.os \
|
src/renderer_common/render_thunk_extractor.os \
|
||||||
|
@ -45,10 +45,10 @@ src/json/libmapnik-json.a:
|
||||||
|
|
||||||
mapnik: src/json/libmapnik-json.a
|
mapnik: src/json/libmapnik-json.a
|
||||||
# then install the rest with -j$(JOBS)
|
# then install the rest with -j$(JOBS)
|
||||||
$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1
|
$(PYTHON) scons/scons.py -j$(JOBS) --config=auto --implicit-cache --max-drift=1
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@$(PYTHON) scons/scons.py -j$(JOBS) -c --config=cache --implicit-cache --max-drift=1
|
@$(PYTHON) scons/scons.py -j$(JOBS) -c --config=auto --implicit-cache --max-drift=1
|
||||||
@if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi
|
@if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi
|
||||||
@if test -e "config.log"; then rm "config.log"; fi
|
@if test -e "config.log"; then rm "config.log"; fi
|
||||||
@if test -e "config.cache"; then rm "config.cache"; fi
|
@if test -e "config.cache"; then rm "config.cache"; fi
|
||||||
|
@ -71,7 +71,7 @@ rebuild:
|
||||||
make uninstall && make clean && time make && make install
|
make uninstall && make clean && time make && make install
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
@$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 uninstall
|
@$(PYTHON) scons/scons.py -j$(JOBS) --config=auto --implicit-cache --max-drift=1 uninstall
|
||||||
|
|
||||||
test/data-visual:
|
test/data-visual:
|
||||||
./scripts/ensure_test_data.sh
|
./scripts/ensure_test_data.sh
|
||||||
|
|
17
SConstruct
17
SConstruct
|
@ -25,7 +25,6 @@ import platform
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
from SCons.SConf import SetCacheMode
|
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -142,7 +141,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 +378,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 +691,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 +1288,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 +2164,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')
|
||||||
|
|
|
@ -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 - 2020 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 - 2020 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/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
|
|
|
@ -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,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
|
|
|
@ -77,7 +77,7 @@ way for wrapping up the functions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -98,15 +98,17 @@ way for wrapping up the functions.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Action.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
@ -77,7 +77,7 @@ There are the following methods for internal use within this module:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -98,9 +98,9 @@ There are the following methods for internal use within this module:
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Builder.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import collections
|
from collections import UserDict, UserList
|
||||||
|
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
|
@ -111,7 +111,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 +197,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 +215,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 +224,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 +274,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 +293,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 +309,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 +328,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 +361,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 +396,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 +421,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
|
||||||
|
|
||||||
|
@ -554,8 +551,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 +562,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 +647,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 +752,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,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,18 +21,20 @@
|
||||||
# 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
CacheDir support
|
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 +47,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 +114,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 +135,97 @@ 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,
|
self._readconfig(path)
|
||||||
# produce a warning. If the directory doesn't exist or is empty,
|
|
||||||
# write a config file.
|
|
||||||
|
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')
|
config_file = os.path.join(path, 'config')
|
||||||
if not os.path.exists(config_file):
|
try:
|
||||||
# A note: There is a race hazard here, if two processes start and
|
os.makedirs(path, exist_ok=True)
|
||||||
# attempt to create the cache directory at the same time. However,
|
except FileExistsError:
|
||||||
# python doesn't really give you the option to do exclusive file
|
pass
|
||||||
# creation (it doesn't even give you the option to error on opening
|
except OSError:
|
||||||
# an existing file for writing...). The ordering of events here
|
msg = "Failed to create cache directory " + path
|
||||||
# as an attempt to alleviate this, on the basis that it's a pretty
|
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||||
# unlikely occurence (it'd require two builds with a brand new cache
|
|
||||||
# directory)
|
try:
|
||||||
if os.path.isdir(path) and len(os.listdir(path)) != 0:
|
with open(config_file, 'x') as config:
|
||||||
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.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 +237,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)
|
||||||
|
|
|
@ -136,7 +136,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 +157,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 +177,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 +197,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 +217,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 +290,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 +315,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
|
||||||
|
@ -354,7 +358,7 @@ def CheckHeader(context, header_name, header = None, language = None,
|
||||||
|
|
||||||
context.Display("Checking for %s header file %s... " % (lang, header_name))
|
context.Display("Checking for %s header file %s... " % (lang, header_name))
|
||||||
ret = context.CompileProg(text, suffix)
|
ret = context.CompileProg(text, suffix)
|
||||||
_YesNoResult(context, ret, "HAVE_" + header_name, text,
|
_YesNoResult(context, ret, "HAVE_" + header_name, text,
|
||||||
"Define to 1 if you have the <%s> header file." % header_name)
|
"Define to 1 if you have the <%s> header file." % header_name)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -400,7 +404,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))
|
||||||
|
@ -439,7 +443,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
|
||||||
Returns:
|
Returns:
|
||||||
status : int
|
status : int
|
||||||
0 if the check failed, or the found size of the type if the check succeeded."""
|
0 if the check failed, or the found size of the type if the check succeeded."""
|
||||||
|
|
||||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||||
if context.headerfilename:
|
if context.headerfilename:
|
||||||
includetext = '#include "%s"' % context.headerfilename
|
includetext = '#include "%s"' % context.headerfilename
|
||||||
|
@ -454,8 +458,8 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
|
||||||
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
||||||
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 +469,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;
|
||||||
|
@ -477,7 +481,7 @@ int main()
|
||||||
st = context.CompileProg(src % (type_name, expect), suffix)
|
st = context.CompileProg(src % (type_name, expect), suffix)
|
||||||
if not st:
|
if not st:
|
||||||
context.Display("yes\n")
|
context.Display("yes\n")
|
||||||
_Have(context, "SIZEOF_%s" % type_name, expect,
|
_Have(context, "SIZEOF_%s" % type_name, expect,
|
||||||
"The size of `%s', as computed by sizeof." % type_name)
|
"The size of `%s', as computed by sizeof." % type_name)
|
||||||
return expect
|
return expect
|
||||||
else:
|
else:
|
||||||
|
@ -498,7 +502,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;
|
||||||
}
|
}
|
||||||
|
@ -541,7 +545,7 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
|
||||||
Returns:
|
Returns:
|
||||||
status : bool
|
status : bool
|
||||||
True if the check failed, False if succeeded."""
|
True if the check failed, False if succeeded."""
|
||||||
|
|
||||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||||
if context.headerfilename:
|
if context.headerfilename:
|
||||||
includetext = '#include "%s"' % context.headerfilename
|
includetext = '#include "%s"' % context.headerfilename
|
||||||
|
@ -556,11 +560,11 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
|
||||||
context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
|
context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
src = includetext + includes
|
src = includetext + includes
|
||||||
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;
|
||||||
|
@ -677,7 +681,7 @@ return 0;
|
||||||
"Define to 1 if you have the `%s' library." % lib_name)
|
"Define to 1 if you have the `%s' library." % lib_name)
|
||||||
if oldLIBS != -1 and (ret or not autoadd):
|
if oldLIBS != -1 and (ret or not autoadd):
|
||||||
context.SetLIBS(oldLIBS)
|
context.SetLIBS(oldLIBS)
|
||||||
|
|
||||||
if not ret:
|
if not ret:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -704,7 +708,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 +727,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:
|
||||||
|
@ -751,7 +755,7 @@ def _Have(context, key, have, comment = None):
|
||||||
line = "#define %s %d\n" % (key_up, have)
|
line = "#define %s %d\n" % (key_up, have)
|
||||||
else:
|
else:
|
||||||
line = "#define %s %s\n" % (key_up, str(have))
|
line = "#define %s %s\n" % (key_up, str(have))
|
||||||
|
|
||||||
if comment is not None:
|
if comment is not None:
|
||||||
lines = "\n/* %s */\n" % comment + line
|
lines = "\n/* %s */\n" % comment + line
|
||||||
else:
|
else:
|
|
@ -9,7 +9,7 @@ caller_trace()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,8 +31,9 @@ caller_trace()
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Debug.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
import atexit
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -66,7 +67,7 @@ def string_to_classes(s):
|
||||||
def fetchLoggedInstances(classes="*"):
|
def fetchLoggedInstances(classes="*"):
|
||||||
classnames = string_to_classes(classes)
|
classnames = string_to_classes(classes)
|
||||||
return [(cn, len(tracked_classes[cn])) for cn in classnames]
|
return [(cn, len(tracked_classes[cn])) for cn in classnames]
|
||||||
|
|
||||||
def countLoggedInstances(classes, file=sys.stdout):
|
def countLoggedInstances(classes, file=sys.stdout):
|
||||||
for classname in string_to_classes(classes):
|
for classname in string_to_classes(classes):
|
||||||
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
|
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
|
||||||
|
@ -201,22 +202,39 @@ 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, filename=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 file argument persists
|
||||||
|
across calls unless overridden.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: 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
|
||||||
|
|
||||||
|
def trace_cleanup(traceFP):
|
||||||
|
traceFP.close()
|
||||||
|
|
||||||
if file is None:
|
if file is None:
|
||||||
file = TraceDefault
|
file = TraceDefault
|
||||||
else:
|
else:
|
||||||
TraceDefault = file
|
TraceDefault = file
|
||||||
if tstamp is None:
|
if not tstamp:
|
||||||
tstamp = TimeStampDefault
|
tstamp = TimeStampDefault
|
||||||
else:
|
else:
|
||||||
TimeStampDefault = tstamp
|
TimeStampDefault = tstamp
|
||||||
|
@ -225,6 +243,7 @@ def Trace(msg, file=None, mode='w', tstamp=None):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
try:
|
||||||
fp = TraceFP[file] = open(file, mode)
|
fp = TraceFP[file] = open(file, 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 = file
|
||||||
|
@ -234,7 +253,6 @@ def Trace(msg, file=None, mode='w', tstamp=None):
|
||||||
PreviousTime = now
|
PreviousTime = now
|
||||||
fp.write(msg)
|
fp.write(msg)
|
||||||
fp.flush()
|
fp.flush()
|
||||||
fp.close()
|
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# tab-width:4
|
# tab-width:4
|
|
@ -10,7 +10,7 @@ from distutils.msvccompiler.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,9 +31,7 @@ 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Defaults.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -193,7 +191,7 @@ def chmod_func(dest, mode):
|
||||||
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 +208,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()
|
||||||
|
@ -333,8 +331,8 @@ 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,
|
||||||
|
@ -342,6 +340,7 @@ Touch = ActionFactory(touch_func,
|
||||||
|
|
||||||
# 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 +357,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
|
||||||
|
@ -395,6 +395,7 @@ def _concat_ixes(prefix, list, suffix, env):
|
||||||
|
|
||||||
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
|
||||||
|
@ -497,7 +498,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 +517,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.
|
||||||
|
|
||||||
|
@ -565,7 +566,6 @@ ConstructionEnvironment = {
|
||||||
'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,
|
||||||
|
@ -580,6 +580,7 @@ ConstructionEnvironment = {
|
||||||
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||||
|
|
||||||
'TEMPFILE' : NullCmdGenerator,
|
'TEMPFILE' : NullCmdGenerator,
|
||||||
|
'TEMPFILEARGJOIN': ' ',
|
||||||
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
||||||
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
||||||
'File' : Variable_Method_Caller('TARGET', 'File'),
|
'File' : Variable_Method_Caller('TARGET', 'File'),
|
|
@ -10,7 +10,7 @@ Environment
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ Environment
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Environment.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
@ -46,7 +46,7 @@ import SCons.Builder
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
from SCons.Debug import logInstanceCreation
|
||||||
import SCons.Defaults
|
import SCons.Defaults
|
||||||
import SCons.Errors
|
from SCons.Errors import UserError, BuildError
|
||||||
import SCons.Memoize
|
import SCons.Memoize
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
import SCons.Node.Alias
|
import SCons.Node.Alias
|
||||||
|
@ -60,7 +60,7 @@ import SCons.Tool
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Warnings
|
import SCons.Warnings
|
||||||
|
|
||||||
class _Null(object):
|
class _Null:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_null = _Null
|
_null = _Null
|
||||||
|
@ -75,11 +75,6 @@ CalculatorArgs = {}
|
||||||
semi_deepcopy = SCons.Util.semi_deepcopy
|
semi_deepcopy = SCons.Util.semi_deepcopy
|
||||||
semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict
|
semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict
|
||||||
|
|
||||||
# Pull UserError into the global name space for the benefit of
|
|
||||||
# Environment().SourceSignatures(), which has some import statements
|
|
||||||
# which seem to mess up its ability to reference SCons directly.
|
|
||||||
UserError = SCons.Errors.UserError
|
|
||||||
|
|
||||||
def alias_builder(env, target, source):
|
def alias_builder(env, target, source):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -128,7 +123,7 @@ future_reserved_construction_var_names = [
|
||||||
|
|
||||||
def copy_non_reserved_keywords(dict):
|
def copy_non_reserved_keywords(dict):
|
||||||
result = semi_deepcopy(dict)
|
result = semi_deepcopy(dict)
|
||||||
for k in list(result.keys()):
|
for k in result.copy().keys():
|
||||||
if k in reserved_construction_var_names:
|
if k in reserved_construction_var_names:
|
||||||
msg = "Ignoring attempt to set reserved variable `$%s'"
|
msg = "Ignoring attempt to set reserved variable `$%s'"
|
||||||
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k)
|
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k)
|
||||||
|
@ -147,14 +142,14 @@ def _set_future_reserved(env, key, value):
|
||||||
def _set_BUILDERS(env, key, value):
|
def _set_BUILDERS(env, key, value):
|
||||||
try:
|
try:
|
||||||
bd = env._dict[key]
|
bd = env._dict[key]
|
||||||
for k in list(bd.keys()):
|
for k in bd.copy().keys():
|
||||||
del bd[k]
|
del bd[k]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
bd = BuilderDict(kwbd, env)
|
bd = BuilderDict(bd, env)
|
||||||
env._dict[key] = bd
|
env._dict[key] = bd
|
||||||
for k, v in value.items():
|
for k, v in value.items():
|
||||||
if not SCons.Builder.is_a_Builder(v):
|
if not SCons.Builder.is_a_Builder(v):
|
||||||
raise SCons.Errors.UserError('%s is not a Builder.' % repr(v))
|
raise UserError('%s is not a Builder.' % repr(v))
|
||||||
bd.update(value)
|
bd.update(value)
|
||||||
|
|
||||||
def _del_SCANNERS(env, key):
|
def _del_SCANNERS(env, key):
|
||||||
|
@ -196,7 +191,7 @@ def _delete_duplicates(l, keep_last):
|
||||||
# BuilderWrapper a subclass that overrides __call__() to enforce specific
|
# BuilderWrapper a subclass that overrides __call__() to enforce specific
|
||||||
# Builder calling conventions, simplified some of our higher-layer code.
|
# Builder calling conventions, simplified some of our higher-layer code.
|
||||||
|
|
||||||
class MethodWrapper(object):
|
class MethodWrapper:
|
||||||
"""
|
"""
|
||||||
A generic Wrapper class that associates a method (which can
|
A generic Wrapper class that associates a method (which can
|
||||||
actually be any callable) with an object. As part of creating this
|
actually be any callable) with an object. As part of creating this
|
||||||
|
@ -339,7 +334,7 @@ def is_valid_construction_var(varstr):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SubstitutionEnvironment(object):
|
class SubstitutionEnvironment:
|
||||||
"""Base class for different flavors of construction environments.
|
"""Base class for different flavors of construction environments.
|
||||||
|
|
||||||
This class contains a minimal set of methods that handle construction
|
This class contains a minimal set of methods that handle construction
|
||||||
|
@ -431,7 +426,7 @@ class SubstitutionEnvironment(object):
|
||||||
# efficient than calling another function or a method.
|
# efficient than calling another function or a method.
|
||||||
if key not in self._dict \
|
if key not in self._dict \
|
||||||
and not _is_valid_var.match(key):
|
and not _is_valid_var.match(key):
|
||||||
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
|
raise UserError("Illegal construction variable `%s'" % key)
|
||||||
self._dict[key] = value
|
self._dict[key] = value
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
|
@ -439,13 +434,23 @@ class SubstitutionEnvironment(object):
|
||||||
return self._dict.get(key, default)
|
return self._dict.get(key, default)
|
||||||
|
|
||||||
def has_key(self, key):
|
def has_key(self, key):
|
||||||
|
"""Emulates the has_key() method of dictionaries."""
|
||||||
return key in self._dict
|
return key in self._dict
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return self._dict.__contains__(key)
|
return self._dict.__contains__(key)
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
"""Emulates the keys() method of dictionaries."""
|
||||||
|
return self._dict.keys()
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
"""Emulates the values() method of dictionaries."""
|
||||||
|
return self._dict.values()
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return list(self._dict.items())
|
"""Emulates the items() method of dictionaries."""
|
||||||
|
return self._dict.items()
|
||||||
|
|
||||||
def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
|
def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
|
||||||
if node_factory is _null:
|
if node_factory is _null:
|
||||||
|
@ -589,7 +594,7 @@ class SubstitutionEnvironment(object):
|
||||||
out,err = p.communicate()
|
out,err = p.communicate()
|
||||||
status = p.wait()
|
status = p.wait()
|
||||||
if err:
|
if err:
|
||||||
sys.stderr.write(u"" + err)
|
sys.stderr.write("" + err)
|
||||||
if status:
|
if status:
|
||||||
raise OSError("'%s' exited %d" % (command, status))
|
raise OSError("'%s' exited %d" % (command, status))
|
||||||
return out
|
return out
|
||||||
|
@ -608,7 +613,7 @@ class SubstitutionEnvironment(object):
|
||||||
Removes the specified function's MethodWrapper from the
|
Removes the specified function's MethodWrapper from the
|
||||||
added_methods list, so we don't re-bind it when making a clone.
|
added_methods list, so we don't re-bind it when making a clone.
|
||||||
"""
|
"""
|
||||||
self.added_methods = [dm for dm in self.added_methods if not dm.method is function]
|
self.added_methods = [dm for dm in self.added_methods if dm.method is not function]
|
||||||
|
|
||||||
def Override(self, overrides):
|
def Override(self, overrides):
|
||||||
"""
|
"""
|
||||||
|
@ -707,25 +712,34 @@ class SubstitutionEnvironment(object):
|
||||||
append_next_arg_to = None # for multi-word args
|
append_next_arg_to = None # for multi-word args
|
||||||
for arg in params:
|
for arg in params:
|
||||||
if append_next_arg_to:
|
if append_next_arg_to:
|
||||||
if append_next_arg_to == 'CPPDEFINES':
|
if append_next_arg_to == 'CPPDEFINES':
|
||||||
append_define(arg)
|
append_define(arg)
|
||||||
elif append_next_arg_to == '-include':
|
elif append_next_arg_to == '-include':
|
||||||
t = ('-include', self.fs.File(arg))
|
t = ('-include', self.fs.File(arg))
|
||||||
dict['CCFLAGS'].append(t)
|
dict['CCFLAGS'].append(t)
|
||||||
elif append_next_arg_to == '-isysroot':
|
elif append_next_arg_to == '-imacros':
|
||||||
t = ('-isysroot', arg)
|
t = ('-imacros', self.fs.File(arg))
|
||||||
dict['CCFLAGS'].append(t)
|
dict['CCFLAGS'].append(t)
|
||||||
dict['LINKFLAGS'].append(t)
|
elif append_next_arg_to == '-isysroot':
|
||||||
elif append_next_arg_to == '-isystem':
|
t = ('-isysroot', arg)
|
||||||
t = ('-isystem', arg)
|
dict['CCFLAGS'].append(t)
|
||||||
dict['CCFLAGS'].append(t)
|
dict['LINKFLAGS'].append(t)
|
||||||
elif append_next_arg_to == '-arch':
|
elif append_next_arg_to == '-isystem':
|
||||||
t = ('-arch', arg)
|
t = ('-isystem', arg)
|
||||||
dict['CCFLAGS'].append(t)
|
dict['CCFLAGS'].append(t)
|
||||||
dict['LINKFLAGS'].append(t)
|
elif append_next_arg_to == '-iquote':
|
||||||
else:
|
t = ('-iquote', arg)
|
||||||
dict[append_next_arg_to].append(arg)
|
dict['CCFLAGS'].append(t)
|
||||||
append_next_arg_to = None
|
elif append_next_arg_to == '-idirafter':
|
||||||
|
t = ('-idirafter', arg)
|
||||||
|
dict['CCFLAGS'].append(t)
|
||||||
|
elif append_next_arg_to == '-arch':
|
||||||
|
t = ('-arch', arg)
|
||||||
|
dict['CCFLAGS'].append(t)
|
||||||
|
dict['LINKFLAGS'].append(t)
|
||||||
|
else:
|
||||||
|
dict[append_next_arg_to].append(arg)
|
||||||
|
append_next_arg_to = None
|
||||||
elif not arg[0] in ['-', '+']:
|
elif not arg[0] in ['-', '+']:
|
||||||
dict['LIBS'].append(self.fs.File(arg))
|
dict['LIBS'].append(self.fs.File(arg))
|
||||||
elif arg == '-dylib_file':
|
elif arg == '-dylib_file':
|
||||||
|
@ -777,13 +791,14 @@ class SubstitutionEnvironment(object):
|
||||||
elif arg in ['-mno-cygwin',
|
elif arg in ['-mno-cygwin',
|
||||||
'-pthread',
|
'-pthread',
|
||||||
'-openmp',
|
'-openmp',
|
||||||
|
'-fmerge-all-constants',
|
||||||
'-fopenmp']:
|
'-fopenmp']:
|
||||||
dict['CCFLAGS'].append(arg)
|
dict['CCFLAGS'].append(arg)
|
||||||
dict['LINKFLAGS'].append(arg)
|
dict['LINKFLAGS'].append(arg)
|
||||||
elif arg == '-mwindows':
|
elif arg == '-mwindows':
|
||||||
dict['LINKFLAGS'].append(arg)
|
dict['LINKFLAGS'].append(arg)
|
||||||
elif arg[:5] == '-std=':
|
elif arg[:5] == '-std=':
|
||||||
if arg[5:].find('++')!=-1:
|
if '++' in arg[5:]:
|
||||||
key='CXXFLAGS'
|
key='CXXFLAGS'
|
||||||
else:
|
else:
|
||||||
key='CFLAGS'
|
key='CFLAGS'
|
||||||
|
@ -791,7 +806,7 @@ class SubstitutionEnvironment(object):
|
||||||
elif arg[0] == '+':
|
elif arg[0] == '+':
|
||||||
dict['CCFLAGS'].append(arg)
|
dict['CCFLAGS'].append(arg)
|
||||||
dict['LINKFLAGS'].append(arg)
|
dict['LINKFLAGS'].append(arg)
|
||||||
elif arg in ['-include', '-isysroot', '-isystem', '-arch']:
|
elif arg in ['-include', '-imacros', '-isysroot', '-isystem', '-iquote', '-idirafter', '-arch']:
|
||||||
append_next_arg_to = arg
|
append_next_arg_to = arg
|
||||||
else:
|
else:
|
||||||
dict['CCFLAGS'].append(arg)
|
dict['CCFLAGS'].append(arg)
|
||||||
|
@ -850,26 +865,28 @@ class SubstitutionEnvironment(object):
|
||||||
t.append(v)
|
t.append(v)
|
||||||
else:
|
else:
|
||||||
### keep right-most occurence
|
### keep right-most occurence
|
||||||
orig.reverse()
|
for v in orig[::-1]:
|
||||||
for v in orig:
|
|
||||||
if v not in t:
|
if v not in t:
|
||||||
t.insert(0, v)
|
t.insert(0, v)
|
||||||
self[key] = t
|
self[key] = t
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def default_decide_source(dependency, target, prev_ni):
|
def default_decide_source(dependency, target, prev_ni, repo_node=None):
|
||||||
f = SCons.Defaults.DefaultEnvironment().decide_source
|
f = SCons.Defaults.DefaultEnvironment().decide_source
|
||||||
return f(dependency, target, prev_ni)
|
return f(dependency, target, prev_ni, repo_node)
|
||||||
|
|
||||||
def default_decide_target(dependency, target, prev_ni):
|
|
||||||
|
def default_decide_target(dependency, target, prev_ni, repo_node=None):
|
||||||
f = SCons.Defaults.DefaultEnvironment().decide_target
|
f = SCons.Defaults.DefaultEnvironment().decide_target
|
||||||
return f(dependency, target, prev_ni)
|
return f(dependency, target, prev_ni, repo_node)
|
||||||
|
|
||||||
|
|
||||||
def default_copy_from_cache(src, dst):
|
def default_copy_from_cache(src, dst):
|
||||||
f = SCons.Defaults.DefaultEnvironment().copy_from_cache
|
f = SCons.Defaults.DefaultEnvironment().copy_from_cache
|
||||||
return f(src, dst)
|
return f(src, dst)
|
||||||
|
|
||||||
|
|
||||||
class Base(SubstitutionEnvironment):
|
class Base(SubstitutionEnvironment):
|
||||||
"""Base class for "real" construction Environments. These are the
|
"""Base class for "real" construction Environments. These are the
|
||||||
primary objects used to communicate dependency and construction
|
primary objects used to communicate dependency and construction
|
||||||
|
@ -1217,7 +1234,7 @@ class Base(SubstitutionEnvironment):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def AppendENVPath(self, name, newpath, envname = 'ENV',
|
def AppendENVPath(self, name, newpath, envname = 'ENV',
|
||||||
sep = os.pathsep, delete_existing=1):
|
sep = os.pathsep, delete_existing=0):
|
||||||
"""Append path elements to the path 'name' in the 'ENV'
|
"""Append path elements to the path 'name' in the 'ENV'
|
||||||
dictionary for this environment. Will only add any particular
|
dictionary for this environment. Will only add any particular
|
||||||
path once, and will normpath and normcase all paths to help
|
path once, and will normpath and normcase all paths to help
|
||||||
|
@ -1342,7 +1359,7 @@ class Base(SubstitutionEnvironment):
|
||||||
dk = list(filter(lambda x, val=val: x not in val, dk))
|
dk = list(filter(lambda x, val=val: x not in val, dk))
|
||||||
self._dict[key] = dk + [val]
|
self._dict[key] = dk + [val]
|
||||||
else:
|
else:
|
||||||
if not val in dk:
|
if val not in dk:
|
||||||
self._dict[key] = dk + [val]
|
self._dict[key] = dk + [val]
|
||||||
else:
|
else:
|
||||||
if key == 'CPPDEFINES':
|
if key == 'CPPDEFINES':
|
||||||
|
@ -1420,38 +1437,30 @@ class Base(SubstitutionEnvironment):
|
||||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
|
if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def Copy(self, *args, **kw):
|
def _changed_build(self, dependency, target, prev_ni, repo_node=None):
|
||||||
global _warn_copy_deprecated
|
if dependency.changed_state(target, prev_ni, repo_node):
|
||||||
if _warn_copy_deprecated:
|
|
||||||
msg = "The env.Copy() method is deprecated; use the env.Clone() method instead."
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg)
|
|
||||||
_warn_copy_deprecated = False
|
|
||||||
return self.Clone(*args, **kw)
|
|
||||||
|
|
||||||
def _changed_build(self, dependency, target, prev_ni):
|
|
||||||
if dependency.changed_state(target, prev_ni):
|
|
||||||
return 1
|
return 1
|
||||||
return self.decide_source(dependency, target, prev_ni)
|
return self.decide_source(dependency, target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _changed_content(self, dependency, target, prev_ni):
|
def _changed_content(self, dependency, target, prev_ni, repo_node=None):
|
||||||
return dependency.changed_content(target, prev_ni)
|
return dependency.changed_content(target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _changed_source(self, dependency, target, prev_ni):
|
def _changed_source(self, dependency, target, prev_ni, repo_node=None):
|
||||||
target_env = dependency.get_build_env()
|
target_env = dependency.get_build_env()
|
||||||
type = target_env.get_tgt_sig_type()
|
type = target_env.get_tgt_sig_type()
|
||||||
if type == 'source':
|
if type == 'source':
|
||||||
return target_env.decide_source(dependency, target, prev_ni)
|
return target_env.decide_source(dependency, target, prev_ni, repo_node)
|
||||||
else:
|
else:
|
||||||
return target_env.decide_target(dependency, target, prev_ni)
|
return target_env.decide_target(dependency, target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _changed_timestamp_then_content(self, dependency, target, prev_ni):
|
def _changed_timestamp_then_content(self, dependency, target, prev_ni, repo_node=None):
|
||||||
return dependency.changed_timestamp_then_content(target, prev_ni)
|
return dependency.changed_timestamp_then_content(target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _changed_timestamp_newer(self, dependency, target, prev_ni):
|
def _changed_timestamp_newer(self, dependency, target, prev_ni, repo_node=None):
|
||||||
return dependency.changed_timestamp_newer(target, prev_ni)
|
return dependency.changed_timestamp_newer(target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _changed_timestamp_match(self, dependency, target, prev_ni):
|
def _changed_timestamp_match(self, dependency, target, prev_ni, repo_node=None):
|
||||||
return dependency.changed_timestamp_match(target, prev_ni)
|
return dependency.changed_timestamp_match(target, prev_ni, repo_node)
|
||||||
|
|
||||||
def _copy_from_cache(self, src, dst):
|
def _copy_from_cache(self, src, dst):
|
||||||
return self.fs.copy(src, dst)
|
return self.fs.copy(src, dst)
|
||||||
|
@ -1483,8 +1492,14 @@ class Base(SubstitutionEnvironment):
|
||||||
|
|
||||||
self.copy_from_cache = copy_function
|
self.copy_from_cache = copy_function
|
||||||
|
|
||||||
|
|
||||||
def Detect(self, progs):
|
def Detect(self, progs):
|
||||||
"""Return the first available program in progs.
|
"""Return the first available program in progs.
|
||||||
|
|
||||||
|
:param progs: one or more command names to check for
|
||||||
|
:type progs: str or list
|
||||||
|
:returns str: first name from progs that can be found.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not SCons.Util.is_List(progs):
|
if not SCons.Util.is_List(progs):
|
||||||
progs = [ progs ]
|
progs = [ progs ]
|
||||||
|
@ -1493,7 +1508,22 @@ class Base(SubstitutionEnvironment):
|
||||||
if path: return prog
|
if path: return prog
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def Dictionary(self, *args):
|
def Dictionary(self, *args):
|
||||||
|
"""Return construction variables from an environment.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
\*args (optional): variable names to look up
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If `args` omitted, the dictionary of all construction variables.
|
||||||
|
If one arg, the corresponding value is returned.
|
||||||
|
If more than one arg, a list of values is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: if any of `args` is not in the construction environment.
|
||||||
|
|
||||||
|
"""
|
||||||
if not args:
|
if not args:
|
||||||
return self._dict
|
return self._dict
|
||||||
dlist = [self._dict[x] for x in args]
|
dlist = [self._dict[x] for x in args]
|
||||||
|
@ -1501,31 +1531,56 @@ class Base(SubstitutionEnvironment):
|
||||||
dlist = dlist[0]
|
dlist = dlist[0]
|
||||||
return dlist
|
return dlist
|
||||||
|
|
||||||
def Dump(self, key = None):
|
|
||||||
"""
|
|
||||||
Using the standard Python pretty printer, return the contents of the
|
|
||||||
scons build environment as a string.
|
|
||||||
|
|
||||||
If the key passed in is anything other than None, then that will
|
def Dump(self, key=None, format='pretty'):
|
||||||
be used as an index into the build environment dictionary and
|
""" Return construction variables serialized to a string.
|
||||||
whatever is found there will be fed into the pretty printer. Note
|
|
||||||
that this key is case sensitive.
|
Args:
|
||||||
|
key (optional): if None, format the whole dict of variables.
|
||||||
|
Else format the value of `key` (Default value = None)
|
||||||
|
format (optional): specify the format to serialize to.
|
||||||
|
`"pretty"` generates a pretty-printed string,
|
||||||
|
`"json"` a JSON-formatted string.
|
||||||
|
(Default value = None, equivalent to `"pretty"`)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import pprint
|
|
||||||
pp = pprint.PrettyPrinter(indent=2)
|
|
||||||
if key:
|
if key:
|
||||||
dict = self.Dictionary(key)
|
cvars = self.Dictionary(key)
|
||||||
else:
|
else:
|
||||||
dict = self.Dictionary()
|
cvars = self.Dictionary()
|
||||||
return pp.pformat(dict)
|
|
||||||
|
fmt = format.lower()
|
||||||
|
|
||||||
|
if fmt == 'pretty':
|
||||||
|
import pprint
|
||||||
|
pp = pprint.PrettyPrinter(indent=2)
|
||||||
|
|
||||||
|
# TODO: pprint doesn't do a nice job on path-style values
|
||||||
|
# if the paths contain spaces (i.e. Windows), because the
|
||||||
|
# algorithm tries to break lines on spaces, while breaking
|
||||||
|
# on the path-separator would be more "natural". Is there
|
||||||
|
# a better way to format those?
|
||||||
|
return pp.pformat(cvars)
|
||||||
|
|
||||||
|
elif fmt == 'json':
|
||||||
|
import json
|
||||||
|
def non_serializable(obj):
|
||||||
|
return str(type(obj).__qualname__)
|
||||||
|
return json.dumps(cvars, indent=4, default=non_serializable)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupported serialization format: %s." % fmt)
|
||||||
|
|
||||||
|
|
||||||
def FindIxes(self, paths, prefix, suffix):
|
def FindIxes(self, paths, prefix, suffix):
|
||||||
"""
|
"""Search a list of paths for something that matches the prefix and suffix.
|
||||||
Search a list of paths for something that matches the prefix and suffix.
|
|
||||||
|
Args:
|
||||||
|
paths: the list of paths or nodes.
|
||||||
|
prefix: construction variable for the prefix.
|
||||||
|
suffix: construction variable for the suffix.
|
||||||
|
|
||||||
|
Returns: the matched path or None
|
||||||
|
|
||||||
paths - the list of paths or nodes.
|
|
||||||
prefix - construction variable for the prefix.
|
|
||||||
suffix - construction variable for the suffix.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
suffix = self.subst('$'+suffix)
|
suffix = self.subst('$'+suffix)
|
||||||
|
@ -1568,12 +1623,12 @@ class Base(SubstitutionEnvironment):
|
||||||
"""
|
"""
|
||||||
filename = self.subst(filename)
|
filename = self.subst(filename)
|
||||||
try:
|
try:
|
||||||
fp = open(filename, 'r')
|
with open(filename, 'r') as fp:
|
||||||
|
lines = SCons.Util.LogicalLines(fp).readlines()
|
||||||
except IOError:
|
except IOError:
|
||||||
if must_exist:
|
if must_exist:
|
||||||
raise
|
raise
|
||||||
return
|
return
|
||||||
lines = SCons.Util.LogicalLines(fp).readlines()
|
|
||||||
lines = [l for l in lines if l[0] != '#']
|
lines = [l for l in lines if l[0] != '#']
|
||||||
tdlist = []
|
tdlist = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -1590,7 +1645,7 @@ class Base(SubstitutionEnvironment):
|
||||||
for td in tdlist:
|
for td in tdlist:
|
||||||
targets.extend(td[0])
|
targets.extend(td[0])
|
||||||
if len(targets) > 1:
|
if len(targets) > 1:
|
||||||
raise SCons.Errors.UserError(
|
raise UserError(
|
||||||
"More than one dependency target found in `%s': %s"
|
"More than one dependency target found in `%s': %s"
|
||||||
% (filename, targets))
|
% (filename, targets))
|
||||||
for target, depends in tdlist:
|
for target, depends in tdlist:
|
||||||
|
@ -1722,7 +1777,7 @@ class Base(SubstitutionEnvironment):
|
||||||
dk = [x for x in dk if x not in val]
|
dk = [x for x in dk if x not in val]
|
||||||
self._dict[key] = [val] + dk
|
self._dict[key] = [val] + dk
|
||||||
else:
|
else:
|
||||||
if not val in dk:
|
if val not in dk:
|
||||||
self._dict[key] = [val] + dk
|
self._dict[key] = [val] + dk
|
||||||
else:
|
else:
|
||||||
if delete_existing:
|
if delete_existing:
|
||||||
|
@ -1833,7 +1888,7 @@ class Base(SubstitutionEnvironment):
|
||||||
uniq = {}
|
uniq = {}
|
||||||
for executor in [n.get_executor() for n in nodes]:
|
for executor in [n.get_executor() for n in nodes]:
|
||||||
uniq[executor] = 1
|
uniq[executor] = 1
|
||||||
for executor in list(uniq.keys()):
|
for executor in uniq.keys():
|
||||||
executor.add_pre_action(action)
|
executor.add_pre_action(action)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
@ -1843,7 +1898,7 @@ class Base(SubstitutionEnvironment):
|
||||||
uniq = {}
|
uniq = {}
|
||||||
for executor in [n.get_executor() for n in nodes]:
|
for executor in [n.get_executor() for n in nodes]:
|
||||||
uniq[executor] = 1
|
uniq[executor] = 1
|
||||||
for executor in list(uniq.keys()):
|
for executor in uniq.keys():
|
||||||
executor.add_post_action(action)
|
executor.add_post_action(action)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
@ -1908,14 +1963,6 @@ class Base(SubstitutionEnvironment):
|
||||||
t.set_always_build()
|
t.set_always_build()
|
||||||
return tlist
|
return tlist
|
||||||
|
|
||||||
def BuildDir(self, *args, **kw):
|
|
||||||
msg = """BuildDir() and the build_dir keyword have been deprecated;\n\tuse VariantDir() and the variant_dir keyword instead."""
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg)
|
|
||||||
if 'build_dir' in kw:
|
|
||||||
kw['variant_dir'] = kw['build_dir']
|
|
||||||
del kw['build_dir']
|
|
||||||
return self.VariantDir(*args, **kw)
|
|
||||||
|
|
||||||
def Builder(self, **kw):
|
def Builder(self, **kw):
|
||||||
nkw = self.subst_kw(kw)
|
nkw = self.subst_kw(kw)
|
||||||
return SCons.Builder.Builder(**nkw)
|
return SCons.Builder.Builder(**nkw)
|
||||||
|
@ -1954,13 +2001,42 @@ class Base(SubstitutionEnvironment):
|
||||||
be any type that the Builder constructor will accept
|
be any type that the Builder constructor will accept
|
||||||
for an action."""
|
for an action."""
|
||||||
bkw = {
|
bkw = {
|
||||||
'action' : action,
|
'action': action,
|
||||||
'target_factory' : self.fs.Entry,
|
'target_factory': self.fs.Entry,
|
||||||
'source_factory' : self.fs.Entry,
|
'source_factory': self.fs.Entry,
|
||||||
}
|
}
|
||||||
try: bkw['source_scanner'] = kw['source_scanner']
|
# source scanner
|
||||||
except KeyError: pass
|
try:
|
||||||
else: del kw['source_scanner']
|
bkw['source_scanner'] = kw['source_scanner']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del kw['source_scanner']
|
||||||
|
|
||||||
|
# target scanner
|
||||||
|
try:
|
||||||
|
bkw['target_scanner'] = kw['target_scanner']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del kw['target_scanner']
|
||||||
|
|
||||||
|
# source factory
|
||||||
|
try:
|
||||||
|
bkw['source_factory'] = kw['source_factory']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del kw['source_factory']
|
||||||
|
|
||||||
|
# target factory
|
||||||
|
try:
|
||||||
|
bkw['target_factory'] = kw['target_factory']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del kw['target_factory']
|
||||||
|
|
||||||
bld = SCons.Builder.Builder(**bkw)
|
bld = SCons.Builder.Builder(**bkw)
|
||||||
return bld(self, target, source, **kw)
|
return bld(self, target, source, **kw)
|
||||||
|
|
||||||
|
@ -2029,7 +2105,7 @@ class Base(SubstitutionEnvironment):
|
||||||
"""
|
"""
|
||||||
action = self.Action(action, *args, **kw)
|
action = self.Action(action, *args, **kw)
|
||||||
result = action([], [], self)
|
result = action([], [], self)
|
||||||
if isinstance(result, SCons.Errors.BuildError):
|
if isinstance(result, BuildError):
|
||||||
errstr = result.errstr
|
errstr = result.errstr
|
||||||
if result.filename:
|
if result.filename:
|
||||||
errstr = result.filename + ': ' + errstr
|
errstr = result.filename + ': ' + errstr
|
||||||
|
@ -2149,7 +2225,7 @@ class Base(SubstitutionEnvironment):
|
||||||
|
|
||||||
for side_effect in side_effects:
|
for side_effect in side_effects:
|
||||||
if side_effect.multiple_side_effect_has_builder():
|
if side_effect.multiple_side_effect_has_builder():
|
||||||
raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
|
raise UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
|
||||||
side_effect.add_source(targets)
|
side_effect.add_source(targets)
|
||||||
side_effect.side_effect = 1
|
side_effect.side_effect = 1
|
||||||
self.Precious(side_effect)
|
self.Precious(side_effect)
|
||||||
|
@ -2157,34 +2233,6 @@ class Base(SubstitutionEnvironment):
|
||||||
target.side_effects.append(side_effect)
|
target.side_effects.append(side_effect)
|
||||||
return side_effects
|
return side_effects
|
||||||
|
|
||||||
def SourceCode(self, entry, builder):
|
|
||||||
"""Arrange for a source code builder for (part of) a tree."""
|
|
||||||
msg = """SourceCode() has been deprecated and there is no replacement.
|
|
||||||
\tIf you need this function, please contact scons-dev@scons.org"""
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceCodeWarning, msg)
|
|
||||||
entries = self.arg2nodes(entry, self.fs.Entry)
|
|
||||||
for entry in entries:
|
|
||||||
entry.set_src_builder(builder)
|
|
||||||
return entries
|
|
||||||
|
|
||||||
def SourceSignatures(self, type):
|
|
||||||
global _warn_source_signatures_deprecated
|
|
||||||
if _warn_source_signatures_deprecated:
|
|
||||||
msg = "The env.SourceSignatures() method is deprecated;\n" + \
|
|
||||||
"\tconvert your build to use the env.Decider() method instead."
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg)
|
|
||||||
_warn_source_signatures_deprecated = False
|
|
||||||
type = self.subst(type)
|
|
||||||
self.src_sig_type = type
|
|
||||||
if type == 'MD5':
|
|
||||||
if not SCons.Util.md5:
|
|
||||||
raise UserError("MD5 signatures are not available in this version of Python.")
|
|
||||||
self.decide_source = self._changed_content
|
|
||||||
elif type == 'timestamp':
|
|
||||||
self.decide_source = self._changed_timestamp_match
|
|
||||||
else:
|
|
||||||
raise UserError("Unknown source signature type '%s'" % type)
|
|
||||||
|
|
||||||
def Split(self, arg):
|
def Split(self, arg):
|
||||||
"""This function converts a string or list into a list of strings
|
"""This function converts a string or list into a list of strings
|
||||||
or Nodes. This makes things easier for users by allowing files to
|
or Nodes. This makes things easier for users by allowing files to
|
||||||
|
@ -2206,32 +2254,10 @@ class Base(SubstitutionEnvironment):
|
||||||
else:
|
else:
|
||||||
return [self.subst(arg)]
|
return [self.subst(arg)]
|
||||||
|
|
||||||
def TargetSignatures(self, type):
|
def Value(self, value, built_value=None, name=None):
|
||||||
global _warn_target_signatures_deprecated
|
|
||||||
if _warn_target_signatures_deprecated:
|
|
||||||
msg = "The env.TargetSignatures() method is deprecated;\n" + \
|
|
||||||
"\tconvert your build to use the env.Decider() method instead."
|
|
||||||
SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg)
|
|
||||||
_warn_target_signatures_deprecated = False
|
|
||||||
type = self.subst(type)
|
|
||||||
self.tgt_sig_type = type
|
|
||||||
if type in ('MD5', 'content'):
|
|
||||||
if not SCons.Util.md5:
|
|
||||||
raise UserError("MD5 signatures are not available in this version of Python.")
|
|
||||||
self.decide_target = self._changed_content
|
|
||||||
elif type == 'timestamp':
|
|
||||||
self.decide_target = self._changed_timestamp_match
|
|
||||||
elif type == 'build':
|
|
||||||
self.decide_target = self._changed_build
|
|
||||||
elif type == 'source':
|
|
||||||
self.decide_target = self._changed_source
|
|
||||||
else:
|
|
||||||
raise UserError("Unknown target signature type '%s'"%type)
|
|
||||||
|
|
||||||
def Value(self, value, built_value=None):
|
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
return SCons.Node.Python.Value(value, built_value)
|
return SCons.Node.Python.ValueWithMemo(value, built_value, name)
|
||||||
|
|
||||||
def VariantDir(self, variant_dir, src_dir, duplicate=1):
|
def VariantDir(self, variant_dir, src_dir, duplicate=1):
|
||||||
variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0]
|
variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0]
|
||||||
|
@ -2255,10 +2281,10 @@ class Base(SubstitutionEnvironment):
|
||||||
build_source(node.all_children())
|
build_source(node.all_children())
|
||||||
|
|
||||||
def final_source(node):
|
def final_source(node):
|
||||||
while (node != node.srcnode()):
|
while node != node.srcnode():
|
||||||
node = node.srcnode()
|
node = node.srcnode()
|
||||||
return node
|
return node
|
||||||
sources = list(map( final_source, sources ));
|
sources = list(map(final_source, sources))
|
||||||
# remove duplicates
|
# remove duplicates
|
||||||
return list(set(sources))
|
return list(set(sources))
|
||||||
|
|
||||||
|
@ -2299,7 +2325,20 @@ class OverrideEnvironment(Base):
|
||||||
|
|
||||||
# Methods that make this class act like a proxy.
|
# Methods that make this class act like a proxy.
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.__dict__['__subject'], name)
|
attr = getattr(self.__dict__['__subject'], name)
|
||||||
|
# Here we check if attr is one of the Wrapper classes. For
|
||||||
|
# example when a pseudo-builder is being called from an
|
||||||
|
# OverrideEnvironment.
|
||||||
|
#
|
||||||
|
# These wrappers when they're constructed capture the
|
||||||
|
# Environment they are being constructed with and so will not
|
||||||
|
# have access to overrided values. So we rebuild them with the
|
||||||
|
# OverrideEnvironment so they have access to overrided values.
|
||||||
|
if isinstance(attr, (MethodWrapper, BuilderWrapper)):
|
||||||
|
return attr.clone(self)
|
||||||
|
else:
|
||||||
|
return attr
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
setattr(self.__dict__['__subject'], name, value)
|
setattr(self.__dict__['__subject'], name, value)
|
||||||
|
|
||||||
|
@ -2309,10 +2348,12 @@ class OverrideEnvironment(Base):
|
||||||
return self.__dict__['overrides'][key]
|
return self.__dict__['overrides'][key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return self.__dict__['__subject'].__getitem__(key)
|
return self.__dict__['__subject'].__getitem__(key)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
if not is_valid_construction_var(key):
|
if not is_valid_construction_var(key):
|
||||||
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
|
raise UserError("Illegal construction variable `%s'" % key)
|
||||||
self.__dict__['overrides'][key] = value
|
self.__dict__['overrides'][key] = value
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
try:
|
try:
|
||||||
del self.__dict__['overrides'][key]
|
del self.__dict__['overrides'][key]
|
||||||
|
@ -2327,30 +2368,43 @@ class OverrideEnvironment(Base):
|
||||||
raise
|
raise
|
||||||
result = None
|
result = None
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
"""Emulates the get() method of dictionaries."""
|
"""Emulates the get() method of dictionaries."""
|
||||||
try:
|
try:
|
||||||
return self.__dict__['overrides'][key]
|
return self.__dict__['overrides'][key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return self.__dict__['__subject'].get(key, default)
|
return self.__dict__['__subject'].get(key, default)
|
||||||
|
|
||||||
def has_key(self, key):
|
def has_key(self, key):
|
||||||
|
"""Emulates the has_key() method of dictionaries."""
|
||||||
try:
|
try:
|
||||||
self.__dict__['overrides'][key]
|
self.__dict__['overrides'][key]
|
||||||
return 1
|
return 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return key in self.__dict__['__subject']
|
return key in self.__dict__['__subject']
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
if self.__dict__['overrides'].__contains__(key):
|
if self.__dict__['overrides'].__contains__(key):
|
||||||
return 1
|
return 1
|
||||||
return self.__dict__['__subject'].__contains__(key)
|
return self.__dict__['__subject'].__contains__(key)
|
||||||
|
|
||||||
def Dictionary(self):
|
def Dictionary(self):
|
||||||
"""Emulates the items() method of dictionaries."""
|
|
||||||
d = self.__dict__['__subject'].Dictionary().copy()
|
d = self.__dict__['__subject'].Dictionary().copy()
|
||||||
d.update(self.__dict__['overrides'])
|
d.update(self.__dict__['overrides'])
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
"""Emulates the items() method of dictionaries."""
|
"""Emulates the items() method of dictionaries."""
|
||||||
return list(self.Dictionary().items())
|
return self.Dictionary().items()
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
"""Emulates the keys() method of dictionaries."""
|
||||||
|
return self.Dictionary().keys()
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
"""Emulates the values() method of dictionaries."""
|
||||||
|
return self.Dictionary().values()
|
||||||
|
|
||||||
# Overridden private construction environment methods.
|
# Overridden private construction environment methods.
|
||||||
def _update(self, dict):
|
def _update(self, dict):
|
||||||
|
@ -2372,6 +2426,7 @@ class OverrideEnvironment(Base):
|
||||||
kw = copy_non_reserved_keywords(kw)
|
kw = copy_non_reserved_keywords(kw)
|
||||||
self.__dict__['overrides'].update(semi_deepcopy(kw))
|
self.__dict__['overrides'].update(semi_deepcopy(kw))
|
||||||
|
|
||||||
|
|
||||||
# The entry point that will be used by the external world
|
# The entry point that will be used by the external world
|
||||||
# to refer to a construction environment. This allows the wrapper
|
# to refer to a construction environment. This allows the wrapper
|
||||||
# interface to extend a construction environment for its own purposes
|
# interface to extend a construction environment for its own purposes
|
97
scons/scons-local-4.0.1/SCons/EnvironmentValues.py
Normal file
97
scons/scons-local-4.0.1/SCons/EnvironmentValues.py
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
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)
|
||||||
|
pass
|
||||||
|
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])
|
16
scons/scons-local-4.0.1/SCons/EnvironmentValuesTest.py
Normal file
16
scons/scons-local-4.0.1/SCons/EnvironmentValuesTest.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
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,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
|
||||||
|
@ -28,64 +28,60 @@ and user errors in SCons.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Errors.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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 +91,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 +120,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 +134,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):
|
||||||
|
@ -176,28 +173,27 @@ def convert_to_BuildError(status, exc_info=None):
|
||||||
filename = status.filename
|
filename = status.filename
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
filename = None
|
filename = None
|
||||||
|
|
||||||
buildError = BuildError(
|
buildError = BuildError(
|
||||||
errstr=status.args[0],
|
errstr=status.args[0],
|
||||||
status=status.errno,
|
status=status.errno,
|
||||||
exitstatus=2,
|
exitstatus=2,
|
||||||
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)
|
||||||
|
@ -217,7 +213,7 @@ def convert_to_BuildError(status, exc_info=None):
|
||||||
errstr="Error %s" % status,
|
errstr="Error %s" % status,
|
||||||
status=status,
|
status=status,
|
||||||
exitstatus=2)
|
exitstatus=2)
|
||||||
|
|
||||||
#import sys
|
#import sys
|
||||||
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
|
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
|
||||||
return buildError
|
return buildError
|
|
@ -6,7 +6,7 @@ Nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -26,9 +26,7 @@ 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Executor.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
@ -36,15 +34,16 @@ 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."""
|
||||||
|
|
||||||
__slots__ = ('targets',
|
__slots__ = ('targets',
|
||||||
'sources')
|
'sources')
|
||||||
|
|
||||||
def __init__(self, targets=[], sources=[]):
|
def __init__(self, targets=[], sources=[]):
|
||||||
self.targets = targets
|
self.targets = targets
|
||||||
self.sources = sources
|
self.sources = sources
|
||||||
|
@ -71,7 +70,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 +79,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,13 +126,13 @@ 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(
|
||||||
errstr=msg,
|
errstr=msg,
|
||||||
node=obj.batches[0].targets,
|
node=obj.batches[0].targets,
|
||||||
executor=obj,
|
executor=obj,
|
||||||
action=act)
|
action=act)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
@ -155,7 +154,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 +449,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 +571,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 +587,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.
|
||||||
|
|
||||||
|
@ -595,7 +595,7 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
|
||||||
disassociate Builders from Nodes entirely, so we're not
|
disassociate Builders from Nodes entirely, so we're not
|
||||||
going to worry about unit tests for this--at least for now.
|
going to worry about unit tests for this--at least for now.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ('pre_actions',
|
__slots__ = ('pre_actions',
|
||||||
'post_actions',
|
'post_actions',
|
||||||
'env',
|
'env',
|
||||||
|
@ -611,9 +611,10 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
|
||||||
'action_list',
|
'action_list',
|
||||||
'_do_execute',
|
'_do_execute',
|
||||||
'_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()
|
||||||
|
@ -647,7 +648,7 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
|
||||||
"""Morph this Null executor to a real Executor object."""
|
"""Morph this Null executor to a real Executor object."""
|
||||||
batches = self.batches
|
batches = self.batches
|
||||||
self.__class__ = Executor
|
self.__class__ = Executor
|
||||||
self.__init__([])
|
self.__init__([])
|
||||||
self.batches = batches
|
self.batches = batches
|
||||||
|
|
||||||
# The following methods require morphing this Null Executor to a
|
# The following methods require morphing this Null Executor to a
|
|
@ -7,7 +7,7 @@ stop, and wait on jobs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ stop, and wait on jobs.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Job.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.compat
|
import SCons.compat
|
||||||
|
|
||||||
|
@ -52,18 +52,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.
|
||||||
"""
|
"""
|
||||||
|
@ -87,7 +87,7 @@ class Jobs(object):
|
||||||
stack_size = explicit_stack_size
|
stack_size = explicit_stack_size
|
||||||
if stack_size is None:
|
if stack_size is None:
|
||||||
stack_size = default_stack_size
|
stack_size = default_stack_size
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.job = Parallel(taskmaster, num, stack_size)
|
self.job = Parallel(taskmaster, num, stack_size)
|
||||||
self.num_jobs = num
|
self.num_jobs = num
|
||||||
|
@ -163,7 +163,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.
|
||||||
|
@ -172,14 +172,14 @@ class Serial(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, taskmaster):
|
def __init__(self, taskmaster):
|
||||||
"""Create a new serial job given a taskmaster.
|
"""Create a new serial job given a taskmaster.
|
||||||
|
|
||||||
The taskmaster's next_task() method should return the next task
|
The taskmaster's next_task() method should return the next task
|
||||||
that needs to be executed, or None if there are no more tasks. The
|
that needs to be executed, or None if there are no more tasks. The
|
||||||
taskmaster's executed() method will be called for each task when it
|
taskmaster's executed() method will be called for each task when it
|
||||||
is successfully executed, or failed() will be called if it failed to
|
is successfully executed, or failed() will be called if it failed to
|
||||||
execute (e.g. execute() raised an exception)."""
|
execute (e.g. execute() raised an exception)."""
|
||||||
|
|
||||||
self.taskmaster = taskmaster
|
self.taskmaster = taskmaster
|
||||||
self.interrupted = InterruptState()
|
self.interrupted = InterruptState()
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ class Serial(object):
|
||||||
and executing them, and return when there are no more tasks. If a task
|
and executing them, and return when there are no more tasks. If a task
|
||||||
fails to execute (i.e. execute() raises an exception), then the job will
|
fails to execute (i.e. execute() raises an exception), then the job will
|
||||||
stop."""
|
stop."""
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
task = self.taskmaster.next_task()
|
task = self.taskmaster.next_task()
|
||||||
|
|
||||||
|
@ -199,7 +199,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,12 +264,12 @@ 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):
|
||||||
"""Create the request and reply queues, and 'num' worker threads.
|
"""Create the request and reply queues, and 'num' worker threads.
|
||||||
|
|
||||||
One must specify the stack size of the worker threads. The
|
One must specify the stack size of the worker threads. The
|
||||||
stack size is specified in kilobytes.
|
stack size is specified in kilobytes.
|
||||||
"""
|
"""
|
||||||
|
@ -277,11 +277,11 @@ else:
|
||||||
self.resultsQueue = queue.Queue(0)
|
self.resultsQueue = queue.Queue(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
prev_size = threading.stack_size(stack_size*1024)
|
prev_size = threading.stack_size(stack_size*1024)
|
||||||
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)
|
||||||
|
@ -322,7 +322,7 @@ else:
|
||||||
self.requestQueue.put(None)
|
self.requestQueue.put(None)
|
||||||
|
|
||||||
# Wait for all of the workers to terminate.
|
# Wait for all of the workers to terminate.
|
||||||
#
|
#
|
||||||
# If we don't do this, later Python versions (2.4, 2.5) often
|
# If we don't do this, later Python versions (2.4, 2.5) often
|
||||||
# seem to raise exceptions during shutdown. This happens
|
# seem to raise exceptions during shutdown. This happens
|
||||||
# in requestQueue.get(), as an assertion failure that
|
# in requestQueue.get(), as an assertion failure that
|
||||||
|
@ -338,8 +338,8 @@ 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.
|
||||||
|
|
||||||
This class is thread safe.
|
This class is thread safe.
|
||||||
|
@ -373,7 +373,7 @@ else:
|
||||||
an exception), then the job will stop."""
|
an exception), then the job will stop."""
|
||||||
|
|
||||||
jobs = 0
|
jobs = 0
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# Start up as many available tasks as we're
|
# Start up as many available tasks as we're
|
||||||
# allowed to.
|
# allowed to.
|
|
@ -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,9 +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.
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Memoize.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
__doc__ = """Memoizer
|
__doc__ = """Memoizer
|
||||||
|
|
||||||
|
@ -106,7 +104,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.
|
||||||
|
|
|
@ -8,7 +8,7 @@ This creates a hash of global Aliases (dummy targets).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,13 +30,14 @@ This creates a hash of global Aliases (dummy targets).
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/Alias.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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 +167,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
|
||||||
|
|
|
@ -11,7 +11,7 @@ that can be used by scripts or modules looking for the canonical default.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,9 +31,7 @@ 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/FS.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import os
|
import os
|
||||||
|
@ -43,6 +41,8 @@ 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
|
||||||
|
@ -53,12 +53,15 @@ 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
|
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 +77,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 +138,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 +281,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 +291,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 +339,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 +367,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 +383,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
|
||||||
|
@ -463,7 +479,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 +530,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 +698,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 +731,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()
|
||||||
|
@ -938,14 +985,14 @@ 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 +1094,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):
|
||||||
|
@ -1389,10 +1437,10 @@ class FS(LocalFS):
|
||||||
if not isinstance(d, SCons.Node.Node):
|
if not isinstance(d, SCons.Node.Node):
|
||||||
d = self.Dir(d)
|
d = self.Dir(d)
|
||||||
self.Top.addRepository(d)
|
self.Top.addRepository(d)
|
||||||
|
|
||||||
def PyPackageDir(self, modulename):
|
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
|
||||||
Linux: /usr/lib/scons
|
Linux: /usr/lib/scons
|
||||||
|
@ -1400,22 +1448,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 +1558,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 +1619,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 +1630,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 +1696,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 +1736,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 +1870,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 +2268,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 +2310,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 +2340,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 +2476,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 +2498,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
|
||||||
|
@ -2666,11 +2733,10 @@ class File(Base):
|
||||||
Compute and return the MD5 hash for this file.
|
Compute and return the MD5 hash for this file.
|
||||||
"""
|
"""
|
||||||
if not self.rexists():
|
if not self.rexists():
|
||||||
return SCons.Util.MD5signature('')
|
return MD5signature('')
|
||||||
fname = self.rfile().get_abspath()
|
fname = self.rfile().get_abspath()
|
||||||
try:
|
try:
|
||||||
cs = SCons.Util.MD5filesignature(fname,
|
cs = MD5filesignature(fname, chunksize=File.md5_chunksize * 1024)
|
||||||
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
|
||||||
|
@ -2971,7 +3037,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 +3125,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:
|
||||||
|
@ -3153,7 +3222,7 @@ class File(Base):
|
||||||
if csig is None:
|
if csig is None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.get_size() < SCons.Node.FS.File.md5_chunksize:
|
if self.get_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 +3294,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 +3527,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 +3550,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 +3577,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 +3623,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 * 1024)
|
||||||
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 +3643,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 +3655,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 +3666,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 +3685,7 @@ def get_default_fs():
|
||||||
default_fs = FS()
|
default_fs = FS()
|
||||||
return default_fs
|
return default_fs
|
||||||
|
|
||||||
class FileFinder(object):
|
class FileFinder:
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -3472,7 +3758,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)
|
|
@ -5,7 +5,7 @@ Python nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,10 +27,13 @@ Python nodes.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Node/Python.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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 +41,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 +79,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 +88,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 +96,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)
|
||||||
|
|
||||||
|
@ -137,6 +148,10 @@ class Value(SCons.Node.Node):
|
||||||
return contents
|
return contents
|
||||||
|
|
||||||
def get_contents(self):
|
def get_contents(self):
|
||||||
|
"""
|
||||||
|
Get contents for signature calculations.
|
||||||
|
:return: bytes
|
||||||
|
"""
|
||||||
text_contents = self.get_text_contents()
|
text_contents = self.get_text_contents()
|
||||||
try:
|
try:
|
||||||
return text_contents.encode()
|
return text_contents.encode()
|
||||||
|
@ -144,7 +159,6 @@ class Value(SCons.Node.Node):
|
||||||
# Already encoded as python2 str are bytes
|
# Already encoded as python2 str are bytes
|
||||||
return text_contents
|
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:
|
||||||
|
@ -155,15 +169,45 @@ class Value(SCons.Node.Node):
|
||||||
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
|
|
@ -19,10 +19,8 @@ be able to depend on any other type of "thing."
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -43,21 +41,28 @@ 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
import os
|
||||||
import collections
|
import collections
|
||||||
import copy
|
import copy
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
try:
|
||||||
|
from itertools import zip_longest
|
||||||
|
except ImportError:
|
||||||
|
from itertools import izip_longest as zip_longest
|
||||||
|
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
from SCons.Debug import logInstanceCreation
|
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.Util import MD5signature
|
||||||
|
|
||||||
from SCons.Debug import Trace
|
from SCons.Debug import Trace
|
||||||
|
|
||||||
from SCons.compat import with_metaclass, NoSlotsPyPy
|
from SCons.compat import NoSlotsPyPy
|
||||||
|
|
||||||
print_duplicate = 0
|
print_duplicate = 0
|
||||||
|
|
||||||
|
@ -102,9 +107,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 +147,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 +164,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 +258,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 +278,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 +356,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 +395,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 +451,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 +514,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 +562,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 +616,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 +683,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 +778,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:
|
||||||
|
@ -912,6 +949,10 @@ 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 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 +1138,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 +1173,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 +1185,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 +1211,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 +1257,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 +1496,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 +1650,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 +1719,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,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/PathList.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__doc__ = """SCons.PathList
|
__doc__ = """SCons.PathList
|
||||||
|
|
||||||
|
@ -66,7 +66,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 +143,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.
|
||||||
|
|
|
@ -20,7 +20,7 @@ their own platform definition.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -41,13 +41,11 @@ their own platform definition.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Platform/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import SCons.compat
|
import SCons.compat
|
||||||
|
|
||||||
import imp
|
import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -60,8 +58,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 +85,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 +99,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 +111,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 +129,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
|
||||||
|
@ -185,21 +194,27 @@ class TempFileMunge(object):
|
||||||
node = target[0] if SCons.Util.is_List(target) else target
|
node = target[0] if SCons.Util.is_List(target) else target
|
||||||
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
|
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
|
||||||
if node is not None else None
|
if node is not None else None
|
||||||
if cmdlist is not None :
|
if cmdlist is not None:
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
# We do a normpath because mktemp() has what appears to be
|
# 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 +232,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,8 +256,9 @@ 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)
|
||||||
|
|
||||||
# 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.
|
||||||
|
@ -252,6 +270,23 @@ class TempFileMunge(object):
|
||||||
pass
|
pass
|
||||||
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,4 +1,4 @@
|
||||||
"""engine.SCons.Platform.aix
|
"""SCons.Platform.aix
|
||||||
|
|
||||||
Platform-specific initialization for IBM AIX systems.
|
Platform-specific initialization for IBM AIX systems.
|
||||||
|
|
||||||
|
@ -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/Platform/aix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -55,6 +55,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
|
|
@ -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,11 +30,20 @@ selection method.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Platform/cygwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
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,4 +1,4 @@
|
||||||
"""engine.SCons.Platform.darwin
|
"""SCons.Platform.darwin
|
||||||
|
|
||||||
Platform-specific initialization for Mac OS X systems.
|
Platform-specific initialization for Mac OS X systems.
|
||||||
|
|
||||||
|
@ -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/Platform/darwin.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from . import posix
|
from . import posix
|
||||||
import os
|
import os
|
||||||
|
@ -56,12 +56,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,4 +1,4 @@
|
||||||
"""engine.SCons.Platform.hpux
|
"""SCons.Platform.hpux
|
||||||
|
|
||||||
Platform-specific initialization for HP-UX systems.
|
Platform-specific initialization for HP-UX systems.
|
||||||
|
|
||||||
|
@ -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/Platform/hpux.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from . import posix
|
from . import posix
|
||||||
|
|
|
@ -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/Platform/irix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from . import posix
|
from . import posix
|
||||||
|
|
39
scons/scons-local-4.0.1/SCons/Platform/mingw.py
Normal file
39
scons/scons-local-4.0.1/SCons/Platform/mingw.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
"""SCons.Platform.mingw
|
||||||
|
|
||||||
|
Platform-specific initialization for the MinGW system.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#
|
||||||
|
# __COPYRIGHT__
|
||||||
|
#
|
||||||
|
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
MINGW_DEFAULT_PATHS = []
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
MINGW_DEFAULT_PATHS = [
|
||||||
|
r'C:\msys64',
|
||||||
|
r'C:\msys'
|
||||||
|
]
|
|
@ -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/Platform/os2.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
from . import win32
|
from . import win32
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
|
@ -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/Platform/posix.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
|
@ -41,6 +41,8 @@ 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 +50,7 @@ exitvalmap = {
|
||||||
}
|
}
|
||||||
|
|
||||||
def escape(arg):
|
def escape(arg):
|
||||||
"escape shell special characters"
|
"""escape shell special characters"""
|
||||||
slash = '\\'
|
slash = '\\'
|
||||||
special = '"$'
|
special = '"$'
|
||||||
|
|
||||||
|
@ -119,6 +121,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,4 +1,4 @@
|
||||||
"""engine.SCons.Platform.sunos
|
"""SCons.Platform.sunos
|
||||||
|
|
||||||
Platform-specific initialization for Sun systems.
|
Platform-specific initialization for Sun systems.
|
||||||
|
|
||||||
|
@ -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/Platform/sunos.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from . import posix
|
from . import posix
|
||||||
|
|
120
scons/scons-local-4.0.1/SCons/Platform/virtualenv.py
Normal file
120
scons/scons-local-4.0.1/SCons/Platform/virtualenv.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
"""SCons.Platform.virtualenv
|
||||||
|
|
||||||
|
Support for virtualenv.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#
|
||||||
|
# __COPYRIGHT__
|
||||||
|
#
|
||||||
|
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
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:
|
|
@ -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/Platform/win32.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -39,16 +39,18 @@ 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
|
||||||
|
|
||||||
|
CHOCO_DEFAULT_PATH = [
|
||||||
|
r'C:\ProgramData\chocolatey\bin'
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import msvcrt
|
import msvcrt
|
||||||
import win32api
|
import win32api
|
||||||
import win32con
|
import win32con
|
||||||
|
|
||||||
msvcrt.get_osfhandle
|
|
||||||
win32api.SetHandleInformation
|
|
||||||
win32con.HANDLE_FLAG_INHERIT
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
parallel_msg = \
|
parallel_msg = \
|
||||||
"you do not seem to have the pywin32 extensions installed;\n" + \
|
"you do not seem to have the pywin32 extensions installed;\n" + \
|
||||||
|
@ -60,38 +62,6 @@ except AttributeError:
|
||||||
else:
|
else:
|
||||||
parallel_msg = None
|
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 +102,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 +138,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 +267,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
|
||||||
|
|
||||||
|
@ -322,7 +298,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 +412,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 +438,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
|
|
@ -12,7 +12,7 @@ libraries are installed, if some command line options are supported etc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,12 +33,11 @@ libraries are installed, if some command line options are supported etc.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/SConf.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import SCons.compat
|
import SCons.compat
|
||||||
|
|
||||||
|
import atexit
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -56,6 +55,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 +65,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 +98,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,8 +132,8 @@ 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.Warning):
|
||||||
|
@ -161,11 +161,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 +190,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 +249,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 +273,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 +283,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 +327,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 +375,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 +397,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 +470,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):
|
||||||
|
@ -503,6 +525,20 @@ class SConfBase(object):
|
||||||
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)
|
||||||
|
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 +577,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 +595,30 @@ 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)
|
||||||
|
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)
|
||||||
|
textFileNode = self.env.SConfSourceBuilder(target=textFile,
|
||||||
|
source=sourcetext)
|
||||||
|
nodesToBeBuilt.extend(textFileNode)
|
||||||
|
|
||||||
|
source = textFile
|
||||||
|
target = textFile.File(f + "SConfActionsContentDummyTarget")
|
||||||
|
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 +627,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 +637,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 +655,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 +682,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 +693,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 +717,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 ):
|
||||||
|
@ -705,11 +751,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 +790,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 +885,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 +1059,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 +1086,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):
|
|
@ -5,7 +5,7 @@ Writing and reading information to the .sconsign file or files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -26,10 +26,7 @@ Writing and reading information to the .sconsign file or 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/SConsign.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
import SCons.compat
|
import SCons.compat
|
||||||
|
|
||||||
|
@ -76,7 +73,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 +120,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.
|
||||||
|
@ -165,7 +163,7 @@ class SConsignEntry(object):
|
||||||
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 +332,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 +397,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 +420,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,11 @@
|
||||||
"""SCons.Scanner.C
|
"""SCons.Scanner.C
|
||||||
|
|
||||||
This module implements the dependency scanner for C/C++ code.
|
This module implements the dependency scanner for C/C++ code.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ This module implements the dependency scanner for C/C++ code.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/C.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
@ -80,7 +80,7 @@ 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.
|
||||||
|
|
||||||
|
@ -124,6 +124,100 @@ def CScanner():
|
||||||
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")')
|
'^[ \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
|
|
@ -8,7 +8,7 @@ Coded by Andy Friesen
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ Coded by Andy Friesen
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/D.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
||||||
|
|
||||||
|
@ -46,7 +46,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,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/Scanner/Dir.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
|
@ -5,7 +5,7 @@ This module implements the dependency scanner for Fortran code.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -26,7 +26,7 @@ This module implements the dependency scanner for Fortran code.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/Fortran.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -78,7 +78,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 +187,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 +275,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 +285,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",
|
|
@ -6,7 +6,7 @@ Definition Language) files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -28,7 +28,7 @@ Definition Language) files.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/IDL.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
||||||
import SCons.Scanner
|
import SCons.Scanner
|
|
@ -5,7 +5,7 @@ This module implements the dependency scanner for LaTeX code.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ This module implements the dependency scanner for LaTeX code.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/LaTeX.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
@ -42,7 +42,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 +77,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.
|
||||||
|
@ -128,8 +128,8 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
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
|
||||||
of the keyword for the inclusion ("include", "includegraphics",
|
of the keyword for the inclusion ("include", "includegraphics",
|
||||||
"input", or "bibliography"), and then the file name itself.
|
"input", or "bibliography"), and then the file name itself.
|
||||||
Based on a quick look at LaTeX documentation, it seems that we
|
Based on a quick look at LaTeX documentation, it seems that we
|
||||||
should append .tex suffix for the "include" keywords, append .tex if
|
should append .tex suffix for the "include" keywords, append .tex if
|
||||||
there is no extension for the "input" keyword, and need to add .bib
|
there is no extension for the "input" keyword, and need to add .bib
|
||||||
for the "bibliography" keyword that does not accept extensions by itself.
|
for the "bibliography" keyword that does not accept extensions by itself.
|
||||||
|
@ -137,7 +137,7 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
Finally, if there is no extension for an "includegraphics" keyword
|
Finally, if there is no extension for an "includegraphics" keyword
|
||||||
latex will append .ps or .eps to find the file, while pdftex may use .pdf,
|
latex will append .ps or .eps to find the file, while pdftex may use .pdf,
|
||||||
.jpg, .tif, .mps, or .png.
|
.jpg, .tif, .mps, or .png.
|
||||||
|
|
||||||
The actual subset and search order may be altered by
|
The actual subset and search order may be altered by
|
||||||
DeclareGraphicsExtensions command. This complication is ignored.
|
DeclareGraphicsExtensions command. This complication is ignored.
|
||||||
The default order corresponds to experimentation with teTeX::
|
The default order corresponds to experimentation with teTeX::
|
||||||
|
@ -179,15 +179,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 +211,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 +239,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 +325,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 +340,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 +364,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
|
||||||
|
|
||||||
|
@ -386,8 +378,8 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
directory of the main file just as latex does"""
|
directory of the main file just as latex does"""
|
||||||
|
|
||||||
path_dict = dict(list(path))
|
path_dict = dict(list(path))
|
||||||
|
|
||||||
queue = []
|
queue = []
|
||||||
queue.extend( self.scan(node) )
|
queue.extend( self.scan(node) )
|
||||||
seen = {}
|
seen = {}
|
||||||
|
|
||||||
|
@ -402,7 +394,7 @@ class LaTeX(SCons.Scanner.Base):
|
||||||
source_dir = node.get_dir()
|
source_dir = node.get_dir()
|
||||||
#for include in includes:
|
#for include in includes:
|
||||||
while queue:
|
while queue:
|
||||||
|
|
||||||
include = queue.pop()
|
include = queue.pop()
|
||||||
inc_type, inc_subdir, inc_filename = include
|
inc_type, inc_subdir, inc_filename = include
|
||||||
|
|
|
@ -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/Scanner/Prog.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
import SCons.Node.FS
|
import SCons.Node.FS
|
171
scons/scons-local-4.0.1/SCons/Scanner/Python.py
Normal file
171
scons/scons-local-4.0.1/SCons/Scanner/Python.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
"""SCons.Scanner.Python
|
||||||
|
|
||||||
|
This module implements the 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#
|
||||||
|
# __COPYRIGHT__
|
||||||
|
#
|
||||||
|
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
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:
|
|
@ -6,7 +6,7 @@ Definition Language) files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -28,7 +28,7 @@ Definition Language) files.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/RC.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ def RCScan():
|
||||||
"""Return a prototype Scanner instance for scanning RC source files"""
|
"""Return a prototype Scanner instance for scanning RC source files"""
|
||||||
|
|
||||||
res_re= r'^(?:\s*#\s*(?:include)|' \
|
res_re= r'^(?:\s*#\s*(?:include)|' \
|
||||||
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
||||||
'\s*.*?)' \
|
r'\s*.*?)' \
|
||||||
'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||||
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
|
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
|
||||||
"$RCSUFFIXES",
|
"$RCSUFFIXES",
|
||||||
"CPPPATH",
|
"CPPPATH",
|
|
@ -5,7 +5,7 @@ This module implements the dependency scanner for SWIG code.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,14 +27,14 @@ This module implements the dependency scanner for SWIG code.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/SWIG.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -5,7 +5,7 @@ The Scanner package for the SCons software construction utility.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ The Scanner package for the SCons software construction utility.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Scanner/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -35,7 +35,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
|
||||||
|
@ -61,7 +61,7 @@ def Scanner(function, *args, **kw):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FindPathDirs(object):
|
class FindPathDirs:
|
||||||
"""
|
"""
|
||||||
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.
|
||||||
|
@ -81,7 +81,7 @@ class FindPathDirs(object):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base:
|
||||||
"""
|
"""
|
||||||
The base class for dependency scanners. This implements
|
The base class for dependency scanners. This implements
|
||||||
straightforward, single-pass scanning of a single file.
|
straightforward, single-pass scanning of a single file.
|
||||||
|
@ -207,7 +207,7 @@ class Base(object):
|
||||||
|
|
||||||
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,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
|
||||||
|
@ -19,9 +19,7 @@
|
||||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/Interactive.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
SCons interactive mode
|
SCons interactive mode
|
||||||
|
@ -247,7 +245,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
|
|
@ -10,14 +10,11 @@ some other module. If it's specific to the "scons" script invocation,
|
||||||
it goes here.
|
it goes here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
unsupported_python_version = (3, 4, 0)
|
||||||
|
deprecated_python_version = (3, 4, 0)
|
||||||
|
|
||||||
|
|
||||||
unsupported_python_version = (2, 6, 0)
|
# __COPYRIGHT__
|
||||||
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 +35,20 @@ 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
|
||||||
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 SCons.CacheDir
|
import SCons.CacheDir
|
||||||
import SCons.Debug
|
import SCons.Debug
|
||||||
|
@ -58,14 +59,29 @@ 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
|
||||||
|
first_command_start = None
|
||||||
|
last_command_end = None
|
||||||
|
print_objects = 0
|
||||||
|
print_memoizer = 0
|
||||||
|
print_stacktrace = 0
|
||||||
|
print_time = 0
|
||||||
|
print_action_timestamps = 0
|
||||||
|
sconscript_time = 0
|
||||||
|
cumulative_command_time = 0
|
||||||
|
exit_status = 0 # final exit status, assume success by default
|
||||||
|
this_build_status = 0 # "exit status" of an individual build
|
||||||
|
num_jobs = None
|
||||||
|
delayed_warnings = []
|
||||||
|
|
||||||
|
|
||||||
def fetch_win32_parallel_msg():
|
def fetch_win32_parallel_msg():
|
||||||
# A subsidiary function that exists solely to isolate this import
|
# A subsidiary function that exists solely to isolate this import
|
||||||
|
@ -85,17 +101,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 +209,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 +354,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 +430,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 +447,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 +460,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 +472,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 +496,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 +628,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 +640,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 +678,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 +698,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 +817,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 +878,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)
|
||||||
|
|
||||||
|
@ -1161,7 +1184,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 +1263,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,7 +1280,11 @@ 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
|
||||||
# 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
|
||||||
|
@ -1339,15 +1370,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 +1393,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,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,14 @@
|
||||||
# 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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:
|
try:
|
||||||
from gettext import gettext
|
from gettext import gettext
|
||||||
|
@ -38,6 +38,7 @@ except ImportError:
|
||||||
_ = gettext
|
_ = 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
|
||||||
|
@ -139,14 +140,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 +168,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 +198,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 +230,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):
|
||||||
"""
|
"""
|
||||||
|
@ -358,32 +332,30 @@ 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
|
|
||||||
command line is immediately available if the user turns
|
|
||||||
around and does a GetOption() right away.
|
|
||||||
|
|
||||||
We mimic the processing of the single args
|
|
||||||
in the original OptionParser._process_args(), but here we
|
|
||||||
allow exact matches for long-opts only (no partial
|
|
||||||
argument names!).
|
|
||||||
|
|
||||||
Else, this would lead to problems in add_local_option()
|
Parse options stored in `self.largs`, so that any value
|
||||||
|
overridden on the command line is immediately available
|
||||||
|
if the user turns around and does a :func:`GetOption` right away.
|
||||||
|
|
||||||
|
We mimic the processing of the single args
|
||||||
|
in the original OptionParser :func:`_process_args`, but here we
|
||||||
|
allow exact matches for long-opts only (no partial argument names!).
|
||||||
|
Otherwise there could be problems in :func:`add_local_option`
|
||||||
below. When called from there, we try to reparse the
|
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.
|
1. haven't been processed so far (`self.largs`), but
|
||||||
|
2. are possibly not added to the list of options yet.
|
||||||
So, when we only have a value for "--myargument" yet,
|
|
||||||
a command-line argument of "--myarg=test" would set it.
|
So, when we only have a value for "--myargument" so far,
|
||||||
Responsible for this behaviour is the method
|
a command-line argument of "--myarg=test" would set it,
|
||||||
_match_long_opt(), which allows for partial matches of
|
per the behaviour of :func:`_match_long_opt`,
|
||||||
the option name, as long as the common prefix appears to
|
which allows for partial matches of the option name,
|
||||||
be unique.
|
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).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
rargs = []
|
rargs = []
|
||||||
largs_restore = []
|
largs_restore = []
|
||||||
|
@ -400,7 +372,7 @@ class SConsOptionParser(optparse.OptionParser):
|
||||||
if "=" in l:
|
if "=" in l:
|
||||||
# Split into option and value
|
# Split into option and value
|
||||||
lopt = l.split("=", 1)
|
lopt = l.split("=", 1)
|
||||||
|
|
||||||
if lopt[0] in self._long_opt:
|
if lopt[0] in self._long_opt:
|
||||||
# Argument is already known
|
# Argument is already known
|
||||||
rargs.append('='.join(lopt))
|
rargs.append('='.join(lopt))
|
||||||
|
@ -415,7 +387,7 @@ class SConsOptionParser(optparse.OptionParser):
|
||||||
skip = True
|
skip = True
|
||||||
else:
|
else:
|
||||||
rargs.append(l)
|
rargs.append(l)
|
||||||
|
|
||||||
# Parse the filtered list
|
# Parse the filtered list
|
||||||
self.parse_args(rargs, self.values)
|
self.parse_args(rargs, self.values)
|
||||||
# Restore the list of remaining arguments for the
|
# Restore the list of remaining arguments for the
|
||||||
|
@ -614,9 +586,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 +612,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 +624,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 +643,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 +673,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 +690,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 +723,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 +836,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 +850,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 +903,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 +976,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:
|
|
@ -6,7 +6,7 @@ files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 @@ 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons
|
import SCons
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
|
@ -42,8 +42,8 @@ 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 collections
|
||||||
|
@ -98,7 +98,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 +110,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 +133,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 +153,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:
|
||||||
|
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 +202,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 +279,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 +295,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 +399,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 +421,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 +442,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 +553,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 +587,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 +640,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
|
|
@ -12,7 +12,7 @@ it goes here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -34,7 +34,7 @@ it goes here.
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Script/__init__.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import time
|
import time
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
@ -81,8 +81,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
|
||||||
|
@ -150,6 +150,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 +163,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 +278,20 @@ 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 +314,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 +344,8 @@ GlobalDefaultEnvironmentFunctions = [
|
||||||
'Requires',
|
'Requires',
|
||||||
'SConsignFile',
|
'SConsignFile',
|
||||||
'SideEffect',
|
'SideEffect',
|
||||||
'SourceCode',
|
|
||||||
'SourceSignatures',
|
|
||||||
'Split',
|
'Split',
|
||||||
'Tag',
|
'Tag',
|
||||||
'TargetSignatures',
|
|
||||||
'Value',
|
'Value',
|
||||||
'VariantDir',
|
'VariantDir',
|
||||||
]
|
]
|
||||||
|
@ -374,7 +373,9 @@ GlobalDefaultBuilders = [
|
||||||
'SharedObject',
|
'SharedObject',
|
||||||
'StaticLibrary',
|
'StaticLibrary',
|
||||||
'StaticObject',
|
'StaticObject',
|
||||||
|
'Substfile',
|
||||||
'Tar',
|
'Tar',
|
||||||
|
'Textfile',
|
||||||
'TypeLibrary',
|
'TypeLibrary',
|
||||||
'Zip',
|
'Zip',
|
||||||
'Package',
|
'Package',
|
|
@ -5,7 +5,7 @@ SCons string substitution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -26,11 +26,11 @@ 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"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
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
|
||||||
|
@ -58,7 +58,7 @@ def raise_exception(exception, target, s):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Literal(object):
|
class Literal:
|
||||||
"""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 +86,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 +171,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 +232,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 +331,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 +751,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 +795,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 +810,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]
|
||||||
|
|
||||||
|
@ -612,234 +886,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv
|
||||||
The companion scons_subst() function (above) handles basic
|
The companion scons_subst() function (above) handles basic
|
||||||
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,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,17 +20,15 @@
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
Generic Taskmaster module for the SCons build engine.
|
Generic Taskmaster module for the SCons build engine.
|
||||||
=====================================================
|
=====================================================
|
||||||
|
|
||||||
This module contains the primary interface(s) between a wrapping user
|
This module contains the primary interface(s) between a wrapping user
|
||||||
interface and the SCons build engine. There are two key classes here:
|
interface and the SCons build engine. There are two key classes here:
|
||||||
|
|
||||||
Taskmaster
|
Taskmaster
|
||||||
----------
|
----------
|
||||||
This is the main engine for walking the dependency graph and
|
This is the main engine for walking the dependency graph and
|
||||||
|
@ -54,12 +52,13 @@ __doc__ = """
|
||||||
target(s) that it decides need to be evaluated and/or built.
|
target(s) that it decides need to be evaluated and/or built.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Taskmaster.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
from itertools import chain
|
|
||||||
import operator
|
import operator
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
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 +80,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 +116,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 +168,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 +209,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 +222,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 +388,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 +436,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 +453,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 +540,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 +568,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 +596,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 +778,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 +806,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 +814,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 +845,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 +860,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 +906,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 +932,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,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
"""SCons.Tool.DCommon
|
"""SCons.Tool.DCommon
|
||||||
|
|
||||||
Common code for the various D tools.
|
Common code for the various D tools.
|
||||||
|
@ -9,7 +7,7 @@ Coded by Russel Winder (russel@winder.org.uk)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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 +29,7 @@ Coded by Russel Winder (russel@winder.org.uk)
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/DCommon.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
@ -5,7 +5,7 @@ Stuff for processing Fortran, common to all fortran dialects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -26,9 +26,7 @@ Stuff for processing Fortran, common to all fortran dialects.
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
__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
|
||||||
|
@ -64,7 +62,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())
|
|
@ -3,8 +3,8 @@
|
||||||
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
|
||||||
# "Software"), to deal in the Software without restriction, including
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
@ -12,10 +12,10 @@ Used by several tools of `gettext` toolset.
|
||||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
# permit persons to whom the Software is furnished to do so, subject to
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
# the following conditions:
|
# the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included
|
# The above copyright notice and this permission notice shall be included
|
||||||
# in all copies or substantial portions of the Software.
|
# in all copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
@ -24,7 +24,7 @@ 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
|
||||||
|
@ -69,9 +69,9 @@ 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`
|
||||||
(this is required by builders and actions gettext) and `noclean` flags by
|
(this is required by builders and actions gettext) and `noclean` flags by
|
||||||
default for all produced nodes.
|
default for all produced nodes.
|
||||||
|
@ -80,9 +80,9 @@ class _POTargetFactory(object):
|
||||||
def __init__(self, env, nodefault=True, alias=None, precious=True
|
def __init__(self, env, nodefault=True, alias=None, precious=True
|
||||||
, noclean=True):
|
, noclean=True):
|
||||||
""" Object constructor.
|
""" Object constructor.
|
||||||
|
|
||||||
**Arguments**
|
**Arguments**
|
||||||
|
|
||||||
- *env* (`SCons.Environment.Environment`)
|
- *env* (`SCons.Environment.Environment`)
|
||||||
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
|
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
|
||||||
from default target `'.'`
|
from default target `'.'`
|
||||||
|
@ -160,13 +160,13 @@ from SCons.Builder import BuilderBase
|
||||||
#############################################################################
|
#############################################################################
|
||||||
class _POFileBuilder(BuilderBase):
|
class _POFileBuilder(BuilderBase):
|
||||||
""" `PO` file builder.
|
""" `PO` file builder.
|
||||||
|
|
||||||
This is multi-target single-source builder. In typical situation the source
|
This is multi-target single-source builder. In typical situation the source
|
||||||
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
|
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
|
||||||
targets to be updated from this `POT`. We must run
|
targets to be updated from this `POT`. We must run
|
||||||
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
|
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
|
||||||
dependencies separatelly for each target file.
|
dependencies separatelly for each target file.
|
||||||
|
|
||||||
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
|
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
|
||||||
with target being list of all targets, all targets would be rebuilt each time
|
with target being list of all targets, all targets would be rebuilt each time
|
||||||
one of the targets from this list is missing. This would happen, for example,
|
one of the targets from this list is missing. This would happen, for example,
|
||||||
|
@ -198,29 +198,29 @@ 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)
|
||||||
|
|
||||||
def _execute(self, env, target, source, *args, **kw):
|
def _execute(self, env, target, source, *args, **kw):
|
||||||
""" Execute builder's actions.
|
""" Execute builder's actions.
|
||||||
|
|
||||||
Here we append to `target` the languages read from `$LINGUAS_FILE` and
|
Here we append to `target` the languages read from `$LINGUAS_FILE` and
|
||||||
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
|
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
|
||||||
The arguments and return value are same as for
|
The arguments and return value are same as for
|
||||||
`SCons.Builder.BuilderBase._execute()`.
|
`SCons.Builder.BuilderBase._execute()`.
|
||||||
"""
|
"""
|
||||||
import SCons.Util
|
import SCons.Util
|
||||||
import SCons.Node
|
import SCons.Node
|
||||||
|
@ -269,10 +269,10 @@ 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.
|
||||||
|
|
||||||
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
|
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
|
||||||
for nodes that are outside of current working directory (`env.fs.getcwd()`).
|
for nodes that are outside of current working directory (`env.fs.getcwd()`).
|
||||||
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
|
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
|
||||||
|
@ -285,17 +285,17 @@ class RPaths(object):
|
||||||
the references would be correct only on the machine, where `POT` file was
|
the references would be correct only on the machine, where `POT` file was
|
||||||
recently re-created. For such reason, we need a function, which always
|
recently re-created. For such reason, we need a function, which always
|
||||||
returns relative paths. This is the purpose of `RPaths` callable object.
|
returns relative paths. This is the purpose of `RPaths` callable object.
|
||||||
|
|
||||||
The `__call__` method returns paths relative to current working directory, but
|
The `__call__` method returns paths relative to current working directory, but
|
||||||
we assume, that *xgettext(1)* is run from the directory, where target file is
|
we assume, that *xgettext(1)* is run from the directory, where target file is
|
||||||
going to be created.
|
going to be created.
|
||||||
|
|
||||||
Note, that this may not work for files distributed over several hosts or
|
Note, that this may not work for files distributed over several hosts or
|
||||||
across different drives on windows. We assume here, that single local
|
across different drives on windows. We assume here, that single local
|
||||||
filesystem holds both source files and target `POT` templates.
|
filesystem holds both source files and target `POT` templates.
|
||||||
|
|
||||||
Intended use of `RPaths` - in `xgettext.py`::
|
Intended use of `RPaths` - in `xgettext.py`::
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
from GettextCommon import RPaths
|
from GettextCommon import RPaths
|
||||||
...
|
...
|
||||||
|
@ -318,9 +318,9 @@ class RPaths(object):
|
||||||
|
|
||||||
def __init__(self, env):
|
def __init__(self, env):
|
||||||
""" Initialize `RPaths` callable object.
|
""" Initialize `RPaths` callable object.
|
||||||
|
|
||||||
**Arguments**:
|
**Arguments**:
|
||||||
|
|
||||||
- *env* - a `SCons.Environment.Environment` object, defines *current
|
- *env* - a `SCons.Environment.Environment` object, defines *current
|
||||||
working dir*.
|
working dir*.
|
||||||
"""
|
"""
|
||||||
|
@ -329,16 +329,16 @@ class RPaths(object):
|
||||||
# FIXME: I'm not sure, how it should be implemented (what the *args are in
|
# FIXME: I'm not sure, how it should be implemented (what the *args are in
|
||||||
# general, what is **kw).
|
# general, what is **kw).
|
||||||
def __call__(self, nodes, *args, **kw):
|
def __call__(self, nodes, *args, **kw):
|
||||||
""" Return nodes' paths (strings) relative to current working directory.
|
""" Return nodes' paths (strings) relative to current working directory.
|
||||||
|
|
||||||
**Arguments**:
|
**Arguments**:
|
||||||
|
|
||||||
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
|
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
|
||||||
- *args* - currently unused.
|
- *args* - currently unused.
|
||||||
- *kw* - currently unused.
|
- *kw* - currently unused.
|
||||||
|
|
||||||
**Returns**:
|
**Returns**:
|
||||||
|
|
||||||
- Tuple of strings, which represent paths relative to current working
|
- Tuple of strings, which represent paths relative to current working
|
||||||
directory (for given environment).
|
directory (for given environment).
|
||||||
"""
|
"""
|
||||||
|
@ -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,19 @@ 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|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
|
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' +
|
||||||
r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' +
|
r'\d*\.\d*|[A-Za-z_][\w$.]*|<[A-Za-z_]\w+>|' +
|
||||||
r'/\*|\*/|\[\])')
|
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)
|
||||||
|
|
||||||
|
@ -115,8 +149,8 @@ if java_parsing:
|
||||||
ret = SkipState(1, self)
|
ret = SkipState(1, self)
|
||||||
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 +159,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 +180,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 +206,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 +318,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 +359,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 +375,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 +439,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.0.1/SCons/Tool/MSCommon/README
Normal file
107
scons/scons-local-4.0.1/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,7 +21,7 @@
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py 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++.
|
||||||
|
@ -42,7 +42,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,14 @@
|
||||||
# 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
|
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 +37,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,78 @@ 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
|
logging.basicConfig(
|
||||||
except ImportError:
|
# This looks like:
|
||||||
debug = lambda message: open(LOGFILE, 'a').write(message + '\n')
|
# 00109ms:MSCommon/vc.py:find_vc_pdir#447:
|
||||||
else:
|
format=(
|
||||||
logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
|
'%(relativeCreated)05dms'
|
||||||
debug = logging.debug
|
':MSCommon/%(filename)s'
|
||||||
|
':%(funcName)s'
|
||||||
|
'#%(lineno)s'
|
||||||
|
':%(message)s: '
|
||||||
|
),
|
||||||
|
filename=LOGFILE,
|
||||||
|
level=logging.DEBUG)
|
||||||
|
debug = logging.getLogger(name=__name__).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 +129,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 +142,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 +157,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 +180,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 +222,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 +245,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)
|
||||||
|
|
954
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vc.py
Normal file
954
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vc.py
Normal file
|
@ -0,0 +1,954 @@
|
||||||
|
#
|
||||||
|
# __COPYRIGHT__
|
||||||
|
#
|
||||||
|
# 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:
|
||||||
|
# * 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
|
||||||
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
__doc__ = """Module for Visual C/C++ detection and configuration.
|
||||||
|
"""
|
||||||
|
import SCons.compat
|
||||||
|
import SCons.Util
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
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("HOST_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 cached_get_installed_vcs(env=None):
|
||||||
|
global __INSTALLED_VCS_RUN
|
||||||
|
|
||||||
|
if __INSTALLED_VCS_RUN is None:
|
||||||
|
ret = get_installed_vcs(env)
|
||||||
|
__INSTALLED_VCS_RUN = ret
|
||||||
|
|
||||||
|
return __INSTALLED_VCS_RUN
|
||||||
|
|
||||||
|
def get_installed_vcs(env=None):
|
||||||
|
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)))
|
||||||
|
return installed_versions
|
||||||
|
|
||||||
|
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 = cached_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, cached_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 = cached_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
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
|
@ -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/aixlink.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
224
scons/scons-local-4.0.1/SCons/Tool/applelink.py
Normal file
224
scons/scons-local-4.0.1/SCons/Tool/applelink.py
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
"""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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#
|
||||||
|
# __COPYRIGHT__
|
||||||
|
#
|
||||||
|
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
from SCons.Tool import ShLibSonameGenerator
|
||||||
|
|
||||||
|
class AppleLinkInvalidCurrentVersionException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AppleLinkInvalidCompatibilityVersionException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _applelib_versioned_lib_suffix(env, suffix, version):
|
||||||
|
"""For suffix='.dylib' and version='0.1.2' it returns '.0.1.2.dylib'"""
|
||||||
|
Verbose = False
|
||||||
|
if Verbose:
|
||||||
|
print("_applelib_versioned_lib_suffix: suffix={!r}".format(suffix))
|
||||||
|
print("_applelib_versioned_lib_suffix: version={!r}".format(version))
|
||||||
|
if version not in suffix:
|
||||||
|
suffix = "." + version + suffix
|
||||||
|
if Verbose:
|
||||||
|
print("_applelib_versioned_lib_suffix: return suffix={!r}".format(suffix))
|
||||||
|
return suffix
|
||||||
|
|
||||||
|
|
||||||
|
def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
|
||||||
|
"""For libnode='/optional/dir/libfoo.X.Y.Z.dylib' it returns 'libfoo.X.dylib'"""
|
||||||
|
Verbose = False
|
||||||
|
if Verbose:
|
||||||
|
print("_applelib_versioned_lib_soname: version={!r}".format(version))
|
||||||
|
name = name_func(env, libnode, version, prefix, suffix)
|
||||||
|
if Verbose:
|
||||||
|
print("_applelib_versioned_lib_soname: name={!r}".format(name))
|
||||||
|
major = version.split('.')[0]
|
||||||
|
(libname,_suffix) = name.split('.')
|
||||||
|
# if a desired SONAME was supplied, use that, otherwise create
|
||||||
|
# a default from the major version
|
||||||
|
if env.get('SONAME'):
|
||||||
|
soname = ShLibSonameGenerator(env, libnode)
|
||||||
|
else:
|
||||||
|
soname = '.'.join([libname, major, _suffix])
|
||||||
|
if Verbose:
|
||||||
|
print("_applelib_versioned_lib_soname: soname={!r}".format(soname))
|
||||||
|
return soname
|
||||||
|
|
||||||
|
def _applelib_versioned_shlib_soname(env, libnode, version, prefix, suffix):
|
||||||
|
return _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name)
|
||||||
|
|
||||||
|
|
||||||
|
# User programmatically describes how SHLIBVERSION maps to values for compat/current.
|
||||||
|
_applelib_max_version_values = (65535, 255, 255)
|
||||||
|
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'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
|
||||||
|
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||||
|
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix
|
||||||
|
env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname
|
||||||
|
|
||||||
|
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'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
|
||||||
|
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||||
|
|
||||||
|
env['__SHLIBVERSIONFLAGS'] = '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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/EnumOption.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 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:
|
# 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
|
|
@ -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/clang.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
# __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
# 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 +45,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 +55,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,7 +82,8 @@ 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:
|
||||||
|
line = pipe.stdout.readline()
|
||||||
if sys.version_info[0] > 2:
|
if sys.version_info[0] > 2:
|
||||||
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)
|
18
scons/scons-local-4.0.1/SCons/Tool/clangCommon/__init__.py
Normal file
18
scons/scons-local-4.0.1/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,15 +69,29 @@ 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:
|
||||||
|
line = pipe.stdout.readline()
|
||||||
if sys.version_info[0] > 2:
|
if sys.version_info[0] > 2:
|
||||||
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)
|
250
scons/scons-local-4.0.1/SCons/Tool/compilation_db.py
Normal file
250
scons/scons-local-4.0.1/SCons/Tool/compilation_db.py
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
"""
|
||||||
|
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 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']
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -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/cxx.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
@ -8,8 +8,6 @@ selection method.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -133,7 +131,7 @@ def _versioned_lib_suffix(env, suffix, version):
|
||||||
if Verbose:
|
if Verbose:
|
||||||
print("_versioned_lib_suffix: suffix= ", suffix)
|
print("_versioned_lib_suffix: suffix= ", suffix)
|
||||||
print("_versioned_lib_suffix: version= ", version)
|
print("_versioned_lib_suffix: version= ", version)
|
||||||
cygversion = re.sub('\.', '-', version)
|
cygversion = re.sub(r'\.', '-', version)
|
||||||
if not suffix.startswith('-' + cygversion):
|
if not suffix.startswith('-' + cygversion):
|
||||||
suffix = '-' + cygversion + suffix
|
suffix = '-' + cygversion + suffix
|
||||||
if Verbose:
|
if Verbose:
|
|
@ -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/default.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import SCons.Tool
|
import SCons.Tool
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
"""SCons.Tool.dmd
|
"""SCons.Tool.dmd
|
||||||
|
|
||||||
Tool-specific initialization for the Digital Mars D compiler.
|
Tool-specific initialization for the Digital Mars D compiler.
|
||||||
|
@ -12,26 +10,47 @@ Evolved by Russel Winder (russel@winder.org.uk)
|
||||||
2010-02-07 onwards
|
2010-02-07 onwards
|
||||||
|
|
||||||
Compiler variables:
|
Compiler variables:
|
||||||
DC - The name of the D compiler to use. Defaults to dmd or gdmd,
|
|
||||||
whichever is found.
|
DC
|
||||||
DPATH - List of paths to search for import modules.
|
The name of the D compiler to use.
|
||||||
DVERSIONS - List of version tags to enable when compiling.
|
Defaults to dmd or gdmd, whichever is found.
|
||||||
DDEBUG - List of debug tags to enable when compiling.
|
|
||||||
|
DPATH
|
||||||
|
List of paths to search for import modules.
|
||||||
|
|
||||||
|
DVERSIONS
|
||||||
|
List of version tags to enable when compiling.
|
||||||
|
|
||||||
|
DDEBUG
|
||||||
|
List of debug tags to enable when compiling.
|
||||||
|
|
||||||
Linker related variables:
|
Linker related variables:
|
||||||
LIBS - List of library files to link in.
|
|
||||||
DLINK - Name of the linker to use. Defaults to dmd or gdmd,
|
LIBS
|
||||||
whichever is found.
|
List of library files to link in.
|
||||||
DLINKFLAGS - List of linker flags.
|
|
||||||
|
DLINK
|
||||||
|
Name of the linker to use.
|
||||||
|
Defaults to dmd or gdmd, whichever is found.
|
||||||
|
|
||||||
|
DLINKFLAGS
|
||||||
|
List of linker flags.
|
||||||
|
|
||||||
Lib tool variables:
|
Lib tool variables:
|
||||||
DLIB - Name of the lib tool to use. Defaults to lib.
|
|
||||||
DLIBFLAGS - List of flags to pass to the lib tool.
|
DLIB
|
||||||
LIBS - Same as for the linker. (libraries to pull into the .lib)
|
Name of the lib tool to use. Defaults to lib.
|
||||||
|
|
||||||
|
DLIBFLAGS
|
||||||
|
List of flags to pass to the lib tool.
|
||||||
|
|
||||||
|
LIBS
|
||||||
|
Same as for the linker. (libraries to pull into the .lib)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -53,7 +72,7 @@ Lib tool variables:
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__revision__ = "src/engine/SCons/Tool/dmd.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog"
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
|
@ -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
|
||||||
|
@ -51,20 +51,14 @@ scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||||
# Local folder for the collection of DocBook XSLs
|
# Local folder for the collection of DocBook XSLs
|
||||||
db_xsl_folder = 'docbook-xsl-1.76.1'
|
db_xsl_folder = 'docbook-xsl-1.76.1'
|
||||||
|
|
||||||
# Do we have libxml2/libxslt/lxml?
|
# Do we have lxml?
|
||||||
has_libxml2 = True
|
|
||||||
has_lxml = True
|
has_lxml = True
|
||||||
try:
|
|
||||||
import libxml2
|
|
||||||
import libxslt
|
|
||||||
except:
|
|
||||||
has_libxml2 = False
|
|
||||||
try:
|
try:
|
||||||
import lxml
|
import lxml
|
||||||
except:
|
except Exception:
|
||||||
has_lxml = False
|
has_lxml = False
|
||||||
|
|
||||||
# Set this to True, to prefer xsltproc over libxml2 and lxml
|
# Set this to True, to prefer xsltproc over lxml
|
||||||
prefer_xsltproc = False
|
prefer_xsltproc = False
|
||||||
|
|
||||||
# Regexs for parsing Docbook XML sources of MAN pages
|
# Regexs for parsing Docbook XML sources of MAN pages
|
||||||
|
@ -84,7 +78,7 @@ def __extend_targets_sources(target, source):
|
||||||
source = [source]
|
source = [source]
|
||||||
if len(target) < len(source):
|
if len(target) < len(source):
|
||||||
target.extend(source[len(target):])
|
target.extend(source[len(target):])
|
||||||
|
|
||||||
return target, source
|
return target, source
|
||||||
|
|
||||||
def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
|
def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
|
||||||
|
@ -94,28 +88,20 @@ def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
|
||||||
path_args = [scriptpath, db_xsl_folder] + default_path
|
path_args = [scriptpath, db_xsl_folder] + default_path
|
||||||
xsl_style = os.path.join(*path_args)
|
xsl_style = os.path.join(*path_args)
|
||||||
kw['DOCBOOK_XSL'] = xsl_style
|
kw['DOCBOOK_XSL'] = xsl_style
|
||||||
|
|
||||||
def __select_builder(lxml_builder, libxml2_builder, cmdline_builder):
|
|
||||||
""" Selects a builder, based on which Python modules are present. """
|
|
||||||
if prefer_xsltproc:
|
|
||||||
return cmdline_builder
|
|
||||||
|
|
||||||
if not has_libxml2:
|
|
||||||
# At the moment we prefer libxml2 over lxml, the latter can lead
|
|
||||||
# to conflicts when installed together with libxml2.
|
|
||||||
if has_lxml:
|
|
||||||
return lxml_builder
|
|
||||||
else:
|
|
||||||
return cmdline_builder
|
|
||||||
|
|
||||||
return libxml2_builder
|
def __select_builder(lxml_builder, cmdline_builder):
|
||||||
|
""" Selects a builder, based on which Python modules are present. """
|
||||||
|
if has_lxml and not prefer_xsltproc:
|
||||||
|
return lxml_builder
|
||||||
|
|
||||||
|
return cmdline_builder
|
||||||
|
|
||||||
def __ensure_suffix(t, suffix):
|
def __ensure_suffix(t, suffix):
|
||||||
""" Ensure that the target t has the given suffix. """
|
""" Ensure that the target t has the given suffix. """
|
||||||
tpath = str(t)
|
tpath = str(t)
|
||||||
if not tpath.endswith(suffix):
|
if not tpath.endswith(suffix):
|
||||||
return tpath+suffix
|
return tpath+suffix
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def __ensure_suffix_stem(t, suffix):
|
def __ensure_suffix_stem(t, suffix):
|
||||||
|
@ -124,18 +110,18 @@ def __ensure_suffix_stem(t, suffix):
|
||||||
if not tpath.endswith(suffix):
|
if not tpath.endswith(suffix):
|
||||||
stem = tpath
|
stem = tpath
|
||||||
tpath += suffix
|
tpath += suffix
|
||||||
|
|
||||||
return tpath, stem
|
return tpath, stem
|
||||||
else:
|
else:
|
||||||
stem, ext = os.path.splitext(tpath)
|
stem, ext = os.path.splitext(tpath)
|
||||||
|
|
||||||
return t, stem
|
return t, stem
|
||||||
|
|
||||||
def __get_xml_text(root):
|
def __get_xml_text(root):
|
||||||
""" Return the text for the given root node (xml.dom.minidom). """
|
""" Return the text for the given root node (xml.dom.minidom). """
|
||||||
txt = ""
|
txt = ""
|
||||||
for e in root.childNodes:
|
for e in root.childNodes:
|
||||||
if (e.nodeType == e.TEXT_NODE):
|
if e.nodeType == e.TEXT_NODE:
|
||||||
txt += e.data
|
txt += e.data
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
@ -151,7 +137,7 @@ def __create_output_dir(base_dir):
|
||||||
else:
|
else:
|
||||||
if base_dir.endswith('/'):
|
if base_dir.endswith('/'):
|
||||||
dir = base_dir
|
dir = base_dir
|
||||||
|
|
||||||
if dir and not os.path.isdir(dir):
|
if dir and not os.path.isdir(dir):
|
||||||
os.makedirs(dir)
|
os.makedirs(dir)
|
||||||
|
|
||||||
|
@ -166,6 +152,8 @@ xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan']
|
||||||
# see: http://saxon.sourceforge.net/
|
# see: http://saxon.sourceforge.net/
|
||||||
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
|
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
|
||||||
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
||||||
|
# Note if saxon-xslt is version 5.5 the proper arguments are: (swap order of docbook_xsl and source)
|
||||||
|
# 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $SOURCE $DOCBOOK_XSL $DOCBOOK_XSLTPROCPARAMS',
|
||||||
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
||||||
'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'}
|
'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'}
|
||||||
xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'}
|
xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'}
|
||||||
|
@ -201,11 +189,11 @@ def _detect(env):
|
||||||
the requested output formats.
|
the requested output formats.
|
||||||
"""
|
"""
|
||||||
global prefer_xsltproc
|
global prefer_xsltproc
|
||||||
|
|
||||||
if env.get('DOCBOOK_PREFER_XSLTPROC',''):
|
if env.get('DOCBOOK_PREFER_XSLTPROC',''):
|
||||||
prefer_xsltproc = True
|
prefer_xsltproc = True
|
||||||
|
|
||||||
if ((not has_libxml2 and not has_lxml) or (prefer_xsltproc)):
|
if (not has_lxml) or prefer_xsltproc:
|
||||||
# Try to find the XSLT processors
|
# Try to find the XSLT processors
|
||||||
__detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority)
|
__detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority)
|
||||||
__detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com)
|
__detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com)
|
||||||
|
@ -217,58 +205,40 @@ def _detect(env):
|
||||||
#
|
#
|
||||||
include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']')
|
include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']')
|
||||||
sentity_re = re.compile('<!ENTITY\\s+%*\\s*[^\\s]+\\s+SYSTEM\\s+["|\']([^\\n]*)["|\']>')
|
sentity_re = re.compile('<!ENTITY\\s+%*\\s*[^\\s]+\\s+SYSTEM\\s+["|\']([^\\n]*)["|\']>')
|
||||||
|
|
||||||
def __xml_scan(node, env, path, arg):
|
def __xml_scan(node, env, path, arg):
|
||||||
""" Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """
|
""" Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """
|
||||||
# Does the node exist yet?
|
# Does the node exist yet?
|
||||||
if not os.path.isfile(str(node)):
|
if not os.path.isfile(str(node)):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if env.get('DOCBOOK_SCANENT',''):
|
if env.get('DOCBOOK_SCANENT',''):
|
||||||
# Use simple pattern matching for system entities..., no support
|
# Use simple pattern matching for system entities..., no support
|
||||||
# for recursion yet.
|
# for recursion yet.
|
||||||
contents = node.get_text_contents()
|
contents = node.get_text_contents()
|
||||||
return sentity_re.findall(contents)
|
return sentity_re.findall(contents)
|
||||||
|
|
||||||
xsl_file = os.path.join(scriptpath,'utils','xmldepend.xsl')
|
xsl_file = os.path.join(scriptpath,'utils','xmldepend.xsl')
|
||||||
if not has_libxml2 or prefer_xsltproc:
|
if not has_lxml or prefer_xsltproc:
|
||||||
if has_lxml and not prefer_xsltproc:
|
# Try to call xsltproc
|
||||||
|
xsltproc = env.subst("$DOCBOOK_XSLTPROC")
|
||||||
from lxml import etree
|
if xsltproc and xsltproc.endswith('xsltproc'):
|
||||||
|
result = env.backtick(' '.join([xsltproc, xsl_file, str(node)]))
|
||||||
xsl_tree = etree.parse(xsl_file)
|
|
||||||
doc = etree.parse(str(node))
|
|
||||||
result = doc.xslt(xsl_tree)
|
|
||||||
|
|
||||||
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
||||||
return depfiles
|
return depfiles
|
||||||
else:
|
else:
|
||||||
# Try to call xsltproc
|
# Use simple pattern matching, there is currently no support
|
||||||
xsltproc = env.subst("$DOCBOOK_XSLTPROC")
|
# for xi:includes...
|
||||||
if xsltproc and xsltproc.endswith('xsltproc'):
|
contents = node.get_text_contents()
|
||||||
result = env.backtick(' '.join([xsltproc, xsl_file, str(node)]))
|
return include_re.findall(contents)
|
||||||
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
|
||||||
return depfiles
|
from lxml import etree
|
||||||
else:
|
|
||||||
# Use simple pattern matching, there is currently no support
|
|
||||||
# for xi:includes...
|
|
||||||
contents = node.get_text_contents()
|
|
||||||
return include_re.findall(contents)
|
|
||||||
|
|
||||||
styledoc = libxml2.parseFile(xsl_file)
|
xsl_tree = etree.parse(xsl_file)
|
||||||
style = libxslt.parseStylesheetDoc(styledoc)
|
doc = etree.parse(str(node))
|
||||||
doc = libxml2.readFile(str(node), None, libxml2.XML_PARSE_NOENT)
|
result = doc.xslt(xsl_tree)
|
||||||
result = style.applyStylesheet(doc, None)
|
|
||||||
|
|
||||||
depfiles = []
|
|
||||||
for x in str(result).splitlines():
|
|
||||||
if x.strip() != "" and not x.startswith("<?xml "):
|
|
||||||
depfiles.extend(x.strip().split())
|
|
||||||
|
|
||||||
style.freeStylesheet()
|
|
||||||
doc.freeDoc()
|
|
||||||
result.freeDoc()
|
|
||||||
|
|
||||||
|
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
||||||
return depfiles
|
return depfiles
|
||||||
|
|
||||||
# Creating the instance of our XML dependency scanner
|
# Creating the instance of our XML dependency scanner
|
||||||
|
@ -280,12 +250,21 @@ docbook_xml_scanner = SCons.Script.Scanner(function = __xml_scan,
|
||||||
# Action generators
|
# Action generators
|
||||||
#
|
#
|
||||||
def __generate_xsltproc_action(source, target, env, for_signature):
|
def __generate_xsltproc_action(source, target, env, for_signature):
|
||||||
cmd = env['DOCBOOK_XSLTPROCCOM']
|
cmd = env['DOCBOOK_XSLTPROCCOM']
|
||||||
# Does the environment have a base_dir defined?
|
# Does the environment have a base_dir defined?
|
||||||
base_dir = env.subst('$base_dir')
|
base_dir = env.subst('$base_dir')
|
||||||
if base_dir:
|
if base_dir:
|
||||||
# Yes, so replace target path by its filename
|
# Yes, so replace target path by its filename
|
||||||
return cmd.replace('$TARGET','${TARGET.file}')
|
return cmd.replace('$TARGET', os.path.join(base_dir, '${TARGET.file}'))
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def __generate_xsltproc_nobase_action(source, target, env, for_signature):
|
||||||
|
cmd = env['DOCBOOK_XSLTPROCCOM']
|
||||||
|
# Does the environment have a base_dir defined?
|
||||||
|
base_dir = env.subst('$base_dir')
|
||||||
|
if base_dir:
|
||||||
|
# Yes, so replace target path by its filename
|
||||||
|
return cmd.replace('$TARGET', '${TARGET.file}')
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
@ -298,7 +277,7 @@ def __emit_xsl_basedir(target, source, env):
|
||||||
if base_dir:
|
if base_dir:
|
||||||
# Yes, so prepend it to each target
|
# Yes, so prepend it to each target
|
||||||
return [os.path.join(base_dir, str(t)) for t in target], source
|
return [os.path.join(base_dir, str(t)) for t in target], source
|
||||||
|
|
||||||
# No, so simply pass target and source names through
|
# No, so simply pass target and source names through
|
||||||
return target, source
|
return target, source
|
||||||
|
|
||||||
|
@ -306,37 +285,16 @@ def __emit_xsl_basedir(target, source, env):
|
||||||
#
|
#
|
||||||
# Builders
|
# Builders
|
||||||
#
|
#
|
||||||
def __build_libxml2(target, source, env):
|
|
||||||
"""
|
|
||||||
General XSLT builder (HTML/FO), using the libxml2 module.
|
|
||||||
"""
|
|
||||||
xsl_style = env.subst('$DOCBOOK_XSL')
|
|
||||||
styledoc = libxml2.parseFile(xsl_style)
|
|
||||||
style = libxslt.parseStylesheetDoc(styledoc)
|
|
||||||
doc = libxml2.readFile(str(source[0]),None,libxml2.XML_PARSE_NOENT)
|
|
||||||
# Support for additional parameters
|
|
||||||
parampass = {}
|
|
||||||
if parampass:
|
|
||||||
result = style.applyStylesheet(doc, parampass)
|
|
||||||
else:
|
|
||||||
result = style.applyStylesheet(doc, None)
|
|
||||||
style.saveResultToFilename(str(target[0]), result, 0)
|
|
||||||
style.freeStylesheet()
|
|
||||||
doc.freeDoc()
|
|
||||||
result.freeDoc()
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __build_lxml(target, source, env):
|
def __build_lxml(target, source, env):
|
||||||
"""
|
"""
|
||||||
General XSLT builder (HTML/FO), using the lxml module.
|
General XSLT builder (HTML/FO), using the lxml module.
|
||||||
"""
|
"""
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
xslt_ac = etree.XSLTAccessControl(read_file=True,
|
xslt_ac = etree.XSLTAccessControl(read_file=True,
|
||||||
write_file=True,
|
write_file=True,
|
||||||
create_dir=True,
|
create_dir=True,
|
||||||
read_network=False,
|
read_network=False,
|
||||||
write_network=False)
|
write_network=False)
|
||||||
xsl_style = env.subst('$DOCBOOK_XSL')
|
xsl_style = env.subst('$DOCBOOK_XSL')
|
||||||
xsl_tree = etree.parse(xsl_style)
|
xsl_tree = etree.parse(xsl_style)
|
||||||
|
@ -348,59 +306,71 @@ def __build_lxml(target, source, env):
|
||||||
result = transform(doc, **parampass)
|
result = transform(doc, **parampass)
|
||||||
else:
|
else:
|
||||||
result = transform(doc)
|
result = transform(doc)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
of = open(str(target[0]), "wb")
|
with open(str(target[0]), "wb") as of:
|
||||||
of.write(of.write(etree.tostring(result, pretty_print=True)))
|
of.write(etree.tostring(result, encoding="utf-8", pretty_print=True))
|
||||||
of.close()
|
except Exception as e:
|
||||||
except:
|
print("ERROR: Failed to write {}".format(str(target[0])))
|
||||||
pass
|
print(e)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __xinclude_libxml2(target, source, env):
|
def __build_lxml_noresult(target, source, env):
|
||||||
"""
|
"""
|
||||||
Resolving XIncludes, using the libxml2 module.
|
Specialized XSLT builder for transformations without a direct result where the Docbook
|
||||||
|
stylesheet itself creates the target file, using the lxml module.
|
||||||
"""
|
"""
|
||||||
doc = libxml2.readFile(str(source[0]), None, libxml2.XML_PARSE_NOENT)
|
from lxml import etree
|
||||||
doc.xincludeProcessFlags(libxml2.XML_PARSE_NOENT)
|
|
||||||
doc.saveFile(str(target[0]))
|
xslt_ac = etree.XSLTAccessControl(read_file=True,
|
||||||
doc.freeDoc()
|
write_file=True,
|
||||||
|
create_dir=True,
|
||||||
|
read_network=False,
|
||||||
|
write_network=False)
|
||||||
|
xsl_style = env.subst('$DOCBOOK_XSL')
|
||||||
|
xsl_tree = etree.parse(xsl_style)
|
||||||
|
transform = etree.XSLT(xsl_tree, access_control=xslt_ac)
|
||||||
|
doc = etree.parse(str(source[0]))
|
||||||
|
# Support for additional parameters
|
||||||
|
parampass = {}
|
||||||
|
if parampass:
|
||||||
|
result = transform(doc, **parampass)
|
||||||
|
else:
|
||||||
|
result = transform(doc)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def __xinclude_lxml(target, source, env):
|
def __xinclude_lxml(target, source, env):
|
||||||
"""
|
"""
|
||||||
Resolving XIncludes, using the lxml module.
|
Resolving XIncludes, using the lxml module.
|
||||||
"""
|
"""
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
doc = etree.parse(str(source[0]))
|
doc = etree.parse(str(source[0]))
|
||||||
doc.xinclude()
|
doc.xinclude()
|
||||||
try:
|
try:
|
||||||
doc.write(str(target[0]), xml_declaration=True,
|
doc.write(str(target[0]), xml_declaration=True,
|
||||||
encoding="UTF-8", pretty_print=True)
|
encoding="UTF-8", pretty_print=True)
|
||||||
except:
|
except Exception as e:
|
||||||
pass
|
print("ERROR: Failed to write {}".format(str(target[0])))
|
||||||
|
print(e)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
__libxml2_builder = SCons.Builder.Builder(
|
|
||||||
action = __build_libxml2,
|
|
||||||
src_suffix = '.xml',
|
|
||||||
source_scanner = docbook_xml_scanner,
|
|
||||||
emitter = __emit_xsl_basedir)
|
|
||||||
__lxml_builder = SCons.Builder.Builder(
|
__lxml_builder = SCons.Builder.Builder(
|
||||||
action = __build_lxml,
|
action = __build_lxml,
|
||||||
src_suffix = '.xml',
|
src_suffix = '.xml',
|
||||||
source_scanner = docbook_xml_scanner,
|
source_scanner = docbook_xml_scanner,
|
||||||
emitter = __emit_xsl_basedir)
|
emitter = __emit_xsl_basedir)
|
||||||
|
|
||||||
__xinclude_libxml2_builder = SCons.Builder.Builder(
|
__lxml_noresult_builder = SCons.Builder.Builder(
|
||||||
action = __xinclude_libxml2,
|
action = __build_lxml_noresult,
|
||||||
suffix = '.xml',
|
|
||||||
src_suffix = '.xml',
|
src_suffix = '.xml',
|
||||||
source_scanner = docbook_xml_scanner)
|
source_scanner = docbook_xml_scanner,
|
||||||
|
emitter = __emit_xsl_basedir)
|
||||||
|
|
||||||
__xinclude_lxml_builder = SCons.Builder.Builder(
|
__xinclude_lxml_builder = SCons.Builder.Builder(
|
||||||
action = __xinclude_lxml,
|
action = __xinclude_lxml,
|
||||||
suffix = '.xml',
|
suffix = '.xml',
|
||||||
|
@ -413,6 +383,12 @@ __xsltproc_builder = SCons.Builder.Builder(
|
||||||
src_suffix = '.xml',
|
src_suffix = '.xml',
|
||||||
source_scanner = docbook_xml_scanner,
|
source_scanner = docbook_xml_scanner,
|
||||||
emitter = __emit_xsl_basedir)
|
emitter = __emit_xsl_basedir)
|
||||||
|
__xsltproc_nobase_builder = SCons.Builder.Builder(
|
||||||
|
action = SCons.Action.CommandGeneratorAction(__generate_xsltproc_nobase_action,
|
||||||
|
{'cmdstr' : '$DOCBOOK_XSLTPROCCOMSTR'}),
|
||||||
|
src_suffix = '.xml',
|
||||||
|
source_scanner = docbook_xml_scanner,
|
||||||
|
emitter = __emit_xsl_basedir)
|
||||||
__xmllint_builder = SCons.Builder.Builder(
|
__xmllint_builder = SCons.Builder.Builder(
|
||||||
action = SCons.Action.Action('$DOCBOOK_XMLLINTCOM','$DOCBOOK_XMLLINTCOMSTR'),
|
action = SCons.Action.Action('$DOCBOOK_XMLLINTCOM','$DOCBOOK_XMLLINTCOMSTR'),
|
||||||
suffix = '.xml',
|
suffix = '.xml',
|
||||||
|
@ -430,33 +406,31 @@ def DocbookEpub(env, target, source=None, *args, **kw):
|
||||||
"""
|
"""
|
||||||
import zipfile
|
import zipfile
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
def build_open_container(target, source, env):
|
def build_open_container(target, source, env):
|
||||||
"""Generate the *.epub file from intermediate outputs
|
"""Generate the *.epub file from intermediate outputs
|
||||||
|
|
||||||
Constructs the epub file according to the Open Container Format. This
|
Constructs the epub file according to the Open Container Format. This
|
||||||
function could be replaced by a call to the SCons Zip builder if support
|
function could be replaced by a call to the SCons Zip builder if support
|
||||||
was added for different compression formats for separate source nodes.
|
was added for different compression formats for separate source nodes.
|
||||||
"""
|
"""
|
||||||
zf = zipfile.ZipFile(str(target[0]), 'w')
|
with zipfile.ZipFile(str(target[0]), 'w') as zf:
|
||||||
mime_file = open('mimetype', 'w')
|
with open('mimetype', 'w') as mime_file:
|
||||||
mime_file.write('application/epub+zip')
|
mime_file.write('application/epub+zip')
|
||||||
mime_file.close()
|
zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
|
||||||
zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
|
for s in source:
|
||||||
for s in source:
|
if os.path.isfile(str(s)):
|
||||||
if os.path.isfile(str(s)):
|
head, tail = os.path.split(str(s))
|
||||||
head, tail = os.path.split(str(s))
|
if not head:
|
||||||
if not head:
|
continue
|
||||||
continue
|
s = head
|
||||||
s = head
|
for dirpath, dirnames, filenames in os.walk(str(s)):
|
||||||
for dirpath, dirnames, filenames in os.walk(str(s)):
|
for fname in filenames:
|
||||||
for fname in filenames:
|
path = os.path.join(dirpath, fname)
|
||||||
path = os.path.join(dirpath, fname)
|
if os.path.isfile(path):
|
||||||
if os.path.isfile(path):
|
zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
|
||||||
zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
|
zipfile.ZIP_DEFLATED)
|
||||||
zipfile.ZIP_DEFLATED)
|
|
||||||
zf.close()
|
|
||||||
|
|
||||||
def add_resources(target, source, env):
|
def add_resources(target, source, env):
|
||||||
"""Add missing resources to the OEBPS directory
|
"""Add missing resources to the OEBPS directory
|
||||||
|
|
||||||
|
@ -466,78 +440,52 @@ def DocbookEpub(env, target, source=None, *args, **kw):
|
||||||
content_file = os.path.join(source[0].get_abspath(), 'content.opf')
|
content_file = os.path.join(source[0].get_abspath(), 'content.opf')
|
||||||
if not os.path.isfile(content_file):
|
if not os.path.isfile(content_file):
|
||||||
return
|
return
|
||||||
|
|
||||||
hrefs = []
|
hrefs = []
|
||||||
if has_libxml2:
|
if has_lxml:
|
||||||
nsmap = {'opf' : 'http://www.idpf.org/2007/opf'}
|
|
||||||
# Read file and resolve entities
|
|
||||||
doc = libxml2.readFile(content_file, None, 0)
|
|
||||||
opf = doc.getRootElement()
|
|
||||||
# Create xpath context
|
|
||||||
xpath_context = doc.xpathNewContext()
|
|
||||||
# Register namespaces
|
|
||||||
for key, val in nsmap.items():
|
|
||||||
xpath_context.xpathRegisterNs(key, val)
|
|
||||||
|
|
||||||
if hasattr(opf, 'xpathEval') and xpath_context:
|
|
||||||
# Use the xpath context
|
|
||||||
xpath_context.setContextNode(opf)
|
|
||||||
items = xpath_context.xpathEval(".//opf:item")
|
|
||||||
else:
|
|
||||||
items = opf.findall(".//{'http://www.idpf.org/2007/opf'}item")
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
if hasattr(item, 'prop'):
|
|
||||||
hrefs.append(item.prop('href'))
|
|
||||||
else:
|
|
||||||
hrefs.append(item.attrib['href'])
|
|
||||||
|
|
||||||
doc.freeDoc()
|
|
||||||
xpath_context.xpathFreeContext()
|
|
||||||
elif has_lxml:
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
opf = etree.parse(content_file)
|
opf = etree.parse(content_file)
|
||||||
# All the opf:item elements are resources
|
# All the opf:item elements are resources
|
||||||
for item in opf.xpath('//opf:item',
|
for item in opf.xpath('//opf:item',
|
||||||
namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):
|
namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):
|
||||||
hrefs.append(item.attrib['href'])
|
hrefs.append(item.attrib['href'])
|
||||||
|
|
||||||
for href in hrefs:
|
for href in hrefs:
|
||||||
# If the resource was not already created by DocBook XSL itself,
|
# If the resource was not already created by DocBook XSL itself,
|
||||||
# copy it into the OEBPS folder
|
# copy it into the OEBPS folder
|
||||||
referenced_file = os.path.join(source[0].get_abspath(), href)
|
referenced_file = os.path.join(source[0].get_abspath(), href)
|
||||||
if not os.path.exists(referenced_file):
|
if not os.path.exists(referenced_file):
|
||||||
shutil.copy(href, os.path.join(source[0].get_abspath(), href))
|
shutil.copy(href, os.path.join(source[0].get_abspath(), href))
|
||||||
|
|
||||||
# Init list of targets/sources
|
# Init list of targets/sources
|
||||||
target, source = __extend_targets_sources(target, source)
|
target, source = __extend_targets_sources(target, source)
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_EPUB', ['epub','docbook.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_EPUB', ['epub','docbook.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
if not env.GetOption('clean'):
|
if not env.GetOption('clean'):
|
||||||
# Ensure that the folders OEBPS and META-INF exist
|
# Ensure that the folders OEBPS and META-INF exist
|
||||||
__create_output_dir('OEBPS/')
|
__create_output_dir('OEBPS/')
|
||||||
__create_output_dir('META-INF/')
|
__create_output_dir('META-INF/')
|
||||||
dirs = env.Dir(['OEBPS', 'META-INF'])
|
dirs = env.Dir(['OEBPS', 'META-INF'])
|
||||||
|
|
||||||
# Set the fixed base_dir
|
# Set the fixed base_dir
|
||||||
kw['base_dir'] = 'OEBPS/'
|
kw['base_dir'] = 'OEBPS/'
|
||||||
tocncx = __builder.__call__(env, 'toc.ncx', source[0], **kw)
|
tocncx = __builder.__call__(env, 'toc.ncx', source[0], **kw)
|
||||||
cxml = env.File('META-INF/container.xml')
|
cxml = env.File('META-INF/container.xml')
|
||||||
env.SideEffect(cxml, tocncx)
|
env.SideEffect(cxml, tocncx)
|
||||||
|
|
||||||
env.Depends(tocncx, kw['DOCBOOK_XSL'])
|
env.Depends(tocncx, kw['DOCBOOK_XSL'])
|
||||||
result.extend(tocncx+[cxml])
|
result.extend(tocncx+[cxml])
|
||||||
|
|
||||||
container = env.Command(__ensure_suffix(str(target[0]), '.epub'),
|
container = env.Command(__ensure_suffix(str(target[0]), '.epub'),
|
||||||
tocncx+[cxml], [add_resources, build_open_container])
|
tocncx+[cxml], [add_resources, build_open_container])
|
||||||
mimetype = env.File('mimetype')
|
mimetype = env.File('mimetype')
|
||||||
env.SideEffect(mimetype, container)
|
env.SideEffect(mimetype, container)
|
||||||
|
|
||||||
|
@ -553,13 +501,13 @@ def DocbookHtml(env, target, source=None, *args, **kw):
|
||||||
"""
|
"""
|
||||||
# Init list of targets/sources
|
# Init list of targets/sources
|
||||||
target, source = __extend_targets_sources(target, source)
|
target, source = __extend_targets_sources(target, source)
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTML', ['html','docbook.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTML', ['html','docbook.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
for t,s in zip(target,source):
|
for t,s in zip(target,source):
|
||||||
|
@ -581,18 +529,18 @@ def DocbookHtmlChunked(env, target, source=None, *args, **kw):
|
||||||
target = ['index.html']
|
target = ['index.html']
|
||||||
elif not SCons.Util.is_List(source):
|
elif not SCons.Util.is_List(source):
|
||||||
source = [source]
|
source = [source]
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED', ['html','chunkfast.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED', ['html','chunkfast.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||||
|
|
||||||
# Detect base dir
|
# Detect base dir
|
||||||
base_dir = kw.get('base_dir', '')
|
base_dir = kw.get('base_dir', '')
|
||||||
if base_dir:
|
if base_dir:
|
||||||
__create_output_dir(base_dir)
|
__create_output_dir(base_dir)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
||||||
|
@ -615,19 +563,19 @@ def DocbookHtmlhelp(env, target, source=None, *args, **kw):
|
||||||
source = target
|
source = target
|
||||||
target = ['index.html']
|
target = ['index.html']
|
||||||
elif not SCons.Util.is_List(source):
|
elif not SCons.Util.is_List(source):
|
||||||
source = [source]
|
source = [source]
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLHELP', ['htmlhelp','htmlhelp.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLHELP', ['htmlhelp','htmlhelp.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||||
|
|
||||||
# Detect base dir
|
# Detect base dir
|
||||||
base_dir = kw.get('base_dir', '')
|
base_dir = kw.get('base_dir', '')
|
||||||
if base_dir:
|
if base_dir:
|
||||||
__create_output_dir(base_dir)
|
__create_output_dir(base_dir)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
||||||
|
@ -650,7 +598,7 @@ def DocbookPdf(env, target, source=None, *args, **kw):
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_PDF', ['fo','docbook.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_PDF', ['fo','docbook.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
|
@ -674,7 +622,7 @@ def DocbookMan(env, target, source=None, *args, **kw):
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_MAN', ['manpages','docbook.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_MAN', ['manpages','docbook.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
|
@ -685,30 +633,29 @@ def DocbookMan(env, target, source=None, *args, **kw):
|
||||||
if os.path.isfile(srcfile):
|
if os.path.isfile(srcfile):
|
||||||
try:
|
try:
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
dom = xml.dom.minidom.parse(__ensure_suffix(str(s),'.xml'))
|
dom = xml.dom.minidom.parse(__ensure_suffix(str(s),'.xml'))
|
||||||
# Extract volume number, default is 1
|
# Extract volume number, default is 1
|
||||||
for node in dom.getElementsByTagName('refmeta'):
|
for node in dom.getElementsByTagName('refmeta'):
|
||||||
for vol in node.getElementsByTagName('manvolnum'):
|
for vol in node.getElementsByTagName('manvolnum'):
|
||||||
volnum = __get_xml_text(vol)
|
volnum = __get_xml_text(vol)
|
||||||
|
|
||||||
# Extract output filenames
|
# Extract output filenames
|
||||||
for node in dom.getElementsByTagName('refnamediv'):
|
for node in dom.getElementsByTagName('refnamediv'):
|
||||||
for ref in node.getElementsByTagName('refname'):
|
for ref in node.getElementsByTagName('refname'):
|
||||||
outfiles.append(__get_xml_text(ref)+'.'+volnum)
|
outfiles.append(__get_xml_text(ref)+'.'+volnum)
|
||||||
|
|
||||||
except:
|
except Exception:
|
||||||
# Use simple regex parsing
|
# Use simple regex parsing
|
||||||
f = open(__ensure_suffix(str(s),'.xml'), 'r')
|
with open(__ensure_suffix(str(s),'.xml'), 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
f.close()
|
|
||||||
|
|
||||||
for m in re_manvolnum.finditer(content):
|
for m in re_manvolnum.finditer(content):
|
||||||
volnum = m.group(1)
|
volnum = m.group(1)
|
||||||
|
|
||||||
for m in re_refname.finditer(content):
|
for m in re_refname.finditer(content):
|
||||||
outfiles.append(m.group(1)+'.'+volnum)
|
outfiles.append(m.group(1)+'.'+volnum)
|
||||||
|
|
||||||
if not outfiles:
|
if not outfiles:
|
||||||
# Use stem of the source file
|
# Use stem of the source file
|
||||||
spath = str(s)
|
spath = str(s)
|
||||||
|
@ -720,14 +667,14 @@ def DocbookMan(env, target, source=None, *args, **kw):
|
||||||
else:
|
else:
|
||||||
# We have to completely rely on the given target name
|
# We have to completely rely on the given target name
|
||||||
outfiles.append(t)
|
outfiles.append(t)
|
||||||
|
|
||||||
__builder.__call__(env, outfiles[0], s, **kw)
|
__builder.__call__(env, outfiles[0], s, **kw)
|
||||||
env.Depends(outfiles[0], kw['DOCBOOK_XSL'])
|
env.Depends(outfiles[0], kw['DOCBOOK_XSL'])
|
||||||
result.append(outfiles[0])
|
result.append(outfiles[0])
|
||||||
if len(outfiles) > 1:
|
if len(outfiles) > 1:
|
||||||
env.Clean(outfiles[0], outfiles[1:])
|
env.Clean(outfiles[0], outfiles[1:])
|
||||||
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def DocbookSlidesPdf(env, target, source=None, *args, **kw):
|
def DocbookSlidesPdf(env, target, source=None, *args, **kw):
|
||||||
|
@ -741,14 +688,14 @@ def DocbookSlidesPdf(env, target, source=None, *args, **kw):
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESPDF', ['slides','fo','plain.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESPDF', ['slides','fo','plain.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
for t,s in zip(target,source):
|
for t,s in zip(target,source):
|
||||||
t, stem = __ensure_suffix_stem(t, '.pdf')
|
t, stem = __ensure_suffix_stem(t, '.pdf')
|
||||||
xsl = __builder.__call__(env, stem+'.fo', s, **kw)
|
xsl = __builder.__call__(env, stem+'.fo', s, **kw)
|
||||||
env.Depends(xsl, kw['DOCBOOK_XSL'])
|
env.Depends(xsl, kw['DOCBOOK_XSL'])
|
||||||
result.extend(xsl)
|
result.extend(xsl)
|
||||||
result.extend(__fop_builder.__call__(env, t, xsl, **kw))
|
result.extend(__fop_builder.__call__(env, t, xsl, **kw))
|
||||||
|
|
||||||
|
@ -765,13 +712,13 @@ def DocbookSlidesHtml(env, target, source=None, *args, **kw):
|
||||||
source = target
|
source = target
|
||||||
target = ['index.html']
|
target = ['index.html']
|
||||||
elif not SCons.Util.is_List(source):
|
elif not SCons.Util.is_List(source):
|
||||||
source = [source]
|
source = [source]
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESHTML', ['slides','html','plain.xsl'])
|
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESHTML', ['slides','xhtml','plain.xsl'])
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Detect base dir
|
# Detect base dir
|
||||||
base_dir = kw.get('base_dir', '')
|
base_dir = kw.get('base_dir', '')
|
||||||
|
@ -797,13 +744,13 @@ def DocbookXInclude(env, target, source, *args, **kw):
|
||||||
target, source = __extend_targets_sources(target, source)
|
target, source = __extend_targets_sources(target, source)
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__xinclude_lxml_builder,__xinclude_libxml2_builder,__xmllint_builder)
|
__builder = __select_builder(__xinclude_lxml_builder,__xmllint_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
for t,s in zip(target,source):
|
for t,s in zip(target,source):
|
||||||
result.extend(__builder.__call__(env, t, s, **kw))
|
result.extend(__builder.__call__(env, t, s, **kw))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def DocbookXslt(env, target, source=None, *args, **kw):
|
def DocbookXslt(env, target, source=None, *args, **kw):
|
||||||
|
@ -812,13 +759,13 @@ def DocbookXslt(env, target, source=None, *args, **kw):
|
||||||
"""
|
"""
|
||||||
# Init list of targets/sources
|
# Init list of targets/sources
|
||||||
target, source = __extend_targets_sources(target, source)
|
target, source = __extend_targets_sources(target, source)
|
||||||
|
|
||||||
# Init XSL stylesheet
|
# Init XSL stylesheet
|
||||||
kw['DOCBOOK_XSL'] = kw.get('xsl', 'transform.xsl')
|
kw['DOCBOOK_XSL'] = kw.get('xsl', 'transform.xsl')
|
||||||
|
|
||||||
# Setup builder
|
# Setup builder
|
||||||
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
|
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||||
|
|
||||||
# Create targets
|
# Create targets
|
||||||
result = []
|
result = []
|
||||||
for t,s in zip(target,source):
|
for t,s in zip(target,source):
|
||||||
|
@ -842,18 +789,18 @@ def generate(env):
|
||||||
DOCBOOK_DEFAULT_XSL_MAN = '',
|
DOCBOOK_DEFAULT_XSL_MAN = '',
|
||||||
DOCBOOK_DEFAULT_XSL_SLIDESPDF = '',
|
DOCBOOK_DEFAULT_XSL_SLIDESPDF = '',
|
||||||
DOCBOOK_DEFAULT_XSL_SLIDESHTML = '',
|
DOCBOOK_DEFAULT_XSL_SLIDESHTML = '',
|
||||||
|
|
||||||
# Paths to the detected executables
|
# Paths to the detected executables
|
||||||
DOCBOOK_XSLTPROC = '',
|
DOCBOOK_XSLTPROC = '',
|
||||||
DOCBOOK_XMLLINT = '',
|
DOCBOOK_XMLLINT = '',
|
||||||
DOCBOOK_FOP = '',
|
DOCBOOK_FOP = '',
|
||||||
|
|
||||||
# Additional flags for the text processors
|
# Additional flags for the text processors
|
||||||
DOCBOOK_XSLTPROCFLAGS = SCons.Util.CLVar(''),
|
DOCBOOK_XSLTPROCFLAGS = SCons.Util.CLVar(''),
|
||||||
DOCBOOK_XMLLINTFLAGS = SCons.Util.CLVar(''),
|
DOCBOOK_XMLLINTFLAGS = SCons.Util.CLVar(''),
|
||||||
DOCBOOK_FOPFLAGS = SCons.Util.CLVar(''),
|
DOCBOOK_FOPFLAGS = SCons.Util.CLVar(''),
|
||||||
DOCBOOK_XSLTPROCPARAMS = SCons.Util.CLVar(''),
|
DOCBOOK_XSLTPROCPARAMS = SCons.Util.CLVar(''),
|
||||||
|
|
||||||
# Default command lines for the detected executables
|
# Default command lines for the detected executables
|
||||||
DOCBOOK_XSLTPROCCOM = xsltproc_com['xsltproc'],
|
DOCBOOK_XSLTPROCCOM = xsltproc_com['xsltproc'],
|
||||||
DOCBOOK_XMLLINTCOM = xmllint_com['xmllint'],
|
DOCBOOK_XMLLINTCOM = xmllint_com['xmllint'],
|
||||||
|
@ -863,7 +810,7 @@ def generate(env):
|
||||||
DOCBOOK_XSLTPROCCOMSTR = None,
|
DOCBOOK_XSLTPROCCOMSTR = None,
|
||||||
DOCBOOK_XMLLINTCOMSTR = None,
|
DOCBOOK_XMLLINTCOMSTR = None,
|
||||||
DOCBOOK_FOPCOMSTR = None,
|
DOCBOOK_FOPCOMSTR = None,
|
||||||
|
|
||||||
)
|
)
|
||||||
_detect(env)
|
_detect(env)
|
||||||
|
|
605
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.xml
Normal file
605
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.xml
Normal file
|
@ -0,0 +1,605 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
__COPYRIGHT__
|
||||||
|
|
||||||
|
This file is processed by the bin/SConsDoc.py module.
|
||||||
|
See its __doc__ string for a discussion of the format.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE sconsdoc [
|
||||||
|
<!ENTITY % scons SYSTEM '../../../doc/scons.mod'>
|
||||||
|
%scons;
|
||||||
|
<!ENTITY % builders-mod SYSTEM '../../../doc/generated/builders.mod'>
|
||||||
|
%builders-mod;
|
||||||
|
<!ENTITY % functions-mod SYSTEM '../../../doc/generated/functions.mod'>
|
||||||
|
%functions-mod;
|
||||||
|
<!ENTITY % tools-mod SYSTEM '../../../doc/generated/tools.mod'>
|
||||||
|
%tools-mod;
|
||||||
|
<!ENTITY % variables-mod SYSTEM '../../../doc/generated/variables.mod'>
|
||||||
|
%variables-mod;
|
||||||
|
]>
|
||||||
|
|
||||||
|
<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
|
||||||
|
|
||||||
|
<tool name="docbook">
|
||||||
|
<summary>
|
||||||
|
<para>This tool tries to make working with Docbook in SCons a little easier.
|
||||||
|
It provides several toolchains for creating different output formats,
|
||||||
|
like HTML or PDF. Contained in the package is
|
||||||
|
a distribution of the Docbook XSL stylesheets as of version 1.76.1.
|
||||||
|
As long as you don't specify your own stylesheets for customization,
|
||||||
|
these official versions are picked as default...which should reduce
|
||||||
|
the inevitable setup hassles for you.
|
||||||
|
</para>
|
||||||
|
<para>Implicit dependencies to images and XIncludes are detected automatically
|
||||||
|
if you meet the HTML requirements. The additional
|
||||||
|
stylesheet <filename>utils/xmldepend.xsl</filename> by Paul DuBois is used for this purpose.
|
||||||
|
</para>
|
||||||
|
<para>Note, that there is no support for XML catalog resolving offered! This tool calls
|
||||||
|
the XSLT processors and PDF renderers with the stylesheets you specified, that's it.
|
||||||
|
The rest lies in your hands and you still have to know what you're doing when
|
||||||
|
resolving names via a catalog.
|
||||||
|
</para>
|
||||||
|
<para>For activating the tool "docbook", you have to add its name to the Environment constructor,
|
||||||
|
like this
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
</screen>
|
||||||
|
<para>On its startup, the Docbook tool tries to find a required <literal>xsltproc</literal> processor, and
|
||||||
|
a PDF renderer, e.g. <literal>fop</literal>. So make sure that these are added to your system's environment
|
||||||
|
<literal>PATH</literal> and can be called directly, without specifying their full path.
|
||||||
|
</para>
|
||||||
|
<para>For the most basic processing of Docbook to HTML, you need to have installed
|
||||||
|
</para>
|
||||||
|
<itemizedlist><listitem><para>the Python <literal>lxml</literal> binding to <literal>libxml2</literal>, or
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem><para>a standalone XSLT processor, currently detected are <literal>xsltproc</literal>, <literal>saxon</literal>, <literal>saxon-xslt</literal>
|
||||||
|
and <literal>xalan</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>Rendering to PDF requires you to have one of the applications
|
||||||
|
<literal>fop</literal> or <literal>xep</literal> installed.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>Creating a HTML or PDF document is very simple and straightforward. Say
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml('manual.html', 'manual.xml')
|
||||||
|
env.DocbookPdf('manual.pdf', 'manual.xml')
|
||||||
|
</screen>
|
||||||
|
<para>to get both outputs from your XML source <filename>manual.xml</filename>. As a shortcut, you can
|
||||||
|
give the stem of the filenames alone, like this:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml('manual')
|
||||||
|
env.DocbookPdf('manual')
|
||||||
|
</screen>
|
||||||
|
<para>and get the same result. Target and source lists are also supported:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml(['manual.html','reference.html'], ['manual.xml','reference.xml'])
|
||||||
|
</screen>
|
||||||
|
<para>or even
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml(['manual','reference'])
|
||||||
|
</screen>
|
||||||
|
<important><para>Whenever you leave out the list of sources, you may not specify a file extension! The
|
||||||
|
Tool uses the given names as file stems, and adds the suffixes for target and source files
|
||||||
|
accordingly.
|
||||||
|
</para>
|
||||||
|
</important>
|
||||||
|
<para>The rules given above are valid for the Builders &b-link-DocbookHtml;,
|
||||||
|
&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the
|
||||||
|
&b-link-DocbookMan; transformation you
|
||||||
|
can specify a target name, but the actual output names are automatically
|
||||||
|
set from the <literal>refname</literal> entries in your XML source.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and
|
||||||
|
&b-link-DocbookSlidesHtml; are special, in that:
|
||||||
|
</para>
|
||||||
|
<orderedlist><listitem><para>they create a large set of files, where the exact names and their number depend
|
||||||
|
on the content of the source file, and
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem><para>the main target is always named <filename>index.html</filename>, i.e. the output name for the
|
||||||
|
XSL transformation is not picked up by the stylesheets.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</orderedlist>
|
||||||
|
<para>As a result, there is simply no use in specifying a target HTML name.
|
||||||
|
So the basic syntax for these builders is always:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlhelp('manual')
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
<para>If you want to use a specific XSL file, you can set the
|
||||||
|
additional <literal>xsl</literal> parameter to your
|
||||||
|
Builder call as follows:
|
||||||
|
</para>
|
||||||
|
<screen>env.DocbookHtml('other.html', 'manual.xml', xsl='html.xsl')
|
||||||
|
</screen>
|
||||||
|
<para>Since this may get tedious if you always use the same local naming for your customized XSL files,
|
||||||
|
e.g. <filename>html.xsl</filename> for HTML and <filename>pdf.xsl</filename> for PDF output, a set of
|
||||||
|
variables for setting the default XSL name is provided. These are:
|
||||||
|
</para>
|
||||||
|
<screen>DOCBOOK_DEFAULT_XSL_HTML
|
||||||
|
DOCBOOK_DEFAULT_XSL_HTMLCHUNKED
|
||||||
|
DOCBOOK_DEFAULT_XSL_HTMLHELP
|
||||||
|
DOCBOOK_DEFAULT_XSL_PDF
|
||||||
|
DOCBOOK_DEFAULT_XSL_EPUB
|
||||||
|
DOCBOOK_DEFAULT_XSL_MAN
|
||||||
|
DOCBOOK_DEFAULT_XSL_SLIDESPDF
|
||||||
|
DOCBOOK_DEFAULT_XSL_SLIDESHTML
|
||||||
|
</screen>
|
||||||
|
<para>and you can set them when constructing your environment:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'],
|
||||||
|
DOCBOOK_DEFAULT_XSL_HTML='html.xsl',
|
||||||
|
DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl')
|
||||||
|
env.DocbookHtml('manual') # now uses html.xsl
|
||||||
|
</screen>
|
||||||
|
</summary>
|
||||||
|
<sets>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_HTML</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_HTMLCHUNKED</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_HTMLHELP</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_PDF</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_EPUB</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_MAN</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_SLIDESPDF</item>
|
||||||
|
<item>DOCBOOK_DEFAULT_XSL_SLIDESHTML</item>
|
||||||
|
<item>DOCBOOK_XSLTPROC</item>
|
||||||
|
<item>DOCBOOK_XMLLINT</item>
|
||||||
|
<item>DOCBOOK_FOP</item>
|
||||||
|
<item>DOCBOOK_XSLTPROCFLAGS</item>
|
||||||
|
<item>DOCBOOK_XMLLINTFLAGS</item>
|
||||||
|
<item>DOCBOOK_FOPFLAGS</item>
|
||||||
|
<item>DOCBOOK_XSLTPROCPARAMS</item>
|
||||||
|
<item>DOCBOOK_XSLTPROCCOM</item>
|
||||||
|
<item>DOCBOOK_XMLLINTCOM</item>
|
||||||
|
<item>DOCBOOK_FOPCOM</item>
|
||||||
|
</sets>
|
||||||
|
<uses>
|
||||||
|
<item>DOCBOOK_XSLTPROCCOMSTR</item>
|
||||||
|
<item>DOCBOOK_XMLLINTCOMSTR</item>
|
||||||
|
<item>DOCBOOK_FOPCOMSTR</item>
|
||||||
|
</uses>
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_HTML">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookHtml; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_HTMLCHUNKED">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookHtmlChunked; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_HTMLHELP">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookHtmlhelp; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_PDF">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookPdf; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_EPUB">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookEpub; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_MAN">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookMan; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_SLIDESPDF">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookSlidesPdf; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_DEFAULT_XSL_SLIDESHTML">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The default XSLT file for the &b-link-DocbookSlidesHtml; builder within the
|
||||||
|
current environment, if no other XSLT gets specified via keyword.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XSLTPROC">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The path to the external executable <literal>xsltproc</literal>
|
||||||
|
(or <literal>saxon</literal>, <literal>xalan</literal>), if one of them
|
||||||
|
is installed.
|
||||||
|
Note, that this is only used as last fallback for XSL transformations, if
|
||||||
|
no lxml Python binding can be imported in the current system.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XMLLINT">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The path to the external executable <literal>xmllint</literal>, if it's installed.
|
||||||
|
Note, that this is only used as last fallback for resolving
|
||||||
|
XIncludes, if no lxml Python binding can be imported
|
||||||
|
in the current system.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_FOP">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The path to the PDF renderer <literal>fop</literal> or <literal>xep</literal>,
|
||||||
|
if one of them is installed (<literal>fop</literal> gets checked first).
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XSLTPROCFLAGS">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
Additonal command-line flags for the external executable
|
||||||
|
<literal>xsltproc</literal> (or <literal>saxon</literal>,
|
||||||
|
<literal>xalan</literal>).
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XMLLINTFLAGS">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
Additonal command-line flags for the external executable
|
||||||
|
<literal>xmllint</literal>.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_FOPFLAGS">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
Additonal command-line flags for the
|
||||||
|
PDF renderer <literal>fop</literal> or <literal>xep</literal>.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XSLTPROCPARAMS">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
Additonal parameters that are not intended for the XSLT processor executable, but
|
||||||
|
the XSL processing itself. By default, they get appended at the end of the command line
|
||||||
|
for <literal>saxon</literal> and <literal>saxon-xslt</literal>, respectively.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XSLTPROCCOM">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The full command-line for the external executable
|
||||||
|
<literal>xsltproc</literal> (or <literal>saxon</literal>,
|
||||||
|
<literal>xalan</literal>).
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XMLLINTCOM">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The full command-line for the external executable
|
||||||
|
<literal>xmllint</literal>.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_FOPCOM">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The full command-line for the
|
||||||
|
PDF renderer <literal>fop</literal> or <literal>xep</literal>.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XSLTPROCCOMSTR">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The string displayed when <literal>xsltproc</literal> is used to transform
|
||||||
|
an XML file via a given XSLT stylesheet.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_XMLLINTCOMSTR">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The string displayed when <literal>xmllint</literal> is used to resolve
|
||||||
|
XIncludes for a given XML file.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="DOCBOOK_FOPCOMSTR">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
The string displayed when a renderer like <literal>fop</literal> or
|
||||||
|
<literal>xep</literal> is used to create PDF output from an XML file.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<builder name="DocbookHtml">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for HTML output.
|
||||||
|
</para>
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml('manual.html', 'manual.xml')
|
||||||
|
</example_commands>
|
||||||
|
<para>
|
||||||
|
or simply
|
||||||
|
</para>
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtml('manual')
|
||||||
|
</example_commands>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookHtmlChunked">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for chunked HTML output.
|
||||||
|
It supports the <literal>base.dir</literal> parameter. The
|
||||||
|
<filename>chunkfast.xsl</filename> file (requires "EXSLT") is used as the
|
||||||
|
default stylesheet. Basic syntax:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlChunked('manual')
|
||||||
|
</example_commands>
|
||||||
|
<para>
|
||||||
|
where <filename>manual.xml</filename> is the input file.
|
||||||
|
</para>
|
||||||
|
<para>If you use the <literal>root.filename</literal>
|
||||||
|
parameter in your own stylesheets you have to specify the new target name.
|
||||||
|
This ensures that the dependencies get correct, especially for the cleanup via <quote><literal>scons -c</literal></quote>:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlChunked('mymanual.html', 'manual', xsl='htmlchunk.xsl')
|
||||||
|
</screen>
|
||||||
|
<para>Some basic support for the <literal>base.dir</literal> is provided. You
|
||||||
|
can add the <literal>base_dir</literal> keyword to your Builder
|
||||||
|
call, and the given prefix gets prepended to all the created filenames:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlChunked('manual', xsl='htmlchunk.xsl', base_dir='output/')
|
||||||
|
</screen>
|
||||||
|
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||||
|
your files get renamed only!
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookHtmlhelp">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for HTMLHELP output.
|
||||||
|
Its basic syntax is:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlhelp('manual')
|
||||||
|
</example_commands>
|
||||||
|
<para>
|
||||||
|
where <filename>manual.xml</filename> is the input file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>If you use the <literal>root.filename</literal>
|
||||||
|
parameter in your own stylesheets you have to specify the new target name.
|
||||||
|
This ensures that the dependencies get correct, especially for the cleanup via <quote><literal>scons -c</literal></quote>:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlhelp('mymanual.html', 'manual', xsl='htmlhelp.xsl')
|
||||||
|
</screen>
|
||||||
|
<para>Some basic support for the <literal>base.dir</literal> parameter
|
||||||
|
is provided. You can add the <literal>base_dir</literal> keyword to
|
||||||
|
your Builder call, and the given prefix gets prepended to all the
|
||||||
|
created filenames:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookHtmlhelp('manual', xsl='htmlhelp.xsl', base_dir='output/')
|
||||||
|
</screen>
|
||||||
|
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||||
|
your files get renamed only!
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookPdf">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for PDF output.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookPdf('manual.pdf', 'manual.xml')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
or simply
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookPdf('manual')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookEpub">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for EPUB output.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookEpub('manual.epub', 'manual.xml')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
or simply
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookEpub('manual')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookMan">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for Man page output.
|
||||||
|
Its basic syntax is:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookMan('manual')
|
||||||
|
</example_commands>
|
||||||
|
<para>
|
||||||
|
where <filename>manual.xml</filename> is the input file. Note, that
|
||||||
|
you can specify a target name, but the actual output names are automatically
|
||||||
|
set from the <literal>refname</literal> entries in your XML source.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookSlidesPdf">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for PDF slides output.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookSlidesPdf('manual.pdf', 'manual.xml')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
or simply
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookSlidesPdf('manual')
|
||||||
|
</example_commands>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookSlidesHtml">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, providing a Docbook toolchain for HTML slides output.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookSlidesHtml('manual')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
<para>If you use the <literal>titlefoil.html</literal> parameter in
|
||||||
|
your own stylesheets you have to give the new target name. This ensures
|
||||||
|
that the dependencies get correct, especially for the cleanup via
|
||||||
|
<quote><literal>scons -c</literal></quote>:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookSlidesHtml('mymanual.html','manual', xsl='slideshtml.xsl')
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
<para>Some basic support for the <literal>base.dir</literal> parameter
|
||||||
|
is provided. You
|
||||||
|
can add the <literal>base_dir</literal> keyword to your Builder
|
||||||
|
call, and the given prefix gets prepended to all the created filenames:
|
||||||
|
</para>
|
||||||
|
<screen>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookSlidesHtml('manual', xsl='slideshtml.xsl', base_dir='output/')
|
||||||
|
</screen>
|
||||||
|
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||||
|
your files get renamed only!
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookXInclude">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, for resolving XIncludes in a separate processing step.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookXInclude('manual_xincluded.xml', 'manual.xml')
|
||||||
|
</example_commands>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="DocbookXslt">
|
||||||
|
<summary>
|
||||||
|
<para>
|
||||||
|
A pseudo-Builder, applying a given XSL transformation to the input file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example_commands>env = Environment(tools=['docbook'])
|
||||||
|
env.DocbookXslt('manual_transformed.xml', 'manual.xml', xsl='transform.xslt')
|
||||||
|
</example_commands>
|
||||||
|
|
||||||
|
<para>Note, that this builder requires the <literal>xsl</literal> parameter
|
||||||
|
to be set.
|
||||||
|
</para>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
</sconsdoc>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue