diff options
author | Adam Gross <grossag@vmware.com> | 2020-11-06 17:46:12 (GMT) |
---|---|---|
committer | Adam Gross <grossag@vmware.com> | 2020-11-06 17:46:12 (GMT) |
commit | cc7b28e50655960e7aab2dd8581f427a0920bf38 (patch) | |
tree | 3c9e36a05f4069bf2e8699e351043254c3edd1da | |
parent | 450b28367cdcbf10f855e43e0571915ebf9f09ca (diff) | |
parent | ebe6e9b1b2fedbe3dd44c07aa2b6739d4079879e (diff) | |
download | SCons-cc7b28e50655960e7aab2dd8581f427a0920bf38.zip SCons-cc7b28e50655960e7aab2dd8581f427a0920bf38.tar.gz SCons-cc7b28e50655960e7aab2dd8581f427a0920bf38.tar.bz2 |
Merge branch 'master' into topic/grossag/newhashes
380 files changed, 3661 insertions, 3386 deletions
diff --git a/.appveyor/install.bat b/.appveyor/install.bat index 67a064d..3dea66a 100644 --- a/.appveyor/install.bat +++ b/.appveyor/install.bat @@ -3,7 +3,7 @@ for /F "tokens=*" %%g in ('C:\\%WINPYTHON%\\python.exe -c "import sys; print(sys REM use mingw 32 bit until #3291 is resolved set PATH=C:\\%WINPYTHON%;C:\\%WINPYTHON%\\Scripts;C:\\ProgramData\\chocolatey\\bin;C:\\MinGW\\bin;C:\\MinGW\\msys\\1.0\\bin;C:\\cygwin\\bin;C:\\msys64\\usr\\bin;C:\\msys64\\mingw64\\bin;%PATH% C:\\%WINPYTHON%\\python.exe -m pip install -U --progress-bar off pip setuptools wheel -C:\\%WINPYTHON%\\python.exe -m pip install -U --progress-bar off pypiwin32 coverage codecov +C:\\%WINPYTHON%\\python.exe -m pip install -U --progress-bar off coverage codecov set STATIC_DEPS=true & C:\\%WINPYTHON%\\python.exe -m pip install -U --progress-bar off lxml REM install 3rd party tools to test with choco install --allow-empty-checksums dmd ldc swig vswhere xsltproc winflexbison @@ -52,3 +52,7 @@ htmlcov # Mac junk **/.DS_Store + + +# SCons specific +*.1 diff --git a/.travis.yml b/.travis.yml index 263a7ea..10bc138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -92,3 +92,4 @@ jobs: - python scripts/scons.py - ls -l build/dist - python build/scons-local/scons.py --version + - ./.travis/verify_packages.sh diff --git a/.travis/verify_packages.sh b/.travis/verify_packages.sh new file mode 100755 index 0000000..de64a4f --- /dev/null +++ b/.travis/verify_packages.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -e +set -x + +retval=0 +expected_man_file_count=3 +echo "Checking wheel file" +wheel_man_files=$(unzip -l build/dist/SCons-*-py3-none-any.whl | grep -e '[a-z].1$' | wc -l | xargs) +echo "Number of manpage files: $wheel_man_files" + +echo "Checking tgz sdist package" +tgz_man_files=$(tar tvfz build/dist/SCons-*.tar.gz | grep -e '[a-z].1$' | wc -l |xargs) + +echo "Checking zip sdist package" +zip_man_files=$(unzip -l build/dist/SCons-*.zip | grep -e '[a-z].1$' | wc -l |xargs) + +if [[ $wheel_man_files != $expected_man_file_count ]]; then + echo "Manpages not in wheel" + retval=1 +fi + +if [[ $tgz_man_files != $expected_man_file_count ]]; then + echo "Manpages not in tgz sdist package" + retval=2 +fi + +if [[ $zip_man_files != $expected_man_file_count ]]; then + echo "Manpages not in zip sdist package" + retval=3 +fi + +exit $retval
\ No newline at end of file diff --git a/CHANGES.txt b/CHANGES.txt index 9abf2bf..2b23756 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -8,21 +8,83 @@ NOTE: The 4.0.0 Release of SCons dropped Python 2.7 Support RELEASE VERSION/DATE TO BE FILLED IN LATER - From John Doe: + From Joseph Brill: + - Internal MSVC and test updates: Rework the msvc installed versions cache so that it + is not exposed externally and update external references accordingly. + - Modify the MSCommon internal-use only debug logging records to contain the correct relative + file path when the debug function is called from outside the MSCommon module. + + From William Deegan: + - Fix yacc tool, not respecting YACC set at time of tool initialization. + - Refactor SCons.Tool to move all common shared and loadable module linking logic to SCons.Tool.linkCommon + - Remove pywin32 imports from SCons.Script.Main. No longer needed. + - Switch to use ctypes instead of pywin32 (requiring an extra pip install) - Fixes Github Issue #2291 + - pywin32 no longer necessary for SCons install. (pip install SCons will no longer also require pywin32 on win32) + - Remove pywin32 usage from SCons.Util where it was used for accessing the registry. Python native winreg + library already includes this functionality. + - Remove using pywin32 to retrieve peak memory usage on Win32 for `--debug=memory` + - Fix Issue #3759 - include scons.1, sconsign.1, scons-time.1 manpages in sdist and wheel packages. + - Change SCons's build so the generated `SCons/__init__.py` is no longer removed by `scons -c` - - Whatever John Doe did. + + From Michał Górny: + - Fix dvipdf test failure due to passing incorrect flag to dvipdf. From Adam Gross: - Fix minor bug affecting SCons.Node.FS.File.get_csig()'s usage of the MD5 chunksize. User-facing behavior does not change with this fix (GH Issue #3726). + - Fix occasional test failures caused by not being able to find a file or directory fixture + when running multiple tests with multiple jobs. - Added support for a new command-line parameter "--hash-format" to override the default hash format that SCons uses. It can also be set via SetOption('hash_format'). Supported values include md5, sha1, and sha256, but you can also use any other algorithm that is offered by your Python interpreter's hashlib package. + From Joachim Kuebart: + - Suppress missing SConscript deprecation warning if `must_exist=False` + is used. + + From Rocco Matano: + - Fix Zip tool to respect ZIPCOMSTR. Previously all zip builder calls would yield something + like zip(["test.zip"], ["zip_scons.py"]) and ignore ZIPCOMSTR if ZIPCOM and ZIPCOMSTR + weren't set after the Environment/Tool is initialized. (Explained in PR #3659) + + From Daniel Moody: + - Fix issue where java parsed a class incorrectly from lambdas used after a new. + From Mats Wichmann: - Complete tests for Dictionary, env.keys() and env.values() for OverrideEnvironment. Enable env.setdefault() method, add tests. + - Raise an error if an option (not otherwise consumed) is used which + looks like an abbreviation of one one added by AddOption. (#3653) + - Tool module not found will now raise a UserError to more clearly indicate this is + probably an SConscript problem, and to make the traceback more relevant. + - Fix three issues with MergeFlags: + - Signature/return did not match documentation or existing usage - the implementation + now no longer returns the passed env + - merging --param arguments did not work (issue #3107); + - passing a dict to merge where the values are strings failed (issue #2961). + - Include previously-excluded SideEffect section in User Guide. + - Clean up unneeded imports (autoflake tool). + - Make sure cProfile is used if profiling - SCons was expecting + the Util module to monkeypatch in cProfile as profile if available, + but this is no longer being done. + - Cleanup in SCons.Util.AddMethod. If called with an environment instance + as the object to modify, the method would not be correctly set up in + any Clone of that instance. Now tries to detect this and calls + MethodWrapper to set up the method the same way env.AddMethod does. + MethodWrapper moved to Util to avoid a circular import. Fixes #3028. + - Some Python 2 compatibility code dropped + + From Simon Tegelid + - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command + with an action list like this: + ['${TEMPFILE("xxx.py -otempfile $SOURCE")}', '${TEMPFILE("yyy.py -o$TARGET tempfile")}'] + Could yield a single tempfile with the first TEMPFILE's contents, used by both steps + in the action list. + + + RELEASE 4.0.1 - Mon, 16 Jul 2020 16:06:40 -0700 diff --git a/MANIFEST.in b/MANIFEST.in index e509c38..04ec000 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,8 @@ recursive-include SCons/Tool/docbook * # For license file include LICENSE +include scons.1 sconsign.1 scons-time.1 +recursive-include build/doc/man *.1 diff --git a/README-SF.rst b/README-SF.rst index e33c3f1..fce28d9 100755 --- a/README-SF.rst +++ b/README-SF.rst @@ -48,8 +48,7 @@ Execution Requirements ====================== Running SCons requires Python 3.5 or higher. There should be no other -dependencies or requirements to run scons, although the pywin32 Python -package is strongly recommended if running on Windows systems. +dependencies or requirements to run scons. The default SCons configuration assumes use of the Microsoft Visual C++ compiler suite on Win32 systems, and assumes a C compiler named 'cc', a C++ diff --git a/README-package.rst b/README-package.rst index 605e5fe..4aaea1c 100755 --- a/README-package.rst +++ b/README-package.rst @@ -45,8 +45,7 @@ Requirements ------------ Running SCons requires Python 3.5 or higher. There should be no other -dependencies or requirements to run SCons, although the pywin32 Python -package is strongly recommended if running on Windows systems. +dependencies or requirements to run SCons. By default, SCons knows how to search for available programming tools on @@ -73,8 +73,7 @@ Execution Requirements ====================== Running SCons requires Python 3.5 or higher. There should be no other -dependencies or requirements to run scons, although the pywin32 Python -package is strongly recommended if running on Windows systems. +dependencies or requirements to run scons The default SCons configuration assumes use of the Microsoft Visual C++ compiler suite on Win32 systems, and assumes a C compiler named 'cc', a C++ @@ -98,33 +97,20 @@ Nothing special. Executing SCons Without Installing ================================== -You can execute the local SCons directly from the SCons subdirectory by first -setting the SCONS_LIB_DIR environment variable to the local SCons -subdirectory, and then executing the local scripts/scons.py script to -populate the build/scons/ subdirectory. You would do this as follows on a -Linux or UNIX system (using sh or a derivative like bash or ksh):: +You can execute the SCons directly from this repository. For Linux or UNIX:: - $ setenv MYSCONS=`pwd` - $ python $MYSCONS/scripts/scons.py [arguments] + $ python scripts/scons.py [arguments] Or on Windows:: - C:\scons>set MYSCONS=%cd% - C:\scons>python %MYSCONS%\scripts\scons.py [arguments] - -An alternative approach is to skip the above and use:: - - $ python scripts/scons.py [arguments] + C:\scons>python scripts\scons.py [arguments] - -You can use the -C option to have SCons change directory to another location -where you already have a build configuration set up:: +If you run SCons this way, it will execute `SConstruct` file for this repo, +which will build and pack SCons itself. Use the -C option to change directory +to your project:: $ python scripts/scons.py -C /some/other/location [arguments] -For simplicity in the following examples, we will only show the bootstrap.py -approach. - Installation ============ diff --git a/SCons/Action.py b/SCons/Action.py index f29d6a7..fdb0463 100644 --- a/SCons/Action.py +++ b/SCons/Action.py @@ -1,11 +1,34 @@ -"""SCons.Action +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""SCons Actions. -This encapsulates information about executing any sort of action that +Information about executing any sort of action that can build one or more target Nodes (typically files) from one or more source Nodes (also typically files) given a specific Environment. The base class here is ActionBase. The base class supplies just a few -OO utility methods and some generic methods for displaying information +utility methods and some generic methods for displaying information about an Action in response to the various commands that control printing. A second-level base class is _ActionAction. This extends ActionBase @@ -60,7 +83,7 @@ this module: get_presig() Fetches the "contents" of a subclass for signature calculation. The varlist is added to this to produce the Action's contents. - TODO(?): Change this to always return ascii/bytes and not unicode (or py3 strings) + TODO(?): Change this to always return bytes and not str? strfunction() Returns a substituted string representation of the Action. @@ -77,29 +100,6 @@ way for wrapping up the functions. """ -# __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 pickle import re diff --git a/SCons/Action.xml b/SCons/Action.xml index 8263a57..0e3ef33 100644 --- a/SCons/Action.xml +++ b/SCons/Action.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/ActionTests.py b/SCons/ActionTests.py index 81dacfa..c03e87f 100644 --- a/SCons/ActionTests.py +++ b/SCons/ActionTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,13 +22,11 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - - # Define a null function and a null class for use as builder actions. # Where these are defined in the file seems to affect their byte-code # contents, so try to minimize changes by defining them here, before we # even import anything. + def GlobalFunc(): pass diff --git a/SCons/Builder.py b/SCons/Builder.py index d54ef24..a0df272 100644 --- a/SCons/Builder.py +++ b/SCons/Builder.py @@ -1,3 +1,26 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ SCons.Builder @@ -76,30 +99,6 @@ There are the following methods for internal use within this module: """ -# -# __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__" - from collections import UserDict, UserList import SCons.Action diff --git a/SCons/BuilderTests.py b/SCons/BuilderTests.py index 6dfefd5..0e46194 100644 --- a/SCons/BuilderTests.py +++ b/SCons/BuilderTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,8 +20,6 @@ # 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.compat @@ -1617,16 +1616,7 @@ class CompositeBuilderTestCase(unittest.TestCase): assert str(err) == expect, err if __name__ == "__main__": - suite = unittest.TestSuite() - tclasses = [ - BuilderTestCase, - CompositeBuilderTestCase - ] - for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests(list(map(tclass, names))) - - TestUnit.run(suite) + unittest.main() # Local Variables: # tab-width:4 diff --git a/SCons/CacheDir.py b/SCons/CacheDir.py index 3bb6671..879c21b 100644 --- a/SCons/CacheDir.py +++ b/SCons/CacheDir.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -__doc__ = """ -CacheDir support +"""CacheDir support """ import atexit diff --git a/SCons/CacheDirTests.py b/SCons/CacheDirTests.py index 798150f..c4a0ed7 100644 --- a/SCons/CacheDirTests.py +++ b/SCons/CacheDirTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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.path import shutil diff --git a/SCons/Conftest.py b/SCons/Conftest.py index 4491884..908713c 100644 --- a/SCons/Conftest.py +++ b/SCons/Conftest.py @@ -1,9 +1,6 @@ -"""SCons.Conftest - -Autoconf-like configuration support; low level implementation of tests. -""" - +# MIT License # +# Copyright The SCons Foundation # Copyright (c) 2003 Stichting NLnet Labs # Copyright (c) 2001, 2002, 2003 Steven Knight # @@ -25,80 +22,72 @@ Autoconf-like configuration support; low level implementation of tests. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# -# The purpose of this module is to define how a check is to be performed. -# Use one of the Check...() functions below. -# - -# -# A context class is used that defines functions for carrying out the tests, -# logging and messages. The following methods and members must be present: -# -# context.Display(msg) Function called to print messages that are normally -# displayed for the user. Newlines are explicitly used. -# The text should also be written to the logfile! -# -# context.Log(msg) Function called to write to a log file. -# -# context.BuildProg(text, ext) -# Function called to build a program, using "ext" for the -# file extention. Must return an empty string for -# success, an error message for failure. -# For reliable test results building should be done just -# like an actual program would be build, using the same -# command and arguments (including configure results so -# far). -# -# context.CompileProg(text, ext) -# Function called to compile a program, using "ext" for -# the file extention. Must return an empty string for -# success, an error message for failure. -# For reliable test results compiling should be done just -# like an actual source file would be compiled, using the -# same command and arguments (including configure results -# so far). -# -# context.AppendLIBS(lib_name_list) -# Append "lib_name_list" to the value of LIBS. -# "lib_namelist" is a list of strings. -# Return the value of LIBS before changing it (any type -# can be used, it is passed to SetLIBS() later.) -# -# context.PrependLIBS(lib_name_list) -# Prepend "lib_name_list" to the value of LIBS. -# "lib_namelist" is a list of strings. -# Return the value of LIBS before changing it (any type -# can be used, it is passed to SetLIBS() later.) -# -# context.SetLIBS(value) -# Set LIBS to "value". The type of "value" is what -# AppendLIBS() returned. -# Return the value of LIBS before changing it (any type -# can be used, it is passed to SetLIBS() later.) -# -# context.headerfilename -# Name of file to append configure results to, usually -# "confdefs.h". -# The file must not exist or be empty when starting. -# Empty or None to skip this (some tests will not work!). -# -# context.config_h (may be missing). If present, must be a string, which -# will be filled with the contents of a config_h file. -# -# context.vardict Dictionary holding variables used for the tests and -# stores results from the tests, used for the build -# commands. -# Normally contains "CC", "LIBS", "CPPFLAGS", etc. -# -# context.havedict Dictionary holding results from the tests that are to -# be used inside a program. -# Names often start with "HAVE_". These are zero -# (feature not present) or one (feature present). Other -# variables may have any value, e.g., "PERLVERSION" can -# be a number and "SYSTEMNAME" a string. -# +"""Autoconf-like configuration support + +The purpose of this module is to define how a check is to be performed. + +A context class is used that defines functions for carrying out the tests, +logging and messages. The following methods and members must be present: + +context.Display(msg) + Function called to print messages that are normally displayed + for the user. Newlines are explicitly used. The text should + also be written to the logfile! + +context.Log(msg) + Function called to write to a log file. + +context.BuildProg(text, ext) + Function called to build a program, using "ext" for the file + extension. Must return an empty string for success, an error + message for failure. For reliable test results building should + be done just like an actual program would be build, using the + same command and arguments (including configure results so far). + +context.CompileProg(text, ext) + Function called to compile a program, using "ext" for the file + extension. Must return an empty string for success, an error + message for failure. For reliable test results compiling should be + done just like an actual source file would be compiled, using the + same command and arguments (including configure results so far). + +context.AppendLIBS(lib_name_list) + Append "lib_name_list" to the value of LIBS. "lib_namelist" is + a list of strings. Return the value of LIBS before changing it + (any type can be used, it is passed to SetLIBS() later.) + +context.PrependLIBS(lib_name_list) + Prepend "lib_name_list" to the value of LIBS. "lib_namelist" is + a list of strings. Return the value of LIBS before changing it + (any type can be used, it is passed to SetLIBS() later.) + +context.SetLIBS(value) + Set LIBS to "value". The type of "value" is what AppendLIBS() + returned. Return the value of LIBS before changing it (any type + can be used, it is passed to SetLIBS() later.) + +context.headerfilename + Name of file to append configure results to, usually "confdefs.h". + The file must not exist or be empty when starting. Empty or None + to skip this (some tests will not work!). + +context.config_h (may be missing). + If present, must be a string, which will be filled with the + contents of a config_h file. + +context.vardict + Dictionary holding variables used for the tests and stores results + from the tests, used for the build commands. Normally contains + "CC", "LIBS", "CPPFLAGS", etc. + +context.havedict + Dictionary holding results from the tests that are to be used + inside a program. Names often start with "HAVE_". These are zero + (feature not present) or one (feature present). Other variables + may have any value, e.g., "PERLVERSION" can be a number and + "SYSTEMNAME" a string. +""" import re diff --git a/SCons/Debug.py b/SCons/Debug.py index 2212eb8..2310cb7 100644 --- a/SCons/Debug.py +++ b/SCons/Debug.py @@ -1,15 +1,6 @@ -"""SCons.Debug - -Code for debugging SCons internal things. Shouldn't be -needed by most users. Quick shortcuts: - -from SCons.Debug import caller_trace -caller_trace() - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -29,9 +20,14 @@ caller_trace() # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Code for debugging SCons internal things. + +Shouldn't be needed by most users. Quick shortcuts: + +from SCons.Debug import caller_trace +caller_trace() +""" import atexit import os @@ -94,7 +90,6 @@ def dumpLoggedInstances(classes, file=sys.stdout): file.write(' %20s : %s\n' % (key, value)) - if sys.platform[:5] == "linux": # Linux doesn't actually support memory usage stats from getrusage(). def memory(): @@ -106,28 +101,23 @@ elif sys.platform[:6] == 'darwin': #TODO really get memory stats for OS X def memory(): return 0 +elif sys.platform == 'win32': + from SCons.compat.win32 import get_peak_memory_usage + memory = get_peak_memory_usage else: try: import resource except ImportError: - try: - import win32process - import win32api - except ImportError: - def memory(): - return 0 - else: - def memory(): - process_handle = win32api.GetCurrentProcess() - memory_info = win32process.GetProcessMemoryInfo( process_handle ) - return memory_info['PeakWorkingSetSize'] + def memory(): + return 0 else: def memory(): res = resource.getrusage(resource.RUSAGE_SELF) return res[4] -# returns caller's stack + def caller_stack(): + """return caller's stack""" import traceback tb = traceback.extract_stack() # strip itself and the caller from the output diff --git a/SCons/Defaults.py b/SCons/Defaults.py index 20ded91..6a87787 100644 --- a/SCons/Defaults.py +++ b/SCons/Defaults.py @@ -1,16 +1,6 @@ -"""SCons.Defaults - -Builders and other things for the local site. Here's where we'll -duplicate the functionality of autoconf until we move it into the -installation procedure or use something like qmconf. - -The code that reads the registry to find MSVC components was borrowed -from distutils.msvccompiler. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -30,9 +20,15 @@ from distutils.msvccompiler. # 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__" +"""Builders and other things for the local site. + +Here's where we'll duplicate the functionality of autoconf until we +move it into the installation procedure or use something like qmconf. + +The code that reads the registry to find MSVC components was borrowed +from distutils.msvccompiler. +""" import os import errno @@ -58,9 +54,7 @@ _default_env = None # Lazily instantiate the default environment so the overhead of creating # it doesn't apply when it's not needed. def _fetch_DefaultEnvironment(*args, **kw): - """ - Returns the already-created default construction environment. - """ + """Returns the already-created default construction environment.""" global _default_env return _default_env diff --git a/SCons/Defaults.xml b/SCons/Defaults.xml index 8f3fe12..6b034d9 100644 --- a/SCons/Defaults.xml +++ b/SCons/Defaults.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/DefaultsTests.py b/SCons/DefaultsTests.py index 34941bc..97dab84 100644 --- a/SCons/DefaultsTests.py +++ b/SCons/DefaultsTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,14 +20,10 @@ # 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.compat import os -import sys import unittest import TestCmd diff --git a/SCons/Environment.py b/SCons/Environment.py index 2b3add0..0bf5079 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1,16 +1,6 @@ -"""SCons.Environment - -Base class for construction Environments. These are -the primary objects used to communicate dependency and -construction information to the build engine. - -Keyword arguments supplied when the construction Environment -is created are construction variables used to initialize the -Environment -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -31,8 +21,14 @@ Environment # 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__" +"""Base class for construction Environments. + +These are the primary objects used to communicate dependency and +construction information to the build engine. +Keyword arguments supplied when the construction Environment is created +are construction variables used to initialize the Environment. +""" import copy import os @@ -58,6 +54,7 @@ import SCons.SConsign import SCons.Subst import SCons.Tool import SCons.Util +from SCons.Util import MethodWrapper import SCons.Warnings class _Null: @@ -184,48 +181,17 @@ def _delete_duplicates(l, keep_last): # Shannon at the following page (there called the "transplant" class): # # ASPN : Python Cookbook : Dynamically added methods to a class -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 +# https://code.activestate.com/recipes/81732/ # # We had independently been using the idiom as BuilderWrapper, but # factoring out the common parts into this base class, and making # BuilderWrapper a subclass that overrides __call__() to enforce specific # Builder calling conventions, simplified some of our higher-layer code. +# +# Note: MethodWrapper moved to SCons.Util as it was needed there +# and otherwise we had a circular import problem. -class MethodWrapper: - """ - A generic Wrapper class that associates a method (which can - actually be any callable) with an object. As part of creating this - MethodWrapper object an attribute with the specified (by default, - the name of the supplied method) is added to the underlying object. - When that new "method" is called, our __call__() method adds the - object as the first argument, simulating the Python behavior of - supplying "self" on method calls. - - We hang on to the name by which the method was added to the underlying - base class so that we can provide a method to "clone" ourselves onto - a new underlying object being copied (without which we wouldn't need - to save that info). - """ - def __init__(self, object, method, name=None): - if name is None: - name = method.__name__ - self.object = object - self.method = method - self.name = name - setattr(self.object, name, self) - - def __call__(self, *args, **kwargs): - nargs = (self.object,) + args - return self.method(*nargs, **kwargs) - - def clone(self, new_object): - """ - Returns an object that re-binds the underlying "method" to - the specified new object. - """ - return self.__class__(new_object, self.method, self.name) - -class BuilderWrapper(MethodWrapper): +class BuilderWrapper(SCons.Util.MethodWrapper): """ A MethodWrapper subclass that that associates an environment with a Builder. @@ -252,7 +218,7 @@ class BuilderWrapper(MethodWrapper): target = [target] if source is not None and not SCons.Util.is_List(source): source = [source] - return MethodWrapper.__call__(self, target, source, *args, **kw) + return super().__call__(target, source, *args, **kw) def __repr__(self): return '<BuilderWrapper %s>' % repr(self.name) @@ -642,17 +608,23 @@ class SubstitutionEnvironment: else: overrides[key] = SCons.Subst.scons_subst_once(value, self, key) env = OverrideEnvironment(self, overrides) - if merges: env.MergeFlags(merges) + if merges: + env.MergeFlags(merges) return env def ParseFlags(self, *flags): - """ - Parse the set of flags and return a dict with the flags placed - in the appropriate entry. The flags are treated as a typical - set of command-line flags for a GNU-like toolchain and used to - populate the entries in the dict immediately below. If one of - the flag strings begins with a bang (exclamation mark), it is - assumed to be a command and the rest of the string is executed; + """Return a dict of parsed flags. + + Parse ``flags`` and return a dict with the flags distributed into + the appropriate construction variable names. The flags are treated + as a typical set of command-line flags for a GNU-like toolchain, + such as might have been generated by one of the \*-config scripts, + and used to populate the entries based on knowledge embedded in + this method - the choices are not expected to be portable to other + toolchains. + + If one of the ``flags`` strings begins with a bang (exclamation mark), + it is assumed to be a command and the rest of the string is executed; the result of that evaluation is then added to the dict. """ dict = { @@ -741,6 +713,9 @@ class SubstitutionEnvironment: t = ('-arch', arg) dict['CCFLAGS'].append(t) dict['LINKFLAGS'].append(t) + elif append_next_arg_to == '--param': + t = ('--param', arg) + dict['CCFLAGS'].append(t) else: dict[append_next_arg_to].append(arg) append_next_arg_to = None @@ -792,11 +767,13 @@ class SubstitutionEnvironment: dict['FRAMEWORKPATH'].append(arg[2:]) else: append_next_arg_to = 'FRAMEWORKPATH' - elif arg in ['-mno-cygwin', - '-pthread', - '-openmp', - '-fmerge-all-constants', - '-fopenmp']: + elif arg in [ + '-mno-cygwin', + '-pthread', + '-openmp', + '-fmerge-all-constants', + '-fopenmp', + ]: dict['CCFLAGS'].append(arg) dict['LINKFLAGS'].append(arg) elif arg == '-mwindows': @@ -810,7 +787,16 @@ class SubstitutionEnvironment: elif arg[0] == '+': dict['CCFLAGS'].append(arg) dict['LINKFLAGS'].append(arg) - elif arg in ['-include', '-imacros', '-isysroot', '-isystem', '-iquote', '-idirafter', '-arch']: + elif arg in [ + '-include', + '-imacros', + '-isysroot', + '-isystem', + '-iquote', + '-idirafter', + '-arch', + '--param', + ]: append_next_arg_to = arg else: dict['CCFLAGS'].append(arg) @@ -819,24 +805,30 @@ class SubstitutionEnvironment: do_parse(arg) return dict - def MergeFlags(self, args, unique=1, dict=None): - """ - Merge the dict in args into the construction variables of this - env, or the passed-in dict. If args is not a dict, it is - converted into a dict using ParseFlags. If unique is not set, - the flags are appended rather than merged. - """ + def MergeFlags(self, args, unique=True): + """Merge flags into construction variables. + + Merges the flags from ``args`` into this construction environent. + If ``args`` is not a dict, it is first converted to a dictionary with + flags distributed into appropriate construction variables. + See :meth:`ParseFlags`. + + Args: + args: flags to merge + unique: merge flags rather than appending (default: True) - if dict is None: - dict = self + """ if not SCons.Util.is_Dict(args): args = self.ParseFlags(args) + if not unique: self.Append(**args) - return self + return + for key, value in args.items(): if not value: continue + value = SCons.Util.Split(value) try: orig = self[key] except KeyError: @@ -873,7 +865,6 @@ class SubstitutionEnvironment: if v not in t: t.insert(0, v) self[key] = t - return self def default_decide_source(dependency, target, prev_ni, repo_node=None): @@ -1012,7 +1003,8 @@ class Base(SubstitutionEnvironment): self._dict[key] = val # Finally, apply any flags to be merged in - if parse_flags: self.MergeFlags(parse_flags) + if parse_flags: + self.MergeFlags(parse_flags) ####################################################################### # Utility methods that are primarily for internal use by SCons. @@ -1164,9 +1156,7 @@ class Base(SubstitutionEnvironment): ####################################################################### def Append(self, **kw): - """Append values to existing construction variables - in an Environment. - """ + """Append values to existing construction variables in an Environment.""" kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): # It would be easier on the eyes to write this using @@ -1453,7 +1443,8 @@ class Base(SubstitutionEnvironment): clone.Replace(**new) # Finally, apply any flags to be merged in - if parse_flags: clone.MergeFlags(parse_flags) + if parse_flags: + clone.MergeFlags(parse_flags) if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone') return clone @@ -1608,7 +1599,7 @@ class Base(SubstitutionEnvironment): if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: return path - def ParseConfig(self, command, function=None, unique=1): + def ParseConfig(self, command, function=None, unique=True): """ Use the specified function to parse the output of the command in order to modify the current environment. The 'command' can @@ -1628,7 +1619,7 @@ class Base(SubstitutionEnvironment): command = self.subst(command) return function(self, self.backtick(command)) - def ParseDepends(self, filename, must_exist=None, only_one=0): + def ParseDepends(self, filename, must_exist=None, only_one=False): """ Parse a mkdep-style file for explicit dependencies. This is completely abusable, and should be unnecessary in the "normal" @@ -2354,7 +2345,7 @@ class OverrideEnvironment(Base): # 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)): + if isinstance(attr, MethodWrapper): return attr.clone(self) else: return attr diff --git a/SCons/Environment.xml b/SCons/Environment.xml index 08df523..7d3927b 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. @@ -286,31 +286,22 @@ until the Action object is actually used. </arguments> <summary> <para> -When called with the -<function>AddMethod</function>() -form, -adds the specified -<parameter>function</parameter> -to the specified -<parameter>object</parameter> -as the specified method -<parameter>name</parameter>. -When called using the -&f-env-AddMethod; form, -adds the specified -<parameter>function</parameter> -to the construction environment -<replaceable>env</replaceable> -as the specified method -<parameter>name</parameter>. -In both cases, if -<parameter>name</parameter> -is omitted or -<constant>None</constant>, -the name of the -specified -<parameter>function</parameter> -itself is used for the method name. +Adds <parameter>function</parameter> to an object as a method. +<parameter>function</parameter> will be called with an instance +object as the first argument as for other methods. +If <parameter>name</parameter> is given, it is used as +the name of the new method, else the name of +<parameter>function</parameter> is used. +</para> +<para> +When the global function &f-AddMethod; is called, +the object to add the method to must be passed as the first argument; +typically this will be &Environment;, +in order to create a method which applies to all &consenvs; +subsequently constructed. +When called using the &f-env-AddMethod; form, +the method is added to the specified &consenv; only. +Added methods propagate through &f-env-Clone; calls. </para> <para> @@ -318,22 +309,17 @@ Examples: </para> <example_commands> -# Note that the first argument to the function to -# be attached as a method must be the object through -# which the method will be called; the Python -# convention is to call it 'self'. +# Function to add must accept an instance argument. +# The Python convention is to call this 'self'. def my_method(self, arg): print("my_method() got", arg) -# Use the global AddMethod() function to add a method -# to the Environment class. This +# Use the global function to add a method to the Environment class: AddMethod(Environment, my_method) env = Environment() env.my_method('arg') -# Add the function as a method, using the function -# name for the method call. -env = Environment() +# Use the optional name argument to set the name of the method: env.AddMethod(my_method, 'other_method_name') env.other_method_name('another arg') </example_commands> @@ -3174,8 +3160,8 @@ def create(target, source, env): # A function that will write a 'prefix=$SOURCE' # string into the file name specified as the # $TARGET. - f = open(str(target[0]), 'wb') - f.write('prefix=' + source[0].get_contents()) + with open(str(target[0]), 'wb') as f: + f.write('prefix=' + source[0].get_contents()) # Fetch the prefix= argument, if any, from the command # line, and use /usr/local as the default. @@ -3209,90 +3195,75 @@ env.UpdateValue(target = Value(output), source = Value(input)) </arguments> <summary> <para> -Use the -&f-VariantDir; -function to create a copy of your sources in another location: -if a name under -<parameter>variant_dir</parameter> -is not found but exists under -<parameter>src_dir</parameter>, -the file or directory is copied to -<parameter>variant_dir</parameter>. -Target files can be built in a different directory -than the original sources by simply refering to the sources (and targets) -within the variant tree. -</para> - -<para> +Sets up an alternate build location. +When building in the <parameter>variant_dir</parameter>, +&SCons; backfills as needed with files from <parameter>src_dir</parameter> +to create a complete build directory. &f-VariantDir; can be called multiple times with the same <parameter>src_dir</parameter> to set up multiple builds with different options -(<parameter>variants</parameter>). +(<emphasis>variants</emphasis>). +</para> + +<para> The -<parameter>src_dir</parameter> -location must be in or underneath the SConstruct file's directory, and -<parameter>variant_dir</parameter> +<parameter>variant</parameter> +location must be in or underneath the project top directory, +and <parameter>src_dir</parameter> may not be underneath -<parameter>src_dir</parameter>. -<!-- -TODO: Can the above restrictions be clarified or relaxed? -TODO: The latter restriction is clearly not completely right; -TODO: src_dir = '.' works fine with a build dir under it. ---> +<parameter>variant_dir</parameter>. </para> <para> -The default behavior is for -&scons; -to physically duplicate the source files in the variant tree. +By default, &SCons; +physically duplicates the source files and SConscript files +as needed into the variant tree. Thus, a build performed in the variant tree is guaranteed to be identical to a build performed in the source tree even if intermediate source files are generated during the build, -or preprocessors or other scanners search for included files +or if preprocessors or other scanners search for included files relative to the source file, -or individual compilers or other invoked tools are hard-coded +or if individual compilers or other invoked tools are hard-coded to put derived files in the same directory as source files. +Only the files &SCons; calculates are needed for the build are +duplicated into <parameter>variant_dir</parameter>. </para> <para> If possible on the platform, -the duplication is performed by linking rather than copying; -see also the +the duplication is performed by linking rather than copying. +This behavior is affected by the <option>--duplicate</option> command-line option. -Moreover, only the files needed for the build are duplicated; -files and directories that are not used are not present in -<parameter>variant_dir</parameter>. </para> <para> -Duplicating the source tree may be disabled by setting the -<literal>duplicate</literal> +Duplicating the source files may be disabled by setting the +<parameter>duplicate</parameter> argument to -<literal>0</literal> -(zero). +<constant>False</constant>. This will cause -&scons; +&SCons; to invoke Builders using the path names of source files in <parameter>src_dir</parameter> and the path names of derived files within <parameter>variant_dir</parameter>. -This is always more efficient than -<literal>duplicate=1</literal>, -and is usually safe for most builds -(but see above for cases that may cause problems). +This is more efficient than +<literal>duplicate=True</literal>, +and is safe for most builds; +revert to <constant>True</constant> +if it causes problems. </para> <para> -Note that &f-VariantDir; -works most naturally with a subsidiary SConscript file. -However, you would then call the subsidiary SConscript file -not in the source directory, but in the +works most naturally with used with a subsidiary SConscript file. +The subsidiary SConscript file is called as if it +were in <parameter>variant_dir</parameter>, regardless of the value of -<literal>duplicate</literal>. +<parameter>duplicate</parameter>. This is how you tell &scons; which variant of a source tree to build: @@ -3322,15 +3293,11 @@ Examples: # use names in the build directory, not the source directory VariantDir('build', 'src', duplicate=0) Program('build/prog', 'build/source.c') -</example_commands> -<example_commands> # this builds both the source and docs in a separate subtree VariantDir('build', '.', duplicate=0) SConscript(dirs=['build/src','build/doc']) -</example_commands> -<example_commands> # same as previous example, but only uses SConscript SConscript(dirs='src', variant_dir='build/src', duplicate=0) SConscript(dirs='doc', variant_dir='build/doc', duplicate=0) diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index b8f18d5..53dd9a7 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,8 +20,6 @@ # 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.compat @@ -34,7 +33,13 @@ from collections import UserDict as UD, UserList as UL import TestCmd import TestUnit -from SCons.Environment import * +from SCons.Environment import ( + Environment, + NoSubstitutionProxy, + OverrideEnvironment, + SubstitutionEnvironment, + is_valid_construction_var, +) import SCons.Warnings def diff_env(env1, env2): @@ -722,7 +727,7 @@ sys.exit(0) r = env4.func2() assert r == 'func2-4', r - # Test that clones don't re-bind an attribute that the user + # Test that clones don't re-bind an attribute that the user set. env1 = Environment(FOO = '1') env1.AddMethod(func2) def replace_func2(): @@ -732,6 +737,18 @@ sys.exit(0) r = env2.func2() assert r == 'replace_func2', r + # Test clone rebinding if using global AddMethod. + env1 = Environment(FOO='1') + SCons.Util.AddMethod(env1, func2) + r = env1.func2() + assert r == 'func2-1', r + r = env1.func2('-xxx') + assert r == 'func2-1-xxx', r + env2 = env1.Clone(FOO='2') + r = env2.func2() + assert r == 'func2-2', r + + def test_Override(self): """Test overriding construction variables""" env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4) @@ -787,33 +804,36 @@ sys.exit(0) d = env.ParseFlags([]) assert d == empty, d - s = "-I/usr/include/fum -I bar -X\n" + \ - '-I"C:\\Program Files\\ASCEND\\include" ' + \ - "-L/usr/fax -L foo -lxxx -l yyy " + \ - '-L"C:\\Program Files\\ASCEND" -lascend ' + \ - "-Wa,-as -Wl,-link " + \ - "-Wl,-rpath=rpath1 " + \ - "-Wl,-R,rpath2 " + \ - "-Wl,-Rrpath3 " + \ - "-Wp,-cpp " + \ - "-std=c99 " + \ - "-std=c++0x " + \ - "-framework Carbon " + \ - "-frameworkdir=fwd1 " + \ - "-Ffwd2 " + \ - "-F fwd3 " + \ - "-dylib_file foo-dylib " + \ - "-pthread " + \ - "-fmerge-all-constants " +\ - "-fopenmp " + \ - "-mno-cygwin -mwindows " + \ - "-arch i386 -isysroot /tmp " + \ - "-iquote /usr/include/foo1 " + \ - "-isystem /usr/include/foo2 " + \ - "-idirafter /usr/include/foo3 " + \ - "-imacros /usr/include/foo4 " + \ - "+DD64 " + \ + s = ( + "-I/usr/include/fum -I bar -X " + '-I"C:\\Program Files\\ASCEND\\include" ' + "-L/usr/fax -L foo -lxxx -l yyy " + '-L"C:\\Program Files\\ASCEND" -lascend ' + "-Wa,-as -Wl,-link " + "-Wl,-rpath=rpath1 " + "-Wl,-R,rpath2 " + "-Wl,-Rrpath3 " + "-Wp,-cpp " + "-std=c99 " + "-std=c++0x " + "-framework Carbon " + "-frameworkdir=fwd1 " + "-Ffwd2 " + "-F fwd3 " + "-dylib_file foo-dylib " + "-pthread " + "-fmerge-all-constants " + "-fopenmp " + "-mno-cygwin -mwindows " + "-arch i386 -isysroot /tmp " + "-iquote /usr/include/foo1 " + "-isystem /usr/include/foo2 " + "-idirafter /usr/include/foo3 " + "-imacros /usr/include/foo4 " + "--param l1-cache-size=32 --param l2-cache-size=6144 " + "+DD64 " "-DFOO -DBAR=value -D BAZ " + ) d = env.ParseFlags(s) @@ -827,6 +847,7 @@ sys.exit(0) ('-isystem', '/usr/include/foo2'), ('-idirafter', '/usr/include/foo3'), ('-imacros', env.fs.File('/usr/include/foo4')), + ('--param', 'l1-cache-size=32'), ('--param', 'l2-cache-size=6144'), '+DD64'], repr(d['CCFLAGS']) assert d['CXXFLAGS'] == ['-std=c++0x'], repr(d['CXXFLAGS']) assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES'] @@ -852,24 +873,40 @@ sys.exit(0) def test_MergeFlags(self): - """Test the MergeFlags() method - """ + """Test the MergeFlags() method.""" + env = SubstitutionEnvironment() + # does not set flag if value empty env.MergeFlags('') assert 'CCFLAGS' not in env, env['CCFLAGS'] + # merges value if flag did not exist env.MergeFlags('-X') assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + + # avoid SubstitutionEnvironment for these, has no .Append method, + # which is needed for unique=False test + env = Environment(CCFLAGS=None) + # merge with existing but empty flag env.MergeFlags('-X') assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + # default Unique=True enforces no dupes + env.MergeFlags('-X') + assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + # Unique=False allows dupes + env.MergeFlags('-X', unique=False) + assert env['CCFLAGS'] == ['-X', '-X'], env['CCFLAGS'] - env = SubstitutionEnvironment(CCFLAGS=None) - env.MergeFlags('-Y') - assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS'] + # merge from a dict with list values + env = SubstitutionEnvironment(B='b') + env.MergeFlags({'A': ['aaa'], 'B': ['bb', 'bbb']}) + assert env['A'] == ['aaa'], env['A'] + assert env['B'] == ['b', 'bb', 'bbb'], env['B'] - env = SubstitutionEnvironment() - env.MergeFlags({'A':['aaa'], 'B':['bbb']}) + # issue #2961: merge from a dict with string values + env = SubstitutionEnvironment(B='b') + env.MergeFlags({'A': 'aaa', 'B': 'bb bbb'}) assert env['A'] == ['aaa'], env['A'] - assert env['B'] == ['bbb'], env['B'] + assert env['B'] == ['b', 'bb', 'bbb'], env['B'] # issue #3665: if merging dict which is a compound object # (i.e. value can be lists, etc.), the value object should not @@ -881,6 +918,7 @@ sys.exit(0) pass flags = {'CFLAGS': ['-pipe', '-pthread', '-g']} import copy + saveflags = copy.deepcopy(flags) env.MergeFlags(flags) self.assertEqual(flags, saveflags) @@ -1376,7 +1414,7 @@ def generate(env, **kw): env[k] = v def exists(env): - return 1 + return True """) env = self.TestEnvironment(tools = [('faketool', {'a':1, 'b':2, 'c':3})], @@ -1856,14 +1894,14 @@ def exists(env): test.write('xxx.py', """\ def exists(env): - 1 + return True def generate(env): env['XXX'] = 'one' """) test.write('yyy.py', """\ def exists(env): - 1 + return True def generate(env): env['YYY'] = 'two' """) @@ -2456,16 +2494,16 @@ f5: \ exc_caught = None try: env.Tool('does_not_exist') - except SCons.Errors.SConsEnvironmentError: + except SCons.Errors.UserError: exc_caught = 1 - assert exc_caught, "did not catch expected SConsEnvironmentError" + assert exc_caught, "did not catch expected UserError" exc_caught = None try: env.Tool('$NONE') - except SCons.Errors.SConsEnvironmentError: + except SCons.Errors.UserError: exc_caught = 1 - assert exc_caught, "did not catch expected SConsEnvironmentError" + assert exc_caught, "did not catch expected UserError" # Use a non-existent toolpath directory just to make sure we # can call Tool() with the keyword argument. @@ -2481,14 +2519,14 @@ f5: \ test.write('xxx.py', """\ def exists(env): - 1 + return True def generate(env): env['XXX'] = 'one' """) test.write('yyy.py', """\ def exists(env): - 1 + return True def generate(env): env['YYY'] = 'two' """) @@ -3951,16 +3989,7 @@ class EnvironmentVariableTestCase(unittest.TestCase): if __name__ == "__main__": - suite = unittest.TestSuite() - tclasses = [ SubstitutionTestCase, - BaseTestCase, - OverrideEnvironmentTestCase, - NoSubstitutionProxyTestCase, - EnvironmentVariableTestCase ] - for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests(list(map(tclass, names))) - TestUnit.run(suite) + unittest.main() # Local Variables: # tab-width:4 diff --git a/SCons/EnvironmentValues.py b/SCons/EnvironmentValues.py index aaa71d0..c5eb972 100644 --- a/SCons/EnvironmentValues.py +++ b/SCons/EnvironmentValues.py @@ -1,3 +1,26 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import re _is_valid_var = re.compile(r'[_a-zA-Z]\w*$') @@ -72,7 +95,6 @@ class EnvironmentValue: # 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 diff --git a/SCons/EnvironmentValuesTest.py b/SCons/EnvironmentValuesTest.py index 58ee9cf..074aa85 100644 --- a/SCons/EnvironmentValuesTest.py +++ b/SCons/EnvironmentValuesTest.py @@ -1,3 +1,26 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import unittest from SCons.EnvironmentValues import EnvironmentValues diff --git a/SCons/Errors.py b/SCons/Errors.py index 887afcf..42db072 100644 --- a/SCons/Errors.py +++ b/SCons/Errors.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,17 +20,13 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -"""SCons.Errors +"""SCons exception classes. -This file contains the exception classes used to handle internal -and user errors in SCons. +Used to handle internal and user errors in SCons. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import shutil import SCons.Util diff --git a/SCons/ErrorsTests.py b/SCons/ErrorsTests.py index d777ba1..cc63d9b 100644 --- a/SCons/ErrorsTests.py +++ b/SCons/ErrorsTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,13 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import errno -import os -import sys import unittest import SCons.Errors diff --git a/SCons/Executor.py b/SCons/Executor.py index f658229..005906f 100644 --- a/SCons/Executor.py +++ b/SCons/Executor.py @@ -1,12 +1,6 @@ -"""SCons.Executor - -A module for executing actions with specific lists of target and source -Nodes. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +20,8 @@ Nodes. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""Execute actions with specific lists of target and source Nodes.""" import collections diff --git a/SCons/ExecutorTests.py b/SCons/ExecutorTests.py index 41728ef..c43c450 100644 --- a/SCons/ExecutorTests.py +++ b/SCons/ExecutorTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Executor diff --git a/SCons/Job.py b/SCons/Job.py index 4e2f68c..f87a3bb 100644 --- a/SCons/Job.py +++ b/SCons/Job.py @@ -1,13 +1,6 @@ -"""SCons.Job - -This module defines the Serial and Parallel classes that execute tasks to -complete a build. The Jobs class provides a higher level interface to start, -stop, and wait on jobs. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,9 +20,12 @@ stop, and wait on jobs. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Serial and Parallel classes to execute build tasks. + +The Jobs class provides a higher level interface to start, +stop, and wait on jobs. +""" import SCons.compat diff --git a/SCons/JobTests.py b/SCons/JobTests.py index 7fc969b..5b5a590 100644 --- a/SCons/JobTests.py +++ b/SCons/JobTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,8 +21,6 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import unittest import random import math @@ -211,7 +210,7 @@ class Taskmaster: try: import threading self.guard = threading.Lock() - except: + except ImportError: self.guard = DummyLock() # keep track of the order tasks are begun in @@ -255,7 +254,7 @@ class ParallelTestCase(unittest.TestCase): try: import threading - except: + except ImportError: raise NoThreadsException() taskmaster = Taskmaster(num_tasks, self, RandomTask) diff --git a/SCons/Memoize.py b/SCons/Memoize.py index 9d6bc51..8c3303f 100644 --- a/SCons/Memoize.py +++ b/SCons/Memoize.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,10 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -__doc__ = """Memoizer +"""Decorator-based memoizer to count caching stats. A decorator-based implementation to count hits and misses of the computed values that various methods cache in memory. diff --git a/SCons/MemoizeTests.py b/SCons/MemoizeTests.py index f1e5550..7830d99 100644 --- a/SCons/MemoizeTests.py +++ b/SCons/MemoizeTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Memoize diff --git a/SCons/Node/Alias.py b/SCons/Node/Alias.py index 00e3726..b5e4eb4 100644 --- a/SCons/Node/Alias.py +++ b/SCons/Node/Alias.py @@ -1,14 +1,6 @@ - -"""scons.Node.Alias - -Alias nodes. - -This creates a hash of global Aliases (dummy targets). - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,11 @@ This creates a hash of global Aliases (dummy targets). # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Alias nodes. + +This creates a hash of global Aliases (dummy targets). +""" import collections diff --git a/SCons/Node/AliasTests.py b/SCons/Node/AliasTests.py index 613a5c0..14662fd 100644 --- a/SCons/Node/AliasTests.py +++ b/SCons/Node/AliasTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Errors diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index bf0598b..1e5d5b8 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -1,17 +1,6 @@ -"""scons.Node.FS - -File system nodes. - -These Nodes represent the canonical external objects that people think -of when they think of building software: files and directories. - -This holds a "default_fs" variable that should be initialized with an FS -that can be used by scripts or modules looking for the canonical default. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -31,7 +20,15 @@ that can be used by scripts or modules looking for the canonical default. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""File system nodes. + +These Nodes represent the canonical external objects that people think +of when they think of building software: files and directories. + +This holds a "default_fs" variable that should be initialized with an FS +that can be used by scripts or modules looking for the canonical default. +""" import fnmatch import os @@ -46,7 +43,7 @@ import importlib.util import SCons.Action import SCons.Debug -from SCons.Debug import logInstanceCreation +from SCons.Debug import logInstanceCreation, Trace import SCons.Errors import SCons.Memoize import SCons.Node @@ -56,8 +53,6 @@ import SCons.Util from SCons.Util import hash_signature, hash_file_signature, hash_collect import SCons.Warnings -from SCons.Debug import Trace - print_duplicate = 0 MD5_TIMESTAMP_DEBUG = False @@ -439,7 +434,7 @@ class EntryProxy(SCons.Util.Proxy): # In PY3 if a class defines __eq__, then it must explicitly provide # __hash__. Since SCons.Util.Proxy provides __eq__ we need the following - # see: https://docs.python.org/3.1/reference/datamodel.html#object.__hash__ + # see: https://docs.python.org/3/reference/datamodel.html#object.__hash__ __hash__ = SCons.Util.Delegate('__hash__') def __get_abspath(self): diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py index 85f9f0e..457d199 100644 --- a/SCons/Node/FSTests.py +++ b/SCons/Node/FSTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.compat - import os import os.path import sys @@ -1694,7 +1692,6 @@ class FSTestCase(_tempdirTestCase): except AttributeError: # could be python 3.7 or newer, make sure splitdrive can do UNC assert ntpath.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive' - pass path = strip_slash(path) return '//' + path[1:] diff --git a/SCons/Node/NodeTests.py b/SCons/Node/NodeTests.py index 729be01..6e240d4 100644 --- a/SCons/Node/NodeTests.py +++ b/SCons/Node/NodeTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,14 +21,10 @@ # 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.compat import collections -import os import re -import sys import unittest import SCons.Errors diff --git a/SCons/Node/Python.py b/SCons/Node/Python.py index 68c6ee8..0eab05c 100644 --- a/SCons/Node/Python.py +++ b/SCons/Node/Python.py @@ -1,11 +1,6 @@ -"""scons.Node.Python - -Python nodes. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ Python nodes. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Python nodes.""" import SCons.Node @@ -135,7 +129,7 @@ class Value(SCons.Node.Node): self.built_value = self.value return self.built_value - def get_text_contents(self): + def get_text_contents(self) -> str: """By the assumption that the node.built_value is a deterministic product of the sources, the contents of a Value are the concatenation of all the contents of its sources. As @@ -147,24 +141,16 @@ class Value(SCons.Node.Node): contents = contents + kid.get_contents().decode() return contents - def get_contents(self): - """ - Get contents for signature calculations. - :return: bytes - """ - text_contents = self.get_text_contents() - try: - return text_contents.encode() - except UnicodeDecodeError: - # Already encoded as python2 str are bytes - return text_contents + def get_contents(self) -> bytes: + """Get contents for signature calculations.""" + return self.get_text_contents().encode() def changed_since_last_build(self, target, prev_ni): cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: - return 1 + return True def get_csig(self, calc=None): """Because we're a Python value node and don't have a real diff --git a/SCons/Node/PythonTests.py b/SCons/Node/PythonTests.py index b6fa859..b6a3f79 100644 --- a/SCons/Node/PythonTests.py +++ b/SCons/Node/PythonTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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 unittest diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index d64a468..6a3770e 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -1,26 +1,6 @@ -"""SCons.Node - -The Node package for the SCons software construction utility. - -This is, in many ways, the heart of SCons. - -A Node is where we encapsulate all of the dependency information about -any thing that SCons can build, or about any thing which SCons can use -to build some other thing. The canonical "thing," of course, is a file, -but a Node can also represent something remote (like a web page) or -something completely abstract (like an Alias). - -Each specific type of "thing" is specifically represented by a subclass -of the Node base class: Node.FS.File for files, Node.Alias for aliases, -etc. Dependency information is kept here in the base class, and -information specific to files/aliases/etc. is in the subclass. The -goal, if we've done this correctly, is that any type of "thing" should -be able to depend on any other type of "thing." - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -41,9 +21,25 @@ be able to depend on any other type of "thing." # 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__" +"""The Node package for the SCons software construction utility. + +This is, in many ways, the heart of SCons. + +A Node is where we encapsulate all of the dependency information about +any thing that SCons can build, or about any thing which SCons can use +to build some other thing. The canonical "thing," of course, is a file, +but a Node can also represent something remote (like a web page) or +something completely abstract (like an Alias). + +Each specific type of "thing" is specifically represented by a subclass +of the Node base class: Node.FS.File for files, Node.Alias for aliases, +etc. Dependency information is kept here in the base class, and +information specific to files/aliases/etc. is in the subclass. The +goal, if we've done this correctly, is that any type of "thing" should +be able to depend on any other type of "thing." + +""" -import os import collections import copy from itertools import chain @@ -823,25 +819,21 @@ class Node(object, metaclass=NoSlotsPyPy): def release_target_info(self): """Called just after this node has been marked - up-to-date or was built completely. + up-to-date or was built completely. - This is where we try to release as many target node infos - as possible for clean builds and update runs, in order - to minimize the overall memory consumption. + This is where we try to release as many target node infos + as possible for clean builds and update runs, in order + to minimize the overall memory consumption. - By purging attributes that aren't needed any longer after - a Node (=File) got built, we don't have to care that much how - many KBytes a Node actually requires...as long as we free - the memory shortly afterwards. + By purging attributes that aren't needed any longer after + a Node (=File) got built, we don't have to care that much how + many KBytes a Node actually requires...as long as we free + the memory shortly afterwards. - @see: built() and File.release_target_info() - """ + @see: built() and File.release_target_info() + """ pass - # - # - # - def add_to_waiting_s_e(self, node): self.waiting_s_e.add(node) diff --git a/SCons/PathList.py b/SCons/PathList.py index 768198b..a7e666d 100644 --- a/SCons/PathList.py +++ b/SCons/PathList.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,17 +20,13 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -__doc__ = """SCons.PathList -A module for handling lists of directory paths (the sort of things -that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and -efficiency as we can, while still keeping the evaluation delayed so that we -Do the Right Thing (almost) regardless of how the variable is specified. +"""Handle lists of directory paths. +These are the path lists that get set as CPPPATH, LIBPATH, +etc.) with as much caching of data and efficiency as we can, while +still keeping the evaluation delayed so that we Do the Right Thing +(almost) regardless of how the variable is specified. """ import os diff --git a/SCons/PathListTests.py b/SCons/PathListTests.py index 0d15c08..ea7cecd 100644 --- a/SCons/PathListTests.py +++ b/SCons/PathListTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import TestUnit @@ -189,16 +186,7 @@ class PathListTestCase(unittest.TestCase): if __name__ == "__main__": - suite = unittest.TestSuite() - tclasses = [ - subst_pathTestCase, - PathListCacheTestCase, - PathListTestCase, - ] - for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests(list(map(tclass, names))) - TestUnit.run(suite) + unittest.main() # Local Variables: # tab-width:4 diff --git a/SCons/Platform/Platform.xml b/SCons/Platform/Platform.xml index 6582590..b150906 100644 --- a/SCons/Platform/Platform.xml +++ b/SCons/Platform/Platform.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/Platform/PlatformTests.py b/SCons/Platform/PlatformTests.py index e065c3c..1a72eb7 100644 --- a/SCons/Platform/PlatformTests.py +++ b/SCons/Platform/PlatformTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,16 +20,12 @@ # 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.compat import collections import unittest import os +import SCons.compat import SCons.Errors import SCons.Platform import SCons.Environment @@ -107,14 +104,13 @@ class PlatformTestCase(unittest.TestCase): p(env) assert env['PROGSUFFIX'] == '.exe', env assert env['LIBSUFFIX'] == '.lib', env - assert str + exc_caught = None try: p = SCons.Platform.Platform('_does_not_exist_') except SCons.Errors.UserError: - pass - else: # TODO pylint E0704: bare raise not inside except - raise + exc_caught = 1 + assert exc_caught, "did not catch expected UserError" env = Environment() SCons.Platform.Platform()(env) @@ -193,14 +189,15 @@ class TempFileMungeTestCase(unittest.TestCase): SCons.Action.print_actions = old_actions assert file_content != env['TEMPFILEARGJOINBYTE'].join(['test','command','line']) - def test_tempfilecreation_once(self): - # Init class with cmd, such that the fully expanded - # string reads "a test command line". - # Note, how we're using a command string here that is - # actually longer than the substituted one. This is to ensure - # that the TempFileMunge class internally really takes the - # length of the expanded string into account. + """ + Init class with cmd, such that the fully expanded + string reads "a test command line". + Note, how we're using a command string here that is + actually longer than the substituted one. This is to ensure + that the TempFileMunge class internally really takes the + length of the expanded string into account. + """ defined_cmd = "a $VERY $OVERSIMPLIFIED line" t = SCons.Platform.TempFileMunge(defined_cmd) env = SCons.Environment.SubstitutionEnvironment(tools=[]) @@ -220,12 +217,14 @@ class TempFileMungeTestCase(unittest.TestCase): def __init__(self): self.attributes = self.Attrs() + target = [Node()] cmd = t(target, None, env, 0) # ...and restoring its setting. SCons.Action.print_actions = old_actions assert cmd != defined_cmd, cmd - assert cmd == getattr(target[0].attributes, 'tempfile_cmdlist', None) + assert cmd == target[0].attributes.tempfile_cmdlist[defined_cmd] + class PlatformEscapeTestCase(unittest.TestCase): diff --git a/SCons/Platform/__init__.py b/SCons/Platform/__init__.py index 5d3541b..745db09 100644 --- a/SCons/Platform/__init__.py +++ b/SCons/Platform/__init__.py @@ -1,26 +1,6 @@ -"""SCons.Platform - -SCons platform selection. - -This looks for modules that define a callable object that can modify a -construction environment as appropriate for a given platform. - -Note that we take a more simplistic view of "platform" than Python does. -We're looking for a single string that determines a set of -tool-independent variables with which to initialize a construction -environment. Consequently, we'll examine both sys.platform and os.name -(and anything else that might come in to play) in order to return some -specification which is unique enough for our purposes. - -Note that because this subsystem just *selects* a callable that can -modify a construction environment, it's possible for people to define -their own "platform specification" in an arbitrary callable function. -No one needs to use or tie in to this subsystem in order to roll -their own platform definition. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -40,8 +20,25 @@ their own platform definition. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""SCons platform selection. + +Looks for modules that define a callable object that can modify a +construction environment as appropriate for a given platform. + +Note that we take a more simplistic view of "platform" than Python does. +We're looking for a single string that determines a set of +tool-independent variables with which to initialize a construction +environment. Consequently, we'll examine both sys.platform and os.name +(and anything else that might come in to play) in order to return some +specification which is unique enough for our purposes. + +Note that because this subsystem just *selects* a callable that can +modify a construction environment, it's possible for people to define +their own "platform specification" in an arbitrary callable function. +No one needs to use or tie in to this subsystem in order to roll +their own platform definition. +""" import SCons.compat @@ -191,9 +188,20 @@ class TempFileMunge: # Check if we already created the temporary file for this target # It should have been previously done by Action.strfunction() call - node = target[0] if SCons.Util.is_List(target) else target - cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \ - if node is not None else None + if SCons.Util.is_List(target): + node = target[0] + else: + node = target + + cmdlist = None + + if SCons.Util.is_List(self.cmd): + cmdlist_key = tuple(self.cmd) + else: + cmdlist_key = self.cmd + + if node and hasattr(node.attributes, 'tempfile_cmdlist'): + cmdlist = node.attributes.tempfile_cmdlist.get(cmdlist_key, None) if cmdlist is not None: return cmdlist @@ -260,14 +268,18 @@ class TempFileMunge: str(cmd[0]) + " " + " ".join(args)) self._print_cmd_str(target, source, env, cmdstr) + cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] + # Store the temporary file command list into the target Node.attributes # to avoid creating two temporary files one for print and one for execute. - cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] if node is not None: - try : - setattr(node.attributes, 'tempfile_cmdlist', cmdlist) + try: + # Storing in tempfile_cmdlist by self.cmd provided when intializing + # $TEMPFILE{} fixes issue raised in PR #3140 and #3553 + node.attributes.tempfile_cmdlist[cmdlist_key] = cmdlist except AttributeError: - pass + node.attributes.tempfile_cmdlist = {cmdlist_key:cmdlist} + return cmdlist def _print_cmd_str(self, target, source, env, cmdstr): diff --git a/SCons/Platform/aix.py b/SCons/Platform/aix.py index 247437a..bee3eb8 100644 --- a/SCons/Platform/aix.py +++ b/SCons/Platform/aix.py @@ -1,14 +1,6 @@ -"""SCons.Platform.aix - -Platform-specific initialization for IBM AIX systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,11 +20,14 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for IBM AIX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" -import os import subprocess from . import posix @@ -70,8 +65,6 @@ def get_xlc(env, xlc=None, packages=[]): or ('/' not in xlc and filename.endswith('/' + xlc)): xlcVersion = fileset.split()[1] xlcPath, sep, xlc = filename.rpartition('/') - pass - pass return (xlcPath, xlc, xlcVersion) def generate(env): diff --git a/SCons/Platform/cygwin.py b/SCons/Platform/cygwin.py index f6c5086..ce01007 100644 --- a/SCons/Platform/cygwin.py +++ b/SCons/Platform/cygwin.py @@ -1,14 +1,6 @@ -"""SCons.Platform.cygwin - -Platform-specific initialization for Cygwin systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for Cygwin systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" import sys diff --git a/SCons/Platform/darwin.py b/SCons/Platform/darwin.py index 590e79a..68cb7df 100644 --- a/SCons/Platform/darwin.py +++ b/SCons/Platform/darwin.py @@ -1,14 +1,6 @@ -"""SCons.Platform.darwin - -Platform-specific initialization for Mac OS X systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for Mac OS X systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" from . import posix import os diff --git a/SCons/Platform/hpux.py b/SCons/Platform/hpux.py index 701be8a..551468e 100644 --- a/SCons/Platform/hpux.py +++ b/SCons/Platform/hpux.py @@ -1,14 +1,6 @@ -"""SCons.Platform.hpux - -Platform-specific initialization for HP-UX systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for HP-UX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" from . import posix diff --git a/SCons/Platform/irix.py b/SCons/Platform/irix.py index 2e5f217..70f3708 100644 --- a/SCons/Platform/irix.py +++ b/SCons/Platform/irix.py @@ -1,14 +1,6 @@ -"""SCons.Platform.irix - -Platform-specific initialization for SGI IRIX systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for SGI IRIX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" from . import posix diff --git a/SCons/Platform/mingw.py b/SCons/Platform/mingw.py index 73633d7..1d38a9b 100644 --- a/SCons/Platform/mingw.py +++ b/SCons/Platform/mingw.py @@ -1,11 +1,6 @@ -"""SCons.Platform.mingw - -Platform-specific initialization for the MinGW system. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ Platform-specific initialization for the MinGW system. # 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__" +"""Platform-specific initialization for the MinGW system.""" import sys @@ -36,4 +30,4 @@ if sys.platform == 'win32': MINGW_DEFAULT_PATHS = [ r'C:\msys64', r'C:\msys' - ]
\ No newline at end of file + ] diff --git a/SCons/Platform/os2.py b/SCons/Platform/os2.py index 5ca26bc..6b412ee 100644 --- a/SCons/Platform/os2.py +++ b/SCons/Platform/os2.py @@ -1,14 +1,6 @@ -"""SCons.Platform.os2 - -Platform-specific initialization for OS/2 systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,14 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for OS/2 systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + from . import win32 def generate(env): diff --git a/SCons/Platform/posix.py b/SCons/Platform/posix.py index ad4e859..4a5db10 100644 --- a/SCons/Platform/posix.py +++ b/SCons/Platform/posix.py @@ -1,14 +1,6 @@ -"""SCons.Platform.posix - -Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,15 +20,16 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" import errno -import os -import os.path import subprocess -import sys import select import SCons.Util diff --git a/SCons/Platform/posix.xml b/SCons/Platform/posix.xml index b58af83..e90e159 100644 --- a/SCons/Platform/posix.xml +++ b/SCons/Platform/posix.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/Platform/sunos.py b/SCons/Platform/sunos.py index 40e698e..d33af1e 100644 --- a/SCons/Platform/sunos.py +++ b/SCons/Platform/sunos.py @@ -1,14 +1,6 @@ -"""SCons.Platform.sunos - -Platform-specific initialization for Sun systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for Sun systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" from . import posix diff --git a/SCons/Platform/sunos.xml b/SCons/Platform/sunos.xml index a518301..ffeae96 100644 --- a/SCons/Platform/sunos.xml +++ b/SCons/Platform/sunos.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/Platform/virtualenv.py b/SCons/Platform/virtualenv.py index 4708cb2..2204a59 100644 --- a/SCons/Platform/virtualenv.py +++ b/SCons/Platform/virtualenv.py @@ -1,10 +1,6 @@ -"""SCons.Platform.virtualenv - -Support for virtualenv. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -24,9 +20,8 @@ Support for virtualenv. # 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__" +"""'Platform" support for a Python virtualenv.""" import os import sys @@ -50,14 +45,14 @@ virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE'] def _running_in_virtualenv(): - """Returns True, if scons is executed within a 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.""" + """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) diff --git a/SCons/Platform/virtualenvTests.py b/SCons/Platform/virtualenvTests.py index da0c06b..c840749 100644 --- a/SCons/Platform/virtualenvTests.py +++ b/SCons/Platform/virtualenvTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,17 +20,13 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import SCons.compat import collections import unittest import os import sys +import SCons.compat import SCons.Platform.virtualenv import SCons.Util diff --git a/SCons/Platform/win32.py b/SCons/Platform/win32.py index 84fd8f8..aa76387 100644 --- a/SCons/Platform/win32.py +++ b/SCons/Platform/win32.py @@ -1,14 +1,6 @@ -"""SCons.Platform.win32 - -Platform-specific initialization for Win32 systems. - -There normally shouldn't be any need to import this module directly. It -will usually be imported through the generic SCons.Platform.Platform() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Platform-specific initialization for Win32 systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" import os import os.path @@ -47,22 +43,6 @@ CHOCO_DEFAULT_PATH = [ r'C:\ProgramData\chocolatey\bin' ] -try: - import msvcrt - import win32api - import win32con -except ImportError: - parallel_msg = \ - "you do not seem to have the pywin32 extensions installed;\n" + \ - "\tparallel (-j) builds may not work reliably with open Python files." -except AttributeError: - parallel_msg = \ - "your pywin32 extensions do not support file handle operations;\n" + \ - "\tparallel (-j) builds may not work reliably with open Python files." -else: - parallel_msg = None - - if False: # Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile try: @@ -288,7 +268,6 @@ def get_program_files_dir(): val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') except SCons.Util.RegError: val = '' - pass if val == '': # A reasonable default if we can't read the registry diff --git a/SCons/Platform/win32.xml b/SCons/Platform/win32.xml index e53f02a..3000e33 100644 --- a/SCons/Platform/win32.xml +++ b/SCons/Platform/win32.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/SConf.py b/SCons/SConf.py index 1046019..d024600 100644 --- a/SCons/SConf.py +++ b/SCons/SConf.py @@ -1,18 +1,6 @@ -"""SCons.SConf - -Autoconf-like configuration support. - -In other words, SConf allows to run tests on the build machine to detect -capabilities of system and do some things based on result: generate config -files, header files for C/C++, update variables in environment. - -Tests on the build system can detect if compiler sees header files, if -libraries are installed, if some command line options are supported etc. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,8 +20,16 @@ libraries are installed, if some command line options are supported etc. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""Autoconf-like configuration support. + +In other words, SConf allows to run tests on the build machine to detect +capabilities of system and do some things based on result: generate config +files, header files for C/C++, update variables in environment. + +Tests on the build system can detect if compiler sees header files, if +libraries are installed, if some command line options are supported etc. +""" import SCons.compat diff --git a/SCons/SConfTests.py b/SCons/SConfTests.py index 7faabdd..b8ee7d2 100644 --- a/SCons/SConfTests.py +++ b/SCons/SConfTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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.compat diff --git a/SCons/SConsign.py b/SCons/SConsign.py index dc2311a..8e3ebf4 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -1,11 +1,6 @@ -"""SCons.SConsign - -Writing and reading information to the .sconsign file or files. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,8 +20,8 @@ Writing and reading information to the .sconsign file or files. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""Operations on signature database files (.sconsign). """ import SCons.compat diff --git a/SCons/SConsignTests.py b/SCons/SConsignTests.py index 2f832b4..fdce588 100644 --- a/SCons/SConsignTests.py +++ b/SCons/SConsignTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import unittest import TestCmd @@ -382,18 +379,7 @@ class writeTestCase(SConsignTestCase): if __name__ == "__main__": - suite = unittest.TestSuite() - tclasses = [ - BaseTestCase, - SConsignDBTestCase, - SConsignDirFileTestCase, - SConsignFileTestCase, - writeTestCase, - ] - for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests(list(map(tclass, names))) - TestUnit.run(suite) + unittest.main() # Local Variables: # tab-width:4 diff --git a/SCons/Scanner/C.py b/SCons/Scanner/C.py index 21da574..91beb04 100644 --- a/SCons/Scanner/C.py +++ b/SCons/Scanner/C.py @@ -1,11 +1,6 @@ -"""SCons.Scanner.C - -This module implements the dependency scanner for C/C++ code. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ This module implements the dependency scanner for C/C++ code. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for C/C++ code.""" import SCons.Node.FS import SCons.Scanner @@ -36,8 +30,7 @@ import SCons.Util import SCons.cpp class SConsCPPScanner(SCons.cpp.PreProcessor): - """ - SCons-specific subclass of the cpp.py module's processing. + """SCons-specific subclass of the cpp.py module's processing. We subclass this so that: 1) we can deal with files represented by Nodes, not strings; 2) we can keep track of the files that are @@ -81,8 +74,7 @@ def dictify_CPPDEFINES(env): return cppdefines class SConsCPPScannerWrapper: - """ - The SCons wrapper around a cpp.py scanner. + """The SCons wrapper around a cpp.py scanner. This is the actual glue between the calling conventions of generic SCons scanners, and the (subclass of) cpp.py class that knows how @@ -116,12 +108,14 @@ def CScanner(): # knows how to evaluate #if/#ifdef/#else/#elif lines when searching # for #includes. This is commented out for now until we add the # right configurability to let users pick between the scanners. - #return SConsCPPScannerWrapper("CScanner", "CPPPATH") - - cs = SCons.Scanner.ClassicCPP("CScanner", - "$CPPSUFFIXES", - "CPPPATH", - '^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")') + # return SConsCPPScannerWrapper("CScanner", "CPPPATH") + + cs = SCons.Scanner.ClassicCPP( + "CScanner", + "$CPPSUFFIXES", + "CPPPATH", + r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")', + ) return cs @@ -131,8 +125,7 @@ def CScanner(): class SConsCPPConditionalScanner(SCons.cpp.PreProcessor): - """ - SCons-specific subclass of the cpp.py module's processing. + """SCons-specific subclass of the cpp.py module's processing. We subclass this so that: 1) we can deal with files represented by Nodes, not strings; 2) we can keep track of the files that are diff --git a/SCons/Scanner/CTests.py b/SCons/Scanner/CTests.py index 8042e3f..25c6e99 100644 --- a/SCons/Scanner/CTests.py +++ b/SCons/Scanner/CTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,6 @@ # 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.compat import collections import os @@ -32,6 +28,7 @@ import unittest import TestCmd import TestUnit +import SCons.compat import SCons.Node.FS import SCons.Warnings diff --git a/SCons/Scanner/D.py b/SCons/Scanner/D.py index b3fb29e..645934b 100644 --- a/SCons/Scanner/D.py +++ b/SCons/Scanner/D.py @@ -1,14 +1,6 @@ -"""SCons.Scanner.D - -Scanner for the Digital Mars "D" programming language. - -Coded by Andy Friesen -17 Nov 2003 - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,11 @@ Coded by Andy Friesen # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Scanner for the Digital Mars "D" programming language. + +Coded by Andy Friesen, 17 Nov 2003 +""" import SCons.Scanner diff --git a/SCons/Scanner/DTests.py b/SCons/Scanner/DTests.py index d0157bf..7b764aa 100644 --- a/SCons/Scanner/DTests.py +++ b/SCons/Scanner/DTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,10 +20,9 @@ # 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 collections +import os import unittest import TestCmd @@ -31,8 +31,6 @@ import SCons.Scanner.D test = TestCmd.TestCmd(workdir = '') -import collections -import os class DummyEnvironment(collections.UserDict): def __init__(self, **kw): diff --git a/SCons/Scanner/Dir.py b/SCons/Scanner/Dir.py index 3b33fe5..617bf2b 100644 --- a/SCons/Scanner/Dir.py +++ b/SCons/Scanner/Dir.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,8 +21,6 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import SCons.Node.FS import SCons.Scanner diff --git a/SCons/Scanner/DirTests.py b/SCons/Scanner/DirTests.py index 8f866c4..2e73fe2 100644 --- a/SCons/Scanner/DirTests.py +++ b/SCons/Scanner/DirTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path -import sys import unittest import TestCmd diff --git a/SCons/Scanner/Fortran.py b/SCons/Scanner/Fortran.py index 67e6180..18e5082 100644 --- a/SCons/Scanner/Fortran.py +++ b/SCons/Scanner/Fortran.py @@ -1,11 +1,6 @@ -"""SCons.Scanner.Fortran - -This module implements the dependency scanner for Fortran code. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +21,7 @@ This module implements the dependency scanner for Fortran code. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for Fortran code.""" import re diff --git a/SCons/Scanner/FortranTests.py b/SCons/Scanner/FortranTests.py index be2acd3..487fb7b 100644 --- a/SCons/Scanner/FortranTests.py +++ b/SCons/Scanner/FortranTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import os.path import unittest import SCons.Scanner.Fortran diff --git a/SCons/Scanner/IDL.py b/SCons/Scanner/IDL.py index 86ee006..418608f 100644 --- a/SCons/Scanner/IDL.py +++ b/SCons/Scanner/IDL.py @@ -1,12 +1,6 @@ -"""SCons.Scanner.IDL - -This module implements the dependency scanner for IDL (Interface -Definition Language) files. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,19 +20,20 @@ Definition Language) files. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for IDL (Interface Definition Language) files.""" import SCons.Node.FS import SCons.Scanner def IDLScan(): """Return a prototype Scanner instance for scanning IDL source files""" - cs = SCons.Scanner.ClassicCPP("IDLScan", - "$IDLSUFFIXES", - "CPPPATH", - '^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")') + cs = SCons.Scanner.ClassicCPP( + "IDLScan", + "$IDLSUFFIXES", + "CPPPATH", + r'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")', + ) return cs # Local Variables: diff --git a/SCons/Scanner/IDLTests.py b/SCons/Scanner/IDLTests.py index 9cbb73d..fc1d1c8 100644 --- a/SCons/Scanner/IDLTests.py +++ b/SCons/Scanner/IDLTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest -import sys import os import os.path diff --git a/SCons/Scanner/LaTeX.py b/SCons/Scanner/LaTeX.py index a85592e..73f0035 100644 --- a/SCons/Scanner/LaTeX.py +++ b/SCons/Scanner/LaTeX.py @@ -1,11 +1,6 @@ -"""SCons.Scanner.LaTeX - -This module implements the dependency scanner for LaTeX code. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ This module implements the dependency scanner for LaTeX code. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for LaTeX code.""" import os.path import re @@ -96,7 +90,6 @@ class FindENVPathDirs: return tuple(dir.Rfindalldirs(path)) - def LaTeXScanner(): """ Return a prototype Scanner instance for scanning LaTeX source files @@ -109,6 +102,7 @@ def LaTeXScanner(): recursive = 0) return ds + def PDFLaTeXScanner(): """ Return a prototype Scanner instance for scanning LaTeX source files @@ -121,9 +115,9 @@ def PDFLaTeXScanner(): recursive = 0) return ds + class LaTeX(SCons.Scanner.Base): - """ - Class for scanning LaTeX files for included files. + """Class for scanning LaTeX files for included files. Unlike most scanners, which use regular expressions that just return the included file name, this returns a tuple consisting diff --git a/SCons/Scanner/LaTeXTests.py b/SCons/Scanner/LaTeXTests.py index 409699c..818cbe4 100644 --- a/SCons/Scanner/LaTeXTests.py +++ b/SCons/Scanner/LaTeXTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,19 +20,14 @@ # 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.compat import collections import os -import sys import unittest import TestCmd +import SCons.compat import SCons.Node.FS import SCons.Scanner.LaTeX diff --git a/SCons/Scanner/Prog.py b/SCons/Scanner/Prog.py index 6567b3d..41be1a4 100644 --- a/SCons/Scanner/Prog.py +++ b/SCons/Scanner/Prog.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for program files.""" import SCons.Node import SCons.Node.FS @@ -39,9 +39,7 @@ def ProgramScanner(**kw): return ps def _subst_libs(env, libs): - """ - Substitute environment variables and split into list. - """ + """Substitute environment variables and split into list.""" if SCons.Util.is_String(libs): libs = env.subst(libs) if SCons.Util.is_String(libs): @@ -57,9 +55,9 @@ def _subst_libs(env, libs): return libs def scan(node, env, libpath = ()): - """ - This scanner scans program files for static-library - dependencies. It will search the LIBPATH environment variable + """Scans program files for static-library dependencies. + + It will search the LIBPATH environment variable for libraries specified in the LIBS variable, returning any files it finds as dependencies. """ diff --git a/SCons/Scanner/ProgTests.py b/SCons/Scanner/ProgTests.py index b91a2ad..4b17d9b 100644 --- a/SCons/Scanner/ProgTests.py +++ b/SCons/Scanner/ProgTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path -import sys import unittest import TestCmd diff --git a/SCons/Scanner/Python.py b/SCons/Scanner/Python.py index deb2241..dc6812c 100644 --- a/SCons/Scanner/Python.py +++ b/SCons/Scanner/Python.py @@ -1,18 +1,6 @@ -"""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. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,9 +20,17 @@ those directories in PYTHONPATH. # 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__" +"""Dependency scanner for Python code. + +One important note about the design is that this does not take any dependencies +upon packages or binaries in the Python installation unless they are listed in +PYTHONPATH. To do otherwise would have required code to determine where the +Python installation is, which is outside of the scope of a scanner like this. +If consumers want to pick up dependencies upon these packages, they must put +those directories in PYTHONPATH. + +""" import itertools import os @@ -55,8 +51,7 @@ def path_function(env, dir=None, target=None, source=None, argument=None): def find_include_names(node): - """ - Scans the node for all imports. + """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) diff --git a/SCons/Scanner/PythonTests.py b/SCons/Scanner/PythonTests.py index 0d4e628..faf548a 100644 --- a/SCons/Scanner/PythonTests.py +++ b/SCons/Scanner/PythonTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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.compat diff --git a/SCons/Scanner/RC.py b/SCons/Scanner/RC.py index abaaef7..12e431d 100644 --- a/SCons/Scanner/RC.py +++ b/SCons/Scanner/RC.py @@ -1,12 +1,6 @@ -"""SCons.Scanner.RC - -This module implements the dependency scanner for RC (Interface -Definition Language) files. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,20 +20,17 @@ Definition Language) files. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for RC (Interface Definition Language) files.""" -import re import SCons.Node.FS import SCons.Scanner def no_tlb(nodes): - """ - Filter out .tlb files as they are binary and shouldn't be scanned - """ + """Filter out .tlb files as they are binary and shouldn't be scanned.""" + # print("Nodes:%s"%[str(n) for n in nodes]) return [n for n in nodes if str(n)[-4:] != '.tlb'] @@ -47,16 +38,16 @@ def no_tlb(nodes): def RCScan(): """Return a prototype Scanner instance for scanning RC source files""" - res_re= r'^(?:\s*#\s*(?:include)|' \ - r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \ - r'\s*.*?)' \ - r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$' - resScanner = SCons.Scanner.ClassicCPP("ResourceScanner", - "$RCSUFFIXES", - "CPPPATH", - res_re, - recursive=no_tlb) - + res_re = ( + r'^(?:\s*#\s*(?:include)|' + r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' + r'\s*.*?)' + r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$' + ) + resScanner = SCons.Scanner.ClassicCPP( + "ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re, recursive=no_tlb + ) + return resScanner # Local Variables: diff --git a/SCons/Scanner/RCTests.py b/SCons/Scanner/RCTests.py index 347149c..9183ec7 100644 --- a/SCons/Scanner/RCTests.py +++ b/SCons/Scanner/RCTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest -import sys import collections import os @@ -158,13 +155,6 @@ class RCScannerTestCase3(unittest.TestCase): deps_match(self, deps, headers) -def suite(): - suite = unittest.TestSuite() - suite.addTest(RCScannerTestCase1()) - suite.addTest(RCScannerTestCase2()) - suite.addTest(RCScannerTestCase3()) - return suite - if __name__ == "__main__": unittest.main() diff --git a/SCons/Scanner/SWIG.py b/SCons/Scanner/SWIG.py index a333134..5a60c74 100644 --- a/SCons/Scanner/SWIG.py +++ b/SCons/Scanner/SWIG.py @@ -1,11 +1,6 @@ -"""SCons.Scanner.SWIG - -This module implements the dependency scanner for SWIG code. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ This module implements the dependency scanner for SWIG code. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Dependency scanner for SWIG code.""" import SCons.Scanner diff --git a/SCons/Scanner/Scanner.xml b/SCons/Scanner/Scanner.xml index 4f96d39..c9b7f32 100644 --- a/SCons/Scanner/Scanner.xml +++ b/SCons/Scanner/Scanner.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/Scanner/ScannerTests.py b/SCons/Scanner/ScannerTests.py index bf9879e..815dabd 100644 --- a/SCons/Scanner/ScannerTests.py +++ b/SCons/Scanner/ScannerTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,16 +21,12 @@ # 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.compat - import collections -import sys import unittest import TestUnit +import SCons.compat import SCons.Scanner class DummyFS: diff --git a/SCons/Scanner/__init__.py b/SCons/Scanner/__init__.py index e99c526..d98f651 100644 --- a/SCons/Scanner/__init__.py +++ b/SCons/Scanner/__init__.py @@ -1,11 +1,6 @@ -"""SCons.Scanner - -The Scanner package for the SCons software construction utility. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ The Scanner package for the SCons software construction utility. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The Scanner package for the SCons software construction utility.""" import re @@ -43,16 +37,16 @@ class _Null: _null = _Null def Scanner(function, *args, **kw): - """ - Public interface factory function for creating different types - of Scanners based on the different types of "functions" that may - be supplied. + """Factory function to create a Scanner Object. + + Creates the appropriate Scanner based on the type of "function". TODO: Deprecate this some day. We've moved the functionality inside the Base class and really don't need this factory function any more. It was, however, used by some of our Tool modules, so the call probably ended up in various people's custom modules patterned on SCons code. + """ if SCons.Util.is_Dict(function): return Selector(function, *args, **kw) @@ -60,10 +54,8 @@ def Scanner(function, *args, **kw): return Base(function, *args, **kw) - class FindPathDirs: - """ - A class to bind a specific E{*}PATH variable name to a function that + """Class to bind a specific E{*}PATH variable name to a function that will return all of the E{*}path directories. """ def __init__(self, variable): @@ -82,66 +74,25 @@ class FindPathDirs: class Base: - """ - The base class for dependency scanners. This implements - straightforward, single-pass scanning of a single file. - """ - - def __init__(self, - function, - name = "NONE", - argument = _null, - skeys = _null, - path_function = None, - # Node.FS.Base so that, by default, it's okay for a - # scanner to return a Dir, File or Entry. - node_class = SCons.Node.FS.Base, - node_factory = None, - scan_check = None, - recursive = None): - """ - Construct a new scanner object given a scanner function. - - 'function' - a scanner function taking two or three - arguments and returning a list of strings. - - 'name' - a name for identifying this scanner object. + """Base class for dependency scanners. - 'argument' - an optional argument that, if specified, will be - passed to both the scanner function and the path_function. - - 'skeys' - an optional list argument that can be used to determine - which scanner should be used for a given Node. In the case of File - nodes, for example, the 'skeys' would be file suffixes. - - 'path_function' - a function that takes four or five arguments - (a construction environment, Node for the directory containing - the SConscript file that defined the primary target, list of - target nodes, list of source nodes, and optional argument for - this instance) and returns a tuple of the directories that can - be searched for implicit dependency files. May also return a - callable() which is called with no args and returns the tuple - (supporting Bindable class). - - 'node_class' - the class of Nodes which this scan will return. - If node_class is None, then this scanner will not enforce any - Node conversion and will return the raw results from the - underlying scanner function. - - 'node_factory' - the factory function to be called to translate - the raw results returned by the scanner function into the - expected node_class objects. - - 'scan_check' - a function to be called to first check whether - this node really needs to be scanned. - - 'recursive' - specifies that this scanner should be invoked - recursively on all of the implicit dependencies it returns - (the canonical example being #include lines in C source files). - May be a callable, which will be called to filter the list - of nodes found to select a subset for recursive scanning - (the canonical example being only recursively scanning - subdirectories within a directory). + This implements straightforward, single-pass scanning of a single file. + """ + def __init__( + self, + function, + name="NONE", + argument=_null, + skeys=_null, + path_function=None, + # Node.FS.Base so that, by default, it's okay for a + # scanner to return a Dir, File or Entry. + node_class=SCons.Node.FS.Base, + node_factory=None, + scan_check=None, + recursive=None, + ): + """Construct a new scanner object given a scanner function. The scanner function's first argument will be a Node that should be scanned for dependencies, the second argument will be an @@ -152,14 +103,55 @@ class Base: Examples: - s = Scanner(my_scanner_function) - - s = Scanner(function = my_scanner_function) - - s = Scanner(function = my_scanner_function, argument = 'foo') + s = Scanner(my_scanner_function) + s = Scanner(function = my_scanner_function) + s = Scanner(function = my_scanner_function, argument = 'foo') + + Args: + function: a scanner function taking two or three arguments + and returning a list of strings. + + name: a name for identifying this scanner object. + + argument: an optional argument that, if specified, will be + passed to both the scanner function and the path_function. + + skeys: an optional list argument that can be used + to determine which scanner should be used for a given + Node. In the case of File nodes, for example, the 'skeys' + would be file suffixes. + + path_function: a function that takes four or five arguments + (a construction environment, Node for the directory + containing the SConscript file that defined the primary + target, list of target nodes, list of source nodes, and + optional argument for this instance) and returns a tuple + of the directories that can be searched for implicit + dependency files. May also return a callable() which + is called with no args and returns the tuple (supporting + Bindable class). + + node_class: the class of Nodes which this scan will return. + If node_class is None, then this scanner will not enforce + any Node conversion and will return the raw results from + the underlying scanner function. + + node_factory: the factory function to be called to + translate the raw results returned by the scanner function + into the expected node_class objects. + + scan_check: a function to be called to first check whether + this node really needs to be scanned. + + recursive: specifies that this scanner should be invoked + recursively on all of the implicit dependencies it returns + (the canonical example being #include lines in C source + files). May be a callable, which will be called to filter + the list of nodes found to select a subset for recursive + scanning (the canonical example being only recursively + scanning subdirectories within a directory). """ - # Note: this class could easily work with scanner functions that take # something other than a filename as an argument (e.g. a database # node) and a dependencies list that aren't file names. All that @@ -196,11 +188,15 @@ class Base: return self.path_function(env, dir, target, source) def __call__(self, node, env, path=()): - """ - This method scans a single object. 'node' is the node - that will be passed to the scanner function, and 'env' is the - environment that will be passed to the scanner function. A list of - direct dependency nodes for the specified node will be returned. + """Scans a single object. + + Args: + node: the node that will be passed to the scanner function + env: the environment that will be passed to the scanner function. + + Returns: + A list of direct dependency nodes for the specified node. + """ if self.scan_check and not self.scan_check(node, env): return [] diff --git a/SCons/Script/Interactive.py b/SCons/Script/Interactive.py index a414b4e..26a8bcd 100644 --- a/SCons/Script/Interactive.py +++ b/SCons/Script/Interactive.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -__doc__ = """ -SCons interactive mode -""" +"""SCons interactive mode. """ # TODO: # diff --git a/SCons/Script/Main.py b/SCons/Script/Main.py index c8be54a..ea9bd95 100644 --- a/SCons/Script/Main.py +++ b/SCons/Script/Main.py @@ -1,20 +1,6 @@ -"""SCons.Script - -This file implements the main() function used by the scons script. - -Architecturally, this *is* the scons script, and will likely only be -called from the external "scons" wrapper. Consequently, anything here -should not be, or be considered, part of the build engine. If it's -something that we expect other software to want to use, it should go in -some other module. If it's specific to the "scons" script invocation, -it goes here. -""" - -unsupported_python_version = (3, 4, 0) -deprecated_python_version = (3, 4, 0) - - -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -35,8 +21,19 @@ deprecated_python_version = (3, 4, 0) # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The main() function used by the scons script. + +Architecturally, this *is* the scons script, and will likely only be +called from the external "scons" wrapper. Consequently, anything here +should not be, or be considered, part of the build engine. If it's +something that we expect other software to want to use, it should go in +some other module. If it's specific to the "scons" script invocation, +it goes here. +""" +# these define the range of versions SCons supports +unsupported_python_version = (3, 4, 0) +deprecated_python_version = (3, 4, 0) import SCons.compat @@ -49,6 +46,7 @@ import time import traceback import sysconfig import platform +import threading import SCons.CacheDir import SCons.Debug @@ -83,17 +81,6 @@ num_jobs = None delayed_warnings = [] -def fetch_win32_parallel_msg(): - # A subsidiary function that exists solely to isolate this import - # so we don't have to pull it in on all platforms, and so that an - # in-line "import" statement in the _main() function below doesn't - # cause warnings about local names shadowing use of the 'SCons' - # global in nest scopes and UnboundLocalErrors and the like in some - # versions (2.1) of Python. - import SCons.Platform.win32 - return SCons.Platform.win32.parallel_msg - - def revert_io(): # This call is added to revert stderr and stdout to the original # ones just in case some build rule or something else in the system @@ -1287,16 +1274,19 @@ def _build_targets(fs, options, targets, target_top): # 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 + # python_has_threads = sysconfig.get_config_var('WITH_THREAD') or is_pypy or is_37_or_later + + # As of python 3.4 threading has a dummy_threading module for use when there is no threading + # it's get_ident() will allways return -1, while real threading modules get_ident() will + # always return a positive integer + python_has_threads = threading.get_ident() != -1 # to check if python configured with threads. global num_jobs num_jobs = options.num_jobs jobs = SCons.Job.Jobs(num_jobs, taskmaster) if num_jobs > 1: msg = None - if sys.platform == 'win32': - msg = fetch_win32_parallel_msg() - elif jobs.num_jobs == 1 or not python_has_threads: + if jobs.num_jobs == 1 or not python_has_threads: msg = "parallel builds are unsupported by this version of Python;\n" + \ "\tignoring -j or num_jobs option.\n" if msg: @@ -1346,8 +1336,7 @@ def _exec_main(parser, values): import pdb pdb.Pdb().runcall(_main, parser) elif options.profile_file: - # compat layer imports "cProfile" for us if it's available. - from profile import Profile + from cProfile import Profile prof = Profile() try: diff --git a/SCons/Script/Main.xml b/SCons/Script/Main.xml index 0a8f9dc..ff1165c 100644 --- a/SCons/Script/Main.xml +++ b/SCons/Script/Main.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. @@ -36,13 +36,13 @@ are the same as those supported by the <function>add_option</function> method in the standard Python library module <systemitem>optparse</systemitem>, with a few additional capabilities noted below. See the documentation for -<emphasis>optparse</emphasis> +<systemitem>optparse</systemitem> for a thorough discussion of its option-processing capabities. </para> <para> In addition to the arguments and values supported by the -<emphasis>optparse</emphasis> +<systemitem>optparse</systemitem> <function>add_option</function> method, &f-AddOption; allows setting the @@ -80,10 +80,10 @@ it will recognize <option>--device</option>, and so forth as long as there is no other option which could also match to the same abbreviation. Options added via -<function>AddOption</function> do not support +&f-AddOption; do not support the automatic recognition of abbreviations. Instead, to allow specific abbreviations, -include them in the &f-AddOption; call. +include them as synonyms in the &f-AddOption; call itself. </para> <para> @@ -99,7 +99,7 @@ options added with &f-AddOption;. The value may also be set using &f-SetOption; or -<function>env.SetOption</function>(), +&f-env.SetOption;, if conditions in a &SConscript; require overriding any default value. @@ -765,123 +765,135 @@ Multiple targets can be passed in to a single call to </arguments> <summary> <para> -This function provides a way to set a select subset of the scons command -line options from a SConscript file. The options supported are: -</para> - -<para> -<variablelist> -<varlistentry> -<term><literal>clean</literal></term> -<listitem> -<para> -which corresponds to <option>-c</option>, <option>--clean</option> -and <option>--remove</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>duplicate</literal></term> -<listitem> -<para> -which corresponds to <option>--duplicate</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>help</literal></term> -<listitem> -<para> -which corresponds to <option>-h</option> and <option>--help</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>implicit_cache</literal></term> -<listitem> -<para> -which corresponds to <option>--implicit-cache</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>max_drift</literal></term> -<listitem> -<para> -which corresponds to <option>--max-drift</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>no_exec</literal></term> -<listitem> -<para> -which corresponds to <option>-n</option>, <option>--no-exec</option>, -<option>--just-print</option>, <option>--dry-run</option> -and <option>--recon</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>num_jobs</literal></term> -<listitem> -<para> -which corresponds to <option>-j</option> and <option>--jobs</option>; -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>random</literal></term> -<listitem> -<para> -which corresponds to <option>--random</option>; and -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>silent</literal></term> -<listitem> -<para> -which corresponds to <option>--silent</option>. -</para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>no_progress</literal></term> -<listitem> -<para> -which corresponds to -Q. -</para> -<para> - Note: The initial progress output will still be output as this is done before the SConstruct/SConscript which contains the SetOption is processed - <literal>scons: Reading SConscript files ...</literal> -</para> -<para><emphasis>Available since &scons; 4.0.</emphasis></para> -</listitem> -</varlistentry> -<varlistentry> -<term><literal>stack_size</literal></term> -<listitem> -<para> -which corresponds to --stack-size. -</para> -</listitem> -</varlistentry> -</variablelist> +Sets &scons; option variable <parameter>name</parameter> +to <parameter>value</parameter>. +These options are all also settable via +&scons; command-line options but the variable name +may differ from the command-line option name (see table). +A value set via command-line option will take +precedence over one set with &f-SetOption;, which +allows setting a project default in the scripts and +temporarily overriding it via command line. +Options which affect the reading and processing of SConscript files +are not settable this way, since those files must +be read in order to find the &f-SetOption; call. +</para> + +<para> +The settable variables with their associated command-line options are: +</para> + +<!-- UPDATE_SETOPTION_DOCS --> +<!-- This list comes directly from SConsValues.settable. Keep in sync. --> + +<informaltable rowsep="1" colsep="1" frame="topbot"> +<tgroup cols="2"> +<thead> +<row><entry>Variable</entry><entry>Command-line options</entry></row> +</thead> +<tbody> +<row><entry> +<varname>clean</varname> +</entry><entry> +<option>-c</option>, <option>--clean</option>, <option>--remove</option> +</entry></row> +<row><entry> +<varname>diskcheck</varname> +</entry><entry> +<option>--diskcheck</option> +</entry></row> +<row><entry> +<varname>duplicate</varname> +</entry><entry> +<option>--duplicate</option> +</entry></row> +<row><entry> +<varname>help</varname> +</entry><entry> +<option>-h</option>, <option>--help</option> +</entry></row> +<row><entry> +<varname>implicit_cache</varname> +</entry><entry> +<option>--implicit-cache</option> +</entry></row> +<!--TODO: add implicit-deps-changed, implicit-deps-unchanged ? --> +<row><entry> +<varname>max_drift</varname> +</entry><entry> +<option>--max-drift</option> +</entry></row> +<row><entry> +<varname>md5_chunksize</varname> +</entry><entry> +<option>--md5-chunksize</option> +</entry></row> +<row><entry> +<varname>no_exec</varname> +</entry><entry> +<option>-n</option>, <option>--no-exec</option>, +<option>--just-print</option>, <option>--dry-run</option>, +<option>--recon</option> +</entry></row> +<row><entry> +<varname>no_progress</varname> +</entry><entry> +<option>-Q</option> +</entry></row> +<row><entry> +<varname>num_jobs</varname> +</entry><entry> +<option>-j</option>, <option>--jobs</option> +</entry></row> +<row><entry> +<varname>random</varname> +</entry><entry> +<option>--random</option> +</entry></row> +<row><entry> +<varname>silent</varname> +</entry><entry> +<option>--silent</option>. +</entry></row> +<row><entry> +<varname>stack_size</varname> +</entry><entry> +<option>--stack-size</option> +</entry></row> +<row><entry> +<varname>warn</varname> +</entry><entry> +<option>--warn</option>. +</entry></row> +</tbody> +</tgroup> +</informaltable> + +<para> +See the documentation in the manpage for the +corresponding command line option for information about each specific option. +Option values which are boolean in nature (that is, they are +either on or off) should be set to a true value (<constant>True</constant>, +<constant>1</constant>) or a false value (<constant>False</constant>, +<constant>0</constant>). </para> +<note> <para> -See the documentation for the -corresponding command line option for information about each specific -option. +If <varname>no_progress</varname> is set via &f-SetOption; +there will still be initial progress output as &SCons; has +to start reading SConscript files before it can see the +&f-SetOption; in an SConscript file: +<computeroutput>scons: Reading SConscript files ...</computeroutput> </para> +</note> <para> Example: </para> <example_commands> -SetOption('max_drift', 1) +SetOption('max_drift', True) </example_commands> </summary> </scons_function> diff --git a/SCons/Script/MainTests.py b/SCons/Script/MainTests.py index aa6bfac..232a8a2 100644 --- a/SCons/Script/MainTests.py +++ b/SCons/Script/MainTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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 unittest diff --git a/SCons/Script/SConsOptions.py b/SCons/Script/SConsOptions.py index 775a2ef..cf132a2 100644 --- a/SCons/Script/SConsOptions.py +++ b/SCons/Script/SConsOptions.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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 optparse import re @@ -126,7 +124,8 @@ class SConsValues(optparse.Values): # is not available. raise AttributeError(attr) - + # keep this list in sync with the SetOption doc in SCons/Script/Main.xml + # search for UPDATE_SETOPTION_DOCS there. settable = [ 'clean', 'diskcheck', @@ -274,8 +273,7 @@ class SConsOptionParser(optparse.OptionParser): """ arg = rargs.pop(0) - # Value explicitly attached to arg? Pretend it's the next - # argument. + # Value explicitly attached to arg? Pretend it's the next argument. if "=" in arg: (opt, next_arg) = arg.split("=", 1) rargs.insert(0, next_arg) @@ -285,7 +283,11 @@ class SConsOptionParser(optparse.OptionParser): had_explicit_value = False try: - opt = self._match_long_opt(opt) + if opt != self._match_long_opt(opt): + raise optparse.BadOptionError( + "'%s'. Did you mean '%s'?" + % (opt, self._match_long_opt(opt)) + ) except optparse.BadOptionError: if self.preserve_unknown_options: # SCons-specific: if requested, add unknown options to @@ -399,7 +401,7 @@ class SConsOptionParser(optparse.OptionParser): """ Adds a local option to the parser. - This is initiated by a SetOption() call to add a user-defined + This is initiated by an AddOption() call to add a user-defined command-line option. We add the option to a separate option group for the local options, creating the group if necessary. """ diff --git a/SCons/Script/SConscript.py b/SCons/Script/SConscript.py index 309bed3..b8dfd93 100644 --- a/SCons/Script/SConscript.py +++ b/SCons/Script/SConscript.py @@ -1,12 +1,6 @@ -"""SCons.Script.SConscript - -This module defines the Python API provided to SConscript and SConstruct -files. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,7 +21,7 @@ files. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""This module defines the Python API provided to SConscript files.""" import SCons import SCons.Action @@ -46,7 +40,6 @@ from SCons.Util import is_List, is_String, is_Dict, flatten from SCons.Node import SConscriptNodes from . import Main -import collections import os import os.path import re @@ -172,7 +165,7 @@ def handle_missing_SConscript(f, must_exist=None): msg = "Fatal: missing SConscript '%s'" % f.get_internal_path() raise SCons.Errors.UserError(msg) - if SCons.Script._warn_missing_sconscript_deprecated: + if SCons.Script._warn_missing_sconscript_deprecated and must_exist is None: msg = "Calling missing SConscript without error is deprecated.\n" + \ "Transition by adding must_exist=0 to SConscript calls.\n" + \ "Missing SConscript '%s'" % f.get_internal_path() diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml index 03efcfb..dc6e7a6 100644 --- a/SCons/Script/SConscript.xml +++ b/SCons/Script/SConscript.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/Script/SConscriptTests.py b/SCons/Script/SConscriptTests.py index 8b2521d..bb88dfa 100644 --- a/SCons/Script/SConscriptTests.py +++ b/SCons/Script/SConscriptTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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.Script.SConscript diff --git a/SCons/Script/__init__.py b/SCons/Script/__init__.py index ee9b382..dff1567 100644 --- a/SCons/Script/__init__.py +++ b/SCons/Script/__init__.py @@ -1,18 +1,6 @@ -"""SCons.Script - -This file implements the main() function used by the scons script. - -Architecturally, this *is* the scons script, and will likely only be -called from the external "scons" wrapper. Consequently, anything here -should not be, or be considered, part of the build engine. If it's -something that we expect other software to want to use, it should go in -some other module. If it's specific to the "scons" script invocation, -it goes here. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,20 +20,23 @@ it goes here. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The main() function used by the scons script. + +Architecturally, this *is* the scons script, and will likely only be +called from the external "scons" wrapper. Consequently, anything here +should not be, or be considered, part of the build engine. If it's +something that we expect other software to want to use, it should go in +some other module. If it's specific to the "scons" script invocation, +it goes here. +""" import time start_time = time.time() import collections import os - -try: - from StringIO import StringIO -except ImportError: - from io import StringIO +from io import StringIO import sys @@ -134,7 +125,6 @@ GetBuildFailures = Main.GetBuildFailures #profiling = Main.profiling #repositories = Main.repositories -# from . import SConscript _SConscript = SConscript @@ -282,7 +272,11 @@ _no_missing_sconscript = False _warn_missing_sconscript_deprecated = True def set_missing_sconscript_error(flag=1): - """Set behavior on missing file in SConscript() call. Returns previous value""" + """Set behavior on missing file in SConscript() call. + + Returns: + previous value + """ global _no_missing_sconscript old = _no_missing_sconscript _no_missing_sconscript = flag diff --git a/SCons/Subst.py b/SCons/Subst.py index 3aa0d8a..ea756ff 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -1,11 +1,6 @@ -"""SCons.Subst - -SCons string substitution. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +21,7 @@ SCons string substitution. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""SCons string substitution.""" import collections import re @@ -36,18 +31,20 @@ import SCons.Errors from SCons.Util import is_String, is_Sequence # Indexed by the SUBST_* constants below. -_strconv = [SCons.Util.to_String_for_subst, - SCons.Util.to_String_for_subst, - SCons.Util.to_String_for_signature] - - +_strconv = [ + SCons.Util.to_String_for_subst, + SCons.Util.to_String_for_subst, + SCons.Util.to_String_for_signature, +] AllowableExceptions = (IndexError, NameError) + def SetAllowableExceptions(*excepts): global AllowableExceptions AllowableExceptions = [_f for _f in excepts if _f] + def raise_exception(exception, target, s): name = exception.__class__.__name__ msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s) @@ -57,7 +54,6 @@ def raise_exception(exception, target, s): raise SCons.Errors.UserError(msg) - class Literal: """A wrapper for a string. If you use this object wrapped around a string, then it will be interpreted as literal. diff --git a/SCons/Subst.xml b/SCons/Subst.xml index 4352de4..0d50bf2 100644 --- a/SCons/Subst.xml +++ b/SCons/Subst.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -__COPYRIGHT__ +Copyright The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. diff --git a/SCons/SubstTests.py b/SCons/SubstTests.py index 07eb61d..8443cad 100644 --- a/SCons/SubstTests.py +++ b/SCons/SubstTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,16 +20,12 @@ # 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.compat import os -import sys import unittest -from collections import UserDict import SCons.Errors @@ -544,9 +541,7 @@ class scons_subst_TestCase(SubstTestCase): scons_subst('$foo.bar.3.0', env) except SCons.Errors.UserError as e: expect = [ - # Python 2.3, 2.4 - "SyntaxError `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'", - # Python 2.5 + # Python 2.5 and later "SyntaxError `invalid syntax (<string>, line 1)' trying to evaluate `$foo.bar.3.0'", ] assert str(e) in expect, e diff --git a/SCons/Taskmaster.py b/SCons/Taskmaster.py index bfb7dc1..a1358e0 100644 --- a/SCons/Taskmaster.py +++ b/SCons/Taskmaster.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,43 +21,33 @@ # 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 sys +"""Generic Taskmaster module for the SCons build engine. -__doc__ = """ - Generic Taskmaster module for the SCons build engine. - ===================================================== - - This module contains the primary interface(s) between a wrapping user - interface and the SCons build engine. There are two key classes here: - - Taskmaster - ---------- - This is the main engine for walking the dependency graph and - calling things to decide what does or doesn't need to be built. - - Task - ---- - This is the base class for allowing a wrapping interface to - decide what does or doesn't actually need to be done. The - intention is for a wrapping interface to subclass this as - appropriate for different types of behavior it may need. - - The canonical example is the SCons native Python interface, - which has Task subclasses that handle its specific behavior, - like printing "'foo' is up to date" when a top-level target - doesn't need to be built, and handling the -c option by removing - targets as its "build" action. There is also a separate subclass - for suppressing this output when the -q option is used. - - The Taskmaster instantiates a Task object for each (set of) - target(s) that it decides need to be evaluated and/or built. -""" +This module contains the primary interface(s) between a wrapping user +interface and the SCons build engine. There are two key classes here: + +Taskmaster + This is the main engine for walking the dependency graph and + calling things to decide what does or doesn't need to be built. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +Task + This is the base class for allowing a wrapping interface to + decide what does or doesn't actually need to be done. The + intention is for a wrapping interface to subclass this as + appropriate for different types of behavior it may need. + + The canonical example is the SCons native Python interface, + which has Task subclasses that handle its specific behavior, + like printing "'foo' is up to date" when a top-level target + doesn't need to be built, and handling the -c option by removing + targets as its "build" action. There is also a separate subclass + for suppressing this output when the -q option is used. + + The Taskmaster instantiates a Task object for each (set of) + target(s) that it decides need to be evaluated and/or built. +""" -import operator import sys -import traceback from abc import ABC, abstractmethod from itertools import chain diff --git a/SCons/TaskmasterTests.py b/SCons/TaskmasterTests.py index c11d8e8..f20fd71 100644 --- a/SCons/TaskmasterTests.py +++ b/SCons/TaskmasterTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,9 @@ # 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.compat -import copy import sys import unittest @@ -867,10 +865,9 @@ class TaskmasterTestCase(unittest.TestCase): except MyException as e: exc_caught = 1 exc_value = e - except Exception as e: - exc_actually_caught = e + except Exception as exc_actually_caught: pass - assert exc_caught, "did not catch expected MyException: %s"%exc_actually_caught + assert exc_caught, "did not catch expected MyException: %s" % exc_actually_caught assert str(exc_value) == "exception value", exc_value assert built_text is None, built_text diff --git a/SCons/Tool/JavaCommon.py b/SCons/Tool/JavaCommon.py index bb05977..d869b38 100644 --- a/SCons/Tool/JavaCommon.py +++ b/SCons/Tool/JavaCommon.py @@ -87,9 +87,10 @@ if java_parsing: # any alphanumeric token surrounded by angle brackets (generics); # the multi-line comment begin and end tokens /* and */; # array declarations "[]". + # Lambda function symbols: -> _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' + r'\d*\.\d*|[A-Za-z_][\w$.]*|<[A-Za-z_]\w+>|' + - r'/\*|\*/|\[\])') + r'/\*|\*/|\[\]|->)') class OuterState: diff --git a/SCons/Tool/JavaCommonTests.py b/SCons/Tool/JavaCommonTests.py index b0a788e..f35cb9e 100644 --- a/SCons/Tool/JavaCommonTests.py +++ b/SCons/Tool/JavaCommonTests.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path -import sys import unittest import fnmatch @@ -97,7 +96,7 @@ public class Foo """Test class names with $ in them""" input = """\ -public class BadDep { +public class BadDep { public void new$rand () {} } """ @@ -484,6 +483,43 @@ public class NestedExample expect = [ 'NestedExample$1', 'NestedExample$1$1', 'NestedExample' ] assert expect == classes, (expect, classes) + def test_lambda_after_new(self): + """Test lamdas after new""" + + input = """\ +// import java.util.*; + +public class LamdaExample +{ + + public void testFunc (int arg1, String arg2, Runnable lambda){ + } + public LamdaExample() + { + testFunc( + 5, + new String("test"), + // Lambda symbol is after new, and used curly braces so + // we should not parse this as a new class. + () -> {} + ); + } + + + public static void main(String argv[]) + { + LamdaExample e = new LamdaExample(); + } +} +""" + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4') + expect = [ 'LamdaExample' ] + assert expect == classes, (expect, classes) + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.8') + expect = [ 'LamdaExample' ] + assert expect == classes, (expect, classes) + def test_private_inner_class_instantiation(self): """Test anonymous inner class generated by private instantiation""" @@ -532,7 +568,7 @@ class Broken * Detected. */ class InnerOK { InnerOK () { } } - + { System.out.println("a number: " + 1000.0 + ""); } diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py index be7720a..ee8f2bd 100644 --- a/SCons/Tool/MSCommon/__init__.py +++ b/SCons/Tool/MSCommon/__init__.py @@ -27,10 +27,6 @@ __doc__ = """ Common functions for Microsoft Visual Studio and Visual C/C++. """ -import copy -import os -import re -import subprocess import SCons.Errors import SCons.Platform.win32 diff --git a/SCons/Tool/MSCommon/arch.py b/SCons/Tool/MSCommon/arch.py index ba57a2c..0032422 100644 --- a/SCons/Tool/MSCommon/arch.py +++ b/SCons/Tool/MSCommon/arch.py @@ -26,7 +26,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" __doc__ = """Module to define supported Windows chip architectures. """ -import os class ArchDefinition: """ diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py index e1a82f2..81004df 100644 --- a/SCons/Tool/MSCommon/common.py +++ b/SCons/Tool/MSCommon/common.py @@ -42,19 +42,46 @@ if LOGFILE == '-': print(message) elif LOGFILE: import logging + modulelist = ( + # root module and parent/root module + 'MSCommon', 'Tool', + # python library and below: correct iff scons does not have a lib folder + 'lib', + # scons modules + 'SCons', 'test', 'scons' + ) + def get_relative_filename(filename, module_list): + if not filename: + return filename + for module in module_list: + try: + ind = filename.rindex(module) + return filename[ind:] + except ValueError: + pass + return filename + class _Debug_Filter(logging.Filter): + # custom filter for module relative filename + def filter(self, record): + relfilename = get_relative_filename(record.pathname, modulelist) + relfilename = relfilename.replace('\\', '/') + record.relfilename = relfilename + return True logging.basicConfig( # This looks like: # 00109ms:MSCommon/vc.py:find_vc_pdir#447: format=( '%(relativeCreated)05dms' - ':MSCommon/%(filename)s' + ':%(relfilename)s' ':%(funcName)s' '#%(lineno)s' ':%(message)s: ' ), filename=LOGFILE, level=logging.DEBUG) - debug = logging.getLogger(name=__name__).debug + logger = logging.getLogger(name=__name__) + logger.addFilter(_Debug_Filter()) + debug = logger.debug else: def debug(x): return None diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py index c6417e9..9a43ae1 100644 --- a/SCons/Tool/MSCommon/vc.py +++ b/SCons/Tool/MSCommon/vc.py @@ -43,7 +43,6 @@ import SCons.Util import subprocess import os import platform -import sys from string import digits as string_digits from subprocess import PIPE @@ -657,16 +656,12 @@ def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version): return False -def cached_get_installed_vcs(env=None): +def 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 + if __INSTALLED_VCS_RUN is not None: + return __INSTALLED_VCS_RUN -def get_installed_vcs(env=None): installed_versions = [] for ver in _VCVER: @@ -687,7 +682,9 @@ def get_installed_vcs(env=None): raise except VisualCException as e: debug('did not find VC %s: caught exception %s' % (ver, str(e))) - return installed_versions + + __INSTALLED_VCS_RUN = installed_versions + return __INSTALLED_VCS_RUN def reset_installed_vcs(): """Make it try again to find VC. This is just for the tests.""" @@ -758,7 +755,7 @@ def get_default_version(env): return msvs_version if not msvc_version: - installed_vcs = cached_get_installed_vcs(env) + installed_vcs = get_installed_vcs(env) debug('installed_vcs:%s' % installed_vcs) if not installed_vcs: #msg = 'No installed VCs' @@ -853,7 +850,7 @@ def msvc_find_valid_batch_script(env, version): 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)) + warn_msg = warn_msg % (version, get_installed_vcs(env)) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) continue @@ -948,7 +945,7 @@ def msvc_setup_env(env): SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) def msvc_exists(env=None, version=None): - vcs = cached_get_installed_vcs(env) + vcs = get_installed_vcs(env) if version is None: return len(vcs) > 0 return version in vcs diff --git a/SCons/Tool/ToolTests.py b/SCons/Tool/ToolTests.py index 75a9454..9a6d9b5 100644 --- a/SCons/Tool/ToolTests.py +++ b/SCons/Tool/ToolTests.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import unittest import TestUnit @@ -84,19 +83,21 @@ class ToolTestCase(unittest.TestCase): assert env['INCPREFIX'] == '-I', env['INCPREFIX'] assert env['TOOLS'] == ['g++'], env['TOOLS'] + exc_caught = None try: SCons.Tool.Tool() except TypeError: - pass - else: # TODO pylint E0704: bare raise not inside except - raise + exc_caught = 1 + assert exc_caught, "did not catch expected UserError" + exc_caught = None try: p = SCons.Tool.Tool('_does_not_exist_') - except SCons.Errors.SConsEnvironmentError: - pass - else: # TODO pylint E0704: bare raise not inside except - raise + except SCons.Errors.UserError as e: + exc_caught = 1 + # Old msg was Python-style "No tool named", check for new msg: + assert "No tool module" in str(e), e + assert exc_caught, "did not catch expected UserError" def test_pathfind(self): diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py index 32017cb..0c7afb8 100644 --- a/SCons/Tool/__init__.py +++ b/SCons/Tool/__init__.py @@ -39,7 +39,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import os -from collections.abc import Callable import importlib.util import SCons.Builder @@ -51,6 +50,8 @@ import SCons.Scanner.D import SCons.Scanner.LaTeX import SCons.Scanner.Prog import SCons.Scanner.SWIG +from SCons.Tool.linkCommon import ShLibPrefixGenerator, LdModPrefixGenerator, ShLibSuffixGenerator, \ + LdModSuffixGenerator, LibSymlinksActionFunction, LibSymlinksStrFun DefaultToolpath = [] @@ -183,13 +184,16 @@ class Tool: if debug: sys.stderr.write("Spec Found? .%s :%s\n" % (self.name, spec)) if spec is None: - error_string = "No module named %s" % self.name - raise SCons.Errors.SConsEnvironmentError(error_string) + sconstools = os.path.normpath(sys.modules['SCons.Tool'].__path__[0]) + if self.toolpath: + sconstools = ", ".join(self.toolpath) + ", " + sconstools + error_string = "No tool module '%s' found in %s" % (self.name, sconstools) + raise SCons.Errors.UserError(error_string) module = importlib.util.module_from_spec(spec) if module is None: if debug: print("MODULE IS NONE:%s" % self.name) - error_string = "No module named %s" % self.name + error_string = "Tool module '%s' failed import" % self.name raise SCons.Errors.SConsEnvironmentError(error_string) # Don't reload a tool we already loaded. @@ -272,6 +276,9 @@ class Tool: return self.name +LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) + + ########################################################################## # Create common executable program / library / object builders @@ -325,485 +332,6 @@ def createStaticLibBuilder(env): return static_lib -def _call_linker_cb(env, callback, args, result=None): - """Returns the result of env['LINKCALLBACKS'][callback](*args) - if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback] - is callable. If these conditions are not met, return the value provided as - the *result* argument. This function is mainly used for generating library - info such as versioned suffixes, symlink maps, sonames etc. by delegating - the core job to callbacks configured by current linker tool""" - - Verbose = False - - if Verbose: - print('_call_linker_cb: args=%r' % args) - print('_call_linker_cb: callback=%r' % callback) - - try: - cbfun = env['LINKCALLBACKS'][callback] - except (KeyError, TypeError): - if Verbose: - print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) - pass - else: - if Verbose: - print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) - print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) - if isinstance(cbfun, Callable): - if Verbose: - print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) - result = cbfun(env, *args) - return result - - -def _call_env_subst(env, string, *args, **kw): - kw2 = {} - for k in ('raw', 'target', 'source', 'conv', 'executor'): - try: - kw2[k] = kw[k] - except KeyError: - pass - return env.subst(string, *args, **kw2) - - -class _ShLibInfoSupport: - @property - def libtype(self): - return 'ShLib' - - def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env, '$SHLIBPREFIX', *args, **kw) - - def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env, '$SHLIBSUFFIX', *args, **kw) - - def get_lib_version(self, env, *args, **kw): - return _call_env_subst(env, '$SHLIBVERSION', *args, **kw) - - def get_lib_noversionsymlinks(self, env, *args, **kw): - return _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) - - -class _LdModInfoSupport: - @property - def libtype(self): - return 'LdMod' - - def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env, '$LDMODULEPREFIX', *args, **kw) - - def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env, '$LDMODULESUFFIX', *args, **kw) - - def get_lib_version(self, env, *args, **kw): - return _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) - - def get_lib_noversionsymlinks(self, env, *args, **kw): - return _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) - - -class _ImpLibInfoSupport: - @property - def libtype(self): - return 'ImpLib' - - def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env, '$IMPLIBPREFIX', *args, **kw) - - def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env, '$IMPLIBSUFFIX', *args, **kw) - - def get_lib_version(self, env, *args, **kw): - version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) - if not version: - try: - lt = kw['implib_libtype'] - except KeyError: - pass - else: - if lt == 'ShLib': - version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) - elif lt == 'LdMod': - version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) - return version - - def get_lib_noversionsymlinks(self, env, *args, **kw): - disable = None - try: - env['IMPLIBNOVERSIONSYMLINKS'] - except KeyError: - try: - lt = kw['implib_libtype'] - except KeyError: - pass - else: - if lt == 'ShLib': - disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) - elif lt == 'LdMod': - disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) - else: - disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) - return disable - - -class _LibInfoGeneratorBase: - """Generator base class for library-related info such as suffixes for - versioned libraries, symlink maps, sonames etc. It handles commonities - of SharedLibrary and LoadableModule - """ - _support_classes = {'ShLib': _ShLibInfoSupport, - 'LdMod': _LdModInfoSupport, - 'ImpLib': _ImpLibInfoSupport} - - def __init__(self, libtype, infoname): - self.libtype = libtype - self.infoname = infoname - - @property - def libtype(self): - return self._support.libtype - - @libtype.setter - def libtype(self, libtype): - try: - support_class = self._support_classes[libtype] - except KeyError: - raise ValueError('unsupported libtype %r' % libtype) - self._support = support_class() - - def get_lib_prefix(self, env, *args, **kw): - return self._support.get_lib_prefix(env, *args, **kw) - - def get_lib_suffix(self, env, *args, **kw): - return self._support.get_lib_suffix(env, *args, **kw) - - def get_lib_version(self, env, *args, **kw): - return self._support.get_lib_version(env, *args, **kw) - - def get_lib_noversionsymlinks(self, env, *args, **kw): - return self._support.get_lib_noversionsymlinks(env, *args, **kw) - - def get_versioned_lib_info_generator(self, **kw): - """ - Returns name of generator linker callback that will be used to generate - our info for a versioned library. For example, if our libtype is 'ShLib' - and infoname is 'Prefix', it would return 'VersionedShLibPrefix'. - """ - try: - libtype = kw['generator_libtype'] - except KeyError: - libtype = self.libtype - return 'Versioned%s%s' % (libtype, self.infoname) - - def generate_versioned_lib_info(self, env, args, result=None, **kw): - callback = self.get_versioned_lib_info_generator(**kw) - return _call_linker_cb(env, callback, args, result) - - -class _LibPrefixGenerator(_LibInfoGeneratorBase): - """Library prefix generator, used as target_prefix in SharedLibrary and - LoadableModule builders""" - - def __init__(self, libtype): - super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix') - - def __call__(self, env, sources=None, **kw): - Verbose = False - - if sources and 'source' not in kw: - kw2 = kw.copy() - kw2['source'] = sources - else: - kw2 = kw - - prefix = self.get_lib_prefix(env, **kw2) - if Verbose: - print("_LibPrefixGenerator: input prefix=%r" % prefix) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print("_LibPrefixGenerator: version=%r" % version) - - if version: - prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) - - if Verbose: - print("_LibPrefixGenerator: return prefix=%r" % prefix) - return prefix - - -ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') -LdModPrefixGenerator = _LibPrefixGenerator('LdMod') -ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib') - - -class _LibSuffixGenerator(_LibInfoGeneratorBase): - """Library suffix generator, used as target_suffix in SharedLibrary and - LoadableModule builders""" - - def __init__(self, libtype): - super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix') - - def __call__(self, env, sources=None, **kw): - Verbose = False - - if sources and 'source' not in kw: - kw2 = kw.copy() - kw2['source'] = sources - else: - kw2 = kw - - suffix = self.get_lib_suffix(env, **kw2) - if Verbose: - print("_LibSuffixGenerator: input suffix=%r" % suffix) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print("_LibSuffixGenerator: version=%r" % version) - - if version: - suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) - - if Verbose: - print("_LibSuffixGenerator: return suffix=%r" % suffix) - return suffix - - -ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') -LdModSuffixGenerator = _LibSuffixGenerator('LdMod') -ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') - - -class _LibSymlinkGenerator(_LibInfoGeneratorBase): - """Library symlink map generator. It generates a list of symlinks that - should be created by SharedLibrary or LoadableModule builders""" - - def __init__(self, libtype): - super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks') - - def __call__(self, env, libnode, **kw): - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) - - symlinks = None - - version = self.get_lib_version(env, **kw2) - disable = self.get_lib_noversionsymlinks(env, **kw2) - if Verbose: - print('_LibSymlinkGenerator: version=%r' % version) - print('_LibSymlinkGenerator: disable=%r' % disable) - - if version and not disable: - prefix = self.get_lib_prefix(env, **kw2) - suffix = self.get_lib_suffix(env, **kw2) - symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) - - if Verbose: - print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks)) - return symlinks - - -ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') -LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') -ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') - - -class _LibNameGenerator(_LibInfoGeneratorBase): - """Generates "unmangled" library name from a library file node. - - Generally, it's thought to revert modifications done by prefix/suffix - generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library - builder. For example, on gnulink the suffix generator used by SharedLibrary - builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which - ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation - of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with - "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", - $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", - the _LibNameGenerator shall return "libfoo.so". Other link tools may - implement it's own way of library name unmangling. - """ - - def __init__(self, libtype): - super(_LibNameGenerator, self).__init__(libtype, 'Name') - - def __call__(self, env, libnode, **kw): - """Returns "demangled" library name""" - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibNameGenerator: libnode=%r" % libnode.get_path()) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print('_LibNameGenerator: version=%r' % version) - - name = None - if version: - prefix = self.get_lib_prefix(env, **kw2) - suffix = self.get_lib_suffix(env, **kw2) - name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) - - if not name: - name = os.path.basename(libnode.get_path()) - - if Verbose: - print('_LibNameGenerator: return name=%r' % name) - - return name - - -ShLibNameGenerator = _LibNameGenerator('ShLib') -LdModNameGenerator = _LibNameGenerator('LdMod') -ImpLibNameGenerator = _LibNameGenerator('ImpLib') - - -class _LibSonameGenerator(_LibInfoGeneratorBase): - """Library soname generator. Returns library soname (e.g. libfoo.so.0) for - a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" - - def __init__(self, libtype): - super(_LibSonameGenerator, self).__init__(libtype, 'Soname') - - def __call__(self, env, libnode, **kw): - """Returns a SONAME based on a shared library's node path""" - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) - - soname = _call_env_subst(env, '$SONAME', **kw2) - if not soname: - version = self.get_lib_version(env, **kw2) - if Verbose: - print("_LibSonameGenerator: version=%r" % version) - if version: - prefix = self.get_lib_prefix(env, **kw2) - suffix = self.get_lib_suffix(env, **kw2) - soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) - - if not soname: - # fallback to library name (as returned by appropriate _LibNameGenerator) - soname = _LibNameGenerator(self.libtype)(env, libnode) - if Verbose: - print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) - - if Verbose: - print("_LibSonameGenerator: return soname=%r" % soname) - - return soname - - -ShLibSonameGenerator = _LibSonameGenerator('ShLib') -LdModSonameGenerator = _LibSonameGenerator('LdMod') - - -def StringizeLibSymlinks(symlinks): - """Converts list with pairs of nodes to list with pairs of node paths - (strings). Used mainly for debugging.""" - if SCons.Util.is_List(symlinks): - try: - return [(k.get_path(), v.get_path()) for k, v in symlinks] - except (TypeError, ValueError): - return symlinks - else: - return symlinks - - -def EmitLibSymlinks(env, symlinks, libnode, **kw): - """Used by emitters to handle (shared/versioned) library symlinks""" - Verbose = False - - # nodes involved in process... all symlinks + library - nodes = list(set([x for x, y in symlinks] + [libnode])) - - clean_targets = kw.get('clean_targets', []) - if not SCons.Util.is_List(clean_targets): - clean_targets = [clean_targets] - - for link, linktgt in symlinks: - env.SideEffect(link, linktgt) - if Verbose: - print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path())) - clean_list = [x for x in nodes if x != linktgt] - env.Clean(list(set([linktgt] + clean_targets)), clean_list) - if Verbose: - print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list])) - - -def CreateLibSymlinks(env, symlinks): - """Physically creates symlinks. The symlinks argument must be a list in - form [ (link, linktarget), ... ], where link and linktarget are SCons - nodes. - """ - - Verbose = False - for link, linktgt in symlinks: - linktgt = link.get_dir().rel_path(linktgt) - link = link.get_path() - if Verbose: - print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt)) - # Delete the (previously created) symlink if exists. Let only symlinks - # to be deleted to prevent accidental deletion of source files... - if env.fs.islink(link): - env.fs.unlink(link) - if Verbose: - print("CreateLibSymlinks: removed old symlink %r" % link) - # If a file or directory exists with the same name as link, an OSError - # will be thrown, which should be enough, I think. - env.fs.symlink(linktgt, link) - if Verbose: - print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt)) - return 0 - - -def LibSymlinksActionFunction(target, source, env): - for tgt in target: - symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) - if symlinks: - CreateLibSymlinks(env, symlinks) - return 0 - - -def LibSymlinksStrFun(target, source, env, *args): - cmd = None - for tgt in target: - symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) - if symlinks: - if cmd is None: cmd = "" - if cmd: cmd += "\n" - cmd += "Create symlinks for: %r" % tgt.get_path() - try: - linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]) - except (KeyError, ValueError): - pass - else: - cmd += ": %s" % linkstr - return cmd - - -LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) - - def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary Builder in an Environment if it is not there already. diff --git a/SCons/Tool/applelink.py b/SCons/Tool/applelink.py index 8c081a2..aec8b93 100644 --- a/SCons/Tool/applelink.py +++ b/SCons/Tool/applelink.py @@ -39,11 +39,13 @@ import SCons.Util # the -rpath option, so we use the "link" tool instead of "gnulink". from . import link -from SCons.Tool import ShLibSonameGenerator +from .linkCommon import ShLibSonameGenerator + class AppleLinkInvalidCurrentVersionException(Exception): pass + class AppleLinkInvalidCompatibilityVersionException(Exception): pass @@ -70,7 +72,7 @@ def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_f if Verbose: print("_applelib_versioned_lib_soname: name={!r}".format(name)) major = version.split('.')[0] - (libname,_suffix) = name.split('.') + (libname, _suffix) = name.split('.') # if a desired SONAME was supplied, use that, otherwise create # a default from the major version if env.get('SONAME'): @@ -81,12 +83,15 @@ def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_f 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. @@ -99,17 +104,18 @@ def _applelib_check_valid_version(version_string): """ parts = version_string.split('.') if len(parts) > 3: - return False, "Version string has too many periods [%s]"%version_string + return False, "Version string has too many periods [%s]" % version_string if len(parts) <= 0: - return False, "Version string unspecified [%s]"%version_string + 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) + 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 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, "" @@ -190,9 +196,8 @@ def generate(env): 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) + link._setup_versioned_lib_variables(env, tool='applelink') #, use_soname=True) env['LINKCALLBACKS'] = link._versioned_lib_callbacks() env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname @@ -205,15 +210,14 @@ def generate(env): # 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['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' diff --git a/SCons/Tool/clang.py b/SCons/Tool/clang.py index 162daad..e39c742 100644 --- a/SCons/Tool/clang.py +++ b/SCons/Tool/clang.py @@ -84,8 +84,7 @@ def generate(env): # clang -dumpversion is of no use with pipe.stdout: line = pipe.stdout.readline() - if sys.version_info[0] > 2: - line = line.decode() + line = line.decode() match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) if match: env['CCVERSION'] = match.group(1) diff --git a/SCons/Tool/clangxx.py b/SCons/Tool/clangxx.py index b1dc6f3..736d455 100644 --- a/SCons/Tool/clangxx.py +++ b/SCons/Tool/clangxx.py @@ -92,8 +92,7 @@ def generate(env): # clang -dumpversion is of no use with pipe.stdout: line = pipe.stdout.readline() - if sys.version_info[0] > 2: - line = line.decode() + line = line.decode() match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) if match: env['CXXVERSION'] = match.group(1) diff --git a/SCons/Tool/cyglink.py b/SCons/Tool/cyglink.py index fbb6d24..08b8a98 100644 --- a/SCons/Tool/cyglink.py +++ b/SCons/Tool/cyglink.py @@ -12,19 +12,25 @@ import re import os import SCons.Action +from SCons.Tool.linkCommon import ImpLibSymlinkGenerator, StringizeLibSymlinks, EmitLibSymlinks, ImpLibPrefixGenerator, \ + ImpLibSuffixGenerator, ImpLibNameGenerator import SCons.Util import SCons.Tool -#MAYBE: from . import gnulink from . import gnulink from . import link + def _lib_generator(target, source, env, for_signature, **kw): - try: cmd = kw['cmd'] - except KeyError: cmd = SCons.Util.CLVar(['$SHLINK']) + try: + cmd = kw['cmd'] + except KeyError: + cmd = SCons.Util.CLVar(['$SHLINK']) - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' + try: + vp = kw['varprefix'] + except KeyError: + vp = 'SHLIB' dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) if dll: cmd.extend(['-o', dll]) @@ -34,12 +40,12 @@ def _lib_generator(target, source, env, for_signature, **kw): implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX') if implib: cmd.extend([ - '-Wl,--out-implib='+implib.get_string(for_signature), + '-Wl,--out-implib=' + implib.get_string(for_signature), '-Wl,--export-all-symbols', '-Wl,--enable-auto-import', '-Wl,--whole-archive', '$SOURCES', '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS' - ]) + ]) else: cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) @@ -49,12 +55,14 @@ def _lib_generator(target, source, env, for_signature, **kw): def shlib_generator(target, source, env, for_signature): return _lib_generator(target, source, env, for_signature, varprefix='SHLIB', - cmd = SCons.Util.CLVar(['$SHLINK'])) + cmd=SCons.Util.CLVar(['$SHLINK'])) + def ldmod_generator(target, source, env, for_signature): return _lib_generator(target, source, env, for_signature, varprefix='LDMODULE', - cmd = SCons.Util.CLVar(['$LDMODULE'])) + cmd=SCons.Util.CLVar(['$LDMODULE'])) + def _lib_emitter(target, source, env, **kw): Verbose = False @@ -62,11 +70,15 @@ def _lib_emitter(target, source, env, **kw): if Verbose: print("_lib_emitter: target[0]=%r" % target[0].get_path()) - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' + try: + vp = kw['varprefix'] + except KeyError: + vp = 'SHLIB' - try: libtype = kw['libtype'] - except KeyError: libtype = 'ShLib' + try: + libtype = kw['libtype'] + except KeyError: + libtype = 'ShLib' dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) no_import_lib = env.get('no_import_lib', 0) @@ -75,12 +87,13 @@ def _lib_emitter(target, source, env, **kw): print("_lib_emitter: dll=%r" % dll.get_path()) if not dll or len(target) > 1: - raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) + raise SCons.Errors.UserError( + "A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) # Remove any "lib" after the prefix pre = env.subst('$%sPREFIX' % vp) - if dll.name[len(pre):len(pre)+3] == 'lib': - dll.name = pre + dll.name[len(pre)+3:] + if dll.name[len(pre):len(pre) + 3] == 'lib': + dll.name = pre + dll.name[len(pre) + 3:] if Verbose: print("_lib_emitter: dll.name=%r" % dll.name) @@ -107,23 +120,26 @@ def _lib_emitter(target, source, env, **kw): implib_target.attributes.shared = 1 target.append(implib_target) - symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') + symlinks = ImpLibSymlinkGenerator(env, implib_target, + implib_libtype=libtype, + generator_libtype=libtype + 'ImpLib') if Verbose: - print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + print("_lib_emitter: implib symlinks=%r" % StringizeLibSymlinks(symlinks)) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) + EmitLibSymlinks(env, symlinks, implib_target, clean_targets=target[0]) implib_target.attributes.shliblinks = symlinks return (target, source) + def shlib_emitter(target, source, env): return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib') + def ldmod_emitter(target, source, env): return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod') + def _versioned_lib_suffix(env, suffix, version): """Generate versioned shared library suffix from a unversioned one. If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'""" @@ -138,12 +154,14 @@ def _versioned_lib_suffix(env, suffix, version): print("_versioned_lib_suffix: return suffix= ", suffix) return suffix + def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw): return link._versioned_lib_name(env, libnode, version, prefix, suffix, - SCons.Tool.ImpLibPrefixGenerator, - SCons.Tool.ImpLibSuffixGenerator, + ImpLibPrefixGenerator, + ImpLibSuffixGenerator, implib_libtype=kw['libtype']) + def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): """Generate link names that should be created for a versioned shared library. Returns a list in the form [ (link, linktarget), ... ] @@ -154,17 +172,18 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path()) print("_versioned_implib_symlinks: version=%r" % version) - try: libtype = kw['libtype'] - except KeyError: libtype = 'ShLib' - + try: + libtype = kw['libtype'] + except KeyError: + libtype = 'ShLib' linkdir = os.path.dirname(libnode.get_path()) if Verbose: print("_versioned_implib_symlinks: linkdir=%r" % linkdir) - name = SCons.Tool.ImpLibNameGenerator(env, libnode, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') + name = ImpLibNameGenerator(env, libnode, + implib_libtype=libtype, + generator_libtype=libtype + 'ImpLib') if Verbose: print("_versioned_implib_symlinks: name=%r" % name) @@ -174,59 +193,65 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): symlinks = [(link0, libnode)] if Verbose: - print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + print("_versioned_implib_symlinks: return symlinks=%r" % StringizeLibSymlinks(symlinks)) return symlinks + shlib_action = SCons.Action.Action(shlib_generator, generator=1) ldmod_action = SCons.Action.Action(ldmod_generator, generator=1) + def generate(env): """Add Builders and construction variables for cyglink to an Environment.""" gnulink.generate(env) - env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined') + env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined') env['SHLINKCOM'] = shlib_action env['LDMODULECOM'] = ldmod_action - env.Append(SHLIBEMITTER = [shlib_emitter]) - env.Append(LDMODULEEMITTER = [ldmod_emitter]) + env.Append(SHLIBEMITTER=[shlib_emitter]) + env.Append(LDMODULEEMITTER=[ldmod_emitter]) - env['SHLIBPREFIX'] = 'cyg' - env['SHLIBSUFFIX'] = '.dll' + env['SHLIBPREFIX'] = 'cyg' + env['SHLIBSUFFIX'] = '.dll' - env['IMPLIBPREFIX'] = 'lib' - env['IMPLIBSUFFIX'] = '.dll.a' + env['IMPLIBPREFIX'] = 'lib' + env['IMPLIBSUFFIX'] = '.dll.a' # Variables used by versioned shared libraries - env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' - env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink... # LINKCALLBACKS are NOT inherited from gnulink env['LINKCALLBACKS'] = { - 'VersionedShLibSuffix' : _versioned_lib_suffix, - 'VersionedLdModSuffix' : _versioned_lib_suffix, - 'VersionedImpLibSuffix' : _versioned_lib_suffix, - 'VersionedShLibName' : link._versioned_shlib_name, - 'VersionedLdModName' : link._versioned_ldmod_name, - 'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'), - 'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'), - 'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), - 'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), + 'VersionedShLibSuffix': _versioned_lib_suffix, + 'VersionedLdModSuffix': _versioned_lib_suffix, + 'VersionedImpLibSuffix': _versioned_lib_suffix, + 'VersionedShLibName': link._versioned_shlib_name, + 'VersionedLdModName': link._versioned_ldmod_name, + 'VersionedShLibImpLibName': lambda *args: _versioned_implib_name(*args, libtype='ShLib'), + 'VersionedLdModImpLibName': lambda *args: _versioned_implib_name(*args, libtype='LdMod'), + 'VersionedShLibImpLibSymlinks': lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), + 'VersionedLdModImpLibSymlinks': lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), } # these variables were set by gnulink but are not used in cyglink - try: del env['_SHLIBSONAME'] - except KeyError: pass - try: del env['_LDMODULESONAME'] - except KeyError: pass + try: + del env['_SHLIBSONAME'] + except KeyError: + pass + try: + del env['_LDMODULESONAME'] + except KeyError: + pass + def exists(env): return gnulink.exists(env) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/SCons/Tool/dmd.py b/SCons/Tool/dmd.py index ba12131..5970246 100644 --- a/SCons/Tool/dmd.py +++ b/SCons/Tool/dmd.py @@ -50,8 +50,6 @@ LIBS """ # -# __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 @@ -72,11 +70,6 @@ LIBS # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import subprocess - import SCons.Action import SCons.Builder import SCons.Defaults @@ -84,6 +77,7 @@ import SCons.Scanner.D import SCons.Tool import SCons.Tool.DCommon as DCommon +from SCons.Tool.linkCommon import ShLibSonameGenerator def generate(env): @@ -128,7 +122,8 @@ def generate(env): env['SHDLINK'] = '$DC' env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so') - env['SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + env[ + 'SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' @@ -139,7 +134,8 @@ def generate(env): env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' - env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format( + '-c ' if env['PLATFORM'] == 'win32' else '') # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' @@ -157,7 +153,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' @@ -172,7 +168,6 @@ def generate(env): def exists(env): return env.Detect(['dmd', 'ldmd2', 'gdmd']) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py b/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py index 3d53bf7..d79ece3 100644 --- a/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py +++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py @@ -1,7 +1,5 @@ # docbook.py: extension module # $Id: docbook.py 8353 2009-03-17 16:57:50Z mzjn $ -import sys -import string import libxml2 import libxslt import re diff --git a/SCons/Tool/fortran.py b/SCons/Tool/fortran.py index aeb9130..0a68df6 100644 --- a/SCons/Tool/fortran.py +++ b/SCons/Tool/fortran.py @@ -33,7 +33,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import re import SCons.Action import SCons.Defaults diff --git a/SCons/Tool/gcc.py b/SCons/Tool/gcc.py index d56f6a0..37626ef 100644 --- a/SCons/Tool/gcc.py +++ b/SCons/Tool/gcc.py @@ -34,7 +34,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" from . import cc -import os import re import subprocess diff --git a/SCons/Tool/gdc.py b/SCons/Tool/gdc.py index ecf4f3a..12c327e 100644 --- a/SCons/Tool/gdc.py +++ b/SCons/Tool/gdc.py @@ -53,6 +53,7 @@ import SCons.Defaults import SCons.Tool import SCons.Tool.DCommon as DCommon +import SCons.Tool.linkCommon def generate(env): @@ -120,7 +121,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.linkCommon.ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' diff --git a/SCons/Tool/gxx.py b/SCons/Tool/gxx.py index 4b86327..88186cb 100644 --- a/SCons/Tool/gxx.py +++ b/SCons/Tool/gxx.py @@ -33,9 +33,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path -import re -import subprocess import SCons.Tool import SCons.Util diff --git a/SCons/Tool/install.py b/SCons/Tool/install.py index 67c9ec8..e79203e 100644 --- a/SCons/Tool/install.py +++ b/SCons/Tool/install.py @@ -29,13 +29,13 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os from shutil import copy2, copymode, copystat import SCons.Action import SCons.Tool +from SCons.Tool.linkCommon import StringizeLibSymlinks, CreateLibSymlinks, EmitLibSymlinks import SCons.Util # @@ -213,9 +213,9 @@ def installShlibLinks(dest, source, env): Verbose = False symlinks = listShlibLinksToInstall(dest, source, env) if Verbose: - print('installShlibLinks: symlinks={!r}'.format(SCons.Tool.StringizeLibSymlinks(symlinks))) + print('installShlibLinks: symlinks={!r}'.format(StringizeLibSymlinks(symlinks))) if symlinks: - SCons.Tool.CreateLibSymlinks(env, symlinks) + CreateLibSymlinks(env, symlinks) return def installFunc(target, source, env): @@ -292,7 +292,7 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env): print("add_versioned_targets_to_INSTALLED_FILES: target={!r}".format(list(map(str, target)))) symlinks = listShlibLinksToInstall(target[0], source, env) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + EmitLibSymlinks(env, symlinks, target[0]) _UNIQUE_INSTALLED_FILES = None return (target, source) diff --git a/SCons/Tool/intelc.py b/SCons/Tool/intelc.py index 38bdc32..5025719 100644 --- a/SCons/Tool/intelc.py +++ b/SCons/Tool/intelc.py @@ -32,7 +32,11 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import math, sys, os.path, glob, string, re +import glob +import math +import os.path +import re +import sys is_windows = sys.platform == 'win32' is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or diff --git a/SCons/Tool/ldc.py b/SCons/Tool/ldc.py index f915569..d893841 100644 --- a/SCons/Tool/ldc.py +++ b/SCons/Tool/ldc.py @@ -24,8 +24,6 @@ Lib tool variables: """ # -# __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 @@ -46,11 +44,6 @@ Lib tool variables: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import subprocess - import SCons.Action import SCons.Builder import SCons.Defaults @@ -58,6 +51,7 @@ import SCons.Scanner.D import SCons.Tool import SCons.Tool.DCommon as DCommon +from SCons.Tool.linkCommon import ShLibSonameGenerator def generate(env): @@ -133,7 +127,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' diff --git a/SCons/Tool/link.py b/SCons/Tool/link.py index a3567aa..de377ac 100644 --- a/SCons/Tool/link.py +++ b/SCons/Tool/link.py @@ -9,8 +9,6 @@ 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 @@ -30,7 +28,6 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import re @@ -46,7 +43,9 @@ from SCons.Tool.DCommon import isD from SCons.Tool.cxx import iscplusplus -from SCons.Tool import ShLibSonameGenerator +from SCons.Tool.linkCommon import StringizeLibSymlinks, ShLibSonameGenerator, EmitLibSymlinks, ShLibSymlinkGenerator, \ + LdModSymlinkGenerator, ShLibPrefixGenerator, ShLibSuffixGenerator, LdModPrefixGenerator, LdModSuffixGenerator, \ + LdModSonameGenerator issued_mixed_link_warning = False @@ -97,17 +96,17 @@ def _lib_emitter(target, source, env, **kw): print("_lib_emitter: symlinks={!r}".format(symlinks)) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + EmitLibSymlinks(env, symlinks, target[0]) target[0].attributes.shliblinks = symlinks return (target, source) def shlib_emitter(target, source, env): - return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.ShLibSymlinkGenerator) + return _lib_emitter(target, source, env, symlink_generator=ShLibSymlinkGenerator) def ldmod_emitter(target, source, env): - return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.LdModSymlinkGenerator) + return _lib_emitter(target, source, env, symlink_generator=LdModSymlinkGenerator) # This is generic enough to be included here... @@ -142,14 +141,14 @@ def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw): - prefix_generator = SCons.Tool.ShLibPrefixGenerator - suffix_generator = SCons.Tool.ShLibSuffixGenerator + prefix_generator = ShLibPrefixGenerator + suffix_generator = ShLibSuffixGenerator return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw): - prefix_generator = SCons.Tool.LdModPrefixGenerator - suffix_generator = SCons.Tool.LdModSuffixGenerator + prefix_generator = LdModPrefixGenerator + suffix_generator = LdModSuffixGenerator return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) @@ -236,7 +235,8 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so symlinks = [(link0, libnode), (link1, libnode)] if Verbose: - print("_versioned_lib_symlinks: return symlinks={!r}".format(SCons.Tool.StringizeLibSymlinks(symlinks))) + print("_versioned_lib_symlinks: return symlinks={!r}".format( + StringizeLibSymlinks(symlinks))) return symlinks @@ -301,8 +301,8 @@ def _setup_versioned_lib_variables(env, **kw): env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME' env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' - env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator - env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator + env['ShLibSonameGenerator'] = ShLibSonameGenerator + env['LdModSonameGenerator'] = LdModSonameGenerator else: env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' diff --git a/SCons/Tool/linkCommon/__init__.py b/SCons/Tool/linkCommon/__init__.py new file mode 100644 index 0000000..f66ad6d --- /dev/null +++ b/SCons/Tool/linkCommon/__init__.py @@ -0,0 +1,502 @@ +"""SCons.Tool.linkCommon + +Common link/shared library logic +""" + +# +# 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 os +from typing import Callable +from SCons.Util import is_List + + +def _call_linker_cb(env, callback, args, result=None): + """Returns the result of env['LINKCALLBACKS'][callback](*args) + if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback] + is callable. If these conditions are not met, return the value provided as + the *result* argument. This function is mainly used for generating library + info such as versioned suffixes, symlink maps, sonames etc. by delegating + the core job to callbacks configured by current linker tool""" + + Verbose = False + + if Verbose: + print('_call_linker_cb: args=%r' % args) + print('_call_linker_cb: callback=%r' % callback) + + try: + cbfun = env['LINKCALLBACKS'][callback] + except (KeyError, TypeError): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) + else: + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) + print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) + if isinstance(cbfun, Callable): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) + result = cbfun(env, *args) + return result + + +class _ShLibInfoSupport: + @property + def libtype(self): + return 'ShLib' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBSUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + + +class _LdModInfoSupport: + @property + def libtype(self): + return 'LdMod' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULEPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULESUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + + +class _ImpLibInfoSupport: + @property + def libtype(self): + return 'ImpLib' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$IMPLIBPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$IMPLIBSUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) + if not version: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + elif lt == 'LdMod': + version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + return version + + def get_lib_noversionsymlinks(self, env, *args, **kw): + disable = None + try: + env['IMPLIBNOVERSIONSYMLINKS'] + except KeyError: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + elif lt == 'LdMod': + disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + else: + disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) + return disable + + +class _LibInfoGeneratorBase: + """Generator base class for library-related info such as suffixes for + versioned libraries, symlink maps, sonames etc. It handles commonities + of SharedLibrary and LoadableModule + """ + _support_classes = {'ShLib': _ShLibInfoSupport, + 'LdMod': _LdModInfoSupport, + 'ImpLib': _ImpLibInfoSupport} + + def __init__(self, libtype, infoname): + self.libtype = libtype + self.infoname = infoname + + @property + def libtype(self): + return self._support.libtype + + @libtype.setter + def libtype(self, libtype): + try: + support_class = self._support_classes[libtype] + except KeyError: + raise ValueError('unsupported libtype %r' % libtype) + self._support = support_class() + + def get_lib_prefix(self, env, *args, **kw): + return self._support.get_lib_prefix(env, *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return self._support.get_lib_suffix(env, *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return self._support.get_lib_version(env, *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return self._support.get_lib_noversionsymlinks(env, *args, **kw) + + def get_versioned_lib_info_generator(self, **kw): + """ + Returns name of generator linker callback that will be used to generate + our info for a versioned library. For example, if our libtype is 'ShLib' + and infoname is 'Prefix', it would return 'VersionedShLibPrefix'. + """ + try: + libtype = kw['generator_libtype'] + except KeyError: + libtype = self.libtype + return 'Versioned%s%s' % (libtype, self.infoname) + + def generate_versioned_lib_info(self, env, args, result=None, **kw): + callback = self.get_versioned_lib_info_generator(**kw) + return _call_linker_cb(env, callback, args, result) + + +class _LibPrefixGenerator(_LibInfoGeneratorBase): + """Library prefix generator, used as target_prefix in SharedLibrary and + LoadableModule builders""" + + def __init__(self, libtype): + super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix') + + def __call__(self, env, sources=None, **kw): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + prefix = self.get_lib_prefix(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: input prefix=%r" % prefix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: version=%r" % version) + + if version: + prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) + + if Verbose: + print("_LibPrefixGenerator: return prefix=%r" % prefix) + return prefix + + +ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') +LdModPrefixGenerator = _LibPrefixGenerator('LdMod') +ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib') + + +class _LibSuffixGenerator(_LibInfoGeneratorBase): + """Library suffix generator, used as target_suffix in SharedLibrary and + LoadableModule builders""" + + def __init__(self, libtype): + super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix') + + def __call__(self, env, sources=None, **kw): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + suffix = self.get_lib_suffix(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: input suffix=%r" % suffix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: version=%r" % version) + + if version: + suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) + + if Verbose: + print("_LibSuffixGenerator: return suffix=%r" % suffix) + return suffix + + +ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') +LdModSuffixGenerator = _LibSuffixGenerator('LdMod') +ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') + + +class _LibSymlinkGenerator(_LibInfoGeneratorBase): + """Library symlink map generator. It generates a list of symlinks that + should be created by SharedLibrary or LoadableModule builders""" + + def __init__(self, libtype): + super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks') + + def __call__(self, env, libnode, **kw): + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) + + symlinks = None + + version = self.get_lib_version(env, **kw2) + disable = self.get_lib_noversionsymlinks(env, **kw2) + if Verbose: + print('_LibSymlinkGenerator: version=%r' % version) + print('_LibSymlinkGenerator: disable=%r' % disable) + + if version and not disable: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if Verbose: + print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks)) + return symlinks + + +ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') +LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') +ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') + + +class _LibNameGenerator(_LibInfoGeneratorBase): + """Generates "unmangled" library name from a library file node. + + Generally, it's thought to revert modifications done by prefix/suffix + generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library + builder. For example, on gnulink the suffix generator used by SharedLibrary + builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which + ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation + of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with + "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", + $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", + the _LibNameGenerator shall return "libfoo.so". Other link tools may + implement it's own way of library name unmangling. + """ + + def __init__(self, libtype): + super(_LibNameGenerator, self).__init__(libtype, 'Name') + + def __call__(self, env, libnode, **kw): + """Returns "demangled" library name""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibNameGenerator: libnode=%r" % libnode.get_path()) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print('_LibNameGenerator: version=%r' % version) + + name = None + if version: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if not name: + name = os.path.basename(libnode.get_path()) + + if Verbose: + print('_LibNameGenerator: return name=%r' % name) + + return name + + +ShLibNameGenerator = _LibNameGenerator('ShLib') +LdModNameGenerator = _LibNameGenerator('LdMod') +ImpLibNameGenerator = _LibNameGenerator('ImpLib') + + +class _LibSonameGenerator(_LibInfoGeneratorBase): + """Library soname generator. Returns library soname (e.g. libfoo.so.0) for + a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" + + def __init__(self, libtype): + super(_LibSonameGenerator, self).__init__(libtype, 'Soname') + + def __call__(self, env, libnode, **kw): + """Returns a SONAME based on a shared library's node path""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) + + soname = _call_env_subst(env, '$SONAME', **kw2) + if not soname: + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibSonameGenerator: version=%r" % version) + if version: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if not soname: + # fallback to library name (as returned by appropriate _LibNameGenerator) + soname = _LibNameGenerator(self.libtype)(env, libnode) + if Verbose: + print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) + + if Verbose: + print("_LibSonameGenerator: return soname=%r" % soname) + + return soname + + +ShLibSonameGenerator = _LibSonameGenerator('ShLib') +LdModSonameGenerator = _LibSonameGenerator('LdMod') + + +def StringizeLibSymlinks(symlinks): + """Converts list with pairs of nodes to list with pairs of node paths + (strings). Used mainly for debugging.""" + if is_List(symlinks): + try: + return [(k.get_path(), v.get_path()) for k, v in symlinks] + except (TypeError, ValueError): + return symlinks + else: + return symlinks + + +def EmitLibSymlinks(env, symlinks, libnode, **kw): + """Used by emitters to handle (shared/versioned) library symlinks""" + Verbose = False + + # nodes involved in process... all symlinks + library + nodes = list(set([x for x, y in symlinks] + [libnode])) + + clean_targets = kw.get('clean_targets', []) + if not is_List(clean_targets): + clean_targets = [clean_targets] + + for link, linktgt in symlinks: + env.SideEffect(link, linktgt) + if Verbose: + print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path())) + clean_list = [x for x in nodes if x != linktgt] + env.Clean(list(set([linktgt] + clean_targets)), clean_list) + if Verbose: + print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list])) + + +def CreateLibSymlinks(env, symlinks): + """Physically creates symlinks. The symlinks argument must be a list in + form [ (link, linktarget), ... ], where link and linktarget are SCons + nodes. + """ + + Verbose = False + for link, linktgt in symlinks: + linktgt = link.get_dir().rel_path(linktgt) + link = link.get_path() + if Verbose: + print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt)) + # Delete the (previously created) symlink if exists. Let only symlinks + # to be deleted to prevent accidental deletion of source files... + if env.fs.islink(link): + env.fs.unlink(link) + if Verbose: + print("CreateLibSymlinks: removed old symlink %r" % link) + # If a file or directory exists with the same name as link, an OSError + # will be thrown, which should be enough, I think. + env.fs.symlink(linktgt, link) + if Verbose: + print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt)) + return 0 + + +def LibSymlinksActionFunction(target, source, env): + for tgt in target: + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) + if symlinks: + CreateLibSymlinks(env, symlinks) + return 0 + + +def LibSymlinksStrFun(target, source, env, *args): + cmd = None + for tgt in target: + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) + if symlinks: + if cmd is None: cmd = "" + if cmd: cmd += "\n" + cmd += "Create symlinks for: %r" % tgt.get_path() + try: + linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]) + except (KeyError, ValueError): + pass + else: + cmd += ": %s" % linkstr + return cmd + + +def _call_env_subst(env, string, *args, **kw): + kw2 = {} + for k in ('raw', 'target', 'source', 'conv', 'executor'): + try: + kw2[k] = kw[k] + except KeyError: + pass + return env.subst(string, *args, **kw2)
\ No newline at end of file diff --git a/SCons/Tool/linkloc.py b/SCons/Tool/linkloc.py index 0ca37b3..6ee5d61 100644 --- a/SCons/Tool/linkloc.py +++ b/SCons/Tool/linkloc.py @@ -34,7 +34,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import re import SCons.Action diff --git a/SCons/Tool/msginit.py b/SCons/Tool/msginit.py index a94cb85..4b72c30 100644 --- a/SCons/Tool/msginit.py +++ b/SCons/Tool/msginit.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Warnings import SCons.Builder -import re ############################################################################# def _optional_no_translator_flag(env): diff --git a/SCons/Tool/msvc.py b/SCons/Tool/msvc.py index b9eb60a..a06a434 100644 --- a/SCons/Tool/msvc.py +++ b/SCons/Tool/msvc.py @@ -35,8 +35,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path import os -import re -import sys import SCons.Action import SCons.Builder diff --git a/SCons/Tool/packaging/rpm.py b/SCons/Tool/packaging/rpm.py index a026e45..cdeabcf 100644 --- a/SCons/Tool/packaging/rpm.py +++ b/SCons/Tool/packaging/rpm.py @@ -27,7 +27,6 @@ The rpm packager. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import SCons.Builder import SCons.Tool.rpmutils diff --git a/SCons/Tool/qt.py b/SCons/Tool/qt.py index fab1625..d8a51b2 100644 --- a/SCons/Tool/qt.py +++ b/SCons/Tool/qt.py @@ -35,7 +35,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path import re -import glob import SCons.Action import SCons.Builder diff --git a/SCons/Tool/textfile.py b/SCons/Tool/textfile.py index bb8a0f9..c1b597f 100644 --- a/SCons/Tool/textfile.py +++ b/SCons/Tool/textfile.py @@ -48,8 +48,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons -import os -import re from SCons.Node import Node from SCons.Node.Python import Value @@ -76,8 +74,8 @@ def _do_subst(node, subs): if 'b' in TEXTFILE_FILE_WRITE_MODE: try: contents = bytearray(contents, 'utf-8') - except UnicodeDecodeError: - # contents is already utf-8 encoded python 2 str i.e. a byte array + except TypeError: + # TODO: this should not happen, get_text_contents returns text contents = bytearray(contents) return contents diff --git a/SCons/Tool/wixTests.py b/SCons/Tool/wixTests.py index 6039115..5b255d9 100644 --- a/SCons/Tool/wixTests.py +++ b/SCons/Tool/wixTests.py @@ -26,7 +26,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest import os.path import os -import sys import SCons.Errors from SCons.Tool.wix import * diff --git a/SCons/Tool/yacc.py b/SCons/Tool/yacc.py index 0b62305..ab019b2 100644 --- a/SCons/Tool/yacc.py +++ b/SCons/Tool/yacc.py @@ -50,14 +50,14 @@ if sys.platform == 'win32': else: BINS = ["bison", "yacc"] + def _yaccEmitter(target, source, env, ysuf, hsuf): yaccflags = env.subst("$YACCFLAGS", target=target, source=source) flags = SCons.Util.CLVar(yaccflags) targetBase, targetExt = os.path.splitext(SCons.Util.to_String(target[0])) - if '.ym' in ysuf: # If using Objective-C - target = [targetBase + ".m"] # the extension is ".m". - + if '.ym' in ysuf: # If using Objective-C + target = [targetBase + ".m"] # the extension is ".m". # If -d is specified on the command line, yacc will emit a .h # or .hpp file with the same name as the .c or .cpp output file. @@ -75,10 +75,8 @@ def _yaccEmitter(target, source, env, ysuf, hsuf): # be noted and also be cleaned # Bug #2558 if "-v" in flags: - env.SideEffect(targetBase+'.output',target[0]) - env.Clean(target[0],targetBase+'.output') - - + env.SideEffect(targetBase + '.output', target[0]) + env.Clean(target[0], targetBase + '.output') # With --defines and --graph, the name of the file is totally defined # in the options. @@ -94,15 +92,19 @@ def _yaccEmitter(target, source, env, ysuf, hsuf): return (target, source) + def yEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.y', '.yacc'], '$YACCHFILESUFFIX') + def ymEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.ym'], '$YACCHFILESUFFIX') + def yyEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX') + def get_yacc_path(env, append_paths=False): """ Find the path to the yacc tool, searching several possible names @@ -118,7 +120,7 @@ def get_yacc_path(env, append_paths=False): bin_path = SCons.Tool.find_program_path( env, prog, - default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS) if bin_path: if append_paths: env.AppendENVPath('PATH', os.path.dirname(bin_path)) @@ -149,14 +151,20 @@ def generate(env): # ignore the return, all we need is for the path to be added _ = get_yacc_path(env, append_paths=True) - env["YACC"] = env.Detect(BINS) + if 'YACC' not in env: + env["YACC"] = env.Detect(BINS) + env['YACCFLAGS'] = SCons.Util.CLVar('') - env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' + env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' env['YACCVCGFILESUFFIX'] = '.vcg' + def exists(env): + if 'YACC' in env: + return env.Detect(env['YACC']) + if sys.platform == 'win32': return get_yacc_path(env) else: diff --git a/SCons/Tool/zip.py b/SCons/Tool/zip.py index 23d540f..cbf2c16 100644 --- a/SCons/Tool/zip.py +++ b/SCons/Tool/zip.py @@ -42,7 +42,9 @@ import SCons.Util import zipfile -zipcompression = zipfile.ZIP_DEFLATED +zip_compression = zipfile.ZIP_DEFLATED + + def zip(target, source, env): compression = env.get('ZIPCOMPRESSION', 0) zf = zipfile.ZipFile(str(target[0]), 'w', compression) @@ -52,19 +54,20 @@ def zip(target, source, env): for fname in filenames: path = os.path.join(dirpath, fname) if os.path.isfile(path): - zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', '')))) else: zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', '')))) zf.close() -zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION']) +# Fix PR #3569 - If you don't specify ZIPCOM and ZIPCOMSTR when creating +# env, then it will ignore ZIPCOMSTR set afterwards. +zipAction = SCons.Action.Action(zip, "$ZIPCOMSTR", varlist=['ZIPCOMPRESSION']) -ZipBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), - source_factory = SCons.Node.FS.Entry, - source_scanner = SCons.Defaults.DirScanner, - suffix = '$ZIPSUFFIX', - multi = 1) +ZipBuilder = SCons.Builder.Builder(action=SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), + source_factory=SCons.Node.FS.Entry, + source_scanner=SCons.Defaults.DirScanner, + suffix='$ZIPSUFFIX', + multi=1) def generate(env): @@ -75,12 +78,13 @@ def generate(env): bld = ZipBuilder env['BUILDERS']['Zip'] = bld - env['ZIP'] = 'zip' - env['ZIPFLAGS'] = SCons.Util.CLVar('') - env['ZIPCOM'] = zipAction - env['ZIPCOMPRESSION'] = zipcompression - env['ZIPSUFFIX'] = '.zip' - env['ZIPROOT'] = SCons.Util.CLVar('') + env['ZIP'] = 'zip' + env['ZIPFLAGS'] = SCons.Util.CLVar('') + env['ZIPCOM'] = zipAction + env['ZIPCOMPRESSION'] = zip_compression + env['ZIPSUFFIX'] = '.zip' + env['ZIPROOT'] = SCons.Util.CLVar('') + def exists(env): return True diff --git a/SCons/Util.py b/SCons/Util.py index 2b90ea1..053c5de 100644 --- a/SCons/Util.py +++ b/SCons/Util.py @@ -1,9 +1,6 @@ -"""SCons.Util - -Various utility functions go here. -""" +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -24,30 +21,25 @@ Various utility functions go here. # 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__" +"""Various SCons utility functions.""" import os import sys import copy import re -import types -import codecs import pprint import hashlib from collections import UserDict, UserList, UserString, OrderedDict from collections.abc import MappingView +from types import MethodType, FunctionType PYPY = hasattr(sys, 'pypy_translation_info') -# Below not used? -# InstanceType = types.InstanceType - -MethodType = types.MethodType -FunctionType = types.FunctionType - -def dictify(keys, values, result={}): - for k, v in zip(keys, values): - result[k] = v +# unused? +def dictify(keys, values, result=None): + if result is None: + result = {} + result.update(dict(zip(keys, values))) return result _altsep = os.altsep @@ -637,6 +629,41 @@ class Delegate: else: return self + +class MethodWrapper: + """A generic Wrapper class that associates a method with an object. + + As part of creating this MethodWrapper object an attribute with the + specified name (by default, the name of the supplied method) is added + to the underlying object. When that new "method" is called, our + __call__() method adds the object as the first argument, simulating + the Python behavior of supplying "self" on method calls. + + We hang on to the name by which the method was added to the underlying + base class so that we can provide a method to "clone" ourselves onto + a new underlying object being copied (without which we wouldn't need + to save that info). + """ + def __init__(self, object, method, name=None): + if name is None: + name = method.__name__ + self.object = object + self.method = method + self.name = name + setattr(self.object, name, self) + + def __call__(self, *args, **kwargs): + nargs = (self.object,) + args + return self.method(*nargs, **kwargs) + + def clone(self, new_object): + """ + Returns an object that re-binds the underlying "method" to + the specified new object. + """ + return self.__class__(new_object, self.method, self.name) + + # attempt to load the windows registry module: can_read_reg = 0 try: @@ -652,22 +679,9 @@ try: RegError = winreg.error except ImportError: - try: - import win32api - import win32con - can_read_reg = 1 - hkey_mod = win32con - - RegOpenKeyEx = win32api.RegOpenKeyEx - RegEnumKey = win32api.RegEnumKey - RegEnumValue = win32api.RegEnumValue - RegQueryValueEx = win32api.RegQueryValueEx - RegError = win32api.error - - except ImportError: - class _NoError(Exception): - pass - RegError = _NoError + class _NoError(Exception): + pass + RegError = _NoError # Make sure we have a definition of WindowsError so we can @@ -1113,7 +1127,7 @@ def adjustixes(fname, pre, suf, ensure_suffix=False): # From Tim Peters, -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# https://code.activestate.com/recipes/52560 # ASPN: Python Cookbook: Remove duplicates from a sequence # (Also in the printed Python Cookbook.) @@ -1187,9 +1201,8 @@ def unique(s): return u - # From Alex Martelli, -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# https://code.activestate.com/recipes/52560 # ASPN: Python Cookbook: Remove duplicates from a sequence # First comment, dated 2001/10/13. # (Also in the printed Python Cookbook.) @@ -1392,42 +1405,41 @@ def make_path_relative(path): return path - -# The original idea for AddMethod() and RenameFunction() come from the +# The original idea for AddMethod() came from the # following post to the ActiveState Python Cookbook: # -# ASPN: Python Cookbook : Install bound methods in an instance -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 -# -# That code was a little fragile, though, so the following changes -# have been wrung on it: +# ASPN: Python Cookbook : Install bound methods in an instance +# https://code.activestate.com/recipes/223613 # +# Changed as follows: # * Switched the installmethod() "object" and "function" arguments, # so the order reflects that the left-hand side is the thing being # "assigned to" and the right-hand side is the value being assigned. -# -# * Changed explicit type-checking to the "try: klass = object.__class__" -# block in installmethod() below so that it still works with the -# old-style classes that SCons uses. -# -# * Replaced the by-hand creation of methods and functions with use of -# the "new" module, as alluded to in Alex Martelli's response to the -# following Cookbook post: -# -# ASPN: Python Cookbook : Dynamically added methods to a class -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 +# * The instance/class detection is changed a bit, as it's all +# new-style classes now with Py3. +# * The by-hand construction of the function object from renamefunction() +# is not needed, the remaining bit is now used inline in AddMethod. def AddMethod(obj, function, name=None): - """ - Adds either a bound method to an instance or the function itself (or an unbound method in Python 2) to a class. - If name is ommited the name of the specified function - is used by default. + """Adds a method to an object. + + Adds `function` to `obj` if `obj` is a class object. + Adds `function` as a bound method if `obj` is an instance object. + If `obj` looks like an environment instance, use `MethodWrapper` + to add it. If `name` is supplied it is used as the name of `function`. + + Although this works for any class object, the intent as a public + API is to be used on Environment, to be able to add a method to all + construction environments; it is preferred to use env.AddMethod + to add to an individual environment. Example:: + class A: + ... a = A() def f(self, x, y): - self.z = x + y + self.z = x + y AddMethod(f, A, "add") a.add(2, 4) print(a.z) @@ -1437,32 +1449,24 @@ def AddMethod(obj, function, name=None): if name is None: name = function.__name__ else: - function = RenameFunction(function, name) + # "rename" + function = FunctionType( + function.__code__, function.__globals__, name, function.__defaults__ + ) - # Note the Python version checks - WLB - # Python 3.3 dropped the 3rd parameter from types.MethodType if hasattr(obj, '__class__') and obj.__class__ is not type: - # "obj" is an instance, so it gets a bound method. - if sys.version_info[:2] > (3, 2): - method = MethodType(function, obj) + # obj is an instance, so it gets a bound method. + if hasattr(obj, "added_methods"): + method = MethodWrapper(obj, function, name) + obj.added_methods.append(method) else: - method = MethodType(function, obj, obj.__class__) + method = MethodType(function, obj) else: - # Handle classes + # obj is a class method = function setattr(obj, name, method) -def RenameFunction(function, name): - """ - Returns a function identical to the specified function, but with - the specified name. - """ - return FunctionType(function.__code__, - function.__globals__, - name, - function.__defaults__) - # Default hash function. SCons-internal. _hash_function = None @@ -1617,8 +1621,7 @@ def silent_intern(x): # From Dinu C. Gherman, # Python Cookbook, second edition, recipe 6.17, p. 277. -# Also: -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 +# Also: https://code.activestate.com/recipes/68205 # ASPN: Python Cookbook: Null Object Design Pattern class Null: @@ -1659,9 +1662,6 @@ class NullSeq(Null): return self -del __revision__ - - def to_bytes(s): if s is None: return b'None' diff --git a/SCons/UtilTests.py b/SCons/UtilTests.py index 319724d..2be2672 100644 --- a/SCons/UtilTests.py +++ b/SCons/UtilTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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.compat @@ -196,11 +194,7 @@ class UtilTestCase(unittest.TestCase): try: node, expect, withtags = self.tree_case_1() - if sys.version_info.major < 3: - IOStream = io.BytesIO - else: - IOStream = io.StringIO - + IOStream = io.StringIO sys.stdout = IOStream() print_tree(node, get_children) actual = sys.stdout.getvalue() @@ -252,11 +246,6 @@ class UtilTestCase(unittest.TestCase): def test_is_Dict(self): assert is_Dict({}) assert is_Dict(UserDict()) - - # os.environ is not a dictionary in python 3 - if sys.version_info < (3, 0): - assert is_Dict(os.environ) - try: class mydict(dict): pass diff --git a/SCons/Utilities/ConfigureCache.py b/SCons/Utilities/ConfigureCache.py index 08faeae..67aac3c 100644 --- a/SCons/Utilities/ConfigureCache.py +++ b/SCons/Utilities/ConfigureCache.py @@ -2,7 +2,9 @@ # # SCons - a Software Constructor # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -166,4 +168,4 @@ def main(): json.dump(config, conf) if __name__ == "__main__": - main()
\ No newline at end of file + main() diff --git a/SCons/Utilities/sconsign.py b/SCons/Utilities/sconsign.py index 76a8233..3288779 100644 --- a/SCons/Utilities/sconsign.py +++ b/SCons/Utilities/sconsign.py @@ -2,7 +2,9 @@ # # SCons - a Software Constructor # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -23,6 +25,8 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +"""Utility script to dump information from SCons signature database.""" + import getopt import os import sys @@ -94,11 +98,6 @@ def default_mapper(entry, name): val = eval("entry." + name) except AttributeError: val = None - if sys.version_info.major >= 3 and isinstance(val, bytes): - # This is a dirty hack for py 2/3 compatibility. csig is a bytes object - # in Python3 while Python2 bytes are str. Hence, we decode the csig to a - # Python3 string - val = val.decode() return str(val) @@ -323,8 +322,8 @@ class Do_SConsignDB: sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" % (self.dbm_name, fname, e)) exc_type, _, _ = sys.exc_info() - if exc_type.__name__ == "ValueError" and sys.version_info < (3,0,0): - sys.stderr.write("Python 2 only supports pickle protocols 0-2.\n") + if exc_type.__name__ == "ValueError": + sys.stderr.write("unrecognized pickle protocol.\n") return if Print_Directories: diff --git a/SCons/Variables/BoolVariable.py b/SCons/Variables/BoolVariable.py index 9c66cde..6d9ff72 100644 --- a/SCons/Variables/BoolVariable.py +++ b/SCons/Variables/BoolVariable.py @@ -1,18 +1,6 @@ -"""SCons.Variables.BoolVariable - -This file defines the option type for SCons implementing true/false values. - -Usage example:: - - opts = Variables() - opts.Add(BoolVariable('embedded', 'build for an embedded system', 0)) - ... - if env['embedded'] == 1: - ... -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,9 +20,17 @@ Usage example:: # 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__" +"""Option type for true/false Variables. + +Usage example:: + + opts = Variables() + opts.Add(BoolVariable('embedded', 'build for an embedded system', 0)) + ... + if env['embedded'] == 1: + ... +""" __all__ = ['BoolVariable',] diff --git a/SCons/Variables/BoolVariableTests.py b/SCons/Variables/BoolVariableTests.py index 3184407..e486e4b 100644 --- a/SCons/Variables/BoolVariableTests.py +++ b/SCons/Variables/BoolVariableTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Errors diff --git a/SCons/Variables/EnumVariable.py b/SCons/Variables/EnumVariable.py index 8053503..6e0a8c5 100644 --- a/SCons/Variables/EnumVariable.py +++ b/SCons/Variables/EnumVariable.py @@ -1,21 +1,6 @@ -"""SCons.Variables.EnumVariable - -This file defines the option type for SCons allowing only specified -input-values. - -Usage example:: - - opts = Variables() - opts.Add(EnumVariable('debug', 'debug output and symbols', 'no', - allowed_values=('yes', 'no', 'full'), - map={}, ignorecase=2)) - ... - if env['debug'] == 'full': - ... -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -35,9 +20,30 @@ Usage example:: # 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__" +"""Option type for enumeration Variables. + +This file defines the option type for SCons allowing only specified +input-values. + +Usage example:: + + opts = Variables() + opts.Add( + EnumVariable( + 'debug', + 'debug output and symbols', + 'no', + allowed_values=('yes', 'no', 'full'), + map={}, + ignorecase=2, + ) + ) + ... + if env['debug'] == 'full': + ... +""" + __all__ = ['EnumVariable',] diff --git a/SCons/Variables/EnumVariableTests.py b/SCons/Variables/EnumVariableTests.py index 4ecb8bd..75bb54f 100644 --- a/SCons/Variables/EnumVariableTests.py +++ b/SCons/Variables/EnumVariableTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Errors diff --git a/SCons/Variables/ListVariable.py b/SCons/Variables/ListVariable.py index 7ebbb23..c615258 100644 --- a/SCons/Variables/ListVariable.py +++ b/SCons/Variables/ListVariable.py @@ -1,31 +1,6 @@ -"""SCons.Variables.ListVariable - -This file defines the option type for SCons implementing 'lists'. - -A 'list' option may either be 'all', 'none' or a list of names -separated by comma. After the option has been processed, the option -value holds either the named list elements, all list elements or no -list elements at all. - -Usage example:: - - list_of_libs = Split('x11 gl qt ical') - - opts = Variables() - opts.Add(ListVariable('shared', - 'libraries to build as shared libraries', - 'all', - elems = list_of_libs)) - ... - for lib in list_of_libs: - if lib in env['shared']: - env.SharedObject(...) - else: - env.Object(...) -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -46,7 +21,35 @@ Usage example:: # 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__" +"""Option type for list Variables. + +This file defines the option type for SCons implementing 'lists'. + +A 'list' option may either be 'all', 'none' or a list of names +separated by comma. After the option has been processed, the option +value holds either the named list elements, all list elements or no +list elements at all. + +Usage example:: + + list_of_libs = Split('x11 gl qt ical') + + opts = Variables() + opts.Add( + ListVariable( + 'shared', + 'libraries to build as shared libraries', + 'all', + elems=list_of_libs, + ) + ) + ... + for lib in list_of_libs: + if lib in env['shared']: + env.SharedObject(...) + else: + env.Object(...) +""" # Known Bug: This should behave like a Set-Type, but does not really, # since elements can occur twice. diff --git a/SCons/Variables/ListVariableTests.py b/SCons/Variables/ListVariableTests.py index 8f79e07..c73cef3 100644 --- a/SCons/Variables/ListVariableTests.py +++ b/SCons/Variables/ListVariableTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import copy -import sys import unittest import SCons.Errors diff --git a/SCons/Variables/PackageVariable.py b/SCons/Variables/PackageVariable.py index 6847f3d..d4dafd5 100644 --- a/SCons/Variables/PackageVariable.py +++ b/SCons/Variables/PackageVariable.py @@ -1,7 +1,29 @@ -"""SCons.Variables.PackageVariable +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Option type for package Variables. -This file defines the option type for SCons implementing 'package -activation'. +This file defines the option type for SCons implementing 'package activation'. To be used whenever a 'package' may be enabled/disabled and the package path may be specified. @@ -15,6 +37,7 @@ Usage example: To replace autoconf's --with-xxx=yyy :: + opts = Variables() opts.Add(PackageVariable('x11', 'use X11 installed here (yes = search some places', @@ -27,31 +50,6 @@ Usage example: ... build with x11 ... """ -# -# __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__" - __all__ = ['PackageVariable',] import SCons.Errors diff --git a/SCons/Variables/PackageVariableTests.py b/SCons/Variables/PackageVariableTests.py index a7e6b0d..988fbe0 100644 --- a/SCons/Variables/PackageVariableTests.py +++ b/SCons/Variables/PackageVariableTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Errors diff --git a/SCons/Variables/PathVariable.py b/SCons/Variables/PathVariable.py index c0ebb18..081872b 100644 --- a/SCons/Variables/PathVariable.py +++ b/SCons/Variables/PathVariable.py @@ -1,4 +1,27 @@ -"""SCons.Variables.PathVariable +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Option type for path Variables. This file defines an option type for SCons implementing path settings. @@ -8,21 +31,18 @@ Arguments to PathVariable are: option-name = name of this option on the command line (e.g. "prefix") option-help = help string for option option-dflt = default value for this option - validator = [optional] validator for option value. Predefined validators are: - - PathAccept -- accepts any path setting; no validation - PathIsDir -- path must be an existing directory - PathIsDirCreate -- path must be a dir; will create - PathIsFile -- path must be a file - PathExists -- path must exist (any type) [default] - - The validator is a function that is called and which - should return True or False to indicate if the path - is valid. The arguments to the validator function - are: (key, val, env). The key is the name of the - option, the val is the path specified for the option, - and the env is the env to which the Options have been - added. + validator = [optional] validator for option value. Predefined are: + PathAccept -- accepts any path setting; no validation + PathIsDir -- path must be an existing directory + PathIsDirCreate -- path must be a dir; will create + PathIsFile -- path must be a file + PathExists -- path must exist (any type) [default] + + The validator is a function that is called and which should return + True or False to indicate if the path is valid. The arguments + to the validator function are: (key, val, env). The key is the + name of the option, the val is the path specified for the option, + and the env is the env to which the Options have been added. Usage example:: @@ -41,34 +61,8 @@ Usage example:: opts.Add(PathVariable('qt_libraries', 'where the Qt library is installed', '$qtdir/lib')) - """ -# -# __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__" - __all__ = ['PathVariable',] import os diff --git a/SCons/Variables/PathVariableTests.py b/SCons/Variables/PathVariableTests.py index 48ad0e0..6e3a70b 100644 --- a/SCons/Variables/PathVariableTests.py +++ b/SCons/Variables/PathVariableTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,12 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path -import sys import unittest import SCons.Errors diff --git a/SCons/Variables/VariablesTests.py b/SCons/Variables/VariablesTests.py index 93866e0..768f88e 100644 --- a/SCons/Variables/VariablesTests.py +++ b/SCons/Variables/VariablesTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import TestSCons diff --git a/SCons/Variables/__init__.py b/SCons/Variables/__init__.py index f7531b4..2c32310 100644 --- a/SCons/Variables/__init__.py +++ b/SCons/Variables/__init__.py @@ -1,11 +1,6 @@ -"""SCons.Variables - -This file defines the Variables class that is used to add user-friendly -customizable variables to an SCons build. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +21,7 @@ customizable variables to an SCons build. # 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__" +"""Add user-friendly customizable variables to an SCons build. """ import os.path import sys diff --git a/SCons/Warnings.py b/SCons/Warnings.py index b5ce52e..198c6ae 100644 --- a/SCons/Warnings.py +++ b/SCons/Warnings.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,15 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -"""SCons.Warnings - -This file implements the warnings framework for SCons. - -""" -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The SCons warnings framework.""" import sys diff --git a/SCons/WarningsTests.py b/SCons/WarningsTests.py index e4720eb..c22b049 100644 --- a/SCons/WarningsTests.py +++ b/SCons/WarningsTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # 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 import unittest import SCons.Warnings diff --git a/SCons/__init__.py b/SCons/__init__.py index f3d3851..fcd665e 100644 --- a/SCons/__init__.py +++ b/SCons/__init__.py @@ -1,9 +1,9 @@ -__version__="4.0.1" +__version__="4.0.1.9998" __copyright__="Copyright (c) 2001 - 2020 The SCons Foundation" __developer__="bdbaddog" -__date__="2020-07-17 01:50:03" +__date__="2020-10-09 19:00:35" __buildsys__="ProDog2020" -__revision__="c289977f8b34786ab6c334311e232886da7e8df1" -__build__="c289977f8b34786ab6c334311e232886da7e8df1" +__revision__="93525bed88d19a00f5de400086c0046011d3b833" +__build__="93525bed88d19a00f5de400086c0046011d3b833" # make sure compatibility is always in place import SCons.compat # noqa
\ No newline at end of file diff --git a/SCons/__main__.py b/SCons/__main__.py index 0dfbb9d..67120c8 100644 --- a/SCons/__main__.py +++ b/SCons/__main__.py @@ -1,3 +1,26 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import SCons.Script # this does all the work, and calls sys.exit # with the proper exit status when done. diff --git a/SCons/compat/__init__.py b/SCons/compat/__init__.py index 9fb4898..91d10d1 100644 --- a/SCons/compat/__init__.py +++ b/SCons/compat/__init__.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,21 +20,21 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__doc__ = """ -SCons compatibility package for old Python versions +"""SCons compatibility package for old Python versions This subpackage holds modules that provide backwards-compatible -implementations of various things that we'd like to use in SCons but which -only show up in later versions of Python than the early, old version(s) -we still support. +implementations of various things from newer Python versions +that we cannot count on because SCons still supported older Pythons. Other code will not generally reference things in this package through the SCons.compat namespace. The modules included here add things to the builtins namespace or the global module list so that the rest of our code can use the objects and names imported here regardless of -Python version. +Python version. As a result, if this module is used, it should violate +the normal convention for imports (standard library imports first, +then program-specific imports, each ordered aplhabetically) +and needs to be listed first. The rest of the things here will be in individual compatibility modules that are either: 1) suitably modified copies of the future modules that @@ -57,9 +58,6 @@ function defined below loads the module as the "real" name (without the rest of our code will find our pre-loaded compatibility module. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os import sys import importlib @@ -81,7 +79,6 @@ def rename_module(new, old): # Default pickle protocol. Higher protocols are more efficient/featured # but incompatible with older Python versions. # Negative numbers choose the highest available protocol. -import pickle # Was pickle.HIGHEST_PROTOCOL # Changed to 4 so that python 3.8's not incompatible with previous versions diff --git a/SCons/compat/_scons_dbm.py b/SCons/compat/_scons_dbm.py index edfe6fd..72e5d6a 100644 --- a/SCons/compat/_scons_dbm.py +++ b/SCons/compat/_scons_dbm.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,10 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__doc__ = """ -dbm compatibility module for Python versions that don't have dbm. +"""dbm compatibility module for Python versions that don't have dbm. This does not not NOT (repeat, *NOT*) provide complete dbm functionality. It's just a stub on which to hang just enough pieces of dbm functionality @@ -30,8 +29,6 @@ that the whichdb.whichdb() implementstation in the various 2.X versions of Python won't blow up even if dbm wasn't compiled in. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - class error(Exception): pass diff --git a/SCons/compat/win32.py b/SCons/compat/win32.py new file mode 100644 index 0000000..e01adfa --- /dev/null +++ b/SCons/compat/win32.py @@ -0,0 +1,101 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +"""Logic to replicate parts of pywin32 SCons uses.""" + +__all__ = ['get_current_process', 'get_memory_info', 'get_memory_usage', 'get_peak_memory_usage'] + +import ctypes +from ctypes import wintypes + +# +# From Activestate Recipe +# https://code.activestate.com/recipes/578513-get-memory-usage-of-windows-processes-using-getpro/ +# MIT licensed +# +GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess +GetCurrentProcess.argtypes = [] +GetCurrentProcess.restype = wintypes.HANDLE + +SIZE_T = ctypes.c_size_t + + +class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure): + _fields_ = [ + ('cb', wintypes.DWORD), + ('PageFaultCount', wintypes.DWORD), + ('PeakWorkingSetSize', SIZE_T), + ('WorkingSetSize', SIZE_T), + ('QuotaPeakPagedPoolUsage', SIZE_T), + ('QuotaPagedPoolUsage', SIZE_T), + ('QuotaPeakNonPagedPoolUsage', SIZE_T), + ('QuotaNonPagedPoolUsage', SIZE_T), + ('PagefileUsage', SIZE_T), + ('PeakPagefileUsage', SIZE_T), + ('PrivateUsage', SIZE_T), + ] + + +GetProcessMemoryInfo = ctypes.windll.psapi.GetProcessMemoryInfo +GetProcessMemoryInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(PROCESS_MEMORY_COUNTERS_EX), + wintypes.DWORD, +] +GetProcessMemoryInfo.restype = wintypes.BOOL + + +def get_current_process(): + """Return handle to current process.""" + return GetCurrentProcess() + + +def get_memory_info(process=None): + """Return Win32 process memory counters structure as a dict.""" + if process is None: + process = get_current_process() + counters = PROCESS_MEMORY_COUNTERS_EX() + ret = GetProcessMemoryInfo(process, ctypes.byref(counters), + ctypes.sizeof(counters)) + if not ret: + raise ctypes.WinError() + info = dict((name, getattr(counters, name)) + for name, _ in counters._fields_) + return info + + +def get_memory_usage(process=None): + """Return this process's memory usage in bytes.""" + info = get_memory_info(process=process) + return info['PrivateUsage'] + + +def get_peak_memory_usage(process=None): + """Return this process's memory usage in bytes.""" + info = get_memory_info(process=process) + return info['PeakWorkingSetSize'] + + +if __name__ == '__main__': + import pprint + + pprint.pprint(get_memory_info()) diff --git a/SCons/cpp.py b/SCons/cpp.py index 0811c71..65358b3 100644 --- a/SCons/cpp.py +++ b/SCons/cpp.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,13 +20,9 @@ # 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__" +"""SCons C Pre-Processor module""" -__doc__ = """ -SCons C Pre-Processor module -""" import SCons.compat import os @@ -651,8 +648,6 @@ class DumbPreProcessor(PreProcessor): for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']: d[func] = d[func] = self.do_nothing -del __revision__ - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/SCons/cppTests.py b/SCons/cppTests.py index 22a5c81..c19046c 100644 --- a/SCons/cppTests.py +++ b/SCons/cppTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,8 +20,6 @@ # 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 atexit import unittest @@ -30,7 +29,6 @@ import TestUnit import cpp - basic_input = """ #include "file1-yes" #include <file2-yes> diff --git a/SCons/dblite.py b/SCons/dblite.py index 338dcc7..c6943e3 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -1,3 +1,26 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ dblite.py module contributed by Ralf W. Grosse-Kunstleve. Extended for Unicode by Steven Knight. diff --git a/SCons/exitfuncs.py b/SCons/exitfuncs.py index 7d00df7..ba6243a 100644 --- a/SCons/exitfuncs.py +++ b/SCons/exitfuncs.py @@ -1,11 +1,6 @@ -"""SCons.exitfuncs - -Register functions which are executed when SCons exits for any reason. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,10 +20,10 @@ Register functions which are executed when SCons exits for any reason. # 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__" +"""Register functions which are executed when SCons exits for any reason.""" +# This is obsolete now import atexit @@ -12,7 +12,9 @@ copyright_years = strftime('2001 - %Y') # This gets inserted into the man pages to reflect the month of release. month_year = strftime('%B %Y') # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -36,7 +38,7 @@ month_year = strftime('%B %Y') project = 'scons' -default_version = '4.0.1' +default_version = '4.0.1.9998' copyright = "Copyright (c) %s The SCons Foundation" % copyright_years # @@ -193,14 +195,21 @@ Export('command_line', 'env', 'whereis', 'revaction') SConscript('doc/SConscript') +# Copy manpage's into base dir for inclusign in pypi packages +man_pages = env.Install("#/", Glob("#/build/doc/man/*.1")) + # Build packages for pypi -env.Command('$DISTDIR/SCons-${VERSION}-py3-none-any.whl', ['setup.cfg', 'setup.py', 'SCons/__init__.py'], +wheel = env.Command('$DISTDIR/SCons-${VERSION}-py3-none-any.whl', ['setup.cfg', 'setup.py', 'SCons/__init__.py']+man_pages, '$PYTHON setup.py bdist_wheel') -env.Command('$DISTDIR/SCons-${VERSION}.zip', ['setup.cfg', 'setup.py', 'SCons/__init__.py'], +zip_file = env.Command('$DISTDIR/SCons-${VERSION}.zip', ['setup.cfg', 'setup.py', 'SCons/__init__.py']+man_pages, '$PYTHON setup.py sdist --format=zip') -env.Command('$DISTDIR/SCons-${VERSION}.tar.gz', ['setup.cfg', 'setup.py', 'SCons/__init__.py'], +tgz_file = env.Command('$DISTDIR/SCons-${VERSION}.tar.gz', ['setup.cfg', 'setup.py', 'SCons/__init__.py']+man_pages, '$PYTHON setup.py sdist --format=gztar') +# Now set depends so the above run in a particular order +env.Depends(tgz_file, [zip_file, wheel]) +env.AddPostAction(tgz_file, Delete(man_pages)) + # TODO add auto copyright date to README.rst, LICENSE # TODO build API DOCS diff --git a/bin/SConsDoc.py b/bin/SConsDoc.py index ba9c923..baffbdc 100644 --- a/bin/SConsDoc.py +++ b/bin/SConsDoc.py @@ -41,9 +41,11 @@ Builder example: <para>This is the summary description of an SCons Builder. It will get placed in the man page, and in the appropriate User's Guide appendix. - The name of any builder may be interpolated + The name of this builder may be interpolated anywhere in the document by specifying the - &b-BUILDER; element. It need not be on a line by itself.</para> + &b-BUILDER; element. A link to this definition may be + interpolated by specifying the &b-link-BUILDER; element. + </para> Unlike normal XML, blank lines are significant in these descriptions and serve to separate paragraphs. @@ -59,16 +61,28 @@ Builder example: Function example: <scons_function name="FUNCTION"> - <arguments> + <arguments signature="SIGTYPE"> (arg1, arg2, key=value) </arguments> <summary> <para>This is the summary description of an SCons function. It will get placed in the man page, and in the appropriate User's Guide appendix. - The name of any builder may be interpolated + If the "signature" attribute is specified, SIGTYPE may be one + of "global", "env" or "both" (the default if omitted is "both"), + to indicate the signature applies to the global form or the + environment form, or to generate both with the same signature + (excepting the insertion of "env."). + This allows for the cases of + describing that only one signature should be generated, + or both signatures should be generated and they differ, + or both signatures should be generated and they are the same. + The name of this function may be interpolated anywhere in the document by specifying the - &f-FUNCTION; element. It need not be on a line by itself.</para> + &f-FUNCTION; element or the &f-env-FUNCTION; element. + Links to this definition may be interpolated by specifying + the &f-link-FUNCTION: or &f-link-env-FUNCTION; element. + </para> <example> print("this is example code, it will be offset and indented") @@ -83,9 +97,11 @@ Construction variable example: <para>This is the summary description of a construction variable. It will get placed in the man page, and in the appropriate User's Guide appendix. - The name of any construction variable may be interpolated + The name of this construction variable may be interpolated anywhere in the document by specifying the - &t-VARIABLE; element. It need not be on a line by itself.</para> + &cv-VARIABLE; element. A link to this definition may be + interpolated by specifying the &cv-link-VARIABLE; element. + </para> <example> print("this is example code, it will be offset and indented") @@ -100,9 +116,11 @@ Tool example: <para>This is the summary description of an SCons Tool. It will get placed in the man page, and in the appropriate User's Guide appendix. - The name of any tool may be interpolated + The name of this tool may be interpolated anywhere in the document by specifying the - &t-TOOL; element. It need not be on a line by itself.</para> + &t-TOOL; element. A link to this definition may be + interpolated by specifying the &t-link-TOOL; element. + </para> <example> print("this is example code, it will be offset and indented") diff --git a/doc/generated/examples/builderscommands_ex5_1.xml b/doc/generated/examples/builderscommands_ex5_1.xml new file mode 100644 index 0000000..67659c1 --- /dev/null +++ b/doc/generated/examples/builderscommands_ex5_1.xml @@ -0,0 +1,3 @@ +<screen 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">% <userinput>scons -Q</userinput> +Building foo.out +</screen> diff --git a/doc/generated/examples/commandline_BoolVariable_5.xml b/doc/generated/examples/commandline_BoolVariable_5.xml index e232588..3cd75e9 100644 --- a/doc/generated/examples/commandline_BoolVariable_5.xml +++ b/doc/generated/examples/commandline_BoolVariable_5.xml @@ -2,5 +2,5 @@ scons: *** Error converting option: RELEASE Invalid value for boolean option: bad_value -File "/home/my/project/SConstruct", line 5, in <module> +File "/home/my/project/SConstruct", line 3, in <module> </screen> diff --git a/doc/generated/examples/commandline_EnumVariable_2.xml b/doc/generated/examples/commandline_EnumVariable_2.xml index 51a5462..8856d29 100644 --- a/doc/generated/examples/commandline_EnumVariable_2.xml +++ b/doc/generated/examples/commandline_EnumVariable_2.xml @@ -1,5 +1,5 @@ <screen 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">% <userinput>scons -Q COLOR=magenta foo.o</userinput> scons: *** Invalid value for option COLOR: magenta. Valid values are: ('red', 'green', 'blue') -File "/home/my/project/SConstruct", line 6, in <module> +File "/home/my/project/SConstruct", line 10, in <module> </screen> diff --git a/doc/generated/examples/commandline_EnumVariable_4.xml b/doc/generated/examples/commandline_EnumVariable_4.xml index d1aca84..3e73c5b 100644 --- a/doc/generated/examples/commandline_EnumVariable_4.xml +++ b/doc/generated/examples/commandline_EnumVariable_4.xml @@ -1,13 +1,13 @@ <screen 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">% <userinput>scons -Q COLOR=Red foo.o</userinput> scons: *** Invalid value for option COLOR: Red. Valid values are: ('red', 'green', 'blue') -File "/home/my/project/SConstruct", line 6, in <module> +File "/home/my/project/SConstruct", line 10, in <module> % <userinput>scons -Q COLOR=BLUE foo.o</userinput> scons: *** Invalid value for option COLOR: BLUE. Valid values are: ('red', 'green', 'blue') -File "/home/my/project/SConstruct", line 6, in <module> +File "/home/my/project/SConstruct", line 10, in <module> % <userinput>scons -Q COLOR=nAvY foo.o</userinput> scons: *** Invalid value for option COLOR: nAvY. Valid values are: ('red', 'green', 'blue') -File "/home/my/project/SConstruct", line 6, in <module> +File "/home/my/project/SConstruct", line 10, in <module> </screen> diff --git a/doc/generated/examples/commandline_ListVariable_3.xml b/doc/generated/examples/commandline_ListVariable_3.xml index 7a8c857..11936ab 100644 --- a/doc/generated/examples/commandline_ListVariable_3.xml +++ b/doc/generated/examples/commandline_ListVariable_3.xml @@ -2,5 +2,5 @@ scons: *** Error converting option: COLORS Invalid value(s) for option: magenta -File "/home/my/project/SConstruct", line 6, in <module> +File "/home/my/project/SConstruct", line 7, in <module> </screen> diff --git a/doc/generated/examples/commandline_ListVariable_4.xml b/doc/generated/examples/commandline_ListVariable_4.xml new file mode 100644 index 0000000..d464c48 --- /dev/null +++ b/doc/generated/examples/commandline_ListVariable_4.xml @@ -0,0 +1,6 @@ +<screen 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">% <userinput>scons -Q foo.o</userinput> + +scons: *** Error converting option: COLORS +Invalid value(s) for option: 0 +File "/home/my/project/SConstruct", line 7, in <module> +</screen> diff --git a/doc/generated/examples/commandline_PathVariable_2.xml b/doc/generated/examples/commandline_PathVariable_2.xml index d2ce952..156702a 100644 --- a/doc/generated/examples/commandline_PathVariable_2.xml +++ b/doc/generated/examples/commandline_PathVariable_2.xml @@ -1,5 +1,5 @@ <screen 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">% <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput> scons: *** Path for option CONFIG does not exist: /does/not/exist -File "/home/my/project/SConstruct", line 5, in <module> +File "/home/my/project/SConstruct", line 7, in <module> </screen> diff --git a/doc/generated/examples/commandline_UnknownVariables_1.xml b/doc/generated/examples/commandline_UnknownVariables_1.xml index 08c566c..6725c47 100644 --- a/doc/generated/examples/commandline_UnknownVariables_1.xml +++ b/doc/generated/examples/commandline_UnknownVariables_1.xml @@ -1,3 +1,3 @@ <screen 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">% <userinput>scons -Q NOT_KNOWN=foo</userinput> -Unknown variables: dict_keys(['NOT_KNOWN']) +Unknown variables: NOT_KNOWN </screen> diff --git a/doc/generated/examples/separate_ex1_1.xml b/doc/generated/examples/separate_ex1_1.xml index 6efc16f..803bc4f 100644 --- a/doc/generated/examples/separate_ex1_1.xml +++ b/doc/generated/examples/separate_ex1_1.xml @@ -3,6 +3,8 @@ SConscript hello.c % <userinput>scons -Q</userinput> cc -o build/hello.o -c build/hello.c cc -o build/hello build/hello.o +% <userinput>ls src</userinput> +SConscript hello.c % <userinput>ls build</userinput> SConscript hello hello.c hello.o </screen> diff --git a/doc/generated/examples/sideeffect_simple2_1.xml b/doc/generated/examples/sideeffect_simple2_1.xml new file mode 100644 index 0000000..f60625b --- /dev/null +++ b/doc/generated/examples/sideeffect_simple2_1.xml @@ -0,0 +1,4 @@ +<screen 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">% <userinput>scons -Q</userinput> +echo > file1 data1; echo >log updated file1 +Copy("file2", "log") +</screen> diff --git a/doc/generated/examples/sideeffect_simple_1.xml b/doc/generated/examples/sideeffect_simple_1.xml index cc94830..f60625b 100644 --- a/doc/generated/examples/sideeffect_simple_1.xml +++ b/doc/generated/examples/sideeffect_simple_1.xml @@ -1,4 +1,4 @@ -<screen 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">% <userinput>scons -Q --jobs=2</userinput> +<screen 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">% <userinput>scons -Q</userinput> echo > file1 data1; echo >log updated file1 Copy("file2", "log") </screen> diff --git a/doc/man/scons.xml b/doc/man/scons.xml index 207433e..e43e73a 100644 --- a/doc/man/scons.xml +++ b/doc/man/scons.xml @@ -109,16 +109,17 @@ commands to build them.</para> which specifies the files to be built (<firstterm>targets</firstterm>), and, if necessary, the rules to build those files. Premade rules exist for building many common software components -such as executable programs, object files, libraries, +such as executable programs, object files and libraries, so that for many software projects, -only the target and input files need be specified.</para> +only the target and input files (<firstterm>sources</firstterm>) +need be specified.</para> <para> When invoked, &scons; searches for a file named &SConstruct; (it also checks alternate spellings -&Sconstruct;, &sconstruct;, &SConstruct.py; &Sconstruct.py; +&Sconstruct;, &sconstruct;, &SConstruct.py;, &Sconstruct.py; and &sconstruct.py; in that order) in the current directory and reads its configuration from that file. @@ -147,7 +148,10 @@ regardless of the actual file names or number of such files.</para> looks for a directory named <filename>site_scons</filename> in various system directories and in the directory containing the -&SConstruct; file and prepends the ones it +&SConstruct; file +or, if specified, the +directory from the <option>--site-dir</option> option instead, +and prepends the ones it finds to the Python module search path (<varname>sys.path</varname>), thus allowing modules in such directories to be imported in the normal Python way in SConscript files. @@ -214,12 +218,10 @@ that you want to use to build your target files are not in standard system locations, &scons; will not find them unless -you explicitly include the locations into the value of -<varname>PATH</varname> in the <varname>ENV</varname> -variable in the internal &consenv;. -Whenever you create a &consenv;, -you can propagate the value of <envar>PATH</envar> -from your external environment as follows:</para> +you explicitly include the locations into the +execution environment by setting the path in the +<varname>ENV</varname> &consvar; in the +internal &consenv;:</para> <programlisting language="python"> import os @@ -229,13 +231,18 @@ env = Environment(ENV={'PATH': os.environ['PATH']}) <para>Similarly, if the commands use specific external environment variables that &scons; does not recognize, they can be propagated into -the internal environment:</para> +the execution environment:</para> <programlisting language="python"> import os -env = Environment(ENV={'PATH': os.environ['PATH'], - 'ANDROID_HOME': os.environ['ANDROID_HOME'], - 'ANDROID_NDK_HOME': os.environ['ANDROID_NDK_HOME']}) + +env = Environment( + ENV={ + 'PATH': os.environ['PATH'], + 'ANDROID_HOME': os.environ['ANDROID_HOME'], + 'ANDROID_NDK_HOME': os.environ['ANDROID_NDK_HOME'], + } +) </programlisting> <para>Or you may explicitly propagate the invoking user's @@ -269,12 +276,14 @@ ability to define new scanners for unknown input file types.</para> is normally executed in a top-level directory containing an &SConstruct; file. When &scons; is invoked, -the command line (including the contents -of the &SCONSFLAGS; environment variable, -if set) is processed. +the command line (including the contents of the +<link linkend="v-SCONSFLAGS">&SCONSFLAGS;</link> +environment variable, if set) is processed. Command-line options (see <xref linkend="options"/>) are consumed. -Any variable argument assignments are collected, and -remaining arguments are taken as the targets to build.</para> +Any variable argument assignments +(see <xref linkend="commandline_construction_variables"/>) +are collected, and +remaining arguments are taken as targets to build.</para> <para>Values of variables to be passed to the SConscript files may be specified on the command line:</para> @@ -283,8 +292,8 @@ may be specified on the command line:</para> <userinput>scons debug=1</userinput> </screen> -<para>These variables are available -through the &ARGUMENTS; dictionary, +<para>These variables are available through the +<link linkend="v-ARGUMENTS">&ARGUMENTS;</link> dictionary, and can be used in the SConscript files to modify the build in any way:</para> @@ -296,28 +305,62 @@ else: </programlisting> <para>The command-line variable arguments are also available -in the &ARGLIST; list, +in the <link linkend="v-ARGLIST">&ARGLIST;</link> list, indexed by their order on the command line. This allows you to process them in order rather than by name, if necessary. Each &ARGLIST; entry is a tuple containing (<replaceable>argname</replaceable>, <replaceable>argvalue</replaceable>). </para> -<para>Targets on the command line may be files, directories, -or phony targets defined using the &Alias; function. -The command line targets are made available in the -&COMMAND_LINE_TARGETS; list. +<para>&SCons; acts on the <firstterm>selected targets</firstterm>, +whether the requested operation is build, no-exec or clean. +Targets are selected as follows: </para> - +<orderedlist> +<listitem> +<para> +Targets specified on the command line. +These may be files, directories, +or phony targets defined using the &f-link-Alias; function. +Directory targets are scanned by &scons; for any targets +that may be found with a destination in or under that directory. +The targets listed on the command line are made available in the +<link linkend="v-COMMAND_LINE_TARGETS">&COMMAND_LINE_TARGETS;</link> list. +</para> +</listitem> +<listitem> <para>If no targets are specified on the command line, -&scons; -will build the default targets. The default targets -are those specified in the SConscript files via calls -to the &Default; function; if none, the default targets are -those target files in or below the current directory. -Targets specified via the &Default; function are available -in the &DEFAULT_TARGETS; list. +&scons; will select those targets +specified in the SConscript files via calls +to the &f-link-Default; function. These are +known as the <firstterm>default targets</firstterm>, +and are made available in the +<link linkend="v-DEFAULT_TARGETS">&DEFAULT_TARGETS;</link> list. +</para> +</listitem> +<listitem> +<para> +If there are no targets from the previous steps, +&scons; selects the current directory for scanning, +unless command-line options which affect the target +scan are detected (<option>-C</option>, +<option>-d</option>, <option>-u</option>, <option>-U</option>). +Since targets thus selected were not the result of +user instructions, this target list is not made available +for direct inspection; use the <option>--debug=explain</option> +option if they need to be examined. </para> +</listitem> +<listitem> +<para> +&scons; always adds to the selected targets any intermediate +targets which are necessary to build the specified ones. +For example, if constructing a shared library or dll from C +source files, &scons; will also build the object files which +will make up the library. +</para> +</listitem> +</orderedlist> <para>To ignore the default targets specified through calls to &Default; and instead build all @@ -373,11 +416,12 @@ also the related <option>-D</option> and <option>-U</option> options):</para> requested, as &scons; needs to make sure any dependent files are built.</para> -<para>Specifying "cleanup" targets in SConscript files is not usually necessary. +<para>Specifying "cleanup" targets in SConscript files is +usually not necessary. The <option>-c</option> -flag removes all files -necessary to build the specified target:</para> +flag removes all selected targets: +</para> <screen> <userinput>scons -c .</userinput> @@ -394,11 +438,11 @@ and <filename>export</filename>.</para> <para> Additional files or directories to remove can be specified using the -&Clean; function in the SConscript files. +&f-link-Clean; function in the SConscript files. Conversely, targets that would normally be removed by the <option>-c</option> invocation can be retained by calling the -&NoClean; function with those targets.</para> +&f-link-NoClean; function with those targets.</para> <para>&scons; supports building multiple targets in parallel via a @@ -414,7 +458,7 @@ of simultaneous tasks that may be spawned:</para> <para>&scons; can maintain a cache of target (derived) files that can -be shared between multiple builds. When caching is enabled in a +be shared between multiple builds. When derived-file caching is enabled in an SConscript file, any target files built by &scons; will be copied @@ -471,9 +515,7 @@ by appropriate setting of &consvars;.</para> <para>&scons; requires Python 3.5 or higher. -There should be no other dependencies or requirements to run &scons;, -although the <package>pywin32</package> Python package is -strongly recommended if running on Windows systems. +There should be no other dependencies or requirements to run &scons;. </para> </refsect1> @@ -487,6 +529,12 @@ supports the same command-line options as GNU &Make; and many of those supported by <application>cons</application>. </para> +<!-- The recommended approach of multiple <term> entries per <varlistentry> --> +<!-- (if needed) is not used for Options, because the default docbook --> +<!-- presentation format for a varlist has been changed in SCons from --> +<!-- csv to one-per-line to improve the display of Builders and --> +<!-- Functions/Methods in those sections. Do the csv manually. --> + <!-- Note: commented-out options are retained as they may be a model --> <!-- for future development directions. Do not remove. --> @@ -505,11 +553,12 @@ and many of those supported by <application>cons</application>. <option>--remove</option> </term> <listitem> -<para>Clean up by removing all target files for which a construction -command is specified. -Also remove any files or directories associated to the construction command -using the &Clean; function. -Will not remove any targets specified by the &NoClean; function.</para> +<para>Clean up by removing the selected targets, +well as any files or directories associated +with a selected target through calls to the &f-link-Clean; function. +Will not remove any targets which are marked for +preservation through calls to the &f-link-NoClean; function. +</para> </listitem> </varlistentry> @@ -1454,6 +1503,7 @@ be appropriate for most uses.</para> <varlistentry> <term> <option>-n</option>, + <option>--no-exec</option>, <option>--just-print</option>, <option>--dry-run</option>, <option>--recon</option> @@ -2161,7 +2211,7 @@ but setting it after the &consenv; is constructed has no effect. <para>As a convenience, &consvars; may also be set or modified by the <parameter>parse_flags</parameter> -keyword argument during object creation, +keyword argument during object creation, which has the effect of the &f-link-env-MergeFlags; method being applied to the argument value @@ -2268,31 +2318,32 @@ See <xref linkend="commandline_construction_variables"/> for details. <title>Tools</title> <para> -&SCons; has a large number of predefined tools which -are used to help initialize the &consenv;, -and additional tools can be added. -An &scons; <firstterm>tool specification</firstterm> -is only responsible for setup. +&SCons; has a large number of predefined tools +(more properly, <firstterm>tool specifications</firstterm>) +which are used to help initialize the &consenv;. +An &scons; tool is only responsible for setup. For example, if the SConscript file declares the need to construct an object file from a C-language source file by calling the &b-link-Object; builder, then a tool representing an available C compiler needs to have run first, to set up the builder and all the &consvars; -it needs, in that &consenv;. Normally this +it needs in the associated &consenv;; the tool itself +is not called in the process of the build. Normally this happens invisibly: &scons; has per-platform lists of default tools, and it runs through those tools, -calling the ones which are actually applicable -(skipping those where necessary programs are not -installed on the build system, etc.). +calling the ones which are actually applicable, +skipping those where necessary programs are not +installed on the build system, or other preconditions are not met. </para> <para> A specific set of tools -with which to initialize the environment when +with which to initialize an environment when creating it may be specified using the optional keyword argument -<parameter>tools</parameter>. +<parameter>tools</parameter>, which takes a list +of tool names. This is useful to override the defaults, to specify non-default built-in tools, and to supply added tools:</para> @@ -2302,7 +2353,7 @@ env = Environment(tools=['msvc', 'lex']) </programlisting> <para> -Tools can also be called by using the &f-link-Tool; +Tools can also be directly called by using the &f-link-Tool; method (see below). </para> @@ -2317,39 +2368,51 @@ The tool name <literal>'default'</literal> can be used to retain the default list. </para> -<para>If no <parameter>tools</parameter> list is specified, -or the list includes <literal>'default'</literal>, -then &scons; will detect usable tools, -using the value of <varname>PATH</varname> -in the <varname>ENV</varname> &consvar; (<emphasis>not</emphasis> -the external <envar>PATH</envar> from <varname>os.environ</varname>) +<para>If no <parameter>tools</parameter> argument is specified, +or if <parameter>tools</parameter> includes <literal>'default'</literal>, +then &scons; will auto-detect usable tools, +using the execution environment value of <varname>PATH</varname> +(that is, <varname><replaceable>env</replaceable>['ENV']['PATH']</varname> - +the external evironment <envar>PATH</envar> from <varname>os.environ</varname> +is <emphasis>not</emphasis> used) for looking up any backing programs, and the platform name in effect to determine the default tools for that platform. Changing the <varname>PATH</varname> variable after the &consenv; is constructed will not cause the tools to -be redetected.</para> +be re-detected.</para> -<para>To help locate added tools, specify the -<parameter>toolpath</parameter> keyword argument:</para> +<para> +Additional tools can be added to a project either by +placing them in a <filename>site_tools</filename> subdirectory +of a site directory, or in a custom location specified to +&scons; by giving the +<parameter>toolpath</parameter> keyword argument. +<parameter>toolpath</parameter> also takes a list as its value: +</para> <programlisting language="python"> env = Environment(tools=['default', 'foo'], toolpath=['tools']) </programlisting> <para> -This looks for a tool specification in <filename>tools/foo.py</filename> +This looks for a tool specification module <filename>foo.py</filename> +in directory <filename>tools</filename> and in the standard locations, as well as using the ordinary default tools for the platform. </para> <para> -Tools in the toolpath are used in preference to -any of the built-in ones. For example, adding -a tool <filename>gcc.py</filename> to the toolpath -directory would override the built-in gcc tool. -The toolpath is +Directories specified via <parameter>toolpath</parameter> are prepended +to the existing tool path. The default tool path is any <filename>site_tools</filename> +directories, so tools in a specified <parameter>toolpath</parameter> +take priority, +followed by tools in a <filename>site_tools</filename> directory, +followed by built-in tools. For example, adding +a tool specification module <filename>gcc.py</filename> to the toolpath +directory would override the built-in &t-link-gcc; tool. +The tool path is stored in the environment and will be -picked up by subsequent calls to the -&f-Clone; and &f-Tool; methods: +used by subsequent calls to the &f-link-Tool; method, +as well as by &f-link-env-Clone;. </para> <programlisting language="python"> @@ -2359,7 +2422,7 @@ derived.CustomBuilder() </programlisting> <para> -A tool specification must include two functions: +A tool specification module must include two functions: </para> <variablelist> @@ -2378,7 +2441,8 @@ to vary its initialization.</para> <term><function>exists</function>(<parameter>env</parameter>)</term> <listitem> <para>Return <constant>True</constant> if the tool can -be called. Usually this means looking up one or more +be called in the context of <parameter>env</parameter>. +Usually this means looking up one or more known programs using the <envar>PATH</envar> from the supplied <parameter>env</parameter>, but the tool can make the "exists" decision in any way it chooses. @@ -2387,6 +2451,18 @@ make the "exists" decision in any way it chooses. </varlistentry> </variablelist> +<note> +<para> +At the moment, user-added tools do not automatically have their +<function>exists</function> function called. +As a result, it is recommended that the <function>generate</function> +function be defensively coded - that is, do not rely on any +necessary existence checks already having been performed. +This is expected to be a temporary limitation, +and the <function>exists</function> function should still be provided. +</para> +</note> + <para>The elements of the <parameter>tools</parameter> list may also be functions or callable objects, in which case the &Environment; method @@ -2690,7 +2766,7 @@ see the descriptions below of these variables for more information.</para> <para>The optional <parameter>parse_flags</parameter> keyword argument is recognized by builders. -This works similarly to the +This works similarly to the &f-link-env-MergeFlags; method, where the argument value is broken into individual settings and merged into the appropriate &consvars;. </para> @@ -3081,7 +3157,7 @@ that can be used in SConscript files to affect how you want the build to be performed.</para> <variablelist> - <varlistentry> + <varlistentry id="v-ARGLIST"> <term>&ARGLIST;</term> <listitem> <para>A list of the @@ -3113,7 +3189,7 @@ for key, value in ARGLIST: </listitem> </varlistentry> - <varlistentry> + <varlistentry id="v-ARGUMENTS"> <term>&ARGUMENTS;</term> <listitem> <para>A dictionary of all the @@ -3138,7 +3214,7 @@ else: </listitem> </varlistentry> - <varlistentry> + <varlistentry id="v-BUILD_TARGETS"> <term>&BUILD_TARGETS;</term> <listitem> <para>A list of the targets which @@ -3184,7 +3260,7 @@ if 'special/program' in BUILD_TARGETS: </listitem> </varlistentry> - <varlistentry> + <varlistentry id="v-COMMAND_LINE_TARGETS"> <term>&COMMAND_LINE_TARGETS;</term> <listitem> <para>A list of the targets explicitly specified on @@ -3207,7 +3283,7 @@ if 'special/program' in COMMAND_LINE_TARGETS: </listitem> </varlistentry> - <varlistentry> + <varlistentry id="v-DEFAULT_TARGETS"> <term>&DEFAULT_TARGETS;</term> <listitem> <para>A list of the target @@ -4174,6 +4250,13 @@ Calling &Variables; with no arguments is equivalent to: vars = Variables(files=None, args=ARGUMENTS) </programlisting> +<para> +Note that since the variables are eventually added as &consvars;, +you should choose variable names which do not unintentionally change +pre-defined &consvars; that your project will make use of +(see <xref linkend="construction_variables"/>). +</para> + </listitem> </varlistentry> </variablelist> @@ -5458,18 +5541,21 @@ and emitter functions.</para> function will turn its <parameter>action</parameter> keyword argument into an appropriate -internal Action object. +internal Action object, as will +the &f-link-Command; function. You can also explicitly create Action objects for passing to &f-Builder;, or other functions that take actions as arguments, by calling the &f-link-Action; factory function. -This can be used to configure -an Action object more flexibly, -or it may simply be more efficient -than letting each separate Builder object -create a separate Action -when multiple -Builder objects need to do the same thing.</para> +This may more efficient when multiple +Builder objects need to do the same thing +rather than letting each of those Builder objects +create a separate Action object. +It also allows more flexible configuration +of an Action object. For example, to control +the message printed when the action is taken +you need to create the action object using &f-Action;. +</para> <para>The &Action; factory function @@ -5589,23 +5675,22 @@ it was called. The global function form &f-link-Action; the Action object is actually used. </para> -<para>The second argument to &f-Action; -is optional and is used to define the output +<para>The optional second argument to &f-Action; +is used to control the output which is printed when the Action is actually performed. -In the absence of this parameter, -or if it's an empty string, +If this parameter is omitted, +or if the value is an empty string, a default output depending on the type of the action is used. For example, a command-line action will print the executed command. -The argument must be either a Python function or a string:</para> +The following argument types are accepted: +</para> <itemizedlist> <listitem> <para>If the output argument is a function, -it must return a string +the function will be called to obtain a string describing the action being executed. -A function may also be specified using the -<parameter>strfunction</parameter> -keyword argument. The function +The function must accept these three keyword arguments:</para> <simplelist type="vert"> @@ -5626,18 +5711,29 @@ more than one target file or source file.</para> <listitem> <para>If the output argument is a string, -substitution is performed on it before it is printed. -The output string may also be specified using the -<parameter>cmdstr</parameter> -keyword argument. +substitution is performed on the string before it is printed. The string typically contains variables, notably <literal>$TARGET(S)</literal> and <literal>$SOURCE(S)</literal>, or consists of just a single variable, which is optionally defined somewhere else. -SCons itself heavily uses the latter variant.</para> +&SCons; itself heavily uses the latter variant.</para> + </listitem> + + <listitem> +<para>If the argument is <constant>None</constant>, +output is suppressed entirely.</para> </listitem> </itemizedlist> +<para> +Instead of using a positional argument, +the <parameter>cmdstr</parameter> +keyword argument may be used to specify the output string, +or the <parameter>strfunction</parameter> keyword argument +may be used to specify a function to return the output string, +Use <literal>cmdstr=None</literal> to suppress output. +</para> + <para>Examples:</para> <programlisting language="python"> @@ -6101,14 +6197,25 @@ env.Command('marker', 'input_file', action=[MyBuildAction, Touch('$TARGET')]) <para>Before executing a command, &scons; -performs &consvar; substitution on the string that makes up -the command line of the builder. -&Consvars; to be interpolated are indicated in the +performs variable substitution on the string that makes up +the action part of the builder. +Variables to be interpolated are indicated in the string with a leading <literal>$</literal>, to distinguish them from plain text which is not to be substituted. +The name may be surrounded by curly braces +(<literal>${}</literal>) +to separate the name from surrounding characters if necessary. +Curly braces are required when you use +Python list subscripting/slicing notation on a variable +to select one or more items from a list, +or access a variable's special attributes, +or use Python expression substitution. +</para> + +<para> Besides regular &consvars;, scons provides the following -special variables for each command execution:</para> +special variables for use in expanding commands:</para> <variablelist> <varlistentry> @@ -6180,45 +6287,39 @@ changed since the target was last built.</para> </varlistentry> </variablelist> -<para>Note that the above variables are reserved -and may not be assigned to in the &consenv;.</para> +<para>These names are reserved +and may not be assigned to or used as &consvars;.</para> -<para>For example, given the &consvars; -<literal>CC='cc'</literal>, -<literal>targets=['foo']</literal> -and -<literal>sources=['foo.c', 'bar.c']</literal>: +<para>For example, the following builder call: </para> <programlisting language="python"> -action='$CC -c -o $TARGET $SOURCES' +env = Environment(CC='cc') +env.Command( + target=['foo'], + source=['foo.c', 'bar.c'], + action='@echo $CC -c -o $TARGET $SOURCES' +) </programlisting> -<para>would produce the command line:</para> +<para>would produce the following output:</para> <screen> cc -c -o foo foo.c bar.c </screen> -<para>Variable names may be surrounded by curly braces -(<emphasis role="bold">{}</emphasis>) -to separate the name from surrounding characters which -are not part of the name. -Within the curly braces, a variable name may use -Python list subscripting/slicing notation to select one -or more items from a list. -In the previous example, the string: +<para> +In the previous example, a string <code>${SOURCES[1]}</code> -would produce:</para> - -<screen> -bar.c -</screen> +would expand to: <computeroutput>bar.c</computeroutput>. +</para> -<para>Additionally, a variable name may +<para>A variable name may have the following modifiers appended within the enclosing curly braces -to access properties of the interpolated string:</para> +to access properties of the interpolated string. +These are known as <firstterm>special attributes</firstterm>. +</para> <simplelist> <member><parameter>base</parameter> - @@ -6297,23 +6398,18 @@ ${SOURCE.rsrcdir} => /usr/repository/src </literallayout> <para> -Modifiers can be combined, like -<literal>${TARGET.base.windows}</literal>, +Some modifiers can be combined, like <literal>${TARGET.srcpath.base)</literal>, <literal>${TARGET.file.suffix}</literal>, etc. </para> -<para>Note that curly braces braces may also be used -to enclose arbitrary Python code to be evaluated. -(In fact, this is how the above modifiers are substituted, -they are simply attributes of the Python objects -that represent &cv-TARGET;, &cv-SOURCES;, etc.) +<para>The curly brace notation may also be used +to enclose a Python expression to be evaluated. See <xref linkend='python_code_substitution'/> below -for more thorough examples of -how this can be used.</para> +for a description.</para> -<para>Lastly, a variable name -may be a callable Python function +<para>A variable name +may also be a Python function associated with a &consvar; in the environment. The function should @@ -6344,6 +6440,12 @@ def foo(target, source, env, for_signature): env=Environment(FOO=foo, BAR="$FOO baz") </programlisting> +<para>As a reminder, this evaluation happens when +<literal>$BAR</literal> is actually used in a +builder action. The value of <literal>env['BAR']</literal> +will be exactly as it was set: <literal>"$FOO baz"</literal>. +</para> + <para>You can use this feature to pass arguments to a Python function by creating a callable class that stores one or more arguments in an object, @@ -6415,19 +6517,20 @@ echo Last build occurred . > $TARGET <title>Python Code Substitution</title> <para> -Any Python code within curly braces -(<emphasis role="bold">{}</emphasis>) -and introduced by the variable prefix <literal>$</literal> -will be evaluated using the Python <function>eval</function> statement, -with the Python globals set to -the current environment's set of &consvars;, and the result -substituted in. +If a substitutable expression using the notation +<literal>${something}</literal> does not appear to match one of +the other substitution patterns, +it is evaluated as a Python expression. +This uses Python's <function>eval</function> function, +with the <parameter>globals</parameter> parameter set to +the current environment's set of &consvars;, +and the result substituted in. So in the following case:</para> <programlisting language="python"> -env['COND'] = 0 -env.Command('foo.out', 'foo.in', - '''echo ${COND==1 and 'FOO' or 'BAR'} > $TARGET''') +env.Command( + 'foo.out', 'foo.in', "echo ${COND==1 and 'FOO' or 'BAR'} > $TARGET" +) </programlisting> <para>the command executed will be either</para> @@ -6449,7 +6552,7 @@ built, not when the SConscript is being read. So if <literal>env['COND']</literal> is changed later in the SConscript, the final value will be used.</para> -<para>Here's a more interesting example. Note that all of +<para>Here's a more complete example. Note that all of <envar>COND</envar>, <envar>FOO</envar>, and @@ -6460,17 +6563,29 @@ separated by spaces.</para> <programlisting language="python"> env=Environment() -env['COND'] = 0 +env['COND'] = 1 env['FOO'] = ['foo1', 'foo2'] env['BAR'] = 'barbar' -env.Command('foo.out', 'foo.in', - 'echo ${COND==1 and FOO or BAR} > $TARGET') - -# Will execute this: -# echo foo1 foo2 > foo.out +env.Command( + 'foo.out', 'foo.in', "echo ${COND==1 and FOO or BAR} > $TARGET" +) </programlisting> -<para>SCons uses the following rules when converting &consvars; into +<para>will execute:</para> +<screen> +echo foo1 foo2 > foo.out +</screen> + +<para> +In point of fact, Python expression evaluation is +how the special attributes are substituted: +they are simply attributes of the Python objects +that represent &cv-TARGET;, &cv-SOURCES;, etc., +which &SCons; passes to <function>eval</function> which +returns the value. +</para> + +<para>&SCons; uses the following rules when converting &consvars; into command lines:</para> <variablelist> @@ -6508,6 +6623,16 @@ contain embedded newline characters.</para> </listitem> </varlistentry> </variablelist> + +<note><para> +Use of the Python <function>eval</function> function +is considered to have security implications, since, +depending on input sources, +arbitrary unchecked strings of code can be executed by the Python interpreter. +Although &SCons; makes use of it in a somewhat restricted context, +you should be aware of this issue when using the +<literal>${python-expression-for-subst}</literal> form. +</para></note> </refsect2> <refsect2 id='scanner_objects'> @@ -6532,8 +6657,7 @@ a Python function that will process the Node (file) and return a list of File Nodes representing the implicit -dependencies (file names) found in the contents; -or: +dependencies (file names) found in the contents. </para></listitem> <listitem><para> a dictionary that maps keys @@ -6872,7 +6996,7 @@ script named <para>The MinGW <filename>bin</filename> directory must be in your <envar>PATH</envar> environment variable or the -<envar>ENV['PATH']</envar> &consvar; for &scons; +<varname>['ENV']['PATH']</varname> &consvar; for &scons; to detect and use the MinGW tools. When running under the native Windows Python interpreter, &scons; will prefer the MinGW tools over the Cygwin tools, if they are both installed, regardless of the order of the bin @@ -7473,7 +7597,7 @@ release, it may be necessary to specify </listitem> </varlistentry> - <varlistentry> + <varlistentry id="v-SCONSFLAGS"> <term><envar>SCONSFLAGS</envar></term> <listitem> <para>A string of options that will be used by &scons; diff --git a/doc/overview.rst b/doc/overview.rst index 9a2558a..74aa688 100644 --- a/doc/overview.rst +++ b/doc/overview.rst @@ -92,12 +92,19 @@ Entities ======== We are using entities for special keywords like ``SCons`` that should -appear with the same formatting throughout the text. These are kept in -a single file ``doc/scons.mod`` which gets included by the documents. - -Additionally, for each Tool, Builder, Cvar (construction variable) and -Function, a bunch of linkends in the form of entities get defined. They -can be used in the MAN page and the User manual. +appear with the same formatting throughout the text. This allows a +single place to make styling changes if needed. These are kept in +a single file ``doc/scons.mod`` which gets included by the documents, +and can be used anywhere in the documentation files. + +Additionally, for the definitions of the four special types available +in the SCons doctype - Tool, Builder, Construction Variable and Function - +a bunch of reference links in the form of entities are generated. +These entities can be used in the MAN page and the User manual. +Note that the four type tags themselves (``<tool>``, ``<builder>``, +``<cvar>`` and ``<function>``) can only be used in documentation +sources in the ``SCons`` directory; the build will not scan for these +in the ``doc`` directory. When you add an XML file in the ``SCons/Tools`` folder, e.g. for a tool named ``foobar``, you can use the two entities @@ -134,12 +141,12 @@ By calling the script :: python bin/docs-update-generated.py - + you can recreate the lists of entities (``*.mod``) in the ``generated`` -folder, if required. At the same time, this will generate the ``*.gen`` +folder. At the same time, this will generate the matching ``*.gen`` files, which list the full description of all the Builders, Tools, -Functions and CVars for the MAN page and the User Guide's appendix. -Thus, you want to regenerate when there's a change to +Functions and CVars for the MAN page and the User Guide's appendix. +Thus, you want to regenerate when there's a change to any of those four special elements, or an added or deleted element. These generated files are left checked in so in the normal case you can just rebuild the docs without having to first generate the entity @@ -150,14 +157,59 @@ refer to the start of the Python script ``bin/SConsDoc.py``. It explains the available tags and the exact syntax in detail. -Examples -======== +Linking +======= + +Normal Docbook (v4.5 style, as of this writing) in-document linking +is supported, as is linking to documents with a web address. +For any element in a document, you can include an ``id=name`` +attribute to set an identifier, and write a link to that identifier. +Many of the section headings already have such identifiers, +and it is fine to add more, as long as they remain unique. +As noted in the previous section, for the special types, +entities are generated which contain links, +so you can just use those entities instead +of writing the link reference manually. + +There is something to keep in mind about linking, however. +Cross-document links between the MAN page and the User Guide +do not work. But some text is shared between the two, which +allows the appearance of such linking, and this is where it +gets a little confusing. The text defined by the four special +types is generated into the ``*.gen`` files, +which get included both in the appropriate places in the MAN page, +and in the Appendix in the User Guide. Using entities within +this shared content is fine. Writing links in this shared +content to element identifiers defined elsewhere is not. + +That sounds a little confusing so here is a real example: +an xml source file in ``SCons`` defines the ``SCANNERS`` +construction variable by using ``<cvar name="SCANNERS"> ... </cvar>``. +This will generate the linking entity ``&cv-link-SCANNERS;``, +which can be used anywhere the ``doc/generated/variables.gen`` +file is included (i.e. MAN page and User Guide for now) +to leave a link to this definition. +But the text written inside the ``SCANNERS`` definition +also wants to refer to the "Builder Objects" and "Scanner +Objects" sections in the MAN page, as this contains relevant +further description. This reference should not include an +XML link, even though the MAN page defines the two identifiers +``scanner_objects`` and ``builder_objects``, because this +definition will *also* be included in the User Guide, which +has no such section names or identifiers. It is better here +to write it all in text, as in *See the manpage section +"Builder Objects"* than to leave a dangling reference in one +of the docs. + +SCons Examples +============== In the User Guide, we support automatically created examples. This means that the output of the specified source files and SConstructs is generated by running them with the current SCons version. We do this to ensure that the output displayed in the manual is identical to what -you get when you run the example on the command-line. +you get when you run the example on the command-line, without having +to remember to manually update the example outputs all the time. A short description about how these examples have to be defined can be found at the start of the file ``bin/SConsExamples.py``. Call @@ -212,17 +264,17 @@ User Guide. *generated* Entity lists and outputs of the UserGuide examples. They get generated - by the update scripts ``bin/docs-update-generated.py`` + by the update scripts ``bin/docs-update-generated.py`` and ``bin/docs-create-example-outputs.py``. *images* Images for the ``overview.rst`` document. - + *xsd* The SCons Docbook schema (XSD), based on the Docbook v4.5 DTD/XSD. - + *xslt* XSLT transformation scripts for converting the special SCons tags like ``scons_output`` to valid Docbook during document processing. - + diff --git a/doc/user/MANIFEST b/doc/user/MANIFEST index d7237df..5be5aff 100644 --- a/doc/user/MANIFEST +++ b/doc/user/MANIFEST @@ -44,6 +44,7 @@ run.xml scanners.xml sconf.xml separate.xml +sideeffect.xml simple.xml tasks.xml tools.xml diff --git a/doc/user/build-install.xml b/doc/user/build-install.xml index 87a86aa..c106dc5 100644 --- a/doc/user/build-install.xml +++ b/doc/user/build-install.xml @@ -110,12 +110,13 @@ Python 3.7.1 </screen> <para> - Note to Windows users: there are many different ways Python - can get installed or invoked on Windows, it is beyond the scope - of this guide to unravel all of them. Try using the - <firstterm>Python launcher</firstterm> (see - <ulink url="https://www.python.org/dev/peps/pep-0397/">PEP 397</ulink>) - by using the name <command>py</command> instead of + Note to Windows users: there are a number of different ways Python + can be installed or invoked on Windows, it is beyond the scope + of this guide to unravel all of them. Many will have an additional + program called the <firstterm>Python launcher</firstterm> (described, + somewhat technically, in + <ulink url="https://www.python.org/dev/peps/pep-0397/">PEP 397</ulink>): + try using the command name <command>py</command> instead of <command>python</command>, if that is not available drop back to trying <command>python</command>. </para> @@ -129,21 +130,23 @@ Python 3.7.1 If Python is not installed on your system, or is not findable in the current search path, you will see an error message - stating something like "command not found" + stating something like <computeroutput>"command not found"</computeroutput> (on UNIX or Linux) - or "'python' is not recognized - as an internal or external command, operable progam or batch file" + or <computeroutput>"'python' is not recognized as an internal + or external command, operable progam or batch file"</computeroutput> (on Windows <command>cmd</command>). - In that case, you need to install Python - (or fix the search path) + In that case, you need to either install Python + or fix the search path before you can install &SCons;. </para> <para> - The canonical location for information - about downloading and installing Python is - <ulink url="http://www.python.org/download/">http://www.python.org/download/</ulink>. - See that page and associated links to get started. + The canonical location for downloading Python + from Python's own website is: + <ulink url="https://www.python.org/download">https://www.python.org/download</ulink>. + There are useful system-specific entries on setup and + usage to be found at: + <ulink url="https://docs.python.org/3/using">https://docs.python.org/3/using</ulink> </para> <para> @@ -153,7 +156,7 @@ Python 3.7.1 by other means, and is easier than installing from source code. Many such systems have separate packages for Python 2 and Python 3 - make sure the Python 3 package is - installed, as &SCons; requires it. + installed, as the latest &SCons; requires it. Building from source may still be a useful option if you need a version that is not offered by the distribution you are using. @@ -195,7 +198,7 @@ Python 3.7.1 For those users using Anaconda or Miniconda, use the <command>conda</command> installer instead, so the &scons; install location will match the version of Python that - system will be using: + system will be using. For example: </para> <screen> @@ -211,14 +214,14 @@ Python 3.7.1 During the still-ongoing Python 2 to 3 transition, some distributions may still have two &SCons; packages available, one which uses Python 2 and one which uses Python 3. Since - latest &scons; only runs on Python 3, to get the current version + the latest &scons; only runs on Python 3, to get the current version you should choose the Python 3 package. </para> <para> If you need a specific version of &SCons; that is different from the package available, - <filename>pip</filename> has a version option or you can follow + <systemitem>pip</systemitem> has a version option or you can follow the instructions in the next section. </para> @@ -229,9 +232,9 @@ Python 3.7.1 <para> If a pre-built &SCons; package is not available for your system, - and installing using <filename>pip</filename> is not suitable, + and installing using <systemitem>pip</systemitem> is not suitable, then you can still easily build and install &SCons; using the native - Python <filename>distutils</filename> package. + Python <systemitem>setuptools</systemitem> package. </para> <para> @@ -265,11 +268,11 @@ Python 3.7.1 install the &scons; script in the python which is used to run the setup.py's scripts directory (<filename>/usr/local/bin</filename> or - <filename>C:\Python27\Scripts</filename>), + <filename>C:\Python37\Scripts</filename>), and will install the &SCons; build engine in the corresponding library directory for the python used (<filename>/usr/local/lib/scons</filename> or - <filename>C:\Python27\scons</filename>). + <filename>C:\Python37\scons</filename>). Because these are system directories, you may need root (on Linux or UNIX) or Administrator (on Windows) privileges to install &SCons; like this. diff --git a/doc/user/builders-commands.xml b/doc/user/builders-commands.xml index 5d378b3..7d47dae 100644 --- a/doc/user/builders-commands.xml +++ b/doc/user/builders-commands.xml @@ -81,7 +81,7 @@ if you only need to execute one specific command to build a single file (or group of files). For these situations, &SCons; supports a - &Command; &Builder; that arranges + &f-link-Command; builder that arranges for a specific action to be executed to build a specific file or files. This looks a lot like the other builders @@ -119,7 +119,7 @@ foo.in This is often more convenient than creating a &Builder; object and adding it to the &cv-link-BUILDERS; variable - of a &consenv; + of a &consenv;. </para> @@ -134,9 +134,11 @@ foo.in <scons_example name="builderscommands_ex2"> <file name="SConstruct" printme="1"> env = Environment() + def build(target, source, env): # Whatever it takes to build return None + env.Command('foo.out', 'foo.in', build) </file> <file name="foo.in"> @@ -157,8 +159,7 @@ foo.in <para> Note that &cv-link-SOURCE; and &cv-link-TARGET; are expanded - in the source and target as well as of SCons 1.1, - so you can write: + in the source and target as well, so you can write: </para> @@ -168,7 +169,6 @@ env.Command('${SOURCE.basename}.out', 'foo.in', build) </file> </scons_example> - <para> which does the same thing as the previous example, but allows you @@ -176,5 +176,61 @@ env.Command('${SOURCE.basename}.out', 'foo.in', build) </para> + <para> + + It may be helpful to use the <parameter>action</parameter> + keyword to specify the action, is this makes things more clear + to the reader: + + </para> + + <scons_example name="builderscommands_ex4"> + <file name="SConstruct" printme="1"> +env.Command('${SOURCE.basename}.out', 'foo.in', action=build) + </file> + </scons_example> + + <para> + + The method described in + <xref linkend="sect-controlling-build-output"/> for controlling + build output works well when used with pre-defined builders which + have pre-defined <literal>*COMSTR</literal> variables for that purpose, + but that is not the case when calling &f-Command;, + where &SCons; has no specific knowledge of the action ahead of time. + If the action argument to &f-Command; is not already an &Action; object, + it will construct one for you with suitable defaults, + which include a message based on the type of action. + However, you can also construct the &Action; object yourself + to pass to &f-Command;, which gives you much more control. + Here's an evolution of the example from above showing this approach: + + </para> + + <scons_example name="builderscommands_ex5"> + <file name="SConstruct" printme="1"> +env = Environment() + +def build(target, source, env): + # Whatever it takes to build + return None + +act = Action(build, cmdstr="Building ${TARGET}") +env.Command('foo.out', 'foo.in', action=act) + </file> + <file name="foo.in"> +foo.in + </file> + </scons_example> + + <para> + + Which executes as follows: + + </para> + + <scons_output example="builderscommands_ex5" suffix="1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> </chapter> diff --git a/doc/user/command-line.xml b/doc/user/command-line.xml index 6910290..8db9230 100644 --- a/doc/user/command-line.xml +++ b/doc/user/command-line.xml @@ -174,8 +174,8 @@ def b(target, source, env): pass def s(target, source, env): return " ... [build output] ..." -a = Action(b, strfunction = s) -env = Environment(BUILDERS = {'A' : Builder(action=a)}) +a = Action(b, strfunction=s) +env = Environment(BUILDERS={'A': Builder(action=a)}) env.A('foo.out', 'foo.in') </file> <file name="foo.in"> @@ -330,7 +330,7 @@ if not GetOption('help'): import os num_cpu = int(os.environ.get('NUM_CPU', 2)) SetOption('num_jobs', num_cpu) -print("running with -j %s"%GetOption('num_jobs')) +print("running with -j %s" % GetOption('num_jobs')) </file> <file name="foo.in"> foo.in @@ -347,9 +347,9 @@ foo.in where the string is spelled differently from the from command-line option. The string for fetching or setting the <option>--jobs</option> - value is <literal>num_jobs</literal> + value is <parameter>num_jobs</parameter> for historical reasons.) - The code in this example prints the <literal>num_jobs</literal> + The code in this example prints the <parameter>num_jobs</parameter> value for illustrative purposes. It uses a default value of <literal>2</literal> to provide some minimal parallelism even on @@ -817,7 +817,7 @@ foo.in env = Environment() debug = ARGUMENTS.get('debug', 0) if int(debug): - env.Append(CCFLAGS = '-g') + env.Append(CCFLAGS='-g') env.Program('prog.c') </file> <file name="prog.c"> @@ -847,7 +847,7 @@ prog.c the last values used to build the object files, and as a result correctly rebuilds the object and executable files - only when the value of the <literal>debug</literal> + only when the value of the <parameter>debug</parameter> argument has changed. </para> @@ -1265,9 +1265,7 @@ vars = Variables('custom.py', ARGUMENTS) <scons_example name="commandline_BoolVariable"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(BoolVariable('RELEASE', - help='Set to build for release', - default=0)) +vars.Add(BoolVariable('RELEASE', help='Set to build for release', default=0)) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) env.Program('foo.c') </file> @@ -1348,7 +1346,7 @@ foo.c </section> <section> - <title>Single Value From a List: the &EnumVariable; Build Variable Function</title> + <title>Single Value From a Selection: the &EnumVariable; Build Variable Function</title> <para> @@ -1370,10 +1368,14 @@ foo.c <scons_example name="commandline_EnumVariable"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(EnumVariable('COLOR', - help='Set background color', - default='red', - allowed_values=('red', 'green', 'blue'))) +vars.Add( + EnumVariable( + 'COLOR', + help='Set background color', + default='red', + allowed_values=('red', 'green', 'blue'), + ) +) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c') Help(vars.GenerateHelpText(env)) @@ -1440,11 +1442,15 @@ foo.c <scons_example name="EnumVariable_map"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(EnumVariable('COLOR', - help='Set background color', - default='red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'})) +vars.Add( + EnumVariable( + 'COLOR', + help='Set background color', + default='red', + allowed_values=('red', 'green', 'blue'), + map={'navy': 'blue'}, + ) +) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c') </file> @@ -1496,13 +1502,17 @@ foo.c <scons_example name="commandline_EnumVariable_ic1"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(EnumVariable('COLOR', - help='Set background color', - default='red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'}, - ignorecase=1)) -env = Environment(variables=vars, CPPDEFINES={'COLOR':'"${COLOR}"'}) +vars.Add( + EnumVariable( + 'COLOR', + help='Set background color', + default='red', + allowed_values=('red', 'green', 'blue'), + map={'navy': 'blue'}, + ignorecase=1, + ) +) +env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c') </file> <file name="foo.c"> @@ -1537,12 +1547,16 @@ foo.c <scons_example name="commandline_EnumVariable_ic2"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(EnumVariable('COLOR', - help='Set background color', - default='red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'}, - ignorecase=2)) +vars.Add( + EnumVariable( + 'COLOR', + help='Set background color', + default='red', + allowed_values=('red', 'green', 'blue'), + map={'navy': 'blue'}, + ignorecase=2, + ) +) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c') </file> @@ -1587,10 +1601,11 @@ foo.c <scons_example name="commandline_ListVariable"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(ListVariable('COLORS', - help='List of colors', - default=0, - names=['red', 'green', 'blue'])) +vars.Add( + ListVariable( + 'COLORS', help='List of colors', default=0, names=['red', 'green', 'blue'] + ) +) env = Environment(variables=vars, CPPDEFINES={'COLORS': '"${COLORS}"'}) env.Program('foo.c') </file> @@ -1639,6 +1654,29 @@ foo.c <scons_output_command>scons -Q COLORS=magenta foo.o</scons_output_command> </scons_output> + <para> + + You can use this last characteristic as a way to enforce at least + one of your valid options being chosen by specifying the valid + values with the <parameter>names</parameter> parameter and then + giving a value not in that list as the <parameter>default</parameter> + parameter - that way if no value is given on the command line, + the default is chosen, and it will error out with an invalid value. + The example is, in fact, set up that way by using + <literal>0</literal> as the default: + + </para> + + <scons_output example="commandline_ListVariable" suffix="4"> + <scons_output_command>scons -Q foo.o</scons_output_command> + </scons_output> + + <para> + + This technique works for &EnumVariable; as well. + + </para> + </section> <section> @@ -1659,9 +1697,11 @@ foo.c <scons_example name="commandline_PathVariable"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(PathVariable('CONFIG', - help='Path to configuration file', - default='__ROOT__/etc/my_config')) +vars.Add( + PathVariable( + 'CONFIG', help='Path to configuration file', default='__ROOT__/etc/my_config' + ) +) env = Environment(variables=vars, CPPDEFINES={'CONFIG_FILE': '"$CONFIG"'}) env.Program('foo.c') </file> @@ -1678,7 +1718,7 @@ foo.c <para> - This then allows the user to + This allows you to override the &CONFIG; build variable on the command line as necessary: @@ -1714,10 +1754,14 @@ foo.c <scons_example name="commandline_PathIsFile"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(PathVariable('CONFIG', - help='Path to configuration file', - default='__ROOT__/etc/my_config', - validator=PathVariable.PathIsFile)) +vars.Add( + PathVariable( + 'CONFIG', + help='Path to configuration file', + default='__ROOT__/etc/my_config', + validator=PathVariable.PathIsFile, + ) +) env = Environment(variables=vars, CPPDEFINES={'CONFIG_FILE': '"$CONFIG"'}) env.Program('foo.c') </file> @@ -1740,10 +1784,14 @@ foo.c <scons_example name="commandline_PathIsDir"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(PathVariable('DBDIR', - help='Path to database directory', - default='__ROOT__/var/my_dbdir', - validator=PathVariable.PathIsDir)) +vars.Add( + PathVariable( + 'DBDIR', + help='Path to database directory', + default='__ROOT__/var/my_dbdir', + validator=PathVariable.PathIsDir, + ) +) env = Environment(variables=vars, CPPDEFINES={'DBDIR': '"$DBDIR"'}) env.Program('foo.c') </file> @@ -1768,10 +1816,14 @@ foo.c <scons_example name="commandline_PathIsDirCreate"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(PathVariable('DBDIR', - help='Path to database directory', - default='__ROOT__/var/my_dbdir', - validator=PathVariable.PathIsDirCreate)) +vars.Add( + PathVariable( + 'DBDIR', + help='Path to database directory', + default='__ROOT__/var/my_dbdir', + validator=PathVariable.PathIsDirCreate, + ) +) env = Environment(variables=vars, CPPDEFINES={'DBDIR': '"$DBDIR"'}) env.Program('foo.c') </file> @@ -1795,10 +1847,14 @@ foo.c <scons_example name="commandline_PathAccept"> <file name="SConstruct" printme="1"> vars = Variables('custom.py') -vars.Add(PathVariable('OUTPUT', - help='Path to output file or directory', - default=None, - validator=PathVariable.PathAccept)) +vars.Add( + PathVariable( + 'OUTPUT', + help='Path to output file or directory', + default=None, + validator=PathVariable.PathAccept, + ) +) env = Environment(variables=vars, CPPDEFINES={'OUTPUT': '"$OUTPUT"'}) env.Program('foo.c') </file> @@ -1829,9 +1885,9 @@ foo.c <scons_example name="commandline_PackageVariable"> <file name="SConstruct" printme="1"> vars = Variables("custom.py") -vars.Add(PackageVariable("PACKAGE", - help="Location package", - default="__ROOT__/opt/location")) +vars.Add( + PackageVariable("PACKAGE", help="Location package", default="__ROOT__/opt/location") +) env = Environment(variables=vars, CPPDEFINES={"PACKAGE": '"$PACKAGE"'}) env.Program("foo.c") </file> @@ -1967,7 +2023,7 @@ vars.Add('RELEASE', help='Set to 1 to build for release', default=0) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) unknown = vars.UnknownVariables() if unknown: - print("Unknown variables: %s"%unknown.keys()) + print("Unknown variables: %s" % " ".join(unknown.keys())) Exit(1) env.Program('foo.c') </file> @@ -1984,12 +2040,12 @@ foo.c that are <emphasis>not</emphasis> among the variables known to the &Variables; object (from having been specified using - the &Variables; object's&Add; method). - In the examble above, + the &Variables; object's &Add; method). + In the example above, we check for whether the dictionary - returned by the &UnknownVariables; is non-empty, + returned by &UnknownVariables; is non-empty, and if so print the Python list - containing the names of the unknwown variables + containing the names of the unknown variables and then call the &Exit; function to terminate &SCons;: @@ -2016,8 +2072,9 @@ foo.c Note that you must delay the call of &UnknownVariables; until after you have applied the &Variables; object to a construction environment - with the <literal>variables=</literal> - keyword argument of an &Environment; call. + with the <parameter>variables=</parameter> + keyword argument of an &Environment; call: the variables + in the object are not fully processed until this has happened. </para> @@ -2259,7 +2316,7 @@ int bar() { printf("prog2/bar.c\n"); } Lastly, if for some reason you don't want any targets built by default, - you can use the Python <literal>None</literal> + you can use the Python <constant>None</constant> variable: </para> @@ -2441,7 +2498,7 @@ else: prog1 = Program('prog1.c') Program('prog2.c') Default(prog1) -print ("BUILD_TARGETS is %s" % [str(t) for t in BUILD_TARGETS]) +print("BUILD_TARGETS is %s" % [str(t) for t in BUILD_TARGETS]) </file> <file name="prog1.c"> prog1.c diff --git a/doc/user/environments.xml b/doc/user/environments.xml index 8c492b3..40bcd31 100644 --- a/doc/user/environments.xml +++ b/doc/user/environments.xml @@ -379,7 +379,7 @@ environment, of directory names, suffixes, etc. </varlistentry> <varlistentry> - <term>&ConsEnv;</term> + <term>Construction Environment</term> <listitem> <para> @@ -479,15 +479,16 @@ environment, of directory names, suffixes, etc. and key-value store) associates keys with values, such that asking the dict about a key gives you back the associated value and assigning to a key creates the association - either a new - setting if the key was unknown, or replacing the previous - previous association if the key was already in the dict. - Accessing can be done by using <literal>[]</literal> - indexing notation, and dictionaries also provide a + setting if the key was unknown, or replacing the + previous association if the key was already in the dictionary. + Values can be retrieved using <firstterm>item access</firstterm> + (the key name in square brackets (<literal>[]</literal>)), + and dictionaries also provide a method named <methodname>get</methodname> which responds - with a default value (<constant>None</constant> or a default - you supply) if the key is not in the dictionary, which - avoids failing in that case. The syntax - for a dictionary itself uses curly braces (<literal>{}</literal>). + with a default value, either <constant>None</constant> or a value + you supply as the second argument, if the key is not in the dictionary, + which avoids failing in that case. The syntax + for initializing a dictionary uses curly braces (<literal>{}</literal>). Here are some simple examples (inspired by those in the official Python tutorial) using syntax that indicates interacting with the &Python; interpreter @@ -498,7 +499,7 @@ environment, of directory names, suffixes, etc. <screen> <prompt>>>></prompt> <userinput>tel = {'jack': 4098, 'sape': 4139}</userinput> -<prompt>>>></prompt> <userinput>tel['guido'] = 4098</userinput> +<prompt>>>></prompt> <userinput>tel['guido'] = 4127</userinput> <prompt>>>></prompt> <userinput>tel['jack']</userinput> 4098 <prompt>>>></prompt> <userinput>del tel['sape']</userinput> @@ -522,7 +523,8 @@ None a &consenv; <emphasis>is</emphasis> a &Python; dictionary. The <varname>os.environ</varname> value that &Python; uses to make available the external environment is also a - dictionary. We will need these concepts in this chapter. + dictionary. We will need these concepts in this chapter + and throughout the rest of this guide. </para> @@ -538,10 +540,10 @@ None the user has in force when executing &SCons; are available in the &Python; - <varname>os.environ</varname> - dictionary. That syntax means the <varname>environ</varname> + <varname>os.environ</varname> dictionary. + That syntax means the <varname>environ</varname> attribute of the <systemitem>os</systemitem> module. - In Python, to access contents of a module you must first + In Python, to access the contents of a module you must first <literal>import</literal> it - so you would include the <literal>import os</literal> statement to any &SConscript; file diff --git a/doc/user/main.xml b/doc/user/main.xml index 6f516f9..fd643b5 100644 --- a/doc/user/main.xml +++ b/doc/user/main.xml @@ -82,7 +82,8 @@ <chapter id="chap-manip-options"> <title>Automatically Putting Command-line Options into their Construction Variables</title> - <!-- TODO: This intro paragraph should describe at a high-level + <!-- TODO: combine this into a chapter document. + This intro paragraph should describe at a high-level what these things do. People are likely to use the intro as a (brief) overview of *what* these functions do to decide if this chapter is where they should read in more detail. --> @@ -104,60 +105,34 @@ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="file-removal.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="hierarchy.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="separate.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="variants.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="gettext.xml"/> - - <!-- - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="builders-built-in.xml"/> - - --> - + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="repositories.xml"/> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="builders-built-in.xml"/> --> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="builders-writing.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="builders-commands.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="add-method.xml"/> - - <!-- - - XXX Action() - XXX AddPostAction() - XXX AddPreAction() - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="actions.xml"/> - - --> - + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="actions.xml"/> --> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="scanners.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="repositories.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sconf.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="caching.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="alias.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="java.xml"/> - - <!-- - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="run.xml"/> - - --> - + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="gettext.xml"/> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="run.xml"/> --> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="misc.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="external.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="troubleshoot.xml"/> -<!-- Appendix below here --> + <!-- Appendix below here --> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="variables.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="builders.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="tools.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="functions.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="tasks.xml"/> - <!-- - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="python.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="example.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="make.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ant.xml"/> - - --> + <!-- These sections are only sekeletons: --> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="python.xml"/> --> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="example.xml"/> --> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="make.xml"/> --> + <!-- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ant.xml"/> --> </book> diff --git a/doc/user/misc.xml b/doc/user/misc.xml index b093629..1b18d2f 100644 --- a/doc/user/misc.xml +++ b/doc/user/misc.xml @@ -625,6 +625,9 @@ env.Command('directory_build_info', </section> + <!-- Former unpublished chapter now included as a section here: --> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sideeffect.xml"/> + <section> <title>Virtual environments (virtualenvs)</title> diff --git a/doc/user/output.xml b/doc/user/output.xml index bae018a..cf6571c 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -197,7 +197,7 @@ if env['PLATFORM'] == 'win32': </section> - <section> + <section id="sect-controlling-build-output"> <title>Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables</title> <para> diff --git a/doc/user/parse_flags_arg.xml b/doc/user/parse_flags_arg.xml index 6e9b926..6014145 100644 --- a/doc/user/parse_flags_arg.xml +++ b/doc/user/parse_flags_arg.xml @@ -17,7 +17,7 @@ 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"> -<title>Merging Options into the Environment: the <parameter>merge_flags</parameter> Parameter</title> +<title>Merging Options While Creating Environment: the <parameter>parse_flags</parameter> Parameter</title> <!-- diff --git a/doc/user/separate.xml b/doc/user/separate.xml index 748a124..236556d 100644 --- a/doc/user/separate.xml +++ b/doc/user/separate.xml @@ -2,7 +2,7 @@ <!DOCTYPE sconsdoc [ <!ENTITY % scons SYSTEM "../scons.mod"> %scons; - + <!ENTITY % builders-mod SYSTEM "../generated/builders.mod"> %builders-mod; <!ENTITY % functions-mod SYSTEM "../generated/functions.mod"> @@ -17,7 +17,7 @@ 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"> -<title>Separating Source and Build Directories</title> +<title>Separating Source and Build Trees: Variant Directories</title> <!-- @@ -44,115 +44,49 @@ --> -<!-- + <para> -=head1 Separating source and build trees - -It's often desirable to keep any derived files from the build completely -separate from the source files. This makes it much easier to keep track of -just what is a source file, and also makes it simpler to handle B<variant> -builds, especially if you want the variant builds to co-exist. - -=head2 Separating build and source directories using the Link command - -Cons provides a simple mechanism that handles all of these requirements. The -C<Link> command is invoked as in this example: - - Link 'build' => 'src'; - -The specified directories are ``linked'' to the specified source -directory. Let's suppose that you setup a source directory, F<src>, with the -sub-directories F<world> and F<hello> below it, as in the previous -example. You could then substitute for the original build lines the -following: - - Build qw( - build/world/Conscript - build/hello/Conscript - ); - -Notice that you treat the F<Conscript> file as if it existed in the build -directory. Now if you type the same command as before, you will get the -following results: - - % cons export - Install build/world/world.h as export/include/world.h - cc -Iexport/include -c build/hello/hello.c -o build/hello/hello.o - cc -Iexport/include -c build/world/world.c -o build/world/world.o - ar r build/world/libworld.a build/world/world.o - ar: creating build/world/libworld.a - ranlib build/world/libworld.a - Install build/world/libworld.a as export/lib/libworld.a - cc -o build/hello/hello build/hello/hello.o -Lexport/lib -lworld - Install build/hello/hello as export/bin/hello - -Again, Cons has taken care of the details for you. In particular, you will -notice that all the builds are done using source files and object files from -the build directory. For example, F<build/world/world.o> is compiled from -F<build/world/world.c>, and F<export/include/world.h> is installed from -F<build/world/world.h>. This is accomplished on most systems by the simple -expedient of ``hard'' linking the required files from each source directory -into the appropriate build directory. - -The links are maintained correctly by Cons, no matter what you do to the -source directory. If you modify a source file, your editor may do this ``in -place'' or it may rename it first and create a new file. In the latter case, -any hard link will be lost. Cons will detect this condition the next time -the source file is needed, and will relink it appropriately. - -You'll also notice, by the way, that B<no> changes were required to the -underlying F<Conscript> files. And we can go further, as we shall see in the -next section. - -=head2 Explicit references to the source directory - -When using the C<Link> command on some operating systems or with some -tool chains, it's sometimes useful to have a command actually use -the path name to the source directory, not the build directory. For -example, on systems that must copy, not "hard link," the F<src/> and -F<build/> copies of C<Linked> files, using the F<src/> path of a file -name might make an editor aware that a syntax error must be fixed in the -source directory, not the build directory. - -You can tell Cons that you want to use the "source path" for a file by -preceding the file name with a ``!'' (exclamation point). For example, -if we add a ``!'' to the beginning of a source file: - - Program $env "foo", "!foo.c"; # Notice initial ! on foo.c - -Cons will compile the target as follows: - - cc -c src/foo.c -o build/foo.o - cc -o build/foo build/foo.o - -Notice that Cons has compiled the program from the the F<src/foo.c> -source file. Without the initial ``!'', Cons would have compiled the -program using the F<build/foo.c> path name. + It's often useful to keep any built files completely + separate from the source files. Consider if you have a + project to build software for a variety of different + controller hardware. The boards are able to share a + lot of code, so it makes sense to keep them in the same + source tree, but certain build options in the source code + and header files differ. If you build "Controller A" first, + then "Controller B", on the second build everything would + have to be rebuilt, because &SCons; sees that the build + instructions differ, and thus the targets that depend on those + different instructions are not valid for the current build. + Now when you go back and build for "Controller A", + things have to be rebuilt from scratch again for the same reason. + However, if you can separate the places the output files + go, this problem can be avoided. + You can even set up to do both builds in one invocation of &SCons;. ---> + </para> <para> - It's often useful to keep any built files completely - separate from the source files. - In &SCons;, this is usually done by creating one or more separate - <emphasis>variant directory trees</emphasis> + You can enable this separation by creating one or more + <firstterm>variant directory</firstterm> trees that are used to hold the built objects files, libraries, and executable programs, etc. for a specific flavor, or variant, of build. &SCons; provides two ways to do this, - one through the &SConscript; function that we've already seen, - and the second through a more flexible &VariantDir; function. + one through the &f-link-SConscript; function that we've already seen, + and the second through a more flexible &f-link-VariantDir; function. </para> <para> - One historical note: the &VariantDir; function + Historical note: the &VariantDir; function used to be called &BuildDir;, a name which was removed because the &SCons; functionality - differs from the model of a "build directory" - implemented by other build systems like the GNU Autotools. + differs from a familiar model of a "build directory" + implemented by other build systems like GNU Autotools. + You might still find references to the old name on + the Internet in postings about &SCons;, but it no longer works. </para> @@ -162,11 +96,11 @@ program using the F<build/foo.c> path name. <para> The most straightforward way to establish a variant directory tree - uses the fact that the usual way to + relies the fact that the usual way to set up a build hierarchy is to have an - &SConscript; file in the source subdirectory. - If you then pass a &variant_dir; argument to the - &SConscript; function call: + SConscript file in the source subdirectory. + If you pass a &variant_dir; argument to the + &f-link-SConscript; function call: </para> @@ -193,20 +127,25 @@ int main() { printf("Hello, world!\n"); } <scons_output example="separate_ex1" suffix="1"> <scons_output_command>ls src</scons_output_command> <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls src</scons_output_command> <scons_output_command>ls build</scons_output_command> </scons_output> <para> - But wait a minute--what's going on here? - &SCons; created the object file + No files were built in &src;, they went to &build;. + The build output might show a bit of a surprise: + the object file <filename>build/hello.o</filename> - in the &build; subdirectory, + and the executable file + <filename>build/hello</filename> + were built in the &build; subdirectory, as expected. But even though our &hello_c; file lives in the &src; subdirectory, &SCons; has actually compiled a <filename>build/hello.c</filename> file - to create the object file. + to create the object file, + and that file is now seen in &build;. </para> @@ -215,7 +154,7 @@ int main() { printf("Hello, world!\n"); } What's happened is that &SCons; has <emphasis>duplicated</emphasis> the &hello_c; file from the &src; subdirectory to the &build; subdirectory, - and built the program from there. + and built the program from there (it also duplicated &SConscript;). The next section explains why &SCons; does this. </para> @@ -227,13 +166,13 @@ int main() { printf("Hello, world!\n"); } <para> - &SCons; duplicates source files in variant directory trees - because it's the most straightforward way to guarantee a correct build - <emphasis>regardless of include-file directory paths, - relative references between files, - or tool support for putting files in different locations</emphasis>, - and the &SCons; philosophy is to, by default, - guarantee a correct build in all cases. + The important thing to understand is that when you set up a variant directory, + &SCons; performs the build <emphasis>in that directory</emphasis>. + It turns out it's easiest to ensure where build products end up + by just building in place. + Since the build is happening in a place different from where the + sources are, the most straightforward way to guarantee a correct build + is for &SCons; to copy them there. </para> @@ -312,13 +251,13 @@ int main() { printf("Hello, world!\n"); } duplicating the source files and everything will work just fine. You can disable the default &SCons; behavior - by specifying <literal>duplicate=0</literal> + by specifying <literal>duplicate=False</literal> when you call the &SConscript; function: </para> <sconstruct> -SConscript('src/SConscript', variant_dir='build', duplicate=0) +SConscript('src/SConscript', variant_dir='build', duplicate=False) </sconstruct> <para> @@ -395,14 +334,14 @@ int main() { printf("Hello, world!\n"); } <para> - You can specify the same <literal>duplicate=0</literal> argument + You can specify the same <literal>duplicate=False</literal> argument that you can specify for an &SConscript; call: </para> <scons_example name="separate_duplicate0"> <file name="SConstruct" printme="1"> -VariantDir('build', 'src', duplicate=0) +VariantDir('build', 'src', duplicate=False) env = Environment() env.Program('build/hello.c') </file> @@ -432,8 +371,10 @@ int main() { printf("Hello, world!\n"); } <para> Even when using the &VariantDir; function, - it's much more natural to use it with - a subsidiary &SConscript; file. + it's more natural to use it with + a subsidiary &SConscript; file, + because then you don't have to adjust your individual + build instructions to use the variant directory path. For example, if the <filename>src/SConscript</filename> looks like this: @@ -490,7 +431,7 @@ int main() { printf("Hello, world!\n"); } <para> - The &Glob; file name pattern matching function + The &f-link-Glob; file name pattern matching function works just as usual when using &VariantDir;. For example, if the <filename>src/SConscript</filename> @@ -558,4 +499,6 @@ const char * f2(); --> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="variants.xml"/> + </chapter> diff --git a/doc/user/sideeffect.xml b/doc/user/sideeffect.xml index d03fbe2..2733769 100644 --- a/doc/user/sideeffect.xml +++ b/doc/user/sideeffect.xml @@ -2,7 +2,7 @@ <!DOCTYPE sconsdoc [ <!ENTITY % scons SYSTEM "../scons.mod"> %scons; - + <!ENTITY % builders-mod SYSTEM "../generated/builders.mod"> %builders-mod; <!ENTITY % functions-mod SYSTEM "../generated/functions.mod"> @@ -13,11 +13,11 @@ %variables-mod; ]> -<chapter id="chap-sideeffect" +<section id="sect-sideeffect" 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"> -<title>Sideeffect files</title> +<title>Declaring Additional Outputs: the &f-SideEffect; Function </title> <!-- @@ -46,68 +46,142 @@ <para> - If &SCons; is unaware that a build step produces an extra file, - the &SideEffect; method can be used to identify it, - so that the file can be used as a dependency in subsequent build steps. - However, the primary use for the &SideEffect; method - is to prevent two build steps from simultaneously modifying the same file. + Sometimes the way an action is defined causes effects on files + that &SCons; does not recognize as targets. The &f-link-SideEffect; + method can be used to informs &SCons; about such files. + This can be used just to flag a dependency for use in subsequent + build steps, although there is usually a better way to do that. + The primary use for the &SideEffect; method + is to prevent two build steps from simultaneously modifying + or accessing the same file in a way that could impact each other. </para> <para> - TODO: currently doesn't work due to issue #2154: - https://github.com/SCons/scons/issues/2154 + + In this example, the rule to build <filename>file1</filename> + will also put data into <filename>log</filename>, which is used + as a source for the command to generate <filename>file2</filename>, + but <filename>log</filename> is unknown to &SCons; on a clean + build: it neither exists, nor is it a target output by any builder. + The <filename>SConscript</filename> uses + &SideEffect; to inform &SCons; about the additional output file. + </para> - + + <scons_example name="sideeffect_simple"> + <file name="SConstruct" printme="1"> +env = Environment() +f2 = env.Command( + target='file2', + source='log', + action=Copy('$TARGET', '$SOURCE') +) +f1 = env.Command( + target='file1', + source=[], + action='echo >$TARGET data1; echo >log updated file1' +) +env.SideEffect('log', f1) + </file> + </scons_example> + <para> - If more than one build step creates or manipulates the same file, - it can cause unpleasant results if both build steps are run at the same time. - The shared file is declared as a side-effect of building the primary targets - and &SCons; will prevent the two build steps from running in parallel. + Without the &f-SideEffect;, this build would fail with a message + <computeroutput>Source `log' not found, needed by target `file2'</computeroutput>, + but now it can proceed: </para> + <scons_output example="sideeffect_simple" suffix="1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + <para> - In this example, the <filename>SConscript</filename> uses - &SideEffect; to inform &SCons; about the additional output file. + However, it is better to actually identify + <filename>log</filename> as a target, since in this + case that's what it is: </para> - <scons_example name="sideeffect_simple"> + <scons_example name="sideeffect_simple2"> <file name="SConstruct" printme="1"> env = Environment() -f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE')) -f1 = env.Command('file1', [], - 'echo >$TARGET data1; echo >log updated file1') -env.SideEffect('log', env.Command('file1', [], - 'echo >$TARGET data1; echo >log updated file1')) +f2 = env.Command( + target='file2', + source='log', + action=Copy('$TARGET', '$SOURCE') +) +f1 = env.Command( + target=['file1', 'log'], + source=[], + action='echo >$TARGET data1; echo >log updated file1' +) </file> </scons_example> + <scons_output example="sideeffect_simple2" suffix="1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + <para> - Even when run in parallel mode, &SCons; will run the two steps in order: + In general, &SideEffect; is not intended for the case when + a command produces extra target files (that is, files which + will be used as sources to other build steps). For example, the + the Microsoft Visual C/C++ compiler is capable of performing + incremental linking, for which it uses a status file - such that + linking <filename>foo.exe</filename> also produces + a <filename>foo.ilk</filename>, or uses it if it was already present, + if the <option>/INCREMENTAL</option> option was supplied. + Specifying <filename>foo.ilk</filename> as a + side-effect of <filename>foo.exe</filename> + is <emphasis>not</emphasis> a recommended use of &SideEffect; + since <filename>foo.ilk</filename> is used by the link. + &SCons; handles side-effect files + slightly differently in its analysis of the dependency graph. + When a command produces multiple output files, + they should be specified as multiple targets of + the call to the relevant builder function. + The &SideEffect; function itself should really only be used + when it's important to ensure that commands are not executed in parallel, + such as when a "peripheral" file (such as a log file) + may actually be updated by more than one command invocation. </para> - <scons_output example="sideeffect_simple" suffix="1"> - <scons_output_command>scons -Q --jobs=2</scons_output_command> - </scons_output> + <para> + + Unfortunately, the tool which sets up the &b-Program; builder + for the MSVC compiler chain does not come prebuilt + with an understanding of the details of the <filename>.ilk</filename> + example - that the target list would need to change + in the presence of that specific option flag. Unlike the trivial + example above where we could simply tell the &Command; builder + there were two targets of the action, modifying the + chain of events for a builder like &b-Program;, + though not inherently complex, is definitely an + advanced &SCons; topic. It's okay to use &SideEffect; here + to get started, as long as it comes with an understanding + that it's "not quite right". Perhaps leave a comment in + the file as a reminder, if it does turn out to cause problems later. + + </para> <para> - Sometimes a program the you need to call - to build a target file - will also update another file, - such as a log file describing what the program + So if the main use is to prevent parallelism problems, + here is an example to illustrate. + Say a program that you need to call to build a target file + will also update a log file describing what the program does while building the target. - For example, we the folowing configuration + The following configuration would have &SCons; invoke a hypothetical script named <application>build</application> (in the local directory) - with command-line arguments that write + with command-line arguments telling it to write log information to a common <filename>logfile.txt</filename> file: @@ -115,10 +189,16 @@ env.SideEffect('log', env.Command('file1', [], <screen> env = Environment() -env.Command('file1.out', 'file.in', - './build --log logfile.txt $SOURCE $TARGET') -env.Command('file2.out', 'file.in', - './build --log logfile.txt $SOURCE $TARGET') +env.Command( + target='file1.out', + source='file1.in', + action='./build --log logfile.txt $SOURCE $TARGET' +) +env.Command( + target='file2.out', + source='file2.in', + action='./build --log logfile.txt $SOURCE $TARGET' +) </screen> <para> @@ -156,10 +236,16 @@ env.Command('file2.out', 'file.in', <scons_example name="sideeffect_shared"> <file name="SConstruct" printme="1"> env = Environment() -f1 = env.Command('file1.out', 'file1.in', - './build --log logfile.txt $SOURCE $TARGET') -f2 = env.Command('file2.out', 'file2.in', - './build --log logfile.txt $SOURCE $TARGET') +f1 = env.Command( + target='file1.out', + source='file1.in', + action='./build --log logfile.txt $SOURCE $TARGET' +) +f2 = env.Command( + target='file2.out', + source='file2.in', + action='./build --log logfile.txt $SOURCE $TARGET' +) env.SideEffect('logfile.txt', f1 + f2) </file> <file name="file1.in">file1.in</file> @@ -177,7 +263,7 @@ cat This makes sure the the two <application>./build</application> steps are run sequentially, - even withthe <filename>--jobs=2</filename> in the command line: + even with the <filename>--jobs=2</filename> in the command line: </para> @@ -189,20 +275,23 @@ cat The &SideEffect; function can be called multiple times for the same side-effect file. - Additionally, the name used as a &SideEffect; does not - even need to actually exist as a file on disk. + In fact, the name used as a &SideEffect; does not + even need to actually exist as a file on disk - &SCons; will still make sure that the relevant targets - will be executed sequentially, not in parallel: + will be executed sequentially, not in parallel. + The side effect is actually a pseudo-target, and &SCons; + mainly cares whether nodes are listed as depending on it, + not about its contents. </para> <scons_example name="sideeffect_parallel"> <file name="SConstruct" printme="1"> env = Environment() -f1 = env.Command('file1.out', [], 'echo >$TARGET data1') +f1 = env.Command('file1.out', [], action='echo >$TARGET data1') env.SideEffect('not_really_updated', f1) -f2 = env.Command('file2.out', [], 'echo >$TARGET data2') +f2 = env.Command('file2.out', [], action='echo >$TARGET data2') env.SideEffect('not_really_updated', f2) </file> </scons_example> @@ -211,28 +300,5 @@ env.SideEffect('not_really_updated', f2) <scons_output_command>scons -Q --jobs=2</scons_output_command> </scons_output> - <para> - - Note that it might be tempting to - use &SideEffect; for additional target files - that a command produces. - For example, versions the Microsoft Visual C/C++ compiler - produce a <filename>foo.ilk</filename> - alongside compiling <filename>foo.obj</filename> file. - Specifying <filename>foo.ilk</filename> as a - side-effect of <filename>foo.obj</filename> - is <emphasis>not</emphasis> a recommended use of &SideEffect;, - because &SCons; handle side-effect files - slightly differently in its analysis of the dependency graph. - When a command produces multiple output files, - they should be specified as multiple targets of - the call to the relevant builder function, - and the &SideEffect; function itself should really only be used - when it's important to ensure that commands are not executed in parallel, - such as when a "peripheral" file (such as a log file) - may actually updated by more than one command invocation. - - </para> + </section> - </chapter> - diff --git a/doc/user/simple.xml b/doc/user/simple.xml index 138ff54..8582613 100644 --- a/doc/user/simple.xml +++ b/doc/user/simple.xml @@ -459,7 +459,7 @@ int main() { printf("Goodbye, world!\n"); } we see the output from calling the <function>print</function> function in between the messages about reading the &SConscript; files, - indicating that that is when the + indicating that is when the Python statements are being executed: </para> diff --git a/doc/user/troubleshoot.xml b/doc/user/troubleshoot.xml index 7049deb..3906af6 100644 --- a/doc/user/troubleshoot.xml +++ b/doc/user/troubleshoot.xml @@ -69,8 +69,8 @@ odds are pretty good that someone else will run into the same problem, too. If so, please let the SCons development team know - (preferably by filing a bug report - or feature request at our project pages at tigris.org) + using the contact information at + <ulink url="https://scons.org/contact.html"/> so that we can use your feedback to try to come up with a better way to help you, and others, get the necessary insight into &SCons; behavior diff --git a/doc/user/variants.xml b/doc/user/variants.xml index 0c83b04..6cf8c3d 100644 --- a/doc/user/variants.xml +++ b/doc/user/variants.xml @@ -13,11 +13,11 @@ %variables-mod; ]> -<chapter id="chap-variants" +<section id="sect-variants" 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"> -<title>Variant Builds</title> +<title>Variant Build Examples</title> <!-- @@ -44,30 +44,6 @@ --> -<!-- - -=head1 Variant builds - -=head2 Variations on a theme - -Other variations of this model are possible. For example, you might decide -that you want to separate out your include files into platform dependent and -platform independent files. In this case, you'd have to define an -alternative to C<$INCLUDE> for platform-dependent files. Most F<Conscript> -files, generating purely platform-independent include files, would not have -to change. - -You might also want to be able to compile your whole system with debugging -or profiling, for example, enabled. You could do this with appropriate -command line options, such as C<DEBUG=on>. This would then be translated -into the appropriate platform-specific requirements to enable debugging -(this might include turning off optimization, for example). You could -optionally vary the name space for these different types of systems, but, as -we'll see in the next section, it's not B<essential> to do this, since Cons -is pretty smart about rebuilding things when you change options. - ---> - <para> The &variant_dir; keyword argument of @@ -76,9 +52,15 @@ is pretty smart about rebuilding things when you change options. variant builds using &SCons;. Suppose, for example, that we want to build a program for both Windows and Linux platforms, - but that we want to build it in a shared directory + but that we want to build it in directory on a network share with separate side-by-side build directories for the Windows and Linux versions of the program. + We have to do a little bit of work to construct paths, + to make sure unwanted location dependencies don't creep in. + The top-relative path reference can be useful here. + To avoid writing conditional code based on platform, + we can build the <parameter>variant_dir</parameter> + path dynamically: </para> @@ -90,13 +72,15 @@ include = "#export/$PLATFORM/include" lib = "#export/$PLATFORM/lib" bin = "#export/$PLATFORM/bin" -env = Environment(PLATFORM = platform, - BINDIR = bin, - INCDIR = include, - LIBDIR = lib, - CPPPATH = [include], - LIBPATH = [lib], - LIBS = 'world') +env = Environment( + PLATFORM=platform, + BINDIR=bin, + INCDIR=include, + LIBDIR=lib, + CPPPATH=[include], + LIBPATH=[lib], + LIBS='world', +) Export('env') @@ -155,20 +139,32 @@ int world() { printf "world.c\n"; } <scons_output_command>scons -Q OS=windows</scons_output_command> </scons_output> - <!-- + <para> + + In order to build several variants at once when using the + <parameter>variant_dir</parameter> argument to &SConscript;, + you can call the function repeatedely - this example + does so in a loop. Note that the &f-link-SConscript; trick of + passing a list of script files, or a list of source directories, + does not work with <parameter>variant_dir</parameter>, + &SCons; allows only a single &SConscript; to be given if + <parameter>variant_dir</parameter> is used. + + </para> <scons_example name="variants_ex2"> <file name="SConstruct" printme="1"> -env = Environment(OS = ARGUMENTS.get('OS')) +env = Environment(OS=ARGUMENTS.get('OS')) for os in ['newell', 'post']: SConscript('src/SConscript', variant_dir='build/' + os) </file> </scons_example> + <!-- <scons_output example="variants_ex2" suffix="1"> <scons_output_command>scons -Q</scons_output_command> </scons_output> --> -</chapter> +</section> @@ -1,29 +1,25 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # runtest.py - wrapper script for running SCons tests # # The SCons test suite consists of: # -# - unit tests - included in *Tests.py files from src/ dir +# - unit tests - included in *Tests.py files from SCons/ dir # - end-to-end tests - these are *.py files in test/ directory that # require custom SCons framework from testing/ # # This script adds SCons/ and testing/ directories to PYTHONPATH, # performs test discovery and processes them according to options. -# -# With -p (--package) option, script tests specified package from -# build directory and sets PYTHONPATH to reference modules unpacked -# during build process for testing purposes (build/test-*). """ Options: -a --all Run all tests. -b --baseline BASE Run test scripts against baseline BASE. - --builddir DIR Directory in which packages were built. -d --debug Run test scripts under the Python debugger. -D --devmode Run tests in Python's development mode (3.7+ only) + --e2e-only Run only the end-to-end tests -e --external Run the script in external mode (for external Tools) -f --file FILE Only run tests listed in FILE. -j --jobs JOBS Run tests in JOBS parallel jobs. @@ -37,15 +33,6 @@ Options: chars! You might run into some deadlocks else. -o --output FILE Save the output from a test run to the log file. -P PYTHON Use the specified Python interpreter. - -p --package PACKAGE Test against the specified PACKAGE: - deb Debian - local-tar-gz .tar.gz standalone package - local-zip .zip standalone package - rpm Red Hat - src-tar-gz .tar.gz source package - src-zip .zip source package - tar-gz .tar.gz distribution - zip .zip distribution --passed Summarize which tests passed. -q --quiet Don't print the test being executed. --quit-on-failure Quit on any test failure. @@ -54,6 +41,7 @@ Options: and a percentage value, based on the total and current number of tests. -t --time Print test execution time. + --unit-only Run only the unit tests -v VERSION Specify the SCons version. --verbose=LEVEL Set verbose level: 1 = print executed commands, @@ -87,7 +75,6 @@ from queue import Queue cwd = os.getcwd() baseline = None -builddir = os.path.join(cwd, 'build') external = 0 devmode = False debug = '' @@ -95,7 +82,6 @@ execute_tests = True jobs = 1 list_only = False printcommand = True -package = None print_passed_summary = False scons = None scons_exec = False @@ -103,13 +89,13 @@ testlistfile = None version = '' print_times = False python = None -sp = [] print_progress = True catch_output = False suppress_output = False allow_pipe_files = True quit_on_failure = False excludelistfile = None +e2e_only = unit_only = False script = sys.argv[0].split("/")[-1] usagestr = """\ @@ -153,7 +139,6 @@ opts, args = getopt.getopt( "b:dDef:hj:klnP:p:qsv:Xx:t", [ "baseline=", - "builddir=", "debug", "devmode", "external", @@ -164,7 +149,6 @@ opts, args = getopt.getopt( "list", "no-exec", "nopipefiles", - "package=", "passed", "python=", "quiet", @@ -175,16 +159,14 @@ opts, args = getopt.getopt( "exec=", "verbose=", "exclude-list=", + "e2e-only", + "unit-only", ], ) for o, a in opts: if o in ['-b', '--baseline']: baseline = a - elif o in ['--builddir']: - builddir = a - if not os.path.isabs(builddir): - builddir = os.path.normpath(os.path.join(cwd, builddir)) elif o in ['-d', '--debug']: for d in sys.path: pdb = os.path.join(d, 'pdb.py') @@ -215,8 +197,6 @@ for o, a in opts: execute_tests = False elif o in ['--nopipefiles']: allow_pipe_files = False - elif o in ['-p', '--package']: - package = a elif o in ['--passed']: print_passed_summary = True elif o in ['-P', '--python']: @@ -241,9 +221,13 @@ for o, a in opts: scons = a elif o in ['--exclude-list']: excludelistfile = a + elif o in ['--e2e-only']: + e2e_only = True + elif o in ['--unit-only']: + unit_only = True -class Unbuffered(): +class Unbuffered: """ class to arrange for stdout/stderr to be unbuffered """ def __init__(self, file): self.file = file @@ -261,7 +245,7 @@ sys.stderr = Unbuffered(sys.stderr) if options.output: logfile = open(options.output, 'w') - class Tee(): + class Tee: def __init__(self, openfile, stream): self.file = openfile self.stream = stream @@ -296,13 +280,9 @@ else: return f return None -sp.append(builddir) -sp.append(cwd) -# _ws = re.compile(r'\s') - def escape(s): if _ws.search(s): s = '"' + s + '"' @@ -313,8 +293,8 @@ def escape(s): if not catch_output: # Without any output suppressed, we let the subprocess # write its stuff freely to stdout/stderr. - def spawn_it(command_args): - cp = subprocess.run(command_args, shell=False) + def spawn_it(command_args, env): + cp = subprocess.run(command_args, shell=False, env=env) return cp.stdout, cp.stderr, cp.returncode else: # Else, we catch the output of both pipes... @@ -330,7 +310,7 @@ else: # http://http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/ # and pass temp file objects to Popen() instead of the ubiquitous # subprocess.PIPE. - def spawn_it(command_args): + def spawn_it(command_args, env): # Create temporary files tmp_stdout = tempfile.TemporaryFile(mode='w+t') tmp_stderr = tempfile.TemporaryFile(mode='w+t') @@ -338,7 +318,8 @@ else: cp = subprocess.run(command_args, stdout=tmp_stdout, stderr=tmp_stderr, - shell=False) + shell=False, + env=env) try: # Rewind to start of files @@ -368,11 +349,12 @@ else: # (but the subprocess isn't writing anything there). # Hence a deadlock. # Be dragons here! Better don't use this! - def spawn_it(command_args): + def spawn_it(command_args, env): cp = subprocess.run(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=False) + shell=False, + env=env) return cp.stdout, cp.stderr, cp.returncode @@ -400,8 +382,8 @@ class RuntestBase(ABC): class SystemExecutor(RuntestBase): """ Test class for tests executed with spawn_it() """ - def execute(self): - self.stderr, self.stdout, s = spawn_it(self.command_args) + def execute(self, env): + self.stderr, self.stdout, s = spawn_it(self.command_args, env) self.status = s if s < 0 or s > 2: sys.stdout.write("Unexpected exit status %d\n" % s) @@ -414,13 +396,13 @@ class PopenExecutor(RuntestBase): by calling subprocess.run (behind the covers uses Popen. Very similar to SystemExecutor, but uses command_str instead of command_args, and doesn't allow for not catching - the output. + the output). """ # For an explanation of the following 'if ... else' # and the 'allow_pipe_files' option, please check out the # definition of spawn_it() above. if allow_pipe_files: - def execute(self): + def execute(self, env): # Create temporary files tmp_stdout = tempfile.TemporaryFile(mode='w+t') tmp_stderr = tempfile.TemporaryFile(mode='w+t') @@ -428,7 +410,8 @@ class PopenExecutor(RuntestBase): cp = subprocess.run(self.command_str.split(), stdout=tmp_stdout, stderr=tmp_stderr, - shell=False) + shell=False, + env=env) self.status = cp.returncode try: @@ -443,11 +426,12 @@ class PopenExecutor(RuntestBase): tmp_stdout.close() tmp_stderr.close() else: - def execute(self): + def execute(self, env): cp = subprocess.run(self.command_str.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=False) + shell=False, + env=env) self.status = cp.returncode self.stdout = cp.stdout self.stderr = cp.stderr @@ -553,13 +537,38 @@ if old_pythonpath: # ---[ test discovery ]------------------------------------ +# This section figures which tests to run. +# +# The initial testlist is made by reading from the testlistfile, +# if supplied, or by looking at the test arguments, if supplied, +# or by looking for all test files if the "all" argument is supplied. +# One of the three is required. +# +# Each test path, whichever of the three sources it comes from, +# specifies either a test file or a directory to search for +# SCons tests. SCons code layout assumes that any file under the 'SCons' +# subdirectory that ends with 'Tests.py' is a unit test, and any Python +# script (*.py) under the 'test' subdirectory is an end-to-end test. +# We need to track these because they are invoked differently. +# find_unit_tests and find_e2e_tests are used for this searching. +# +# Note that there are some tests under 'SCons' that *begin* with +# 'test_', but they're packaging and installation tests, not +# functional tests, so we don't execute them by default. (They can +# still be executed by hand, though). +# +# Test exclusions, if specified, are then applied. -tests = [] -excludetests = [] unittests = [] endtests = [] +def scanlist(testlist): + """Process a testlist file""" + tests = [t.strip() for t in testlist if not t.startswith('#')] + return [t for t in tests if t] + + def find_unit_tests(directory): """ Look for unit tests """ result = [] @@ -583,7 +592,7 @@ def find_e2e_tests(directory): continue try: with open(os.path.join(dirpath, ".exclude_tests")) as f: - excludes = [e.split("#", 1)[0].strip() for e in f.readlines()] + excludes = scanlist(f) except EnvironmentError: excludes = [] for fname in filenames: @@ -592,27 +601,12 @@ def find_e2e_tests(directory): return sorted(result) +# initial selection: if testlistfile: with open(testlistfile, 'r') as f: - tests = f.readlines() - tests = [x for x in tests if x[0] != '#'] - tests = [x[:-1] for x in tests] - tests = [x.strip() for x in tests] - tests = [x for x in tests if x] + tests = scanlist(f) else: testpaths = [] - - # Each test path specifies a test file, or a directory to search for - # SCons tests. SCons code layout assumes that any file under the 'SCons' - # subdirectory that ends with 'Tests.py' is a unit test, and any Python - # script (*.py) under the 'test' subdirectory an end-to-end test. - # We need to track these because they are invoked differently. - # - # Note that there are some tests under 'SCons' that *begin* with - # 'test_', but they're packaging and installation tests, not - # functional tests, so we don't execute them by default. (They can - # still be executed by hand, though). - if options.all: testpaths = ['SCons', 'test'] elif args: @@ -622,47 +616,44 @@ else: # Clean up path so it can match startswith's below # sys.stderr.write("Changed:%s->"%tp) # remove leading ./ or .\ - if tp[0] == '.' and tp[1] in (os.sep, os.altsep): + if tp.startswith('.') and tp[1] in (os.sep, os.altsep): tp = tp[2:] # tp = os.path.normpath(tp) # sys.stderr.write('->%s<-'%tp) # sys.stderr.write("to:%s\n"%tp) for path in glob.glob(tp): if os.path.isdir(path): - if path.startswith('SCons') or path.startswith('testing'): - for p in find_unit_tests(path): - unittests.append(p) + if path.startswith(('SCons', 'testing')): + unittests.extend(find_unit_tests(path)) elif path.startswith('test'): - for p in find_e2e_tests(path): - endtests.append(p) + endtests.extend(find_e2e_tests(path)) else: if path.endswith("Tests.py"): unittests.append(path) - else: + elif path.endswith(".py"): endtests.append(path) + tests = unittests + endtests - tests.extend(unittests) - tests.extend(endtests) - tests.sort() +# Remove exclusions: +if e2e_only: + tests = [t for t in tests if not t.endswith("Tests.py")] +if unit_only: + tests = [t for t in tests if t.endswith("Tests.py")] +if excludelistfile: + with open(excludelistfile, 'r') as f: + excludetests = scanlist(f) + tests = [t for t in tests if t not in excludetests] if not tests: sys.stderr.write(usagestr + """ -runtest.py: No tests were found. - Tests can be specified on the command line, read from file - with -f option, or discovered with -a to run all tests. +runtest: no tests were found. + Tests can be specified on the command line, read from a file with + the -f/--file option, or discovered with -a/--all to run all tests. """) sys.exit(1) -if excludelistfile: - with open(excludelistfile, 'r') as f: - excludetests = f.readlines() - excludetests = [x for x in excludetests if x[0] != '#'] - excludetests = [x[:-1] for x in excludetests] - excludetests = [x.strip() for x in excludetests] - excludetests = [x for x in excludetests if x] # ---[ test processing ]----------------------------------- -tests = [t for t in tests if t not in excludetests] tests = [Test(t, n + 1) for n, t in enumerate(tests)] if list_only: @@ -697,10 +688,9 @@ def log_result(t, io_lock=None): we need to lock access to the log to avoid interleaving. The same would apply if output was a file. - :param t: a completed testcase - :type t: Test - :param io_lock: - :type io_lock: threading.Lock + Args: + t (Test): (completed) testcase instance + io_lock (threading.lock): (optional) lock to use """ # there is no lock in single-job run, which includes @@ -727,6 +717,18 @@ def log_result(t, io_lock=None): def run_test(t, io_lock=None, run_async=True): + """ Run a testcase. + + Builds the command line to give to execute(). + Also the best place to record some information that will be + used in output, which in some conditions is printed here. + + Args: + t (Test): testcase instance + io_lock (threading.Lock): (optional) lock to use + run_async (bool): whether to run asynchronously + """ + t.headline = "" command_args = [] if debug: @@ -738,7 +740,7 @@ def run_test(t, io_lock=None, run_async=True): # For example --runner TestUnit.TAPTestRunner command_args.append('--runner ' + options.runner) t.command_args = [escape(python)] + command_args - t.command_str = " ".join([escape(python)] + command_args) + t.command_str = " ".join(t.command_args) if printcommand: if print_progress: t.headline += "%d/%d (%.2f%s) %s\n" % ( @@ -753,16 +755,21 @@ def run_test(t, io_lock=None, run_async=True): if not suppress_output and not catch_output: # defer printing the headline until test is done sys.stdout.write(t.headline) - head, tail = os.path.split(t.abspath) + head, _ = os.path.split(t.abspath) fixture_dirs = [] if head: fixture_dirs.append(head) fixture_dirs.append(os.path.join(scriptpath, 'test', 'fixture')) - os.environ['FIXTURE_DIRS'] = os.pathsep.join(fixture_dirs) + + # Set the list of fixture dirs directly in the environment. Just putting + # it in os.environ and spawning the process is racy. Make it reliable by + # overriding the environment passed to execute(). + env = dict(os.environ) + env['FIXTURE_DIRS'] = os.pathsep.join(fixture_dirs) test_start_time = time_func() if execute_tests: - t.execute() + t.execute(env) t.test_time = time_func() - test_start_time log_result(t, io_lock=io_lock) @@ -775,7 +782,7 @@ class RunTest(threading.Thread): """ def __init__(self, queue=None, io_lock=None, group=None, target=None, name=None, args=(), kwargs=None): - super(RunTest, self).__init__(group=group, target=target, name=name) + super().__init__(group=group, target=target, name=name) self.queue = queue self.io_lock = io_lock @@ -856,6 +863,7 @@ if options.output: if fail: sys.exit(1) elif no_result: + # if no fails, but skips were found sys.exit(2) else: sys.exit(0) @@ -28,6 +28,7 @@ classifiers = Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Environment :: Console Intended Audience :: Developers License :: OSI Approved :: MIT License @@ -42,7 +43,6 @@ zip_safe = False python_requires = >=3.5 install_requires = setuptools - pywin32 >= 1.0;platform_system=="Windows" setup_requires = setuptools include_package_data = True @@ -61,13 +61,20 @@ console_scripts = [options.package_data] -* = *.txt, *.rst +* = *.txt, *.rst, *.1 SCons.Tool.docbook = *.* + +[options.data_files] +. = build/doc/man/scons.1 + build/doc/man/scons-time.1 + build/doc/man/sconsign.1 + [sdist] dist-dir=build/dist [bdist_wheel] ; We're now py3 only ;universal=true -dist-dir=build/dist
\ No newline at end of file +dist-dir=build/dist + @@ -7,11 +7,13 @@ from setuptools.command.build_py import build_py as build_py_orig import codecs import os.path + def read(rel_path): here = os.path.abspath(os.path.dirname(__file__)) with codecs.open(os.path.join(here, rel_path), 'r') as fp: return fp.read() + def get_version(rel_path): for line in read(rel_path).splitlines(): if line.startswith('__version__'): @@ -21,7 +23,6 @@ def get_version(rel_path): raise RuntimeError("Unable to find version string.") - exclude = ['*Tests'] diff --git a/site_scons/scons_local_package.py b/site_scons/scons_local_package.py index 5e633e9..aaf058a 100644 --- a/site_scons/scons_local_package.py +++ b/site_scons/scons_local_package.py @@ -1,4 +1,6 @@ -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -60,6 +62,12 @@ def install_local_package_files(env): fn = os.path.basename(bf) all_local_installed.append(env.SCons_revision('#/build/scons-local/%s'%fn, bf)) + # Now copy manpages into scons-local package + built_manpage_files = env.Glob('build/doc/man/*.1') + for bmp in built_manpage_files: + fn = os.path.basename(str(bmp)) + all_local_installed.append(env.SCons_revision('#/build/scons-local/%s'%fn, bmp)) + rename_files = [('scons-${VERSION}.bat', 'scripts/scons.bat'), ('scons-README', 'README-local'), ('scons-LICENSE', 'LICENSE-local')] diff --git a/site_scons/update_build_info.py b/site_scons/update_build_info.py index b9d565a..59ddf0c 100644 --- a/site_scons/update_build_info.py +++ b/site_scons/update_build_info.py @@ -14,3 +14,4 @@ def update_init_file(env): 'import SCons.compat # noqa'], ) env.Precious(si) + env.NoClean(si) # Don't clean this file as it breaks the build. diff --git a/test/AR/AR.py b/test/AR/AR.py index 552b827..2b92ff4 100644 --- a/test/AR/AR.py +++ b/test/AR/AR.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/AR/ARFLAGS.py b/test/AR/ARFLAGS.py index 2aa1a14..21b3793 100644 --- a/test/AR/ARFLAGS.py +++ b/test/AR/ARFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/AS/AS.py b/test/AS/AS.py index 56a1498..0b6611d 100644 --- a/test/AS/AS.py +++ b/test/AS/AS.py @@ -29,8 +29,6 @@ Verify the ability to set the $AS construction variable to a different assembler (a wrapper we create). """ -import os -import sys import TestSCons diff --git a/test/AS/ASFLAGS.py b/test/AS/ASFLAGS.py index 52f44af..4a1c162 100644 --- a/test/AS/ASFLAGS.py +++ b/test/AS/ASFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/AS/ASPP.py b/test/AS/ASPP.py index 64e1080..9c8f047 100644 --- a/test/AS/ASPP.py +++ b/test/AS/ASPP.py @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import sys import TestSCons diff --git a/test/AS/ASPPFLAGS.py b/test/AS/ASPPFLAGS.py index 5dd9a38..f7d7c5c 100644 --- a/test/AS/ASPPFLAGS.py +++ b/test/AS/ASPPFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/Actions/append.py b/test/Actions/append.py index 0a59c42..b5d4c3a 100644 --- a/test/Actions/append.py +++ b/test/Actions/append.py @@ -30,7 +30,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import stat -import sys import TestSCons _exe = TestSCons._exe diff --git a/test/Actions/pre-post.py b/test/Actions/pre-post.py index 4d22b07..358aa43 100644 --- a/test/Actions/pre-post.py +++ b/test/Actions/pre-post.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import stat import TestSCons diff --git a/test/AddOption/longopts.py b/test/AddOption/longopts.py index 47ae4f1..48c3502 100644 --- a/test/AddOption/longopts.py +++ b/test/AddOption/longopts.py @@ -51,6 +51,16 @@ test.run('-Q -q . --myargument=helloworld', test.run('-Q -q . --myarg=helloworld', stdout="myargument: gully\nmyarg: helloworld\n") +# Issue #3653: add a check for an abbreviation which never gets AddOption'd. +test.run('-Q -q . --myargumen=helloworld', status=2, + stdout="myargument: gully\nmyarg: balla\n", + stderr="""\ +usage: scons [OPTION] [TARGET] ... + +SCons Error: no such option: '--myargumen'. Did you mean '--myargument'? +""") + + test.pass_test() # Local Variables: diff --git a/test/Builder/errors.py b/test/Builder/errors.py index bd7e100..375e052 100644 --- a/test/Builder/errors.py +++ b/test/Builder/errors.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test the ability to catch Builder creation with poorly specified Actions. """ -import os.path import TestSCons diff --git a/test/CC/CCVERSION.py b/test/CC/CCVERSION.py index 7e829f0..3ee601f 100644 --- a/test/CC/CCVERSION.py +++ b/test/CC/CCVERSION.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/CC/SHCC.py b/test/CC/SHCC.py index c756219..1c9f68d 100644 --- a/test/CC/SHCC.py +++ b/test/CC/SHCC.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/CFILESUFFIX.py b/test/CFILESUFFIX.py index 7af4fa4..0a62307 100644 --- a/test/CFILESUFFIX.py +++ b/test/CFILESUFFIX.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that we can set CFILESUFFIX to arbitrary values. """ -import os import TestSCons diff --git a/test/CXX/CXX.py b/test/CXX/CXX.py index abccf1e..4be4199 100644 --- a/test/CXX/CXX.py +++ b/test/CXX/CXX.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/CXX/CXXFILESUFFIX.py b/test/CXX/CXXFILESUFFIX.py index 48d727e..0ae5827 100644 --- a/test/CXX/CXXFILESUFFIX.py +++ b/test/CXX/CXXFILESUFFIX.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/CacheDir/CacheDir_TryCompile.py b/test/CacheDir/CacheDir_TryCompile.py index bb22835..dbea9be 100644 --- a/test/CacheDir/CacheDir_TryCompile.py +++ b/test/CacheDir/CacheDir_TryCompile.py @@ -32,7 +32,6 @@ could be bytes instead of a string which would fail when combining cache signatu which ended up a mixture of bytes and strings. """ -import os import TestSCons diff --git a/test/CacheDir/NoCache.py b/test/CacheDir/NoCache.py index 8ecfeb3..506a859 100644 --- a/test/CacheDir/NoCache.py +++ b/test/CacheDir/NoCache.py @@ -28,7 +28,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that the NoCache environment method works. """ -import TestSCons, os.path +import TestSCons test = TestSCons.TestSCons() diff --git a/test/CacheDir/multiple-targets.py b/test/CacheDir/multiple-targets.py index 99ab8da..d985ca0 100644 --- a/test/CacheDir/multiple-targets.py +++ b/test/CacheDir/multiple-targets.py @@ -28,8 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test that multiple target files get retrieved from a CacheDir correctly. """ -import os.path -import shutil import TestSCons diff --git a/test/CacheDir/option--cd.py b/test/CacheDir/option--cd.py index 1620858..3ea739c 100644 --- a/test/CacheDir/option--cd.py +++ b/test/CacheDir/option--cd.py @@ -29,8 +29,6 @@ Test the --cache-disable option when retrieving derived files from a CacheDir. """ -import os.path -import shutil import TestSCons diff --git a/test/CacheDir/option--cr.py b/test/CacheDir/option--cr.py index b7696c5..0395876 100644 --- a/test/CacheDir/option--cr.py +++ b/test/CacheDir/option--cr.py @@ -29,8 +29,6 @@ Test the --cache-readonly option when retrieving derived files from a CacheDir. It should retrieve as normal but not update files. """ -import os.path -import shutil import TestSCons diff --git a/test/CacheDir/option--cs.py b/test/CacheDir/option--cs.py index feb89bd..a2b09ed 100644 --- a/test/CacheDir/option--cs.py +++ b/test/CacheDir/option--cs.py @@ -29,8 +29,6 @@ Test printing build actions when using the --cache-show option and retrieving derived files from a CacheDir. """ -import os.path -import shutil import TestSCons diff --git a/test/CacheDir/readonly-cache.py b/test/CacheDir/readonly-cache.py index 63cfd22..4aad0ee 100755 --- a/test/CacheDir/readonly-cache.py +++ b/test/CacheDir/readonly-cache.py @@ -32,7 +32,6 @@ import glob import os import TestSCons import time -from stat import * test = TestSCons.TestSCons() diff --git a/test/CacheDir/scanner-target.py b/test/CacheDir/scanner-target.py index 249e587..202910b 100644 --- a/test/CacheDir/scanner-target.py +++ b/test/CacheDir/scanner-target.py @@ -31,8 +31,6 @@ to push the file to the CacheDir after the build signature had already been cleared (as a sign that the built file should now be rescanned). """ -import os.path -import shutil import TestSCons diff --git a/test/Clean/Option.py b/test/Clean/Option.py index 5795ff2..c63dff7 100644 --- a/test/Clean/Option.py +++ b/test/Clean/Option.py @@ -29,7 +29,6 @@ Verify that {Set,Get}Option('clean') works correctly to control cleaning behavior. """ -import os import TestSCons diff --git a/test/CommandGenerator.py b/test/CommandGenerator.py index b8155e7..5cae4a6 100644 --- a/test/CommandGenerator.py +++ b/test/CommandGenerator.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/Configure/VariantDir2.py b/test/Configure/VariantDir2.py index ffe6525..98f4ccd 100644 --- a/test/Configure/VariantDir2.py +++ b/test/Configure/VariantDir2.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that Configure contexts work with SConstruct/SConscript structure """ -import os import TestSCons diff --git a/test/Configure/config-h.py b/test/Configure/config-h.py index 0331b24..f617d92 100644 --- a/test/Configure/config-h.py +++ b/test/Configure/config-h.py @@ -27,7 +27,6 @@ Verify creation of a config.h file from a Configure context. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import re import TestSCons diff --git a/test/Copy-Symlinks.py b/test/Copy-Symlinks.py index eab38e3..d2f5f4b 100644 --- a/test/Copy-Symlinks.py +++ b/test/Copy-Symlinks.py @@ -29,8 +29,6 @@ Verify that the Copy() Action symlink soft-copy support works. """ import os -import stat -import sys import TestSCons import SCons.Defaults diff --git a/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py b/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py index b58227d..66d84c8 100644 --- a/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py +++ b/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py @@ -30,7 +30,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -from os.path import abspath, dirname, join +from os.path import abspath, dirname import sys sys.path.insert(1, abspath(dirname(__file__) + '/../../../Support')) diff --git a/test/D/MixedDAndC/Common/common.py b/test/D/MixedDAndC/Common/common.py index 852e2e2..2de1304 100644 --- a/test/D/MixedDAndC/Common/common.py +++ b/test/D/MixedDAndC/Common/common.py @@ -30,7 +30,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons from os.path import abspath, dirname -from platform import architecture import sys sys.path.insert(1, abspath(dirname(__file__) + '/../../Support')) diff --git a/test/DVIPDF/DVIPDFFLAGS.py b/test/DVIPDF/DVIPDFFLAGS.py index 9ecb736..9900cf7 100644 --- a/test/DVIPDF/DVIPDFFLAGS.py +++ b/test/DVIPDF/DVIPDFFLAGS.py @@ -122,7 +122,7 @@ subprocess.run(cmd, shell=True) test.write('SConstruct', """ import os ENV = {'PATH' : os.environ['PATH']} -foo = Environment(DVIPDFFLAGS = '-N', ENV = ENV) +foo = Environment(DVIPDFFLAGS = '-R2', ENV = ENV) dvipdf = foo.Dictionary('DVIPDF') bar = Environment(DVIPDF = r'%(_python_)s wrapper.py ' + dvipdf, ENV = ENV) foo.PDF(target = 'foo.pdf', diff --git a/test/Decider/MD5-winonly-firstbuild.py b/test/Decider/MD5-winonly-firstbuild.py index 87f7999..beabce3 100644 --- a/test/Decider/MD5-winonly-firstbuild.py +++ b/test/Decider/MD5-winonly-firstbuild.py @@ -29,8 +29,6 @@ Test but which only shows on windows when one generated file depends on another In this case flex and yacc are an example. """ -import os -import stat import TestSCons from TestCmd import IS_WINDOWS diff --git a/test/Dir/PyPackageDir/PyPackageDir.py b/test/Dir/PyPackageDir/PyPackageDir.py index b215c7b..beb256b 100644 --- a/test/Dir/PyPackageDir/PyPackageDir.py +++ b/test/Dir/PyPackageDir/PyPackageDir.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import os.path
import TestSCons
test = TestSCons.TestSCons()
diff --git a/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py b/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py index 3ad6369..e603232 100644 --- a/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py +++ b/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py @@ -28,7 +28,6 @@ the xsltproc executable, if it exists. """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py b/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py index 2b004c6..ebefb92 100644 --- a/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py +++ b/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py @@ -28,7 +28,6 @@ the xsltproc executable, if it exists. """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/Docbook/basedir/slideshtml/slideshtml_cmd.py b/test/Docbook/basedir/slideshtml/slideshtml_cmd.py index 901d94e..b0f1f25 100644 --- a/test/Docbook/basedir/slideshtml/slideshtml_cmd.py +++ b/test/Docbook/basedir/slideshtml/slideshtml_cmd.py @@ -28,7 +28,6 @@ the xsltproc executable, if it exists. """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py b/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py index 6b79102..9715c0f 100644 --- a/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py +++ b/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py @@ -27,7 +27,6 @@ Test the chunked HTML builder while using the xsltproc executable, if it exists. """ -import os import TestSCons test = TestSCons.TestSCons() diff --git a/test/Docbook/basic/slideshtml/slideshtml_cmd.py b/test/Docbook/basic/slideshtml/slideshtml_cmd.py index 7ebc8d4..9c8097b 100644 --- a/test/Docbook/basic/slideshtml/slideshtml_cmd.py +++ b/test/Docbook/basic/slideshtml/slideshtml_cmd.py @@ -28,7 +28,6 @@ the xsltproc executable, if it exists. """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/Errors/execute-a-directory.py b/test/Errors/execute-a-directory.py index 8b6d13b..ff50620 100644 --- a/test/Errors/execute-a-directory.py +++ b/test/Errors/execute-a-directory.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import TestSCons diff --git a/test/Errors/non-executable-file.py b/test/Errors/non-executable-file.py index 64c75c6..98d4721 100644 --- a/test/Errors/non-executable-file.py +++ b/test/Errors/non-executable-file.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import TestSCons diff --git a/test/Fortran/F03.py b/test/Fortran/F03.py index 989d878..ce56cc3 100644 --- a/test/Fortran/F03.py +++ b/test/Fortran/F03.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F03FILESUFFIXES.py b/test/Fortran/F03FILESUFFIXES.py index 5620a2d..49c9c66 100644 --- a/test/Fortran/F03FILESUFFIXES.py +++ b/test/Fortran/F03FILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F03FILESUFFIXES2.py b/test/Fortran/F03FILESUFFIXES2.py index 6073aab..6512341 100644 --- a/test/Fortran/F03FILESUFFIXES2.py +++ b/test/Fortran/F03FILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F03FLAGS.py b/test/Fortran/F03FLAGS.py index 54b8083..63d1fcb 100644 --- a/test/Fortran/F03FLAGS.py +++ b/test/Fortran/F03FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F08.py b/test/Fortran/F08.py index f60509c..eb381ee 100644 --- a/test/Fortran/F08.py +++ b/test/Fortran/F08.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F08FILESUFFIXES.py b/test/Fortran/F08FILESUFFIXES.py index 989d685..392ff64 100644 --- a/test/Fortran/F08FILESUFFIXES.py +++ b/test/Fortran/F08FILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F08FILESUFFIXES2.py b/test/Fortran/F08FILESUFFIXES2.py index 0d99225..babb8e6 100644 --- a/test/Fortran/F08FILESUFFIXES2.py +++ b/test/Fortran/F08FILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F08FLAGS.py b/test/Fortran/F08FLAGS.py index 015fb0b..81ae441 100644 --- a/test/Fortran/F08FLAGS.py +++ b/test/Fortran/F08FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F77.py b/test/Fortran/F77.py index ed5d33f..c43fb3e 100644 --- a/test/Fortran/F77.py +++ b/test/Fortran/F77.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F77FILESUFFIXES.py b/test/Fortran/F77FILESUFFIXES.py index c289e10..8c7aec8 100644 --- a/test/Fortran/F77FILESUFFIXES.py +++ b/test/Fortran/F77FILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F77FILESUFFIXES2.py b/test/Fortran/F77FILESUFFIXES2.py index 1f26012..86cd931 100644 --- a/test/Fortran/F77FILESUFFIXES2.py +++ b/test/Fortran/F77FILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F77FLAGS.py b/test/Fortran/F77FLAGS.py index caf291d..01bf33b 100644 --- a/test/Fortran/F77FLAGS.py +++ b/test/Fortran/F77FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F90.py b/test/Fortran/F90.py index d76af07..404f883 100644 --- a/test/Fortran/F90.py +++ b/test/Fortran/F90.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F90FILESUFFIXES.py b/test/Fortran/F90FILESUFFIXES.py index d91c4c8..e376f3c 100644 --- a/test/Fortran/F90FILESUFFIXES.py +++ b/test/Fortran/F90FILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F90FILESUFFIXES2.py b/test/Fortran/F90FILESUFFIXES2.py index 3efc52c..e01425f 100644 --- a/test/Fortran/F90FILESUFFIXES2.py +++ b/test/Fortran/F90FILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F90FLAGS.py b/test/Fortran/F90FLAGS.py index f748e5d..5a469e9 100644 --- a/test/Fortran/F90FLAGS.py +++ b/test/Fortran/F90FLAGS.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F95.py b/test/Fortran/F95.py index 8e6d0b9..7b4c97a 100644 --- a/test/Fortran/F95.py +++ b/test/Fortran/F95.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F95FILESUFFIXES.py b/test/Fortran/F95FILESUFFIXES.py index 427c881..710f838 100644 --- a/test/Fortran/F95FILESUFFIXES.py +++ b/test/Fortran/F95FILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F95FILESUFFIXES2.py b/test/Fortran/F95FILESUFFIXES2.py index a0ee1cf..2f8bb17 100644 --- a/test/Fortran/F95FILESUFFIXES2.py +++ b/test/Fortran/F95FILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/F95FLAGS.py b/test/Fortran/F95FLAGS.py index 203aee1..2853cc9 100644 --- a/test/Fortran/F95FLAGS.py +++ b/test/Fortran/F95FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/FORTRAN.py b/test/Fortran/FORTRAN.py index 721d48f..62d7065 100644 --- a/test/Fortran/FORTRAN.py +++ b/test/Fortran/FORTRAN.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/FORTRANFILESUFFIXES.py b/test/Fortran/FORTRANFILESUFFIXES.py index ec659a1..e58b971 100644 --- a/test/Fortran/FORTRANFILESUFFIXES.py +++ b/test/Fortran/FORTRANFILESUFFIXES.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/FORTRANFILESUFFIXES2.py b/test/Fortran/FORTRANFILESUFFIXES2.py index 6dda07d..a57dd2a 100644 --- a/test/Fortran/FORTRANFILESUFFIXES2.py +++ b/test/Fortran/FORTRANFILESUFFIXES2.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/FORTRANFLAGS.py b/test/Fortran/FORTRANFLAGS.py index 316f67c..218c95f 100644 --- a/test/Fortran/FORTRANFLAGS.py +++ b/test/Fortran/FORTRANFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/FORTRANPPFILESUFFIXES.py b/test/Fortran/FORTRANPPFILESUFFIXES.py index 6b3b3d8..2c10b10 100644 --- a/test/Fortran/FORTRANPPFILESUFFIXES.py +++ b/test/Fortran/FORTRANPPFILESUFFIXES.py @@ -25,9 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import string -import sys import TestSCons diff --git a/test/Fortran/SHF03.py b/test/Fortran/SHF03.py index 0ab2cc9..1c3fb1b 100644 --- a/test/Fortran/SHF03.py +++ b/test/Fortran/SHF03.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF08.py b/test/Fortran/SHF08.py index 8147b79..49a4c47 100644 --- a/test/Fortran/SHF08.py +++ b/test/Fortran/SHF08.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF77.py b/test/Fortran/SHF77.py index 1b0e180..4358533 100644 --- a/test/Fortran/SHF77.py +++ b/test/Fortran/SHF77.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF77FLAGS.py b/test/Fortran/SHF77FLAGS.py index 19d40b6..3a7e6b2 100644 --- a/test/Fortran/SHF77FLAGS.py +++ b/test/Fortran/SHF77FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF90.py b/test/Fortran/SHF90.py index 1524bf3..057f98c 100644 --- a/test/Fortran/SHF90.py +++ b/test/Fortran/SHF90.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF90FLAGS.py b/test/Fortran/SHF90FLAGS.py index 947bf4b..900acbc 100644 --- a/test/Fortran/SHF90FLAGS.py +++ b/test/Fortran/SHF90FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF95.py b/test/Fortran/SHF95.py index 27d9a76..3b1f4fb 100644 --- a/test/Fortran/SHF95.py +++ b/test/Fortran/SHF95.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHF95FLAGS.py b/test/Fortran/SHF95FLAGS.py index d1fbe3f..56744d6 100644 --- a/test/Fortran/SHF95FLAGS.py +++ b/test/Fortran/SHF95FLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHFORTRAN.py b/test/Fortran/SHFORTRAN.py index f4850d7..a8806e7 100644 --- a/test/Fortran/SHFORTRAN.py +++ b/test/Fortran/SHFORTRAN.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Fortran/SHFORTRANFLAGS.py b/test/Fortran/SHFORTRANFLAGS.py index ac2abd8..6a4692b 100644 --- a/test/Fortran/SHFORTRANFLAGS.py +++ b/test/Fortran/SHFORTRANFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff --git a/test/Install/directories.py b/test/Install/directories.py index 3ebc713..e980936 100644 --- a/test/Install/directories.py +++ b/test/Install/directories.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test using Install() on directories. """ -import os.path import TestSCons diff --git a/test/Install/non-ascii-name.py b/test/Install/non-ascii-name.py index 462040d..7e25743 100644 --- a/test/Install/non-ascii-name.py +++ b/test/Install/non-ascii-name.py @@ -29,7 +29,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that the Install() Builder works """ -import os.path import TestSCons diff --git a/test/Java/JAR.py b/test/Java/JAR.py index d5425af..2cd6012 100644 --- a/test/Java/JAR.py +++ b/test/Java/JAR.py @@ -26,7 +26,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import TestSCons -import sys _python_ = TestSCons._python_ diff --git a/test/Java/JARCHDIR.py b/test/Java/JARCHDIR.py index 59bf082..24a8597 100644 --- a/test/Java/JARCHDIR.py +++ b/test/Java/JARCHDIR.py @@ -33,7 +33,6 @@ Includes logic to make sure that expansions of $JARCHDIR that include ${TARGET} or ${SOURCE} work. """ -import os import TestSCons diff --git a/test/Java/JARFLAGS.py b/test/Java/JARFLAGS.py index 6983bf7..fc6e55e 100644 --- a/test/Java/JARFLAGS.py +++ b/test/Java/JARFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/Java/jar_not_in_PATH.py b/test/Java/jar_not_in_PATH.py index 9a716c5..d69f9c3 100644 --- a/test/Java/jar_not_in_PATH.py +++ b/test/Java/jar_not_in_PATH.py @@ -29,7 +29,6 @@ Ensures that the Tool gets initialized, even when jar is not directly found via the PATH variable (issue #2730). """ -import os import TestSCons diff --git a/test/Java/nested-classes.py b/test/Java/nested-classes.py index a764054..0208eb6 100644 --- a/test/Java/nested-classes.py +++ b/test/Java/nested-classes.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test Java compilation with inner and anonymous classes (Issue 2087). """ -import os import TestSCons diff --git a/test/Java/swig-dependencies.py b/test/Java/swig-dependencies.py index a3af9ec..c1821f8 100644 --- a/test/Java/swig-dependencies.py +++ b/test/Java/swig-dependencies.py @@ -143,7 +143,6 @@ except: # the test framework test.skip_test('Throwing no result for this test because of bug ' + 'related here: https://github.com/SCons/scons/issues/2907\n') - pass #test.must_exist(['java', 'classes', 'foopack', 'foopack.class']) #test.must_exist(['java', 'classes', 'foopack', 'foopackJNI.class']) test.must_exist(['java', 'classes', 'foopack.class']) diff --git a/test/LEX/LEX.py b/test/LEX/LEX.py index a739bfe..79d8359 100644 --- a/test/LEX/LEX.py +++ b/test/LEX/LEX.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/LEX/LEXFLAGS.py b/test/LEX/LEXFLAGS.py index 994834e..2cebca7 100644 --- a/test/LEX/LEXFLAGS.py +++ b/test/LEX/LEXFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/LINK/LDMODULEVERSIONFLAGS.py b/test/LINK/LDMODULEVERSIONFLAGS.py index d8f280a..509bde8 100644 --- a/test/LINK/LDMODULEVERSIONFLAGS.py +++ b/test/LINK/LDMODULEVERSIONFLAGS.py @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import re import TestSCons import SCons.Platform diff --git a/test/LINK/LINK.py b/test/LINK/LINK.py index 6c99134..f278ac0 100644 --- a/test/LINK/LINK.py +++ b/test/LINK/LINK.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/LINK/LINKFLAGS.py b/test/LINK/LINKFLAGS.py index 749e369..d3b675e 100644 --- a/test/LINK/LINKFLAGS.py +++ b/test/LINK/LINKFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/LINK/SHLIBVERSIONFLAGS.py b/test/LINK/SHLIBVERSIONFLAGS.py index 6cf7290..d2e271c 100644 --- a/test/LINK/SHLIBVERSIONFLAGS.py +++ b/test/LINK/SHLIBVERSIONFLAGS.py @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import re import TestSCons import SCons.Platform diff --git a/test/LINK/SHLINK.py b/test/LINK/SHLINK.py index 9d406fc..26d88fa 100644 --- a/test/LINK/SHLINK.py +++ b/test/LINK/SHLINK.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/LINK/SHLINKFLAGS.py b/test/LINK/SHLINKFLAGS.py index af5bdbb..a4ae652 100644 --- a/test/LINK/SHLINKFLAGS.py +++ b/test/LINK/SHLINKFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 104f696..5f74f92 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import TestSCons import SCons.Platform diff --git a/test/Libs/SharedLibrary-update-deps.py b/test/Libs/SharedLibrary-update-deps.py index 3abce83..922d580 100644 --- a/test/Libs/SharedLibrary-update-deps.py +++ b/test/Libs/SharedLibrary-update-deps.py @@ -30,7 +30,6 @@ This is https://github.com/SCons/scons/issues/2903 """ import sys -import os.path import TestSCons test = TestSCons.TestSCons() diff --git a/test/MSVC/MSVC_UWP_APP.py b/test/MSVC/MSVC_UWP_APP.py index 0f33dda..4bb2f5c 100644 --- a/test/MSVC/MSVC_UWP_APP.py +++ b/test/MSVC/MSVC_UWP_APP.py @@ -82,7 +82,7 @@ test = TestSCons.TestSCons() test.skip_if_not_msvc() -installed_msvc_versions = msvc.cached_get_installed_vcs() +installed_msvc_versions = msvc.get_installed_vcs() # MSVC guaranteed to be at least one version on the system or else # skip_if_not_msvc() function would have skipped the test diff --git a/test/MSVC/PCHSTOP-errors.py b/test/MSVC/PCHSTOP-errors.py index aa14a3f..a359135 100644 --- a/test/MSVC/PCHSTOP-errors.py +++ b/test/MSVC/PCHSTOP-errors.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" # Test error reporting """ -import re import TestSCons diff --git a/test/MSVC/mssdk.py b/test/MSVC/mssdk.py index 9890d48..88dd5d1 100644 --- a/test/MSVC/mssdk.py +++ b/test/MSVC/mssdk.py @@ -27,7 +27,6 @@ Simple test to make sure mssdk works. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import time import TestSCons diff --git a/test/MSVC/pch-basics.py b/test/MSVC/pch-basics.py index ebee0da..e2b40f1 100644 --- a/test/MSVC/pch-basics.py +++ b/test/MSVC/pch-basics.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify PCH works to build a simple exe and a simple dll. """ -import time import TestSCons diff --git a/test/MSVC/pch-spaces-subdir.py b/test/MSVC/pch-spaces-subdir.py index 65595fc..f00fac1 100644 --- a/test/MSVC/pch-spaces-subdir.py +++ b/test/MSVC/pch-spaces-subdir.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify PCH works if variant dir has spaces in its name """ -import time import TestSCons diff --git a/test/MSVS/common-prefix.py b/test/MSVS/common-prefix.py index 7079661..7bba783 100644 --- a/test/MSVS/common-prefix.py +++ b/test/MSVS/common-prefix.py @@ -30,7 +30,6 @@ Test that we can generate Visual Studio 8.0 project (.vcproj) and solution (.sln) files that look correct. """ -import os import sys import TestSConsMSVS diff --git a/test/MSVS/runfile.py b/test/MSVS/runfile.py index 631c919..1cc4720 100644 --- a/test/MSVS/runfile.py +++ b/test/MSVS/runfile.py @@ -30,7 +30,6 @@ Test that we can generate Visual Studio 8.0 project (.vcproj) and solution (.sln) files that look correct. """ -import os import sys import TestSConsMSVS diff --git a/test/MSVS/vs-6.0-exec.py b/test/MSVS/vs-6.0-exec.py index ab70872..40f69c0 100644 --- a/test/MSVS/vs-6.0-exec.py +++ b/test/MSVS/vs-6.0-exec.py @@ -29,7 +29,6 @@ Test that we can actually build a simple program using our generated Visual Studio 6 project (.dsp) and solution (.dsw) files. """ -import os import sys import TestSConsMSVS diff --git a/test/MSVS/vs-7.0-exec.py b/test/MSVS/vs-7.0-exec.py index 3c41aa5..a6235a7 100644 --- a/test/MSVS/vs-7.0-exec.py +++ b/test/MSVS/vs-7.0-exec.py @@ -29,7 +29,6 @@ Test that we can actually build a simple program using our generated Visual Studio 7.0 project (.vcproj) and solution (.sln) files. """ -import os import sys import TestSConsMSVS diff --git a/test/MSVS/vs-7.0-scc-files.py b/test/MSVS/vs-7.0-scc-files.py index 4d90a92..f1f77db 100644 --- a/test/MSVS/vs-7.0-scc-files.py +++ b/test/MSVS/vs-7.0-scc-files.py @@ -29,7 +29,6 @@ Test that we can generate Visual Studio 7.0 project (.vcproj) and solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff --git a/test/MSVS/vs-7.0-scc-legacy-files.py b/test/MSVS/vs-7.0-scc-legacy-files.py index e87441b..a180b8a 100644 --- a/test/MSVS/vs-7.0-scc-legacy-files.py +++ b/test/MSVS/vs-7.0-scc-legacy-files.py @@ -29,7 +29,6 @@ Test that we can generate Visual Studio 7.0 project (.vcproj) and solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff --git a/test/MSVS/vs-7.1-exec.py b/test/MSVS/vs-7.1-exec.py index f66b92d..7bb3055 100644 --- a/test/MSVS/vs-7.1-exec.py +++ b/test/MSVS/vs-7.1-exec.py @@ -29,7 +29,6 @@ Test that we can actually build a simple program using our generated Visual Studio 7.1 project (.vcproj) and solution (.sln) files """ -import os import sys import TestSConsMSVS diff --git a/test/MSVS/vs-7.1-scc-files.py b/test/MSVS/vs-7.1-scc-files.py index 8404422..0b42930 100644 --- a/test/MSVS/vs-7.1-scc-files.py +++ b/test/MSVS/vs-7.1-scc-files.py @@ -29,7 +29,6 @@ Test that we can generate Visual Studio 7.1 project (.vcproj) and solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff --git a/test/MSVS/vs-7.1-scc-legacy-files.py b/test/MSVS/vs-7.1-scc-legacy-files.py index f80c965..bb184d6 100644 --- a/test/MSVS/vs-7.1-scc-legacy-files.py +++ b/test/MSVS/vs-7.1-scc-legacy-files.py @@ -29,7 +29,6 @@ Test that we can generate Visual Studio 7.1 project (.vcproj) and solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff --git a/test/MinGW/mingw_uses_comstr_issue_2799.py b/test/MinGW/mingw_uses_comstr_issue_2799.py index cc92446..fc96ad4 100644 --- a/test/MinGW/mingw_uses_comstr_issue_2799.py +++ b/test/MinGW/mingw_uses_comstr_issue_2799.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test that mingw respects SHLINKCOMSTR, SHCCCOMSTR, and LDMODULECOMSTR """ -import sys import TestSCons _python_ = TestSCons._python_ diff --git a/test/Progress/TARGET.py b/test/Progress/TARGET.py index bbe2538..9535390 100644 --- a/test/Progress/TARGET.py +++ b/test/Progress/TARGET.py @@ -29,7 +29,6 @@ Verify substition of the $TARGET string in progress output, including overwriting it by setting the overwrite= keyword argument. """ -import os import TestSCons diff --git a/test/Progress/spinner.py b/test/Progress/spinner.py index ff88841..f9be6e9 100644 --- a/test/Progress/spinner.py +++ b/test/Progress/spinner.py @@ -29,7 +29,6 @@ Verify output when a Progress() call is initialized with the list that represents a canonical "spinner" on the output. """ -import os import TestSCons diff --git a/test/Repository/Install.py b/test/Repository/Install.py index 75052e7..9c1259a 100644 --- a/test/Repository/Install.py +++ b/test/Repository/Install.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/Repository/InstallAs.py b/test/Repository/InstallAs.py index d717254..c153771 100644 --- a/test/Repository/InstallAs.py +++ b/test/Repository/InstallAs.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/Repository/M4.py b/test/Repository/M4.py index 8fa91ab..2e40468 100644 --- a/test/Repository/M4.py +++ b/test/Repository/M4.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test that $M4 and $M4FLAGS work with repositories. """ -import os import TestSCons diff --git a/test/SConscript/fixture/SConstruct b/test/SConscript/fixture/SConstruct new file mode 100644 index 0000000..a955efc --- /dev/null +++ b/test/SConscript/fixture/SConstruct @@ -0,0 +1,17 @@ +import SCons +from SCons.Warnings import _warningOut +import sys + +DefaultEnvironment(tools=[]) +# 1. call should succeed without deprecation warning +try: + SConscript('missing/SConscript', must_exist=False) +except SCons.Errors.UserError as e: + if _warningOut: + _warningOut(e) +# 2. call should succeed with deprecation warning +try: + SConscript('missing/SConscript') +except SCons.Errors.UserError as e: + if _warningOut: + _warningOut(e) diff --git a/test/SConscript/must_exist_deprecation.py b/test/SConscript/must_exist_deprecation.py new file mode 100644 index 0000000..8b267ce --- /dev/null +++ b/test/SConscript/must_exist_deprecation.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# __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__" + +''' +Test deprecation warning if must_exist flag is used in a SConscript call +''' + +import os +import TestSCons + +test = TestSCons.TestSCons() + +# catch the exception if is raised, send it on as a warning +# this gives us traceability of the line responsible +SConstruct_path = test.workpath('SConstruct') +test.file_fixture("fixture/SConstruct") + +# we should see two warnings, the second being the deprecation message. +# need to build the path in the expected msg in an OS-agnostic way +missing = os.path.normpath('missing/SConscript') +warn1 = """ +scons: warning: Ignoring missing SConscript '{}' +""".format(missing) + test.python_file_line(SConstruct_path, 8) +warn2 = """ +scons: warning: Calling missing SConscript without error is deprecated. +Transition by adding must_exist=0 to SConscript calls. +Missing SConscript '{}' +""".format(missing) + test.python_file_line(SConstruct_path, 14) + +expect_stderr = warn1 + warn2 +test.run(arguments = ".", stderr = expect_stderr) +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/SConsignFile/default.py b/test/SConsignFile/default.py index 62ac006..ed1ed56 100644 --- a/test/SConsignFile/default.py +++ b/test/SConsignFile/default.py @@ -29,7 +29,6 @@ Verify the default behavior of SConsignFile(), called with no arguments. """ import TestSCons -import os.path _python_ = TestSCons._python_ diff --git a/test/SConsignFile/explicit-file.py b/test/SConsignFile/explicit-file.py index 7583bdc..afb2dbd 100644 --- a/test/SConsignFile/explicit-file.py +++ b/test/SConsignFile/explicit-file.py @@ -29,7 +29,6 @@ Verify the default behavior of SConsignFile(), called with no arguments. """ import TestSCons -import os.path _python_ = TestSCons._python_ diff --git a/test/SConsignFile/use-dumbdbm.py b/test/SConsignFile/use-dumbdbm.py index 36ba18b..22b0bff 100644 --- a/test/SConsignFile/use-dumbdbm.py +++ b/test/SConsignFile/use-dumbdbm.py @@ -35,14 +35,10 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import dumbdbm - use_dbm = 'dumbdbm' + import dbm.dumb + use_dbm='dbm.dumb' except ImportError: - try: - import dbm.dumb - use_dbm='dbm.dumb' - except ImportError: - test.skip_test('No dumbdbm or dbm.dumb in this version of Python; skipping test.\n') + test.skip_test('No dbm.dumb in this version of Python; skipping test.\n') test.subdir('subdir') diff --git a/test/SConsignFile/use-gdbm.py b/test/SConsignFile/use-gdbm.py index 12a2e8b..461a482 100644 --- a/test/SConsignFile/use-gdbm.py +++ b/test/SConsignFile/use-gdbm.py @@ -35,14 +35,10 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import gdbm - use_dbm = "gdbm" + import dbm.gnu + use_dbm = "dbm.gnu" except ImportError: - try: - import dbm.gnu - use_dbm = "dbm.gnu" - except ImportError: - test.skip_test('No GNU dbm in this version of Python; skipping test.\n') + test.skip_test('No GNU dbm in this version of Python; skipping test.\n') test.subdir('subdir') diff --git a/test/SWIG/SWIGFLAGS.py b/test/SWIG/SWIGFLAGS.py index cb91699..70e16a6 100644 --- a/test/SWIG/SWIGFLAGS.py +++ b/test/SWIG/SWIGFLAGS.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that we can use ${SOURCE} expansions in $SWIGFLAGS. """ -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/SWIG/live.py b/test/SWIG/live.py index e7b2602..3d46b74 100644 --- a/test/SWIG/live.py +++ b/test/SWIG/live.py @@ -27,7 +27,6 @@ Test SWIG behavior with a live, installed SWIG. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/Scanner/Scanner.py b/test/Scanner/Scanner.py index 7e39134..4889d0f 100644 --- a/test/Scanner/Scanner.py +++ b/test/Scanner/Scanner.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os _python_ = TestSCons._python_ diff --git a/test/TEMPFILE/TEMPFILE-actionlist.py b/test/TEMPFILE/TEMPFILE-actionlist.py new file mode 100644 index 0000000..d66b217 --- /dev/null +++ b/test/TEMPFILE/TEMPFILE-actionlist.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +""" +Verify that using $TEMPFILE in multiple actions in a +list invokes each command in the list. +""" + +import TestSCons + +test = TestSCons.TestSCons(match=TestSCons.match_re) +test.file_fixture('fixture/SConstruct-tempfile-actionlist', 'SConstruct') + +test.write('file.input', "file.input\n") + +test.run(arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py -otempfile file.input +xxx.py @\\S+ +Using tempfile \\S+ for command line: +yyy.py -ofile.output tempfile +yyy.py @\\S+ +""") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/TempFileMunge/TEMPFILEDIR.py b/test/TEMPFILE/TEMPFILEDIR.py index b528be3..b528be3 100644 --- a/test/TempFileMunge/TEMPFILEDIR.py +++ b/test/TEMPFILE/TEMPFILEDIR.py diff --git a/test/TempFileMunge/TEMPFILEPREFIX.py b/test/TEMPFILE/TEMPFILEPREFIX.py index ac2ae46..62ac814 100644 --- a/test/TempFileMunge/TEMPFILEPREFIX.py +++ b/test/TEMPFILE/TEMPFILEPREFIX.py @@ -25,8 +25,6 @@ it to appear at the front of name of the generated tempfile used for long command lines. """ -import os -import stat import TestSCons diff --git a/test/TempFileMunge/TEMPFILESUFFIX.py b/test/TEMPFILE/TEMPFILESUFFIX.py index a19317d..bd4cf09 100644 --- a/test/TempFileMunge/TEMPFILESUFFIX.py +++ b/test/TEMPFILE/TEMPFILESUFFIX.py @@ -25,8 +25,6 @@ it to appear at the end of name of the generated tempfile used for long command lines. """ -import os -import stat import TestSCons diff --git a/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist b/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist new file mode 100644 index 0000000..07b6345 --- /dev/null +++ b/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist @@ -0,0 +1,6 @@ +DefaultEnvironment(tools=[]) +env = Environment(tools=[], + BUILDCOM=['${TEMPFILE("xxx.py -otempfile $SOURCE")}', + '${TEMPFILE("yyy.py -o$TARGET tempfile")}'], + MAXLINELENGTH=1) +env.Command('file.output', 'file.input', '$BUILDCOM') diff --git a/test/TempFileMunge/fixture/SConstruct.tempfiledir b/test/TEMPFILE/fixture/SConstruct.tempfiledir index ea26c27..ea26c27 100644 --- a/test/TempFileMunge/fixture/SConstruct.tempfiledir +++ b/test/TEMPFILE/fixture/SConstruct.tempfiledir diff --git a/test/TEX/generated_files.py b/test/TEX/generated_files.py index 9bafc9b..418d99b 100644 --- a/test/TEX/generated_files.py +++ b/test/TEX/generated_files.py @@ -33,7 +33,6 @@ Test courtesy Rob Managan. """ import TestSCons -import os test = TestSCons.TestSCons() diff --git a/test/TEX/synctex.py b/test/TEX/synctex.py index 385a173..c9552d5 100644 --- a/test/TEX/synctex.py +++ b/test/TEX/synctex.py @@ -31,7 +31,6 @@ be aware of the created synctex.gz file. Test configuration contributed by Robert Managan. """ -import os import TestSCons test = TestSCons.TestSCons() diff --git a/test/Variables/BoolVariable.py b/test/Variables/BoolVariable.py index d259984..eaf496a 100644 --- a/test/Variables/BoolVariable.py +++ b/test/Variables/BoolVariable.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test the BoolVariable canned Variable type. """ -import os import TestSCons diff --git a/test/Variables/EnumVariable.py b/test/Variables/EnumVariable.py index cf35b9b..14a8bf3 100644 --- a/test/Variables/EnumVariable.py +++ b/test/Variables/EnumVariable.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test the EnumVariable canned Variable type. """ -import os.path import TestSCons diff --git a/test/Variables/PackageVariable.py b/test/Variables/PackageVariable.py index b3fd10a..eb14383 100644 --- a/test/Variables/PackageVariable.py +++ b/test/Variables/PackageVariable.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test the PackageVariable canned Variable type. """ -import os import TestSCons diff --git a/test/YACC/YACC-fixture/SConstruct_YACC_before b/test/YACC/YACC-fixture/SConstruct_YACC_before new file mode 100644 index 0000000..94f7adf --- /dev/null +++ b/test/YACC/YACC-fixture/SConstruct_YACC_before @@ -0,0 +1,4 @@ +env=Environment(tools=[]) +env2=env.Clone(YACC="SOMETHING_DUMB") +env2.Tool('yacc') +env2.CFile('aaa.y') diff --git a/test/YACC/YACC.py b/test/YACC/YACC.py index b27c2a7..d4cb40e 100644 --- a/test/YACC/YACC.py +++ b/test/YACC/YACC.py @@ -58,8 +58,8 @@ test.must_match('bbb.c', "bbb.yacc" + os.linesep + "myyacc.py" + os.lines test.must_match('ccc.cc', "ccc.yacc" + os.linesep + "myyacc.py" + os.linesep) test.must_match('ddd.m', "ddd.yacc" + os.linesep + "myyacc.py" + os.linesep) - - +test.run(arguments="-n -f SConstruct_YACC_before") +test.fail_test('SOMETHING_DUMB' not in test.stdout(), "YACC is not overridden to be SOMETHING_DUMB") test.pass_test() diff --git a/test/YACC/YACCFLAGS.py b/test/YACC/YACCFLAGS.py index b3f86fe..1ab8c0d 100644 --- a/test/YACC/YACCFLAGS.py +++ b/test/YACC/YACCFLAGS.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff --git a/test/YACC/live.py b/test/YACC/live.py index 4567dba..6314e6c 100644 --- a/test/YACC/live.py +++ b/test/YACC/live.py @@ -29,8 +29,6 @@ Test YACC and YACCFLAGS with a live yacc compiler. """ import TestSCons -import sys -import os _exe = TestSCons._exe _python_ = TestSCons._python_ diff --git a/test/ZIP/ZIPCOMSTR.py b/test/ZIP/ZIPCOMSTR.py index af9ba57..43566fb 100644 --- a/test/ZIP/ZIPCOMSTR.py +++ b/test/ZIP/ZIPCOMSTR.py @@ -42,12 +42,21 @@ env = Environment(tools=['zip'], ZIPCOM = r'%(_python_)s mycompile.py zip $TARGET $SOURCES', ZIPCOMSTR = 'Zipping $TARGET from $SOURCE') env.Zip('aaa.zip', 'aaa.in') + +# Issue explained in PR #3569 - setting ZIPCOM/ZIPCOMSTR after env initialization +# is ignored and yields zip() instead of desired ZIPCOMSTR> +env2 = Environment(tools=['zip']) +env2['ZIPCOM'] = r'%(_python_)s mycompile.py zip $TARGET $SOURCES' +env2['ZIPCOMSTR']="TESTING ONE TWO THREE $TARGET from $SOURCE" +env2.Zip('aaa2.zip', 'aaa.in') + """ % locals()) test.write('aaa.in', 'aaa.in\n/*zip*/\n') test.run(stdout = test.wrap_stdout("""\ Zipping aaa.zip from aaa.in +TESTING ONE TWO THREE aaa2.zip from aaa.in """)) test.must_match('aaa.zip', "aaa.in\n") diff --git a/test/ZIP/ZIPROOT.py b/test/ZIP/ZIPROOT.py index f3e4496..24e82eb 100644 --- a/test/ZIP/ZIPROOT.py +++ b/test/ZIP/ZIPROOT.py @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import stat import TestSCons diff --git a/test/emitter.py b/test/emitter.py index 7712d3a..d2a8b67 100644 --- a/test/emitter.py +++ b/test/emitter.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os test = TestSCons.TestSCons() diff --git a/test/exitfns.py b/test/exitfns.py index fca44b8..c303a8e 100644 --- a/test/exitfns.py +++ b/test/exitfns.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os test = TestSCons.TestSCons() # also exclude these tests since it overides the exit function which doesnt work with coverage diff --git a/test/gettext/MOFiles/UserExamples.py b/test/gettext/MOFiles/UserExamples.py index 1b78268..5cc3037 100644 --- a/test/gettext/MOFiles/UserExamples.py +++ b/test/gettext/MOFiles/UserExamples.py @@ -30,7 +30,6 @@ Make sure, that the examples given in user guide all work. """ import TestSCons -import os test = TestSCons.TestSCons() diff --git a/test/gettext/POUpdate/UserExamples.py b/test/gettext/POUpdate/UserExamples.py index 5f3e6c7..be38996 100644 --- a/test/gettext/POUpdate/UserExamples.py +++ b/test/gettext/POUpdate/UserExamples.py @@ -29,7 +29,6 @@ Make sure, that the examples given in user guide all work. """ import TestSCons -import os test = TestSCons.TestSCons() diff --git a/test/gettext/Translate/MultiCatalog.py b/test/gettext/Translate/MultiCatalog.py index 1a5708c..e8c2b97 100644 --- a/test/gettext/Translate/MultiCatalog.py +++ b/test/gettext/Translate/MultiCatalog.py @@ -42,7 +42,6 @@ files correctly. # replicate the bug. import TestSCons -from os import path test = TestSCons.TestSCons() diff --git a/test/ignore-command.py b/test/ignore-command.py index d5c18a5..3833e61 100644 --- a/test/ignore-command.py +++ b/test/ignore-command.py @@ -28,7 +28,6 @@ Test use of a preceding - to ignore the return value from a command. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/import.py b/test/import.py index 99a40d7..55a40cc 100644 --- a/test/import.py +++ b/test/import.py @@ -1,7 +1,5 @@ #!/usr/bin/env python # -# __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 @@ -22,8 +20,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - """ Verify that we can import and use the contents of Platform and Tool modules directly. @@ -31,7 +27,6 @@ modules directly. import os import re -import sys # must do this here, since TestSCons will chdir tooldir = os.path.join(os.getcwd(), 'SCons', 'Tool') @@ -78,6 +73,8 @@ ignore = ('__init__.py', 'MSCommon', # clang common "clangCommon", + # link common logic + "linkCommon", # Sun pkgchk and pkginfo common stuff 'sun_pkg.py', # RPM utilities diff --git a/test/long-lines/signature.py b/test/long-lines/signature.py index 082a13b..7f9ba43 100644 --- a/test/long-lines/signature.py +++ b/test/long-lines/signature.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,8 +22,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - """ Verify that use of long command lines correctly excludes arguments surrounded by $( $) from the signature calculation. diff --git a/test/multiline.py b/test/multiline.py index c2fabf8..b910b69 100644 --- a/test/multiline.py +++ b/test/multiline.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/no-arguments.py b/test/no-arguments.py index 8925c48..5ed66ab 100644 --- a/test/no-arguments.py +++ b/test/no-arguments.py @@ -30,7 +30,6 @@ is no Default() in the SConstruct file and there are no command-line arguments, or a null command-line argument. """ -import os.path import TestSCons diff --git a/test/option--random.py b/test/option--random.py index c25ec12..1dafca4 100644 --- a/test/option--random.py +++ b/test/option--random.py @@ -27,7 +27,6 @@ Verify that we build correctly using the --random option. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/option--tree.py b/test/option--tree.py index 290f1d4..5192ac0 100644 --- a/test/option--tree.py +++ b/test/option--tree.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import sys import TestSCons test = TestSCons.TestSCons() diff --git a/test/option-k.py b/test/option-k.py index 4f4c86b..d6c81ea 100644 --- a/test/option-k.py +++ b/test/option-k.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/option/debug-count.py b/test/option/debug-count.py index f2fceb4..cf46feb 100644 --- a/test/option/debug-count.py +++ b/test/option/debug-count.py @@ -34,13 +34,6 @@ import TestSCons test = TestSCons.TestSCons() -try: - import weakref -except ImportError: - x = "Python version has no 'weakref' module; skipping tests.\n" - test.skip_test(x) - - test.write('SConstruct', """ DefaultEnvironment(tools=[]) diff --git a/test/option/debug-memory.py b/test/option/debug-memory.py index bf720cc..2958e0b 100644 --- a/test/option/debug-memory.py +++ b/test/option/debug-memory.py @@ -1,6 +1,7 @@ #!/usr/bin/env python +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,8 +23,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - """ Test that the --debug=memory option works. """ @@ -31,21 +30,18 @@ Test that the --debug=memory option works. import re import TestSCons +from TestCmd import IS_WINDOWS test = TestSCons.TestSCons() -try: - import resource -except ImportError: +if not IS_WINDOWS: try: - import win32process - import win32api + import resource # noqa: F401 except ImportError: - x = "Python version has no 'resource' or 'win32api/win32process' module; skipping tests.\n" + x = "Python version has no 'resource' skipping tests.\n" test.skip_test(x) - test.write('SConstruct', """ DefaultEnvironment(tools=[]) def cat(target, source, env): diff --git a/test/option/debug-objects.py b/test/option/debug-objects.py index beec4b7..9c8536c 100644 --- a/test/option/debug-objects.py +++ b/test/option/debug-objects.py @@ -32,13 +32,6 @@ import TestSCons test = TestSCons.TestSCons() -try: - import weakref -except ImportError: - x = "Python version has no 'weakref' module; skipping tests.\n" - test.skip_test(x) - - test.write('SConstruct', """ DefaultEnvironment(tools=[]) diff --git a/test/packaging/place-files-in-subdirectory.py b/test/packaging/place-files-in-subdirectory.py index 838d6b8..dd422e6 100644 --- a/test/packaging/place-files-in-subdirectory.py +++ b/test/packaging/place-files-in-subdirectory.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test the requirement to place files in a given subdirectory before archiving. """ -import os import subprocess import TestSCons diff --git a/test/python-version.py b/test/python-version.py index 9cfd2bd..bbec233 100644 --- a/test/python-version.py +++ b/test/python-version.py @@ -29,7 +29,6 @@ Verify the behavior of our check for unsupported or deprecated versions of Python. """ -import os import re import TestCmd diff --git a/test/runtest/testlistfile.py b/test/runtest/testlistfile.py index 063a8d0..ba034e8 100644 --- a/test/runtest/testlistfile.py +++ b/test/runtest/testlistfile.py @@ -29,7 +29,6 @@ Test a list of tests to run in a file specified with the -f option. """ import os.path -import re import TestRuntest diff --git a/test/scons-time/func/prefix.py b/test/scons-time/func/prefix.py index 67a0c6b..36c9ddf 100644 --- a/test/scons-time/func/prefix.py +++ b/test/scons-time/func/prefix.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Verify that the func -p and --prefix options specify what log files to use. """ -import os.path import TestSCons_time diff --git a/test/scons-time/run/archive/zip.py b/test/scons-time/run/archive/zip.py index 4620440..7bd5538 100644 --- a/test/scons-time/run/archive/zip.py +++ b/test/scons-time/run/archive/zip.py @@ -29,7 +29,6 @@ Verify basic generation of timing information from an input fake-project .zip file. """ -import sys import TestSCons_time diff --git a/test/sconsign/script/SConsignFile.py b/test/sconsign/script/SConsignFile.py index cd82fac..47fe94f 100644 --- a/test/sconsign/script/SConsignFile.py +++ b/test/sconsign/script/SConsignFile.py @@ -29,7 +29,6 @@ Verify that the sconsign script works with files generated when using the signatures in an SConsignFile(). """ -import re import TestSCons import TestSConsign diff --git a/test/silent-command.py b/test/silent-command.py index 7f3b010..3622a04 100644 --- a/test/silent-command.py +++ b/test/silent-command.py @@ -28,7 +28,6 @@ Test the use of a preceding @ to suppress printing a command. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff --git a/test/srcchange.py b/test/srcchange.py index 30f6f20..e72d923 100644 --- a/test/srcchange.py +++ b/test/srcchange.py @@ -32,7 +32,6 @@ of Decider('content'). __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/subdir.py b/test/subdir.py index 363d44c..c5bfcdc 100644 --- a/test/subdir.py +++ b/test/subdir.py @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os.path _python_ = TestSCons._python_ diff --git a/test/symlink/dangling-include.py b/test/symlink/dangling-include.py index b7d5d2f..081573f 100644 --- a/test/symlink/dangling-include.py +++ b/test/symlink/dangling-include.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test how we handle #includes of dangling symlinks. """ -import os import TestSCons diff --git a/test/symlink/dangling-source.py b/test/symlink/dangling-source.py index b2bc540..94690f4 100644 --- a/test/symlink/dangling-source.py +++ b/test/symlink/dangling-source.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" Test how we handle dangling symlinks as source files. """ -import os import TestSCons diff --git a/test/timestamp-fallback.py b/test/timestamp-fallback.py index 2dd50a2..b3e812b 100644 --- a/test/timestamp-fallback.py +++ b/test/timestamp-fallback.py @@ -32,7 +32,6 @@ rare no-md5 Pythons comes into play (some entities ban the use of md5 as unsafe, although SCons does not use it in a security context. """ -import sys import os import TestSCons diff --git a/test/tool_args.py b/test/tool_args.py index 6983705..464d009 100644 --- a/test/tool_args.py +++ b/test/tool_args.py @@ -29,7 +29,6 @@ Test the ability to pass a dictionary of keyword arguments to a Tool specification's generate() method. """ -import os.path import TestSCons diff --git a/test/toolpath/basic.py b/test/toolpath/basic.py index 793497b..0d2429e 100644 --- a/test/toolpath/basic.py +++ b/test/toolpath/basic.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff --git a/test/toolpath/nested/nested.py b/test/toolpath/nested/nested.py index df2ba07..47c0b03 100644 --- a/test/toolpath/nested/nested.py +++ b/test/toolpath/nested/nested.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons test = TestSCons.TestSCons() diff --git a/test/toolpath/relative_import/relative_import.py b/test/toolpath/relative_import/relative_import.py index 8fa2f62..f4362f7 100644 --- a/test/toolpath/relative_import/relative_import.py +++ b/test/toolpath/relative_import/relative_import.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import os.path
import TestSCons
test = TestSCons.TestSCons()
diff --git a/test/update-release-info/update-release-info.py b/test/update-release-info/update-release-info.py index f353d38..2de4713 100644 --- a/test/update-release-info/update-release-info.py +++ b/test/update-release-info/update-release-info.py @@ -27,7 +27,8 @@ have the appropriate triggers to cause the modifications. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os, sys, time +import os +import time import TestRuntest diff --git a/test/virtualenv/activated/option/enable-virtualenv.py b/test/virtualenv/activated/option/enable-virtualenv.py index a5ceecc..ff06583 100644 --- a/test/virtualenv/activated/option/enable-virtualenv.py +++ b/test/virtualenv/activated/option/enable-virtualenv.py @@ -30,7 +30,6 @@ Ensure that the --enable-virtualenv flag works. import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff --git a/test/virtualenv/activated/option/ignore-virtualenv.py b/test/virtualenv/activated/option/ignore-virtualenv.py index ac6f945..b0d482e 100644 --- a/test/virtualenv/activated/option/ignore-virtualenv.py +++ b/test/virtualenv/activated/option/ignore-virtualenv.py @@ -30,7 +30,6 @@ Ensure that the --ignore-virtualenv flag works. import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff --git a/test/virtualenv/activated/virtualenv_activated_python.py b/test/virtualenv/activated/virtualenv_activated_python.py index c673ae1..4e793da 100644 --- a/test/virtualenv/activated/virtualenv_activated_python.py +++ b/test/virtualenv/activated/virtualenv_activated_python.py @@ -33,7 +33,6 @@ environment or in unactivated virtualenv. import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff --git a/test/virtualenv/activated/virtualenv_detect_virtualenv.py b/test/virtualenv/activated/virtualenv_detect_virtualenv.py index 2c00793..e7b7cb0 100644 --- a/test/virtualenv/activated/virtualenv_detect_virtualenv.py +++ b/test/virtualenv/activated/virtualenv_detect_virtualenv.py @@ -30,7 +30,6 @@ Check if SCons.Platform.virtualenv.Virtualenv() works in SConscripts. import TestSCons import SCons.Platform.virtualenv -import sys test = TestSCons.TestSCons() diff --git a/test/virtualenv/regularenv/virtualenv_detect_regularenv.py b/test/virtualenv/regularenv/virtualenv_detect_regularenv.py index 57a0d4f..6856838 100644 --- a/test/virtualenv/regularenv/virtualenv_detect_regularenv.py +++ b/test/virtualenv/regularenv/virtualenv_detect_regularenv.py @@ -30,7 +30,6 @@ Check if SCons.Platform.virtualenv.Virtualenv() works in SConscript. import TestSCons import SCons.Platform.virtualenv -import sys test = TestSCons.TestSCons() diff --git a/test/virtualenv/unactivated/virtualenv_unactivated_python.py b/test/virtualenv/unactivated/virtualenv_unactivated_python.py index a4dc240..38d5329 100644 --- a/test/virtualenv/unactivated/virtualenv_unactivated_python.py +++ b/test/virtualenv/unactivated/virtualenv_unactivated_python.py @@ -33,7 +33,6 @@ a regular environment or in an activated virtualenv. import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index f0051ba..76609a0 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -309,7 +309,6 @@ import tempfile import threading import time import traceback -import types from collections import UserList, UserString from subprocess import PIPE, STDOUT @@ -345,13 +344,13 @@ def is_List(e): def to_bytes(s): - if isinstance(s, bytes) or bytes is str: + if isinstance(s, bytes): return s return bytes(s, 'utf-8') def to_str(s): - if bytes is str or is_String(s): + if is_String(s): return s return str(s, 'utf-8') @@ -470,7 +469,7 @@ def match_exact(lines=None, matches=None, newline=os.sep): :returns: an object (1) on match, else None, like re.match """ - if isinstance(lines, bytes) or bytes is str: + if isinstance(lines, bytes): newline = to_bytes(newline) if not is_List(lines): diff --git a/testing/framework/TestCmdTests.py b/testing/framework/TestCmdTests.py index 7017d2c..e37b90e 100644 --- a/testing/framework/TestCmdTests.py +++ b/testing/framework/TestCmdTests.py @@ -24,13 +24,11 @@ __revision__ = "TestCmdTests.py 1.3.D001 2010/06/03 12:58:27 knight" import os import shutil -import signal import stat import subprocess import sys import tempfile import time -import types import unittest from io import StringIO from contextlib import closing diff --git a/testing/framework/TestCommon.py b/testing/framework/TestCommon.py index 35bf365..1471439 100644 --- a/testing/framework/TestCommon.py +++ b/testing/framework/TestCommon.py @@ -99,7 +99,6 @@ __author__ = "Steven Knight <knight at baldmt dot com>" __revision__ = "TestCommon.py 1.3.D001 2010/06/03 12:58:27 knight" __version__ = "1.3" -import copy import glob import os import stat diff --git a/testing/framework/TestCommonTests.py b/testing/framework/TestCommonTests.py index 6c9e92d..8a93b35 100644 --- a/testing/framework/TestCommonTests.py +++ b/testing/framework/TestCommonTests.py @@ -22,11 +22,9 @@ SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. __author__ = "Steven Knight <knight at baldmt dot com>" __revision__ = "TestCommonTests.py 1.3.D001 2010/06/03 12:58:27 knight" -import difflib import os import re import signal -import stat import sys import unittest diff --git a/testing/framework/TestRuntest.py b/testing/framework/TestRuntest.py index 801f710..a70110c 100644 --- a/testing/framework/TestRuntest.py +++ b/testing/framework/TestRuntest.py @@ -36,8 +36,6 @@ else: pythonstring = python pythonstring = pythonstring.replace('\\', '\\\\') pythonflags = '' -if sys.version_info[0] < 3: - pythonflags = ' -tt' failing_test_template = """\ import sys diff --git a/testing/framework/TestSCons.py b/testing/framework/TestSCons.py index a7eb4c5..36b9df4 100644 --- a/testing/framework/TestSCons.py +++ b/testing/framework/TestSCons.py @@ -1491,12 +1491,9 @@ SConscript(sconscript) self.run(program=python, stdin="""\ import sysconfig, sys, os.path py_ver = 'python%d%d' % sys.version_info[:2] -# use distutils to help find include and lib path -# TODO: PY3 fine to use sysconfig.get_config_var("INCLUDEPY") try: - import distutils.sysconfig - exec_prefix = distutils.sysconfig.EXEC_PREFIX - include = distutils.sysconfig.get_python_inc() + exec_prefix = sysconfig.get_config_var("exec_prefix") + include = sysconfig.get_config_var("INCLUDEPY") print(include) lib_path = os.path.join(exec_prefix, 'libs') if not os.path.exists(lib_path): @@ -1826,7 +1823,11 @@ class TimeSCons(TestSCons): # TODO(sgk): allow the caller to specify the target (argument) # that must be up-to-date. self.add_timing_options(kw) - self.up_to_date(arguments='.', **kw) + + # Build up regex for + # SConscript:/private/var/folders/ng/48pttrpj239fw5rmm3x65pxr0000gn/T/testcmd.12081.pk1bv5i5/SConstruct took 533.646 ms + read_str = 'SConscript:.*\n' + self.up_to_date(arguments='.', read_str=read_str, **kw) sys.stdout.write(self.stdout()) stats = self.collect_stats(self.stdout()) # time-commands should always be 0.0 on a null build, because @@ -1888,6 +1889,27 @@ class TimeSCons(TestSCons): destination = source.replace(source_dir, dest_dir) shutil.copy2(source, destination) + def up_to_date(self, arguments='.', read_str="", **kw): + """Asserts that all of the targets listed in arguments is + up to date, but does not make any assumptions on other targets. + This function is most useful in conjunction with the -n option. + Note: This custom version for timings tests does NOT escape + read_str. + """ + s = "" + for arg in arguments.split(): + s = s + "scons: `%s' is up to date.\n" % arg + kw['arguments'] = arguments + stdout = self.wrap_stdout(read_str="REPLACEME", build_str=s) + # Append '.*' so that timing output that comes after the + # up-to-date output is okay. + stdout = re.escape(stdout) + '.*' + stdout = stdout.replace('REPLACEME', read_str) + kw['stdout'] = stdout + kw['match'] = self.match_re_dotall + self.run(**kw) + + # In some environments, $AR will generate a warning message to stderr # if the library doesn't previously exist and is being created. One diff --git a/testing/framework/TestSConsign.py b/testing/framework/TestSConsign.py index 665059c..11a764c 100644 --- a/testing/framework/TestSConsign.py +++ b/testing/framework/TestSConsign.py @@ -19,7 +19,6 @@ in this subclass. import os import os.path -import sys from TestSCons import * from TestSCons import __all__ |