diff -Nru scons-4.0.1+dfsg/.appveyor/install.bat scons-4.4.0+dfsg/.appveyor/install.bat --- scons-4.0.1+dfsg/.appveyor/install.bat 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.appveyor/install.bat 2022-07-30 21:48:28.000000000 +0000 @@ -3,8 +3,9 @@ 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 +C:\\%WINPYTHON%\\python.exe -m pip install -U --progress-bar off -r requirements.txt REM install 3rd party tools to test with choco install --allow-empty-checksums dmd ldc swig vswhere xsltproc winflexbison set SCONS_CACHE_MSVC_CONFIG=true diff -Nru scons-4.0.1+dfsg/.appveyor.yml scons-4.4.0+dfsg/.appveyor.yml --- scons-4.0.1+dfsg/.appveyor.yml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.appveyor.yml 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,14 @@ #version: '3.0.1.{build}' +# +# When planning updates here, check availability at: +# https://www.appveyor.com/docs/windows-images-software/ +# This is slow, try to keep the number of builds as low as makes sense. image: # linux builds done in Travis CI for now - - Visual Studio 2015 - Visual Studio 2017 - Visual Studio 2019 + - Visual Studio 2022 cache: - downloads -> appveyor.yml @@ -21,33 +25,30 @@ # split builds into sets of four jobs due to appveyor per-job time limit environment: matrix: - - WINPYTHON: "Python35" - COVERAGE: 0 - - WINPYTHON: "Python36" - COVERAGE: 1 + - WINPYTHON: "Python310" + COVERAGE: 0 - WINPYTHON: "Python37" COVERAGE: 0 - WINPYTHON: "Python38" COVERAGE: 0 + + - WINPYTHON: "Python36" + COVERAGE: 1 + + + + # remove sets of build jobs based on criteria below # to fine tune the number and platforms tested matrix: exclude: - # test python 3.5 on Visual Studio 2015 image - - image: Visual Studio 2015 - WINPYTHON: "Python36" - - image: Visual Studio 2015 - WINPYTHON: "Python37" - - image: Visual Studio 2015 - WINPYTHON: "Python38" - # test python 3.8 on Visual Studio 2017 image - image: Visual Studio 2017 - WINPYTHON: "Python35" + WINPYTHON: "Python310" - image: Visual Studio 2017 WINPYTHON: "Python37" - image: Visual Studio 2017 @@ -55,10 +56,18 @@ # test python 3.7 on Visual Studio 2019 image - image: Visual Studio 2019 - WINPYTHON: "Python35" + WINPYTHON: "Python310" - image: Visual Studio 2019 WINPYTHON: "Python36" + # test python 3.10 on Visual Studio 2022 image + - image: Visual Studio 2022 + WINPYTHON: "Python36" + - image: Visual Studio 2022 + WINPYTHON: "Python37" + - image: Visual Studio 2022 + WINPYTHON: "Python38" + # remove some binaries we don't want to be found before_build: - ps: .\.appveyor\ignore_git_bins.ps1 @@ -74,8 +83,8 @@ # setup coverage by creating the coverage config file, and adding coverage # to the sitecustomize so that all python processes start with coverage - ps: .\.appveyor\coverage_setup.ps1 - - # NOTE: running powershell from cmd is intended because + + # NOTE: running powershell from cmd is intended because # it formats the output correctly - cmd: powershell -Command "& { if($env:COVERAGE -eq 1) { coverage run -p --rcfile=$($env:COVERAGE_PROCESS_START) runtest.py -j 2 -t --exclude-list exclude_list.txt -a } else { C:\\%WINPYTHON%\\python.exe runtest.py -j 2 -t --exclude-list exclude_list.txt -a }; if($LastExitCode -eq 2 -Or $LastExitCode -eq 0) { $host.SetShouldExit(0 )} else {$host.SetShouldExit(1)}}" @@ -85,4 +94,4 @@ # running codecov in powershell causes an error so running in platform # shells - cmd: if %COVERAGE% equ 1 codecov -X gcov --file coverage_xml.xml - + diff -Nru scons-4.0.1+dfsg/bin/SConsDoc.py scons-4.4.0+dfsg/bin/SConsDoc.py --- scons-4.0.1+dfsg/bin/SConsDoc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/bin/SConsDoc.py 2022-07-30 21:48:28.000000000 +0000 @@ -41,9 +41,11 @@ 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. + &b-BUILDER; element. A link to this definition may be + interpolated by specifying the &b-link-BUILDER; element. + Unlike normal XML, blank lines are significant in these descriptions and serve to separate paragraphs. @@ -59,16 +61,28 @@ Function example: - + (arg1, arg2, key=value) 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. + &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. + print("this is example code, it will be offset and indented") @@ -83,9 +97,11 @@ 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. + &cv-VARIABLE; element. A link to this definition may be + interpolated by specifying the &cv-link-VARIABLE; element. + print("this is example code, it will be offset and indented") @@ -100,9 +116,11 @@ 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. + &t-TOOL; element. A link to this definition may be + interpolated by specifying the &t-link-TOOL; element. + print("this is example code, it will be offset and indented") @@ -346,9 +364,18 @@ doc.xinclude() try: TreeFactory.xmlschema.assertValid(doc) + except etree.XMLSchemaValidateError as e: + print("ERROR: %s fails to validate:" % fpath) + print(e) + print(e.error_log.last_error.message) + print("In file: [%s]" % e.error_log.last_error.filename) + print("Line : %d" % e.error_log.last_error.line) + return False + except Exception as e: print("ERROR: %s fails to validate:" % fpath) print(e) + return False return True @@ -472,7 +499,7 @@ class Tool(Item): def __init__(self, name): - Item.__init__(self, name) + super().__init__(name) self.entity = self.name.replace('+', 'X') diff -Nru scons-4.0.1+dfsg/bin/scons-test.py scons-4.4.0+dfsg/bin/scons-test.py --- scons-4.0.1+dfsg/bin/scons-test.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/bin/scons-test.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,19 +1,46 @@ #!/usr/bin/env python + +# MIT License # -# A script that takes an scons-src-{version}.zip file, unwraps it in -# a temporary location, and calls runtest.py to execute one or more of -# its tests. +# Copyright The SCons Foundation # -# The default is to download the latest scons-src archive from the SCons -# web site, and to execute all of the tests. +# 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: # -# With a little more work, this will become the basis of an automated -# testing and reporting system that anyone will be able to use to -# participate in testing SCons on their system and regularly reporting -# back the results. A --xml option is a stab at gathering a lot of -# relevant information about the system, the Python version, etc., -# so that problems on different platforms can be identified sooner. +# 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-test.py - test a particular SCons version. + +Takes an scons-src-{version}.zip file, unwraps it in a temporary location, +and calls runtest.py to execute one or more of its tests. + +The default is to download the latest scons-src archive from the SCons +web site, and to execute all of the tests. + +With a little more work, this will become the basis of an automated +testing and reporting system that anyone will be able to use to +participate in testing SCons on their system and regularly reporting +back the results. A --xml option is a stab at gathering a lot of +relevant information about the system, the Python version, etc., +so that problems on different platforms can be identified sooner. +""" + import atexit import getopt import os @@ -22,16 +49,7 @@ import tempfile import time import zipfile - -try: - # try Python 3.x style - from urllib.request import urlretrieve -except ImportError: - # nope, must be 2.x; this hack is equivalent - import imp - # protect import from fixer - urlretrieve = imp.load_module('urllib', - *imp.find_module('urllib')).urlretrieve +from urllib.request import urlretrieve helpstr = """\ Usage: scons-test.py [-f zipfile] [-o outdir] [-v] [--xml] [runtest arguments] diff -Nru scons-4.0.1+dfsg/bin/scons-time.py scons-4.4.0+dfsg/bin/scons-time.py --- scons-4.0.1+dfsg/bin/scons-time.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/bin/scons-time.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,8 @@ #!/usr/bin/env python -# -# scons-time - run SCons timings and collect statistics -# -# A script for running a configuration through SCons with a standard -# set of invocations to collect timing and memory statistics and to -# capture the results in a consistent set of output files for display -# and analysis. -# +# 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,7 +23,13 @@ # 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-time - run SCons timings and collect statistics + +A script for running a configuration through SCons with a standard set +of invocations to collect timing and memory statistics and to capture +the results in a consistent set of output files for display and analysis. +""" import getopt import glob diff -Nru scons-4.0.1+dfsg/bin/update-release-info.py scons-4.4.0+dfsg/bin/update-release-info.py --- scons-4.0.1+dfsg/bin/update-release-info.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/bin/update-release-info.py 2022-07-30 21:48:28.000000000 +0000 @@ -33,8 +33,9 @@ - A new section to accumulate changes is added to src/CHANGES.txt and src/Announce.txt. """ +# 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 @@ -53,14 +54,14 @@ # 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__" +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +import argparse import os +import re import sys import time -import re -import argparse DEBUG = os.environ.get('DEBUG', 0) @@ -257,15 +258,15 @@ rel_info.version_string = new_version # Update ReleaseConfig - t = UpdateFile('ReleaseConfig') - if DEBUG: t.file = '/tmp/ReleaseConfig' + if DEBUG: + t.file = '/tmp/ReleaseConfig' t.replace_assign('version_tuple', str(new_tuple)) # Update src/CHANGES.txt - t = UpdateFile('CHANGES.txt') - if DEBUG: t.file = '/tmp/CHANGES.txt' + if DEBUG: + t.file = '/tmp/CHANGES.txt' t.sub('(\nRELEASE .*)', r"""\nRELEASE VERSION/DATE TO BE FILLED IN LATER\n From John Doe:\n - Whatever John Doe did.\n\n\1""") @@ -273,7 +274,8 @@ # Update src/RELEASE.txt t = UpdateFile('RELEASE.txt', os.path.join('template', 'RELEASE.txt')) - if DEBUG: t.file = '/tmp/RELEASE.txt' + if DEBUG: + t.file = '/tmp/RELEASE.txt' t.replace_version() # Update README @@ -287,9 +289,9 @@ count=0) # Update testing/framework/TestSCons.py - t = UpdateFile(os.path.join('testing', 'framework', 'TestSCons.py')) - if DEBUG: t.file = '/tmp/TestSCons.py' + if DEBUG: + t.file = '/tmp/TestSCons.py' t.replace_assign('copyright_years', repr(rel_info.copyright_years)) t.replace_assign('default_version', repr(rel_info.version_string)) # ??? t.replace_assign('SConsVersion', repr(version_string)) @@ -297,26 +299,18 @@ t.replace_assign('python_version_deprecated', str(rel_info.deprecated_version)) # Update Script/Main.py - t = UpdateFile(os.path.join('SCons', 'Script', 'Main.py')) - if DEBUG: t.file = '/tmp/Main.py' + if DEBUG: + t.file = '/tmp/Main.py' t.replace_assign('unsupported_python_version', str(rel_info.unsupported_version)) t.replace_assign('deprecated_python_version', str(rel_info.deprecated_version)) - # Update doc/user/main.{in,xml} - + # Update doc/user/main.xml docyears = '2004 - %d' % rel_info.release_date[0] - if os.path.exists(os.path.join('doc', 'user', 'main.in')): - # this is no longer used as of Dec 2013 - t = UpdateFile(os.path.join('doc', 'user', 'main.in')) - if DEBUG: t.file = '/tmp/main.in' - ## TODO debug these - # t.sub('[^<]*', '' + docyears + '') - # t.sub('[^<]*', '' + docyears + '') - t = UpdateFile(os.path.join('doc', 'user', 'main.xml')) - if DEBUG: t.file = '/tmp/main.xml' - t.sub('[^<]*', '' + docyears + '') + if DEBUG: + t.file = '/tmp/main.xml' + t.sub('[^<]*', 'Released: ' + rel_info.new_date + '') t.sub('[^<]*', '' + docyears + '') # Write out the last update diff -Nru scons-4.0.1+dfsg/bin/upload-release-files.sh scons-4.4.0+dfsg/bin/upload-release-files.sh --- scons-4.0.1+dfsg/bin/upload-release-files.sh 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/bin/upload-release-files.sh 2022-07-30 21:48:28.000000000 +0000 @@ -18,7 +18,7 @@ # the build products are here: cd build/dist cp -f ../../CHANGES.txt ../../RELEASE.txt . -cp -f ../../README-sf.rst ./README.rst +cp -f ../../README-SF.rst ./README.rst set -x @@ -30,8 +30,8 @@ # Upload main scons release files: $RSYNC $RSYNCOPTS \ - scons-$VERSION.tar.gz \ - scons-$VERSION.zip \ + SCons-$VERSION.tar.gz \ + SCons-$VERSION.zip \ CHANGES.txt RELEASE.txt \ $SF_USER@$SF_MACHINE:$SF_TOPDIR/scons/$VERSION/ diff -Nru scons-4.0.1+dfsg/CHANGES.txt scons-4.4.0+dfsg/CHANGES.txt --- scons-4.0.1+dfsg/CHANGES.txt 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/CHANGES.txt 2022-07-30 21:48:28.000000000 +0000 @@ -5,8 +5,641 @@ Change Log NOTE: The 4.0.0 Release of SCons dropped Python 2.7 Support +NOTE: 4.3.0 now requires Python 3.6.0 and above. Python 3.5.x is no longer supported -RELEASE 4.0.1 - Thu, 16 Jul 2020 15:04:42 -0700 +RELEASE 4.4.0 - Sat, 30 Jul 2022 14:08:29 -0700 + + From Joseph Brill: + - Verify that a user specified msvc script (via MSVC_USE_SCRIPT) exists and raise an exception + when the user specified msvc script does not exist. + - Fix issue where if you only had mingw installed on a Windows system and no MSVC compiler, and + did not explicitly request the mingw tool, mingw tool initialization would fail and set the + default compiler to MSVC which wasn't installed, yielding broken build. + Updated mingw tool so that the generate and exists methods use the same mingw search paths + (issue #4134). + - Update the debug output written to stdout for MSVC initialization which is enabled by setting + SCONS_MSCOMMON_DEBUG=- to use the logging module. Also changed the debug output format + written to stdout to include more information about the source for each message of MSVC + initialization debugging output. A single space was added before the message for all + debugging output records written to stdout and to files. + - Refactor the data definitions for msvc configurations to allow derived data structures to be + constructed during initialization that removes the need for special case handling during + runtime execution. Special case handling of host/target combinations is eliminated and + replaced with pre-computed search lists that implicitly handle the differences between full + versions and express versions of msvc. This fixes an issue where Express versions of the MSVC + compiler were not detected due to differences in initial msvc detection and msvc batch file + determination when configuring the build environment. This could lead to build failures when + only an MSVC Express instance is installed and the MSVC version is not explicitly specified + (issue #2668 and issue #2697). + - Added MSVC_USE_SETTINGS construction variable to pass a dictionary to configure the msvc compiler + system environment as an alternative to bypassing Visual Studio autodetection entirely. + - Added MSVC_SDK_VERSION construction variable which allows building with a specific Microsoft + SDK version. This variable is used with the msvc batch file determined via autodetection subject + to validation constraints. Refer to the documentation for additional requirements and validation + details. + - Added MSVC_TOOLSET_VERSION construction variable which allows building with a specific toolset + version. This variable is used with the msvc batch file determined via autodetection subject to + validation constraints. This variable does not affect the autodetection and selection of msvc + instances. The toolset version is applied after an msvc instance is selected. This could be the + default version of msvc. Refer to the documentation for additional requirements and validation + details. Addresses issue #3265, issue #3664, and pull request #4149. + - Added MSVC_SPECTRE_LIBS construction variable which allows building with spectre-mitigated + Visual C++ libraries. This variable is used with the msvc batch file determined via autodetection + subject to validation constraints. Refer to the documentation for additional requirements and + validation details. + - Added MSVC_SCRIPT_ARGS construction variable which specifies command line arguments that are + passed to the msvc batch file determined via autodetection subject to validation constraints. + Refer to the documentation for additional requirements and validation details. Addresses + enhancement issue #4106. + - An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier. + Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013 + and earlier. Refer to the documentation for additional requirements and validation details. + MSVC_UWP_APP was extended to accept True, False, and None in addition to '1' and '0'. + - The imported system environment variable names for MSVC 7.0 and 6.0 have been changed to the + names set by their respective installers. Prior to this change, bypassing MSVC detection by + specifying the MSVC 7.0 batch file directly would fail due to using an erroneous environment + variable name. Arguments are no longer passed to the MSVC 6.0 to 7.1 batch files as no + arguments are required and could improve the effectiveness of the internal MSVC cache. + - Propagate the OS and windir environment variables from the system environment to the msvc + environment. The OS and windir environment variables are used in the MSVC 6.0 batch file + and the SDK 6.0-7.1 SetEnv.cmd batch files. Inclusion of the OS and windir environment + variables eliminates some partial paths and warnings generated by the MSVC 6.0 and SDK + 6.0-7.1 batch files when the variables are not defined. + Note: Attempting to run the SDK 6.0-7.1 batch files directly via MSVC_USE_SCRIPT can lead to + build failures and/or incomplete build environments. The SDK 6.0-7.1 batch files + require delayed expansion to be enabled which is currently not supported and is + typically not enabled by default on the host system. The batch files may also require + environment variables that are not included by default in the msvc environment. + - Suppress issuing a warning when there are no installed Visual Studio instances for the default + tools configuration (issue #2813). When msvc is the default compiler because there are no + compilers installed, a build may fail due to the cl.exe command not being recognized. At + present, there is no easy way to detect during msvc initialization if the default environment + will be used later to build a program and/or library. There is no error/warning issued for the + default tools as there are legitimate SCons uses that do not require a c compiler. + - Added a global policy setting and an environment construction variable for specifying the + action to be taken when an msvc request cannot be satisfied. The available options are "error", + "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be + set and retrieved via the functions msvc_set_notfound_policy and msvc_get_notfound_policy, + respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment + construction variable is MSVC_NOTFOUND_POLICY. When defined, the environment construction + variable overrides the global policy setting for a given environment. When the active policy + is "error" or "exception", an MSVCVersionNotFound exception is raised. When the active policy + is "warning" or "warn", a VisualCMissingWarning warning is issued and the constructed + environment is likely incomplete. When the active policy is "ignore" or "suppress", no action + is taken and the constructed environment is likely incomplete. As implemented, the default + global policy is "warning". The ability to set the global policy via an SCons command-line + option may be added in a future enhancement. + - Added a global policy setting and an environment construction variable for specifying the + action to be taken when msvc script errors are detected. The available options are "error", + "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be + set and retrieved via the functions msvc_set_scripterror_policy and msvc_get_scripterror_policy, + respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment + construction variable is MSVC_SCRIPTERROR_POLICY. When defined, the environment construction + variable overrides the global policy setting for a given environment. When the active policy + is "error" or "exception", an MSVCScriptExecutionError exception is raised when msvc batch file + errors are detected. When the active policy is "warning" or "warn", an MSVCScriptExecutionWarning + warning is issued when msvc batch file errors are detected. When the active policy is "ignore" or + "suppress", msvc batch error messages are suppressed. As implemented, the default global policy + is "ignore". The ability to set the global policy via an SCons command-line option may be added + in a future enhancement. + - Added experimental function msvc_query_version_toolset to SCons.Tool.MSCommon. Given a version + specification, this function will return an msvc version and an msvc toolset version. The msvc + toolset version may be None. The msvc version and msvc toolset version can be used in the + environment construction variables MSVC_VERSION and MSVC_TOOLSET_VERSION, respectively. The + version specification may be an msvc version or an msvc toolset version. This is a proxy for + using an msvc toolset version to select an msvc instance. This function may be removed when an + msvc toolset version is used during msvc instance selection. + - Modify the MSCommon logger configuration to be independent of the root logger. This fixes an issue + when multiple loggers are created and the MSCommon logger added computed fields to the root logger + that are not present in other logging instances. + - Modify the MSVC_USE_SCRIPT_ARGS test fixture to disable the msvc cache. This fixes an issue where + the MSVC_USE_SCRIPT_ARGS test for success relied on a debug log message that was not produced when + the msvc cache file exists and the test keys are already in the cache as the msvc script invocation + was bypassed. + + From William Deegan: + - Fix check for unsupported Python version. It was broken. Also now the error message + will include what is the minimum supported version of Python + - Fix ActionTests to work with python 3.10.1 (and higher) + NOTE: If you build with Python 3.10.0 and then rebuild with 3.10.1 (or higher), you may + see unexpected rebuilds. This is due to Python internals changing which changed + the signature of a Python Action Function. + - Fix a number of Python ResourceWarnings which are issued when running SCons and/or it's tests + with python 3.9 (or higher) + - Action._subproc() can now be used as a python context manager to ensure that the + POpen object is properly closed. + (Thanks to Mats Wichmann for catching that DummyPopen needed additional logic) + - Added project_url for mailing lists and Discord + - Updated project url in steup.cfg to be https instead of http + - Updated setup.cfg to remove Python 3.5 and add Python 3.10 + - Added default values for source and target arguments to _defines() function. This + is used to expand CPPDEFINES (and others). Previous change added those arguments + with no defaults, so old usage where _defines() was called without source and target + arguments would yield an exception. This issue was found via qt4 and qt5 tools in + scons-contrib https://github.com/SCons/scons-contrib/issues/45 + + From David H: + - Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. + - Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. + + From Daniel Moody: + - Add cache-debug messages for push failures. + - Ninja: Changed generated build.ninja file to run SCons only build Actions via + a SCons Deamon. Added logic for starting and connecting to SCons daemon (currently + only used for ninja) + - Ninja: Fix issue where Configure files weren't being properly processed when build run + via ninja. + - Ninja: Added ninja mingw support and improved ninja CommandGeneratorAction support. + - Ninja: Update ninja file generation to only create response files for build commands + which exceed MAXLINELENGTH + - Ninja: Added NINJA_GENERATED_SOURCE_ALIAS_NAME which allows user to specify an + Alias() which the ninja tool can use to determine which files are generated sources. + If this is not set by the user then the ninja tool will still dynamically determine + which files are generated sources based on NINJA_GENERATED_SOURCE_SUFFIXES, and create + a phony target _ninja_generated_sources. Generated sources will be built first by + ninja. This is needed because ninja cannot determine which generated sources are + required by other build targets. Code contributed by MongoDB + The downstream commit is here: + https://github.com/mongodb/mongo/commit/2fef432fa6e7cf3fd4f22ba3b193222c2887f14f + - Ninja: Added special case for ninja scons daemon to work in win32 python3.6 environments. + This particular environment does a bad job managing popen standard file handles, so + some special workarounds are needed. + - Ninja:Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT. + Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected + format. Compiler tools will also configure the variable automatically. + - Ninja: Made ninja tool force the ninja file as the only target. + - Ninja: Improved the default targets setup and made sure there is always a default target for + the ninja file, which excludes targets that start and stop the daemon. + - Ninja: Update ninja tool so targets passed to SCons are propagated to ninja when scons + automatically executes ninja. + - Small refactor of scons daemons using a shared StateInfo class for communication + between the scons interactive thread and the http server thread. Added error handling + for scons interactive failing to startup. + - Ninja: Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log. + - Ninja: Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry + - Added SHELL_ENV_GENERATORS construction variable. This variable should be set to a list + (or an iterable) which contains functions to be called in order + when constructing the execution environment (Generally this is the shell environment + variables). This allows the user to customize how (for example) PATH is constructed. + Note that these are called for every build command run by SCons. It could have considerable + performance impact if not used carefully. + to connect to the server during start up. + - lex: Fixed an issue with the lex tool where file arguments specified to either "--header-file=" + or "--tables-file=" which included a space in the path to the file would be processed incorrectly + - Ninja: added option "--skip-ninja-regen" to enable skipping regeneration of the ninja file + if scons can determine the ninja file doesnot need to be regenerated, which will also + skip restarting the scons daemon. Note this option is could result in incorrect rebuilds + if scons Glob or scons generated files are used in ninja build target's command lines. + - Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon. + Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs. + NOTE: Test for this requires python psutil module. It will be skipped if not present. + - Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args. + This can also be set in your Environment(). + + From Mats Wichmann: + - Tweak the way default site_scons paths on Windows are expressed to + conform to conventions (what they actually resolve to is unchanged), + drop a Py2 workaround, and pick a better "system" path, old one + remains supported (%AllUsersProfile%\scons\site_scons vs old + %AllUsersProfile%\Application Data\scons\site_scons). + - Fix testsuite to work on Windows systems where there is no usable + association for running .py files directly. There are a few tests where + we need to do this for internal reasons, those are skipped in that case. + Bad association could mean some other tool took it over (Visual + Studio Code is known to do this), or no association at all. + - Updated debug code in MSVC and MSVS tools to conform to the + suggested "lazy interpolation" use of the Python logging module. + Calls now look like 'debug("template %s", text)' rather than + 'debug("template %s" % text)' so the logging system does the + interpolation only when/if needed (was a pylint warning). + - Update Help (-H) output a bit. Drop "ignored for compat" entry. + Pass window size to formatter so it formats for wider displays too. + - runtest.py now accepts -j 0 to auto-detect number of usable + processors for testing threads. + - Fixed crash in C scanner's dictify_CPPDEFINES() function which happens if + AppendUnique is called on CPPPATH. (Issue #4108). + - The MSVC script_env_cache now contains a sanity check: if the retrieved + tools path does not exist, the entry is invalidated so it will + be recomputed, in an attempt to avoid scons failing when certain + compiler version bumps have taken place. The dictionary key (uses + the name of a batch file and any arguments which may have been + passes), is now computed a bit differently: the dashes are left + off if there are no arguments. The default cachefile is changed + to have a .json suffix, for better recognition on Windows since + the contents are json. + - As "code modernization" all of SCons now uses the current super() + zero-argument syntax instead of direct calls to a parent class method + or the super() two-argument syntax. + - Renamed ParseFlag's internal data structure to "mapping" instead of + "dict" (avoid redefining builtin) + - Fix an old use-before-set bug in tex tool (issue #2888) + - Fix a test harness exception returning stderr if a wait_for timed out. + - ParseConfig now correctly passes the *unique* flag to a user-supplied + flag-merging function. + - Restore the ability of the content-timestamp decider to see that a + a source which is a symlink has changed if the file-system target of + that link has been modified (issue #3880) + - Modernize a few tests that use now-deprecated unittest.getTestCaseNames + and unittest.makeSuite - Python itself suggests the replacements. + - SCons.Tool.find_program_path now takes an optional add_path argument + to add a path to the execution environment if it was discovered in + default_paths. Previously, the routine, called by many tool modules, + never altered the execution environment, leaving it to the tools. + - A new construction variable FORTRANCOMMONFLAGS is added which is + applied to all Fortran dialects, in case someone needs to set some + flags globally. FORTRANFLAGS looked like it was intended for that, + but was not applied to other dialects, and e2e tests explicitly checked + that FORTRANFLAGS did not propagate outside the FORTRAN dialect, + so the conclusion is that behavior is intentional (issue #2257) + - SCons programmatic importing (tool modules and platform modules) + no longer uses the deprecated (since Py 3.10) importlib.load_module + routine, shifting to the preferred exec_module. Old Python 2 compatible + import fallback (using the imp module) in tool module loading is dropped. + Tool module loading no longer special-cases Jython, which is a dead + project as far as SCons (no timeline in sight for Python 3 support). + - Improvements to lex and yacc tools: better documentation of + extra-file options, add test for extra-file behavior. + - Two new construction variables are introduced for lex (LEX_HEADER_FILE + and LEX_TABLES_FILE) as the preferred way of specifying these extra-file + options. + - Two new construction variables are introduced for yacc + (YACC_HEADER_FILE and YACC_GRAPH_FILE) as the preferred way of + specifying these extra-file options. + + + From Zhichang Yu: + - Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT. + - Added Configure.CheckMember() checker to check if struct/class has the specified member. + + From Ivan Kravets, PlatformIO: + - Conditional C/C++ Preprocessor: Strip shell's backslashes from the computed include (-DFOO_H=\"foo.h\") + +RELEASE 4.3.0 - Tue, 16 Nov 2021 18:12:46 -0700 + + From Jacob Cassagnol: + - Default hash algorithm check updated for SCons FIPS compliance. Now checks for hash viability + first and then walks the tree to use the first viable hash as the default one. This typically + selects SHA1 on FIPS-enabled systems less than Python 3.9 as the new default instead of MD5, + unless SHA1 has also been disabled by security policy, at which point SCons selects SHA256 + as the default. For systems running Python 3.9 and later, the hashlib bug has been fixed, + and SCons will once again default to MD5 as the preferred algorithm. + + From Joseph Brill: + - Fix MSVS tests (vs-N.N-exec.py) for MSVS 6.0, 7.0, and 7.1 (import missing module). + - Add support for Visual Studio 2022. + + From William Deegan: + - Fix reproducible builds. Restore logic respecting SOURCE_DATE_EPOCH when set. + - Fix version tests to work with updated scons --version output. (Date format changed) + - Fix issue #4021. Change the way subst() is used in Textfile() to not evaluate '$$(' -> '$', + but instead it should yield '$('. + - Change SCons.Platform.win32.get_architecture() to return platform.platform() when run in an + environment where neither: PROCESSOR_ARCHITEW6432 nor PROCESSOR_ARCHITECTURE is set. + This should fix platform tests which started failing when HOST_OS/HOST_ARCH changes + introduced by Aaron Franke (listed below) were merged. + - Further PCH updates. It's now recommended that env['PCH'] should always be a File node. + Either via return value from env.PCH() or by explicitly using File('StdAfx.pch'). + - Added --no-ignore-skips to runtest.py. Changed default to ignore skips when setting + runtest.py's exit status. Previously would exit 2 if any tests were skipped. + Now will only exit 2 if user specifies --no-ignore-skips and some tests were skipped. + + From Ryan Egesdahl: + - Small fix to ensure CLVar default value is an empty list. + See MongoDB bug report: https://jira.mongodb.org/browse/SERVER-59656 + Code contributed by MongoDB. + - Ninja - Fixed an issue where if you control-c and/or killed ninja while it was running scons to + regenerate build.ninja you would end up with no build.ninja file and have to rerun scons from scratch. + Code contributed by MongoDB. + + From Aaron Franke: + - Define HOST_OS and HOST_ARCH in the environment for all platforms. + Before this change, these were only defined for Win32 and OS/2. + + From Daniel Moody: + - Fix ninja tool to never use for_sig substitution because ninja does not use signatures. This + issue affected CommandGeneratorAction function actions specifically. + - Expanded ninja Mkdir to also support Mkdir actions. + - Added support for the PCH environment variable to support subst generators. + - Fix command line escaping for ninja dollar sign escape. Without escaping ninja properly, + the ninja file scons regenerate and callback invocations will lose the $ characters used in + the scons command line which ninja uses itself for escaping. For Example: + scons BUILD=xyz OTHERVAR=$BUILD + Prior to this fix, it would cause ninja to fail to escape the dollar sign, leading to the + single dollar sign being used as a ninja escape character in the ninja file. + + From Daniel Moody: + - Added ninja API 'NINJA_FORCE_SCONS_BUILD' to force a node to callback to scons. + + From Mats Wichmann: + - Two small Python 3.10 fixes: one more docstring turned into raw + because it contained an escape; updated "helpful" syntax error message + from 3.10 was not expected by SubstTests.py and test/Subst/Syntax.py + - EmitterProxy rich comparison set is completed (checker warning). + Added __le__, __gt__, __ge__. + - Fix gcc/g++ tool failing if "gcc --version" returns text which fails + to_String conversion (i.e., not UTF-8) - failure happens when tool + initialization checks version. For gcc, the initial version string is + not translated, for the rest, don't convert, just consume raw and discard. + - Maintenance and doc: modernize some usage in Scanner package, + calling super(), switching some imitialization to comprehensions, + and code formatting. Docstring for scanner Base moved from + init-method to class-level so it's picked up by Sphinx. + Added new sconsign filenames to skip_entry_list in Scanner/Dir.py + - Change SCons.Scanner.Base to ScannerBase. Old name kept as an alias + but is now unused in SCons itself. + - Call Variables option converter consistently - the converter should + have access to the env if it needs to (issue #2064). + - Fixed the variables Add() method to accept a tuple for the variable + name the same way AddVariables() does (issue #3869). + - The premade validator PathIsDirCreate for for PathVariable now catches + the case where the directory could not be created due to permission + problems, allowing a more helpful error to be emitted (issue #2828) + - Maintenance: Python thread.setDaemon is deprecated in favor of + directly updating daemon attribute - update SCons to do this. + - Make sure when subst'ing a callable, the callable is called with + the correct for_signature value, previously it would be true even + if doing SUBST_RAW (issue #4037) + - Update Util/NodeList implementation to get rid of a workaround for + early Python 3 slicing issue that is no longer a problem. + - Rework some Java tests to skip rather than fail on CI systems, where + the working java is > v9, but a 1.8 or 9 was also found. + - Java updates: on Windows, detect more default JDK install locations. + On all platforms, more Java versions (up to 17.0 now). Add more information + on version selection to docs. + Update docs on JavaH tool in light of javah command dropped since 10.0. + Try to be better about preserving user's passed-in JAVA* construction vars. + - Start the deprecation of the qt tool, which refers to Qt3 (usupported + since around 2006). There's a deprecation warning added, initially + defaulting to disabled. + + From Brian Quistorff: + - Fix crash when scons is run from a python environement where a signal + is set from outside Python. + + +RELEASE 4.2.0 - Sat, 31 Jul 2021 18:12:46 -0700 + + From Byron Platt: + - Fix Install() issue when copytree recursion gives bad arguments that can + lead to install side-effects including keeping dangling symlinks and + silently failing to copy directories (and their subdirectories) when the + directory already exists in the target. + + From Joseph Brill: + - Internal MSVS update: Remove unnecessary calls to find all installed versions of msvc + when constructing the installed visual studios list. + + From William Deegan: + - Improve Subst()'s logic to check for proper callable function or class's argument list. + It will now allow callables with expected args, and any extra args as long as they + have default arguments. Additionally functions with no defaults for extra arguments + as long as they are set using functools.partial to create a new callable which set them. + - Fix Issue #3035 - mingw with SHLIBVERSION set fails with either not a dll error or + "Multiple ways to build the same target were specified for:". Now mingw will disable + creating the symlinks (and adding version string to ) dlls. It sets SHLIBNOVERSIONSYMLINKS, + IMPLIBNOVERSIONSYMLINKS and LDMODULENOVERSIONSYMLINKS to True. + - Added --experimental flag, to enable various experimental features/tools. You can specify + 'all', 'none', or any combination of available experimental features. + - Fix Issue #3933 - Remove unguarded print of debug information in SharedLibrary logic when + SHLIBVERSION is specified. + - Fix versioned shared library naming for MacOS platform. (Previously was libxyz.dylib.1.2.3, + has been fixed to libxyz.1.2.3.dylib. Additionally the sonamed symlink had the same issue, + that is now resolved as well) + - Add experimental ninja builder. (Contributed by MongoDB, Daniel Moody and many others). + - Fix #3955 - _LIBDIRFLAGS leaving $( and $) in *COMSTR output. Added affect_signature flag to + _concat function. If set to False, it will prepend and append $( and $). That way the various + Environment variables can use that rather than "$( _concat(...) $)". + - Fix issue with exparimental ninja tool which would fail on windows or when ninja package wasn't + installed but --experimental=ninja was specified. + - As part of experimental ninja tool, allow SetOption() to set both disable_execute_ninja and + disable_ninja. + + From David H: + - Fix Issue #3906 - `IMPLICIT_COMMAND_DEPENDENCIES` was not properly disabled when + set to any string value (For example ['none','false','no','off']) + Also previously 'All' wouldn't have the desired affect. + + From Ivan Kravets: + - Provide a custom argument escape function for `TempFileMunge` using a new + `TEMPFILEARGESCFUNC` variable. Useful if you need to apply extra operations on + a command argument before writing to a temporary file (fix Windows slashes, + normalize paths, etc.) + + From Henrik Maier: + - DocbookXslt tool: The XSLT stylesheet file is now initialized to an env.File() Node, + such that dependencies work correctly in hierarchical builds (eg when using + DocbookXslt in SConscript('subdir/SConscript') context. + + From Daniel Moody: + - Update CacheDir to use uuid for tmpfile uniqueness instead of pid. + This fixes cases for shared cache where two systems write to the same + cache tmpfile at the same time because the happened to get the same pid. + - Added support for passing custom CacheDir derived classes to SCons. Moved + copy_from_cache attribute from the Environment class to CacheDir class. + Code contributed by MongoDB. + - Update BuildTask to pass all targets to the progress object fixing an issue + where multi-target build nodes only got the first target passed to the progress + object. + - Fix a potential race condition in shared cache environments where the permissions are + not writeable for a moment after the file has been renamed and other builds (users) will copy + it out of the cache. Small reorganization of logic to copy files from cachedir. Moved CacheDir + writeable permission code for copy to cache behind the atomic rename operation. + - Added marking of intermediate and and multi target nodes generated from SConf tests so that + is_conftest() is more accurate. + - Added test for configure check failing to ensure it didn't break generating and running ninja. + + + From Mats Wichmann: + - Initial support in tests for Python 3.10 - expected bytecode and + one changed expected exception message. Change some more regexes + to be specified as rawstrings in response to DeprecationWarnings. + - Add an example of adding an emitter to User Guide (concept + from Jeremy Elson) + - Add timing information for sconsign database dump when --debug=time + is selected. Also switch to generally using time.perf_counter, + which is the Python recommended way for timing short durations. + - Drop remaining definitions of dict-like has_key methods, since + Python 3 doesn't have a dictionary has_key (maintenance) + - Do not treat --site-dir=DIR and --no-site-dir as distinct options. + Allows a later instance to override an earlier one. + - Ignore empty cmdline arguments when computing targets (issue 2986) + - Remove long-deprecated construction variables PDFCOM, WIN32_INSERT_DEF, + WIN32DEFPREFIX, WIN32DEFSUFFIX, WIN32EXPPREFIX, WIN32EXPSUFFIX. + All have been replaced by other names since at least 1.0. + - Add a __iadd__ method to the CLVar class so that inplace adds + (+=) also work as expected (issue 2399) + - Remove local copy of CLVar in EnvironmentTests unittest file - + should be testing against the production version, and they + didn't really differ. + - Don't strip spaces in INSTALLSTR by using raw subst (issue 2018) + - Deprecate Python 3.5 as a supported version. + - CPPDEFINES now expands construction variable references (issue 2363) + - Restore behavior that Install()'d files are writable (issue 3927) + - Simplified Mkdir(), the internal mkdir_func no longer needs to handle + existing directories, it can now pass exist_ok=True to os.makedirs(). + - Avoid WhereIs exception if user set a tool name to empty (from issue 1742) + - Maintenance: remove obsolete __getslice__ definitions (Py3 never calls); + add Node.fs.scandir to call new (Py3.5) os.scandir; Node.fs.makedirs + now passes the exist_ok flag; Cachedir creation now uses this flag. + - Maintenance: remove unneeded imports and reorganize some. Fix uses + of warnings in some tools which instantiated the class but did nothing + with them, need to instead call SCons.Warnings.warn with the warn class. + - Drop overridden changed_since_last_build method in Value class. + - Resync the SetOption implementation and the manpage, making sure new + options are available and adding a notes column for misc information. + SetOption equivalents to --hash-chunksize, --implicit-deps-unchanged + and --implicit-deps-changed are enabled. + - Add tests for SetOption failing on disallowed options and value types. + - Maintenance: eliminate lots of checker complaints about Util.py. + - Maintenance: fix checker-spotted issues in Environment (apply_tools) + and EnvironmentTests (asserts comparing with self). + For consistency, env.Tool() now returns a tool object the same way + Tool() has done. + - Change SConscript() missing SConscript behavior - if must_exist=False, + the warning is suppressed. + - Make sure TEMPFILEPREFIX can be set to an empty string (issue 3964) + + From Dillan Mills: + - Add support for the (TARGET,SOURCE,TARGETS,SOURCES,CHANGED_TARGETS,CHANGED_SOURCES}.relpath property. + This will provide a path relative to the top of the build tree (where the SConstruct is located) + Fixes #396 + + From Andrew Morrow: + - Fix issue #3790: Generators in CPPDEFINES now have access to populated source + and target lists + +RELEASE 4.1.0 - Tues, 19 Jan 2021 15:04:42 -0700 + + From James Benton: + - Add COMPILATIONDB_PATH_FILTER env option for CompilationDatabase() builder which allows + filtering of entries based on the output file paths using glob style file matching (issue #3742). + + 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` + - Completely rewrote versioned shared libraries logic. Added support for SOVERSION via dmoody's initial PR #3733 + - No longer automatically disable setting SONAME on shared libraries on OpenBSD. + - Fix race condition bug when initializing a scons cache directory at the + same time from multiple threads or processes. Problem described in PR #3114. + This is a simpler fix which should avoid some problems identified with the initial PR. + (Credit to Fredrik Medley for reporting the issue, the initial PR, and discussing and testing + this solution) + - Minor edits to User Guide and manpage's header with copyright, released date changed. + + 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 are: `md5`, `sha1`, and `sha256`. For all hash formats other than + the default of `md5`, the SConsign database will include the name of the hash format. + For example, `--hash-format=sha256` will create a SConsign with name + `.sconsign_sha256.dblite.`. + - Fix incorrect cache hits and/or misses when running in interactive mode by having + SCons.Node.Node.clear() clear out all caching-related state. + - Change Environment.SideEffect() to not add duplicate side effects. + NOTE: The list of returned side effect Nodes will not include any duplicate side effect Nodes. + - Add support to the Python scanner for finding dynamically generated dependencies. + Previously the scanner only found imports if they existed on disk at scanning time. + + From David H: + - Add ZIP_OVERRIDE_TIMESTAMP env option to Zip builder which allows for overriding of the file + modification times in the archive. + - Fix Zip builder not rebuilding when ZIPROOT env option was changed. + + From Jason Kenny + - Fix python3 crash when Value node get_text_content when child content does not have decode() + NOTE: If you depend on Value node's get_text_content returning concatenated contents of it's + children. This may break your code. It now concatenates the csig() of all children. + + 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 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. + + 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 + - Rework runtest.py to use argparse for arg handling (was a mix + of hand-coded and optparse, with a stated intent to "gradually port"). + - Add options to runtest to generate/not generate a log of failed tests, + and to rerun such tests. Useful when an error cascades through several + tests, can quickly try if a change improves all the fails. Dropped + runtest test for fallback from qmtest, not needed; added new tests. + - Eliminate tex tool usage of "for foo in range(len(iterable))" + - Restore internal Trace function to functional state. + - Only try to initialize the wix tool by default (or when tool `default` is explicitly installed) + on Windows based systems. + - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools + - Use os.replace instead of os.rename in dblite so don't need to + special-case Windows here. dblite is the default storage engine for the SConsign file(s). + - Fix cut-n-paste error in msvc debug printout and make some debug output + in msvs and msvsTests.py be off until needed (uncomment to use) + - Fix Issue #3014 - Empty file and missing file have same csig + - Refactor env.Append/Prepend to remove Py 1.5 era need to nest + try blocks, can now "continue" at the appropriate places. + - Add /snap/bin to env['PATH'] on POSIX, although this is only + really useful for a subset of POSIX systems that use snaps. + Was needed for CI builds, which run on Ubuntu LTS images. + - Eliminate Py2-ism __nonzero__ (now __bool__). Work around issue #3860 + where a check for BuilderBase raising exc. on __bool__ was optimized out. + This issue was found due to a bug in Python 3.10.0a4. See issue #3860 for details. + + +RELEASE 4.0.1 - Mon, 16 Jul 2020 16:06:40 -0700 From Rob Boehne: - Fix fortran tools to set SHFORTRAN variables to $FORTRAN, similarly SHF77, SHF90, SHF95, @@ -23,6 +656,9 @@ - Added Environment() variable TEMPFILEDIR which allows setting the directory which temp files createdby TEMPFILEMUNGE are created in. + From Daniel Moody: + - Added method on Node to test if its node used in SConf. (Github Issue #3626) + RELEASE 4.0.0 - Sat, 04 Jul 2020 12:00:27 +0000 @@ -32,6 +668,7 @@ removed libxslt support from the Docbook Tool. (issue #3580) - Added Docker images for building and testing SCons. (issue #3585) + From James Benton: - Improve Visual Studio solution/project generation code to add support for a per-variant cppflags. Intellisense can be affected by cppflags, @@ -46,7 +683,7 @@ From Joseph Brill: - MSVC updates: When there are multiple product installations (e.g, Community and - Build Tools) of MSVC 2017 or MSVC 2019, an Enterprise, Professional, + Build Tools) of MSVC 2017 or MSVC 2019, an Enterprise, Professional, or Community installation will be selected before a Build Tools installation when "14.1" or "14.2" is requested, respectively. (GH Issue #3699). - MSVC updates: When there are multiple product installations of MSVC 2017 (e.g., @@ -60,7 +697,7 @@ - Test update: Reduce the number of "false negative" test failures for the interactive configuration test (test/interactive/configure.py). - MSVS update: Fix the development environment path for MSVS 7.0. - + From William Deegan: - Fix broken clang + MSVC 2019 combination by using MSVC configuration logic to propagate'VCINSTALLDIR' and 'VCToolsInstallDir' which clang tools use to locate @@ -77,9 +714,9 @@ - Add msys2 installed mingw default path to PATH for mingw tool. - C:\msys64\mingw64\bin - Purge obsolete internal build and tooling scripts - - Allow user specified location for vswhere.exe specified by VSWHERE. + - Allow user specified location for vswhere.exe specified by VSWHERE. NOTE: This must be set at the time the 'msvc' 'msvs' and/or 'mslink' tool(s) are initialized to have any effect. - - Resolve Issue #3451 and Issue #3450 - Rewrite SCons setup.py and packaging. Move script logic to entry points so + - Resolve Issue #3451 and Issue #3450 - Rewrite SCons setup.py and packaging. Move script logic to entry points so package can create scripts which use the correct version of Python. - Resolve Issue #3248 - Removing '-Wl,-Bsymbolic' from SHLIBVERSIONFLAGS NOTE: If your build depends on the above you must now add to your SHLIBVERSIONFLAGS @@ -133,16 +770,16 @@ that instructs scons to use single line drawing characters to draw the dependency tree. From Daniel Moody: - - Add no_progress (-Q) option as a set-able option. However, setting it in the + - Add no_progress (-Q) option as a set-able option. However, setting it in the SConstruct/SConscript will still cause "scons: Reading SConscript files ..." to be printed, since the option is not set when the build scripts first get read. - Added check for SONAME in environment to setup symlinks correctly (Github Issue #3246) - - User callable's called during substition expansion could possibly throw a TypeError - exception, however SCons was using TypeError to detect if the callable had a different - signature than expected, and would silently fail to report user's exceptions. Fixed to + - User callable's called during substition expansion could possibly throw a TypeError + exception, however SCons was using TypeError to detect if the callable had a different + signature than expected, and would silently fail to report user's exceptions. Fixed to use signature module to detect function signature instead of TypeError. (Github Issue #3654) - Added storage of SConstructs and SConscripts nodes into global set for checking - if a given node is a SConstruct/SConscript. + if a given node is a SConstruct/SConscript. Added new node function SCons.Node.is_sconscript(self) (Github Issue #3625) From Andrew Morrow: @@ -225,6 +862,8 @@ dir_fixture. - SubstitutionEnvironment and OverrideEnvironment now have keys() and values() methods to better emulate a dict (already had items()). + - Rename internal Warning base class to SConsWarning to avoid any + possible confusion with Python's own Warning class. RELEASE 3.1.2 - Mon, 17 Dec 2019 02:06:27 +0000 @@ -383,6 +1022,9 @@ From Lukas Schrangl: - Enable LaTeX scanner to find more than one include per line + From Sergey Torokhov: + - Recognize jdk on Gentoo systems. + From Mats Wichmann: - scons-time takes more care closing files and uses safer mkdtemp to avoid possible races on multi-job runs. diff -Nru scons-4.0.1+dfsg/.codecov.yml scons-4.4.0+dfsg/.codecov.yml --- scons-4.0.1+dfsg/.codecov.yml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.codecov.yml 2022-07-30 21:48:28.000000000 +0000 @@ -19,7 +19,7 @@ notify: irc: default: - server: "chat.freenode.net#scons" + server: "irc.libera.chat#scons" branches: master threshold: null message: "Coverage {{changed}} for {{owner}}/{{repo}}" # customize the message diff -Nru scons-4.0.1+dfsg/CONTRIBUTING.md scons-4.4.0+dfsg/CONTRIBUTING.md --- scons-4.0.1+dfsg/CONTRIBUTING.md 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -# Contributing to SCons - -First off, thanks for taking the time to contribute! - -Here are some pointers to get started, before more information gets moved here to this page. - - * [Bugs and Feature Requests](https://scons.org/bugs.html) - * [Development](https://scons.org/dev.html) - * [SCons Developer's Guidelines](https://scons.org/guidelines.html) - -Various resources to contact are here: - - * [Contacts](https://scons.org/contact.html) diff -Nru scons-4.0.1+dfsg/CONTRIBUTING.rst scons-4.4.0+dfsg/CONTRIBUTING.rst --- scons-4.0.1+dfsg/CONTRIBUTING.rst 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/CONTRIBUTING.rst 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,535 @@ +Contributing to SCons +##################### + +Introduction +=========== + +Thanks for taking the time to contribute to SCons! + +This will give a brief overview of the development process, +and about the SCons tree (right here, if you're reading this +in Github, or in a cloned repository). + +There are lots of places we could use help - please don't +think we're only interested in contributions to code. + +If you're going to contribute, we'd love to get to know you +a bit and understand and what problems you're looking to solve, +or what you are intending to improve, whether that's documentation, +code, examples, tutorials, etc. A great way to introduce yourself is to +to hop onto the `SCons Discord Server `_ +to chat. You don't have to be a regular Discord user, +there is a web interface. + +Resources +========= + +Here are some important pointers to other resources: + + * `SCons Home Page `_ + * `Github Project Page `_ + * `Bugs and Feature Requests `_ + * `Development `_ + * `SCons Developer's Guidelines `_ + * `Contacts <(https://scons.org/contact.html>`_ + +Reporting Bugs +============== + +One of the easiest ways to contribute is by filing bugs. +The SCons project welcomes bug reports and feature requests, +but we *do* have a preference for having talked about them first - +we request you send an email to the +`SCons Users Mailing List `_ +or hop on the Discord channel (see link above), and if so +instructed, then proceed to an issue report. + +You can explore the list of existing bugs on GitHub. +Sometimes there's work in progress which may include temporary +workarounds for the problem you've run into:: + + https://github.com/SCons/scons/issues + + +About the Development Tree +========================== + +This tree contains a lot more than just the SCons engine itself. +Some of it has to do with packaging it in a couple +of forms: a Python-installable package (source distribution +and installable wheel file, which get uploaded to the Python +Package Index), a portable zip (or tar) distribution +called "scons-local", and a full source bundle. You usually +don't need to worry about the packaging parts when working +on a source or doc contribution - unless you're adding an entirely +new file, then the packaging bits may need to know about it. The +project maintainers can usually help with that part. +There are also tests and tools in the tree. + +The *full* development cycle is not just to test code changes directly, +but also to package SCons, unpack the package, install SCons in a test +location, and then run the tests against the unpacked and installed +software. This helps eliminate problems caused by the development +tree being different than the tree anyone else would see (files +not checked in to git, files not added to package manifest, etc.) +Most of that is handled by the CI setup driven through GitHub, +which runs checks for each update to a Pull Request. + +For just working on making an individual change to the SCons source, however, +you don't actually need to build or install SCons; you just edit and +execute SCons in-place. See the following sections below for more +information: + + `Making Changes`_ + How to edit and execute SCons in-place. + + `Debugging`_ + Tips for debugging problems in SCons. + + `Testing`_ + How to use the automated regression tests. + + `Typical Development Workflow`_ + An example of how to put the edit/execute/test pieces + together in a reasonable development workflow. + + +Executing SCons Without Installing +================================== + +Since SCons is written entirely in Python, you don't have to "build" +SCons to run it. "Building" refers to the steps taken to prepare +for constructing packages, the most time-consuing of which is +building the documentation. + +Documentation is written in a markup language which is a +light extension of Docbook-XML, and the doc build consists +of translating to pure docbook, then using standard tools to +generate HTML and PDF outputs from that. There's lots more +on the documentation process at the Documentation Toolchain page:: + + https://github.com/SCons/scons/blob/master/doc/overview.rst + + +You can execute SCons directly from this repository. For Linux or UNIX:: + + $ python scripts/scons.py [arguments] + +Or on Windows:: + + C:\scons>py scripts\scons.py [arguments] + +If you run SCons this way, it will read the ``SConstruct`` file in this repo, +which will build and package SCons itself, which you probably don't want +unless you are doing development that relates to the packaging. + +Often when doing SCons development, you have a sample project that +isn't working right, and it's useful to be able to build that +project from the place you're working on changes to SCons. You +can do that with the ``C`` (change directory) option:: + + $ python scripts/scons.py -C /some/other/location [arguments] + +There is another approach that kind of reverses that order: +construct a Python virtualenv and install the development tree in it. +If you're not familiar with virtualenvs, there's an example here:: + + https://scons-cookbook.readthedocs.io/en/latest/#setting-up-a-python-virtualenv-for-scons + +Follow the initial steps, except omit installing ``scons`` as a package. +When the virtualenv is contructed and activated, go to your working SCons +git tree and perform a development install instead:: + + (myvenv) $ pip install --editable . + +Now while this virtualenv is activated, the command ``scons`` will refer +to this editable version, and you don't have to be "in" this tree +to run it. + +You can also arrange to execute ``scons.py`` from the command line +by adding it to the ``PATH``, like:: + + # on Linux/Mac + $ export PATH=$PATH:`pwd`/scripts + + # on Windows + C:\> set PATH="%PATH%;C:\path\to\scripts" + +Be careful on Windows, the path has a limit of 1024 characters which +is pretty easy to exceed, and it will just truncate. + +You may first need to make ``scons.py`` executable (it should be +by default, but sometimes things happen):: + + $ chmod +x scripts/scons.py + + +Other Required Software +======================= + +Running SCons has no installation dependencies beyond a compatible version +of Python. The tools which will be used to to actually construct the +project, such as compilers, documentation production tools, etc. +should of course be installed by the appropriate means. In order +to develop SCons and run its test suite, there are some dependencies, +listed in the ``requirements.txt`` file. + +Making Changes +============== + +Virtually all of the SCons functionality exists in the "build engine," the +``SCons`` subdirectory hierarchy that contains all of the modules that +make up SCons. The ``scripts/scons.py`` wrapper script exists mainly to find +the appropriate build engine library and then execute it. + +In order to make your own changes locally and test them by hand, simply edit +modules in the local ``SCons`` subdirectory tree and then run +(see the section above about `Executing SCons Without Installing`_):: + + $ python scripts/scons.py [arguments] + +(or, if using the virtualenv/editable approach, ``scons [arguents]``) + +Note that the regular SCons development process makes heavy use of automated +testing. See the `Testing`_ and `Typical Development Workflow`_ sections below for more +information about the automated regression tests and how they can be used in a +development cycle to validate that your changes don't break existing +functionality. + + +Debugging +========= + +Python comes with a good interactive debugger. When debugging changes by hand +(i.e., when not using the automated tests), you can invoke SCons under control +of the Python debugger by specifying the ``--debug=pdb`` option:: + + $ scons --debug=pdb [arguments] + > /home/knight/scons/SCons/Script/Main.py(927)_main() + -> default_warnings = [ SCons.Warnings.CorruptSConsignWarning, + (Pdb) + +Once in the debugger, you can set breakpoints at lines in files in the build +engine modules by providing the path name of the file relative to the +top directory (that is, including the SCons/ as the first directory +component):: + + (Pdb) b SCons/Tool/msvc.py:158 + +Since Python 3.7.0 you can also insert a call to the ``breakpoint()`` +function in your code, call ``scons.py`` normally, and it will drop into +the debugger at that point. + +The debugger supports single stepping, stepping into functions, printing +variables, etc. + +When debugging unexpected behavior when running the test suite +(see the `Testing`_ section, below), it can get a bit more complicated. +For the Unit Tests, you will be running in-process, and so the +``runtest.py`` script's debug option is helpful in getting things set up. + +Trying to debug problems found by running the end-to-end tests is +more difficult, because the test automation harness re-invokes SCons and +captures output - essentially, an instance of SCons is being runs as +a "black box", and so it is considerably harder to interact with it +effectively. The way forward is usually to add statements to trace progress. +You can't just use the ``print`` function directly, or even ``sys.stdout.write()`` +because those change the SCons output, and the end-to-end tests usually +look for matches of specific output strings to decide if a given SCons +invocation has behaved as expected - so interleaving your trace information +would cause lots of mismatches, and often obscure what you are trying to debug. + +To deal with this, SCons supports a ``Trace()`` function that (by default) will +print messages to your console screen (``/dev/tty`` on UNIX or Linux, ``con`` on +Windows). By adding ``Trace()`` calls to the SCons source code:: + + def sample_method(self, value): + from SCons.Debug import Trace + Trace('called sample_method(%s, %s)\n' % (self, value)) + +You can then run automated tests that print any arbitrary information you wish +about what's going on inside SCons, without interfering with the test +automation. + +The ``Trace()`` function can also redirect its output to a file, rather than the +screen:: + + def sample_method(self, value): + from SCons.Debug import Trace + Trace('called sample_method(%s, %s)\n' % (self, value), + file='trace.out') + +Where the ``Trace()`` function sends its output is stateful: once you use the +``file=`` argument, all subsequent calls to ``Trace()`` send their output to the +same file, until another call with a ``file=`` argument is reached. + + +Testing +======= + +Tests are run by the ``runtest.py`` script in the top directory. + +There are two types of tests in this package: + +1. Unit tests for individual SCons modules live underneath the SCons + subdirectory and have the same base name as the module with ``Tests.py`` + appended--for example, the unit test for the ``Builder`` module in + ``Builder.py`` is the ``BuilderTests.py`` script. + +2. End-to-end tests of SCons live in the ``test/`` subdirectory. + +You may specifically list one or more tests to be run:: + + $ python runtest.py SCons/BuilderTests.py + + $ python runtest.py test/option-j.py test/Program.py + +You also use the ``-f`` option to execute just the tests listed in a specified +text file:: + + $ cat testlist.txt + test/option-j.py + test/Program.py + $ python runtest.py -f testlist.txt + +One test must be listed per line, and any lines that begin with '#' will be +ignored (allowing you, for example, to comment out tests that are currently +passing and then uncomment all of the tests in the file for a final validation +run). + +The runtest.py script also takes a ``-a`` option that searches the tree for all of +the tests and runs them:: + + $ python runtest.py -a + +If a previous run had test failures, those are saved to logfile which +can be used to run just the failed tests - this is useful for the common +case of a change breaking a few things, and you want to first check that +a fix fixes those, before rerunning the full suite:: + + $ python runtest.py --retry + +If more than one test is run, the ``runtest.py`` script prints a summary of +any tests that failed or yielded no result (usually these are skips due +to run-time checks of conditions). ``runtest.py`` has options to change +the output, just see the command's help message. + +The above invocations all test directly the files underneath the ``SCons/`` +subdirectory, and do not require that a build be performed first. + +Typical Development Workflow +============================ + + Caveat: The point of this section isn't to describe one dogmatic workflow. + Just running the test suite can be time-consuming, and getting a patch to + pass all of the tests can be more so. If you're genuinely blocked, it may + make more sense to submit a patch with a note about which tests still + fail, and how. Someone else may be able to take your "initial draft" and + figure out how to improve it to fix the rest of the tests. So there's + plenty of room for use of good judgement. + +The various techniques described in the above sections can be combined to +create simple and effective workflows that allow you to validate that patches +you submit to SCons don't break existing functionality and have adequate +testing, thereby increasing the speed with which they can be integrated. + +For example, suppose your project's SCons configuration is blocked by an SCons +bug, and you decide you want to fix it and submit the patch. Here's one +possible way to go about doing that (using UNIX/Linux as the development +platform, Windows users can translate as appropriate)): + +- Change to the top of your checked-out SCons tree. + +- Confirm that the bug still exists in this version of SCons by using the ``-C`` + option to run the broken build:: + + $ python scripts/scons.py -C /home/me/broken_project . + +- Fix the bug in SCons by editing appropriate module files underneath + SCons. + +- Confirm that you've fixed the bug affecting your project:: + + $ python scripts/scons.py -C /home/me/broken_project . + +- Test to see if your fix had any unintended side effects that break existing + functionality:: + + $ python runtest.py -a -o test.log + + Be patient, there are more than 1100 test scripts in the whole suite! + + If any test scripts fail, they will be listed in a summary at the end of the + log file. Some test scripts may also report NO RESULT because (for example) + your local system is the wrong type or doesn't have some installed utilities + necessary to run the script. In general, you can ignore the NO RESULT list, + beyond having checked once that the tests that matter to your change are + actually being executed on your test system! These failed tests are + automatically saved to ``failed_tests.log``. + +- Now debug the test failures and fix them, either by changing SCons, or by + making necessary changes to the tests (if, for example, you have a strong + reason to change functionality, or if you find that the bug really is in the + test script itself). After each change, use the ``--retry`` + option to examine the effects of the change on the subset of tests that + last failed:: + + $ [edit] + $ python runtest.py --retry + + Repeat this until all of the tests that originally failed now pass. + +- Now you need to go back and validate that any changes you made while getting + the tests to pass didn't break the fix you originally put in, and didn't + introduce any *additional* unintended side effects that broke other tests:: + + $ python scripts/scons.py -C /home/me/broken_project . + $ python runtest.py -a -o test.log + +Of course, the above is only one suggested workflow. In practice, there is a +lot of room for judgment and experience to make things go quicker. For +example, if you're making a change to just the Java support, you might start +looking for regressions by just running the ``test/Java/\*.py`` tests instead of +running all tests with ``runtest.py -a``. + + +Building Packages +================= + +We use SCons (version 3.1.2 or later) to build its own packages. If you +already have an appropriate version of SCons installed on your system, +you can build everything by simply running it:: + + $ scons + +If you don't have SCons already installed on your system, +you can run the build directly from the source tree +(see the section above about `Executing SCons Without Installing`_):: + + $ python scripts/scons.py + +Those are full builds: depending on the utilities installed on your system, +any or all of the following packages will be built:: + + SCons-4.3.0-py3-none-any.whl + SCons-4.3.0ayyyymmdd.tar.gz + SCons-4.3.0ayyyymmdd.zip + scons-doc-4.3.0ayyyymmdd.tar.gz + scons-local-4.3.0ayyyymmdd.tar.gz + scons-local-4.3.0ayyyymmdd.zip + +The ``SConstruct`` file is supposed to be smart enough to avoid trying to build +packages for which you don't have the proper utilities installed. + +If you receive a build error, please report it to the scons-devel mailing list +and open a bug report on the SCons bug tracker. + +Note that in addition to creating the above packages, the default build will +also unpack one or more of the packages for testing. + +If you're working on documentation and just want to make sure that still builds, +there's a "doc" target:: + + $ python scripts/scons.py doc + +Contents of this Tree +===================== + +Not guaranteed to be up-to-date (but better than nothing): + +bench/ + A subdirectory for benchmarking scripts, used to perform timing tests + to decide what specific idioms are most efficient for various parts of + the code base. We check these in so they're available in case we have + to revisit any of these decisions in the future. + +bin/ + Miscellaneous utilities used in SCons development. Right now, + some of the stuff here includes: + + - a script that runs pychecker on our source tree; + + - a script that counts source and test files and numbers of lines in each; + + - a prototype script for capturing sample SCons output in xml files; + + - a script that can profile and time a packaging build of SCons itself; + + - a copy of xml_export, which can retrieve project data from SourceForge; + (obsolete, as project now lives on GitHub and PyPi). + + - scripts and a Python module for translating the SCons home-brew XML + documentation tags into DocBook and man page format + +bootstrap.py + Obsolete packaging logic - ignore this. + +debian/ + Files needed to construct a Debian package. The contents of this directory + are dictated by the + `Debian Policy Manual `). + The package will not be accepted into the Debian distribution unless + the contents of this directory satisfy the relevant Debian policies. + At this point, this is a sample; SCons is packaged in the Debian + project (and thus inherited by projects which derive from it, if + they haven't made their own packages). See: + + - `Debian scons packages `_ + - `Ubuntu scons packages `_ + +doc/ + SCons documentation. A variety of things here, in various stages of + (in)completeness. Note not all of the documentation is in ``doc`` - + for tools and other self-contained items, there is often a documentation + file together with the source, with a ``.xml`` suffix, in the same + way there is often a unit-test file kept together with the source it tests. + +LICENSE + A copy of the copyright and terms under which SCons is distributed (the + Open Source Initiative-approved MIT license). + +LICENSE-local + A copy of the copyright and terms under which SCons is distributed for + inclusion in the scons-local-{version} packages. This is the same as + LICENSE with a preamble that specifies the licensing terms are for SCons + itself, not any other package that includes SCons. + +README.rst + What you're looking at right now. + +README-local.rst + A README file for inclusion in the scons-local-{version} packages. + Similar to this file, but stripped down and modified for people looking at + including SCons in their shipped software. + +README-SF.rst + A README file the SourceForge project page - although the project is + no longer developed on SourceForge, this still serves as a download + location. + +runtest.py + Script for running SCons tests. By default, this will run a test against + the code in the local SCons tree, so you don't have to do a build before + testing your changes. + +SConstruct + The file describing to SCons how to build the SCons distribution. + + (It has been pointed out that it's hard to find the SCons API in this + SConstruct file, and that it looks a lot more like a pure Python script + than a build configuration file. That's mainly because all of the magick + we have to perform to deal with all of the different packaging formats + requires a lot of pure Python manipulation. In other words, don't look at + this file for an example of how easy it is to use SCons to build "normal" + software.) + +SCons/ + This is the source code of the engine, plus unit tests and + documentation stubs kept together with pieces of the engine. + +test/ + End-to-end tests of the SCons utility itself. These are separate from the + individual module unit tests. + +testing/ + SCons testing framework. diff -Nru scons-4.0.1+dfsg/debian/changelog scons-4.4.0+dfsg/debian/changelog --- scons-4.0.1+dfsg/debian/changelog 2020-10-27 17:38:13.000000000 +0000 +++ scons-4.4.0+dfsg/debian/changelog 2022-09-20 15:35:41.000000000 +0000 @@ -1,3 +1,14 @@ +scons (4.4.0+dfsg-1) unstable; urgency=medium + + * New upstream release: + - fix content-timestamp decider for symlinks (closes: #981584). + * Move binaries back to /usr (closes: #1020082). + * Handle man pages correctly. + * Suggest scons-doc on scons package (closes: #973301). + * Update Standards-Version to 4.6.1 . + + -- Laszlo Boszormenyi (GCS) Tue, 20 Sep 2022 17:35:41 +0200 + scons (4.0.1+dfsg-2) unstable; urgency=medium * Upload to Sid. diff -Nru scons-4.0.1+dfsg/debian/control scons-4.4.0+dfsg/debian/control --- scons-4.0.1+dfsg/debian/control 2020-08-23 18:25:23.000000000 +0000 +++ scons-4.4.0+dfsg/debian/control 2022-09-20 15:35:41.000000000 +0000 @@ -12,8 +12,9 @@ biber , clang , gdc , + python3-psutil , ldc [amd64] -Standards-Version: 4.5.0 +Standards-Version: 4.6.1 Rules-Requires-Root: no Homepage: https://www.scons.org/ Vcs-Git: https://salsa.debian.org/debian/scons.git @@ -24,6 +25,7 @@ Depends: ${python3:Depends}, ${misc:Depends} +Suggests: scons-doc Description: replacement for make SCons is a make replacement providing a range of enhanced features such as automated dependency generation and built in compilation cache @@ -33,6 +35,7 @@ Package: scons-doc Architecture: all +Multi-Arch: foreign Depends: ${misc:Depends} Breaks: scons-doc (<< 4.0.1) Replaces: scons-doc (<< 4.0.1) diff -Nru scons-4.0.1+dfsg/debian/rules scons-4.4.0+dfsg/debian/rules --- scons-4.0.1+dfsg/debian/rules 2020-08-23 18:25:23.000000000 +0000 +++ scons-4.4.0+dfsg/debian/rules 2022-09-20 15:35:41.000000000 +0000 @@ -17,11 +17,19 @@ cd $(CURDIR)/doc/user && python3 ../../scripts/scons.py override_dh_auto_install: - python3 setup.py install --prefix /usr --root '$(CURDIR)/debian/scons' - $(RM) -r debian/scons/usr/lib/python*/site-packages/SCons/Tool/docbook/ + # setup.cfg contains bad path for man pages + cp -av $(CURDIR)/doc/man/*.1 $(CURDIR) + python3 setup.py install \ + --prefix /usr \ + --install-data=/usr/share/man/man1/ \ + --root '$(CURDIR)/debian/scons' + mv $(CURDIR)/debian/scons/usr/local/bin/ $(CURDIR)/debian/scons/usr/ + $(RM) -r debian/scons/usr/local/lib/python*/dist-packages/SCons/Tool/docbook/ override_dh_auto_clean: $(RM) -r .sconsign.dblite bootstrap build $$(find * -name __pycache__ -type d) + $(RM) $(CURDIR)/*.1 + $(RM) $(CURDIR)/failed_tests.log $(RM) -r $(CURDIR)/SCons.egg-info $(CURDIR)/.pybuild # generated documentation $(RM) $(CURDIR)/doc/man/.sconsign.dblite diff -Nru scons-4.0.1+dfsg/debian/scons.manpages scons-4.4.0+dfsg/debian/scons.manpages --- scons-4.0.1+dfsg/debian/scons.manpages 2020-08-23 18:25:23.000000000 +0000 +++ scons-4.4.0+dfsg/debian/scons.manpages 2021-12-19 18:20:48.000000000 +0000 @@ -1,3 +1 @@ -doc/man/scons.1 -doc/man/sconsign.1 debian/scons-configure-cache.1 diff -Nru scons-4.0.1+dfsg/debian/source/lintian-overrides scons-4.4.0+dfsg/debian/source/lintian-overrides --- scons-4.0.1+dfsg/debian/source/lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/debian/source/lintian-overrides 2022-09-20 15:35:41.000000000 +0000 @@ -0,0 +1,13 @@ +# Long lines +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/NEWS.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/RELEASE-NOTES.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch01.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch02.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch02s01.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch02s02.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch02s03.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch02s04.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch03.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch03s01.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/ch03s02.html] +source-is-missing [SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/content/index.html] diff -Nru scons-4.0.1+dfsg/doc/design/engine.xml scons-4.4.0+dfsg/doc/design/engine.xml --- scons-4.0.1+dfsg/doc/design/engine.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/design/engine.xml 2022-07-30 21:48:28.000000000 +0000 @@ -484,6 +484,17 @@ + + .relpath + + + + The path to the file relative to the root SConstruct file's directory. + + + + + diff -Nru scons-4.0.1+dfsg/doc/design/html.xsl scons-4.4.0+dfsg/doc/design/html.xsl --- scons-4.0.1+dfsg/doc/design/html.xsl 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/design/html.xsl 2022-07-30 21:48:28.000000000 +0000 @@ -24,11 +24,14 @@ --> + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> - + + + @@ -52,5 +55,97 @@ set toc,title - + + + + + + + + + + + + + + + + + + + + <xsl:copy-of select="$title"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru scons-4.0.1+dfsg/doc/generated/builders.gen scons-4.4.0+dfsg/doc/generated/builders.gen --- scons-4.0.1+dfsg/doc/generated/builders.gen 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/builders.gen 2022-07-30 21:48:28.000000000 +0000 @@ -54,30 +54,55 @@ CompilationDatabase() env.CompilationDatabase() - The &b-CompilationDatabase; builder writes a JSON formatted compilation - database according to the - LLVM specification - which is consumed by a number of clang tools, editors, and other tools. - - - If you don't specify any files, the builder will default to compile_commands.json. - - - If you specify a single file as below - -env.CompilationDatabase('my_output.json') - - SCons will automatically use that as the target file. - If you specify more than one source, the source list will be ignored. - - - You should not specify source files. The &b-CompilationDatabase; builder instruments SCons to collect them from all - the C, C++, assembly source/target pairs. - - - NOTE: You must load the &t-compilation_db; tool prior to specifying any part of your build or some source/target - files will not show up in your output file. - + &b-CompilationDatabase; is a special builder which + adds a target to create a JSON formatted + compilation database compatible with + clang tooling + (see the + LLVM specification). + This database is suitable for consumption by various + tools and editors who can use it to obtain build and + dependency information which otherwise would be + internal to &SCons;. + The builder does not require any source files to be specified, + rather it arranges to emit information about all + of the C, C++ and assembler source/output pairs + identified in the build that are not excluded by the + optional filter &cv-link-COMPILATIONDB_PATH_FILTER;. + The target is subject to the usual &SCons; target + selection rules. + + + If called with no arguments, + the builder will default to a target name of + compile_commands.json. + + + If called with a single positional argument, + &scons; will "deduce" the target name from that source + argument, giving it the same name, and then + ignore the source. + This is the usual way to call the builder if a + non-default target name is wanted. + + + If called with either the target= + or source= keyword arguments, + the value of the argument is taken as the target name. + If called with both, the target= + value is used and source= is ignored. + If called with multiple sources, + the source list will be ignored, + since there is no way to deduce what the intent was; + in this case the default target name will be used. + + + + You must load the &t-compilation_db; tool prior to specifying + any part of your build or some source/output + files will not show up in the compilation database. + + Available since &scons; 4.0. @@ -147,8 +172,8 @@ DocbookHtmlChunked() env.DocbookHtmlChunked() -A pseudo-Builder, providing a Docbook toolchain for chunked HTML output. -It supports the base.dir parameter. The +A pseudo-Builder providing a Docbook toolchain for chunked HTML output. +It supports the base.dir parameter. The chunkfast.xsl file (requires "EXSLT") is used as the default stylesheet. Basic syntax: @@ -159,22 +184,23 @@ where manual.xml is the input file. -If you use the root.filename +If you use the root.filename parameter in your own stylesheets you have to specify the new target name. This ensures that the dependencies get correct, especially for the cleanup via scons -c: env = Environment(tools=['docbook']) env.DocbookHtmlChunked('mymanual.html', 'manual', xsl='htmlchunk.xsl') -Some basic support for the base.dir is provided. You -can add the base_dir keyword to your Builder -call, and the given prefix gets prepended to all the created filenames: +Some basic support for the base.dir parameter +is provided. You can add the base_dir keyword to +your Builder call, and the given prefix gets prepended to all the +created filenames: env = Environment(tools=['docbook']) env.DocbookHtmlChunked('manual', xsl='htmlchunk.xsl', base_dir='output/') Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! +your files get renamed only! @@ -193,15 +219,15 @@ where manual.xml is the input file. -If you use the root.filename +If you use the root.filename parameter in your own stylesheets you have to specify the new target name. -This ensures that the dependencies get correct, especially for the cleanup via scons -c: +This ensures that the dependencies get correct, especially for the cleanup via scons -c: env = Environment(tools=['docbook']) env.DocbookHtmlhelp('mymanual.html', 'manual', xsl='htmlhelp.xsl') -Some basic support for the base.dir parameter -is provided. You can add the base_dir keyword to +Some basic support for the base.dir parameter +is provided. You can add the base_dir keyword to your Builder call, and the given prefix gets prepended to all the created filenames: @@ -209,7 +235,7 @@ env.DocbookHtmlhelp('manual', xsl='htmlhelp.xsl', base_dir='output/') Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! +your files get renamed only! @@ -226,7 +252,7 @@ env.DocbookMan('manual') -where manual.xml is the input file. Note, that +where manual.xml is the input file. Note, that you can specify a target name, but the actual output names are automatically set from the refname entries in your XML source. @@ -264,25 +290,25 @@ env.DocbookSlidesHtml('manual') -If you use the titlefoil.html parameter in +If you use the titlefoil.html parameter in your own stylesheets you have to give the new target name. This ensures -that the dependencies get correct, especially for the cleanup via -scons -c: +that the dependencies get correct, especially for the cleanup via +scons -c: env = Environment(tools=['docbook']) env.DocbookSlidesHtml('mymanual.html','manual', xsl='slideshtml.xsl') -Some basic support for the base.dir parameter +Some basic support for the base.dir parameter is provided. You -can add the base_dir keyword to your Builder +can add the base_dir keyword to your Builder call, and the given prefix gets prepended to all the created filenames: env = Environment(tools=['docbook']) env.DocbookSlidesHtml('manual', xsl='slideshtml.xsl', base_dir='output/') Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! +your files get renamed only! @@ -330,7 +356,7 @@ env.DocbookXslt('manual_transformed.xml', 'manual.xml', xsl='transform.xslt') -Note, that this builder requires the xsl parameter +Note, that this builder requires the xsl parameter to be set. @@ -393,15 +419,18 @@ Gs() env.Gs() -A Builder for explicitly calling the gs executable. -Depending on the underlying OS, the different names gs, -gsos2 and gswin32c +A Builder for explicitly calling the gs executable. +Depending on the underlying OS, the different names gs, +gsos2 and gswin32c are tried. -env = Environment(tools=['gs']) -env.Gs('cover.jpg','scons-scons.pdf', - GSFLAGS='-dNOPAUSE -dBATCH -sDEVICE=jpeg -dFirstPage=1 -dLastPage=1 -q') - ) + +env = Environment(tools=['gs']) +env.Gs( + 'cover.jpg', + 'scons-scons.pdf', + GSFLAGS='-dNOPAUSE -dBATCH -sDEVICE=jpeg -dFirstPage=1 -dLastPage=1 -q', +) @@ -669,6 +698,27 @@ JAVACLASSDIR="classes", ) + + + +Java versions starting with 10.0 no longer use the +javah command for generating JNI +headers/sources, and indeed have removed the command entirely +(see Java Enhancement Proposal +JEP 313), +making this tool harder to use for that purpose. +&SCons; may autodiscover a javah +belonging to an older release if there are multiple Java +versions on the system, which will lead to incorrect results. +To use with a newer Java, override the default values of &cv-link-JAVAH; +(to contain the path to the javac) +and &cv-link-JAVAHFLAGS; (to contain at least a +flag) and note that generating headers with +javac requires supplying source +.java files only, +not .class files. + + @@ -715,15 +765,16 @@ Moc() env.Moc() -Builds an output file from a moc input file. Moc input files are either -header files or cxx files. This builder is only available after using the -tool 'qt'. See the &cv-link-QTDIR; variable for more information. +Builds an output file from a moc input file. +moc input files are either header files or C++ files. +This builder is only available after using the +tool &t-link-qt;. See the &cv-link-QTDIR; variable for more information. Example: -env.Moc('foo.h') # generates moc_foo.cc -env.Moc('foo.cpp') # generates foo.moc +env.Moc('foo.h') # generates moc_foo.cc +env.Moc('foo.cpp') # generates foo.moc @@ -1192,6 +1243,73 @@ + + Ninja() + env.Ninja() + + A special builder which + adds a target to create a Ninja build file. + The builder does not require any source files to be specified. + + + This is an experimental feature. To enable it you must use one of the following methods + + + + +# On the command line +--experimental=ninja + +# Or in your SConstruct +SetOption('experimental', 'ninja') + + + This functionality is subject to change and/or removal without deprecation cycle. + + + To use this tool you need to install the &Python; &ninja; package, + as the tool by default depends on being able to do an + import of the package + + This can be done via: + +python -m pip install ninja + + + + + + + If called with no arguments, + the builder will default to a target name of + ninja.build. + + + If called with a single positional argument, + &scons; will "deduce" the target name from that source + argument, giving it the same name, and then + ignore the source. + This is the usual way to call the builder if a + non-default target name is wanted. + + + If called with either the + target= + or source= keyword arguments, + the value of the argument is taken as the target name. + If called with both, the + target= + value is used and source= is ignored. + If called with multiple sources, + the source list will be ignored, + since there is no way to deduce what the intent was; + in this case the default target name will be used. + + + Available since &scons; 4.2. + + + Object() env.Object() @@ -1206,58 +1324,83 @@ Package() env.Package() -Builds a Binary Package of the given source files. +Builds software distribution packages. +A package is a container format which +includes files to install along with metadata. +Packaging is optional, and must be enabled by specifying +the &t-link-packaging; tool. For example: -env.Package(source = FindInstalledFiles()) +env = Environment(tools=['default', 'packaging']) + -Builds software distribution packages. -Packages consist of files to install and packaging information. -The former may be specified with the &source; parameter and may be left out, -in which case the &FindInstalledFiles; function will collect -all files that have an &b-Install; or &b-InstallAs; Builder attached. -If the ⌖ is not specified -it will be deduced from additional information given to this Builder. +&SCons; can build packages in a number of well known packaging formats. +The target package type may be selected with the +the &cv-link-PACKAGETYPE; construction variable +or the command line option. +The package type may be a list, in which case &SCons; will attempt +to build packages for each type in the list. Example: + +env.Package(PACKAGETYPE=['src_zip', 'src_targz'], ...other args...) + + + +The currently supported packagers are: + + + + + +msiMicrosoft Installer package +rpmRPM Package Manger package +ipkgItsy Package Management package +tarbz2bzip2-compressed tar file +targzgzip-compressed tar file +tarxzxz-compressed tar file +zipzip file +src_tarbz2bzip2-compressed tar file suitable as source to another packager +src_targzgzip-compressed tar file suitable as source to another packager +src_tarxzxz-compressed tar file suitable as source to another packager +src_zipzip file suitable as source to another packager + + + + -The packaging information is specified -with the help of construction variables documented below. -This information is called a tag to stress that -some of them can also be attached to files with the &Tag; function. -The mandatory ones will complain if they were not specified. -They vary depending on chosen target packager. +The file list to include in the package may be specified with +the &source; keyword argument. If omitted, +the &f-link-FindInstalledFiles; function is called behind the scenes +to select all files that have an &b-link-Install;, &b-link-InstallAs; +or &b-link-InstallVersionedLib; Builder attached. +If the ⌖ keyword argument is omitted, the target name(s) +will be deduced from the package type(s). -The target packager may be selected with the "PACKAGETYPE" command line -option or with the &cv-PACKAGETYPE; construction variable. Currently -the following packagers available: - - -
- -msi - Microsoft Installer -rpm - RPM Package Manger -ipkg - Itsy Package Management System -tarbz2 - bzip2 compressed tar -targz - gzip compressed tar -tarxz - xz compressed tar -zip - zip file -src_tarbz2 - bzip2 compressed tar source -src_targz - gzip compressed tar source -src_tarxz - xz compressed tar source -src_zip - zip file source - -
- - -An updated list is always available under the -package_type option when -running scons --help -on a project that has packaging activated. +The metadata comes partly from attributes of the files to be packaged, +and partly from packaging tags. +Tags can be passed as keyword arguments +to the &b-Package; builder call, +and may also be attached to files +(or more accurately, Nodes representing files) +with the &f-link-Tag; function. +Some package-level tags are mandatory, and will lead to errors if omitted. +The mandatory tags vary depending on the package type. + + + + +While packaging, the builder uses a temporary location named +by the value of the &cv-link-PACKAGEROOT; variable - +the package sources are copied there before packaging. + + + +Packaging example: @@ -1272,9 +1415,24 @@ SUMMARY="balalalalal", DESCRIPTION="this should be really really long", X_RPM_GROUP="Application/fu", - SOURCE_URL="http://foo.org/foo-1.2.3.tar.gz", + SOURCE_URL="https://foo.org/foo-1.2.3.tar.gz", ) + + +In this example, the target /bin/my_program +created by the &b-Install; call would not be built by default +since it is not under the project top directory. +However, since no source +is specified to the &b-Package; builder, +it is selected for packaging by the default sources rule. +Since packaging is done using &cv-link-PACKAGEROOT;, no write is +actually done to the system's /bin directory, +and the target will be selected since +after rebasing to underneath &cv-PACKAGEROOT; it is now under +the top directory of the project. + +
@@ -1282,13 +1440,13 @@ env.PCH() Builds a Microsoft Visual C++ precompiled header. -Calling this builder method +Calling this builder returns a list of two targets: the PCH as the first element, and the object file as the second element. Normally the object file is ignored. -This builder method is only +This builder is only provided when Microsoft Visual C++ is being used as the compiler. -The PCH builder method is generally used in -conjunction with the PCH construction variable to force object files to use +The &b-PCH; builder is generally used in +conjunction with the &cv-link-PCH; construction variable to force object files to use the precompiled header: @@ -2069,8 +2227,8 @@ according to the suffix mappings in the SourceFileScanner object. -See the section "Scanner Objects," -below, for more information. +See the manpage section "Scanner Objects" +for more information.
@@ -2174,8 +2332,8 @@ according to the suffix mappings in the SourceFileScanner object. -See the section "Scanner Objects," -below, for more information. +See the manpage section "Scanner Objects" +for more information.
@@ -2545,11 +2703,11 @@ env.Uic() Builds a header file, an implementation file and a moc file from an ui file. -and returns the corresponding nodes in the above order. -This builder is only available after using the tool 'qt'. Note: you can -specify .ui files directly as source -files to the &b-Program;, -&b-Library; and &b-SharedLibrary; builders +and returns the corresponding nodes in the that order. +This builder is only available after using the tool &t-link-qt;. +Note: you can specify .ui files directly as source +files to the &b-link-Program;, +&b-link-Library; and &b-link-SharedLibrary; builders without using this builder. Using this builder lets you override the standard naming conventions (be careful: prefixes are always prepended to names of built files; if you don't want prefixes, you may set them to ``). @@ -2558,9 +2716,11 @@ -env.Uic('foo.ui') # -> ['foo.h', 'uic_foo.cc', 'moc_foo.cc'] -env.Uic(target = Split('include/foo.h gen/uicfoo.cc gen/mocfoo.cc'), - source = 'foo.ui') # -> ['include/foo.h', 'gen/uicfoo.cc', 'gen/mocfoo.cc'] +env.Uic('foo.ui') # -> ['foo.h', 'uic_foo.cc', 'moc_foo.cc'] +env.Uic( + target=Split('include/foo.h gen/uicfoo.cc gen/mocfoo.cc'), + source='foo.ui' +) # -> ['include/foo.h', 'gen/uicfoo.cc', 'gen/mocfoo.cc'] diff -Nru scons-4.0.1+dfsg/doc/generated/builders.mod scons-4.4.0+dfsg/doc/generated/builders.mod --- scons-4.0.1+dfsg/doc/generated/builders.mod 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/builders.mod 2022-07-30 21:48:28.000000000 +0000 @@ -37,6 +37,7 @@ MOFiles"> MSVSProject"> MSVSSolution"> +Ninja"> Object"> Package"> PCH"> @@ -94,6 +95,7 @@ env.MOFiles"> env.MSVSProject"> env.MSVSSolution"> +env.Ninja"> env.Object"> env.Package"> env.PCH"> @@ -157,6 +159,7 @@ MOFiles"> MSVSProject"> MSVSSolution"> +Ninja"> Object"> Package"> PCH"> @@ -214,6 +217,7 @@ env.MOFiles"> env.MSVSProject"> env.MSVSSolution"> +env.Ninja"> env.Object"> env.Package"> env.PCH"> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/builders_adding_emitter_1.xml scons-4.4.0+dfsg/doc/generated/examples/builders_adding_emitter_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/builders_adding_emitter_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/builders_adding_emitter_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,13 @@ +% scons -Q --tree=prune +cc -o hello.o -c hello.c +cc -o hello -Wl,-Map=hello.map,--cref hello.o ++-. + +-SConstruct + +-hello + | +-hello.o + | +-hello.c + +-hello.c + +-hello.map + | +-[hello.o] + +-[hello.o] + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/buildersbuiltin_ex4_1.xml scons-4.4.0+dfsg/doc/generated/examples/buildersbuiltin_ex4_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/buildersbuiltin_ex4_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/buildersbuiltin_ex4_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,3 @@ % scons -Q . -zip(["out.zip"], ["file1", "file2"]) +zip_builder(["out.zip"], ["file1", "file2"]) diff -Nru scons-4.0.1+dfsg/doc/generated/examples/builderscommands_ex5_1.xml scons-4.4.0+dfsg/doc/generated/examples/builderscommands_ex5_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/builderscommands_ex5_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/builderscommands_ex5_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +% scons -Q +Building foo.out + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/builders_override_ex1_1.xml scons-4.4.0+dfsg/doc/generated/examples/builders_override_ex1_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/builders_override_ex1_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/builders_override_ex1_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,5 @@ +% scons -Q +cc -o foo1.o -c -DFOO foo.c +cc -o foo2.o -c -DBAR foo.c +cc -o foo3.o -c -DBAR -DFOO foo.c + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/builders_override_ex2_1.xml scons-4.4.0+dfsg/doc/generated/examples/builders_override_ex2_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/builders_override_ex2_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/builders_override_ex2_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,4 @@ +% scons -Q +cc -o hello.o -c -DEBUG -Iinclude hello.c +cc -o hello hello.o -lm + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/builderswriting_ex2_1.xml scons-4.4.0+dfsg/doc/generated/examples/builderswriting_ex2_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/builderswriting_ex2_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/builderswriting_ex2_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q AttributeError: 'SConsEnvironment' object has no attribute 'Program': - File "/home/my/project/SConstruct", line 4: + File "/home/my/project/SConstruct", line 7: env.Program('hello.c') diff -Nru scons-4.0.1+dfsg/doc/generated/examples/caching_ex-random_1.xml scons-4.4.0+dfsg/doc/generated/examples/caching_ex-random_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/caching_ex-random_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/caching_ex-random_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,8 +1,8 @@ % scons -Q -cc -o f5.o -c f5.c -cc -o f1.o -c f1.c +cc -o f4.o -c f4.c cc -o f2.o -c f2.c cc -o f3.o -c f3.c -cc -o f4.o -c f4.c +cc -o f1.o -c f1.c +cc -o f5.o -c f5.c cc -o prog f1.o f2.o f3.o f4.o f5.o diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_BoolVariable_5.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_BoolVariable_5.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_BoolVariable_5.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_BoolVariable_5.xml 2022-07-30 21:48:28.000000000 +0000 @@ -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> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_EnumVariable_2.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_EnumVariable_2.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_EnumVariable_2.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_EnumVariable_2.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q COLOR=magenta foo.o 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> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_EnumVariable_4.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_EnumVariable_4.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_EnumVariable_4.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_EnumVariable_4.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,13 +1,13 @@ % scons -Q COLOR=Red foo.o 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> % scons -Q COLOR=BLUE foo.o 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> % scons -Q COLOR=nAvY foo.o 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> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_1.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q COLORS=red,blue foo.o -cc -o foo.o -c -DCOLORS="red blue" foo.c +cc -o foo.o -c -DCOLORS="red -Dblue" foo.c % scons -Q COLORS=blue,green,red foo.o -cc -o foo.o -c -DCOLORS="blue green red" foo.c +cc -o foo.o -c -DCOLORS="blue -Dgreen -Dred" foo.c diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_2.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_2.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_2.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_2.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q COLORS=all foo.o -cc -o foo.o -c -DCOLORS="red green blue" foo.c +cc -o foo.o -c -DCOLORS="red -Dgreen -Dblue" foo.c % scons -Q COLORS=none foo.o cc -o foo.o -c -DCOLORS="" foo.c diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_3.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_3.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_3.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_3.xml 2022-07-30 21:48:28.000000000 +0000 @@ -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> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_4.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_4.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_ListVariable_4.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_ListVariable_4.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +% scons -Q foo.o + +scons: *** Error converting option: COLORS +Invalid value(s) for option: 0 +File "/home/my/project/SConstruct", line 7, in <module> + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_PathVariable_2.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_PathVariable_2.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_PathVariable_2.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_PathVariable_2.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q CONFIG=/does/not/exist foo.o 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> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/commandline_UnknownVariables_1.xml scons-4.4.0+dfsg/doc/generated/examples/commandline_UnknownVariables_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/commandline_UnknownVariables_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/commandline_UnknownVariables_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,3 @@ % scons -Q NOT_KNOWN=foo -Unknown variables: dict_keys(['NOT_KNOWN']) +Unknown variables: NOT_KNOWN diff -Nru scons-4.0.1+dfsg/doc/generated/examples/depends_include_SConstruct scons-4.4.0+dfsg/doc/generated/examples/depends_include_SConstruct --- scons-4.0.1+dfsg/doc/generated/examples/depends_include_SConstruct 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/depends_include_SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,3 @@ -Program('hello.c', CPPPATH = '.') +Program('hello.c', CPPPATH='.') diff -Nru scons-4.0.1+dfsg/doc/generated/examples/depends_mixing_1.xml scons-4.4.0+dfsg/doc/generated/examples/depends_mixing_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/depends_mixing_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/depends_mixing_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ % scons -Q cc -o program1.o -c -I. program1.c -cc -o prog-MD5 program1.o +cc -o prog-content program1.o cc -o program2.o -c -I. program2.c cc -o prog-timestamp program2.o % touch inc.h diff -Nru scons-4.0.1+dfsg/doc/generated/examples/environments_ex6_1.xml scons-4.4.0+dfsg/doc/generated/examples/environments_ex6_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/environments_ex6_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/environments_ex6_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,5 @@ % scons -Q CC is: cc +LATEX is: None scons: `.' is up to date. diff -Nru scons-4.0.1+dfsg/doc/generated/examples/external_cdb_ex1_1.xml scons-4.4.0+dfsg/doc/generated/examples/external_cdb_ex1_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/external_cdb_ex1_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/external_cdb_ex1_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,5 @@ +% scons -Q +Building compilation database compile_commands.json +cc -o hello.o -c hello.c +cc -o hello hello.o + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/external_cdb_ex2_1.xml scons-4.4.0+dfsg/doc/generated/examples/external_cdb_ex2_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/external_cdb_ex2_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/external_cdb_ex2_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +% scons -Q cdb +Building compilation database compile_database.json + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/hierarchy_hash_1.xml scons-4.4.0+dfsg/doc/generated/examples/hierarchy_hash_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/hierarchy_hash_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/hierarchy_hash_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,5 @@ +% scons -Q +path = #/include +force-interpreted path = include +scons: `.' is up to date. + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags1_1.xml scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags1_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags1_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags1_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,4 @@ % scons -Q -['-option', '-O1', '-whatever', '-O3'] +CCFLAGS: ['-option', '-O1', '-whatever', '-O3'] scons: `.' is up to date. diff -Nru scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags2_1.xml scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags2_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags2_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags2_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,4 @@ % scons -Q -['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] +CPPPATH: ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] scons: `.' is up to date. diff -Nru scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags3_1.xml scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags3_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/mergeflags_MergeFlags3_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/mergeflags_MergeFlags3_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ % scons -Q -['-option', '-O1', '-whatever', '-O3'] -['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] +CCFLAGS: ['-option', '-O1', '-whatever', '-O3'] +CPPPATH: ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] scons: `.' is up to date. diff -Nru scons-4.0.1+dfsg/doc/generated/examples/parse_flags_ex1_1.xml scons-4.4.0+dfsg/doc/generated/examples/parse_flags_ex1_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/parse_flags_ex1_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/parse_flags_ex1_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,7 @@ +% scons -Q +CPPPATH: ['/opt/include'] +LIBPATH: ['/opt/lib'] +LIBS: ['foo'] +cc -o f1.o -c -I/opt/include f1.c +cc -o f1 f1.o -L/opt/lib -lfoo + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/separate_ex1_1.xml scons-4.4.0+dfsg/doc/generated/examples/separate_ex1_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/separate_ex1_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/separate_ex1_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -3,6 +3,8 @@ % scons -Q cc -o build/hello.o -c build/hello.c cc -o build/hello build/hello.o +% ls src +SConscript hello.c % ls build SConscript hello hello.c hello.o diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sideeffect_simple_1.xml scons-4.4.0+dfsg/doc/generated/examples/sideeffect_simple_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sideeffect_simple_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sideeffect_simple_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,4 @@ -% scons -Q --jobs=2 +% scons -Q echo > file1 data1; echo >log updated file1 Copy("file2", "log") diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sideeffect_simple2_1.xml scons-4.4.0+dfsg/doc/generated/examples/sideeffect_simple2_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sideeffect_simple2_1.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sideeffect_simple2_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,4 @@ +% scons -Q +echo > file1 data1; echo >log updated file1 +Copy("file2", "log") + diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sourcecode_bitkeeper_1.xml scons-4.4.0+dfsg/doc/generated/examples/sourcecode_bitkeeper_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sourcecode_bitkeeper_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sourcecode_bitkeeper_1.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -% scons -Q -AttributeError: 'SConsEnvironment' object has no attribute 'BitKeeper': - File "/home/my/project/SConstruct", line 2: - env.SourceCode('.', env.BitKeeper()) - diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sourcecode_cvs_1.xml scons-4.4.0+dfsg/doc/generated/examples/sourcecode_cvs_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sourcecode_cvs_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sourcecode_cvs_1.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -% scons -Q -AttributeError: 'SConsEnvironment' object has no attribute 'CVS': - File "/home/my/project/SConstruct", line 2: - env.SourceCode('.', env.CVS('/usr/local/CVS')) - diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sourcecode_rcs_1.xml scons-4.4.0+dfsg/doc/generated/examples/sourcecode_rcs_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sourcecode_rcs_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sourcecode_rcs_1.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -% scons -Q -AttributeError: 'SConsEnvironment' object has no attribute 'RCS': - File "/home/my/project/SConstruct", line 2: - env.SourceCode('.', env.RCS()) - diff -Nru scons-4.0.1+dfsg/doc/generated/examples/sourcecode_sccs_1.xml scons-4.4.0+dfsg/doc/generated/examples/sourcecode_sccs_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/sourcecode_sccs_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/sourcecode_sccs_1.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -% scons -Q -AttributeError: 'SConsEnvironment' object has no attribute 'SCCS': - File "/home/my/project/SConstruct", line 2: - env.SourceCode('.', env.SCCS()) - diff -Nru scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_1.xml scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -28,11 +28,11 @@ 'DSUFFIXES': ['.d'], 'Dir': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, 'Dirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'ENV': {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'}, + 'ENV': {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin:/snap/bin'}, 'ESCAPE': <function escape at 0x700000>, 'File': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'HOST_ARCH': None, - 'HOST_OS': None, + 'HOST_ARCH': 'arm64', + 'HOST_OS': 'posix', 'IDLSUFFIXES': ['.idl', '.IDL'], 'INSTALL': <function copyFunc at 0x700000>, 'INSTALLVERSIONEDLIB': <function copyFuncVersionedLib at 0x700000>, @@ -48,7 +48,7 @@ 'PROGSUFFIX': '', 'PSPAWN': <function piped_env_spawn at 0x700000>, 'RDirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'SCANNERS': [<SCons.Scanner.Base object at 0x700000>], + 'SCANNERS': [<SCons.Scanner.ScannerBase object at 0x700000>], 'SHELL': 'sh', 'SHLIBPREFIX': '$LIBPREFIX', 'SHLIBSUFFIX': '.so', @@ -58,21 +58,23 @@ 'TARGET_ARCH': None, 'TARGET_OS': None, 'TEMPFILE': <class 'SCons.Platform.TempFileMunge'>, + 'TEMPFILEARGESCFUNC': <function quote_spaces at 0x700000>, 'TEMPFILEARGJOIN': ' ', 'TEMPFILEPREFIX': '@', 'TOOLS': ['install', 'install'], - '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, ' - '__env__)}', - '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, ' - 'TARGET, SOURCE)} $)', - '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, ' - 'RDirs, TARGET, SOURCE)} $)', + '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, ' + 'TARGET, SOURCE)}', + '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, ' + 'TARGET, SOURCE, affect_signature=False)}', + '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, ' + 'RDirs, TARGET, SOURCE, affect_signature=False)}', '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', '__DRPATH': '$_DRPATH', '__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', '__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', '__RPATH': '$_RPATH', '__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', + '__lib_either_version_flag': <function __lib_either_version_flag at 0x700000>, '__libversionflags': <function __libversionflags at 0x700000>, '_concat': <function _concat at 0x700000>, '_defines': <function _defines at 0x700000>, diff -Nru scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_2.xml scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_2.xml --- scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_2.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_2.xml 2022-07-30 21:48:28.000000000 +0000 @@ -10,9 +10,9 @@ '_InternalInstallVersionedLib': <function InstallVersionedBuilderWrapper at 0x700000>}, 'CC': 'cl', 'CCCOM': <SCons.Action.FunctionAction object at 0x700000>, + 'CCDEPFLAGS': '/showIncludes', 'CCFLAGS': ['/nologo'], - 'CCPCHFLAGS': [ '${(PCH and "/Yu%s \\"/Fp%s\\""%(PCHSTOP or "",File(PCH))) ' - 'or ""}'], + 'CCPCHFLAGS': <function gen_ccpchflags at 0x700000>, 'CCPDBFLAGS': ['${(PDB and "/Z7") or ""}'], 'CFILESUFFIX': '.c', 'CFLAGS': [], @@ -53,7 +53,7 @@ 'SystemRoot': 'C:\\WINDOWS'}, 'ESCAPE': <function escape at 0x700000>, 'File': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'HOST_ARCH': '', + 'HOST_ARCH': 'arm64', 'HOST_OS': 'win32', 'IDLSUFFIXES': ['.idl', '.IDL'], 'INCPREFIX': '/I', @@ -67,6 +67,7 @@ 'LIBSUFFIXES': ['$LIBSUFFIX'], 'MAXLINELENGTH': 2048, 'MSVC_SETUP_RUN': True, + 'NINJA_DEPFILE_PARSE_FORMAT': 'msvc', 'OBJPREFIX': '', 'OBJSUFFIX': '.obj', 'PCHCOM': '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS ' @@ -82,7 +83,7 @@ 'RCFLAGS': ['/nologo'], 'RCSUFFIXES': ['.rc', '.rc2'], 'RDirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'SCANNERS': [<SCons.Scanner.Base object at 0x700000>], + 'SCANNERS': [<SCons.Scanner.ScannerBase object at 0x700000>], 'SHCC': '$CC', 'SHCCCOM': <SCons.Action.FunctionAction object at 0x700000>, 'SHCCFLAGS': ['$CCFLAGS'], @@ -101,22 +102,24 @@ 'TARGET_ARCH': None, 'TARGET_OS': None, 'TEMPFILE': <class 'SCons.Platform.TempFileMunge'>, + 'TEMPFILEARGESCFUNC': <function quote_spaces at 0x700000>, 'TEMPFILEARGJOIN': '\n', 'TEMPFILEPREFIX': '@', 'TOOLS': ['msvc', 'install', 'install'], 'VSWHERE': None, '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS', - '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, ' - '__env__)}', - '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, ' - 'TARGET, SOURCE)} $)', - '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, ' - 'RDirs, TARGET, SOURCE)} $)', + '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, ' + 'TARGET, SOURCE)}', + '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, ' + 'TARGET, SOURCE, affect_signature=False)}', + '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, ' + 'RDirs, TARGET, SOURCE, affect_signature=False)}', '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', '_MSVC_OUTPUT_FLAG': <function msvc_output_flag at 0x700000>, '__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', '__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', '__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', + '__lib_either_version_flag': <function __lib_either_version_flag at 0x700000>, '__libversionflags': <function __libversionflags at 0x700000>, '_concat': <function _concat at 0x700000>, '_defines': <function _defines at 0x700000>, diff -Nru scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_ENV_1.xml scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_ENV_1.xml --- scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_Dump_ENV_1.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_Dump_ENV_1.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ % scons scons: Reading SConscript files ... -{'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'} +{'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin:/snap/bin'} scons: done reading SConscript files. scons: Building targets ... scons: `.' is up to date. diff -Nru scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_explain1_3.xml scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_explain1_3.xml --- scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_explain1_3.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_explain1_3.xml 2022-07-30 21:48:28.000000000 +0000 @@ -2,5 +2,5 @@ cp file.in file.oout scons: warning: Cannot find target file.out after building -File "/Users/bdbaddog/devel/scons/git/as_scons/scripts/scons.py", line 96, in <module> +File "/Users/bdbaddog/devel/scons/git/as_scons/scripts/scons.py", line 97, in <module> diff -Nru scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_stacktrace_2.xml scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_stacktrace_2.xml --- scons-4.0.1+dfsg/doc/generated/examples/troubleshoot_stacktrace_2.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/examples/troubleshoot_stacktrace_2.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,12 +1,12 @@ % scons -Q --debug=stacktrace scons: *** [prog.o] Source `prog.c' not found, needed by target `prog.o'. scons: internal stack trace: - File "SCons/Job.py", line 199, in start + File "SCons/Job.py", line 203, in start task.prepare() - File "SCons/Script/Main.py", line 190, in prepare + File "SCons/Script/Main.py", line 180, in prepare return SCons.Taskmaster.OutOfDateTask.prepare(self) - File "SCons/Taskmaster.py", line 195, in prepare + File "SCons/Taskmaster.py", line 186, in prepare executor.prepare() - File "SCons/Executor.py", line 429, in prepare + File "SCons/Executor.py", line 418, in prepare raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0])) diff -Nru scons-4.0.1+dfsg/doc/generated/functions.gen scons-4.4.0+dfsg/doc/generated/functions.gen --- scons-4.0.1+dfsg/doc/generated/functions.gen 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/functions.gen 2022-07-30 21:48:28.000000000 +0000 @@ -13,8 +13,8 @@ - Action(action, [cmd/str/fun, [var, ...]] [option=value, ...]) - env.Action(action, [cmd/str/fun, [var, ...]] [option=value, ...]) + Action(action, [output, [var, ...]] [key=value, ...]) + env.Action(action, [output, [var, ...]] [key=value, ...]) A factory function to create an Action object for the specified @@ -44,54 +44,40 @@ AddMethod(object, function, [name]) env.AddMethod(function, [name]) -When called with the -AddMethod() -form, -adds the specified -function -to the specified -object -as the specified method -name. -When called using the -&f-env-AddMethod; form, -adds the specified -function -to the construction environment -env -as the specified method -name. -In both cases, if -name -is omitted or -None, -the name of the -specified -function -itself is used for the method name. +Adds function to an object as a method. +function will be called with an instance +object as the first argument as for other methods. +If name is given, it is used as +the name of the new method, else the name of +function is used. + + +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. -Examples: +More examples: -# 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') @@ -106,13 +92,13 @@ method in the standard Python library module optparse, with a few additional capabilities noted below. See the documentation for -optparse +optparse for a thorough discussion of its option-processing capabities. In addition to the arguments and values supported by the -optparse +optparse add_option method, &f-AddOption; allows setting the @@ -150,10 +136,10 @@ and so forth as long as there is no other option which could also match to the same abbreviation. Options added via -AddOption 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. @@ -169,7 +155,7 @@ The value may also be set using &f-SetOption; or -env.SetOption(), +&f-env.SetOption;, if conditions in a &SConscript; require overriding any default value. @@ -439,55 +425,171 @@ env.Append(key=val, [...]) -Appends the specified keyword arguments -to the end of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the values of the construction variable -and the keyword argument are the same type, -then the two values will be simply added together. -Otherwise, the construction variable -and the value of the keyword argument -are both coerced to lists, -and the lists are added together. -(See also the &Prepend; method). +Intelligently append values to &consvars; in the &consenv; +named by env. +The &consvars; and values to add to them are passed as +key=val pairs (&Python; keyword arguments). +&f-env-Append; is designed to allow adding values +without normally having to know the data type of an existing &consvar;. +Regular &Python; syntax can also be used to manipulate the &consvar;, +but for that you must know the type of the &consvar;: +for example, different &Python; syntax is needed to combine +a list of values with a single string value, or vice versa. +Some pre-defined &consvars; do have type expectations +based on how &SCons; will use them, +for example &cv-link-CPPDEFINES; is normally a string or a list of strings, +but can be a string, +a list of strings, +a list of tuples, +or a dictionary, while &cv-link-LIBEMITTER; +would expect a callable or list of callables, +and &cv-link-BUILDERS; would expect a mapping type. +Consult the documentation for the various &consvars; for more details. -Example: +The following descriptions apply to both the append +and prepend functions, the only difference being +the insertion point of the added values. + + +If env. does not have a &consvar; +indicated by key, +val +is added to the environment under that key as-is. + + + +val can be almost any type, +and &SCons; will combine it with an existing value into an appropriate type, +but there are a few special cases to be aware of. +When two strings are combined, +the result is normally a new string, +with the caller responsible for supplying any needed separation. +The exception to this is the &consvar; &cv-link-CPPDEFINES;, +in which each item will be postprocessed by adding a prefix +and/or suffix, +so the contents are treated as a list of strings, that is, +adding a string will result in a separate string entry, +not a combined string. For &cv-CPPDEFINES; as well as +for &cv-link-LIBS;, and the various *PATH; +variables, &SCons; will supply the compiler-specific +syntax (e.g. adding a -D or /D +prefix for &cv-CPPDEFINES;), so this syntax should be omitted when +adding values to these variables. +Example (gcc syntax shown in the expansion of &CPPDEFINES;): + + + +env = Environment(CXXFLAGS="-std=c11", CPPDEFINES="RELEASE") +print("CXXFLAGS={}, CPPDEFINES={}".format(env['CXXFLAGS'], env['CPPDEFINES'])) +# notice including a leading space in CXXFLAGS value +env.Append(CXXFLAGS=" -O", CPPDEFINES="EXTRA") +print("CXXFLAGS={}, CPPDEFINES={}".format(env['CXXFLAGS'], env['CPPDEFINES'])) +print("CPPDEFINES will expand to {}".format(env.subst("$_CPPDEFFLAGS"))) + + + +$ scons -Q +CXXFLAGS=-std=c11, CPPDEFINES=RELEASE +CXXFLAGS=-std=c11 -O, CPPDEFINES=['RELEASE', 'EXTRA'] +CPPDEFINES will expand to -DRELEASE -DEXTRA +scons: `.' is up to date. + + + +Because &cv-link-CPPDEFINES; is intended to +describe C/C++ pre-processor macro definitions, +it accepts additional syntax. +Preprocessor macros can be valued, or un-valued, as in +-DBAR=1 or +-DFOO. +The macro can be be supplied as a complete string including the value, +or as a tuple (or list) of macro, value, or as a dictionary. +Example (again gcc syntax in the expanded defines): + + + +env = Environment(CPPDEFINES="FOO") +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES="BAR=1") +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES=("OTHER", 2)) +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES={"EXTRA": "arg"}) +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +print("CPPDEFINES will expand to {}".format(env.subst("$_CPPDEFFLAGS"))) + + + +$ scons -Q +CPPDEFINES=FOO +CPPDEFINES=['FOO', 'BAR=1'] +CPPDEFINES=['FOO', 'BAR=1', ('OTHER', 2)] +CPPDEFINES=['FOO', 'BAR=1', ('OTHER', 2), {'EXTRA': 'arg'}] +CPPDEFINES will expand to -DFOO -DBAR=1 -DOTHER=2 -DEXTRA=arg +scons: `.' is up to date. + + + +Adding a string val +to a dictonary &consvar; will enter +val as the key in the dict, +and None as its value. +Using a tuple type to supply a key + value only works +for the special case of &cv-link-CPPDEFINES; +described above. + + + +Although most combinations of types work without +needing to know the details, some combinations +do not make sense and a &Python; exception will be raised. + + + +When using &f-env-Append; to modify &consvars; +which are path specifications (conventionally, +the names of such end in PATH), +it is recommended to add the values as a list of strings, +even if there is only a single string to add. +The same goes for adding library names to &cv-LIBS;. -env.Append(CCFLAGS = ' -g', FOO = ['foo.yyy']) +env.Append(CPPPATH=["#/include"]) + + +See also &f-link-env-AppendUnique;, +&f-link-env-Prepend; and &f-link-env-PrependUnique;. + + - env.AppendENVPath(name, newpath, [envname, sep, delete_existing]) + env.AppendENVPath(name, newpath, [envname, sep, delete_existing=False]) -This appends new path elements to the given path in the -specified external environment -(ENV -by default). -This will only add -any particular path once (leaving the last one it encounters and -ignoring the rest, to preserve path order), -and to help assure this, -will normalize all paths (using -os.path.normpath +Append path elements specified by newpath +to the given search path string or list name +in mapping envname in the &consenv;. +Supplying envname is optional: +the default is the execution environment &cv-link-ENV;. +Optional sep is used as the search path separator, +the default is the platform's separator (os.pathsep). +A path element will only appear once. +Any duplicates in newpath are dropped, +keeping the last appearing (to preserve path order). +If delete_existing +is False (the default) +any addition duplicating an existing path element is ignored; +if delete_existing +is True the existing value will +be dropped and the path element will be added at the end. +To help maintain uniqueness all paths are normalized (using +os.path.normpath and -os.path.normcase). -This can also handle the -case where the given old path variable is a list instead of a -string, in which case a list will be returned instead of a string. - - - -If -delete_existing -is 0, then adding a path that already exists -will not move it to the end; it will stay where it is in the list. +os.path.normcase). @@ -495,33 +597,37 @@ -print 'before:',env['ENV']['INCLUDE'] +print('before:', env['ENV']['INCLUDE']) include_path = '/foo/bar:/foo' env.AppendENVPath('INCLUDE', include_path) -print 'after:',env['ENV']['INCLUDE'] +print('after:', env['ENV']['INCLUDE']) + -yields: +Yields: + before: /foo:/biz after: /biz:/foo/bar:/foo - + + + +See also &f-link-env-PrependENVPath;. + + - env.AppendUnique(key=val, [...], delete_existing=0) + env.AppendUnique(key=val, [...], delete_existing=False) -Appends the specified keyword arguments -to the end of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the construction variable being appended to is a list, -then any value(s) that already exist in the -construction variable will -not -be added again to the list. -However, if delete_existing is 1, -existing matching values are removed first, so -existing values in the arg list move to the end of the list. +Append values to &consvars; in the current &consenv;, +maintaining uniqueness. +Works like &f-link-env-Append; (see for details), +except that values already present in the &consvar; +will not be added again. +If delete_existing +is True, +the existing matching value is first removed, +and the requested value is added, +having the effect of moving such values to the end. @@ -529,8 +635,14 @@ -env.AppendUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) +env.AppendUnique(CCFLAGS='-g', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-Prepend; +and &f-link-env-PrependUnique;. + @@ -554,7 +666,7 @@ argument, at the time it is called using the construction variables in the -env +env construction environment through which &f-env-Builder; was called. The @@ -565,8 +677,8 @@ - CacheDir(cache_dir) - env.CacheDir(cache_dir) + CacheDir(cache_dir, custom_class=None) + env.CacheDir(cache_dir, custom_class=None) Direct &scons; @@ -583,6 +695,15 @@ +When specifying a +custom_class which should be a class type which is a subclass of +SCons.CacheDir.CacheDir, SCons will +internally invoke this class to use for performing caching operations. +This argument is optional and if left to default None, will use the +default SCons.CacheDir.CacheDir class. + + + Calling the environment method &f-link-env-CacheDir; limits the effect to targets built @@ -597,12 +718,12 @@ -When derived-file caching +When derived-file caching is being used and &scons; finds a derived file that needs to be rebuilt, it will first look in the cache to see if a -file with matching build signature exists +file with matching &buildsig; exists (indicating the input file(s) and build action(s) were identical to those for the current target), and if so, will retrieve the file from the cache. @@ -614,7 +735,7 @@ &scons; will build it and then place a copy of the built file in the cache, -identified by its build signature, for future use. +identified by its &buildsig;, for future use. @@ -658,7 +779,7 @@ cache_dir is used for a build, or to bring a cache up to date after -a build with cache updating disabled +a build with cache updating disabled ( or ) has been done. @@ -671,6 +792,13 @@ useful if inputs and/or outputs of some tool are impossible to predict or prohibitively large. + + +Note that (at this time) &SCons; provides no facilities +for managing the derived-file cache. It is up to the developer +to arrange for cache pruning, expiry, etc. if needed. + + @@ -751,7 +879,7 @@ env2 = env.Clone() -env3 = env.Clone(CCFLAGS = '-g') +env3 = env.Clone(CCFLAGS='-g') @@ -760,8 +888,10 @@ -def MyTool(env): env['FOO'] = 'bar' -env4 = env.Clone(tools = ['msvc', MyTool]) +def MyTool(env): + env['FOO'] = 'bar' + +env4 = env.Clone(tools=['msvc', MyTool]) @@ -826,7 +956,7 @@ An action can be an external command, specified as a string, -or a callable Python object; +or a callable &Python; object; see the manpage section "Action Objects" for more complete information. Also note that a string specifying an external command @@ -963,24 +1093,24 @@ -"MD5" +"content" Specifies that a target shall be considered out of date and rebuilt if the dependency's content has changed since the last time the target was built, -as determined be performing an MD5 checksum +as determined be performing an checksum on the dependency's contents and comparing it to the checksum recorded the last time the target was built. -content +MD5 can be used as a synonym for -MD5. +content, but it is deprecated. -"MD5-timestamp" +"content-timestamp" Specifies that a target shall be considered out of date and rebuilt @@ -993,7 +1123,7 @@ rebuilt. This provides behavior very similar to the -MD5 +content behavior of always checksumming file contents, with an optimization of not checking the contents of files whose timestamps haven't changed. @@ -1006,6 +1136,9 @@ updates a file, and runs the build again, all within a single second. +MD5-timestamp +can be used as a synonym for +content-timestamp, but it is deprecated. @@ -1020,7 +1153,7 @@ # Use exact timestamp matches by default. Decider('timestamp-match') -# Use MD5 content signatures for any targets built +# Use hash content signatures for any targets built # with the attached construction environment. env.Decider('content') @@ -1028,7 +1161,7 @@ In addition to the above already-available functions, the function -argument may be a Python function you supply. +argument may be a &Python; function you supply. Such a function must accept the following four arguments: @@ -1073,7 +1206,7 @@ This can be consulted to match various file characteristics such as the timestamp, -size, or content signature. +size, or &contentsig;.
@@ -1135,32 +1268,46 @@ - Default(targets...) - env.Default(targets...) + Default(target[, ...]) + env.Default(target[, ...]) -This specifies a list of default targets, -which will be built by -&scons; -if no explicit targets are given on the command line. -Multiple calls to +Specify default targets to the &SCons; target selection mechanism. +Any call to &f-Default; will cause &SCons; to use the +defined default target list instead of +its built-in algorithm for determining default targets +(see the manpage section "Target Selection"). + + + +target may be one or more strings, +a list of strings, +a NodeList as returned by a Builder, +or None. +A string target may be the name of +a file or directory, or a target previously defined by a call to +&f-link-Alias; (defining the alias later will still create +the alias, but it will not be recognized as a default). +Calls to &f-Default; are additive. +A target of +None +will clear any existing default target list; +subsequent calls to &f-Default; -are legal, -and add to the list of default targets. -As noted above, both forms of this call affect the +will add to the (now empty) default target list +like normal. + + + +Both forms of this call affect the same global list of default targets; the construction environment method applies construction variable expansion to the targets. -Multiple targets should be specified as -separate arguments to the -&f-Default; -method, or as a list. -&f-Default; -will also accept the Node returned by any -of a construction environment's -builder methods. +The current list of targets added using +&f-Default; is available in the +&DEFAULT_TARGETS; list (see below). @@ -1174,26 +1321,6 @@ env.Default(hello) - -An argument to -&f-Default; -of -None -will clear all default targets. -Later calls to -&f-Default; -will add to the (now empty) default-target list -like normal. - - - -The current list of targets added using the -&f-Default; -function or method is available in the -DEFAULT_TARGETS -list; -see below. - @@ -1275,10 +1402,11 @@ progs may be a string or a list of strings. Returns the first value from progs that was found, or None. -Executable is searched by checking the paths specified -by env['ENV']['PATH']. +Executable is searched by checking the paths in the execution environment +(env['ENV']['PATH']). On Windows systems, additionally applies the filename suffixes found in -env['ENV']['PATHEXT'] +the execution environment +(env['ENV']['PATHEXT']) but will not include any such extension in the return value. &f-env-Detect; is a wrapper around &f-link-env-WhereIs;. @@ -1369,7 +1497,7 @@ -If key is +If key is None (the default) the entire dictionary of &consvars; is serialized. If supplied, it is taken as the name of a &consvar; @@ -1398,7 +1526,7 @@ -env=Environment() +env = Environment() print(env.Dump()) @@ -1471,49 +1599,61 @@ initialized with the specified key=value pairs. +The keyword arguments +parse_flags, +platform, +toolpath, +tools +and variables +are also specially recognized. +See the manpage section "Construction Environments" for more details. - Execute(action, [strfunction, varlist]) - env.Execute(action, [strfunction, varlist]) + Execute(action, [actionargs ...]) + env.Execute(action, [actionargs ...]) -Executes an Action object. -The specified +Executes an Action. action may be an Action object -(see manpage section "Action Objects" -for an explanation of behavior), or it may be a command-line string, list of commands, -or executable Python function, -each of which will be converted +or executable &Python; function, +each of which will first be converted into an Action object and then executed. Any additional arguments to &f-Execute; -(strfunction, varlist) are passed on to the &f-link-Action; factory function -which actually creates the Action object. -The exit value of the command -or return value of the Python function -will be returned. +which actually creates the Action object +(see the manpage section Action Objects +for a description). Example: + + + +Execute(Copy('file.out', 'file.in')) + + +&f-Execute; performs its action immediately, +as part of the SConscript-reading phase. +There are no sources or targets declared in an +&f-Execute; call, so any objects it manipulates +will not be tracked as part of the &SCons; dependency graph. +In the example above, neither +file.out nor +file.in will be tracked objects. -Note that +&f-Execute; returns the exit value of the command +or return value of the &Python; function. &scons; -will print an error message if the executed +prints an error message if the executed action -fails--that is, -exits with or returns a non-zero value. -&scons; -will +fails (exits with or returns a non-zero value), +however it does not, -however, -automatically terminate the build -if the specified -action -fails. +automatically terminate the build for such a failure. If you want the build to stop in response to a failed &f-Execute; call, @@ -1521,8 +1661,6 @@ -Execute(Copy('file.out', 'file.in')) - if Execute("mkdir sub/dir/ectory"): # The mkdir failed, don't try to build. Exit(1) @@ -1683,16 +1821,16 @@ -Install( '/bin', [ 'executable_a', 'executable_b' ] ) +Install('/bin', ['executable_a', 'executable_b']) # will return the file node list -# [ '/bin/executable_a', '/bin/executable_b' ] +# ['/bin/executable_a', '/bin/executable_b'] FindInstalledFiles() -Install( '/lib', [ 'some_library' ] ) +Install('/lib', ['some_library']) # will return the file node list -# [ '/bin/executable_a', '/bin/executable_b', '/lib/some_library' ] +# ['/bin/executable_a', '/bin/executable_b', '/lib/some_library'] FindInstalledFiles() @@ -1780,15 +1918,15 @@ -Program( 'src/main_a.c' ) -Program( 'src/main_b.c' ) -Program( 'main_c.c' ) +Program('src/main_a.c') +Program('src/main_b.c') +Program('main_c.c') # returns ['main_c.c', 'src/main_a.c', 'SConstruct', 'src/main_b.c'] FindSourceFiles() # returns ['src/main_b.c', 'src/main_a.c' ] -FindSourceFiles( 'src' ) +FindSourceFiles('src') @@ -1801,7 +1939,7 @@ Flatten(sequence) env.Flatten(sequence) -Takes a sequence (that is, a Python list or tuple) +Takes a sequence (that is, a &Python; list or tuple) that may contain nested sequences and returns a flattened list containing all of the individual elements in any sequence. @@ -1809,7 +1947,7 @@ the lists returned by calls to Builders; other Builders will automatically flatten lists specified as input, -but direct Python manipulation of +but direct &Python; manipulation of these lists does not. @@ -1829,7 +1967,7 @@ # the Builder will flatten the list automatically: Program(source = objects) -# If you need to manipulate the list directly using Python, you need to +# If you need to manipulate the list directly using &Python;, you need to # call Flatten() yourself, or otherwise handle nested lists: for object in Flatten(objects): print(str(object)) @@ -2001,377 +2139,358 @@ env.GetOption(name) This function provides a way to query the value of -SCons options set on scons command line -(or set using the -&f-link-SetOption; -function). -The options supported are: +options which can be set via the command line or using the +&f-link-SetOption; function. - - - -cache_debug - +name can be an entry from the following table, +which shows the corresponding command line arguments +that could affect the value. +name can be also be the destination +variable name from a project-specific option added using the +&f-link-AddOption; function, as long as the addition +happens prior to the &f-GetOption; call in the SConscript files. + + + + + + + Query name + Command-line options + Notes + + + + + + cache_debug + + + + cache_disable + + , + + + + + cache_force + + , + + + + + cache_readonly + + + + cache_show + + + + clean + + , + , + + + + + climb_up + + + + + + + + + + config + + + + debug + + + + directory + , + + + diskcheck + + + + duplicate + + + + enable_virtualenv + + + + experimental + + since 4.2 + + + file + + , + , + , + + + + + hash_format + + since 4.2 + + + help + , + + + ignore_errors + , + + + ignore_virtualenv + + + + implicit_cache + + + + implicit_deps_changed + + + + implicit_deps_unchanged + + + + include_dir + , + + + install_sandbox + + Available only if the &t-link-install; tool has been called + + + keep_going + , + + + max_drift + + + + md5_chunksize + + , + + + since 4.2 + + + no_exec + + , + , + , + , + + + + + no_progress + + + + num_jobs + , + + + package_type + + Available only if the &t-link-packaging; tool has been called + + + profile_file + + + + question + , + + + random + + + + repository + + , + , + + + + + silent + + , + , + + + + + site_dir + , + + + stack_size + + + + taskmastertrace_file + + + + tree_printers + + + + warn + , + + + + + + -which corresponds to ; +See the documentation for the +corresponding command line option for information about each specific +option. - - -cache_disable - - -which corresponds to ; + + + Glob(pattern, [ondisk, source, strings, exclude]) + env.Glob(pattern, [ondisk, source, strings, exclude]) + +Returns Nodes (or strings) that match the specified +pattern, +relative to the directory of the current +&SConscript; +file. +The evironment method form (&f-env-Glob;) +performs string substition on +pattern +and returns whatever matches +the resulting expanded pattern. - - - -cache_force - + -which corresponds to ; +The specified +pattern +uses Unix shell style metacharacters for matching: - - - -cache_show - + + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + -which corresponds to ; +If the first character of a filename is a dot, +it must be matched explicitly. +Character matches do +not +span directory separators. - - - -clean - + -which corresponds to , -and ; +The +&f-Glob; +knows about +repositories +(see the +&f-link-Repository; +function) +and source directories +(see the +&f-link-VariantDir; +function) +and +returns a Node (or string, if so configured) +in the local (SConscript) directory +if a matching Node is found +anywhere in a corresponding +repository or source directory. - - - -config - + -which corresponds to ; +The +ondisk +argument may be set to a value which evaluates +False +to disable the search for matches on disk, +thereby only returning matches among +already-configured File or Dir Nodes. +The default behavior is to +return corresponding Nodes +for any on-disk matches found. - - - -directory - + -which corresponds to and ; +The +source +argument may be set to a value which evaluates +True +to specify that, +when the local directory is a +&f-VariantDir;, +the returned Nodes should be from the +corresponding source directory, +not the local directory. - - - -diskcheck - + -which corresponds to ; +The +strings +argument may be set to a value which evaluates +True +to have the +&f-Glob; +function return strings, not Nodes, +that represent the matched files or directories. +The returned strings will be relative to +the local (SConscript) directory. +(Note that This may make it easier to perform +arbitrary manipulation of file names, +but if the returned strings are +passed to a different +&SConscript; +file, +any Node translation will be relative +to the other +&SConscript; +directory, +not the original +&SConscript; +directory.) - - - -duplicate - - -which corresponds to ; - - - - -file - - -which corresponds to , , and ; - - - - -help - - -which corresponds to and ; - - - - -ignore_errors - - -which corresponds to ; - - - - -implicit_cache - - -which corresponds to ; - - - - -implicit_deps_changed - - -which corresponds to ; - - - - -implicit_deps_unchanged - - -which corresponds to ; - - - - -interactive - - -which corresponds to and ; - - - - -keep_going - - -which corresponds to and ; - - - - -max_drift - - -which corresponds to ; - - - - -no_exec - - -which corresponds to , -, , - and ; - - - - -no_site_dir - - -which corresponds to ; - - - - -num_jobs - - -which corresponds to and ; - - - - -profile_file - - -which corresponds to ; - - - - -question - - -which corresponds to and ; - - - - -random - - -which corresponds to ; - - - - -repository - - -which corresponds to , and ; - - - - -silent - - -which corresponds to , and ; - - - - -site_dir - - -which corresponds to ; - - - - -stack_size - - -which corresponds to ; - - - - -taskmastertrace_file - - -which corresponds to ; and - - - - -warn - - -which corresponds to and . - - - - - - - -See the documentation for the -corresponding command line option for information about each specific -option. - - - - - Glob(pattern, [ondisk, source, strings, exclude]) - env.Glob(pattern, [ondisk, source, strings, exclude]) - -Returns Nodes (or strings) that match the specified -pattern, -relative to the directory of the current -&SConscript; -file. -The evironment method form (&f-env-Glob;) -performs string substition on -pattern -and returns whatever matches -the resulting expanded pattern. - - - -The specified -pattern -uses Unix shell style metacharacters for matching: - - - - * matches everything - ? matches any single character - [seq] matches any character in seq - [!seq] matches any char not in seq - - - -If the first character of a filename is a dot, -it must be matched explicitly. -Character matches do -not -span directory separators. - - - -The -&f-Glob; -knows about -repositories -(see the -&f-link-Repository; -function) -and source directories -(see the -&f-link-VariantDir; -function) -and -returns a Node (or string, if so configured) -in the local (SConscript) directory -if a matching Node is found -anywhere in a corresponding -repository or source directory. - - - -The -ondisk -argument may be set to a value which evaluates -False -to disable the search for matches on disk, -thereby only returning matches among -already-configured File or Dir Nodes. -The default behavior is to -return corresponding Nodes -for any on-disk matches found. - - - -The -source -argument may be set to a value which evaluates -True -to specify that, -when the local directory is a -&f-VariantDir;, -the returned Nodes should be from the -corresponding source directory, -not the local directory. - - - -The -strings -argument may be set to a value which evaluates -True -to have the -&f-Glob; -function return strings, not Nodes, -that represent the matched files or directories. -The returned strings will be relative to -the local (SConscript) directory. -(Note that This may make it easier to perform -arbitrary manipulation of file names, -but if the returned strings are -passed to a different -&SConscript; -file, -any Node translation will be relative -to the other -&SConscript; -directory, -not the original -&SConscript; -directory.) - - + The exclude @@ -2451,8 +2570,8 @@ env.Ignore('foo', 'foo.c') env.Ignore('bar', ['bar1.h', 'bar2.h']) -env.Ignore('.','foobar.obj') -env.Ignore('bar','bar/foobar.obj') +env.Ignore('.', 'foobar.obj') +env.Ignore('bar', 'bar/foobar.obj') @@ -2516,12 +2635,12 @@ env.MergeFlags(arg, [unique]) -Merges the specified +Merges values from arg -values to the construction environment's construction variables. -If the +into &consvars; in the current &consenv;. +If arg -argument is not a dictionary, +is not a dictionary, it is converted to one by calling &f-link-env-ParseFlags; on the argument @@ -2536,19 +2655,17 @@ -By default, -duplicate values are eliminated; -you can, however, specify -unique=0 -to allow duplicate -values to be added. +If unique is true (the default), +duplicate values are not stored. When eliminating duplicate values, -any construction variables that end with +any &consvars; that end with the string PATH keep the left-most unique value. -All other construction variables keep +All other &consvars; keep the right-most unique value. +If unique is false, +values are added even if they are duplicates. @@ -2565,9 +2682,13 @@ # Combine an optimization flag with the flags returned from running pkg-config # twice and merge the result into the construction variables. -env.MergeFlags(['-O3', - '!pkg-config gtk+-2.0 --cflags --libs', - '!pkg-config libpng12 --cflags --libs']) +env.MergeFlags( + [ + '-O3', + '!pkg-config gtk+-2.0 --cflags --libs', + '!pkg-config libpng12 --cflags --libs', + ] +) @@ -2668,38 +2789,52 @@ env.ParseConfig(command, [function, unique]) -Calls the specified -function -to modify the environment as specified by the output of -command. -The default -function -is -&f-link-env-MergeFlags;, -which expects the output of a typical -*-config -command -(for example, -gtk-config) -and adds the options -to the appropriate construction variables. +Updates the current &consenv; with the values extracted +from the output of running external command, +by passing it to a helper function. +command may be a string +or a list of strings representing the command and +its arguments. +If function +is omitted or None, +&f-link-env-MergeFlags; is used. By default, duplicate values are not added to any construction variables; you can specify -unique=0 -to allow duplicate -values to be added. +unique=False +to allow duplicate values to be added. -Interpreted options -and the construction variables they affect -are as specified for the -&f-link-env-ParseFlags; -method (which this method calls). -See that method's description -for a table of options and construction variables. +command is executed using the +SCons execution environment (that is, the &consvar; +&cv-link-ENV; in the current &consenv;). +If command needs additional information +to operate properly, that needs to be set in the execution environment. +For example, pkg-config +may need a custom value set in the PKG_CONFIG_PATH +environment variable. + + + +&f-env-MergeFlags; needs to understand +the output produced by command +in order to distribute it to appropriate &consvars;. +&f-env-MergeFlags; uses a separate function to +do that processing - +see &f-link-env-ParseFlags; for the details, including a +a table of options and corresponding construction variables. +To provide alternative processing of the output of +command, +you can suppply a custom +function, +which must accept three arguments: +the &consenv; to modify, +a string argument containing the output from running +command, +and the optional +unique flag. @@ -2707,8 +2842,7 @@ ParseDepends(filename, [must_exist, only_one]) env.ParseDepends(filename, [must_exist, only_one]) -Parses the contents of the specified -filename +Parses the contents of filename as a list of dependencies in the style of &Make; or @@ -2719,27 +2853,21 @@ By default, it is not an error -if the specified -filename +if filename does not exist. The optional must_exist -argument may be set to a non-zero -value to have -scons -throw an exception and -generate an error if the file does not exist, +argument may be set to True +to have &SCons; +raise an exception if the file does not exist, or is otherwise inaccessible. The optional only_one -argument may be set to a non-zero -value to have -scons -thrown an exception and -generate an error +argument may be set to True +to have &SCons; raise an exception if the file contains dependency information for more than one target. This can provide a small sanity check @@ -2755,7 +2883,6 @@ -The filename and all of the files listed therein will be interpreted relative to @@ -2771,10 +2898,10 @@ env.ParseFlags(flags, ...) Parses one or more strings containing -typical command-line flags for GCC tool chains +typical command-line flags for GCC-style tool chains and returns a dictionary with the flag values separated into the appropriate SCons construction variables. -This is intended as a companion to the +Intended as a companion to the &f-link-env-MergeFlags; method, but allows for the values in the returned dictionary to be modified, if necessary, @@ -2783,17 +2910,26 @@ &f-env-MergeFlags; will call this method if its argument is not a dictionary, so it is usually not necessary to call -&f-link-env-ParseFlags; +&f-env-ParseFlags; directly unless you want to manipulate the values.) If the first character in any string is -an exclamation mark (!), +an exclamation mark (!), the rest of the string is executed as a command, and the output from the command is parsed as GCC tool chain command-line flags and added to the resulting dictionary. +This can be used to call a *-config +command typical of the POSIX programming environment +(for example, +pkg-config). +Note that such a comamnd is executed using the +SCons execution environment; +if the command needs additional information, +that information needs to be explcitly provided. +See &f-link-ParseConfig; for more details. @@ -2853,16 +2989,18 @@ - Platform(string) + Platform(plat) + env.Platform(plat) -The -&f-Platform; -form returns a callable object +When called as a global function, +returns a callable platform object +selected by plat +(defaults to the detected platform for the +current system) that can be used to initialize -a construction environment using the -platform keyword of the -&f-Environment; -function. +a construction environment by passing it as the +platform keyword argument to the +&f-link-Environment; function. @@ -2870,15 +3008,14 @@ -env = Environment(platform = Platform('win32')) +env = Environment(platform=Platform('win32')) -The -&f-env-Platform; -form applies the callable object for the specified platform -string -to the environment through which the method was called. +When called as a method of an environment, +calls the platform object indicated by +plat +to update that environment. @@ -2886,22 +3023,7 @@ -Note that the -win32 -platform adds the -SystemDrive -and -SystemRoot -variables from the user's external environment -to the construction environment's -&cv-link-ENV; -dictionary. -This is so that any executed commands -that use sockets to connect with other systems -(such as fetching source files from -external CVS repository specifications like -:pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons) -will work on Windows systems. +See the manpage section "Construction Environments" for more details. @@ -2922,19 +3044,10 @@ env.Prepend(key=val, [...]) -Appends the specified keyword arguments -to the beginning of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the values of the construction variable -and the keyword argument are the same type, -then the two values will be simply added together. -Otherwise, the construction variable -and the value of the keyword argument -are both coerced to lists, -and the lists are added together. -(See also the Append method, above.) +Prepend values to &consvars; in the current &consenv;, +Works like &f-link-env-Append; (see for details), +except that values are added to the front, +rather than the end, of any existing value of the &consvar; @@ -2942,36 +3055,39 @@ -env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy']) +env.Prepend(CCFLAGS='-g ', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-AppendUnique; +and &f-link-env-PrependUnique;. + - env.PrependENVPath(name, newpath, [envname, sep, delete_existing]) + env.PrependENVPath(name, newpath, [envname, sep, delete_existing=True]) -This appends new path elements to the given path in the -specified external environment -(&cv-ENV; -by default). -This will only add -any particular path once (leaving the first one it encounters and -ignoring the rest, to preserve path order), -and to help assure this, -will normalize all paths (using -os.path.normpath +Prepend path elements specified by newpath +to the given search path string or list name +in mapping envname in the &consenv;. +Supplying envname is optional: +the default is the execution environment &cv-link-ENV;. +Optional sep is used as the search path separator, +the default is the platform's separator (os.pathsep). +A path element will only appear once. +Any duplicates in newpath are dropped, +keeping the first appearing (to preserve path order). +If delete_existing +is False +any addition duplicating an existing path element is ignored; +if delete_existing +is True (the default) the existing value will +be dropped and the path element will be inserted at the beginning. +To help maintain uniqueness all paths are normalized (using +os.path.normpath and -os.path.normcase). -This can also handle the -case where the given old path variable is a list instead of a -string, in which case a list will be returned instead of a string. - - - -If -delete_existing -is 0, then adding a path that already exists -will not move it to the beginning; -it will stay where it is in the list. +os.path.normcase). @@ -2979,38 +3095,40 @@ -print 'before:',env['ENV']['INCLUDE'] +print('before:', env['ENV']['INCLUDE']) include_path = '/foo/bar:/foo' env.PrependENVPath('INCLUDE', include_path) -print 'after:',env['ENV']['INCLUDE'] +print('after:', env['ENV']['INCLUDE']) - -The above example will print: - +Yields: - + before: /biz:/foo after: /foo/bar:/foo:/biz - + + + +See also &f-link-env-AppendENVPath;. + + - env.PrependUnique(key=val, delete_existing=0, [...]) + env.PrependUnique(key=val, delete_existing=False, [...]) -Appends the specified keyword arguments -to the beginning of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the construction variable being appended to is a list, -then any value(s) that already exist in the -construction variable will -not -be added again to the list. -However, if delete_existing is 1, -existing matching values are removed first, so -existing values in the arg list move to the front of the list. +Prepend values to &consvars; in the current &consenv;, +maintaining uniqueness. +Works like &f-link-env-Append; (see for details), +except that values are added to the front, +rather than the end, of any existing value of the &consvar;, +and values already present in the &consvar; +will not be added again. +If delete_existing +is True, +the existing matching value is first removed, +and the requested value is inserted, +having the effect of moving such values to the front. @@ -3018,8 +3136,14 @@ -env.PrependUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) +env.PrependUnique(CCFLAGS='-g', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-AppendUnique; +and &f-link-env-Prepend;. + @@ -3206,7 +3330,7 @@ -env.Replace(CCFLAGS = '-g', FOO = 'foo.xxx') +env.Replace(CCFLAGS='-g', FOO='foo.xxx') @@ -3341,8 +3465,8 @@ - Scanner(function, [argument, keys, path_function, node_class, node_factory, scan_check, recursive]) - env.Scanner(function, [argument, keys, path_function, node_class, node_factory, scan_check, recursive]) + Scanner(function, [name, argument, skeys, path_function, node_class, node_factory, scan_check, recursive]) + env.Scanner(function, [name, argument, skeys, path_function, node_class, node_factory, scan_check, recursive]) Creates a Scanner object for the specified @@ -3355,40 +3479,36 @@ SConscript(scripts, [exports, variant_dir, duplicate, must_exist]) env.SConscript(scripts, [exports, variant_dir, duplicate, must_exist]) - SConscript(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist]) - env.SConscript(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist]) + SConscript(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist]) + env.SConscript(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist]) -Execute one or more subsidiary SConscript (configuration) files. +Executes one or more subsidiary SConscript (configuration) files. There are two ways to call the &f-SConscript; function. -The first calling style -is to explicitly specify one or more -scripts -as the first argument. +The first calling style is to supply +one or more SConscript file names +as the first (positional) argument. A single script may be specified as a string; -multiple scripts must be specified as a list +multiple scripts must be specified as a list of strings (either explicitly or as created by a function like &f-link-Split;). Examples: -SConscript('SConscript') # run SConscript in the current directory +SConscript('SConscript') # run SConscript in the current directory SConscript('src/SConscript') # run SConscript in the src directory SConscript(['src/SConscript', 'doc/SConscript']) config = SConscript('MyConfig.py') -The second way to call -&f-SConscript; -is to specify a list of (sub)directory names -as a -dirs=subdirs -keyword argument. +The other calling style is to omit the positional argument naming +scripts and instead specify a list of directory names using the +dirs keyword argument. In this case, &scons; will @@ -3398,14 +3518,14 @@ You may specify a name other than &SConscript; by supplying an optional -name=script +name=scriptname keyword argument. The first three examples below have the same effect as the first three examples above: -SConscript(dirs='.') # run SConscript in the current directory -SConscript(dirs='src') # run SConscript in the src directory +SConscript(dirs='.') # run SConscript in the current directory +SConscript(dirs='src') # run SConscript in the src directory SConscript(dirs=['src', 'doc']) SConscript(dirs=['sub1', 'sub2'], name='MySConscript') @@ -3413,8 +3533,12 @@ The optional exports -argument provides a string or list of strings representing +keyword argument provides a string or list of strings representing variable names, or a dictionary of named values, to export. +For the first calling style only, a second positional argument +will be interpreted as exports; the +second calling style must use the keyword argument form +for exports. These variables are locally exported only to the called SConscript file(s) and do not affect the global pool of variables managed by the @@ -3438,38 +3562,24 @@ If the optional variant_dir argument is present, it causes an effect equivalent to the -&f-link-VariantDir; function. +&f-link-VariantDir; function, +but in effect only within the scope of the &f-SConscript; call. The variant_dir -argument is interpreted relative to the directory of the calling -SConscript file. -The optional -duplicate argument is -interpreted as for &f-link-VariantDir;. -If variant_dir -is omitted, the duplicate argument is ignored. -See the description of -&f-link-VariantDir; -below for additional details and restrictions. - - - -If -variant_dir -is present, -the source directory is the directory in which the -SConscript -file resides and the -SConscript +argument is interpreted relative to the directory of the +calling SConscript file. +The source directory is the directory in which the +called SConscript +file resides and the SConscript file is evaluated as if it were in the variant_dir -directory: +directory. Thus: SConscript('src/SConscript', variant_dir='build') -is equivalent to +is equivalent to: @@ -3478,9 +3588,8 @@ -This later paradigm is often used when the sources are -in the same directory as the -&SConstruct;: +If the sources are in the same directory as the +&SConstruct;, @@ -3488,7 +3597,7 @@ -is equivalent to +is equivalent to: @@ -3497,6 +3606,17 @@ +The optional +duplicate argument is +interpreted as for &f-link-VariantDir;. +If the variant_dir argument +is omitted, the duplicate argument is ignored. +See the description of +&f-link-VariantDir; +for additional details and restrictions. + + + +to set up multiple variant builds with different options. -The default behavior is for -&scons; -to physically duplicate the source files in 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 -relative to the source file, -or individual compilers or other invoked tools are hard-coded -to put derived files in the same directory as source files. +Note if variant_dir +is not under the project top directory, +target selection rules will not pick targets in the +variant directory unless they are explicitly specified. +When files in variant_dir are referenced, +&SCons; backfills as needed with files from src_dir +to create a complete build directory. +By default, &SCons; +physically duplicates the source files, SConscript files, +and directory structure as needed into the variant directory. +Thus, a build performed in the variant directory is guaranteed to be identical +to a build performed in the source directory even if +intermediate source files are generated during the build, +or if preprocessors or other scanners search for included files +using paths relative to the source file, +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 variant_dir. 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 command-line option. -Moreover, only the files needed for the build are duplicated; -files and directories that are not used are not present in -variant_dir. -Duplicating the source tree may be disabled by setting the -duplicate +Duplicating the source files may be disabled by setting the +duplicate argument to -0 -(zero). +False. This will cause -&scons; +&SCons; to invoke Builders using the path names of source files in src_dir and the path names of derived files within variant_dir. -This is always more efficient than -duplicate=1, -and is usually safe for most builds -(but see above for cases that may cause problems). +This is more efficient than duplicating, +and is safe for most builds; +revert to duplicate=True +if it causes problems. -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 when used with a subsidiary SConscript file. +The subsidiary SConscript file must be called as if it were in variant_dir, regardless of the value of -duplicate. -This is how you tell -&scons; -which variant of a source tree to build: +duplicate. +When calling an SConscript file, you can use the +exports keyword argument +to pass parameters (individually or as an appropriately set up environment) +so the SConscript can pick up the right settings for that variant build. +The SConscript must &f-link-Import; these to use them. Example: +env1 = Environment(...settings for variant1...) +env2 = Environment(...settings for variant2...) + # run src/SConscript in two variant directories VariantDir('build/variant1', 'src') -SConscript('build/variant1/SConscript') +SConscript('build/variant1/SConscript', exports={"env": env1}) VariantDir('build/variant2', 'src') -SConscript('build/variant2/SConscript') +SConscript('build/variant2/SConscript', exports={"env": env2}) See also the -&f-link-SConscript; -function, described above, +&f-link-SConscript; function for another way to specify a variant directory in conjunction with calling a subsidiary SConscript file. -Examples: +More examples: # use names in the build directory, not the source directory VariantDir('build', 'src', duplicate=0) Program('build/prog', 'build/source.c') - - # this builds both the source and docs in a separate subtree VariantDir('build', '.', duplicate=0) SConscript(dirs=['build/src','build/doc']) - - # 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) @@ -4356,11 +4588,11 @@ path keyword argument, or if None (the default) the paths listed in the &consenv; -(env['ENV']['PATH']). +(env['ENV']['PATH']). The external environment's path list (os.environ['PATH']) is used as a fallback if the key -env['ENV']['PATH'] +env['ENV']['PATH'] does not exist. @@ -4369,11 +4601,11 @@ pathext keyword argument, or if None (the default) the pathname extensions listed in the &consenv; -(env['ENV']['PATHEXT']). +(env['ENV']['PATHEXT']). The external environment's pathname extensions list (os.environ['PATHEXT']) is used as a fallback if the key -env['ENV']['PATHEXT'] +env['ENV']['PATHEXT'] does not exist. diff -Nru scons-4.0.1+dfsg/doc/generated/tools.gen scons-4.4.0+dfsg/doc/generated/tools.gen --- scons-4.0.1+dfsg/doc/generated/tools.gen 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/tools.gen 2022-07-30 21:48:28.000000000 +0000 @@ -82,14 +82,14 @@ Sets construction variables for generic POSIX C compilers. -Sets: &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCFLAGS;, &cv-link-CFILESUFFIX;, &cv-link-CFLAGS;, &cv-link-CPPDEFPREFIX;, &cv-link-CPPDEFSUFFIX;, &cv-link-FRAMEWORKPATH;, &cv-link-FRAMEWORKS;, &cv-link-INCPREFIX;, &cv-link-INCSUFFIX;, &cv-link-SHCC;, &cv-link-SHCCCOM;, &cv-link-SHCCFLAGS;, &cv-link-SHCFLAGS;, &cv-link-SHOBJSUFFIX;.Uses: &cv-link-CCCOMSTR;, &cv-link-PLATFORM;, &cv-link-SHCCCOMSTR;. +Sets: &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCDEPFLAGS;, &cv-link-CCFLAGS;, &cv-link-CFILESUFFIX;, &cv-link-CFLAGS;, &cv-link-CPPDEFPREFIX;, &cv-link-CPPDEFSUFFIX;, &cv-link-FRAMEWORKPATH;, &cv-link-FRAMEWORKS;, &cv-link-INCPREFIX;, &cv-link-INCSUFFIX;, &cv-link-SHCC;, &cv-link-SHCCCOM;, &cv-link-SHCCFLAGS;, &cv-link-SHCFLAGS;, &cv-link-SHOBJSUFFIX;.Uses: &cv-link-CCCOMSTR;, &cv-link-PLATFORM;, &cv-link-SHCCCOMSTR;. clang Set construction variables for the Clang C compiler. -Sets: &cv-link-CC;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;. +Sets: &cv-link-CC;, &cv-link-CCDEPFLAGS;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;. clangxx @@ -103,7 +103,7 @@ Sets up &b-link-CompilationDatabase; builder which generates a clang tooling compatible compilation database. - Sets: &cv-link-COMPILATIONDB_COMSTR;, &cv-link-COMPILATIONDB_USE_ABSPATH;. + Sets: &cv-link-COMPILATIONDB_COMSTR;, &cv-link-COMPILATIONDB_PATH_FILTER;, &cv-link-COMPILATIONDB_USE_ABSPATH;. cvf @@ -144,67 +144,79 @@ Some tools will not initialize if an underlying command is not found, and some tools are selected from a list of choices on a first-found basis. The finished tool list can be -examined by inspecting the TOOLS &consvar; +examined by inspecting the &cv-link-TOOLS; &consvar; in the &consenv;. -On all platforms, all tools from the following list -are selected whose respective conditions are met: -filesystem, wix, lex, yacc, rpcgen, swig, -jar, javac, javah, rmic, dvipdf, dvips, gs, -tex, latex, pdflatex, pdftex, tar, zip, textfile. +On all platforms, the tools from the following list +are selected if their respective conditions are met: + filesystem;, + wix, +&t-link-lex;, &t-link-yacc;, +&t-link-rpcgen;, &t-link-swig;, +&t-link-jar;, &t-link-javac;, &t-link-javah;, &t-link-rmic;, +&t-link-dvipdf;, &t-link-dvips;, &t-link-gs;, +&t-link-tex;, &t-link-latex;, &t-link-pdflatex;, &t-link-pdftex;, +&t-link-tar;, &t-link-zip;, &t-link-textfile;. On Linux systems, the default tools list selects (first-found): a C compiler from -gcc, intelc, icc, cc; +&t-link-gcc;, &t-link-intelc;, &t-link-icc;, &t-link-cc;; a C++ compiler from -g++, intelc, icc, cxx; +&t-link-gXX;, &t-link-intelc;, &t-link-icc;, &t-link-cXX;; an assembler from -gas, nasm, masm; +&t-link-gas;, &t-link-nasm;, &t-link-masm;; a linker from -gnulink, ilink; +&t-link-gnulink;, &t-link-ilink;; a Fortran compiler from -gfortran, g77, ifort, ifl, f95, f90, f77; -and a static archiver 'ar'. +&t-link-gfortran;, &t-link-g77;, &t-link-ifort;, &t-link-ifl;, +&t-link-f95;, &t-link-f90;, &t-link-f77;; +and a static archiver &t-link-ar;. It also selects all found from the list -m4, rpm. +&t-link-m4; + rpm. On Windows systems, the default tools list selects (first-found): a C compiler from -msvc, mingw, gcc, intelc, icl, icc, cc, bcc32; +&t-link-msvc;, &t-link-mingw;, &t-link-gcc;, &t-link-intelc;, +&t-link-icl;, &t-link-icc;, &t-link-cc;, &t-link-bcc32;; a C++ compiler from -msvc, intelc, icc, g++, cxx, bcc32; +&t-link-msvc;, &t-link-intelc;, &t-link-icc;, &t-link-gXX;, +&t-link-cXX;, &t-link-bcc32;; an assembler from -masm, nasm, gas, 386asm; +&t-link-masm;, &t-link-nasm;, &t-link-gas;, &t-link-386asm;; a linker from -mslink, gnulink, ilink, linkloc, ilink32; +&t-link-mslink;, &t-link-gnulink;, &t-link-ilink;, +&t-link-linkloc;, &t-link-ilink32;; a Fortran compiler from -gfortran, g77, ifl, cvf, f95, f90, fortran; +&t-link-gfortran;, &t-link-g77;, &t-link-ifl;, &t-link-cvf;, +&t-link-f95;, &t-link-f90;, &t-link-fortran;; and a static archiver from -mslib, ar, tlib; +&t-link-mslib;, &t-link-ar;, &t-link-tlib;; It also selects all found from the list -msvs, midl. +&t-link-msvs;, &t-link-midl;. On MacOS systems, the default tools list selects (first-found): a C compiler from -gcc, cc; +&t-link-gcc;, &t-link-cc;; a C++ compiler from -g++, cxx; -an assembler 'as'; +&t-link-gXX;, &t-link-cXX;; +an assembler &t-link-as;; a linker from -applelink, gnulink; +&t-link-applelink;, &t-link-gnulink;; a Fortran compiler from -gfortran, f95, f90, g77; -and a static archiver ar. +&t-link-gfortran;, &t-link-f95;, &t-link-f90;, &t-link-g77;; +and a static archiver &t-link-ar;. It also selects all found from the list -m4, rpm. +&t-link-m4;, + rpm. @@ -221,7 +233,7 @@ Sets construction variables for D language compiler DMD. -Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DShLibSonameGenerator;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSION;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. +Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. docbook @@ -240,29 +252,29 @@ Note, that there is no support for XML catalog resolving offered! This tool calls the XSLT processors and PDF renderers with the stylesheets you specified, that's it. The rest lies in your hands and you still have to know what you're doing when -resolving names via a catalog. +resolving names via a catalog. For activating the tool "docbook", you have to add its name to the Environment constructor, like this env = Environment(tools=['docbook']) -On its startup, the Docbook tool tries to find a required xsltproc processor, and -a PDF renderer, e.g. fop. So make sure that these are added to your system's environment -PATH and can be called directly, without specifying their full path. +On its startup, the &t-docbook; tool tries to find a required xsltproc processor, and +a PDF renderer, e.g. fop. So make sure that these are added to your system's environment +PATH and can be called directly without specifying their full path. For the most basic processing of Docbook to HTML, you need to have installed -the Python lxml binding to libxml2, or - +the Python lxml +binding to libxml2, or -a standalone XSLT processor, currently detected are xsltproc, saxon, saxon-xslt -and xalan. +a standalone XSLT processor, currently detected are xsltproc, saxon, saxon-xslt +and xalan. Rendering to PDF requires you to have one of the applications -fop or xep installed. +fop or xep installed. Creating a HTML or PDF document is very simple and straightforward. Say @@ -293,14 +305,14 @@ accordingly. -The rules given above are valid for the Builders &b-link-DocbookHtml;, -&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the +The rules given above are valid for the Builders &b-link-DocbookHtml;, +&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the &b-link-DocbookMan; transformation you can specify a target name, but the actual output names are automatically set from the refname entries in your XML source. -The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and +The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and &b-link-DocbookSlidesHtml; are special, in that: they create a large set of files, where the exact names and their number depend @@ -312,7 +324,7 @@ -As a result, there is simply no use in specifying a target HTML name. +As a result, there is simply no use in specifying a target HTML name. So the basic syntax for these builders is always: env = Environment(tools=['docbook']) @@ -320,7 +332,7 @@ If you want to use a specific XSL file, you can set the -additional xsl parameter to your +additional xsl parameter to your Builder call as follows: env.DocbookHtml('other.html', 'manual.xml', xsl='html.xsl') @@ -329,28 +341,31 @@ e.g. html.xsl for HTML and pdf.xsl for PDF output, a set of variables for setting the default XSL name is provided. These are: -DOCBOOK_DEFAULT_XSL_HTML -DOCBOOK_DEFAULT_XSL_HTMLCHUNKED -DOCBOOK_DEFAULT_XSL_HTMLHELP -DOCBOOK_DEFAULT_XSL_PDF -DOCBOOK_DEFAULT_XSL_EPUB -DOCBOOK_DEFAULT_XSL_MAN -DOCBOOK_DEFAULT_XSL_SLIDESPDF -DOCBOOK_DEFAULT_XSL_SLIDESHTML +DOCBOOK_DEFAULT_XSL_HTML +DOCBOOK_DEFAULT_XSL_HTMLCHUNKED +DOCBOOK_DEFAULT_XSL_HTMLHELP +DOCBOOK_DEFAULT_XSL_PDF +DOCBOOK_DEFAULT_XSL_EPUB +DOCBOOK_DEFAULT_XSL_MAN +DOCBOOK_DEFAULT_XSL_SLIDESPDF +DOCBOOK_DEFAULT_XSL_SLIDESHTML and you can set them when constructing your environment: -env = Environment(tools=['docbook'], - DOCBOOK_DEFAULT_XSL_HTML='html.xsl', - DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl') -env.DocbookHtml('manual') # now uses html.xsl + +env = Environment( + tools=['docbook'], + DOCBOOK_DEFAULT_XSL_HTML='html.xsl', + DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl', +) +env.DocbookHtml('manual') # now uses html.xsl Sets: &cv-link-DOCBOOK_DEFAULT_XSL_EPUB;, &cv-link-DOCBOOK_DEFAULT_XSL_HTML;, &cv-link-DOCBOOK_DEFAULT_XSL_HTMLCHUNKED;, &cv-link-DOCBOOK_DEFAULT_XSL_HTMLHELP;, &cv-link-DOCBOOK_DEFAULT_XSL_MAN;, &cv-link-DOCBOOK_DEFAULT_XSL_PDF;, &cv-link-DOCBOOK_DEFAULT_XSL_SLIDESHTML;, &cv-link-DOCBOOK_DEFAULT_XSL_SLIDESPDF;, &cv-link-DOCBOOK_FOP;, &cv-link-DOCBOOK_FOPCOM;, &cv-link-DOCBOOK_FOPFLAGS;, &cv-link-DOCBOOK_XMLLINT;, &cv-link-DOCBOOK_XMLLINTCOM;, &cv-link-DOCBOOK_XMLLINTFLAGS;, &cv-link-DOCBOOK_XSLTPROC;, &cv-link-DOCBOOK_XSLTPROCCOM;, &cv-link-DOCBOOK_XSLTPROCFLAGS;, &cv-link-DOCBOOK_XSLTPROCPARAMS;.Uses: &cv-link-DOCBOOK_FOPCOMSTR;, &cv-link-DOCBOOK_XMLLINTCOMSTR;, &cv-link-DOCBOOK_XSLTPROCCOMSTR;. dvi -Attaches the &b-DVI; builder to the +Attaches the &b-link-DVI; builder to the construction environment. @@ -374,42 +389,42 @@ Set construction variables for generic POSIX Fortran 03 compilers. -Sets: &cv-link-F03;, &cv-link-F03COM;, &cv-link-F03FLAGS;, &cv-link-F03PPCOM;, &cv-link-SHF03;, &cv-link-SHF03COM;, &cv-link-SHF03FLAGS;, &cv-link-SHF03PPCOM;, &cv-link-_F03INCFLAGS;.Uses: &cv-link-F03COMSTR;, &cv-link-F03PPCOMSTR;, &cv-link-SHF03COMSTR;, &cv-link-SHF03PPCOMSTR;. +Sets: &cv-link-F03;, &cv-link-F03COM;, &cv-link-F03FLAGS;, &cv-link-F03PPCOM;, &cv-link-SHF03;, &cv-link-SHF03COM;, &cv-link-SHF03FLAGS;, &cv-link-SHF03PPCOM;, &cv-link-_F03INCFLAGS;.Uses: &cv-link-F03COMSTR;, &cv-link-F03PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF03COMSTR;, &cv-link-SHF03PPCOMSTR;. f08 Set construction variables for generic POSIX Fortran 08 compilers. -Sets: &cv-link-F08;, &cv-link-F08COM;, &cv-link-F08FLAGS;, &cv-link-F08PPCOM;, &cv-link-SHF08;, &cv-link-SHF08COM;, &cv-link-SHF08FLAGS;, &cv-link-SHF08PPCOM;, &cv-link-_F08INCFLAGS;.Uses: &cv-link-F08COMSTR;, &cv-link-F08PPCOMSTR;, &cv-link-SHF08COMSTR;, &cv-link-SHF08PPCOMSTR;. +Sets: &cv-link-F08;, &cv-link-F08COM;, &cv-link-F08FLAGS;, &cv-link-F08PPCOM;, &cv-link-SHF08;, &cv-link-SHF08COM;, &cv-link-SHF08FLAGS;, &cv-link-SHF08PPCOM;, &cv-link-_F08INCFLAGS;.Uses: &cv-link-F08COMSTR;, &cv-link-F08PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF08COMSTR;, &cv-link-SHF08PPCOMSTR;. f77 Set construction variables for generic POSIX Fortran 77 compilers. -Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77FLAGS;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;, &cv-link-_F77INCFLAGS;.Uses: &cv-link-F77COMSTR;, &cv-link-F77PPCOMSTR;, &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHF77COMSTR;, &cv-link-SHF77PPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANPPCOMSTR;. +Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77FLAGS;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;, &cv-link-_F77INCFLAGS;.Uses: &cv-link-F77COMSTR;, &cv-link-F77PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANFLAGS;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHF77COMSTR;, &cv-link-SHF77PPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOMSTR;. f90 Set construction variables for generic POSIX Fortran 90 compilers. -Sets: &cv-link-F90;, &cv-link-F90COM;, &cv-link-F90FLAGS;, &cv-link-F90PPCOM;, &cv-link-SHF90;, &cv-link-SHF90COM;, &cv-link-SHF90FLAGS;, &cv-link-SHF90PPCOM;, &cv-link-_F90INCFLAGS;.Uses: &cv-link-F90COMSTR;, &cv-link-F90PPCOMSTR;, &cv-link-SHF90COMSTR;, &cv-link-SHF90PPCOMSTR;. +Sets: &cv-link-F90;, &cv-link-F90COM;, &cv-link-F90FLAGS;, &cv-link-F90PPCOM;, &cv-link-SHF90;, &cv-link-SHF90COM;, &cv-link-SHF90FLAGS;, &cv-link-SHF90PPCOM;, &cv-link-_F90INCFLAGS;.Uses: &cv-link-F90COMSTR;, &cv-link-F90PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF90COMSTR;, &cv-link-SHF90PPCOMSTR;. f95 Set construction variables for generic POSIX Fortran 95 compilers. -Sets: &cv-link-F95;, &cv-link-F95COM;, &cv-link-F95FLAGS;, &cv-link-F95PPCOM;, &cv-link-SHF95;, &cv-link-SHF95COM;, &cv-link-SHF95FLAGS;, &cv-link-SHF95PPCOM;, &cv-link-_F95INCFLAGS;.Uses: &cv-link-F95COMSTR;, &cv-link-F95PPCOMSTR;, &cv-link-SHF95COMSTR;, &cv-link-SHF95PPCOMSTR;. +Sets: &cv-link-F95;, &cv-link-F95COM;, &cv-link-F95FLAGS;, &cv-link-F95PPCOM;, &cv-link-SHF95;, &cv-link-SHF95COM;, &cv-link-SHF95FLAGS;, &cv-link-SHF95PPCOM;, &cv-link-_F95INCFLAGS;.Uses: &cv-link-F95COMSTR;, &cv-link-F95PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF95COMSTR;, &cv-link-SHF95PPCOMSTR;. fortran -Set construction variables for generic POSIX Fortran compilers. +Set &consvars; for generic POSIX Fortran compilers. -Sets: &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;.Uses: &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANPPCOMSTR;. +Sets: &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;.Uses: &cv-link-CPPFLAGS;, &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANPPCOMSTR;, &cv-link-_CPPDEFFLAGS;. g++ @@ -422,16 +437,14 @@ g77 Set construction variables for the &g77; Fortran compiler. -Calls the &t-f77; Tool module -to set variables. - +Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANPPCOM;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;.Uses: &cv-link-F77FLAGS;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-FORTRANFLAGS;. gas Sets construction variables for the &gas; assembler. -Calls the &t-as; module. +Calls the &t-link-as; tool. Sets: &cv-link-AS;. @@ -440,14 +453,14 @@ Set construction variables for the &gcc; C compiler. -Sets: &cv-link-CC;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;. +Sets: &cv-link-CC;, &cv-link-CCDEPFLAGS;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;. gdc Sets construction variables for the D language compiler GDC. -Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DShLibSonameGenerator;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSION;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. +Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. gettext @@ -485,8 +498,8 @@ Each of the above tools provides its own builder(s) which may be used to perform particular activities related to software internationalization. You -may be however interested in top-level builder -&b-Translate; described few paragraphs later. +may be however interested in top-level +&b-link-Translate; builder. @@ -501,7 +514,8 @@ gfortran -Sets construction variables for the GNU F95/F2003 GNU compiler. +Sets construction variables for the GNU Fortran compiler. +Calls the &t-link-fortran; Tool module to set variables. Sets: &cv-link-F77;, &cv-link-F90;, &cv-link-F95;, &cv-link-FORTRAN;, &cv-link-SHF77;, &cv-link-SHF77FLAGS;, &cv-link-SHF90;, &cv-link-SHF90FLAGS;, &cv-link-SHF95;, &cv-link-SHF95FLAGS;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANFLAGS;. @@ -516,11 +530,11 @@ gs This Tool sets the required construction variables for working with -the Ghostscript command. It also registers an appropriate Action -with the PDF Builder (&b-link-PDF;), such that the conversion from +the Ghostscript software. It also registers an appropriate Action +with the &b-link-PDF; Builder, such that the conversion from PS/EPS to PDF happens automatically for the TeX/LaTeX toolchain. -Finally, it adds an explicit Ghostscript Builder (&b-link-Gs;) to the -environment. +Finally, it adds an explicit &b-link-Gs; Builder for Ghostscript +to the environment. Sets: &cv-link-GS;, &cv-link-GSCOM;, &cv-link-GSFLAGS;.Uses: &cv-link-GSCOMSTR;. @@ -534,9 +548,9 @@ hpcc -Set construction variables for the -aCC on HP/UX systems. -Calls the &t-cXX; tool for additional variables. +Set construction variables for +aCC compilers on HP/UX systems. +Calls the &t-link-cXX; tool for additional variables. Sets: &cv-link-CXX;, &cv-link-CXXVERSION;, &cv-link-SHCXXFLAGS;. @@ -607,9 +621,9 @@ Sets construction variables for the Intel C/C++ compiler (Linux and Windows, version 7 and later). -Calls the &t-gcc; or &t-msvc; +Calls the &t-link-gcc; or &t-link-msvc; (on Linux and Windows, respectively) -to set underlying variables. +tool to set underlying variables. Sets: &cv-link-AR;, &cv-link-CC;, &cv-link-CXX;, &cv-link-INTEL_C_COMPILER_VERSION;, &cv-link-LINK;. @@ -646,14 +660,14 @@ Sets construction variables for the D language compiler LDC2. -Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DShLibSonameGenerator;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSION;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. +Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DRPATHPREFIX;, &cv-link-DRPATHSUFFIX;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLIBVERSIONFLAGS;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;. lex Sets construction variables for the &lex; lexical analyser. -Sets: &cv-link-LEX;, &cv-link-LEXCOM;, &cv-link-LEXFLAGS;, &cv-link-LEXUNISTD;.Uses: &cv-link-LEXCOMSTR;. +Sets: &cv-link-LEX;, &cv-link-LEXCOM;, &cv-link-LEXFLAGS;, &cv-link-LEXUNISTD;.Uses: &cv-link-LEXCOMSTR;, &cv-link-LEXFLAGS;, &cv-link-LEX_HEADER_FILE;, &cv-link-LEX_TABLES_FILE;. link @@ -744,7 +758,7 @@ Sets construction variables for the Microsoft linker. -Sets: &cv-link-LDMODULE;, &cv-link-LDMODULECOM;, &cv-link-LDMODULEFLAGS;, &cv-link-LDMODULEPREFIX;, &cv-link-LDMODULESUFFIX;, &cv-link-LIBDIRPREFIX;, &cv-link-LIBDIRSUFFIX;, &cv-link-LIBLINKPREFIX;, &cv-link-LIBLINKSUFFIX;, &cv-link-LINK;, &cv-link-LINKCOM;, &cv-link-LINKFLAGS;, &cv-link-REGSVR;, &cv-link-REGSVRCOM;, &cv-link-REGSVRFLAGS;, &cv-link-SHLINK;, &cv-link-SHLINKCOM;, &cv-link-SHLINKFLAGS;, &cv-link-WIN32DEFPREFIX;, &cv-link-WIN32DEFSUFFIX;, &cv-link-WIN32EXPPREFIX;, &cv-link-WIN32EXPSUFFIX;, &cv-link-WINDOWSDEFPREFIX;, &cv-link-WINDOWSDEFSUFFIX;, &cv-link-WINDOWSEXPPREFIX;, &cv-link-WINDOWSEXPSUFFIX;, &cv-link-WINDOWSPROGMANIFESTPREFIX;, &cv-link-WINDOWSPROGMANIFESTSUFFIX;, &cv-link-WINDOWSSHLIBMANIFESTPREFIX;, &cv-link-WINDOWSSHLIBMANIFESTSUFFIX;, &cv-link-WINDOWS_INSERT_DEF;.Uses: &cv-link-LDMODULECOMSTR;, &cv-link-LINKCOMSTR;, &cv-link-REGSVRCOMSTR;, &cv-link-SHLINKCOMSTR;. +Sets: &cv-link-LDMODULE;, &cv-link-LDMODULECOM;, &cv-link-LDMODULEFLAGS;, &cv-link-LDMODULEPREFIX;, &cv-link-LDMODULESUFFIX;, &cv-link-LIBDIRPREFIX;, &cv-link-LIBDIRSUFFIX;, &cv-link-LIBLINKPREFIX;, &cv-link-LIBLINKSUFFIX;, &cv-link-LINK;, &cv-link-LINKCOM;, &cv-link-LINKFLAGS;, &cv-link-REGSVR;, &cv-link-REGSVRCOM;, &cv-link-REGSVRFLAGS;, &cv-link-SHLINK;, &cv-link-SHLINKCOM;, &cv-link-SHLINKFLAGS;, &cv-link-WINDOWSDEFPREFIX;, &cv-link-WINDOWSDEFSUFFIX;, &cv-link-WINDOWSEXPPREFIX;, &cv-link-WINDOWSEXPSUFFIX;, &cv-link-WINDOWSPROGMANIFESTPREFIX;, &cv-link-WINDOWSPROGMANIFESTSUFFIX;, &cv-link-WINDOWSSHLIBMANIFESTPREFIX;, &cv-link-WINDOWSSHLIBMANIFESTSUFFIX;, &cv-link-WINDOWS_INSERT_DEF;.Uses: &cv-link-LDMODULECOMSTR;, &cv-link-LINKCOMSTR;, &cv-link-REGSVRCOMSTR;, &cv-link-SHLINKCOMSTR;. mssdk @@ -767,7 +781,7 @@ Sets construction variables for the Microsoft Visual C/C++ compiler. -Sets: &cv-link-BUILDERS;, &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCFLAGS;, &cv-link-CCPCHFLAGS;, &cv-link-CCPDBFLAGS;, &cv-link-CFILESUFFIX;, &cv-link-CFLAGS;, &cv-link-CPPDEFPREFIX;, &cv-link-CPPDEFSUFFIX;, &cv-link-CXX;, &cv-link-CXXCOM;, &cv-link-CXXFILESUFFIX;, &cv-link-CXXFLAGS;, &cv-link-INCPREFIX;, &cv-link-INCSUFFIX;, &cv-link-OBJPREFIX;, &cv-link-OBJSUFFIX;, &cv-link-PCHCOM;, &cv-link-PCHPDBFLAGS;, &cv-link-RC;, &cv-link-RCCOM;, &cv-link-RCFLAGS;, &cv-link-SHCC;, &cv-link-SHCCCOM;, &cv-link-SHCCFLAGS;, &cv-link-SHCFLAGS;, &cv-link-SHCXX;, &cv-link-SHCXXCOM;, &cv-link-SHCXXFLAGS;, &cv-link-SHOBJPREFIX;, &cv-link-SHOBJSUFFIX;.Uses: &cv-link-CCCOMSTR;, &cv-link-CXXCOMSTR;, &cv-link-PCH;, &cv-link-PCHSTOP;, &cv-link-PDB;, &cv-link-SHCCCOMSTR;, &cv-link-SHCXXCOMSTR;. +Sets: &cv-link-BUILDERS;, &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCDEPFLAGS;, &cv-link-CCFLAGS;, &cv-link-CCPCHFLAGS;, &cv-link-CCPDBFLAGS;, &cv-link-CFILESUFFIX;, &cv-link-CFLAGS;, &cv-link-CPPDEFPREFIX;, &cv-link-CPPDEFSUFFIX;, &cv-link-CXX;, &cv-link-CXXCOM;, &cv-link-CXXFILESUFFIX;, &cv-link-CXXFLAGS;, &cv-link-INCPREFIX;, &cv-link-INCSUFFIX;, &cv-link-OBJPREFIX;, &cv-link-OBJSUFFIX;, &cv-link-PCHCOM;, &cv-link-PCHPDBFLAGS;, &cv-link-RC;, &cv-link-RCCOM;, &cv-link-RCFLAGS;, &cv-link-SHCC;, &cv-link-SHCCCOM;, &cv-link-SHCCFLAGS;, &cv-link-SHCFLAGS;, &cv-link-SHCXX;, &cv-link-SHCXXCOM;, &cv-link-SHCXXFLAGS;, &cv-link-SHOBJPREFIX;, &cv-link-SHOBJSUFFIX;.Uses: &cv-link-CCCOMSTR;, &cv-link-CXXCOMSTR;, &cv-link-MSVC_NOTFOUND_POLICY;, &cv-link-PCH;, &cv-link-PCHSTOP;, &cv-link-PDB;, &cv-link-SHCCCOMSTR;, &cv-link-SHCXXCOMSTR;. msvs @@ -796,17 +810,25 @@ Sets: &cv-link-AS;, &cv-link-ASCOM;, &cv-link-ASFLAGS;, &cv-link-ASPPCOM;, &cv-link-ASPPFLAGS;.Uses: &cv-link-ASCOMSTR;, &cv-link-ASPPCOMSTR;. - - packaging + + ninja -A framework for building binary and source packages. - - + Sets up the &b-link-Ninja; builder, which generates a &ninja; build file, and then optionally runs &ninja;. + + + This is an experimental feature. + This functionality is subject to change and/or removal without a deprecation cycle. + + + + Sets: &cv-link-IMPLICIT_COMMAND_DEPENDENCIES;, &cv-link-NINJA_ALIAS_NAME;, &cv-link-NINJA_CMD_ARGS;, &cv-link-NINJA_COMPDB_EXPAND;, &cv-link-NINJA_DEPFILE_PARSE_FORMAT;, &cv-link-NINJA_DIR;, &cv-link-NINJA_DISABLE_AUTO_RUN;, &cv-link-NINJA_ENV_VAR_CACHE;, &cv-link-NINJA_FILE_NAME;, &cv-link-NINJA_FORCE_SCONS_BUILD;, &cv-link-NINJA_GENERATED_SOURCE_ALIAS_NAME;, &cv-link-NINJA_GENERATED_SOURCE_SUFFIXES;, &cv-link-NINJA_MSVC_DEPS_PREFIX;, &cv-link-NINJA_POOL;, &cv-link-NINJA_REGENERATE_DEPS;, &cv-link-NINJA_SCONS_DAEMON_KEEP_ALIVE;, &cv-link-NINJA_SCONS_DAEMON_PORT;, &cv-link-NINJA_SYNTAX;, &cv-link-_NINJA_REGENERATE_DEPS_FUNC;.Uses: &cv-link-AR;, &cv-link-ARCOM;, &cv-link-ARFLAGS;, &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCDEPFLAGS;, &cv-link-CCFLAGS;, &cv-link-CXX;, &cv-link-CXXCOM;, &cv-link-ESCAPE;, &cv-link-LINK;, &cv-link-LINKCOM;, &cv-link-PLATFORM;, &cv-link-PRINT_CMD_LINE_FUNC;, &cv-link-PROGSUFFIX;, &cv-link-RANLIB;, &cv-link-RANLIBCOM;, &cv-link-SHCCCOM;, &cv-link-SHCXXCOM;, &cv-link-SHLINK;, &cv-link-SHLINKCOM;. - - Packaging + + packaging -Sets construction variables for the &b-Package; Builder. +Sets construction variables for the &b-link-Package; Builder. +If this tool is enabled, the +command-line option is also enabled. @@ -845,9 +867,92 @@ qt -Sets construction variables for building Qt applications. +Sets &consvars; for building Qt3 applications. + + + +This tool is only suitable for building targeted to Qt3, +which is obsolete +(the tool is deprecated since 4.3). +There are contributed tools for Qt4 and Qt5, see + +https://github.com/SCons/scons-contrib. +Qt4 has also passed end of life for standard support (in Dec 2015). + + + +Note paths for these &consvars; are assembled +using the os.path.join method +so they will have the appropriate separator at runtime, +but are listed here in the various +entries only with the '/' separator +for simplicity. + + + +In addition, the &consvars; +&cv-link-CPPPATH;, +&cv-link-LIBPATH; and +&cv-link-LIBS; may be modified +and the variables +&cv-link-PROGEMITTER;, &cv-link-SHLIBEMITTER; and &cv-link-LIBEMITTER; +are modified. Because the build-performance is affected when using this tool, +you have to explicitly specify it at Environment creation: + + + +Environment(tools=['default','qt']) + + + +The &t-qt; tool supports the following operations: + + + +Automatic moc file generation from header files. +You do not have to specify moc files explicitly, the tool does it for you. +However, there are a few preconditions to do so: Your header file must have +the same filebase as your implementation file and must stay in the same +directory. It must have one of the suffixes +.h, +.hpp, +.H, +.hxx, +.hh. +You can turn off automatic moc file generation by setting +&cv-link-QT_AUTOSCAN; to False. +See also the corresponding +&b-link-Moc; Builder. + + + +Automatic moc file generation from C++ files. +As described in the Qt documentation, include the moc file at the end of +the C++ file. Note that you have to include the file, which is generated +by the transformation +${QT_MOCCXXPREFIX}<basename>${QT_MOCCXXSUFFIX}, by default +<basename>.mo. A warning is generated after building the moc file if you +do not include the correct file. If you are using &f-link-VariantDir;, you may +need to specify duplicate=True. +You can turn off automatic moc file generation by setting &cv-QT_AUTOSCAN; to +False. See also the corresponding +&b-link-Moc; Builder. + + + +Automatic handling of .ui files. +The implementation files generated from .ui +files are handled much the same as yacc or lex files. +Each .ui file given as a source of &b-link-Program;, +&b-link-Library; or &b-link-SharedLibrary; +will generate three files: the declaration file, the +implementation file and a moc file. Because there are also generated headers, +you may need to specify duplicate=True in calls to +&f-link-VariantDir;. +See also the corresponding +&b-link-Uic; Builder. -Sets: &cv-link-QTDIR;, &cv-link-QT_AUTOSCAN;, &cv-link-QT_BINPATH;, &cv-link-QT_CPPPATH;, &cv-link-QT_LIB;, &cv-link-QT_LIBPATH;, &cv-link-QT_MOC;, &cv-link-QT_MOCCXXPREFIX;, &cv-link-QT_MOCCXXSUFFIX;, &cv-link-QT_MOCFROMCXXCOM;, &cv-link-QT_MOCFROMCXXFLAGS;, &cv-link-QT_MOCFROMHCOM;, &cv-link-QT_MOCFROMHFLAGS;, &cv-link-QT_MOCHPREFIX;, &cv-link-QT_MOCHSUFFIX;, &cv-link-QT_UIC;, &cv-link-QT_UICCOM;, &cv-link-QT_UICDECLFLAGS;, &cv-link-QT_UICDECLPREFIX;, &cv-link-QT_UICDECLSUFFIX;, &cv-link-QT_UICIMPLFLAGS;, &cv-link-QT_UICIMPLPREFIX;, &cv-link-QT_UICIMPLSUFFIX;, &cv-link-QT_UISUFFIX;. +Sets: &cv-link-QTDIR;, &cv-link-QT_AUTOSCAN;, &cv-link-QT_BINPATH;, &cv-link-QT_CPPPATH;, &cv-link-QT_LIB;, &cv-link-QT_LIBPATH;, &cv-link-QT_MOC;, &cv-link-QT_MOCCXXPREFIX;, &cv-link-QT_MOCCXXSUFFIX;, &cv-link-QT_MOCFROMCXXCOM;, &cv-link-QT_MOCFROMCXXFLAGS;, &cv-link-QT_MOCFROMHCOM;, &cv-link-QT_MOCFROMHFLAGS;, &cv-link-QT_MOCHPREFIX;, &cv-link-QT_MOCHSUFFIX;, &cv-link-QT_UIC;, &cv-link-QT_UICCOM;, &cv-link-QT_UICDECLFLAGS;, &cv-link-QT_UICDECLPREFIX;, &cv-link-QT_UICDECLSUFFIX;, &cv-link-QT_UICIMPLFLAGS;, &cv-link-QT_UICIMPLPREFIX;, &cv-link-QT_UICIMPLSUFFIX;, &cv-link-QT_UISUFFIX;.Uses: &cv-link-QTDIR;. rmic @@ -943,7 +1048,7 @@ swig -Sets construction variables for the SWIG interface generator. +Sets construction variables for the &swig; interface compiler. Sets: &cv-link-SWIG;, &cv-link-SWIGCFILESUFFIX;, &cv-link-SWIGCOM;, &cv-link-SWIGCXXFILESUFFIX;, &cv-link-SWIGDIRECTORSUFFIX;, &cv-link-SWIGFLAGS;, &cv-link-SWIGINCPREFIX;, &cv-link-SWIGINCSUFFIX;, &cv-link-SWIGPATH;, &cv-link-SWIGVERSION;, &cv-link-_SWIGINCFLAGS;.Uses: &cv-link-SWIGCOMSTR;. @@ -992,7 +1097,7 @@ Sets construction variables for the &yacc; parse generator. -Sets: &cv-link-YACC;, &cv-link-YACCCOM;, &cv-link-YACCFLAGS;, &cv-link-YACCHFILESUFFIX;, &cv-link-YACCHXXFILESUFFIX;, &cv-link-YACCVCGFILESUFFIX;.Uses: &cv-link-YACCCOMSTR;. +Sets: &cv-link-YACC;, &cv-link-YACCCOM;, &cv-link-YACCFLAGS;, &cv-link-YACCHFILESUFFIX;, &cv-link-YACCHXXFILESUFFIX;, &cv-link-YACCVCGFILESUFFIX;.Uses: &cv-link-YACCCOMSTR;, &cv-link-YACCFLAGS;, &cv-link-YACC_GRAPH_FILE;, &cv-link-YACC_HEADER_FILE;. zip diff -Nru scons-4.0.1+dfsg/doc/generated/tools.mod scons-4.4.0+dfsg/doc/generated/tools.mod --- scons-4.0.1+dfsg/doc/generated/tools.mod 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/tools.mod 2022-07-30 21:48:28.000000000 +0000 @@ -79,8 +79,8 @@ mwcc"> mwld"> nasm"> +ninja"> packaging"> -Packaging"> pdf"> pdflatex"> pdftex"> @@ -185,8 +185,8 @@ mwcc"> mwld"> nasm"> +ninja"> packaging"> -Packaging"> pdf"> pdflatex"> pdftex"> diff -Nru scons-4.0.1+dfsg/doc/generated/variables.gen scons-4.4.0+dfsg/doc/generated/variables.gen --- scons-4.0.1+dfsg/doc/generated/variables.gen 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/variables.gen 2022-07-30 21:48:28.000000000 +0000 @@ -152,6 +152,7 @@ in the RPM .spec file, as well as forming part of the name of a generated RPM package file. +See the &b-link-Package; builder. @@ -324,28 +325,38 @@ A dictionary mapping the names of the builders -available through this environment -to underlying Builder objects. -Builders named -Alias, CFile, CXXFile, DVI, Library, Object, PDF, PostScript, and Program -are available by default. -If you initialize this variable when an -Environment is created: +available through the &consenv; to underlying Builder objects. +Custom builders need to be added to this to make them available. + + + +A platform-dependent default list of builders such as +&b-link-Program;, &b-link-Library; etc. is used to +populate this &consvar; when the &consenv; is initialized +via the presence/absence of the tools those builders depend on. +&cv-BUILDERS; can be examined to learn which builders will +actually be available at run-time. + + + +Note that if you initialize this &consvar; through +assignment when the &consenv; is created, +that value for &cv-BUILDERS; will override any defaults: -env = Environment(BUILDERS = {'NewBuilder' : foo}) +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env = Environment(BUILDERS={'NewBuilder': bld}) -the default Builders will no longer be available. -To use a new Builder object in addition to the default Builders, +To instead use a new Builder object in addition to the default Builders, add your new Builder object like this: env = Environment() -env.Append(BUILDERS = {'NewBuilder' : foo}) +env.Append(BUILDERS={'NewBuilder': bld}) @@ -354,10 +365,21 @@ env = Environment() -env['BUILDERS']['NewBuilder'] = foo +env['BUILDERS']['NewBuilder'] = bld + + + CACHEDIR_CLASS + + +The class type that SCons should use when instantiating a +new &f-link-CacheDir; for the given environment. It must be +a subclass of the SCons.CacheDir.CacheDir class. + + + CC @@ -395,6 +417,18 @@ + + + CCDEPFLAGS + + +Options to pass to C or C++ compiler to generate list of dependency files. + + + This is set only by compilers which support this functionality. (&t-link-gcc;, &t-link-clang;, and &t-link-msvc; currently) + + + CCFLAGS @@ -517,6 +551,7 @@ If set, the function will be called after the SCons template for the file has been written. +See the &b-link-Package; builder. @@ -555,6 +590,7 @@ section of the RPM .spec file. +See the &b-link-Package; builder. @@ -562,7 +598,24 @@ COMPILATIONDB_COMSTR - The string displayed when CompilationDatabase builder's action is run. + The string displayed when the &b-link-CompilationDatabase; + builder's action is run. + + + + + + COMPILATIONDB_PATH_FILTER + + + A string which instructs &b-link-CompilationDatabase; to + only include entries where the output member + matches the pattern in the filter string using fnmatch, which + uses glob style wildcards. + + + + The default value is an empty string '', which disables filtering. @@ -571,9 +624,10 @@ COMPILATIONDB_USE_ABSPATH - This is a boolean flag to instruct &b-link-CompilationDatabase; to - write the file and target members - in the compilation database with absolute or relative paths. + A boolean flag to instruct &b-link-CompilationDatabase; + whether to write the file and + output members + in the compilation database using absolute or relative paths. The default value is False (use relative paths) @@ -585,17 +639,22 @@ _concat -A function used to produce variables like &cv-_CPPINCFLAGS;. It takes -four or five -arguments: a prefix to concatenate onto each element, a list of -elements, a suffix to concatenate onto each element, an environment -for variable interpolation, and an optional function that will be -called to transform the list before concatenation. - + A function used to produce variables like &cv-link-_CPPINCFLAGS;. It takes + four mandatory arguments, and up to 4 additional optional arguments: + 1) a prefix to concatenate onto each element, + 2) a list of elements, + 3) a suffix to concatenate onto each element, + 4) an environment for variable interpolation, + 5) an optional function that will be called to transform the list before concatenation, + 6) an optionally specified target (Can use TARGET), + 7) an optionally specified source (Can use SOURCE), + 8) optional affect_signature flag which will wrap non-empty returned value with $( and $) to indicate the contents + should not affect the signature of the generated command line. + - -env['_CPPINCFLAGS'] = '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs)} $)', - + + env['_CPPINCFLAGS'] = '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}' + @@ -619,7 +678,7 @@ CONFIGURELOG -The name of the Configure context log file. +The name of the &Configure; context log file. The default is config.log in the top-level directory @@ -634,14 +693,13 @@ _CPPDEFFLAGS -An automatically-generated construction variable +An automatically-generated &consvar; containing the C preprocessor command-line options to define values. -The value of &cv-_CPPDEFFLAGS; is created +The value of &cv-link-_CPPDEFFLAGS; is created by respectively prepending and appending -&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; -to the beginning and end -of each definition in &cv-CPPDEFINES;. +&cv-link-CPPDEFPREFIX; and &cv-link-CPPDEFSUFFIX; +to each definition in &cv-link-CPPDEFINES;. @@ -650,10 +708,10 @@ CPPDEFINES -A platform independent specification of C preprocessor definitions. +A platform independent specification of C preprocessor macro definitions. The definitions will be added to command lines through the automatically-generated -&cv-_CPPDEFFLAGS; construction variable (see above), +&cv-link-_CPPDEFFLAGS; &consvar; (see above), which is constructed according to the type of value of &cv-CPPDEFINES;: @@ -661,10 +719,9 @@ If &cv-CPPDEFINES; is a string, the values of the -&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; -construction variables -will be respectively prepended and appended to the beginning and end -of each definition in &cv-CPPDEFINES;. +&cv-link-CPPDEFPREFIX; and &cv-link-CPPDEFSUFFIX; &consvars; +will be respectively prepended and appended to +each definition in &cv-link-CPPDEFINES;. @@ -676,10 +733,9 @@ If &cv-CPPDEFINES; is a list, the values of the -&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; -construction variables -will be respectively prepended and appended to the beginning and end -of each element in the list. +&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; &consvars; +will be respectively prepended and appended to +each element in the list. If any element is a list or tuple, then the first item is the name being defined and the second item is its value: @@ -694,10 +750,9 @@ If &cv-CPPDEFINES; is a dictionary, the values of the -&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; -construction variables -will be respectively prepended and appended to the beginning and end -of each item from the dictionary. +&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX; &consvars; +will be respectively prepended and appended to +each item from the dictionary. The key of each dictionary item is a name being defined to the dictionary item's corresponding value; @@ -723,11 +778,11 @@ CPPDEFPREFIX -The prefix used to specify preprocessor definitions +The prefix used to specify preprocessor macro definitions on the C compiler command line. -This will be prepended to the beginning of each definition -in the &cv-CPPDEFINES; construction variable -when the &cv-_CPPDEFFLAGS; variable is automatically generated. +This will be prepended to each definition +in the &cv-link-CPPDEFINES; &consvar; +when the &cv-link-_CPPDEFFLAGS; variable is automatically generated. @@ -736,11 +791,11 @@ CPPDEFSUFFIX -The suffix used to specify preprocessor definitions +The suffix used to specify preprocessor macro definitions on the C compiler command line. -This will be appended to the end of each definition -in the &cv-CPPDEFINES; construction variable -when the &cv-_CPPDEFFLAGS; variable is automatically generated. +This will be appended to each definition +in the &cv-link-CPPDEFINES; &consvar; +when the &cv-link-_CPPDEFFLAGS; variable is automatically generated. @@ -780,13 +835,13 @@ _CPPINCFLAGS -An automatically-generated construction variable +An automatically-generated &consvar; containing the C preprocessor command-line options for specifying directories to be searched for include files. The value of &cv-_CPPINCFLAGS; is created -by respectively prepending and appending &cv-INCPREFIX; and &cv-INCSUFFIX; -to the beginning and end -of each directory in &cv-CPPPATH;. +by respectively prepending and appending +&cv-link-INCPREFIX; and &cv-link-INCSUFFIX; +to each directory in &cv-link-CPPPATH;. @@ -797,13 +852,24 @@ The list of directories that the C preprocessor will search for include directories. The C/C++ implicit dependency scanner will search these -directories for include files. Don't explicitly put include directory -arguments in CCFLAGS or CXXFLAGS because the result will be non-portable -and the directories will not be searched by the dependency scanner. Note: -directory names in CPPPATH will be looked-up relative to the SConscript -directory when they are used in a command. To force -&scons; -to look-up a directory relative to the root of the source tree use #: +directories for include files. +In general it's not advised to put include directory directives +directly into &cv-link-CCFLAGS; or &cv-link-CXXFLAGS; +as the result will be non-portable +and the directories will not be searched by the dependency scanner. +&cv-CPPPATH; should be a list of path strings, +or a single string, not a pathname list joined by +Python's os.sep. + + + +Note: +directory names in &cv-CPPPATH; +will be looked-up relative to the directory of the SConscript file +when they are used in a command. +To force &scons; +to look-up a directory relative to the root of the source tree use +the # prefix: @@ -812,7 +878,7 @@ The directory look-up can also be forced using the -&Dir;() +&f-link-Dir; function: @@ -824,17 +890,14 @@ The directory list will be added to command lines through the automatically-generated -&cv-_CPPINCFLAGS; -construction variable, +&cv-link-_CPPINCFLAGS; &consvar;, which is constructed by -respectively prepending and appending the value of the -&cv-INCPREFIX; and &cv-INCSUFFIX; -construction variables -to the beginning and end -of each directory in &cv-CPPPATH;. +respectively prepending and appending the values of the +&cv-link-INCPREFIX; and &cv-link-INCSUFFIX; &consvars; +to each directory in &cv-link-CPPPATH;. Any command lines you define that need -the CPPPATH directory list should -include &cv-_CPPINCFLAGS;: +the &cv-CPPPATH; directory list should +include &cv-link-_CPPINCFLAGS;: @@ -1024,6 +1087,7 @@ This is included in the relevant section of the file that controls the packaging build. +See the &b-link-Package; builder. @@ -1038,6 +1102,7 @@ section of an RPM .spec file. +See the &b-link-Package; builder. @@ -1415,7 +1480,7 @@ The full command-line for the external executable -xsltproc (or saxon, +xsltproc (or saxon, xalan). @@ -1436,7 +1501,7 @@ Additonal command-line flags for the external executable -xsltproc (or saxon, +xsltproc (or saxon, xalan). @@ -1479,15 +1544,6 @@ - - - DShLibSonameGenerator - - -DShLibSonameGenerator. - - - DSUFFIXES @@ -1587,56 +1643,59 @@ ENV -A dictionary of environment variables -to use when invoking commands. When -&cv-ENV; is used in a command all list -values will be joined using the path separator and any other non-string -values will simply be coerced to a string. -Note that, by default, -&scons; +The execution environment - +a dictionary of environment variables +used when &SCons; invokes external commands +to build targets defined in this &consenv;. +When &cv-ENV; is passed to a command, +all list values are assumed to be path lists and +are joined using the search path separator. +Any other non-string values are coerced to a string. + + + +Note that by default +&SCons; does not -propagate the environment in force when you -execute -&scons; -to the commands used to build target files. +propagate the environment in effect when you execute +&scons; (the "shell environment") +to the execution environment. This is so that builds will be guaranteed repeatable regardless of the environment variables set at the time &scons; is invoked. - - - -If you want to propagate your -environment variables +If you want to propagate a +shell environment variable to the commands executed to build target files, -you must do so explicitly: +you must do so explicitly. +A common example is +the system &PATH; +environment variable, +so that +&scons; +will find utilities the same way +as the invoking shell (or other process): import os -env = Environment(ENV = os.environ) +env = Environment(ENV={'PATH': os.environ['PATH']}) -Note that you can choose only to propagate -certain environment variables. -A common example is -the system -PATH -environment variable, -so that -&scons; -uses the same utilities -as the invoking shell (or other process): +Although it is usually not recommended, +you can propagate the entire shell environment +in one go: import os -env = Environment(ENV = {'PATH' : os.environ['PATH']}) +env = Environment(ENV=os.environ.copy()) + @@ -1696,7 +1755,7 @@ The list of file extensions for which the F03 dialect will be used. By -default, this is ['.f03'] +default, this is ['.f03'] @@ -1834,7 +1893,7 @@ The list of file extensions for which the compilation + preprocessor pass for -F03 dialect will be used. By default, this is empty +F03 dialect will be used. By default, this is empty. @@ -1884,7 +1943,7 @@ The list of file extensions for which the F08 dialect will be used. By -default, this is ['.f08'] +default, this is ['.f08'] @@ -2022,7 +2081,7 @@ The list of file extensions for which the compilation + preprocessor pass for -F08 dialect will be used. By default, this is empty +F08 dialect will be used. By default, this is empty. @@ -2072,7 +2131,7 @@ The list of file extensions for which the F77 dialect will be used. By -default, this is ['.f77'] +default, this is ['.f77'] @@ -2210,7 +2269,7 @@ The list of file extensions for which the compilation + preprocessor pass for -F77 dialect will be used. By default, this is empty +F77 dialect will be used. By default, this is empty. @@ -2260,7 +2319,7 @@ The list of file extensions for which the F90 dialect will be used. By -default, this is ['.f90'] +default, this is ['.f90'] @@ -2397,7 +2456,7 @@ The list of file extensions for which the compilation + preprocessor pass for -F90 dialect will be used. By default, this is empty +F90 dialect will be used. By default, this is empty. @@ -2447,7 +2506,7 @@ The list of file extensions for which the F95 dialect will be used. By -default, this is ['.f95'] +default, this is ['.f95'] @@ -2585,7 +2644,7 @@ The list of file extensions for which the compilation + preprocessor pass for -F95 dialect will be used. By default, this is empty +F95 dialect will be used. By default, this is empty. @@ -2617,11 +2676,20 @@ The command line used to compile a Fortran source file to an object file. By default, any options specified in the &cv-link-FORTRANFLAGS;, -&cv-link-CPPFLAGS;, -&cv-link-_CPPDEFFLAGS;, &cv-link-_FORTRANMODFLAG;, and -&cv-link-_FORTRANINCFLAGS; construction variables -are included on this command line. +&cv-link-_FORTRANINCFLAGS; +&consvars; are included on this command line. + + + + + + FORTRANCOMMONFLAGS + + +General user-specified options that are passed to the Fortran compiler. +Similar to &cv-link-FORTRANFLAGS;, +but this variable is applied to all dialects. @@ -2643,7 +2711,7 @@ The list of file extensions for which the FORTRAN dialect will be used. By -default, this is ['.f', '.for', '.ftn'] +default, this is ['.f', '.for', '.ftn'] @@ -2652,7 +2720,8 @@ FORTRANFLAGS -General user-specified options that are passed to the Fortran compiler. +General user-specified options for the FORTRAN dialect +that are passed to the Fortran compiler. Note that this variable does not contain @@ -2671,7 +2740,7 @@ _FORTRANINCFLAGS -An automatically-generated construction variable +An automatically-generated &consvar; containing the Fortran compiler command-line options for specifying directories to be searched for include files and module files. @@ -2703,7 +2772,7 @@ The prefix used to specify a module directory on the Fortran compiler command line. This will be prepended to the beginning of the directory -in the &cv-link-FORTRANMODDIR; construction variables +in the &cv-link-FORTRANMODDIR; &consvars; when the &cv-link-_FORTRANMODFLAG; variables is automatically generated. @@ -2716,7 +2785,7 @@ The suffix used to specify a module directory on the Fortran compiler command line. This will be appended to the end of the directory -in the &cv-link-FORTRANMODDIR; construction variables +in the &cv-link-FORTRANMODDIR; &consvars; when the &cv-link-_FORTRANMODFLAG; variables is automatically generated. @@ -2726,7 +2795,7 @@ _FORTRANMODFLAG -An automatically-generated construction variable +An automatically-generated &consvar; containing the Fortran compiler command-line option for specifying the directory location where the Fortran compiler should place any module files that happen to get @@ -2807,11 +2876,11 @@ The directory list will be added to command lines through the automatically-generated &cv-link-_FORTRANINCFLAGS; -construction variable, +&consvar;, which is constructed by respectively prepending and appending the values of the &cv-link-INCPREFIX; and &cv-link-INCSUFFIX; -construction variables +&consvars; to the beginning and end of each directory in &cv-link-FORTRANPATH;. Any command lines you define that need @@ -2836,7 +2905,7 @@ &cv-link-_CPPDEFFLAGS;, &cv-link-_FORTRANMODFLAG;, and &cv-link-_FORTRANINCFLAGS; -construction variables are included on this command line. +&consvars; are included on this command line. @@ -2859,7 +2928,7 @@ The list of file extensions for which the compilation + preprocessor pass for -FORTRAN dialect will be used. By default, this is ['.fpp', '.FPP'] +FORTRAN dialect will be used. By default, this is ['.fpp', '.FPP'] @@ -2997,7 +3066,7 @@ GS -The Ghostscript program used, e.g. to convert PostScript to PDF files. +The Ghostscript program used to, for example, convert PostScript to PDF files. @@ -3038,44 +3107,52 @@ HOST_ARCH - The name of the host hardware architecture used to create the Environment. - If a platform is specified when creating the Environment, then - that Platform's logic will handle setting this value. - This value is immutable, and should not be changed by the user after - the Environment is initialized. - Currently only set for Win32. - + The name of the host hardware architecture + used to create this &consenv;. + The platform code sets this when initializing + (see &cv-link-PLATFORM; and the + platform argument to &f-link-Environment;). + Note the detected name of the architecture may not be identical to + that returned by the &Python; + platform.machine method. + -Sets the host architecture for Visual Studio compiler. If not set, -default to the detected host architecture: note that this may depend -on the python you are using. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. - - - -Valid values are the same as for &cv-link-TARGET_ARCH;. - - - -This is currently only used on Windows, but in the future it may be -used on other OSes as well. - - + On the win32 platform, + if the Microsoft Visual C++ compiler is available, + &t-link-msvc; tool setup is done using + &cv-HOST_ARCH; and &cv-link-TARGET_ARCH;. + Changing the values at any later time will not cause + the tool to be reinitialized. + Valid host arch values are + x86 and arm + for 32-bit hosts and + amd64 and x86_64 + for 64-bit hosts. + + + Should be considered immutable. + &cv-HOST_ARCH; is not currently used by other platforms, + but the option is reserved to do so in future + + HOST_OS - The name of the host operating system used to create the Environment. - If a platform is specified when creating the Environment, then - that Platform's logic will handle setting this value. - This value is immutable, and should not be changed by the user after - the Environment is initialized. - Currently only set for Win32. - - + The name of the host operating system for the platform + used to create this &consenv;. + The platform code sets this when initializing + (see &cv-link-PLATFORM; and the + platform argument to &f-link-Environment;). + + + Should be considered immutable. + &cv-HOST_OS; is not currently used by &SCons;, + but the option is reserved to do so in future + + @@ -3249,9 +3326,9 @@ The prefix used to specify an include directory on the C compiler command line. -This will be prepended to the beginning of each directory -in the &cv-CPPPATH; and &cv-FORTRANPATH; construction variables -when the &cv-_CPPINCFLAGS; and &cv-_FORTRANINCFLAGS; +This will be prepended to each directory +in the &cv-link-CPPPATH; and &cv-link-FORTRANPATH; &consvars; +when the &cv-link-_CPPINCFLAGS; and &cv-link-_FORTRANINCFLAGS; variables are automatically generated. @@ -3263,9 +3340,9 @@ The suffix used to specify an include directory on the C compiler command line. -This will be appended to the end of each directory -in the &cv-CPPPATH; and &cv-FORTRANPATH; construction variables -when the &cv-_CPPINCFLAGS; and &cv-_FORTRANINCFLAGS; +This will be appended to each directory +in the &cv-link-CPPPATH; and &cv-link-FORTRANPATH; &consvars; +when the &cv-link-_CPPINCFLAGS; and &cv-link-_FORTRANINCFLAGS; variables are automatically generated. @@ -3318,7 +3395,7 @@ INTEL_C_COMPILER_VERSION -Set by the "intelc" Tool +Set by the &t-link-intelc; Tool to the major version number of the Intel C compiler selected for use. @@ -3489,15 +3566,6 @@ ; on Windows). - - - Note that this currently just adds the specified - directory via the option. - &SCons; does not currently search the - &cv-JAVACLASSPATH; directories for dependency - .class - files. - @@ -3611,25 +3679,30 @@ JAVAVERSION - Specifies the Java version being used by the &b-Java; builder. - This is not currently used to select one - version of the Java compiler vs. another. - Instead, you should set this to specify the version of Java - supported by your &javac; compiler. - The default is 1.4. - - - + Specifies the Java version being used by the &b-link-Java; + builder. Set this to specify the version of Java targeted + by the &javac; compiler. This is sometimes necessary because Java 1.5 changed the file names that are created for nested anonymous inner classes, which can cause a mismatch with the files that &SCons; expects will be generated by the &javac; compiler. - Setting &cv-JAVAVERSION; to - 1.5 - (or 1.6, as appropriate) - can make &SCons; realize that a Java 1.5 or 1.6 - build is actually up to date. + Setting &cv-JAVAVERSION; to a version greater than + 1.4 makes &SCons; realize that a build + with such a compiler is actually up to date. + The default is 1.4. + + + While this is not primarily intended for + selecting one version of the Java compiler vs. another, + it does have that effect on the Windows platform. A + more precise approach is to set &cv-link-JAVAC; (and related + &consvars; for related utilities) to the path to the specific + Java compiler you want, if that is not the default compiler. + On non-Windows platforms, the + alternatives system may provide a + way to adjust the default Java compiler without + having to specify explicit paths. @@ -3853,6 +3926,31 @@ + + + LEX_HEADER_FILE + + +If supplied, generate a C header file with the name taken from this variable. +Will be emitted as a +command-line option. Use this in preference to including + in &cv-link-LEXFLAGS; directly. + + + + + + LEX_TABLES_FILE + + +If supplied, write the lex tables to a file with the name +taken from this variable. +Will be emitted as a +command-line option. Use this in preference to including + in &cv-link-LEXFLAGS; directly. + + + LEXCOM @@ -3874,7 +3972,7 @@ -env = Environment(LEXCOMSTR = "Lex'ing $TARGET from $SOURCES") +env = Environment(LEXCOMSTR="Lex'ing $TARGET from $SOURCES") @@ -3884,6 +3982,20 @@ General options passed to the lexical analyzer generator. +In addition to passing the value on during invocation, +the &t-link-lex; tool also examines this &consvar; for options +which cause additional output files to be generated, +and adds those to the target list. +Recognized for this purpose are GNU &flex; options + and +; +the output file is named by the option argument. + + +Note that files specified by and + may not be properly handled +by &SCons; in all situations. Consider using +&cv-link-LEX_HEADER_FILE; and &cv-link-LEX_TABLES_FILE; instead. @@ -3905,9 +4017,9 @@ containing the linker command-line options for specifying directories to be searched for library. The value of &cv-_LIBDIRFLAGS; is created -by respectively prepending and appending &cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX; -to the beginning and end -of each directory in &cv-LIBPATH;. +by respectively prepending and appending &cv-link-LIBDIRPREFIX; +and &cv-link-LIBDIRSUFFIX; +to each directory in &cv-link-LIBPATH;. @@ -3917,9 +4029,9 @@ The prefix used to specify a library directory on the linker command line. -This will be prepended to the beginning of each directory -in the &cv-LIBPATH; construction variable -when the &cv-_LIBDIRFLAGS; variable is automatically generated. +This will be prepended to each directory +in the &cv-link-LIBPATH; construction variable +when the &cv-link-_LIBDIRFLAGS; variable is automatically generated. @@ -3929,9 +4041,9 @@ The suffix used to specify a library directory on the linker command line. -This will be appended to the end of each directory -in the &cv-LIBPATH; construction variable -when the &cv-_LIBDIRFLAGS; variable is automatically generated. +This will be appended to each directory +in the &cv-link-LIBPATH; construction variable +when the &cv-link-_LIBDIRFLAGS; variable is automatically generated. @@ -3955,10 +4067,10 @@ An automatically-generated construction variable containing the linker command-line options for specifying libraries to be linked with the resulting target. -The value of &cv-_LIBFLAGS; is created -by respectively prepending and appending &cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX; -to the beginning and end -of each filename in &cv-LIBS;. +The value of &cv-link-_LIBFLAGS; is created +by respectively prepending and appending &cv-link-LIBLINKPREFIX; +and &cv-link-LIBLINKSUFFIX; +to each filename in &cv-link-LIBS;. @@ -3968,9 +4080,9 @@ The prefix used to specify a library to link on the linker command line. -This will be prepended to the beginning of each library -in the &cv-LIBS; construction variable -when the &cv-_LIBFLAGS; variable is automatically generated. +This will be prepended to each library +in the &cv-link-LIBS; construction variable +when the &cv-link-_LIBFLAGS; variable is automatically generated. @@ -3980,9 +4092,9 @@ The suffix used to specify a library to link on the linker command line. -This will be appended to the end of each library -in the &cv-LIBS; construction variable -when the &cv-_LIBFLAGS; variable is automatically generated. +This will be appended to each library +in the &cv-link-LIBS; construction variable +when the &cv-link-_LIBFLAGS; variable is automatically generated. @@ -3991,16 +4103,33 @@ LIBPATH -The list of directories that will be searched for libraries. +The list of directories that will be searched for libraries +specified by the &cv-link-LIBS; &consvar;. +&cv-LIBPATH; should be a list of path strings, +or a single string, not a pathname list joined by +Python's os.sep. + + +Do not put library search directives directly +into &cv-LINKFLAGS; or &cv-SHLINKFLAGS; +as the result will be non-portable. + + + + +Note: +directory names in &cv-LIBPATH; will be looked-up relative to the +directory of the SConscript file +when they are used in a command. +To force &scons; +to look-up a directory relative to the root of the source tree use +the # prefix: @@ -4009,8 +4138,7 @@ The directory look-up can also be forced using the -&Dir;() -function: +&f-link-Dir; function: @@ -4021,16 +4149,15 @@ The directory list will be added to command lines through the automatically-generated -&cv-_LIBDIRFLAGS; +&cv-link-_LIBDIRFLAGS; construction variable, which is constructed by respectively prepending and appending the values of the -&cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX; +&cv-link-LIBDIRPREFIX; and &cv-link-LIBDIRSUFFIX; construction variables -to the beginning and end -of each directory in &cv-LIBPATH;. +to each directory in &cv-LIBPATH;. Any command lines you define that need -the LIBPATH directory list should +the &cv-LIBPATH; directory list should include &cv-_LIBDIRFLAGS;: @@ -4062,7 +4189,7 @@ When searching for library dependencies, SCons will look for files with these prefixes, the base library name, -and suffixes in the &cv-LIBSUFFIXES; list. +and suffixes from the &cv-link-LIBSUFFIXES; list. @@ -4072,24 +4199,32 @@ A list of one or more libraries -that will be linked with -any executable programs -created by this environment. +that will be added to the link line +for linking with any executable program, shared library, or loadable module +created by the &consenv; or override. +String-valued library names should include +only the library base names, +without prefixes such as lib +or suffixes such as .so or .dll. The library list will be added to command lines through the automatically-generated -&cv-_LIBFLAGS; -construction variable, +&cv-_LIBFLAGS; &consvar; which is constructed by respectively prepending and appending the values of the -&cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX; -construction variables -to the beginning and end -of each filename in &cv-LIBS;. +&cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX; &consvars; +to each library name in &cv-LIBS;. +Library name strings should not include a +path component, instead the compiler will be +directed to look for libraries in the paths +specified by &cv-link-LIBPATH;. + + + Any command lines you define that need -the LIBS library list should +the &cv-LIBS; library list should include &cv-_LIBFLAGS;: @@ -4099,12 +4234,12 @@ If you add a -File +File object to the &cv-LIBS; list, the name of that file will be added to &cv-_LIBFLAGS;, -and thus the link line, as is, without +and thus to the link line, as-is, without &cv-LIBLINKPREFIX; or &cv-LIBLINKSUFFIX;. @@ -4142,7 +4277,7 @@ A list of all legal suffixes for library file names. When searching for library dependencies, -SCons will look for files with prefixes, in the &cv-LIBPREFIXES; list, +SCons will look for files with prefixes from the &cv-link-LIBPREFIXES; list, the base library name, and these suffixes. @@ -4155,9 +4290,12 @@ The abbreviated name, preferably the SPDX code, of the license under which this project is released (GPL-3.0, LGPL-2.1, BSD-2-Clause etc.). -See http://www.opensource.org/licenses/alphabetical +See + +http://www.opensource.org/licenses/alphabetical for a list of license names and SPDX codes. +See the &b-link-Package; builder. @@ -4196,6 +4334,16 @@ The linker. See also &cv-link-SHLINK; for linking shared objects. + +On POSIX systems (those using the &t-link-link; tool), +you should normally not change this value as it defaults +to a "smart" linker tool which selects a compiler +driver matching the type of source files in use. +So for example, if you set &cv-link-CXX; to a specific +compiler name, and are compiling C++ sources, +the smartlink function will automatically select the same compiler +for linking. + @@ -4584,120 +4732,1015 @@ - + - MSVC_USE_SCRIPT + MSVC_NOTFOUND_POLICY -Use a batch script to set up Microsoft Visual Studio compiler. +Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not detected. -If set to the name of a Visual Studio .bat file -(e.g. vcvars.bat), -&SCons; will run that batch file instead of the auto-detected one, -and extract the relevant variables from the result (typically -%INCLUDE%, -%LIB%, and -%PATH%) for supplying to the build. -This can be useful to force the use of a compiler version that -&SCons; does not detect. + The &cv-MSVC_NOTFOUND_POLICY; specifies the &scons; behavior when no msvc versions are detected or + when the requested msvc version is not detected. -Setting -&cv-MSVC_USE_SCRIPT; to None bypasses the -Visual Studio autodetection entirely; -use this if you are running SCons in a Visual Studio cmd -window and importing the shell's environment variables - that -is, if you are sure everything is set correctly already and -you don't want &SCons; to change anything. +The valid values for &cv-MSVC_NOTFOUND_POLICY; and the corresponding &scons; behavior are: + + + + +'Error' or 'Exception' + -&cv-MSVC_USE_SCRIPT; overrides &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;. +Raise an exception when no msvc versions are detected or when the requested msvc version is not detected. - - - - MSVC_UWP_APP - - -Build libraries for a Universal Windows Platform (UWP) Application. + + + +'Warning' or 'Warn' + + +Issue a warning and continue when no msvc versions are detected or when the requested msvc version is not detected. +Depending on usage, this could result in build failure(s). + + + +'Ignore' or 'Suppress' + -If &cv-MSVC_UWP_APP; is set, the Visual Studio environment will be set up to point -to the Windows Store compatible libraries and Visual Studio runtimes. In doing so, -any libraries that are built will be able to be used in a UWP App and published -to the Windows Store. -This flag will only have an effect with Visual Studio 2015 or later. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. +Take no action and continue when no msvc versions are detected or when the requested msvc version is not detected. +Depending on usage, this could result in build failure(s). + + + + -Valid values are '1' or '0' +Note: in addition to the camel case values shown above, lower case and upper case values are accepted as well. - - - - - MSVC_VERSION - - -Sets the preferred version of Microsoft Visual C/C++ to use. + +The &cv-MSVC_NOTFOUND_POLICY; is applied when any of the following conditions are satisfied: + + +&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified), +and the default tools list contains one or more of the msvc tools. + + +&cv-MSVC_VERSION; is specified, the default tools list is explicitly specified (e.g., tools=['default']), +and the default tools list contains one or more of the msvc tools. + + +A non-default tools list is specified that contains one or more of the msvc tools (e.g., tools=['msvc', 'mslink']). + + -If &cv-MSVC_VERSION; is not set, SCons will (by default) select the -latest version of Visual C/C++ installed on your system. If the -specified version isn't installed, tool initialization will fail. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. +The &cv-MSVC_NOTFOUND_POLICY; is ignored when any of the following conditions are satisfied: + + +&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified). + + +&cv-MSVC_VERSION; is not specified and the default tools list is explicitly specified (e.g., tools=['default']). + + +A non-default tool list is specified that does not contain any of the msvc tools (e.g., tools=['mingw']). + + -Valid values for Windows are -14.2, -14.1, -14.1Exp, -14.0, -14.0Exp, -12.0, -12.0Exp, -11.0, -11.0Exp, -10.0, -10.0Exp, -9.0, -9.0Exp, -8.0, -8.0Exp, -7.1, -7.0, -and 6.0. -Versions ending in Exp refer to "Express" or -"Express for Desktop" editions. +Important usage details: + + + +&cv-MSVC_NOTFOUND_POLICY; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_NOTFOUND_POLICY; must be set before the first msvc tool is +loaded into the environment. + + + + + + +When &cv-MSVC_NOTFOUND_POLICY; is not specified, the default &scons; behavior is to issue a warning and continue +subject to the conditions listed above. The default &scons; behavior may change in the future. - + - MSVS + MSVC_SCRIPT_ARGS - When the Microsoft Visual Studio tools are initialized, - they set up this dictionary with the following keys: - - - - VERSION - the version of MSVS being used (can be set via - &cv-link-MSVS_VERSION;) - +Pass user-defined arguments to the Visual C++ batch file determined via autodetection. + + + +&cv-MSVC_SCRIPT_ARGS; is available for msvc batch file arguments that do not have first-class support +via construction variables or when there is an issue with the appropriate construction variable validation. +When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;) +rather than &cv-MSVC_SCRIPT_ARGS; arguments. + + + +The valid values for &cv-MSVC_SCRIPT_ARGS; are: None, a string, +or a list of strings. + + + +The &cv-MSVC_SCRIPT_ARGS; value is converted to a scalar string (i.e., "flattened"). +The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined +via autodetection subject to the validation conditions listed below. + + + +&cv-MSVC_SCRIPT_ARGS; is ignored when the value is None and when the +result from argument conversion is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SCRIPT_ARGS; is specified for Visual Studio 2013 and earlier. + + + +Multiple SDK version arguments (e.g., '10.0.20348.0') are specified +in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument +(e.g., '10.0.20348.0') is specified in &cv-MSVC_SCRIPT_ARGS;. +Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and &cv-MSVC_SCRIPT_ARGS; +are not allowed. + + + +Multiple toolset version arguments (e.g., '-vcvars_ver=14.29') +are specified in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument +(e.g., '-vcvars_ver=14.29') is specified in &cv-MSVC_SCRIPT_ARGS;. +Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and +&cv-MSVC_SCRIPT_ARGS; are not allowed. + + + +Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre') +are specified in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument +(e.g., '-vcvars_spectre_libs=spectre') is specified in +&cv-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS; +and &cv-MSVC_SCRIPT_ARGS; are not allowed. + + + +Multiple UWP arguments (e.g., uwp or store) are specified +in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or +store) is specified in &cv-MSVC_SCRIPT_ARGS;. Multiple UWP declarations +via &cv-link-MSVC_UWP_APP; and &cv-MSVC_SCRIPT_ARGS; are not allowed. + + + + + + +Example 1 - A Visual Studio 2022 build with an SDK version and a toolset version +specified with a string argument: + +env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS='10.0.20348.0 -vcvars_ver=14.29.30133') + + + + +Example 2 - A Visual Studio 2022 build with an SDK version and a toolset version +specified with a list argument: + +env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['10.0.20348.0', '-vcvars_ver=14.29.30133']) + + + + +Important usage details: + + + +&cv-MSVC_SCRIPT_ARGS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SCRIPT_ARGS; must be set before the first msvc tool is +loaded into the environment. + + + +Other than checking for multiple declarations as described above, &cv-MSVC_SCRIPT_ARGS; arguments +are not validated. + + + + +Erroneous, inconsistent, and/or version incompatible &cv-MSVC_SCRIPT_ARGS; arguments are likely +to result in build failures for reasons that are not readily apparent and may be difficult to diagnose. + +The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent +and compatible with the version of msvc selected. + + + + + + + + + + MSVC_SCRIPTERROR_POLICY + + +Specify the &scons; behavior when Microsoft Visual C/C++ batch file errors are detected. + + + +The &cv-MSVC_SCRIPTERROR_POLICY; specifies the &scons; behavior when msvc batch file errors are +detected. +When &cv-MSVC_SCRIPTERROR_POLICY; is not specified, the default &scons; behavior is to suppress +msvc batch file error messages. + + +The root cause of msvc build failures may be difficult to diagnose. In these situations, setting +the &scons; behavior to issue a warning when msvc batch file errors are detected may +produce additional diagnostic information. + + + +The valid values for &cv-MSVC_SCRIPTERROR_POLICY; and the corresponding &scons; behavior are: + + + + + +'Error' or 'Exception' + + +Raise an exception when msvc batch file errors are detected. + + + + + +'Warning' or 'Warn' + + +Issue a warning when msvc batch file errors are detected. + + + + + +'Ignore' or 'Suppress' + + +Suppress msvc batch file error messages. + + + + + + + +Note: in addition to the camel case values shown above, lower case and upper case values are accepted as well. + + + +Example 1 - A Visual Studio 2022 build with user-defined script arguments: + +env = environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['8.1', 'store', '-vcvars_ver=14.1']) +env.Program('hello', ['hello.c'], CCFLAGS='/MD', LIBS=['kernel32', 'user32', 'runtimeobject']) + + + + +Example 1 - Output fragment: + +... +link /nologo /OUT:_build001\hello.exe kernel32.lib user32.lib runtimeobject.lib _build001\hello.obj +LINK : fatal error LNK1104: cannot open file 'MSVCRT.lib' +... + + + + +Example 2 - A Visual Studio 2022 build with user-defined script arguments and the script error policy set +to issue a warning when msvc batch file errors are detected: + +env = environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['8.1', 'store', '-vcvars_ver=14.1'], MSVC_SCRIPTERROR_POLICY='warn') +env.Program('hello', ['hello.c'], CCFLAGS='/MD', LIBS=['kernel32', 'user32', 'runtimeobject']) + + + + +Example 2 - Output fragment: + +... +scons: warning: vc script errors detected: +[ERROR:vcvars.bat] The UWP Application Platform requires a Windows 10 SDK. +[ERROR:vcvars.bat] WindowsSdkDir = "C:\Program Files (x86)\Windows Kits\8.1\" +[ERROR:vcvars.bat] host/target architecture is not supported : { x64 , x64 } +... +link /nologo /OUT:_build001\hello.exe kernel32.lib user32.lib runtimeobject.lib _build001\hello.obj +LINK : fatal error LNK1104: cannot open file 'MSVCRT.lib' + + + + +Important usage details: + + + +&cv-MSVC_SCRIPTERROR_POLICY; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SCRIPTERROR_POLICY; must be set before the first msvc tool is +loaded into the environment. + + + +Due to &scons; implementation details, not all Windows system environment variables are propagated +to the environment in which the msvc batch file is executed. Depending on Visual Studio version +and installation options, non-fatal msvc batch file error messages may be generated for ancillary +tools which may not affect builds with the msvc compiler. For this reason, caution is recommended +when setting the script error policy to raise an exception (e.g., 'Error'). + + + + + + + + + + MSVC_SDK_VERSION + + +Build with a specific version of the Microsoft Software Development Kit (SDK). + + + +The valid values for &cv-MSVC_SDK_VERSION; are: None +or a string containing the requested SDK version (e.g., '10.0.20348.0'). + + + +&cv-MSVC_SDK_VERSION; is ignored when the value is None and when +the value is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SDK_VERSION; is specified for Visual Studio 2013 and earlier. + + + +&cv-MSVC_SDK_VERSION; is specified and an SDK version argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via &cv-MSVC_SDK_VERSION; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + +The &cv-MSVC_SDK_VERSION; specified does not match any of the supported formats: + + +'10.0.XXXXX.Y' [SDK 10.0] + + +'8.1' [SDK 8.1] + + + + + +The system folder for the corresponding &cv-MSVC_SDK_VERSION; version is not found. +The requested SDK version does not appear to be installed. + + + +The &cv-MSVC_SDK_VERSION; version does not appear to support the requested platform +type (i.e., UWP or Desktop). The requested SDK version +platform type components do not appear to be installed. + + + +The &cv-MSVC_SDK_VERSION; version is 8.1, the platform type is +UWP, and the build tools selected are from Visual Studio 2017 +and later (i.e., &cv-link-MSVC_VERSION; must be '14.0' or &cv-link-MSVC_TOOLSET_VERSION; +must be '14.0'). + + + + + + +Example 1 - A Visual Studio 2022 build with a specific Windows SDK version: + +env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0') + + + + +Example 2 - A Visual Studio 2022 build with a specific SDK version for the Universal Windows Platform: + +env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0', MSVC_UWP_APP=True) + + + + +Important usage details: + + + +&cv-MSVC_SDK_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SDK_VERSION; must be set before the first msvc tool is +loaded into the environment. + + + + +Should a SDK 10.0 version be installed that does not follow the naming scheme above, the +SDK version will need to be specified via &cv-link-MSVC_SCRIPT_ARGS; until the version number +validation format can be extended. + + + + +Should an exception be raised indicating that the SDK version is not found, verify that +the requested SDK version is installed with the necessary platform type components. + + + +There is a known issue with the Microsoft libraries when the target architecture is +ARM64 and a Windows 11 SDK (version '10.0.22000.0' and later) is used +with the v141 build tools and older v142 toolsets +(versions '14.28.29333' and earlier). Should build failures arise with these combinations +of settings due to unresolved symbols in the Microsoft libraries, &cv-MSVC_SDK_VERSION; may be employed to +specify a Windows 10 SDK (e.g., '10.0.20348.0') for the build. + + + + + + + + + + MSVC_SPECTRE_LIBS + + +Build with the spectre-mitigated Visual C++ libraries. + + + +The valid values for &cv-MSVC_SPECTRE_LIBS; are: True, +False, or None. + + + +When &cv-MSVC_SPECTRE_LIBS; is enabled (i.e., True), +the Visual C++ environment will include the paths to the spectre-mitigated implementations +of the Microsoft Visual C++ libraries. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SPECTRE_LIBS; is enabled for Visual Studio 2015 and earlier. + + + +&cv-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-MSVC_SPECTRE_LIBS; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + +&cv-MSVC_SPECTRE_LIBS; is enabled and the platform type is UWP. There +are no spectre-mitigated libraries for Universal Windows Platform (UWP) applications or +components. + + + + + + +Example - A Visual Studio 2022 build with spectre mitigated Visual C++ libraries: + +env = Environment(MSVC_VERSION='14.3', MSVC_SPECTRE_LIBS=True) + + + + +Important usage details: + + + +&cv-MSVC_SPECTRE_LIBS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SPECTRE_LIBS; must be set before the first msvc tool is +loaded into the environment. + + + +Additional compiler switches (e.g., /Qspectre) are necessary for including +spectre mitigations when building user artifacts. Refer to the Visual Studio documentation for +details. + + + + +The existence of the spectre libraries host architecture and target architecture folders are not +verified when &cv-MSVC_SPECTRE_LIBS; is enabled which could result in build failures. + +The burden is on the user to ensure the requisite libraries with spectre mitigations are installed. + + + + + + + + + + MSVC_TOOLSET_VERSION + + +Build with a specific Visual C++ toolset version. + + + +Specifying &cv-MSVC_TOOLSET_VERSION; does not affect the autodetection and selection +of msvc instances. The &cv-MSVC_TOOLSET_VERSION; is applied after +an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION; +is not specified. + + + +The valid values for &cv-MSVC_TOOLSET_VERSION; are: None +or a string containing the requested toolset version (e.g., '14.29'). + + + +&cv-MSVC_TOOLSET_VERSION; is ignored when the value is None and when +the value is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_TOOLSET_VERSION; is specified for Visual Studio 2015 and earlier. + + + +&cv-MSVC_TOOLSET_VERSION; is specified and a toolset version argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via &cv-MSVC_TOOLSET_VERSION; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + + +The &cv-MSVC_TOOLSET_VERSION; specified does not match any of the supported formats: + + + + + +'XX.Y' + + + +'XX.YY' + + + +'XX.YY.ZZZZZ' + + + +'XX.YY.Z' to 'XX.YY.ZZZZ' + +[&scons; extension not directly supported by the msvc batch files and may be removed in the future] + + + + +'XX.YY.ZZ.N' [SxS format] + + + +'XX.YY.ZZ.NN' [SxS format] + + + + + + + +The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified +is for Visual Studio 2013 and earlier (e.g., '12.0'). + + + +The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified +is greater than the msvc version selected (e.g., '99.0'). + + + +A system folder for the corresponding &cv-MSVC_TOOLSET_VERSION; version is not found. +The requested toolset version does not appear to be installed. + + + + + + +Toolset selection details: + + + +When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number: +the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION; +prefix is selected. + + + +When &cv-MSVC_TOOLSET_VERSION; is specified using the major msvc version prefix +(i.e., 'XX.Y') and the major msvc version is that of the latest release of +Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version. + +In the latest release of Visual Studio, the default Visual C++ toolset version is not necessarily the +toolset with the largest version number. + + + + + + +Example 1 - A default Visual Studio build with a partial toolset version specified: + +env = Environment(MSVC_TOOLSET_VERSION='14.2') + + + + +Example 2 - A default Visual Studio build with a partial toolset version specified: + +env = Environment(MSVC_TOOLSET_VERSION='14.29') + + + + +Example 3 - A Visual Studio 2022 build with a full toolset version specified: + +env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133') + + + + +Example 4 - A Visual Studio 2022 build with an SxS toolset version specified: + +env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11') + + + + +Important usage details: + + + +&cv-MSVC_TOOLSET_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_TOOLSET_VERSION; must be set before the first msvc tool is +loaded into the environment. + + + + +The existence of the toolset host architecture and target architecture folders are not verified +when &cv-MSVC_TOOLSET_VERSION; is specified which could result in build failures. + +The burden is on the user to ensure the requisite toolset target architecture build tools are installed. + + + + + + + + + + MSVC_USE_SCRIPT + + +Use a batch script to set up the Microsoft Visual C++ compiler. + + + +If set to the name of a Visual Studio .bat file +(e.g. vcvars.bat), +&SCons; will run that batch file instead of the auto-detected one, +and extract the relevant variables from the result (typically +%INCLUDE%, +%LIB%, and +%PATH%) for supplying to the build. +This can be useful to force the use of a compiler version that +&SCons; does not detect. +&cv-link-MSVC_USE_SCRIPT_ARGS; provides arguments passed to this script. + + + +Setting +&cv-MSVC_USE_SCRIPT; to None bypasses the +Visual Studio autodetection entirely; +use this if you are running SCons in a Visual Studio cmd +window and importing the shell's environment variables - that +is, if you are sure everything is set correctly already and +you don't want &SCons; to change anything. + + +&cv-MSVC_USE_SCRIPT; ignores &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;. + + + + + + MSVC_USE_SCRIPT_ARGS + + +Provides arguments passed to the script &cv-link-MSVC_USE_SCRIPT;. + + + + + + MSVC_USE_SETTINGS + + +Use a dictionary to set up the Microsoft Visual C++ compiler. + + + +&cv-MSVC_USE_SETTINGS; is ignored when &cv-link-MSVC_USE_SCRIPT; is defined +and/or when &cv-MSVC_USE_SETTINGS; is set to None. + + + +The dictionary is used to populate the environment with the relevant variables +(typically %INCLUDE%, %LIB%, and %PATH%) +for supplying to the build. This can be useful to force the use of a compiler environment +that &SCons; does not configure correctly. This is an alternative to manually configuring +the environment when bypassing Visual Studio autodetection entirely by setting +&cv-link-MSVC_USE_SCRIPT; to None. + + + +Here is an example of configuring a build environment using the Microsoft Visual C/C++ compiler +included in the Microsoft SDK on a 64-bit host and building for a 64-bit architecture: + +# Microsoft SDK 6.0 (MSVC 8.0): 64-bit host and 64-bit target +msvc_use_settings = { + "PATH": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Bin\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin", + "C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727", + "C:\\Windows\\system32", + "C:\\Windows", + "C:\\Windows\\System32\\Wbem", + "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\" + ], + "INCLUDE": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include\\Sys", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include\\gl", + ], + "LIB": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Lib\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Lib\\x64", + ], + "LIBPATH": [], + "VSCMD_ARG_app_plat": [], + "VCINSTALLDIR": [], + "VCToolsInstallDir": [] +} + +# Specifying MSVC_VERSION is recommended +env = Environment(MSVC_VERSION='8.0', MSVC_USE_SETTINGS=msvc_use_settings) + + + + +Important usage details: + + + +&cv-MSVC_USE_SETTINGS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_USE_SETTINGS; must be set before the first msvc tool is +loaded into the environment. + + + + +The dictionary content requirements are based on the internal msvc implementation and +therefore may change at any time. + +The burden is on the user to ensure the dictionary contents are minimally sufficient to +ensure successful builds. + + + + + + + + + + MSVC_UWP_APP + + +Build with the Universal Windows Platform (UWP) application Visual C++ libraries. + + + +The valid values for &cv-MSVC_UWP_APP; are: True, +'1', False, '0', +or None. + + + +When &cv-MSVC_UWP_APP; is enabled (i.e., True or +'1'), the Visual C++ environment will be set up to point +to the Windows Store compatible libraries and Visual C++ runtimes. In doing so, +any libraries that are built will be able to be used in a UWP App and published +to the Windows Store. + + + + + +An exception is raised when any of the following conditions are satisfied: + + +&cv-MSVC_UWP_APP; is enabled for Visual Studio 2013 and earlier. + + +&cv-MSVC_UWP_APP; is enabled and a UWP argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via &cv-MSVC_UWP_APP; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + + + +Example - A Visual Studio 2022 build for the Universal Windows Platform: + +env = Environment(MSVC_VERSION='14.3', MSVC_UWP_APP=True) + + + + +Important usage details: + + + +&cv-MSVC_UWP_APP; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_UWP_APP; must be set before the first msvc tool is +loaded into the environment. + + + + +The existence of the UWP libraries is not verified when &cv-MSVC_UWP_APP; is enabled +which could result in build failures. + +The burden is on the user to ensure the requisite UWP libraries are installed. + + + + + + + + + + MSVC_VERSION + + +Sets the preferred version of Microsoft Visual C/C++ to use. + + + +If &cv-MSVC_VERSION; is not set, SCons will (by default) select the +latest version of Visual C/C++ installed on your system. If the +specified version isn't installed, tool initialization will fail. + + + +&cv-MSVC_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_VERSION; must be set before the first msvc tool is +loaded into the environment. + + + +Valid values for Windows are +14.3, +14.2, +14.1, +14.1Exp, +14.0, +14.0Exp, +12.0, +12.0Exp, +11.0, +11.0Exp, +10.0, +10.0Exp, +9.0, +9.0Exp, +8.0, +8.0Exp, +7.1, +7.0, +and 6.0. +Versions ending in Exp refer to "Express" or +"Express for Desktop" editions. + + + + + + + MSVS + + + When the Microsoft Visual Studio tools are initialized, + they set up this dictionary with the following keys: + + + + VERSION + the version of MSVS being used (can be set via + &cv-link-MSVS_VERSION;) + VERSIONS the available versions of MSVS installed @@ -5012,73 +6055,305 @@ - + + + MT + + +The program used on Windows systems to embed manifests into DLLs and EXEs. +See also &cv-link-WINDOWS_EMBED_MANIFEST;. + + + + + + MTEXECOM + + +The Windows command line used to embed manifests into executables. +See also &cv-link-MTSHLIBCOM;. + + + + + + MTFLAGS + + +Flags passed to the &cv-link-MT; manifest embedding program (Windows only). + + + + + + MTSHLIBCOM + + +The Windows command line used to embed manifests into shared libraries (DLLs). +See also &cv-link-MTEXECOM;. + + + + + + MWCW_VERSION + + +The version number of the MetroWerks CodeWarrior C compiler +to be used. + + + + + + MWCW_VERSIONS + + +A list of installed versions of the MetroWerks CodeWarrior C compiler +on this system. + + + + + + NAME + + +Specfies the name of the project to package. + +See the &b-link-Package; builder. + + + + + NINJA_ALIAS_NAME + + + The name of the alias target which will cause &SCons; to create the &ninja; build file, + and then (optionally) run &ninja;. + The default value is generate-ninja. + + + + + + NINJA_CMD_ARGS + + + A string which will pass arguments through SCons to the ninja command when scons executes ninja. + Has no effect if &cv-NINJA_DISABLE_AUTO_RUN; is set. + + + This value can also be passed on the command line: + + +scons NINJA_CMD_ARGS=-v +or +scons NINJA_CMD_ARGS="-v -j 3" + + + + + + NINJA_COMPDB_EXPAND + + + Boolean value to instruct &ninja; to expand the command line arguments normally put into + response files. + If true, prevents unexpanded lines in the compilation database like + gcc @rsp_file and instead yields expanded lines like + gcc -c -o myfile.o myfile.c -Ia -DXYZ. + + + Ninja's compdb tool added the flag in Ninja V1.9.0 + + + + + + NINJA_DEPFILE_PARSE_FORMAT + + + Determines the type of format ninja should expect when parsing header + include depfiles. Can be , , or . + The option corresponds to format, and + or correspond to . + + + + + + NINJA_DIR + + + The builddir value. + Propagates directly into the generated &ninja; build file. + From Ninja's docs: + + A directory for some Ninja output files. ... (You can also store other build output in this + directory.) + + The default value is .ninja. + + + + + + NINJA_DISABLE_AUTO_RUN + + + Boolean. Default: False. + If true, &SCons; will not run &ninja; automatically after creating the &ninja; build file. + + + + If not explicitly set, this will be set to True + if or + SetOption('disable_execute_ninja', True) is seen. + + + + + + NINJA_ENV_VAR_CACHE + + + A string that sets the environment for any environment variables that + differ between the OS environment and the &SCons; execution environment. + + + + It will be compatible with the default shell of the operating system. + + + + If not explicitly set, &SCons; will generate this dynamically from the + execution environment stored in the current &consenv; + (e.g. env['ENV']) + where those values differ from the existing shell.. + + + + + + NINJA_FILE_NAME + + + The filename for the generated Ninja build file. + The default is ninja.build. + + + + + + NINJA_FORCE_SCONS_BUILD + + + If true, causes the build nodes to callback to scons instead of using + &ninja; to build them. This is intended to be passed to the environment on the builder invocation. + It is useful if you have a build node which does something which is not easily translated into &ninja;. + + + + + + NINJA_GENERATED_SOURCE_ALIAS_NAME + + + A string matching the name of a user defined alias which represents a list of all generated sources. + This will prevent the auto-detection of generated sources from &cv-NINJA_GENERATED_SOURCE_SUFFIXES;. + Then all other source files will be made to depend on this in the &ninja; build file, forcing the + generated sources to be built first. + + + + + + NINJA_GENERATED_SOURCE_SUFFIXES + + + The list of source file suffixes which are generated by &SCons; build steps. + All source files which match these suffixes will be added to the _generated_sources alias in the output + &ninja; build file. + Then all other source files will be made to depend on this in the &ninja; build file, forcing the + generated sources to be built first. + + + + - MT + NINJA_MSVC_DEPS_PREFIX -The program used on Windows systems to embed manifests into DLLs and EXEs. -See also &cv-link-WINDOWS_EMBED_MANIFEST;. - - + The msvc_deps_prefix string. + Propagates directly into the generated &ninja; build file. + From Ninja's docs: + defines the string which should be stripped from msvc's output + + - + - MTEXECOM + NINJA_POOL -The Windows command line used to embed manifests into executables. -See also &cv-link-MTSHLIBCOM;. - - + Set the ninja_pool for this or all targets in scope for this env var. + + - + - MTFLAGS + NINJA_REGENERATE_DEPS -Flags passed to the &cv-link-MT; manifest embedding program (Windows only). - - + A generator function used to create a &ninja; depfile which + includes all the files which would require + &SCons; to be invoked if they change. + Or a list of said files. + + - + - MTSHLIBCOM + _NINJA_REGENERATE_DEPS_FUNC -The Windows command line used to embed manifests into shared libraries (DLLs). -See also &cv-link-MTEXECOM;. - - + Internal value used to specify the function to call with argument env to generate the list of files + which if changed would require the &ninja; build file to be regenerated. + + - + - MWCW_VERSION + NINJA_SCONS_DAEMON_KEEP_ALIVE -The version number of the MetroWerks CodeWarrior C compiler -to be used. - - + The number of seconds for the SCons deamon launched by ninja to stay alive. + (Default: 180000) + + - + - MWCW_VERSIONS + NINJA_SCONS_DAEMON_PORT -A list of installed versions of the MetroWerks CodeWarrior C compiler -on this system. - - + The TCP/IP port for the SCons daemon to listen on. + NOTE: You cannot use a port already being listened to on your build machine. + (Default: random number between 10000,60000) + + - + - NAME + NINJA_SYNTAX -Specfies the name of the project to package. - - + The path to a custom ninja_syntax.py file which is used in generation. + The tool currently assumes you have &ninja; installed as a &Python; module and grabs the syntax file from that + installation if &cv-NINJA_SYNTAX; is not explicitly set. + + @@ -5087,11 +6362,11 @@ When set to non-zero, suppresses creation of a corresponding Windows static import lib by the -SharedLibrary +&b-link-SharedLibrary; builder when used with MinGW, Microsoft Visual Studio or Metrowerks. This also suppresses creation -of an export (.exp) file +of an export (.exp) file when using Microsoft Visual Studio. @@ -5120,8 +6395,9 @@ Specifies the directory where all files in resulting archive will be -placed if applicable. The default value is "$NAME-$VERSION". +placed if applicable. The default value is &cv-NAME;-&cv-VERSION;. +See the &b-link-Package; builder. @@ -5129,29 +6405,16 @@ PACKAGETYPE -Selects the package type to build. Currently these are available: +Selects the package type to build when using the &b-link-Package; +builder. May be a string or list of strings. See the docuentation +for the builder for the currently supported types. -
- -msi - Microsoft Installer -rpm - RPM Package Manger -ipkg - Itsy Package Management System -tarbz2 - bzip2 compressed tar -targz - gzip compressed tar -tarxz - xz compressed tar -zip - zip file -src_tarbz2 - bzip2 compressed tar source -src_targz - gzip compressed tar source -src_tarxz - xz compressed tar source -src_zip - zip file source - -
- -This may be overridden with the +&cv-PACKAGETYPE; may be overridden with the command line option. +See the &b-link-Package; builder.
@@ -5164,6 +6427,7 @@ and should reflect changes in the packaging, not the underlying project code itself. +See the &b-link-Package; builder. @@ -5181,7 +6445,7 @@ -env['PCH'] = 'StdAfx.pch' +env['PCH'] = File('StdAfx.pch') @@ -5191,7 +6455,7 @@ The command line used by the -&b-PCH; +&b-link-PCH; builder to generated a precompiled header. @@ -5212,8 +6476,8 @@ A construction variable that, when expanded, -adds the /yD flag to the command line -only if the &cv-PDB; construction variable is set. +adds the flag to the command line +only if the &cv-link-PDB; construction variable is set.
@@ -5271,15 +6535,6 @@
- - - PDFCOM - - -A deprecated synonym for &cv-link-DVIPDFCOM;. - - - PDFLATEX @@ -5415,20 +6670,21 @@ PLATFORM -The name of the platform used to create the Environment. If no platform is -specified when the Environment is created, -&scons; -autodetects the platform. - + The name of the platform used to create this &consenv;. + &SCons; sets this when initializing the platform, + which by default is auto-detected + (see the platform + argument to &f-link-Environment;). + - -env = Environment(tools = []) + +env = Environment(tools=[]) if env['PLATFORM'] == 'cygwin': Tool('mingw')(env) else: Tool('msvc')(env) - - + + @@ -5523,44 +6779,65 @@ or options or their equivalents). -The function should take four arguments: +The function must accept four arguments: s, -the command being executed (a string), target, -the target being built (file node, list, or string name(s)), +source and +env. +s +is a string showing the command being executed, +target, +is the target being built (file node, list, or string name(s)), source, -the source(s) used (file node, list, or string name(s)), and -env, -the environment being used. +is the source(s) used (file node, list, or string name(s)), +and env +is the environment being used. -The function must do the printing itself. The default implementation, -used if this variable is not set or is None, is: +The function must do the printing itself. +The default implementation, +used if this variable is not set or is None, +is to just print the string, as in: def print_cmd_line(s, target, source, env): - sys.stdout.write(s + "\n") + sys.stdout.write(s + "\n") -Here's an example of a more interesting function: +Here is an example of a more interesting function: def print_cmd_line(s, target, source, env): - sys.stdout.write("Building %s -> %s...\n" % - (' and '.join([str(x) for x in source]), - ' and '.join([str(x) for x in target]))) -env=Environment(PRINT_CMD_LINE_FUNC=print_cmd_line) -env.Program('foo', 'foo.c') + sys.stdout.write( + "Building %s -> %s...\n" + % ( + ' and '.join([str(x) for x in source]), + ' and '.join([str(x) for x in target]), + ) + ) + +env = Environment(PRINT_CMD_LINE_FUNC=print_cmd_line) +env.Program('foo', ['foo.c', 'bar.c']) -This just prints "Building targetname from sourcename..." instead -of the actual commands. -Such a function could also log the actual commands to a log file, -for example. +This prints: + + + +... +scons: Building targets ... +Building bar.c -> bar.o... +Building foo.c -> foo.o... +Building foo.o and bar.o -> foo... +scons: done building targets. + + + +Another example could be a function that logs the actual commands to a file. @@ -5637,8 +6914,8 @@ QT_AUTOSCAN -Turn off scanning for mocable files. Use the Moc Builder to explicitly -specify files to run moc on. +Turn off scanning for mocable files. Use the &b-link-Moc; Builder to explicitly +specify files to run moc on.
@@ -5647,8 +6924,8 @@ QT_BINPATH -The path where the qt binaries are installed. -The default value is '&cv-link-QTDIR;/bin'. +The path where the Qt binaries are installed. +The default value is '&cv-link-QTDIR;/bin'.
@@ -5657,9 +6934,9 @@ QT_CPPPATH -The path where the qt header files are installed. +The path where the Qt header files are installed. The default value is '&cv-link-QTDIR;/include'. -Note: If you set this variable to None, +Note: If you set this variable to None, the tool won't change the &cv-link-CPPPATH; construction variable. @@ -5679,8 +6956,10 @@ QT_LIB -Default value is 'qt'. You may want to set this to 'qt-mt'. Note: If you set -this variable to None, the tool won't change the &cv-link-LIBS; variable. +Default value is 'qt'. +You may want to set this to 'qt-mt'. +Note: If you set this variable to None, +the tool won't change the &cv-link-LIBS; variable.
@@ -5689,9 +6968,9 @@ QT_LIBPATH -The path where the qt libraries are installed. -The default value is '&cv-link-QTDIR;/lib'. -Note: If you set this variable to None, +The path where the Qt libraries are installed. +The default value is '&cv-link-QTDIR;/lib'. +Note: If you set this variable to None, the tool won't change the &cv-link-LIBPATH; construction variable. @@ -5702,7 +6981,7 @@ QT_MOC -Default value is '&cv-link-QT_BINPATH;/moc'. +Default value is '&cv-link-QT_BINPATH;/moc'.
@@ -5711,7 +6990,8 @@ QT_MOCCXXPREFIX -Default value is ''. Prefix for moc output files, when source is a cxx file. +Default value is ''. +Prefix for moc output files when source is a C++ file.
@@ -5720,8 +7000,8 @@ QT_MOCCXXSUFFIX -Default value is '.moc'. Suffix for moc output files, when source is a cxx -file. +Default value is '.moc'. +Suffix for moc output files when source is a C++ file.
@@ -5730,7 +7010,7 @@ QT_MOCFROMCXXCOM -Command to generate a moc file from a cpp file. +Command to generate a moc file from a C++ file. @@ -5739,7 +7019,7 @@ QT_MOCFROMCXXCOMSTR -The string displayed when generating a moc file from a cpp file. +The string displayed when generating a moc file from a C++ file. If this is not set, then &cv-link-QT_MOCFROMCXXCOM; (the command line) is displayed. @@ -5749,8 +7029,8 @@ QT_MOCFROMCXXFLAGS -Default value is '-i'. These flags are passed to moc, when moccing a -C++ file. +Default value is '-i'. +These flags are passed to moc when moccing a C++ file. @@ -5768,7 +7048,7 @@ QT_MOCFROMHCOMSTR -The string displayed when generating a moc file from a cpp file. +The string displayed when generating a moc file from a C++ file. If this is not set, then &cv-link-QT_MOCFROMHCOM; (the command line) is displayed. @@ -5778,8 +7058,8 @@ QT_MOCFROMHFLAGS -Default value is ''. These flags are passed to moc, when moccing a header -file. +Default value is ''. These flags are passed to moc +when moccing a header file. @@ -5788,7 +7068,8 @@ QT_MOCHPREFIX -Default value is 'moc_'. Prefix for moc output files, when source is a header. +Default value is 'moc_'. +Prefix for moc output files when source is a header. @@ -5797,8 +7078,8 @@ QT_MOCHSUFFIX -Default value is '&cv-link-CXXFILESUFFIX;'. Suffix for moc output files, when source is -a header. +Default value is '&cv-link-CXXFILESUFFIX;'. +Suffix for moc output files when source is a header. @@ -5807,7 +7088,7 @@ QT_UIC -Default value is '&cv-link-QT_BINPATH;/uic'. +Default value is '&cv-link-QT_BINPATH;/uic'. @@ -5816,7 +7097,7 @@ QT_UICCOM -Command to generate header files from .ui files. +Command to generate header files from .ui files. @@ -5825,7 +7106,7 @@ QT_UICCOMSTR -The string displayed when generating header files from .ui files. +The string displayed when generating header files from .ui files. If this is not set, then &cv-link-QT_UICCOM; (the command line) is displayed. @@ -5835,8 +7116,8 @@ QT_UICDECLFLAGS -Default value is ''. These flags are passed to uic, when creating a a h -file from a .ui file. +Default value is ''. These flags are passed to uic +when creating a header file from a .ui file. @@ -5845,7 +7126,8 @@ QT_UICDECLPREFIX -Default value is ''. Prefix for uic generated header files. +Default value is ''. +Prefix for uic generated header files. @@ -5854,7 +7136,8 @@ QT_UICDECLSUFFIX -Default value is '.h'. Suffix for uic generated header files. +Default value is '.h'. +Suffix for uic generated header files. @@ -5863,8 +7146,9 @@ QT_UICIMPLFLAGS -Default value is ''. These flags are passed to uic, when creating a cxx -file from a .ui file. +Default value is ''. +These flags are passed to uic when creating a C++ +file from a .ui file. @@ -5873,7 +7157,8 @@ QT_UICIMPLPREFIX -Default value is 'uic_'. Prefix for uic generated implementation files. +Default value is 'uic_'. +Prefix for uic generated implementation files. @@ -5892,7 +7177,8 @@ QT_UISUFFIX -Default value is '.ui'. Suffix of designer input files. +Default value is '.ui'. +Suffix of designer input files. @@ -5901,66 +7187,11 @@ QTDIR -The qt tool tries to take this from os.environ. -It also initializes all QT_* -construction variables listed below. -(Note that all paths are constructed -with python's os.path.join() method, -but are listed here with the '/' separator -for easier reading.) -In addition, the construction environment -variables &cv-link-CPPPATH;, -&cv-link-LIBPATH; and -&cv-link-LIBS; may be modified -and the variables -&cv-link-PROGEMITTER;, &cv-link-SHLIBEMITTER; and &cv-link-LIBEMITTER; -are modified. Because the build-performance is affected when using this tool, -you have to explicitly specify it at Environment creation: - - - -Environment(tools=['default','qt']) - - - -The qt tool supports the following operations: - - - -Automatic moc file generation from header files. -You do not have to specify moc files explicitly, the tool does it for you. -However, there are a few preconditions to do so: Your header file must have -the same filebase as your implementation file and must stay in the same -directory. It must have one of the suffixes .h, .hpp, .H, .hxx, .hh. You -can turn off automatic moc file generation by setting QT_AUTOSCAN to 0. -See also the corresponding -&b-Moc;() -builder method. - - - -Automatic moc file generation from cxx files. -As stated in the qt documentation, include the moc file at the end of -the cxx file. Note that you have to include the file, which is generated -by the transformation ${QT_MOCCXXPREFIX}<basename>${QT_MOCCXXSUFFIX}, by default -<basename>.moc. A warning is generated after building the moc file, if you -do not include the correct file. If you are using VariantDir, you may -need to specify duplicate=1. You can turn off automatic moc file generation -by setting QT_AUTOSCAN to 0. See also the corresponding -&b-Moc; -builder method. - - - -Automatic handling of .ui files. -The implementation files generated from .ui files are handled much the same -as yacc or lex files. Each .ui file given as a source of Program, Library or -SharedLibrary will generate three files, the declaration file, the -implementation file and a moc file. Because there are also generated headers, -you may need to specify duplicate=1 in calls to VariantDir. -See also the corresponding -&b-Uic; -builder method. +The path to the Qt installation to build against. +If not already set, +&t-link-qt; tool tries to obtain this from +os.environ; +if not found there, it tries to make a guess. @@ -6041,7 +7272,7 @@ RCFLAGS -The flags passed to the resource compiler by the RES builder. +The flags passed to the resource compiler by the &b-link-RES; builder. @@ -6056,9 +7287,9 @@ by the resource compiler. The value of &cv-RCINCFLAGS; is created by respectively prepending and appending -&cv-RCINCPREFIX; and &cv-RCINCSUFFIX; +&cv-link-RCINCPREFIX; and &cv-link-RCINCSUFFIX; to the beginning and end -of each directory in &cv-CPPPATH;. +of each directory in &cv-link-CPPPATH;. @@ -6070,8 +7301,8 @@ The prefix (flag) used to specify an include directory on the resource compiler command line. This will be prepended to the beginning of each directory -in the &cv-CPPPATH; construction variable -when the &cv-RCINCFLAGS; variable is expanded. +in the &cv-link-CPPPATH; construction variable +when the &cv-link-RCINCFLAGS; variable is expanded. @@ -6083,8 +7314,8 @@ The suffix used to specify an include directory on the resource compiler command line. This will be appended to the end of each directory -in the &cv-CPPPATH; construction variable -when the &cv-RCINCFLAGS; variable is expanded. +in the &cv-link-CPPPATH; construction variable +when the &cv-link-RCINCFLAGS; variable is expanded. @@ -6105,8 +7336,8 @@ The program used on Windows systems to register a newly-built DLL library -whenever the &b-SharedLibrary; builder -is passed a keyword argument of register=1. +whenever the &b-link-SharedLibrary; builder +is passed a keyword argument of register=True. @@ -6117,8 +7348,8 @@ The command line used on Windows systems to register a newly-built DLL library -whenever the &b-SharedLibrary; builder -is passed a keyword argument of register=1. +whenever the &b-link-SharedLibrary; builder +is passed a keyword argument of register=True. @@ -6498,21 +7729,14 @@ - - - SHDLIBVERSION - - -SHDLIBVERSION. - - - SHDLIBVERSIONFLAGS -SHDLIBVERSIONFLAGS. +Extra flags added to &cv-link-SHDLINKCOM; when building versioned +&b-link-SharedLibrary;. These flags are only used when &cv-link-SHLIBVERSION; is +set. @@ -6561,6 +7785,56 @@ + + + SHELL_ENV_GENERATORS + + +Must be a list (or an iterable) containing functions where each function generates or +alters the environment dictionary which will be used +when executing the &cv-link-SPAWN; function. The functions will initially +be passed a reference of the current execution environment (e.g. env['ENV']), +and each called while iterating the list. Each function must return a dictionary +which will then be passed to the next function iterated. The return dictionary +should contain keys which represent the environment variables and their respective +values. + +This primary purpose of this construction variable is to give the user the ability +to substitute execution environment variables based on env, targets, and sources. +If desired, the user can completely customize the execution environment for particular +targets. + + + +def custom_shell_env(env, target, source, shell_env): + """customize shell_env if desired""" + if str(target[0]) == 'special_target': + shell_env['SPECIAL_VAR'] = env.subst('SOME_VAR', target=target, source=source) + return shell_env + +env["SHELL_ENV_GENERATORS"] = [custom_shell_env] + + + + env +The SCons construction environment from which the +execution environment can be derived from. + + + target +The list of targets associated with this action. + + + source +The list of sources associated with this action. + + + shell_env +The current shell_env after iterating other SHELL_ENV_GENERATORS functions. This can be compared +to the passed env['ENV'] to detect any changes. + + + SHF03 @@ -6611,7 +7885,7 @@ to generated shared-library objects. You only need to set &cv-link-SHF03FLAGS; if you need to define specific user options for Fortran 03 files. -You should normally set the &cv-link-SHFORTRANFLAGS; variable, +You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable, which specifies the user-specified options passed to the default Fortran compiler for all Fortran versions. @@ -6699,7 +7973,7 @@ to generated shared-library objects. You only need to set &cv-link-SHF08FLAGS; if you need to define specific user options for Fortran 08 files. -You should normally set the &cv-link-SHFORTRANFLAGS; variable, +You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable, which specifies the user-specified options passed to the default Fortran compiler for all Fortran versions. @@ -6787,7 +8061,7 @@ to generated shared-library objects. You only need to set &cv-link-SHF77FLAGS; if you need to define specific user options for Fortran 77 files. -You should normally set the &cv-link-SHFORTRANFLAGS; variable, +You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable, which specifies the user-specified options passed to the default Fortran compiler for all Fortran versions. @@ -6875,7 +8149,7 @@ to generated shared-library objects. You only need to set &cv-link-SHF90FLAGS; if you need to define specific user options for Fortran 90 files. -You should normally set the &cv-link-SHFORTRANFLAGS; variable, +You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable, which specifies the user-specified options passed to the default Fortran compiler for all Fortran versions. @@ -6963,7 +8237,7 @@ to generated shared-library objects. You only need to set &cv-link-SHF95FLAGS; if you need to define specific user options for Fortran 95 files. -You should normally set the &cv-link-SHFORTRANFLAGS; variable, +You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable, which specifies the user-specified options passed to the default Fortran compiler for all Fortran versions. @@ -7017,6 +8291,12 @@ The command line used to compile a Fortran source file to a shared-library object file. +By default, any options specified +in the &cv-link-SHFORTRANFLAGS;, +&cv-link-_FORTRANMODFLAG;, and +&cv-link-_FORTRANINCFLAGS; +&consvars; are included on this command line. +See also &cv-link-FORTRANCOM;. @@ -7050,10 +8330,13 @@ The command line used to compile a Fortran source file to a shared-library object file after first running the file through the C preprocessor. -Any options specified -in the &cv-link-SHFORTRANFLAGS; and -&cv-link-CPPFLAGS; construction variables -are included on this command line. +By default, any options specified in the &cv-link-SHFORTRANFLAGS;, +&cv-link-CPPFLAGS;, +&cv-link-_CPPDEFFLAGS;, +&cv-link-_FORTRANMODFLAG;, and +&cv-link-_FORTRANINCFLAGS; +&consvars; are included on this command line. +See also &cv-link-SHFORTRANCOM;. @@ -7169,6 +8452,16 @@ The linker for programs that use shared libraries. See also &cv-link-LINK; for linking static objects. + +On POSIX systems (those using the &t-link-link; tool), +you should normally not change this value as it defaults +to a "smart" linker tool which selects a compiler +driver matching the type of source files in use. +So for example, if you set &cv-link-SHCXX; to a specific +compiler name, and are compiling C++ sources, +the smartlink function will automatically select the same compiler +for linking. + @@ -7278,6 +8571,7 @@ Source: field in the controlling information for Ipkg and RPM packages. +See the &b-link-Package; builder. @@ -7292,13 +8586,32 @@ + + + SOVERSION + + +This will construct the SONAME using on the base library name +(test in the example below) and use specified SOVERSION +to create SONAME. + +env.SharedLibrary('test', 'test.c', SHLIBVERSION='0.1.2', SOVERSION='2') + +The variable is used, for example, by &t-link-gnulink; linker tool. + + +In the example above SONAME would be libtest.so.2 +which would be a symlink and point to libtest.so.0.1.2 + + + SPAWN A command interpreter function that will be called to execute command line -strings. The function must expect the following arguments: +strings. The function must accept five arguments: @@ -7306,18 +8619,18 @@ -sh -is a string naming the shell program to use. +shell +is a string naming the shell program to use, escape is a function that can be called to escape shell special characters in -the command line. +the command line, cmd -is the path to the command to be executed. +is the path to the command to be executed, args -is the arguments to the command. +holds the arguments to the command and env -is a dictionary of the environment variables -in which the command should be executed. +is a dictionary of environment variables +defining the execution environment in which the command should be executed. @@ -7376,6 +8689,7 @@ Description: field in MSI packages. +See the &b-link-Package; builder. @@ -7383,7 +8697,7 @@ SWIG -The scripting language wrapper and interface generator. +The name of the &swig; compiler to use. @@ -7393,10 +8707,11 @@ The suffix that will be used for intermediate C -source files generated by -the scripting language wrapper and interface generator. -The default value is -_wrap&cv-link-CFILESUFFIX;. +source files generated by &swig;. +The default value is '_wrap$CFILESUFFIX' - +that is, the concatenation of the string +_wrap +and the current C suffix &cv-link-CFILESUFFIX;. By default, this value is used whenever the option is @@ -7412,8 +8727,7 @@ SWIGCOM -The command line used to call -the scripting language wrapper and interface generator. +The command line used to call &swig;. @@ -7422,8 +8736,7 @@ SWIGCOMSTR -The string displayed when calling -the scripting language wrapper and interface generator. +The string displayed when calling &swig;. If this is not set, then &cv-link-SWIGCOM; (the command line) is displayed. @@ -7434,12 +8747,13 @@ The suffix that will be used for intermediate C++ -source files generated by -the scripting language wrapper and interface generator. -The default value is -_wrap&cv-link-CFILESUFFIX;. +source files generated by &swig;. +The default value is '_wrap$CXXFILESUFFIX' - +that is, the concatenation of the string +_wrap +and the current C++ suffix &cv-link-CXXFILESUFFIX;. By default, this value is used whenever the --c++ + option is specified as part of the &cv-link-SWIGFLAGS; construction variable. @@ -7452,8 +8766,8 @@ The suffix that will be used for intermediate C++ header -files generated by the scripting language wrapper and interface generator. -These are only generated for C++ code when the SWIG 'directors' feature is +files generated by &swig;. +These are only generated for C++ code when the &swig; 'directors' feature is turned on. The default value is _wrap.h. @@ -7465,22 +8779,14 @@ SWIGFLAGS -General options passed to -the scripting language wrapper and interface generator. -This is where you should set -, +General options passed to &swig;. +This is where you should set the target language +(, , -, -or whatever other options you want to specify to SWIG. -If you set the - -option in this variable, -&scons; -will, by default, -generate a C++ intermediate source file -with the extension that is specified as the -&cv-link-CXXFILESUFFIX; -variable. +, etc.) +and whatever other options you want to specify to &swig;, +such as the to generate C++ code +instead of C Code. @@ -7490,7 +8796,7 @@ An automatically-generated construction variable -containing the SWIG command-line options +containing the &swig; command-line options for specifying directories to be searched for included files. The value of &cv-_SWIGINCFLAGS; is created by respectively prepending and appending @@ -7505,7 +8811,7 @@ SWIGINCPREFIX -The prefix used to specify an include directory on the SWIG command line. +The prefix used to specify an include directory on the &swig; command line. This will be prepended to the beginning of each directory in the &cv-SWIGPATH; construction variable when the &cv-_SWIGINCFLAGS; variable is automatically generated. @@ -7517,7 +8823,7 @@ SWIGINCSUFFIX -The suffix used to specify an include directory on the SWIG command line. +The suffix used to specify an include directory on the &swig; command line. This will be appended to the end of each directory in the &cv-SWIGPATH; construction variable when the &cv-_SWIGINCFLAGS; variable is automatically generated. @@ -7529,8 +8835,7 @@ SWIGOUTDIR -Specifies the output directory in which -the scripting language wrapper and interface generator +Specifies the output directory in which &swig; should place generated language-specific files. This will be used by SCons to identify the files that will be generated by the &swig; call, @@ -7544,22 +8849,24 @@ SWIGPATH -The list of directories that the scripting language wrapper -and interface generate will search for included files. -The SWIG implicit dependency scanner will search these +The list of directories that &swig; +will search for included files. +&SCons;' SWIG implicit dependency scanner will search these directories for include files. The default value is an empty list. Don't explicitly put include directory -arguments in SWIGFLAGS; +arguments in &cv-link-SWIGFLAGS; the result will be non-portable and the directories will not be searched by the dependency scanner. -Note: directory names in SWIGPATH will be looked-up relative to the SConscript +Note: directory names in &cv-link-SWIGPATH; +will be looked-up relative to the SConscript directory when they are used in a command. To force &scons; -to look-up a directory relative to the root of the source tree use #: +to look-up a directory relative to the root of the source tree use +a top-relative path (#): @@ -7603,7 +8910,7 @@ SWIGVERSION -The version number of the SWIG tool. +The detected version string of the &swig; tool. @@ -7666,60 +8973,64 @@ TARGET_ARCH - The name of the target hardware architecture for the compiled objects - created by this Environment. - This defaults to the value of HOST_ARCH, and the user can override it. - Currently only set for Win32. - + The name of the hardware architecture that objects + created using this &consenv; should target. + Can be set when creating a &consenv; by passing as a keyword + argument in the &f-link-Environment; call. + -Sets the target architecture for Visual Studio compiler (i.e. the arch -of the binaries generated by the compiler). If not set, default to -&cv-link-HOST_ARCH;, or, if that is unset, to the architecture of the -running machine's OS (note that the python build or architecture has no -effect). -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. -This is currently only used on Windows, but in the future it will be -used on other OSes as well. -If this is set and &cv-link-MSVC_VERSION; is not set, this will search for -all installed MSVC's that support the &cv-TARGET_ARCH;, selecting the -latest version for use. - - - -On Windows, valid target values are -x86, -arm, -i386 -for 32-bit targets and -amd64, -arm64, -em64t, -x86_64 -and ia64 (Itanium) -for 64-bit targets. -Note that not all target architectures are -supported for all Visual Studio / MSVC versions -check the relevant Microsoft documentation. - - - -For example, if you want to compile 64-bit binaries, you would set -TARGET_ARCH='x86_64' in your SCons environment. - - + On the win32 platform, + if the Microsoft Visual C++ compiler is available, + &t-link-msvc; tool setup is done using + &cv-link-HOST_ARCH; and &cv-TARGET_ARCH;. + If a value is not specified, + will be set to the same value as &cv-link-HOST_ARCH;. + Changing the value after the environment is initialized + will not cause the tool to be reinitialized. + Compiled objects will be in the target architecture if + the compilation system supports generating for that target. + The latest compiler which can fulfill the requirement will + be selected, unless a different version is directed by the + value of the &cv-link-MSVC_VERSION; &consvar;. + + + On the win32/msvc combination, valid target arch values are + x86, + arm, + i386 + for 32-bit targets and + amd64, + arm64, + x86_64 + and ia64 (Itanium) + for 64-bit targets. + For example, if you want to compile 64-bit binaries, you would set + TARGET_ARCH='x86_64' when creating the &consenv;. + Note that not all target architectures are + supported for all Visual Studio / MSVC versions. + Check the relevant Microsoft documentation. + + + &cv-TARGET_ARCH; is not currently used by other compilation tools, + but the option is reserved to do so in future + + TARGET_OS - The name of the target operating system for the compiled objects - created by this Environment. - This defaults to the value of HOST_OS, and the user can override it. - Currently only set for Win32. - - + The name of the operating system that objects + created using this &consenv; should target. + Can be set when creating a &consenv; by passing as a keyword + argument in the &f-link-Environment; call;. + + + &cv-TARGET_OS; is not currently used by &SCons; + but the option is reserved to do so in future + + @@ -7742,13 +9053,76 @@ + + + TEMPFILE + + +A callable object used to handle overly long command line strings, +since operations which call out to a shell will fail +if the line is longer than the shell can accept. +This tends to particularly impact linking. +The tempfile object stores the command line in a temporary +file in the appropriate format, and returns +an alternate command line so the invoked tool will make +use of the contents of the temporary file. +If you need to replace the default tempfile object, +the callable should take into account the settings of +&cv-link-MAXLINELENGTH;, +&cv-link-TEMPFILEPREFIX;, +&cv-link-TEMPFILESUFFIX;, +&cv-link-TEMPFILEARGJOIN;, +&cv-link-TEMPFILEDIR; +and +&cv-link-TEMPFILEARGESCFUNC;. + + + + + + TEMPFILEARGESCFUNC + + +The default argument escape function is +SCons.Subst.quote_spaces. +If you need to apply extra operations on a command argument +(to fix Windows slashes, normalize paths, etc.) +before writing to the temporary file, +you can set the &cv-TEMPFILEARGESCFUNC; variable to a custom function. +Such a function takes a single string argument and returns +a new string with any modifications applied. +Example: + + + +import sys +import re +from SCons.Subst import quote_spaces + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if sys.platform != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + +env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func + + + TEMPFILEARGJOIN -The string (or character) to be used to join the arguments passed to TEMPFILE when command line exceeds the limit set by &cv-MAXLINELENGTH;. -The default value is a space. However for MSVC, MSLINK the default is a line seperator characters as defined by os.linesep. +The string to use to join the arguments passed to +&cv-link-TEMPFILE; when the command line exceeds the limit set by +&cv-link-MAXLINELENGTH;. +The default value is a space. +However for MSVC, MSLINK the default is a line separator +as defined by os.linesep. Note this value is used literally and not expanded by the subst logic. @@ -7758,7 +9132,7 @@ TEMPFILEDIR -The directory to create the tempfile in. +The directory to create the long-lines temporary file in. @@ -7767,16 +9141,13 @@ TEMPFILEPREFIX -The prefix for a temporary file used -to store lines lines longer than $MAXLINELENGTH -as operations which call out to a shell will fail -if the line is too long, which particularly -impacts linking. -The default is '@', which works for the Microsoft +The prefix for the name of the temporary file used +to store command lines exceeding &cv-link-MAXLINELENGTH;. +The default prefix is '@', which works for the Microsoft and GNU toolchains on Windows. Set this appropriately for other toolchains, -for example '-@' for the diab compiler -or '-via' for ARM toolchain. +for example '-@' for the diab compiler +or '-via' for ARM toolchain. @@ -7785,11 +9156,11 @@ TEMPFILESUFFIX -The suffix used for the temporary file name -used for long command lines. The name should -include the dot ('.') if one is wanted as +The suffix for the name of the temporary file used +to store command lines exceeding &cv-link-MAXLINELENGTH;. +The suffix should include the dot ('.') if one is wanted as it will not be added automatically. -The default is '.lnk'. +The default is .lnk. @@ -7914,6 +9285,7 @@ Manufacturer: field in the controlling information for MSI packages. +See the &b-link-Package; builder. @@ -7923,6 +9295,7 @@ The version of the project, specified as a string. +See the &b-link-Package; builder. @@ -7975,61 +9348,18 @@ - - - WIN32_INSERT_DEF - - -A deprecated synonym for &cv-link-WINDOWS_INSERT_DEF;. - - - - - - WIN32DEFPREFIX - - -A deprecated synonym for &cv-link-WINDOWSDEFPREFIX;. - - - - - - WIN32DEFSUFFIX - - -A deprecated synonym for &cv-link-WINDOWSDEFSUFFIX;. - - - - - - WIN32EXPPREFIX - - -A deprecated synonym for &cv-link-WINDOWSEXPSUFFIX;. - - - - - - WIN32EXPSUFFIX - - -A deprecated synonym for &cv-link-WINDOWSEXPSUFFIX;. - - - WINDOWS_EMBED_MANIFEST -Set this variable to True or 1 to embed the compiler-generated manifest +Set to True to embed the +compiler-generated manifest (normally ${TARGET}.manifest) -into all Windows exes and DLLs built with this environment, +into all Windows executables and DLLs built with this environment, as a resource during their link step. This is done using &cv-link-MT; and &cv-link-MTEXECOM; and &cv-link-MTSHLIBCOM;. +See also &cv-link-WINDOWS_INSERT_MANIFEST;. @@ -8038,14 +9368,21 @@ WINDOWS_INSERT_DEF -When this is set to true, +If set to true, a library build of a Windows shared library (.dll file) -will also build a corresponding .def file -at the same time, -if a .def file +will include a reference to the corresponding +module-definition file at the same time, +if a module-definition file is not already listed as a build target. -The default is 0 (do not build a .def file). +The name of the module-definition file will +be constructed from the base name of the library +and the &consvars; +&cv-link-WINDOWSDEFSUFFIX; and +&cv-link-WINDOWSDEFPREFIX;. +The default is to not add a module-definition file. +The module-definition file is not created by this directive, +and must be supplied by the developer. @@ -8054,11 +9391,21 @@ WINDOWS_INSERT_MANIFEST -When this is set to true, +If set to true, &scons; -will be aware of the -.manifest -files generated by Microsoft Visua C/C++ 8. +will add the manifest file +generated by Microsoft Visual C++ 8.0 and later +to the target list so &SCons; will be aware they +were generated. +In the case of an executable, the manifest file name +is constructed using +&cv-link-WINDOWSPROGMANIFESTSUFFIX; and +&cv-link-WINDOWSPROGMANIFESTPREFIX;. +In the case of a shared library, the manifest file name +is constructed using +&cv-link-WINDOWSSHLIBMANIFESTSUFFIX; and +&cv-link-WINDOWSSHLIBMANIFESTPREFIX;. +See also &cv-link-WINDOWS_EMBED_MANIFEST;. @@ -8067,7 +9414,8 @@ WINDOWSDEFPREFIX -The prefix used for Windows .def file names. +The prefix used for a Windows linker module-definition file name. +Defaults to empty. @@ -8076,7 +9424,8 @@ WINDOWSDEFSUFFIX -The suffix used for Windows .def file names. +The suffix used for a Windows linker module-definition file name. +Defaults to .def. @@ -8085,7 +9434,8 @@ WINDOWSEXPPREFIX -The prefix used for Windows .exp file names. +The prefix used for Windows linker exports file names. +Defaults to empty. @@ -8094,7 +9444,8 @@ WINDOWSEXPSUFFIX -The suffix used for Windows .exp file names. +The suffix used for Windows linker exports file names. +Defaults to .exp. @@ -8103,8 +9454,9 @@ WINDOWSPROGMANIFESTPREFIX -The prefix used for executable program .manifest files +The prefix used for executable program manifest files generated by Microsoft Visual C/C++. +Defaults to empty. @@ -8113,8 +9465,9 @@ WINDOWSPROGMANIFESTSUFFIX -The suffix used for executable program .manifest files +The suffix used for executable program manifest files generated by Microsoft Visual C/C++. +Defaults to .manifest. @@ -8123,8 +9476,9 @@ WINDOWSSHLIBMANIFESTPREFIX -The prefix used for shared library .manifest files +The prefix used for shared library manifest files generated by Microsoft Visual C/C++. +Defaults to empty. @@ -8133,8 +9487,9 @@ WINDOWSSHLIBMANIFESTSUFFIX -The suffix used for shared library .manifest files +The suffix used for shared library manifest files generated by Microsoft Visual C/C++. +Defaults to .manifest. @@ -8147,6 +9502,7 @@ Depends: field in the controlling information for Ipkg packages. +See the &b-link-Package; builder. @@ -8158,7 +9514,7 @@ Description: field in the controlling information for Ipkg packages. The default value is -$SUMMARY\n$DESCRIPTION +&cv-SUMMARY;\n&cv-DESCRIPTION; @@ -8204,6 +9560,7 @@ Language: attribute in the controlling information for MSI packages. +See the &b-link-Package; builder. @@ -8215,6 +9572,7 @@ Carriage return characters will be replaced with the RTF equivalent \\par. +See the &b-link-Package; builder. @@ -8236,6 +9594,7 @@ field in the RPM .spec file. +See the &b-link-Package; builder. @@ -8298,7 +9657,7 @@ This value is used as the default attributes for the files in the RPM package. The default value is -(-,root,root). +(-,root,root). @@ -8712,6 +10071,31 @@ + + + YACC_GRAPH_FILE + + +If supplied, write a graph of the automaton to a file with the name +taken from this variable. +Will be emitted as a +command-line option. Use this in preference to including + in &cv-link-YACCFLAGS; directly. + + + + + + YACC_HEADER_FILE + + +If supplied, generate a header file with the name taken from this variable. +Will be emitted as a +command-line option. Use this in preference to including + in &cv-link-YACCFLAGS; directly. + + + YACCCOM @@ -8733,7 +10117,7 @@ -env = Environment(YACCCOMSTR = "Yacc'ing $TARGET from $SOURCES") +env = Environment(YACCCOMSTR="Yacc'ing $TARGET from $SOURCES") @@ -8743,11 +10127,51 @@ General options passed to the parser generator. -If &cv-link-YACCFLAGS; contains a option, -SCons assumes that the call will also create a .h file -(if the yacc source file ends in a .y suffix) -or a .hpp file -(if the yacc source file ends in a .yy suffix) +In addition to passing the value on during invocation, +the &t-link-yacc; tool also examines this &consvar; for options +which cause additional output files to be generated, +and adds those to the target list. + + + +If a option is present, +&scons; assumes that the call will also create a header file +with the suffix defined by &cv-link-YACCHFILESUFFIX; +if the yacc source file ends in a .y suffix, +or a file with the suffix defined by &cv-link-YACCHXXFILESUFFIX; +if the yacc source file ends in a .yy suffix. + + + +If a option is present, +&scons; assumes that the call will also create a graph file +with the suffix defined by &cv-link-YACCVCGFILESUFFIX;. + + + +If a option is present, +&scons; assumes that the call will also create an output debug file +with the suffix .output. + + + +Also recognized are GNU &bison; options + and its deprecated synonym +, +which is similar to + +but the output filename is named by the option argument; +and , +which is similar to + +but the output filename is named by the option argument. + + + +Note that files specified by and + may not be properly handled +by &SCons; in all situations. Consider using +&cv-link-YACC_HEADER_FILE; and &cv-link-YACC_GRAPH_FILE; instead. @@ -8826,6 +10250,23 @@ + + + ZIP_OVERRIDE_TIMESTAMP + + +An optional timestamp which overrides the last modification time of +the file when stored inside the Zip archive. This is a tuple of six values: + +Year (>= 1980) +Month (one-based) +Day of month (one-based) +Hours (zero-based) +Minutes (zero-based) +Seconds (zero-based) + + + ZIPCOM diff -Nru scons-4.0.1+dfsg/doc/generated/variables.mod scons-4.4.0+dfsg/doc/generated/variables.mod --- scons-4.0.1+dfsg/doc/generated/variables.mod 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/generated/variables.mod 2022-07-30 21:48:28.000000000 +0000 @@ -33,9 +33,11 @@ $BIBTEXCOMSTR"> $BIBTEXFLAGS"> $BUILDERS"> +$CACHEDIR_CLASS"> $CC"> $CCCOM"> $CCCOMSTR"> +$CCDEPFLAGS"> $CCFLAGS"> $CCPCHFLAGS"> $CCPDBFLAGS"> @@ -47,6 +49,7 @@ $CHANGED_TARGETS"> $CHANGELOG"> $COMPILATIONDB_COMSTR"> +$COMPILATIONDB_PATH_FILTER"> $COMPILATIONDB_USE_ABSPATH"> $_concat"> $CONFIGUREDIR"> @@ -118,7 +121,6 @@ $DPATH"> $DRPATHPREFIX"> $DRPATHSUFFIX"> -$DShLibSonameGenerator"> $DSUFFIXES"> $DVERPREFIX"> $DVERSIONS"> @@ -184,6 +186,7 @@ $File"> $FORTRAN"> $FORTRANCOM"> +$FORTRANCOMMONFLAGS"> $FORTRANCOMSTR"> $FORTRANFILESUFFIXES"> $FORTRANFLAGS"> @@ -264,6 +267,8 @@ $_LDMODULEVERSIONFLAGS"> $LDMODULEVERSIONFLAGS"> $LEX"> +$LEX_HEADER_FILE"> +$LEX_TABLES_FILE"> $LEXCOM"> $LEXCOMSTR"> $LEXFLAGS"> @@ -318,7 +323,15 @@ $MSSDK_DIR"> $MSSDK_VERSION"> $MSVC_BATCH"> +$MSVC_NOTFOUND_POLICY"> +$MSVC_SCRIPT_ARGS"> +$MSVC_SCRIPTERROR_POLICY"> +$MSVC_SDK_VERSION"> +$MSVC_SPECTRE_LIBS"> +$MSVC_TOOLSET_VERSION"> $MSVC_USE_SCRIPT"> +$MSVC_USE_SCRIPT_ARGS"> +$MSVC_USE_SETTINGS"> $MSVC_UWP_APP"> $MSVC_VERSION"> $MSVS"> @@ -348,6 +361,24 @@ $MWCW_VERSION"> $MWCW_VERSIONS"> $NAME"> +$NINJA_ALIAS_NAME"> +$NINJA_CMD_ARGS"> +$NINJA_COMPDB_EXPAND"> +$NINJA_DEPFILE_PARSE_FORMAT"> +$NINJA_DIR"> +$NINJA_DISABLE_AUTO_RUN"> +$NINJA_ENV_VAR_CACHE"> +$NINJA_FILE_NAME"> +$NINJA_FORCE_SCONS_BUILD"> +$NINJA_GENERATED_SOURCE_ALIAS_NAME"> +$NINJA_GENERATED_SOURCE_SUFFIXES"> +$NINJA_MSVC_DEPS_PREFIX"> +$NINJA_POOL"> +$NINJA_REGENERATE_DEPS"> +$_NINJA_REGENERATE_DEPS_FUNC"> +$NINJA_SCONS_DAEMON_KEEP_ALIVE"> +$NINJA_SCONS_DAEMON_PORT"> +$NINJA_SYNTAX"> $no_import_lib"> $OBJPREFIX"> $OBJSUFFIX"> @@ -360,7 +391,6 @@ $PCHPDBFLAGS"> $PCHSTOP"> $PDB"> -$PDFCOM"> $PDFLATEX"> $PDFLATEXCOM"> $PDFLATEXCOMSTR"> @@ -461,12 +491,12 @@ $SHDC"> $SHDCOM"> $SHDCOMSTR"> -$SHDLIBVERSION"> $SHDLIBVERSIONFLAGS"> $SHDLINK"> $SHDLINKCOM"> $SHDLINKFLAGS"> $SHELL"> +$SHELL_ENV_GENERATORS"> $SHF03"> $SHF03COM"> $SHF03COMSTR"> @@ -521,6 +551,7 @@ $SOURCE"> $SOURCE_URL"> $SOURCES"> +$SOVERSION"> $SPAWN"> $STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME"> $SUBST_DICT"> @@ -549,6 +580,8 @@ $TARGET_OS"> $TARGETS"> $TARSUFFIX"> +$TEMPFILE"> +$TEMPFILEARGESCFUNC"> $TEMPFILEARGJOIN"> $TEMPFILEDIR"> $TEMPFILEPREFIX"> @@ -566,11 +599,6 @@ $VENDOR"> $VERSION"> $VSWHERE"> -$WIN32_INSERT_DEF"> -$WIN32DEFPREFIX"> -$WIN32DEFSUFFIX"> -$WIN32EXPPREFIX"> -$WIN32EXPSUFFIX"> $WINDOWS_EMBED_MANIFEST"> $WINDOWS_INSERT_DEF"> $WINDOWS_INSERT_MANIFEST"> @@ -631,6 +659,8 @@ $XGETTEXTPATHPREFIX"> $XGETTEXTPATHSUFFIX"> $YACC"> +$YACC_GRAPH_FILE"> +$YACC_HEADER_FILE"> $YACCCOM"> $YACCCOMSTR"> $YACCFLAGS"> @@ -638,6 +668,7 @@ $YACCHXXFILESUFFIX"> $YACCVCGFILESUFFIX"> $ZIP"> +$ZIP_OVERRIDE_TIMESTAMP"> $ZIPCOM"> $ZIPCOMPRESSION"> $ZIPCOMSTR"> @@ -676,9 +707,11 @@ $BIBTEXCOMSTR"> $BIBTEXFLAGS"> $BUILDERS"> +$CACHEDIR_CLASS"> $CC"> $CCCOM"> $CCCOMSTR"> +$CCDEPFLAGS"> $CCFLAGS"> $CCPCHFLAGS"> $CCPDBFLAGS"> @@ -690,6 +723,7 @@ $CHANGED_TARGETS"> $CHANGELOG"> $COMPILATIONDB_COMSTR"> +$COMPILATIONDB_PATH_FILTER"> $COMPILATIONDB_USE_ABSPATH"> $_concat"> $CONFIGUREDIR"> @@ -761,7 +795,6 @@ $DPATH"> $DRPATHPREFIX"> $DRPATHSUFFIX"> -$DShLibSonameGenerator"> $DSUFFIXES"> $DVERPREFIX"> $DVERSIONS"> @@ -827,6 +860,7 @@ $File"> $FORTRAN"> $FORTRANCOM"> +$FORTRANCOMMONFLAGS"> $FORTRANCOMSTR"> $FORTRANFILESUFFIXES"> $FORTRANFLAGS"> @@ -907,6 +941,8 @@ $_LDMODULEVERSIONFLAGS"> $LDMODULEVERSIONFLAGS"> $LEX"> +$LEX_HEADER_FILE"> +$LEX_TABLES_FILE"> $LEXCOM"> $LEXCOMSTR"> $LEXFLAGS"> @@ -961,7 +997,15 @@ $MSSDK_DIR"> $MSSDK_VERSION"> $MSVC_BATCH"> +$MSVC_NOTFOUND_POLICY"> +$MSVC_SCRIPT_ARGS"> +$MSVC_SCRIPTERROR_POLICY"> +$MSVC_SDK_VERSION"> +$MSVC_SPECTRE_LIBS"> +$MSVC_TOOLSET_VERSION"> $MSVC_USE_SCRIPT"> +$MSVC_USE_SCRIPT_ARGS"> +$MSVC_USE_SETTINGS"> $MSVC_UWP_APP"> $MSVC_VERSION"> $MSVS"> @@ -991,6 +1035,24 @@ $MWCW_VERSION"> $MWCW_VERSIONS"> $NAME"> +$NINJA_ALIAS_NAME"> +$NINJA_CMD_ARGS"> +$NINJA_COMPDB_EXPAND"> +$NINJA_DEPFILE_PARSE_FORMAT"> +$NINJA_DIR"> +$NINJA_DISABLE_AUTO_RUN"> +$NINJA_ENV_VAR_CACHE"> +$NINJA_FILE_NAME"> +$NINJA_FORCE_SCONS_BUILD"> +$NINJA_GENERATED_SOURCE_ALIAS_NAME"> +$NINJA_GENERATED_SOURCE_SUFFIXES"> +$NINJA_MSVC_DEPS_PREFIX"> +$NINJA_POOL"> +$NINJA_REGENERATE_DEPS"> +$_NINJA_REGENERATE_DEPS_FUNC"> +$NINJA_SCONS_DAEMON_KEEP_ALIVE"> +$NINJA_SCONS_DAEMON_PORT"> +$NINJA_SYNTAX"> $no_import_lib"> $OBJPREFIX"> $OBJSUFFIX"> @@ -1003,7 +1065,6 @@ $PCHPDBFLAGS"> $PCHSTOP"> $PDB"> -$PDFCOM"> $PDFLATEX"> $PDFLATEXCOM"> $PDFLATEXCOMSTR"> @@ -1104,12 +1165,12 @@ $SHDC"> $SHDCOM"> $SHDCOMSTR"> -$SHDLIBVERSION"> $SHDLIBVERSIONFLAGS"> $SHDLINK"> $SHDLINKCOM"> $SHDLINKFLAGS"> $SHELL"> +$SHELL_ENV_GENERATORS"> $SHF03"> $SHF03COM"> $SHF03COMSTR"> @@ -1164,6 +1225,7 @@ $SOURCE"> $SOURCE_URL"> $SOURCES"> +$SOVERSION"> $SPAWN"> $STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME"> $SUBST_DICT"> @@ -1192,6 +1254,8 @@ $TARGET_OS"> $TARGETS"> $TARSUFFIX"> +$TEMPFILE"> +$TEMPFILEARGESCFUNC"> $TEMPFILEARGJOIN"> $TEMPFILEDIR"> $TEMPFILEPREFIX"> @@ -1209,11 +1273,6 @@ $VENDOR"> $VERSION"> $VSWHERE"> -$WIN32_INSERT_DEF"> -$WIN32DEFPREFIX"> -$WIN32DEFSUFFIX"> -$WIN32EXPPREFIX"> -$WIN32EXPSUFFIX"> $WINDOWS_EMBED_MANIFEST"> $WINDOWS_INSERT_DEF"> $WINDOWS_INSERT_MANIFEST"> @@ -1274,6 +1333,8 @@ $XGETTEXTPATHPREFIX"> $XGETTEXTPATHSUFFIX"> $YACC"> +$YACC_GRAPH_FILE"> +$YACC_HEADER_FILE"> $YACCCOM"> $YACCCOMSTR"> $YACCFLAGS"> @@ -1281,6 +1342,7 @@ $YACCHXXFILESUFFIX"> $YACCVCGFILESUFFIX"> $ZIP"> +$ZIP_OVERRIDE_TIMESTAMP"> $ZIPCOM"> $ZIPCOMPRESSION"> $ZIPCOMSTR"> diff -Nru scons-4.0.1+dfsg/doc/man/html.xsl scons-4.4.0+dfsg/doc/man/html.xsl --- scons-4.0.1+dfsg/doc/man/html.xsl 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/man/html.xsl 2022-07-30 21:48:28.000000000 +0000 @@ -25,11 +25,14 @@ --> + + @@ -64,5 +67,87 @@ + + + + + + + + + + <xsl:copy-of select="$title"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru scons-4.0.1+dfsg/doc/man/sconsign.xml scons-4.4.0+dfsg/doc/man/sconsign.xml --- scons-4.0.1+dfsg/doc/man/sconsign.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/man/sconsign.xml 2022-07-30 21:48:28.000000000 +0000 @@ -49,67 +49,58 @@ DESCRIPTION -The -sconsign -command -displays the contents of one or more signature database -(sconsign) -files used by the scons build tool. + +Displays the contents of one or more +sconsign files, +the signature database files +used by the SCons build tool. By default, sconsign dumps the entire contents of the sconsign file(s). -Without the verbose option, -each entry is printed in the following format: +Without options, +individual dependency entries are printed in the following format: - -file: signature timestamp length - implicit_dependency_1: signature timestamp length - implicit_dependency_2: signature timestamp length + +depfile: signature timestamp length + implicit_dependency_1: content_signature timestamp length + implicit_dependency_2: content_signature timestamp length ... action_signature [action string] - + None -is printed -in place of any missing timestamp, build signature -(bsig), -or content signature +is printed in place of any missing timestamp, + content signature (csig) -values for -any entry +or +build action signature +values for any entry or any of its dependencies. If the entry has no implicit dependencies, or no build action, -the lines are simply omitted. - - -The verbose option expands the display into a more human -readable format. - +those lines are omitted. By default, sconsign assumes that any file arguments that end with a -.dbm +.dblite suffix contains signature entries for more than one directory (that is, was specified by the -SConsignFile +SConsignFile function). Any file -argument that ends in -.dblite -is assumed to be a traditional -sconsign -file containing the signature entries +argument that has no suffix +is assumed to be an old-style +sconsign file containing the signature entries for a single directory. If neither of those is true, sconsign @@ -127,7 +118,7 @@ file arguments, the name .sconsign.dblite -is assumed. +is assumed by default. @@ -145,7 +136,7 @@ -Prints the build action information +Prints only the build action information for all entries or the specified entries. @@ -156,7 +147,7 @@ -Prints the content signature (csig) information +Prints only the content signature (csig) information for all entries or the specified entries. @@ -169,11 +160,11 @@ When the signatures are being read from a -.dbm +.dblite file, or the - + or - + options are used, prints information about only the signatures @@ -208,15 +199,15 @@ are in the specified FORMAT. Legal values are -dbm -(the DBM format used -when the -SConsignFile -function is used) -or -sconsign -(the default format -used for an individual +dblite +(the SCons.dblite format used by default, +as well as when the +SConsignFile +function is called, except when a filename argument +of None is given) +and +sconsign +(the format used for an individual .sconsign file in each directory). diff -Nru scons-4.0.1+dfsg/doc/man/scons.xml scons-4.4.0+dfsg/doc/man/scons.xml --- scons-4.0.1+dfsg/doc/man/scons.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/man/scons.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,26 +1,28 @@ @@ -47,22 +49,17 @@ SCons &buildversion; MAN page - - Steven - Knight - - - Steven Knight and the SCons Development Team + The SCons Development Team - 2004 - 2020 - - 2004 - 2020 + Released &builddate; + + ©right_years; The SCons Foundation - version &buildversion; + Version &buildversion; @@ -71,7 +68,6 @@ SCons &buildversion; MAN page - SCONS @@ -102,41 +98,86 @@ (and other tangible products such as documentation files) by determining which component pieces must be built or rebuilt and invoking the necessary -commands to build them. - -You instruct -&scons; by writing a configuration file -which specifies the files to be built (targets), -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, +commands to build them. +&SCons; offers many features to improve developer productivity +such as parallel builds, caching of build artifacts, +automatic dependency scanning, +and a database of information about previous builds so +details do not have to be recalculated each run. + + +&scons; requires Python 3.6 or later to run; +there should be no other dependencies or requirements. +unless the experimental Ninja tool is used. + +Support for Python 3.5 is removed since +&SCons; 4.3.0. +The CPython project has retired 3.5: +. + + +You set up an &SCons; +build system by writing a script +that describes things to build (targets), and, +if necessary, the rules to build those files (actions). +&SCons; comes with a collection of Builder methods +which apply premade actions for building many common software components +such as executable programs, object files and libraries, so that for many software projects, -only the target and input files need be specified. +only the targets and input files (sources) +need be specified in a call to a builder. +&SCons; thus can operate at a level of abstraction above that of pure filenames. +For example if you specify a library target named "foo", +&SCons; keeps track of the actual operating system dependent filename +(such as libfoo.so on a GNU/Linux system), +and how to refer to that library in later construction steps +that want to use it, so you don't have to specify that precise +information yourself. +&SCons; can also scan automatically for dependency information, +such as header files included by source code files +(for example, #include +preprocessor directives in C or C++ files), +so these implicit dependencies do not +have to be specified manually. +&SCons; supports the ability to define new scanners +to support additional input file types. + + +Information about files involved in the build, +including a cryptographic hash of the contents, +is cached for later reuse. +By default this hash (the &contentsig;) +is used to determine if a file has changed since the last build, +but this can be controlled by selecting an appropriate +&f-link-Decider; function. +Implicit dependency files are also part of out-of-date computation. +The scanned implicit dependency information can optionally be +cached and used to speed up future builds. +A hash of each executed build action (the &buildsig; +is cached, so that changes to build instructions (changing flags, etc.) +or to the build tools themselves (new version) +can also trigger a rebuild. + When invoked, &scons; -searches for a file named +looks for a file named &SConstruct; -(it also checks alternate spellings -&Sconstruct;, &sconstruct;, &SConstruct.py; &Sconstruct.py; -and &sconstruct.py; -in that order) in the current directory and reads its -configuration from that file. -An alternate file name may be -specified via the - -option. +in the current directory and reads the +build configuration from that file +(other names are allowed, +see for more information). The &SConstruct; -file can specify subsidiary +file may specify subsidiary configuration files by calling the -&SConscriptFunc; function. +&f-link-SConscript; function. By convention, these subsidiary files are named &SConscript;, although any name may be used. As a result of this naming convention, the term SConscript files -is often used to refer +is used to refer generically to the complete set of configuration files for a project (including the &SConstruct; file), @@ -147,36 +188,47 @@ looks for a directory named site_scons 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 instead, and prepends the ones it finds to the Python module search path (sys.path), thus allowing modules in such directories to be imported in the normal Python way in SConscript files. For each found site directory, -if it contains a file site_init.py -it is evaluated, and if it contains a directory -site_tools the path to it +(1) if it contains a file site_init.py +that file is evaluated, +and (2) if it contains a directory +site_tools the path to that directory is prepended to the default toolpath. See the - + and - + options for details on default paths and controlling the site directories. -&scons; configuration files are written in the +SConscript files are written in the Python programming language, although it is normally not necessary to be a Python programmer to use &scons; effectively. +SConscript files are invoked in a context that makes +the facilities described in this manual page available +in their local namespace without any special steps. Standard Python scripting capabilities such as flow control, data manipulation, and imported Python libraries are available to use to handle complicated build situations. +Other Python files can be made a part of the build system, +but they do not automatically have the &SCons; context and +need to import it if they need access (described later). &scons; -reads and executes all of the SConscript files +reads and executes all of the included SConscript files before it begins building any targets. To make this clear, @@ -196,30 +248,45 @@ The status messages (lines beginning with the scons: tag) may be suppressed using the - + option. -&scons; -does not automatically propagate -the external environment used to execute -&scons; -to the commands used to build target files. -This is so that builds will be guaranteed -repeatable regardless of the environment -variables set at the time -&scons; -is invoked. -This also means that if the compiler or other commands + +To assure reproducible builds, +&SCons; +uses a restricted execution environment +for running external commands used to build targets, +rather then propagating the full environment +in effect at the time &scons; was called. +This helps avoid problems like picking up accidental settings, +temporary debug values that are no longer needed, +or one developer having different settings than another +(or than the CI/CD pipeline). +Environment variables that are needed for proper +operation of such commands need to be set explicitly, +which can be done either by assigning the desired values, +or by picking values individually out of environment variables +using the &Python; os.environ dictionary. +The execution environment for a given &consenv; is +contained in its &cv-link-ENV; &consvar;. +A few environment variables are picked up automatically - +see ). + + + +In particular, if the compiler or other commands 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 -PATH in the ENV -variable in the internal &consenv;. -Whenever you create a &consenv;, -you can propagate the value of PATH -from your external environment as follows: +you explicitly include the locations into the +PATH element of the +execution environment. +One example approach is to +extract the entire PATH +environment variable and set that into the +execution environment: + import os @@ -229,13 +296,18 @@ Similarly, if the commands use specific external environment variables that &scons; does not recognize, they can be propagated into -the internal environment: +the execution environment: 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'], + } +) Or you may explicitly propagate the invoking user's @@ -243,7 +315,7 @@ import os -env = Environment(ENV=os.environ) +env = Environment(ENV=os.environ.copy()) This comes at the expense of making your build @@ -256,25 +328,15 @@ &scons; -can scan known input files automatically for dependency -information (for example, #include -preprocessor directives in C or C++ files) -and will rebuild dependent files appropriately -whenever any "included" input file changes. -&scons; -supports the -ability to define new scanners for unknown input file types. - -&scons; 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 +&SCONSFLAGS; +environment variable, if set) is processed. Command-line options (see ) are consumed. Any variable argument assignments are collected, and -remaining arguments are taken as the targets to build. +remaining arguments are taken as targets to build. Values of variables to be passed to the SConscript files may be specified on the command line: @@ -283,8 +345,8 @@ scons debug=1 -These variables are available -through the &ARGUMENTS; dictionary, +These variables are available through the +&ARGUMENTS; dictionary, and can be used in the SConscript files to modify the build in any way: @@ -296,28 +358,131 @@ The command-line variable arguments are also available -in the &ARGLIST; list, +in the &ARGLIST; 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 (argname, argvalue). -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. + +See +for more information. -If no targets are specified on the command line, +&scons; +can maintain a cache of target (derived) files that can +be shared between multiple builds. When derived-file caching is enabled in an +SConscript file, any target files built by +&scons; +will be copied +to the cache. If an up-to-date target file is found in the cache, it +will be retrieved from the cache instead of being rebuilt locally. +Caching behavior may be disabled and controlled in other ways by the +, +, +, +and + +command-line options. The + +option is useful to prevent multiple builds +from trying to update the cache simultaneously. + + + + + +By default, +&scons; +searches for known programming tools +on various systems and initializes itself based on what is found. +On Windows systems which identify as win32, +&scons; +searches in order for the +Microsoft Visual C++ tools, +the MinGW tool chain, +the Intel compiler tools, +and the PharLap ETS compiler. +On Windows system which identify as cygwin +(that is, if &scons; is invoked from a cygwin shell), +the order changes to prefer the GCC toolchain over the MSVC tools. +On OS/2 systems, +&scons; +searches in order for the +OS/2 compiler, +the GCC tool chain, +and the Microsoft Visual C++ tools, +On SGI IRIX, IBM AIX, Hewlett Packard HP-UX, and Oracle Solaris systems, +&scons; +searches for the native compiler tools +(MIPSpro, Visual Age, aCC, and Forte tools respectively) +and the GCC tool chain. +On all other platforms, +including POSIX (Linux and UNIX) platforms, &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. +searches in order +for the GCC tool chain, +and the Intel compiler tools. +These default values may be overridden +by appropriate setting of &consvars;. + + +Target Selection + +&SCons; acts on the selected targets, +whether the requested operation is build, no-exec or clean. +Targets are selected as follows: + + + + +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 +&COMMAND_LINE_TARGETS; list. + + + +If no targets are specified on the command line, +&scons; will select those targets +specified in the SConscript files via calls +to the &f-link-Default; function. These are +known as the default targets, +and are made available in the +&DEFAULT_TARGETS; list. + + + + +If no targets are selected by the previous steps, +&scons; selects the current directory for scanning, +unless command-line options which affect the target +scan are detected +(, +, +, +). +Since targets thus selected were not the result of +user instructions, this target list is not made available +for direct inspection; use the + +option if they need to be examined. + + + + +&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. + + To ignore the default targets specified through calls to &Default; and instead build all @@ -356,13 +521,17 @@ or by changing directory and invoking scons with the - + option, which traverses up the directory hierarchy until it finds the &SConstruct; file, and then builds targets relatively to the current subdirectory (see -also the related and options): +also the related + +and + +options): cd src/subdir @@ -373,11 +542,12 @@ requested, as &scons; needs to make sure any dependent files are built. -Specifying "cleanup" targets in SConscript files is not usually necessary. +Specifying "cleanup" targets in SConscript files is +usually not necessary. The - -flag removes all files -necessary to build the specified target: + +flag removes all selected targets: + scons -c . @@ -394,15 +564,15 @@ 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 invocation can be retained by calling the -&NoClean; function with those targets. +&f-link-NoClean; function with those targets. &scons; supports building multiple targets in parallel via a - + option that takes, as its argument, the number of simultaneous tasks that may be spawned: @@ -412,70 +582,7 @@ builds four targets in parallel, for example. -&scons; -can maintain a cache of target (derived) files that can -be shared between multiple builds. When caching is enabled in a -SConscript file, any target files built by -&scons; -will be copied -to the cache. If an up-to-date target file is found in the cache, it -will be retrieved from the cache instead of being rebuilt locally. -Caching behavior may be disabled and controlled in other ways by the -, -, -, -and - -command-line options. The - -option is useful to prevent multiple builds -from trying to update the cache simultaneously. - - - - - -By default, -&scons; -searches for known programming tools -on various systems and initializes itself based on what is found. -On Windows systems which identify as win32, -&scons; -searches in order for the -Microsoft Visual C++ tools, -the MinGW tool chain, -the Intel compiler tools, -and the PharLap ETS compiler. -On Windows system which identify as cygwin -(that is, if &scons; is invoked from a cygwin shell), -the order changes to prefer the GCC toolchain over the MSVC tools. -On OS/2 systems, -&scons; -searches in order for the -OS/2 compiler, -the GCC tool chain, -and the Microsoft Visual C++ tools, -On SGI IRIX, IBM AIX, Hewlett Packard HP-UX, and Oracle Solaris systems, -&scons; -searches for the native compiler tools -(MIPSpro, Visual Age, aCC, and Forte tools respectively) -and the GCC tool chain. -On all other platforms, -including POSIX (Linux and UNIX) platforms, -&scons; -searches in order -for the GCC tool chain, -and the Intel compiler tools. -These default values may be overridden -by appropriate setting of &consvars;. - -&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. - - + @@ -487,33 +594,50 @@ and many of those supported by cons. + + + + + + - + Ignored for compatibility with non-GNU versions of &Make; - + , , -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. +Set clean mode. +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. + + +While clean mode removes targets rather than building them, +work which is done directly in Python code in SConscript files +will still be carried out. If it is important to avoid some +such work from taking place in clean mode, it should be protected. +An SConscript file can determine which mode +is active by querying &f-link-GetOption;, as in the call +if GetOption("clean"): + - + - Write debug information about @@ -530,7 +654,7 @@ - + , @@ -546,7 +670,7 @@ - + , @@ -565,7 +689,7 @@ - + Use the derived-file cache, if enabled, to retrieve files, @@ -575,35 +699,36 @@ - + -When using a derived-file cache -and retrieving a file from it, -show the command -that would have been executed to build the file. -Without this option, &scons; reports -"Retrieved `file' from cache.". +When using a derived-file cache show the command +that would have been executed to build the file +(or the corresponding *COMSTR +contents if set) +even if the file is retrieved from cache. +Without this option, &scons; shows a cache retrieval message +if the file is fetched from cache. This allows producing consistent output for build logs, regardless of whether a target file was rebuilt or retrieved from the cache. - + -Control how the &Configure; +Control how the &f-link-Configure; call should use or generate the results of configuration tests. -modeshould be specified from -among the following choices: +mode should be one of +the following choices: auto -scons will use its normal dependency mechanisms +&SCons; will use its normal dependency mechanisms to decide if a test must be rebuilt or not. This saves time by not running the same configuration tests every time you invoke scons, @@ -617,7 +742,7 @@ force -If this option is specified, +If this mode is specified, all configuration tests will be re-run regardless of whether the cached results are out of date. @@ -631,7 +756,7 @@ cache -If this option is specified, +If this mode is specified, no configuration tests will be rerun and all results will be taken from cache. &scons; will report an error @@ -645,7 +770,7 @@ - + , @@ -669,15 +794,15 @@ directory is interpreted relative to the preceding one. This option is similar to using -, +, but does not search for any of the predefined &SConstruct; names in the specified directory. See also options -, - +, + and - + to change the &SConstruct; search behavior when this option is used. @@ -689,11 +814,11 @@ - + Works exactly the same way as the - + option except for the way default targets are handled. When this option is used and no targets are specified on the command line, all default targets are built, whether or not they are below the current @@ -701,14 +826,14 @@ - + Debug the build process. type specifies the kind of debugging info to emit. Multiple types may be specified, separated by commas. -The following entries show the recognized types: +The following types are recognized: @@ -919,86 +1044,51 @@ - - + + Enable specific checks for whether or not there is a file on disk where the SCons configuration expects a directory -(or vice versa), -and whether or not RCS or SCCS sources exist +(or vice versa) when searching for source and include files. -The type -argument can be set to: +can be an available diskcheck type or +the special tokens all or none. +A comma-separated string can be used to select multiple checks. +The default setting is all. +Current available checks are: - all - -Enable all checks explicitly (the default behavior). - - - - - none - -Disable all such checks. - - - - match to check that files and directories on disk match SCons' expected configuration. - - - rcs - -Check for the existence of an RCS source -for any missing source or include files. - - - - - sccs - -Check for the existence of an SCCS source -for any missing source or include files. - - -Multiple checks can be specified separated by commas. -for example, - -would still check for SCCS and RCS sources, -but disable the check for on-disk matches of files and directories. Disabling some or all of these checks can provide a performance boost for large configurations, or when the configuration will check for files and/or directories across networked or shared file systems, at the slight increased risk of an incorrect build -or of not handling errors gracefully -(if include files really should be -found in SCCS or RCS, for example, -or if a file really does exist -where the SCons configuration expects a directory). +or of not handling errors gracefully. + + - + There are three ways to duplicate files in a build tree: hard links, -soft (symbolic) links and copies. The default behaviour of SCons is to -prefer hard links to soft links to copies. You can specify different -behaviours with this option. +soft (symbolic) links and copies. The default policy is to +prefer hard links to soft links to copies. You can specify a +different policy with this option. ORDER must be one of hard-soft-copy @@ -1008,7 +1098,7 @@ soft-copy or copy. -SCons will attempt to duplicate files using +&SCons; will attempt to duplicate files using the mechanisms in the specified order. @@ -1018,34 +1108,53 @@ - + Import virtualenv-related variables to SCons. - - - , - , - , - - - -Use -file -as the initial SConscript file. -Multiple - -options may be specified, -in which case -&scons; -will read all of the specified files. - + + + + + + Enable experimental features and/or tools. + feature can be an available feature name or + the special tokens all or none. + A comma-separated string can be used to select multiple features. + The default setting is none. + Current available features are: ninja. + + No Support offered for any features or tools enabled by this flag. + + Available since &scons; 4.2. + - + + + , + , + , + + + + Use + file + as the initial SConscript file. + Multiple + + options may be specified, + in which case + &scons; + will read all of the specified files. + + + + + , @@ -1068,7 +1177,60 @@ - + + + + + +Set the block size used when computing &contentsigs; to +KILOBYTES. +This value determines the size of the chunks which are read in at once when +computing signature hashes. Files below that size are fully stored in memory +before performing the signature computation while bigger files are read in +block-by-block. A huge block-size leads to high memory consumption while a very +small block-size slows down the build considerably. + +The default value is to use a chunk size of 64 kilobytes, which should +be appropriate for most uses. + +Available since &scons; 4.2. + + + + + + + + +Set the hashing algorithm used by SCons to +ALGORITHM. +This value determines the hashing algorithm used in generating +&contentsigs; or &CacheDir; keys. + +The supported list of values are: md5, sha1, and sha256. +However, the Python interpreter used to run SCons must have the corresponding +support available in the hashlib module +to use the specified algorithm. + +Specifying this value changes the name of the SConsign database. +For example, will create a SConsign +database with name .sconsign_sha256.dblite. + +If this option is not specified, a the first supported hash format found +is selected. Typically this is MD5, however, if you are on a FIPS-compliant system +and using a version of Python less than 3.9, SHA1 or SHA256 will be chosen as the default. +Python 3.9 and onwards clients will always default to MD5, even in FIPS mode, unless +otherwise specified with the option. + +For MD5 databases (either explicitly specified with or +defaulted), the SConsign database is.sconsign.dblite. The newer SHA1 and +SHA256 selections meanwhile store their databases to .sconsign_algorithmname.dblite + +Available since &scons; 4.2. + + + + , @@ -1079,7 +1241,7 @@ - + , @@ -1090,7 +1252,7 @@ - + , @@ -1106,14 +1268,14 @@ - + Suppress importing virtualenv-related variables to SCons. - + Cache implicit dependencies. @@ -1127,8 +1289,7 @@ &scons; will not detect changes to implicit dependency search paths -(e.g. -CPPPATH, LIBPATH) +(e.g. &cv-link-CPPPATH;, &cv-link-LIBPATH;) that would ordinarily cause different versions of same-named files to be used. @@ -1136,13 +1297,12 @@ will miss changes in the implicit dependencies in cases where a new implicit dependency is added earlier in the implicit dependency search path -(e.g. -CPPPATH, LIBPATH) +(e.g. &cv-link-CPPPATH;, &cv-link-LIBPATH;) than a current implicit dependency with the same name. - + Forces SCons to ignore the cached implicit dependencies. This causes the @@ -1151,7 +1311,7 @@ - + Force SCons to ignore changes in the implicit dependencies. @@ -1161,18 +1321,21 @@ - - + + -When using the &Install; functions, prepend path +When using the &Install; builders, prepend +sandbox_path to the installation paths such that all installed files will be placed -underneath path. +under that directory. This option is unavailable if +one of &b-link-Install;, &b-link-InstallAs; or +&b-link-InstallVersionedLib; is not used in the SConscript files. - + Starts SCons in interactive mode. @@ -1329,7 +1492,7 @@ - + , @@ -1349,7 +1512,7 @@ - + , @@ -1390,29 +1553,29 @@ - + Ignored for compatibility with non-GNU versions of &Make;. - + Set the maximum expected drift in the modification time of files to SECONDS. This value determines how long a file must be unmodified -before its cached content signature +before its cached &contentsig; will be used instead of -calculating a new content signature (MD5 checksum) +calculating a new &contentsig; (hash) of the file's contents. The default value is 2 days, which means a file must have a modification time of at least two days ago in order to have its -cached content signature used. -A negative value means to never cache the content -signature and to ignore the cached value if there already is one. A value -of 0 means to always use the cached signature, +cached &contentsig; used. +A negative value means to never cache the +&contentsig; and to ignore the cached value if there already is one. +A value of 0 means to always use the cached signature, no matter how old the file is. @@ -1420,37 +1583,50 @@ -Set the block size used to compute MD5 signatures to -KILOBYTES. -This value determines the size of the chunks which are read in at once when -computing MD5 signatures. Files below that size are fully stored in memory -before performing the signature computation while bigger files are read in -block-by-block. A huge block-size leads to high memory consumption while a very -small block-size slows down the build considerably. +A deprecated synonym for +. + -The default value is to use a chunk size of 64 kilobytes, which should -be appropriate for most uses. +Deprecated since &scons; 4.2. - + , + , , , -No execute. Print the commands that would be executed to build +Set no execute mode. +Print the commands that would be executed to build any out-of-date target files, but do not execute the commands. + +The output is a best effort, as &SCons; cannot always precisely +determine what would be built. For example, if a file is generated +by a builder action that is later used in the build, +that file is not available to scan for dependencies on an unbuilt tree, +or may contain out of date information in a built tree. + + +Work which is done directly in Python code in SConscript files, +as opposed to work done by builder actions during the build phase, +will still be carried out. If it is important to avoid some +such work from taking place in no execute mode, it should be protected. +An SConscript file can determine which mode +is active by querying &f-link-GetOption;, as in the call +if GetOption("no_exec"): + - + Prevents the automatic addition of the standard -site_scons +site_scons dirs to sys.path. Also prevents loading the @@ -1492,7 +1668,21 @@ - + + + +The type or types +of package to create when using the &b-link-Package; builder. +In the case of multiple types, type +should be a comma-separated string; &SCons; will try to build +for all of those packages. +Note this option is only available if the &t-link-packaging; tool +has been enabled. + + + + + Run SCons under the Python profiler @@ -1503,7 +1693,7 @@ - + , @@ -1514,7 +1704,7 @@ - + Quiets SCons status messages about @@ -1531,7 +1721,7 @@ - + Build dependencies in a random order. This is useful when @@ -1541,7 +1731,7 @@ - + , , @@ -1554,7 +1744,7 @@ - + , , @@ -1565,28 +1755,29 @@ - - + + -Uses the named dir as the site directory -rather than the default -site_scons -directories. This directory will be prepended to +Use a specific path as the site directory +rather than searching the list of default site directories. +This directory will be prepended to sys.path, the module -dir/site_init.py +path/site_init.py will be loaded if it exists, and -dir/site_tools +path/site_tools will be added to the default toolpath. -The default set of -site_scons -directories used when +The default set of site directories searched when is not specified depends on the system platform, as follows. +Users or system administrators can tune site-specific or +project-specific &SCons; behavior by setting up a +site directory in one or more of these locations. Directories are examined in the order given, from most -generic to most specific, so the last-executed site_init.py file is -the most specific one (which gives it the chance to override +generic ("system" directories) to most specific (in the current project), +so the last-executed site_init.py file is +the most specific one, giving it the chance to override everything else), and the directories are prepended to the paths, again so the last directory examined comes first in the resulting path. @@ -1595,14 +1786,22 @@ Windows: -%ALLUSERSPROFILE/Application Data/scons/site_scons -%USERPROFILE%/Local Settings/Application Data/scons/site_scons +%ALLUSERSPROFILE%/scons/site_scons +%LOCALAPPDATA%/scons/site_scons %APPDATA%/scons/site_scons -%HOME%/.scons/site_scons +%USERPROFILE%/.scons/site_scons ./site_scons - - + +Note earlier versions of the documentation listed a different +path for the "system" site directory, this path is still checked +but its use is discouraged: + + +%ALLUSERSPROFILE%/Application Data/scons/site_scons + + + Mac OS X: @@ -1645,7 +1844,7 @@ - + Set the size stack used to run threads to @@ -1669,7 +1868,7 @@ - + , @@ -1681,7 +1880,7 @@ - + Prints trace information to the specified @@ -1694,7 +1893,7 @@ - + Prints a tree of the dependencies @@ -1774,7 +1973,7 @@ - + , , @@ -1792,7 +1991,7 @@ - + Works exactly the same way as the @@ -1805,7 +2004,7 @@ - + , @@ -1819,7 +2018,7 @@ - + , @@ -1830,20 +2029,21 @@ - + Turn off -w, even if it was turned on implicitly. - + , -Enable or disable (with the no- prefix) warnings. +Enable or disable (with the prefix "no-") warnings +( is a synonym). type specifies the type of warnings to be enabled or disabled: @@ -1969,6 +2169,18 @@ + tool-qt-deprecated + +Warnings about the &t-link-qt; tool being deprecated. +These warnings are disabled by default for the first +phase of deprecation. Enable to be reminded about use +of this tool module. +Available since &SCons; 4.3. + + + + + missing-sconscript Warnings about missing SConscript files. @@ -2069,7 +2281,7 @@ - + , , @@ -2087,17 +2299,69 @@ - -CONFIGURATION FILE REFERENCE - - + +SCONSCRIPT FILE REFERENCE + + +SConscript Files + +The build configuration is described by one or more files, +known as SConscript files. +There must be at least one file for a valid build +(&scons; will quit if it does not find one). +&scons; by default looks for this file by the name +SConstruct +in the directory from which you run &scons;, +though if necessary, also looks for alternative file names +&Sconstruct;, &sconstruct;, &SConstruct.py;, &Sconstruct.py; +and &sconstruct.py; in that order. +A different file name (which can include a pathname part) +may be specified via the option. +Except for the SConstruct file, +these files are not searched for automatically; +you add additional configuration files to the build +by calling the &f-link-SConscript; function. +This allows parts of the build to be conditionally +included or excluded at run-time depending on how &scons; is invoked. + + + +Each SConscript file in a build configuration is invoked +independently in a separate context. +This provides necessary isolation so that different parts of +the build don't accidentally step on each other. +You have to be explicit about sharing information, +by using the &f-link-Export; function or the &exports; argument +to the &SConscript; function, as well as the &f-link-Return; function +in a called SConscript file, and comsume shared information by using the +&f-link-Import; function. + + + +The following sections describe the various &SCons; facilities +that can be used in SConscript files. Quick links: + + + + Construction Environments + Tools + Builder Methods + Methods and Functions to do Things + SConscript Variables + Construction Variables + Configure Contexts + Command-Line Construction Variables + Node Objects + + + Construction Environments -A &ConsEnv; is the basic means by which SConscript -files communicate build information to -&scons;. +A &ConsEnv; is the basic means by which +you communicate build information to +&SCons;. A new &consenv; is created using the &f-link-Environment; function: @@ -2109,73 +2373,88 @@ &Consenv; attributes called &ConsVars; may be set either by specifying them as keyword arguments when the object is created -or by assigning them a value after the object is created: +or by assigning them a value after the object is created. +These two are nominally equivalent: env = Environment(FOO='foo') -env['BAR'] = 'bar' +env['FOO'] = 'foo' - - - -An existing &consenv; can be duplicated by calling the &f-link-env-Clone; -method. Without arguments, it will be a copy with the same -settings. Otherwise, &f-env-Clone; takes the same arguments as &f-Environment;, -and uses the arguments to create a modified copy. + +Note that certain settings which affect tool detection are +referenced only when the tools are initializided, +so you either need either to supply them as part of the call to +&f-link-Environment;, or defer tool initialization. +For example, initializing the Microsoft Visual C++ version you wish to use: - -&SCons; also provides a special &consenv; called the -&DefEnv;. -The &defenv; is used only for global functions, that is, -construction activities called without the context of a regular &consenv;. -See &f-link-DefaultEnvironment; for more information. - + +# initializes msvc to v14.1 +env = Environment(MSVC_VERSION="14.1") + +env = Environment() +# msvc tool was initialized to default, does not reinitialize +env['MSVC_VERSION'] = "14.1" + +env = Environment(tools=[]) +env['MSVC_VERSION'] = "14.1" +# msvc tool initialization was deferred, so will pick up new value +env.Tool('default') + As a convenience, &consvars; may also be set or modified by the parse_flags -keyword argument, which applies the +keyword argument during object creation, +which has the effect of the &f-link-env-MergeFlags; -method (described below) to the argument value +method being applied to the argument value after all other processing is completed. This is useful either if the exact content of the flags is unknown (for example, read from a control file) -or if the flags need to be distributed to a number of &consvars;. +or if the flags need to be distributed to a number of &consvars;. +&f-link-env-ParseFlags; describes how these arguments +are distributed to &consvars;. + env = Environment(parse_flags='-Iinclude -DEBUG -lm') This example adds 'include' to -the CPPPATH &consvar; +the &cv-link-CPPPATH; &consvar;, 'EBUG' to -CPPDEFINES, +&cv-link-CPPDEFINES;, and 'm' to -LIBS. -&f-link-env-ParseFlags; describes how these arguments -are distributed to &consvars;. +&cv-link-LIBS;. + +An existing &consenv; can be duplicated by calling the &f-link-env-Clone; +method. Without arguments, it will be a copy with the same +settings. Otherwise, &f-env-Clone; takes the same arguments as +&f-link-Environment;, and uses the arguments to create a modified copy. + + + +&SCons; provides a special &consenv; called the +&DefEnv;. +The &defenv; is used only for global functions, that is, +construction activities called without the context of a regular &consenv;. +See &f-link-DefaultEnvironment; for more information. + By default, a new &consenv; is initialized with a set of builder methods and &consvars; that are appropriate for the current platform. -An optional platform keyword argument may be +The optional platform keyword argument may be used to specify that the &consenv; should be initialized for a different platform: env = Environment(platform='cygwin') -env = Environment(platform='os2') -env = Environment(platform='posix') -env = Environment(platform='win32') Specifying a platform initializes the appropriate @@ -2184,23 +2463,35 @@ and suffixes appropriate for that platform. Note that the -win32 +win32 platform adds the -SystemDrive +SystemDrive and -SystemRoot +SystemRoot variables from the user's external environment to the &consenv;'s -ENV +ENV dictionary. This is so that any executed commands that use sockets to connect with other systems -(such as fetching source files from -external CVS repository specifications like -:pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons) will work on Windows systems. -The platform argument may be a function or callable object, +The platform argument may be +a string value representing +one of the pre-defined platforms +(aix, +cygwin, +darwin, +hpux, +irix, +os2, +posix, +sunos or +win32), +or it may be be a callable platform object +returned by a call to &f-link-Platform; +selecting a pre-defined platform, +or it may be a user-supplied callable, in which case the &Environment; method will call it to update the new &consenv;: @@ -2212,37 +2503,63 @@ env = Environment(platform=my_platform) + +Note that supplying a non-default platform or custom +fuction for initialization +may bypass settings that should happen for the host system +and should be used with care. +It is most useful in the case where the platform is an alternative for +the one that would be auto-detected, +such as platform="cygwin" +on a system which would otherwise +identify as win32. + + + +The optional tools and toolpath +keyword arguments affect the way tools available to the environment are initialized. +See for details. + + + +The optional variables keyword argument +allows passing a Variables object which will be used in the +initialization of the &consenv; +See for details. + + Tools -&SCons; has a large number of predefined tools which -are used to help initialize the &consenv;, -and additional tools can be added. -An &scons; tool specification -is only responsible for setup. -For example, if the SConscript file declares +&SCons; has a large number of predefined tool modules +(more properly, tool specification modules) +which are used to help initialize the &consenv;. +An &SCons; tool is only responsible for setup. +For example, if an 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 -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.). +to set up that builder and all the &consvars; +it needs in the associated &consenv;; the tool itself +is not called in the process of the build. Normally this +happens invisibly as &scons; has per-platform +lists of default tools, and it steps through those tools, +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. 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 -tools. +tools, 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: @@ -2252,7 +2569,7 @@ -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). @@ -2267,140 +2584,23 @@ be used to retain the default list. -If no tools list is specified, -or the list includes 'default', -then &scons; will detect usable tools, -using the value of PATH -in the ENV &consvar; (not -the external PATH from os.environ) +If no tools argument is specified, +or if tools includes 'default', +then &scons; will auto-detect usable tools, +using the execution environment value of PATH +(that is, env['ENV']['PATH'] - +the external evironment &PATH; from os.environ +is not used) for looking up any backing programs, and the platform name in effect to determine the default tools for that platform. Changing the PATH variable after the &consenv; is constructed will not cause the tools to -be redetected. - -To help locate added tools, specify the -toolpath keyword argument: - - -env = Environment(tools=['default', 'foo'], toolpath=['tools']) - - - -This looks for a tool specification in tools/foo.py -as well as using the ordinary default tools for the platform. - - - -Tools in the toolpath are used in preference to -any of the built-in ones. For example, adding -a tool gcc.py to the toolpath -directory would override the built-in gcc tool. -The toolpath is -stored in the environment and will be -picked up by subsequent calls to the -&f-Clone; and &f-Tool; methods: - - - -base = Environment(toolpath=['custom_path']) -derived = base.Clone(tools=['custom_tool']) -derived.CustomBuilder() - +be re-detected. - -A tool specification must include two functions: - - - - - generate(env, **kwargs) - -Modifies the environment referenced by env -to set up variables so that the facilities represented by -the tool can be executed. -It may use any keyword arguments -that the user supplies in kwargs -to vary its initialization. - - - - exists(env) - -Return True if the tool can -be called. Usually this means looking up one or more -known programs using the PATH from the -supplied env, but the tool can -make the "exists" decision in any way it chooses. +Additional tools can be added, see the +Extending SCons section +and specifically Tool Modules. - - - - -The elements of the tools list may also -be functions or callable objects, -in which case the &Environment; method -will call those objects -to update the new &consenv; (see &f-link-Tool; for more details): - - -def my_tool(env): - env['XYZZY'] = 'xyzzy' - -env = Environment(tools=[my_tool]) - - -The individual elements of the tools list -may also themselves be lists or tuples of the form -(toolname, kw_dict). -SCons searches for the -toolname -specification file as described above, and -passes -kw_dict, -which must be a dictionary, as keyword arguments to the tool's -generate -function. -The -generate -function can use the arguments to modify the tool's behavior -by setting up the environment in different ways -or otherwise changing its initialization. - - -# in tools/my_tool.py: -def generate(env, **kwargs): - # Sets MY_TOOL to the value of keyword 'arg1' '1' if not supplied - env['MY_TOOL'] = kwargs.get('arg1', '1') - -def exists(env): - return True - -# in SConstruct: -env = Environment(tools=['default', ('my_tool', {'arg1': 'abc'})], - toolpath=['tools']) - - -The tool definition (my_tool in the example) -can use the -PLATFORM variable from -the &consenv; it is passed to customize the tool for different platforms. - -Tools can be "nested" - that is, they -can be located within a subdirectory in the toolpath. -A nested tool name uses a dot to represent a directory separator - - -# namespaced builder -env = Environment(ENV=os.environ, tools=['SubDir1.SubDir2.SomeTool']) -env.SomeTool(targets, sources) - -# Search Paths -# SCons\Tool\SubDir1\SubDir2\SomeTool.py -# SCons\Tool\SubDir1\SubDir2\SomeTool\__init__.py -# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool.py -# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool\__init__.py - SCons supports the following tool specifications out of the box: @@ -2429,55 +2629,73 @@ Builder Methods -You tell &scons; what to build -by calling Builders, functions which know to take a -particular action to produce a particular result type -when given source files of a particular type. &scons; -defines a number of builders, and you can also write your own. -Builders are attached to a &consenv; as methods, -and the available builder methods are listed as +You tell &SCons; what to build +by calling Builders, +functions which take particular action(s) +to produce target(s) of a particular type +(conventionally hinted at by the builder name, e.g. &Program;) +from the specified source files. +A builder call is a declaration: &SCons; enters the +specified relationship into its internal dependency node graph, +and only later makes the decision on whether anything is actually built, +since this depends on command-line options, +target selection rules, and whether the target(s) are +out of date with respect to the sources. + + + +&SCons; +provides a number of builders, and you can also write your own +(see Builder Objects). +Builders are created dynamically at run-time, +often (though not always) by tools which determine +whether the external dependencies for the builder are satisfied, +and which perform the necessary setup +(see Tools). +Builders are attached to a &consenv; as methods. +The available builder methods are registered as key-value pairs in the -BUILDERS attribute of the &consenv;. -The available builders can be displayed like this -for debugging purposes: +&cv-link-BUILDERS; attribute of the &consenv;, +so the available builders can be examined. +This example displays them for debugging purposes: +env = Environment() print("Builders:", list(env['BUILDERS'])) -Builder methods always take two arguments: -target -(a target or a list of targets to be built) +Builder methods take two required arguments: +target and -source -(a source or list of sources to be used as input -when building), -although in some circumstances, -the target argument can actually be omitted (see below). +source. +The target and +source arguments +can be specified either as positional arguments, +in which case target comes first, or as +keyword arguments, using target= +and source=. +Although both arguments are nominally required, +if there is a single source and the target can be inferred +the target argument can be omitted (see below). Builder methods also take a variety of keyword arguments, described below. Because long lists of file names -can lead to a lot of quoting, -&scons; +can lead to a lot of quoting in a builder call, +&SCons; supplies a &f-link-Split; global function and a same-named environment method that splits a single string into a list, using -strings of white-space characters as the delimiter. -(similar to the Python string split -method, but succeeds even if the input isn't a string.) +strings of white-space characters as the delimiter +(similar to the &Python; string split +method, but succeeds even if the input isn't a string). -The target and source arguments to a builder method -can be specified either as positional arguments, -in which case the target comes first, or as -keyword arguments, using target= -and source=. The following are equivalent examples of calling the &Program; builder method: @@ -2493,9 +2711,12 @@ -Python follows the POSIX pathname convention for path -strings: if a string begins with the operating system pathname separator -(on Windows both the slash and backslash separator work, +Sources and targets can be specified as a scalar or as a list, +composed of either strings or nodes (more on nodes below). +When specifying path strings, +&Python; follows the POSIX pathname convention: +if a string begins with the operating system pathname separator +(on Windows both the slash and backslash separator are accepted, and any leading drive specifier is ignored for the determination) it is considered an absolute path, otherwise it is a relative path. @@ -2504,30 +2725,26 @@ contains separator characters, the search follows down from the starting point, which is the top of the directory tree for an absolute path and the current directory for a relative path. +The "current directory" in this context is the directory +of the SConscript file currently being processed. + -&scons; recognizes a third way to specify +&SCons; also recognizes a third way to specify path strings: if the string begins with the # character it is top-relative - it works like a relative path but the search follows down from the directory containing the top-level &SConstruct; rather than -from the current directory. The # is allowed -to be followed by a pathname separator, which is ignored if -found in that position. +from the current directory. The # +can optionally be followed by a pathname separator, +which is ignored if found in that position. Top-relative paths only work in places where &scons; will interpret the path (see some examples below). To be used in other contexts the string will need to be converted to a relative or absolute path first. - -Target and source pathnames can be absolute, relative, or -top-relative. Relative pathnames are searched considering the -directory of the SConscript -file currently being processed as the "current directory". - - Examples: @@ -2582,14 +2799,12 @@ env.Program('bar.c') -As a convenience, a +The optional srcdir -keyword argument may be specified -when calling a Builder. -When specified, +keyword argument specifies that all source file strings that are not absolute paths or top-relative paths -will be interpreted relative to the specified +shall be interpreted relative to the specified srcdir. The following example will build the build/prog @@ -2606,12 +2821,107 @@ env.Program('build/prog', ['f1.c', 'f2.c'], srcdir='src') -It is possible to override (replace or add) -&consvars; when calling a -builder method by passing them as keyword arguments. +The optional +parse_flags +keyword argument causes behavior similar to the +&f-link-env-MergeFlags; method, where the argument value is +broken into individual settings and merged into the appropriate &consvars;. + + + +env.Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm') + + +This example adds 'include' to +the &cv-link-CPPPATH; &consvar;, +'EBUG' to +&cv-link-CPPDEFINES;, +and 'm' to +&cv-link-LIBS;. + + +The optional +chdir +keyword argument +specifies that the Builder's action(s) +should be executed +after changing directory. +If the +chdir +argument is +a path string or a directory Node, +scons will change to the specified directory. +If the +chdir +is not a string or Node +and evaluates true, +then &scons; will change to the +target file's directory. + + + +Python only keeps one current directory +location even if there are multiple threads. +This means that use of the +chdir +argument +will +not +work with the SCons + +option, +because individual worker threads spawned +by SCons interfere with each other +when they start changing directory. + + + +# scons will change to the "sub" subdirectory +# before executing the "cp" command. +env.Command( + target='sub/dir/foo.out', + source='sub/dir/foo.in', + action="cp dir/foo.in dir/foo.out", + chdir='sub', +) + +# Because chdir is not a string, scons will change to the +# target's directory ("sub/dir") before executing the +# "cp" command. +env.Command('sub/dir/foo.out', 'sub/dir/foo.in', "cp foo.in foo.out", chdir=True) + + +Note that &SCons; will +not +automatically modify +its expansion of +&consvars; like &cv-link-TARGET; +and &cv-link-SOURCE; +when using the chdir +keyword argument--that is, +the expanded file names +will still be relative to +the top-level directory where the &SConstruct; was found, +and consequently incorrect +relative to the chdir directory. +If you use the chdir keyword argument, +you will typically need to supply a different +command line using +expansions like +${TARGET.file} +and +${SOURCE.file} +to use just the filename portion of the +target and source. + +Keyword arguments that are not specifically +recognized are treated as &consvar; +overrides, +which replace or add those variables on a limited basis. These overrides -will only be in effect when building that target, and will not -affect other parts of the build. For example, if you want to specify +will only be in effect when building the target of the builder call, +and will not affect other parts of the build. +For example, if you want to specify some libraries needed by just one program: @@ -2621,95 +2931,108 @@ or generate a shared library with a non-standard suffix: -env.SharedLibrary('word', 'word.cpp', - SHLIBSUFFIX='.ocx', - LIBSUFFIXES=['.ocx']) +env.SharedLibrary( + target='word', + source='word.cpp', + SHLIBSUFFIX='.ocx', + LIBSUFFIXES=['.ocx'], +) Note that both the &cv-link-SHLIBSUFFIX; and &cv-link-LIBSUFFIXES; -variables must be set if you want &scons; to search automatically +&consvars; must be set if you want &scons; to search automatically for dependencies on the non-standard library names; -see the descriptions below of these variables for more information. - -It is also possible to use the -parse_flags -keyword argument in an override, -to merge command-line style arguments -into the appropriate &consvars; -(see &f-link-env-MergeFlags;). - - - -env = Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm') - - -This example adds 'include' to -CPPPATH, -'EBUG' to -CPPDEFINES, -and 'm' to -LIBS. +see the descriptions of these variables for more information. Although the builder methods defined by &scons; are, in fact, methods of a &consenv; object, -they may also be called without an explicit environment: +many may also be called without an explicit environment: Program('hello', 'hello.c') SharedLibrary('word', 'word.cpp') -In this case, -the methods are called internally using a default construction -environment that consists of the tools and values that +If called this way, the builder will internally use the +&DefEnv; that consists of the tools and values that &scons; has determined are appropriate for the local system. Builder methods that can be called without an explicit -environment may be called from custom Python modules that you +environment (indicated in the listing of builders below +without a leading env.) +may be called from custom &Python; modules that you import into an SConscript file by adding the following -to the Python module: +to the &Python; module: from SCons.Script import * -All builder methods return a list-like object -containing Nodes that will be built. -A Node -is an internal SCons object -which represents -build targets or sources. + +A builder may add additional targets +beyond those requested +if an attached Emitter chooses to do so +(see for more information. +&cv-link-PROGEMITTER; is an example). +For example, the GNU linker takes a command-line argument +, +which causes it to produce a linker map file in addition +to the executable file actually being linked. +If the &b-link-Program; builder's emitter is configured +to add this mapfile if the option is set, +then two targets will be returned when you only provided for one. + -The returned Node-list object + +For this reason, +builder methods always return a NodeList, +a list-like object whose elements are Nodes. +Nodes are the internal representation of build targets or sources +(see for more information). +The returned NodeList object can be passed to other builder methods as source(s) -or passed to any &SCons; function or method -where a filename would normally be accepted. -For example, if it were necessary +or to other &SCons; functions or methods +where a path string would normally be accepted. + + + For example, to add a specific preprocessor define -when compiling one specific object file: +when compiling one specific object file +but not the others: bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR') -env.Program(source=['foo.c', bar_obj_list, 'main.c']) +env.Program("prog", ['foo.c', bar_obj_list, 'main.c']) + + +Using a Node as in this example +makes for a more portable build +by avoiding having to specify +a platform-specific object suffix +when calling the &b-link-Program; builder method. + + +The NodeList object +is also convenient to pass to the &f-link-Default; function, +for the same reason of avoiding a platform-specific name: + + + +tgt = env.Program("prog", ["foo.c", "bar.c", "main.c"]) +Default(tgt) -Using a Node in this way -makes for a more portable build -by avoiding having to specify -a platform-specific object suffix -when calling the &Program; builder method. - Builder calls will automatically "flatten" lists passed as source and target, so they are free to contain elements which are themselves lists, such as bar_obj_list -returned by the &StaticObject; call above. +returned by the &b-link-StaticObject; call. If you need to manipulate a list of lists returned by builders -directly in Python code, +directly in &Python; code, you can either build a new list by hand: @@ -2721,7 +3044,7 @@ Or you can use the &f-link-Flatten; -function supplied by &scons; +function supplied by &SCons; to create a list containing just the Nodes, which may be more convenient: @@ -2733,20 +3056,20 @@ print(str(obj)) -&SCons; builder calls return -a list-like object, not an actual Python list, -so it is not appropriate to use the Python add +Since builder calls return +a list-like object, not an actual &Python; list, +it is not appropriate to use the &Python; add operator (+ or +=) -to append builder results to a Python list. +to append builder results to a &Python; list. Because the list and the object are different types, -Python will not update the original list in place, -but will instead create a new Node-list object +&Python; will not update the original list in place, +but will instead create a new NodeList object containing the concatenation of the list elements and the builder results. -This will cause problems for any other Python variables +This will cause problems for any other &Python; variables in your SCons configuration that still hold on to a reference to the original list. -Instead, use the Python list +Instead, use the &Python; list extend method to make sure the list is updated in-place. Example: @@ -2764,7 +3087,7 @@ The path name for a Node's file may be used -by passing the Node to Python's builtin +by passing the Node to &Python;'s builtin str function: @@ -2773,77 +3096,42 @@ print("The path to bar_obj is:", str(bar_obj_list[0])) -Note again that because the Builder call returns a list, -we have to access the first element in the list -((bar_obj_list[0])) +Note that because the Builder call returns a +NodeList, +you have to access the first element in the list +(bar_obj_list[0] in the example) to get at the Node that actually represents the object file. -Builder calls support a -chdir -keyword argument that -specifies that the Builder's action(s) -should be executed -after changing directory. -If the -chdir -argument is -a string or a directory Node, -scons will change to the specified directory. -If the -chdir -is not a string or Node -and is non-zero, -then scons will change to the -target file's directory. - - -# scons will change to the "sub" subdirectory -# before executing the "cp" command. -env.Command('sub/dir/foo.out', 'sub/dir/foo.in', - "cp dir/foo.in dir/foo.out", - chdir='sub') - -# Because chdir is not a string, scons will change to the -# target's directory ("sub/dir") before executing the -# "cp" command. -env.Command('sub/dir/foo.out', 'sub/dir/foo.in', - "cp foo.in foo.out", - chdir=1) - - -Note that &SCons; will -not -automatically modify -its expansion of -&consvars; like -$TARGET -and -$SOURCE -when using the chdir -keyword argument--that is, -the expanded file names -will still be relative to -the top-level directory where &SConstruct; was found, -and consequently incorrect -relative to the chdir directory. -If you use the chdir keyword argument, -you will typically need to supply a different -command line using -expansions like -${TARGET.file} -and -${SOURCE.file} -to use just the filename portion of the -targets and source. + +When trying to handle errors that may occur in a builder method, +consider that the corresponding Action is executed at a different +time than the SConscript file statement calling the builder. +It is not useful to wrap a builder call in a +try block, +since success in the builder call is not the same as +the builder itself succeeding. +If necessary, a Builder's Action should be coded to exit with +a useful exception message indicating the problem in the SConscript files - +programmatically recovering from build errors is rarely useful. + -&scons; -predefines the following builder methods. + +The following builder methods are predefined in the +&SCons; core software distribution. Depending on the setup of a particular &consenv; and on the type and software installation status of the underlying system, -not all builders may be available to that -&consenv;. +not all builders may be available in that +&consenv;. +Since the function calling signature is the same for all builders: + + +Buildername(target, source, [key=val, ...]) + + +it is omitted in this listing for brevity. + @@ -3024,7 +3312,7 @@ to affect how you want the build to be performed. - + &ARGLIST; A list of the @@ -3056,7 +3344,7 @@ - + &ARGUMENTS; A dictionary of all the @@ -3081,7 +3369,7 @@ - + &BUILD_TARGETS; A list of the targets which @@ -3127,7 +3415,7 @@ - + &COMMAND_LINE_TARGETS; A list of the targets explicitly specified on @@ -3150,7 +3438,7 @@ - + &DEFAULT_TARGETS; A list of the target @@ -3233,17 +3521,17 @@ A &consenv; has an associated dictionary of &consvars; that are used by built-in or user-supplied build rules. -&Consvar; naming must follow the same rules as for -Python identifiers: +&Consvar; naming must follow the same rules as +Python identifier naming: the initial character must be an underscore or letter, -followed by any number of underscores, letters, or digits. - -A &consenv; is not a Python dictionary, +followed by any number of underscores, letters, or digits. +A &consenv; is not a Python dictionary itself, but it can be indexed like one to access a &consvar;: env["CC"] = "cc" +flags = env.get("CPPDEFINES", []) &Consvars; can also be retrieved and set @@ -3270,14 +3558,38 @@ env2 = env.Clone(CC="cl.exe") + +&Consvars; can also be supplied as keyword +arguments to a builder, in which case those settings +affect only the work done by that builder call, +and not the &consenv; as a whole. +This concept is called an override: + + + +env.Program('hello', 'hello.c', LIBS=['gl', 'glut']) + + A number of useful &consvars; are automatically defined by -scons for each supported platform, and additional &consvars; -can be defined by the user. The following is a list of the possible -automatically defined &consvars;. The actual list available -at execution time will not include all of these, as the ones +scons for each supported platform, and you can modify these +or define any additional &consvars; for your own use, +taking care not to overwrite ones which &SCons; is using. +The following is a list of the possible +automatically defined &consvars;. + + +Note the actual list available +at execution time will never include all of these, as the ones detected as not being useful (wrong platform, necessary external command or files not installed, etc.) will not be set up. -: +Correct build setups should be resilient to the possible +absence of certain &consvars; before using them, +for example by using a &Python; dictionary +get method to retrieve the value and +taking alternative action if the return indicates the variable is unset. +The &f-link-env-Dump; method can be called to examine the +&consvars; set in a particular environment. + @@ -3414,7 +3726,6 @@ - SConf.Finish(context) context.Finish() This method must be called after configuration is done. @@ -3442,7 +3753,7 @@ Exit(1) if conf.CheckLibWithHeader("qt", "qapp.h", "c++", "QApplication qapp(0,0);"): # do stuff for qt - usage, e.g. - conf.env.Append(CPPFLAGS="-DWITH_QT") + conf.env.Append(CPPDEFINES="WITH_QT") env = conf.Finish() @@ -3460,7 +3771,6 @@ - SConf.CheckHeader(context, header, [include_quotes, language]) context.CheckHeader(header, [include_quotes, language]) Checks if @@ -3493,14 +3803,11 @@ - SConf.CheckCHeader(context, header, [include_quotes]) context.CheckCHeader(header, [include_quotes]) -This is a wrapper around -SConf.CheckHeader -which checks if +Checks if header -is usable in the C language. +is usable when compiling a C language program. header may be a list, in which case the last item in the list @@ -3516,19 +3823,18 @@ a two character string, where the first character denotes the opening quote and the second character denotes the closing quote. By default, both characters are " (double quote). +Note this is a wrapper around +CheckHeader. Returns a boolean indicating success or failure. - SConf.CheckCXXHeader(context, header, [include_quotes]) context.CheckCXXHeader(header, [include_quotes]) -This is a wrapper around -SConf.CheckHeader -which checks if +Checks if header -is usable in the C++ language. +is usable when compiling a C++ language program. header may be a list, in which case the last item in the list @@ -3544,19 +3850,19 @@ a two character string, where the first character denotes the opening quote and the second character denotes the closing quote. By default, both characters are " (double quote). +Note this is a wrapper around +CheckHeader. Returns a boolean indicating success or failure. - SConf.CheckFunc(context, function_name, [header, language]) context.CheckFunc(function_name, [header, language]) Checks if the specified C or C++ library function is available based on the context's local environment settings (that is, using -the values of CFLAGS, -CPPFLAGS, LIBS +the values of &cv-link-CFLAGS;, &cv-link-CPPFLAGS;, &cv-link-LIBS; or other relevant &consvars;). @@ -3588,7 +3894,6 @@ - SConf.CheckLib(context, [library, symbol, header, language, autoadd=True]) context.CheckLib([library, symbol, header, language, autoadd=True]) Checks if @@ -3614,7 +3919,7 @@ is not set or is None, then -SConf.CheckLib +CheckLib just checks if you can link against the specified library. @@ -3628,12 +3933,11 @@ - SConf.CheckLibWithHeader(context, library, header, language, [call, autoadd=True]) context.CheckLibWithHeader(library, header, language, [call, autoadd=True]) Provides a more sophisticated way to check against libraries then the -SConf.CheckLib call. +CheckLib call. library specifies the library or a list of libraries to check. header @@ -3663,7 +3967,6 @@ - SConf.CheckType(context, type_name, [includes, language]) context.CheckType(type_name, [includes, language]) Checks for the existence of a type defined by @@ -3690,116 +3993,139 @@ - SConf.CheckCC(context) + context.CheckTypeSize(type_name, [header, language, expect]) + +Checks for the size of a type defined by +typedef. +type_name +specifies the typedef name to check for. +The optional +header +argument is a string +that will be +placed at the top +of the test file +that will be compiled +to check if the type exists; +the default is empty. +If the optional +expect, +is supplied, it should be an integer size; +&CheckTypeSize; will fail unless +type_name is actually +that size. +Returns the size in bytes, or zero if the type was not found +(or if the size did not match expect). + + +For example, + + +CheckTypeSize('short', expect=2) + + +will return the size 2 only if short is +actually two bytes. + + + + context.CheckCC() -Checks whether the C compiler (as defined by the -CC &consvar;) works +Checks whether the C compiler +(as defined by the &cv-link-CC; &consvar;) works, by trying to compile a small source file. +This provides a more rigorous check: +by default, &SCons; itself only detects if there is a program +with the correct name, not if it is a functioning compiler. Returns a boolean indicating success or failure. -By default, SCons only detects if there is a program with the correct name, not -if it is a functioning compiler. - -This uses the exact same command as the one used by the object builder for C -source files, so it can be used to detect if a particular compiler flag works or -not. +The test program will be built with the +same command line as the one used by the &b-link-Object; builder +for C source files, so by setting relevant &consvars; +it can be used to detect if particular compiler flags will +be accepted or rejected by the compiler. + - SConf.CheckCXX(context) context.CheckCXX() -Checks whether the C++ compiler (as defined by the -CXX &consvar;) -works by trying to compile a small source file. By default, -SCons only detects if there is a program with the correct name, -not if it is a functioning compiler. +Checks whether the C++ compiler +(as defined by the &cv-link-CXX; &consvar;) works, +by trying to compile a small source file. +This provides a more rigorous check: +by default, &SCons; itself only detects if there is a program +with the correct name, not if it is a functioning compiler. Returns a boolean indicating success or failure. -This uses the exact same command as the one used by the object builder for -C++ source files, so it can be used to detect if a particular compiler flag -works or not. +The test program will be built with the +same command line as the one used by the &b-link-Object; builder +for C++ source files, so by setting relevant &consvars; +it can be used to detect if particular compiler flags will +be accepted or rejected by the compiler. + - SConf.CheckSHCC(context) context.CheckSHCC() Checks whether the shared-object C compiler (as defined by the -SHCC &consvar;) works -by trying to compile a small source file. By default, -SCons only detects if there is a program with the correct name, -not if it is a functioning compiler. +&cv-link-SHCC; &consvar;) works +by trying to compile a small source file. +This provides a more rigorous check: +by default, &SCons; itself only detects if there is a program +with the correct name, not if it is a functioning compiler. Returns a boolean indicating success or failure. -This uses the exact same command as the one used by the object builder for C -source file, so it can be used to detect if a particular compiler flag works or -not. This does not check whether the object code can be used to build a shared -library, only that the compilation (not link) succeeds. +The test program will be built with the +same command line as the one used by the &b-link-SharedObject; builder +for C source files, so by setting relevant &consvars; +it can be used to detect if particular compiler flags will +be accepted or rejected by the compiler. +Note this does not check whether a shared library/dll can +be created. + - SConf.CheckSHCXX(context) context.CheckSHCXX() Checks whether the shared-object C++ compiler (as defined by the -SHCXX &consvar;) -works by trying to compile a small source file. By default, -SCons only detects if there is a program with the correct name, -not if it is a functioning compiler. +&cv-link-SHCXX; &consvar;) +works by trying to compile a small source file. +This provides a more rigorous check: +by default, &SCons; itself only detects if there is a program +with the correct name, not if it is a functioning compiler. Returns a boolean indicating success or failure. -This uses the exact same command as the one used by the object builder for -C++ source files, so it can be used to detect if a particular compiler flag -works or not. This does not check whether the object code can be used to build -a shared library, only that the compilation (not link) succeeds. +The test program will be built with the +same command line as the one used by the &b-link-SharedObject; builder +for C++ source files, so by setting relevant &consvars; +it can be used to detect if particular compiler flags will +be accepted or rejected by the compiler. +Note this does not check whether a shared library/dll can +be created. + - SConf.CheckTypeSize(context, type_name, [header, language, expect]) - context.CheckTypeSize(type_name, [header, language, expect]) + context.CheckProg(prog_name) -Checks for the size of a type defined by -typedef. -type_name -specifies the typedef name to check for. -The optional -header -argument is a string -that will be -placed at the top -of the test file -that will be compiled -to check if the type exists; -the default is empty. -If the optional -expect, -is supplied, it should be an integer size; -&CheckTypeSize; will fail unless -type_name is actually -that size. -Returns the size in bytes, or zero if the type was not found -(or if the size did not match expect). - - -For example, - - -CheckTypeSize('short', expect=2) - - -will return the size 2 only if short is -actually two bytes. +Checks if +prog_name +exists in the path &SCons; will use at build time. +(context.env['ENV']['PATH']). +Returns a string containing the path to the program, +or None on failure. - SConf.CheckDeclaration(context, symbol, [includes, language]) context.CheckDeclaration(symbol, [includes, language]) Checks if the specified @@ -3814,21 +4140,54 @@ - - SConf.Define(context, symbol, [value, comment]) + + context.CheckMember(aggregate_member, + [header, language]) + + + Checks for the existence of a member of the C/C++ struct or class. + aggregate_member + specifies the struct/class and member to check for. + header + is a string containing one or more + #include + lines that will be inserted into the program + that will be run to test for the existence of the member. + Example: + + + +sconf.CheckMember('struct tm.tm_sec', '#include <time.h>') + + + + Returns a boolean indicating success or failure. + + + + + + + context.Define(symbol, [value, comment]) -This function does not check for anything, but defines a -preprocessor symbol that will be added to the configuration header file. -It is the equivalent of AC_DEFINE, -and defines the symbol -name -with the optional -value -and the optional comment -comment. +This method does not check for anything, but rather forces +the definition of a preprocessor macro that will be added +to the configuration header file. +name is the macro's identifier. +If value is given, +it will be be used as the macro replacement value. +If value is a string and needs to +display with quotes, the quotes need to be included, +as in '"string"' +If the optional +comment is given, +it is inserted as a comment above the macro definition +(suitable comment marks will be added automatically). +This is analogous to using AC_DEFINE in &Autoconf;. + -Define Examples: +Examples: env = Environment() @@ -3844,7 +4203,7 @@ -Be careful about quoting string values, though: +Examples of quoting string values: env = Environment() @@ -3860,7 +4219,7 @@ -For comment: +Example including comment: env = Environment() @@ -3877,127 +4236,122 @@ You can define your own custom checks -in addition to the predefined checks. -You pass a dictionary of these -to the &Configure; function -as the custom_tests argument. -This dictionary maps the names of the checks -to the user defined Python callables -(either Python functions or class instances implementing a -__call__ -method). -Each custom check will be called with a first -argument of a CheckContext, -instance followed by the arguments, +in addition to using the predefined checks. +To enable custom checks, +pass a dictionary to the &f-link-Configure; function +as the custom_tests parameter. +The dictionary maps the names of the checks +to the custom check callables +(either a Python function or an instance of a class implementing a +__call__ method). +Each custom check will be called with a +a CheckContext +instance as the first parameter followed by the remaining arguments, which must be supplied by the user of the check. -A CheckContext instance defines the following methods: +A CheckContext is not the same as +a configure context; rather it is an instance of a class +which contains a configure context +(available as chk_ctx.sconf). +A CheckContext +provides the following methods which custom checks +can make use of:: - context.Message(text) + chk_ctx.Message(text) -Displays a message, as an indicator of progess. -text -will be displayed, e.g. -Checking for library X.... +Displays text +as an indicator of progess. +For example: Checking for library X.... Usually called before the check is started. - context.Result(res) + chk_ctx.Result(res) -Displays a result message, as an indicator of progress. - -res -can be either an integer or a string. If an integer, displays -yes -(if res evaluates True) -or no -(if res evaluates False). -If a string, it is displayed as-is. +Displays a result message as an indicator of progress. +If res is an integer, +displays yes +if res evaluates true +or no if false. +If res is a string, +it is displayed as-is. Usually called after the check has completed. - context.TryCompile(text, extension='') + chk_ctx.TryCompile(text, extension='') -Checks if a file with the specified -extension -(e.g. '.c') containing -text -can be compiled using the environment's -&Object; builder. +Checks if a file containing text +and given the specified extension (e.g. +'.c') +can be compiled to an object file +using the environment's &b-link-Object; builder. Returns a boolean indicating success or failure. - context.TryLink(text, extension='') + chk_ctx.TryLink(text, extension='') -Checks, if a file with the specified -extension -(e.g. '.c') containing -text -can be compiled using the environment's &Program; builder. +Checks if a file containing text +and given the specified extension (e.g. +'.c') +can be compiled to an executable program +using the environment's &b-link-Program; builder. Returns a boolean indicating success or failure. - context.TryRun(text, extension='') + chk_ctx.TryRun(text, extension='') -Checks if a file with the specified -extension -(e.g. '.c') containing -text -can be compiled using the environment's -&Program; builder. On success, the program is run. If the program -executes successfully -(that is, its return status is 0), -a tuple -(1, outputStr) -is returned, where -outputStr -is the standard output of the -program. +Checks if a file containing text +and given the specified extension (e.g. +'.c') +can be compiled to an excutable program +using the environment's &b-link-Program; builder and subsequently executed. +Execution is only attempted if the build succeeds. +If the program executes successfully +(that is, its return status is 0), +a tuple (True, outputStr) +is returned, where outputStr +is the standard output of the program. If the program fails execution (its return status is non-zero), -then (0, '') is returned. +then (False, '') is returned. - context.TryAction(action, [text, extension='']) + chk_ctx.TryAction(action, [text, extension='']) Checks if the specified action -with an optional source file (contents -text, -extension -extension) +with an optional source file +(contents text, +given extension extension) can be executed. action -may be anything which can be converted to a -&scons; -Action. -On success, -(1, outputStr) -is returned, where -outputStr +may be anything which can be converted to an +Action Object. +On success, a tuple +(True, outputStr) +is returned, where outputStr is the content of the target file. On failure -(0, '') +(False, '') is returned. - context.TryBuild(builder[, text, extension='']) + chk_ctx.TryBuild(builder, [text, extension='']) Low level implementation for testing specific builds; the methods above are based on this method. @@ -4009,7 +4363,7 @@ extension, returns a boolean indicating success or failure. In addition, -context.lastTarget +chk_ctx.lastTarget is set to the build target node if the build was successful. @@ -4017,22 +4371,24 @@ Example of implementing and using custom tests: -def CheckQt(context, qtdir): - context.Message( 'Checking for qt ...' ) - lastLIBS = context.env['LIBS'] - lastLIBPATH = context.env['LIBPATH'] - lastCPPPATH= context.env['CPPPATH'] - context.env.Append(LIBS='qt', LIBPATH=qtdir + '/lib', CPPPATH=qtdir + '/include') - ret = context.TryLink(""" +def CheckQt(chk_ctx, qtdir): + chk_ctx.Message('Checking for qt ...') + lastLIBS = chk_ctx.env['LIBS'] + lastLIBPATH = chk_ctx.env['LIBPATH'] + lastCPPPATH = chk_ctx.env['CPPPATH'] + chk_ctx.env.Append(LIBS='qt', LIBPATH=qtdir + '/lib', CPPPATH=qtdir + '/include') + ret = chk_ctx.TryLink( + """\ #include <qapp.h> int main(int argc, char **argv) { QApplication qapp(argc, argv); return 0; } -""") +""" + ) if not ret: - context.env.Replace(LIBS=lastLIBS, LIBPATH=lastLIBPATH, CPPPATH=lastCPPPATH) - context.Result( ret ) + chkctx.env.Replace(LIBS=lastLIBS, LIBPATH=lastLIBPATH, CPPPATH=lastCPPPATH) + chkctx.Result(ret) return ret env = Environment() @@ -4055,24 +4411,24 @@ compiler. &SCons; provides a &Variables; -object to support overriding &consvars; -on the command line: +object to support overriding &consvars; with values obtained +from various sources, often from the command line: scons VARIABLE=foo -The variable values can also be specified in an SConscript file. +The variable values can also be specified in a configuration file or an SConscript file. To obtain the object for manipulating values, call the &Variables; function: - + Variables([files, [args]]) If files is a file or -list of files, those are executed as Python scripts, +list of files, they are executed as Python scripts, and the values of (global) Python variables set in those files are added as &consvars; in the &DefEnv;. If no files are specified, @@ -4080,7 +4436,14 @@ files argument is None, -then no files will be read. The following example file +then no files will be read +(supplying None is necessary +if there are no files but you want to specify +args as a positional argument). + + + +The following example file contents could be used to set an alternative C compiler: @@ -4092,10 +4455,14 @@ is specified, it is a dictionary of values that will override anything read from files. -it is primarily intended to be passed the +The primary use is to pass the &ARGUMENTS; dictionary that holds variables -specified on the command line. -Example: +specified on the command line, +allowing you to indicate that if a setting appears +on both the command line and in the file(s), +the command line setting takes precedence. +However, any dictionary can be passed. +Examples: vars = Variables('custom.py') @@ -4103,6 +4470,20 @@ vars = Variables(None, {FOO:'expansion', BAR:7}) + +Calling &Variables; with no arguments is equivalent to: + + +vars = Variables(files=None, args=ARGUMENTS) + + + +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 ). + + @@ -4110,36 +4491,59 @@ Variables objects have the following methods: - + vars.Add(key, [help, default, validator, converter]) Add a customizable &consvar; to the Variables object. key -is the name of the variable. +is either the name of the variable, +or a tuple (or list), in which case +the first item in the tuple is taken as the variable name, +and any remaining values are considered aliases for the variable. help -is the help text for the variable. +is the help text for the variable +(default empty string). default -is the default value of the variable; -if the default value is +is the default value of the variable +(default None). +If default is None -and there is no explicit value specified, +and a value is not specified, the &consvar; will not be added to the &consenv;. -If set, validator -is called to validate the value of the variable. -A function supplied as a validator shall accept -arguments: key, -value, and env. -The recommended way to handle an invalid value is -to raise an exception (see example below). -If set, converter -is called to convert the value before putting it in the environment, and -should take either a value, or the value and environment, as parameters. + + +As a special case, if key +is a tuple (or list) and is the only +argument, the tuple is unpacked into the five parameters +listed above left to right, with any missing members filled with +the respecitive default values. This form allows Add +to consume a tuple emitted by the convenience functions +BoolVariable, +EnumVariable, +ListVariable, +PackageVariable +and +PathVariable. + + +If the optional validator is supplied, +it is called to validate the value of the variable. +A function supplied as a validator must accept +three arguments: key, +value and env, +and should raise an exception with a helpful error message +if value is invalid. +No return value is expected from the validator. + + +If the optional converter is supplied, +it is called to convert the value before putting it in the environment, +and should take either a value +or a value and environment as parameters. The converter function must return a value, -which will be converted into a string -before being validated by the -validator -(if any) +which will be converted into a string and be passed to the +validator (if any) and then added to the &consenv;. Examples: @@ -4156,11 +4560,11 @@ - + vars.AddVariables(args) A convenience method that adds -multiple customizable &consvars; +one or more customizable &consvars; to a Variables object in one call; equivalent to calling &Add; multiple times. The args @@ -4169,10 +4573,10 @@ for an individual call to the &Add; method. Since tuples are not Python mappings, the arguments cannot use the keyword form, -but rather are positional arguments as documented -for &Add;: a required name, the rest optional -but must be in the specified in order if used. - +but rather are positional arguments as documented for +Add: +a required name, the other four optional, +but must be in the specified order if used. @@ -4186,18 +4590,18 @@ - + vars.Update(env, [args]) Update a &consenv; env -with the customized &consvars; . +with the customized &consvars;. Any specified variables that are not configured for the Variables object will be saved and may be retrieved using the -&UnknownVariables; -method, below. +&UnknownVariables; +method. Normally this method is not called directly, but rather invoked indirectly by passing the Variables object to @@ -4210,7 +4614,7 @@ - + vars.UnknownVariables() Returns a dictionary containing any @@ -4229,14 +4633,17 @@ - + vars.Save(filename, env) Save the currently set variables into a script file named -by filename -that can be used on the next invocation to automatically load the current -settings. This method combined with the Variables method can be used to -support caching of variables between runs. +by filename. Only variables that are +set to non-default values are saved. +You can load these saved settings on a subsequent run +by passing filename to the +&Variables; function, +providing a way to cache particular settings for reuse. + env = Environment() @@ -4249,7 +4656,7 @@ - + vars.GenerateHelpText(env, [sort]) Generate help text documenting the customizable construction @@ -4281,7 +4688,7 @@ - + vars.FormatVariableHelpText(env, opt, help, default, actual) Returns a formatted string @@ -4303,6 +4710,7 @@ def my_format(env, opt, help, default, actual): fmt = "\n%s: default=%s actual=%s (%s)\n" return fmt % (opt, default, actual, help) + vars.FormatVariableHelpText = my_format @@ -4319,7 +4727,7 @@ the &Add; or &AddVariables; method: - + BoolVariable(key, help, default) Returns a tuple of arguments @@ -4354,7 +4762,7 @@ - + EnumVariable(key, help, default, allowed_values, [map, ignorecase]) Returns a tuple of arguments @@ -4403,7 +4811,7 @@ - + ListVariable(key, help, default, names, [map]) Returns a tuple of arguments @@ -4442,7 +4850,7 @@ - + PackageVariable(key, help, default) Returns a tuple of arguments @@ -4482,7 +4890,7 @@ - + PathVariable(key, help, default, [validator]) Returns a tuple of arguments @@ -4611,21 +5019,52 @@ - -File and Directory Nodes + +Node Objects + + +&SCons; represents objects that are the sources or targets of +build operations as Nodes, +which are internal data structures. +There are a number of user-visible types of nodes: +File Nodes, Directory Nodes, Value Nodes and Alias Nodes. +Some of the node types have public attributes and methods, +described below. Each of the node types has a global function +and a matching environment method to create instances: +&f-link-File;, &f-link-Dir;, &f-link-Value; and &f-link-Alias;. + + + +Filesystem Nodes The &f-link-File; and &f-link-Dir; functions/methods return File and Directory Nodes, respectively. -Such nodes are Python objects with -several user-visible attributes -and methods that are often useful to access -in SConscript files: +File and Directory Nodes +(collectively, Filesystem Nodes) +represent build components that correspond to an entry +in the computer's filesystem, +whether or not such an entry exists at the time the Node is created. +You do not usually need to explicitly create filesystem Nodes, +since when you supply a string as a target or source of a Builder, +&SCons; will create the Nodes as needed to populate the +dependency graph. +Builders return the target Node(s) in the form of a list, +which you can then make use of. +However, since filesystem Nodes have some useful +public attributes and methods +that you can use in SConscript files, +it is sometimes appropriate to create them manually, +outside the regular context of a Builder call. + + +The following attributes provide information about a Node: + - n.path + node.path The build path of the given @@ -4639,14 +5078,21 @@ - n.abspath + node.abspath The absolute build path of the given file or directory. - n.srcnode() + node.relpath + +The build path of the given file or directory relative to the root SConstruct file's directory. + + + + + node.srcnode() The srcnode @@ -4659,99 +5105,116 @@ -For example: +Examples: # Get the current build dir's path, relative to top. Dir('.').path + # Current dir's absolute path Dir('.').abspath + +# Current dir's path relative to the root SConstruct file's directory +Dir('.').relpath + # Next line is always '.', because it is the top dir's path relative to itself. Dir('#.').path -File('foo.c').srcnode().path # source path of the given source file. -# Builders also return File objects: +# Source path of the given source file. +File('foo.c').srcnode().path + +# Builders return lists of File objects: foo = env.Program('foo.c') -print("foo will be built in", foo.path) +print("foo will be built in", foo[0].path) -File and Directory Node objects have methods to create +Filesystem Node objects have methods to create new File and Directory Nodes relative to the original Node. +There are also times when you may need to refer to an entry +in a filesystem without knowing in advance whether it's a +file or a directory. +For those situations, +there is an Entry method of filesystem node objects, +which returns a Node that can represent either a file or a directory. -If the object is a Directory Node, -these methods will place the the new Node within the directory -the Node represents: +If the original Node is a Directory Node, +these methods will place the new Node within the directory +the original Node represents: - d.Dir(name) + node.Dir(name) -Returns a directory Node for a subdirectory of -d -named -name. +Returns a directory Node +name +which is a subdirectory of +the directory represented by +node. - d.File(name) + node.File(name) -Returns a file Node for a file within -d -named -name. +Returns a file Node +name +in the directory represented by +node. - d.Entry(name) + node.Entry(name) -Returns an unresolved Node within -d -named -name. +Returns an unresolved Node +name +in the directory represented by +node. -If the object is a File Node, +If the original Node is a File Node, these methods will place the the new Node in the same -directory as the one the Node represents: +directory as the one the original Node represents: - f.Dir(name) + node.Dir(name) -Returns a directory named +Returns a Node name -within the parent directory of -f. +for a directory in the parent directory of +the file represented by +node. - f.File(name) + node.File(name) -Returns a file named +Returns a Node name -within the parent directory of -f. +for a file in the parent directory of +the file represented by +node. - f.Entry(name) + node.Entry(name) -Returns an unresolved Node named +Returns an unresolved Node name -within the parent directory of -f. +in the parent directory of +the file represented by +node. @@ -4777,6 +5240,56 @@ index = html.File('index.html') css = index.File('app.css') + + + +Value and Alias Nodes + + +&SCons; provides two other Node types to represent +object that will not have an equivalent filesystem entry. +Such Nodes always need to be created explicitly. + + + +The &f-link-Alias; method returns an Alias Node. +Aliases are virtual objects - they will not themselves result +in physical objects being constructed, but are entered into +the dependency graph related to their sources. +An alias is checked for up to date by checking if +its sources are up to date. +An alias is built by making sure its sources have been built, +and if any building took place, +applying any Actions that are defined as part of the alias. + + + +An &f-link-Alias; call creates an entry in the alias namespace, +which is used for disambiguation. +If an alias source has a string valued name, +it will be resolved to a filesystem entry Node, +unless it is found in the alias namespace, +in which case it it resolved to the matching alias Node. +As a result, the order of &f-Alias; calls is significant. +An alias can refer to another alias, but only if the +other alias has previously been created. + + + +The &f-link-Value; method returns a Value Node. +Value nodes are often used for generated data that +will not have any corresponding filesystem entry, +but will be used to determine whether a build target is out of date, +or to include as part of a build Action. +Common examples are timestamp strings, +revision control version strings +and other run-time generated strings. + + + +A Value Node can also be the target of a builder. + + @@ -4784,6 +5297,31 @@ EXTENDING SCONS + +&SCons; is designed to be extensible through provided facilities, +so changing the code of &SCons; itself is only rarely needed +to customize its behavior. +A number of the main operations use callable objects +which can be supplemented by writing your own. +Builders, Scanners and Tools each use a kind of plugin system, +allowing you to easily drop in new ones. +Information about creating +Builder Objects and +Scanner Objects +appear in the following sections. +The instructions &SCons; actually uses to +construct things are called Actions, +and it is easy to create Action Objects and hand them +to the objects that need to know about those actions +(besides Builders, see &f-link-AddPostAction;, +&f-link-AddPreAction; and &f-link-Alias; for some examples +of other places that take Actions). +Action Objects +are also described below. +Adding new Tool modules is described in +Tool Modules + + Builder Objects @@ -4794,21 +5332,30 @@ In general, you should only need to add a new Builder object when you want to build a new type of file or other external target. -If you just want to invoke a different compiler or other tool -to build &Program;, &Object;, &Library;, or any other -type of output file for which -&scons; -already has an existing Builder, -it is generally much easier to -use those existing Builders -in a &consenv; -that sets the appropriate &consvars; -(CC, LINK, etc.). +For output file types &scons; already knows about, +you can usually modify the behavior of premade Builders +such as &b-link-Program;, &b-link-Object; or &b-link-Library; +by changing the &consvars; they use +(&cv-link-CC;, &cv-link-LINK;, etc.). +In this manner you can, for example, change the compiler to use, +which is simpler and less error-prone than writing a new builder. +The documentation for each Builder lists which +&consvars; it uses. + Builder objects are created using the &f-link-Builder; factory function. +Once created, a builder is added to an environment +by entering it in the &cv-link-BUILDERS; dictionary +in that environment (some of the examples +in this section illustrate this). +Doing so automatically triggers &SCons; to add a method +with the name of the builder to the environment. + + + The &f-Builder; function accepts the following keyword arguments: @@ -4817,33 +5364,33 @@ action -The command line string used to build the target from the source. +The command used to build the target from the source. action -can also be: +may be a string representing a template command line to execute, a list of strings representing the command -to be executed and its arguments +to execute with its arguments (suitable for enclosing white space in an argument), a dictionary mapping source file name suffixes to any combination of command line strings (if the builder should accept multiple source file extensions), -a Python function; +a Python function, an Action object -(see the next section); +(see Action Objects) or a list of any of the above. -An action function takes three arguments: - - - source - a list of source nodes;. - target - a list of target nodes;. - env - the &consenv;. - +An action function must accept three arguments: +source, +target and +env. +source is a list of source nodes; +target is a list of target nodes; +env is the &consenv; to use for context. + -The -action -and -generator + +The action +and generator arguments must not both be used for the same Builder. @@ -4851,37 +5398,31 @@ prefix -The prefix that will be prepended to the target file name. -prefix may be: - - - a string - a callable object - -a function or other callable that takes +The prefix to prepend to the target file name. +prefix may be +a string, a function (or other callable) that takes two arguments (a &consenv; and a list of sources) -and returns a prefix - a dictionary - -specifies a mapping from a specific source suffix (of the first -source specified) to a corresponding target prefix. Both the source -suffix and target prefix specifications may use environment variable -substitution, and the target prefix (the 'value' entries in the -dictionary) may also be a callable object. The default target prefix -may be indicated by a dictionary entry with a key value of None. - - +and returns a prefix string, +or a dictionary specifying a mapping from a specific source suffix +(of the first source specified) +to a corresponding target prefix string. For the dictionary form, both the source +suffix (key) and target prefix (value) specifications may use environment variable +substitution, and the target prefix +may also be a callable object. The default target prefix +may be indicated by a dictionary entry with a key of None. b = Builder("build_it < $SOURCE > $TARGET", - prefix = "file-") + prefix="file-") def gen_prefix(env, sources): return "file-" + env['PLATFORM'] + '-' + b = Builder("build_it < $SOURCE > $TARGET", - prefix = gen_prefix) + prefix=gen_prefix) b = Builder("build_it < $SOURCE > $TARGET", - suffix = { None: "file-", - "$SRC_SFX_A": gen_prefix }) + suffix={None: "file-", "$SRC_SFX_A": gen_prefix}) @@ -4889,27 +5430,27 @@ suffix -The suffix that will be appended to the target file name. -This may be specified in the same manner as the prefix above. +The suffix to append to the target file name. +Specified in the same manner as for prefix above. If the suffix is a string, then &scons; -will append a '.' to the beginning of the suffix if it's not already -there. The string returned by callable object (or obtained from the -dictionary) is untouched and must append its own '.' to the beginning -if one is desired. +prepends a '.' to the suffix if it's not already there. +The string returned by the callable object or obtained from the +dictionary is untouched and you need to manually prepend a '.' +if one is required. b = Builder("build_it < $SOURCE > $TARGET" - suffix = "-file") + suffix="-file") def gen_suffix(env, sources): return "." + env['PLATFORM'] + "-file" + b = Builder("build_it < $SOURCE > $TARGET", - suffix = gen_suffix) + suffix=gen_suffix) b = Builder("build_it < $SOURCE > $TARGET", - suffix = { None: ".sfx1", - "$SRC_SFX_A": gen_suffix }) + suffix={None: ".sfx1", "$SRC_SFX_A": gen_suffix}) @@ -4917,21 +5458,21 @@ ensure_suffix -When set to any true value, causes -&scons; -to add the target suffix specified by the -suffix -keyword to any target strings -that have a different suffix. -(The default behavior is to leave untouched -any target file name that looks like it already has any suffix.) +If set to a true value, +ensures that targets will end in +suffix. +Thus, the suffix will also be added to any target strings +that have a suffix that is not already suffix. +The default behavior (also indicated by a false value) +is to leave unchanged +any target string that looks like it already has a suffix. b1 = Builder("build_it < $SOURCE > $TARGET" suffix = ".out") b2 = Builder("build_it < $SOURCE > $TARGET" suffix = ".out", - ensure_suffix) + ensure_suffix=True) env = Environment() env['BUILDERS']['B1'] = b1 env['BUILDERS']['B2'] = b2 @@ -4949,8 +5490,9 @@ src_suffix -The expected source file name suffix. This may be a string or a list -of strings. +The expected source file name suffix. +src_suffix +may be a string or a list of strings. @@ -5062,7 +5604,7 @@ - + emitter A function or list of functions to manipulate the target and source @@ -5077,13 +5619,15 @@ is used to select the actual emitter function from an emitter dictionary.) -An emitter function takes three arguments: - - - source - a list of source nodes. - target - a list of target nodes. - env - the &consenv;. - +A function passed as emitter +must accept three arguments: +source, +target and +env. +source is a list of source nodes, +target is a list of target nodes, +env is the &consenv; to use for context. + An emitter must return a tuple containing two lists, the list of targets to be built by this builder, @@ -5093,38 +5637,37 @@ def e(target, source, env): - return (target + ['foo.foo'], source + ['foo.src']) + return target + ['foo.foo'], source + ['foo.src'] # Simple association of an emitter function with a Builder. -b = Builder("my_build < $TARGET > $SOURCE", - emitter = e) +b = Builder("my_build < $TARGET > $SOURCE", emitter=e) def e2(target, source, env): - return (target + ['bar.foo'], source + ['bar.src']) + return target + ['bar.foo'], source + ['bar.src'] # Simple association of a list of emitter functions with a Builder. -b = Builder("my_build < $TARGET > $SOURCE", - emitter = [e, e2]) +b = Builder("my_build < $TARGET > $SOURCE", emitter=[e, e2]) -# Calling an emitter function through a &consvar;. +# Calling an emitter function through a construction variable. env = Environment(MY_EMITTER=e) -b = Builder("my_build < $TARGET > $SOURCE", - emitter='$MY_EMITTER') +b = Builder("my_build < $TARGET > $SOURCE", emitter='$MY_EMITTER') -# Calling a list of emitter functions through a &consvar;. +# Calling a list of emitter functions through a construction variable. env = Environment(EMITTER_LIST=[e, e2]) -b = Builder("my_build < $TARGET > $SOURCE", - emitter='$EMITTER_LIST') +b = Builder("my_build < $TARGET > $SOURCE", emitter='$EMITTER_LIST') # Associating multiple emitters with different file # suffixes using a dictionary. def e_suf1(target, source, env): - return (target + ['another_target_file'], source) + return target + ['another_target_file'], source + def e_suf2(target, source, env): - return (target, source + ['another_source_file']) -b = Builder("my_build < $TARGET > $SOURCE", - emitter={'.suf1' : e_suf1, - '.suf2' : e_suf2}) + return target, source + ['another_source_file'] + +b = Builder( + action="my_build < $TARGET > $SOURCE", + emitter={'.suf1': e_suf1, '.suf2': e_suf2} +) @@ -5133,7 +5676,7 @@ multi Specifies whether this builder is allowed to be called multiple times for -the same target file(s). The default is 0, +the same target file(s). The default is False, which means the builder can not be called multiple times for the same target file(s). Calling a builder multiple times for the same target simply adds additional source @@ -5157,7 +5700,7 @@ - + generator A function that returns a list of actions that will be executed to build @@ -5167,18 +5710,24 @@ can be converted into an Action object (see the next section). -The generator function takes four arguments: - - - source - A list of source nodes;. - target - A list of target nodes;. - env - the &consenv;. - for_signature - - A Boolean value that specifies - whether the generator is being called - for generating a build signature - (as opposed to actually executing the command). - +A function passed as generator +must accept four arguments: +source, +target, +env and +for_signature. +source is a list of source nodes, +target is a list of target nodes, +env is the &consenv; to use for context, +and for_signature is +a Boolean value that tells the function +if it is being called for the purpose of generating a &buildsig; +(as opposed to actually executing the command). +Since the &buildsig; is used for rebuild determination, +the function should omit those elements +that do not affect whether a rebuild should be triggered +if for_signature is true. + Example: @@ -5232,12 +5781,9 @@ this check can be suppressed by setting source_ext_match to -None +False or some other non-true value. -When -source_ext_match -is disable, -&scons; +In this case, &scons; will use the suffix of the first specified source file to select the appropriate action from the action @@ -5256,7 +5802,7 @@ b = Builder(action={'.in' : 'build $SOURCES > $TARGET'}, - source_ext_match = None) + source_ext_match=False) env = Environment(BUILDERS={'MyBuild':b}) env.MyBuild('foo.out', ['foo.in', 'foo.extra']) @@ -5364,18 +5910,19 @@ to set a &consvar; to the repository of a source code system. -Any additional keyword arguments supplied +Any such keyword arguments supplied when a Builder object is called will only be associated with the target created by that particular &f-Builder; call (and any other files built as a -result of the call). - -These extra keyword arguments are passed to the +result of the call). +These extra keyword arguments are passed to the following functions: -command generator functions, -function Actions, -and emitter functions. +command generator functions, +function Actions, +and +emitter functions. + @@ -5384,44 +5931,47 @@ The &f-link-Builder; -function will turn its +factory function will turn its action 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. +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;. + The &Action; factory function returns an appropriate object for the action -represented by the type of the action argument -(the first positional parmeter): +represented by the type of the +action argument +(the first positional parameter): -If the action argument is already an Action object, +If action is already an Action object, the object is simply returned. -If the action argument is a string, +If action is a string, a command-line Action is returned. -If such a string begins with -@, -it indicates printing of the command line is to be suppressed. -If the string begins with -- (hyphen), -it indicates the exit status from the specified command -is to be ignored, allowing execution to continue +If such a string begins with @, +the command line is not printed. +If the string begins with hyphen +(-), +the exit status from the specified command +is ignored, allowing execution to continue even if the command reports failure: @@ -5436,14 +5986,13 @@ -If the action argument is a list, +If action is a list, then a list of Action objects is returned. An Action object is created as necessary for each element in the list. -If an element -within +If an element within the list is itself a list, -the internal list is taken as the +the embedded list is taken as the command and arguments to be executed via the command line. This allows white space to be enclosed @@ -5456,18 +6005,19 @@ -If the action argument is a Python function, -a function Action is returned. -The Python function must accept three keyword arguments: - - - target - - a Node object representing the target file. - source - - a Node object representing the source file. - env - - the &consenv; used for building the target file. - +If action is a callable object, +a Function Action is returned. +The callable must accept three keyword arguments: +target, +source and +env. +target +is a Node object representing the target file, +source +is a Node object representing the source file and +env +is the &consenv; used for building the target file. + The @@ -5504,69 +6054,82 @@ -If the action argument is not one of the above types, -None is returned. +If +action +is not one of the above types, +no action object is generated and &f-Action; +returns None. -As usual the environment method form &f-link-env-Action; -will expand &consvars; in any argument strings, -including the action argument, at the time it is called, +The environment method form &f-link-env-Action; +will expand &consvars; in any argument strings, +including +action, +at the time it is called, using the construction variables in the &consenv; through which it was called. The global function form &f-link-Action; -delays variable expansion until +delays variable expansion until the Action object is actually used. -The second argument to &f-Action; -is optional and is used to define the output +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: +The following argument types are accepted: + -If the output argument is a function, -it must return a string -describing the action being executed. -A function may also be specified using the -strfunction -keyword argument. The function -must accept these three keyword arguments: - - - source - - a Node object representing the source file. - target - - a Node object representing the target file. - env - the &consenv;. - +If the second argument is a string, +or if the cmdstr keyword argument is supplied, +the string defines what is printed. +Substitution is performed on the string before it is printed. +The string typically contains substitutable variables, notably +$TARGET(S) and $SOURCE(S), +or consists of just a single variable +which is optionally defined somewhere else. +&SCons; itself heavily uses the latter variant. + -The -target -and -source -arguments may be lists of Node objects if there is -more than one target file or source file. + +If the second argument is a function, +or if the strfunction keyword argument is supplied, +the function will be called to obtain the string +to be printed when the action is performed. +The function +must accept three keyword arguments: +target, +source and +env, +with the same interpretation as for a callable +action argument above. +The function is responsible for handling any required substitutions. + -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 -cmdstr -keyword argument. -The string typically contains variables, notably -$TARGET(S) and $SOURCE(S), -or consists of just a single -variable, which is optionally defined somewhere else. -SCons itself heavily uses the latter variant. +If the second argument is None, +or if cmdstr=None is supplied, +output is suppressed entirely. + +The cmdstr and +strfunction +keyword arguments may not both be supplied in a single call to &f-Action; + + + +Printing of action strings is affected by the setting of +&cv-link-PRINT_CMD_LINE_FUNC;. + + Examples: @@ -5592,6 +6155,7 @@ Any additional positional arguments, if present, may either be &consvars; or lists of &consvars; whose values will be included in the signature of the Action +(the &buildsig;) when deciding whether a target should be rebuilt because the action changed. Such variables may also be specified using the varlist @@ -5630,30 +6194,25 @@ chdir -Specifies that -scons will execute the action -after changing to the specified directory. -If the -chdir -argument is -a string or a directory Node, -scons will change to the specified directory. -If the -chdir -argument -is not a string or Node -and is non-zero, -then scons will change to the +If chdir is true +(the default is False), +&SCons; will change directories before +executing the action. +If the value of chdir +is a string or a directory Node, +&SCons; will change to the specified directory. +Otherwise, if chdir evaluates true, +&SCons; will change to the target file's directory. -Note that scons will +Note that &SCons; will not automatically modify its expansion of &consvars; like &cv-TARGET; and &cv-SOURCE; when using the chdir -keyword argument--that is, +parameter - that is, the expanded file names will still be relative to the top-level directory containing the &SConstruct; file, @@ -5669,8 +6228,7 @@ targets and source. Example: -a = Action("build < ${SOURCE.file} > ${TARGET.file}", - chdir=1) +a = Action("build < ${SOURCE.file} > ${TARGET.file}", chdir=True) @@ -5678,11 +6236,10 @@ exitstatfunc -A function -that is passed the exit status -(or return value) -from the specified action -and can return an arbitrary +If provided, must be a callable which accepts a single parameter, +the exit status (or return value) +from the specified action, +and which returns an arbitrary or modified value. This can be used, for example, to specify that an Action object's @@ -5705,7 +6262,7 @@ batch_key -Specifies that the Action can create multiple target files +If provided, indicates that the Action can create multiple target files by processing multiple independent source files simultaneously. (The canonical example is "batch compilation" of multiple object files @@ -5742,33 +6299,33 @@ for batch building. A batch_key -function must accept the following arguments: - - - action - The action object. - env - - The &consenv; configured for the target. - target - - The list of targets for a particular configured action. - source - - The list of source for a particular configured action. - +function must accept four parameters: +action, +env, +target and +source. +The first parameter, action, +is the active action object. +The second parameter, env, +is the &consenv; configured for the target. +The target and source +parameters are the lists of targets and sources +for the configured action. + The returned key should typically be a tuple of values derived from the arguments, using any appropriate logic to decide how multiple invocations should be batched. For example, a -batch_key +batch_key function may decide to return -the value of a specific construction -variable from the -env -argument +the value of a specific &consvar; +from env which will cause &scons; to batch-build targets -with matching values of that variable, +with matching values of that &consvar;, or perhaps return the Python id() of the entire &consenv;, @@ -5800,13 +6357,12 @@ - - + Miscellaneous Action Functions -&scons; -supplies a number of functions +&SCons; +supplies Action functions that arrange for various common file and directory manipulations to be performed. @@ -5821,8 +6377,8 @@ that can be executed at the appropriate time. -In practice, -there are two natural ways + +There are two natural ways that these Action Functions are intended to be used. @@ -5834,7 +6390,7 @@ file is being read, you can use the &f-link-Execute; -global function to do so: +global function: Execute(Touch('file')) @@ -5892,6 +6448,12 @@ Chmod('$TARGET', "ugo+w")]) + +The behavior of Chmod is limited on Windows, +see the notes in the Python documentation for +os.chmod, which is the underlying function. + + @@ -5954,12 +6516,14 @@ - Mkdir(dir) + Mkdir(name) Returns an Action -that creates the specified -directory -dir. +that creates the directory +name +and all needed intermediate directories. +name may also be a list +of directories to create. Examples: @@ -6023,21 +6587,205 @@ - + - + Variable Substitution -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 -string with a leading -$, to distinguish them from plain text -which is not to be substituted. + +Before executing a command, &scons; +performs parameter expansion (substitution) +on the string that makes up the action part of the builder. +The format of a substitutable parameter is +${expression}. +If expression refers to a variable, +the braces in ${expression} +can be omitted unless the variable name is +immediately followed by a character that could either be interpreted +as part of the name, or is &Python; syntax such as +[ (for indexing/slicing) +or . (for attribute access - +see Special Attributes below). + + + +If expression refers to a &consvar;, +it is replaced with the value of that variable in the +&consenv; at the time of execution. +If expression looks like +a variable name but is not defined in the &consenv; +it is replaced with an empty string. +If expression refers to one of the +Special Variables +(see below) the corresponding value of the variable is substituted. +expression may also be +a &Python; expression to be evaluated. +See Python Code Substitution +below for a description. + + +&SCons; uses the following rules when converting &consvars; into +command line strings: + + + + If the value is a string it is interpreted as space delimited + command line arguments. + + + + If the value is a list it is interpreted as a list of command + line arguments. Each element of the list is converted to a string. + + + + Anything that is not a list or string is converted to a string and + interpreted as a single command line argument. + + + + Newline characters (\n) delimit lines. + The newline parsing is done after + all other parsing, so it is not possible for arguments (e.g. file names) to + contain embedded newline characters. + + + + For a literal $ + use $$. + For example, $$FOO will be left in the + final string as $FOO. + + + + +When a build action is executed, a hash of the command line is +saved, together with other information about the target(s) built +by the action, for future use in rebuild determination. +This is called the &buildsig; +(or &build_action; signature). +The escape sequence +$( +subexpression +$) +may be used to indicate parts of a command line +that may change without +causing a rebuild--that is, +which are not to be included when calculating the &buildsig;. +All text from +$( +up to and including the matching +$) +will be removed from the command line +before it is added to the &buildsig; +while only the +$( +and +$) +will be removed before the command is executed. +For example, the command line string: + + +"echo Last build occurred $( $TODAY $). > $TARGET" + + +would execute the command: + + +echo Last build occurred $TODAY. > $TARGET + + +but the build signature added to any target files would be computed from: + + +echo Last build occurred . > $TARGET + + +While &consvars; are normally directly substituted, +if a &consvar; has a value which +is a callable &Python; object +(a function, or a class with a __call__ method), +that object is called during substitution. +The callable must accept four arguments: +target, +source, +env and +for_signature. +source is a list of source nodes, +target is a list of target nodes, +env is the &consenv; to use for context, +and for_signature is +a boolean value that tells the callable +if it is being called for the purpose of generating a build signature. +Since the build signature is used for rebuild determination, +variable elements that do not affect whether +a rebuild should be triggered +should be omitted from the returned string +if for_signature is true. +See $( +and $) above +for the syntax. + + + +&SCons; will insert whatever +the callable returns +into the expanded string: + + + +def foo(target, source, env, for_signature): + return "bar" + +# Will expand $BAR to "bar baz" +env = Environment(FOO=foo, BAR="$FOO baz") + + +As a reminder, substitution happens when +$BAR is actually used in a +builder action. The value of env['BAR'] +will be exactly as it was set: "$FOO baz". +This can make debugging tricky, +as the substituted result is not available at the time +the SConscript files are being interpreted and +thus not available to print(). +However, you can perform the substitution on demand +by calling the &f-link-env-subst; method for this purpose. + + +You can use this feature to pass arguments to a +callable variable by creating a callable class +that stores passed arguments in the instance, +and then uses them +(in the __call__ method) +when the instance is called. +Note that in this case, +the entire variable expansion must +be enclosed by curly braces +so that the arguments will +be associated with the +instantiation of the class: + + +class foo: + def __init__(self, arg): + self.arg = arg + + def __call__(self, target, source, env, for_signature): + return self.arg + " bar" + +# Will expand $BAR to "my argument bar baz" +env=Environment(FOO=foo, BAR="${FOO('my argument')} baz") + + + + + +Substitution: Special Variables + + Besides regular &consvars;, scons provides the following -special variables for each command execution: +Special Variables for use in expanding commands: @@ -6109,45 +6857,48 @@ -Note that the above variables are reserved -and may not be assigned to in the &consenv;. + +These names are reserved +and may not be assigned to or used as &consvars;. +&SCons; computes them in a context-dependent manner +and they and are not retrieved from a &consenv;. + -For example, given the &consvars; -CC='cc', -targets=['foo'] -and -sources=['foo.c', 'bar.c']: +For example, the following builder call: -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' +) -would produce the command line: +would produce the following output: cc -c -o foo foo.c bar.c -Variable names may be surrounded by curly braces -({}) -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: + +In the previous example, a string ${SOURCES[1]} -would produce: +would expand to: bar.c. + - -bar.c - + -Additionally, a variable name may + +Substitution: Special Attributes + +A variable name may have the following modifiers appended within the enclosing curly braces -to access properties of the interpolated string: +to access properties of the interpolated string. +These are known as special attributes. + base - @@ -6160,6 +6911,7 @@ filebase - Like file but minus its suffix. suffix - Just the file suffix. abspath - The absolute path name of the file. + relpath - The path name of the file relative to the root SConstruct file's directory. posix - The path with directories separated by forward slashes (/). @@ -6191,172 +6943,71 @@ &f-VariantDir;(). If the file does not exist locally but exists in a Repository, the path in the Repository is returned. - If this file isn't linked, it just returns the - directory and filename unchanged. - - rsrcdir - - The Repository directory containing the source file linked to this file through - &VariantDir;(). - If this file isn't linked, - it just returns the directory part of the filename. - - - -For example, the specified target will -expand as follows for the corresponding modifiers: - - -$TARGET => sub/dir/file.x -${TARGET.base} => sub/dir/file -${TARGET.dir} => sub/dir -${TARGET.file} => file.x -${TARGET.filebase} => file -${TARGET.suffix} => .x -${TARGET.abspath} => /top/dir/sub/dir/file.x - -SConscript('src/SConscript', variant_dir='sub/dir') -$SOURCE => sub/dir/file.x -${SOURCE.srcpath} => src/file.x -${SOURCE.srcdir} => src - -Repository('/usr/repository') -$SOURCE => sub/dir/file.x -${SOURCE.rsrcpath} => /usr/repository/src/file.x -${SOURCE.rsrcdir} => /usr/repository/src - - - -Modifiers can be combined, like -${TARGET.base.windows}, -${TARGET.srcpath.base), -${TARGET.file.suffix}, etc. - - -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.) -See below -for more thorough examples of -how this can be used. - -Lastly, a variable name -may be a callable Python function -associated with a -&consvar; in the environment. -The function should -accept four arguments: - - - target - a list of target nodes - source - a list of source nodes - env - the &consenv; - for_signature - - a Boolean value that specifies - whether the function is being called - for generating a build signature. - - - - -SCons will insert whatever -the called function returns -into the expanded string: - - - -def foo(target, source, env, for_signature): - return "bar" - -# Will expand $BAR to "bar baz" -env=Environment(FOO=foo, BAR="$FOO baz") - - -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, -and then uses them when the -__call__() -method is called. -Note that in this case, -the entire variable expansion must -be enclosed by curly braces -so that the arguments will -be associated with the -instantiation of the class: - - -class foo: - def __init__(self, arg): - self.arg = arg - - def __call__(self, target, source, env, for_signature): - return self.arg + " bar" - -# Will expand $BAR to "my argument bar baz" -env=Environment(FOO=foo, BAR="${FOO('my argument')} baz") - - + If this file isn't linked, it just returns the + directory and filename unchanged. + + rsrcdir - + The Repository directory containing the source file linked to this file through + &VariantDir;(). + If this file isn't linked, + it just returns the directory part of the filename. + + -The special pseudo-variables -$( -and -$) -may be used to surround parts of a command line -that may change -without -causing a rebuild--that is, -which are not included in the signature -of target files built with this command. -All text between -$( -and -$) -will be removed from the command line -before it is added to file signatures, -and the -$( -and -$) -will be removed before the command is executed. -For example, the command line: +For example, the specified target will +expand as follows for the corresponding modifiers: - -echo Last build occurred $( $TODAY $). > $TARGET - + +$TARGET => sub/dir/file.x +${TARGET.base} => sub/dir/file +${TARGET.dir} => sub/dir +${TARGET.file} => file.x +${TARGET.filebase} => file +${TARGET.suffix} => .x +${TARGET.abspath} => /top/dir/sub/dir/file.x +${TARGET.relpath} => sub/dir/file.x -would execute the command: +$TARGET => ../dir2/file.x +${TARGET.abspath} => /top/dir2/file.x +${TARGET.relpath} => ../dir2/file.x - -echo Last build occurred $TODAY. > $TARGET - +SConscript('src/SConscript', variant_dir='sub/dir') +$SOURCE => sub/dir/file.x +${SOURCE.srcpath} => src/file.x +${SOURCE.srcdir} => src -but the command signature added to any target files would be: +Repository('/usr/repository') +$SOURCE => sub/dir/file.x +${SOURCE.rsrcpath} => /usr/repository/src/file.x +${SOURCE.rsrcdir} => /usr/repository/src + - -echo Last build occurred . > $TARGET - + +Some modifiers can be combined, like +${TARGET.srcpath.base), +${TARGET.file.suffix}, etc. + - + - + Python Code Substitution -Any Python code within curly braces -({}) -and introduced by the variable prefix $ -will be evaluated using the Python eval 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 +${expression} +does not appear to match one of the other substitution patterns, +it is evaluated as a Python expression. +This uses Python's eval function, +with the globals parameter set to +the current environment's set of &consvars;, +and the result substituted in. So in the following case: -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" +) the command executed will be either @@ -6378,7 +7029,7 @@ env['COND'] is changed later in the SConscript, the final value will be used. -Here's a more interesting example. Note that all of +Here's a more complete example. Note that all of COND, FOO, and @@ -6389,161 +7040,170 @@ 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" +) -SCons uses the following rules when converting &consvars; into -command lines: - - - - string - -When the value is a string it is interpreted as a space delimited list of -command line arguments. - - - - - list - -When the value is a list it is interpreted as a list of command line -arguments. Each element of the list is converted to a string. - - +will execute: + +echo foo1 foo2 > foo.out + - - other - -Anything that is not a list or string is converted to a string and -interpreted as a single command line argument. - - + +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 eval which +returns the value. + - - newline - -Newline characters (\n) delimit lines. -The newline parsing is done after -all other parsing, so it is not possible for arguments (e.g. file names) to -contain embedded newline characters. - - - + +Use of the Python eval 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 +${python-expression-for-subst} form. + + Scanner Objects -You can use the -&f-link-Scanner; -function to define -objects to scan -new file types for implicit dependencies. -The &f-Scanner; -function accepts the following arguments: + +Scanner objects are used +to scan specific file types for implicit dependencies, +for example embedded preprocessor/compiler directives +that cause other files to be included during processing. +&SCons; has a number of pre-built Scanner objects, +so it is usually only necessary to set up Scanners for new file types. +You do this by calling the &f-link-Scanner; factory function. +&f-Scanner; accepts the following arguments. +Only function is required; +the rest are optional: + function -This can be either: - - -a Python function that will process -the Node (file) -and return a list of File Nodes + +A scanner function to call to process +a given Node (usually a file) +and return a list of Nodes representing the implicit -dependencies (file names) found in the contents; -or: - - -a dictionary that maps keys -(typically the file suffix, but see below for more discussion) -to other Scanners that should be called. - - - -If the argument is a Python function, -the function must accept three required arguments -and an optional fourth: - - - - node - - The internal &SCons; node representing the file. - Use str(node) - to fetch the name of the file, and - node.get_contents() - to fetch the contents of the file as bytes or - node.get_text_contents() - to fetch the contents as text. - Note that the file is - not - guaranteed to exist before the scanner is called, - so the scanner function should check that - if there's any chance that the scanned file - might not exist - (for example, if it's built from other files). - - env - The &consenv; for the scan. - path - - A tuple (or list) - of directories that can be searched - for files. - This will usually be the tuple returned by the - path_function - argument (see below). - - arg - - The argument supplied when the scanner was created, if any - (default None. - - - +dependencies (usually files) found in the contents. +The function must accept three required arguments, +node, +env and +path, +and an optional fourth, +arg. +node is +the internal &SCons; node representing the file to scan, +env is the &consenv; to use during +the scan, and path is a tuple +of directories that can be searched for files, +as generated by the optional scanner +path_function (see below). +If argument was supplied when the Scanner +object was created, it is given as arg +when the scanner function is called; since argument +is optional, the default is no arg. + + +The function can use use +str(node) +to fetch the name of the file, +node.dir +to fetch the directory the file is in, +node.get_contents() +to fetch the contents of the file as bytes or +node.get_text_contents() +to fetch the contents of the file as text. + + +The function must take into account the path +directories when generating the dependency Nodes. To illustrate this, +a C language source file may contain a line like +#include "foo.h". However, there is no guarantee +that foo.h exists in the current directory: +the contents of &cv-link-CPPPATH; is passed to the C preprocessor which +will look in those places for the header, +so the scanner function needs to look in those places as well +in order to build Nodes with correct paths. +Using &f-link-FindPathDirs; with an argument of CPPPATH +as the path_function in the &f-Scanner; call +means the scanner function will be called with the paths extracted +from &cv-CPPPATH; in the environment env +passed as the paths parameter. + + +Note that the file to scan is +not +guaranteed to exist at the time the scanner is called - +it could be a generated file which has not been generated yet - +so the scanner function must be tolerant of that. + + +Alternatively, you can supply a dictionary as the +function parameter, +to map keys (such as file suffixes) to other Scanner objects. +A Scanner created this way serves as a dispatcher: +the Scanner's skeys parameter is +automatically populated with the dictionary's keys, +indicating that the Scanner handles Nodes which would be +selected by those keys; the mapping is then used to pass +the file on to a different Scanner that would not have been +selected to handle that Node based on its +own skeys. + name -The name of the Scanner. -This is mainly used -to identify the Scanner internally. +The name to use for the Scanner. +This is mainly used to identify the Scanner internally. +The default value is "NONE". argument -An optional argument that, if specified, +If specified, will be passed to the scanner function -(described above) +function and the path function -(specified below). +path_function +when called, +as the optional parameter each of those functions takes. + skeys -An optional list that can be used to -determine which scanner should be used for -a given Node. +Scanner key(s) indicating the file types +this scanner is associated with. +Used internally to select an appropriate scanner. In the usual case of scanning for file names, this argument will be a list of suffixes for the different file types that this Scanner knows how to scan. -If the argument is a string, -then it will be expanded -into a list by the current environment. +If skeys is a string, +it will be expanded into a list by the current environment. + @@ -6557,11 +7217,9 @@ the first target was defined, a list of target nodes, a list of source nodes, -and an optional argument supplied -when the scanner was created. -The -path_function -returns a tuple of directories +and the value of argument +if it was supplied when the Scanner was created. +Must return a tuple of directories that can be searched for files to be returned by this Scanner object. (Note that the @@ -6569,7 +7227,8 @@ function can be used to return a ready-made path_function for a given &consvar; name, -instead of having to write your own function from scratch.) +instead of having to write your own function from scratch.) + @@ -6583,7 +7242,11 @@ that are not of this class will be run through the function supplied by the -node_factory argument. +node_factory argument. +A value of None can +be supplied to indicate no conversion; +the default is to return File nodes. + @@ -6593,14 +7256,16 @@ A Python function that will take a string or other object and turn it into the appropriate class of Node -to be returned by this Scanner object. +to be returned by this Scanner object, +as indicated by node_class. + scan_check -An optional Python function that takes two arguments, +A Python function that takes two arguments, a Node (file) and a &consenv;, and returns whether the Node should, in fact, @@ -6615,15 +7280,16 @@ recursive -An optional flag that -specifies whether this scanner should be re-invoked + +Specifies whether this scanner should be re-invoked on the dependency files returned by the scanner. -When this flag is not set, -the Node subsystem will -only invoke the scanner on the file being scanned, -and not (for example) also on the files -specified by the #include lines -in the file being scanned. +If omitted, the Node subsystem will +only invoke the scanner on the file being scanned +and not recurse. +Recursion is needed when the files returned by the +scanner may themselves contain further file dependencies, +as in the case of preprocessor #include lines. +A value that evaluates true enables recursion; recursive may be a callable function, in which case it will be called with a list of @@ -6635,15 +7301,21 @@ -Note that -&scons; -has a global + + +Once created, a Scanner can added to an environment +by setting it in the &cv-link-SCANNERS; list, +which automatically triggers &SCons; to also add it +to the environment as a method. +However, usually a scanner is not truly standalone, but needs to +be plugged in to the existing selection mechanism for +deciding how to scan source files based on filename extensions. +For this, &SCons; has a global SourceFileScanner object that is used by the &b-link-Object;, &b-link-SharedObject; and &b-link-StaticObject; builders to decide -which scanner should be used -for different file extensions. +which scanner should be used. You can use the SourceFileScanner.add_scanner() method to add your own Scanner object @@ -6667,6 +7339,184 @@ + + +Tool Modules + + +Additional tools can be added to a project either by +placing them in a site_tools subdirectory +of a site directory, or in a custom location specified to +&scons; by giving the +toolpath keyword argument to &f-link-Environment;. +A tool module is a form of Python module, invoked internally +using the Python import mechanism, so a tool can consist either +of a single source file taking the name of the tool +(e.g. mytool.py) or a directory taking +the name of the tool (e.g. mytool/) +which contains at least an __init__.py file. + + + +The toolpath parameter +takes a list as its value: + + + +env = Environment(tools=['default', 'foo'], toolpath=['tools']) + + + +This looks for a tool specification module (mytool.py, +or directory mytool) +in directory tools and in the standard locations, +as well as using the ordinary default tools for the platform. + + + +Directories specified via toolpath are prepended +to the existing tool path. +The default tool path is any site_tools directories, +so tools in a specified toolpath take priority, +followed by tools in a site_tools directory, +followed by built-in tools. For example, adding +a tool specification module gcc.py to the toolpath +directory would override the built-in &t-link-gcc; tool. +The tool path is stored in the environment and will be +used by subsequent calls to the &f-link-Tool; method, +as well as by &f-link-env-Clone;. + + + +base = Environment(toolpath=['custom_path']) +derived = base.Clone(tools=['custom_tool']) +derived.CustomBuilder() + + + +A tool specification module must include two functions: + + + + + generate(env, **kwargs) + +Modify the &consenv; env +to set up necessary &consvars;, Builders, Emitters, etc., +so the facilities represented by the tool can be executed. +Care should be taken not to overwrite &consvars; intended +to be settable by the user. For example: + + +def generate(env): + ... + if 'MYTOOL' not in env: + env['MYTOOL'] = env.Detect("mytool") + if 'MYTOOLFLAGS' not in env: + env['MYTOOLFLAGS'] = SCons.Util.CLVar('--myarg') + ... + + +The generate function +may use any keyword arguments +that the user supplies via kwargs +to vary its initialization. + + + + exists(env) + +Return a true value if the tool can +be called in the context of env. +else false. +Usually this means looking up one or more +known programs using the PATH from the +supplied env, but the tool can +make the exists decision in any way it chooses. + + + + + + + +At the moment, user-added tools do not automatically have their +exists function called. +As a result, it is recommended that the generate +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 exists function should still be provided. + + + +The elements of the tools list may also +be functions or callable objects, +in which case the &Environment; method +will call those objects +to update the new &consenv; (see &f-link-Tool; for more details): + + +def my_tool(env): + env['XYZZY'] = 'xyzzy' + +env = Environment(tools=[my_tool]) + + +The individual elements of the tools list +may also themselves be lists or tuples of the form +(toolname, kw_dict). +SCons searches for the +toolname +specification file as described above, and +passes +kw_dict, +which must be a dictionary, as keyword arguments to the tool's +generate +function. +The +generate +function can use the arguments to modify the tool's behavior +by setting up the environment in different ways +or otherwise changing its initialization. + + +# in tools/my_tool.py: +def generate(env, **kwargs): + # Sets MY_TOOL to the value of keyword 'arg1' '1' if not supplied + env['MY_TOOL'] = kwargs.get('arg1', '1') + +def exists(env): + return True + +# in SConstruct: +env = Environment(tools=['default', ('my_tool', {'arg1': 'abc'})], + toolpath=['tools']) + + +The tool specification (my_tool in the example) +can use the +&cv-link-PLATFORM; variable from +the &consenv; it is passed to customize the tool for different platforms. + + +Tools can be "nested" - that is, they +can be located within a subdirectory in the toolpath. +A nested tool name uses a dot to represent a directory separator + + +# namespaced builder +env = Environment(ENV=os.environ.copy(), tools=['SubDir1.SubDir2.SomeTool']) +env.SomeTool(targets, sources) + +# Search Paths +# SCons\Tool\SubDir1\SubDir2\SomeTool.py +# SCons\Tool\SubDir1\SubDir2\SomeTool\__init__.py +# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool.py +# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool\__init__.py + + + @@ -6678,7 +7528,7 @@ issues waiting to trap the unwary. -.C file suffix +.C File Suffix &scons; handles the upper-case .C @@ -6698,27 +7548,126 @@ -.F file suffix +Fortran File Suffixes -&scons; handles the upper-case -.F -file suffix differently, -depending on the capabilities of -the underlying system. -On a case-sensitive system -such as Linux or UNIX, -&scons; treats a file with a -.F -suffix as a Fortran source file -that is to be first run through + +There are several ways source file suffixes impact the +behavior of &SCons; when working with Fortran language code +(not all are system-specific, but they are included here +for completeness). + + + +As the Fortran language has evolved through multiple +standards editions, projects might have a need to handle +files from different language generations differently. +To this end, &SCons; dispatches to a different compiler +dialect setup (expressed as a set of &consvars;) +depending on the file suffix. +By default, all of these setups start out the same, +but individual &consvars; can be modified as needed to tune a given dialect. +Each of these dialacts has a tool specification module +whose documentation describes the &consvars; associated +with that dialect: .f +(as well as .for and .ftn) +in &t-link-fortran;; (&consvars; start with FORTRAN) +.f77 in &t-link-f77;; +(&consvars; start with F77) +.f90 in &t-link-f90;; +(&consvars; start with F90) +.f95 in &t-link-f95;; +(&consvars; start with F95) +.f03 in &t-link-f03;; +(&consvars; start with F03) +.f08 in &t-link-f08; +(&consvars; start with F08). + + + +While &SCons; recognizes multiple internal dialects +based on filename suffixes, +the convention of various available Fortran compilers is +to assign an actual meaning to only two of these suffixes: +.f +(as well as .for and .ftn) +refers to the fixed-format source +code that was the only available option in FORTRAN 77 and earlier, +and .f90 refers to free-format source code +which became available as of the Fortran 90 standard. +Some compilers recognize suffixes which correspond to Fortran +specifications later then F90 as equivalent to +.f90 for this purpose, +while some do not - check the documentation for your compiler. +An occasionally suggested policy suggestion is to use only +.f and .f90 +as Fortran filename suffixes. +The fixed/free form determination can usually be controlled +explicitly with compiler flags +(e.g. for gfortran), +overriding any assumption that may be made based on the source file suffix. + + + +The source file suffix does not imply conformance +with the similarly-named Fortran standard - a suffix of +.f08 does not mean you are compiling +specifically for Fortran 2008. Normally, compilers +provide command-line options for making this selection +(e.g. for gfortran). + + + +For dialects from F90 on (including the generic FORTRAN dialect), +a suffix of .mod is recognized for Fortran modules. +These files are a side effect of compiling a Fortran +source file containing module declarations, +and must be available when other code which declares +that it uses the module is processed. +&SCons; does not currently have integrated support for submodules, +introduced in the Fortran 2008 standard - +the invoked compiler will produce results, +but &SCons; will not recognize +.smod files as tracked objects. + + + +On a case-sensitive system such as Linux or UNIX, +a file with a an upper-cased suffix from the set +.F, +.FOR, +.FTN, +.F90, +.F95, +.F03 and +.F08 +is treated as a Fortran source file +which shall first be run through the standard C preprocessor. -On a case-insensitive system -such as Windows, -&scons; treats a file with a -.F -suffix as a Fortran source file that should -not -be run through the C preprocessor. +The lower-cased versions of these suffixes do not +trigger this behavior. +On systems which do not distinguish between uppper +and lower case in filenames, +this behavior is not available, +but files suffixed with either +.FPP +or .fpp +are always passed to the preprocessor first. +This matches the convention of gfortran +from the GNU Compiler Collection, +and also followed by certain other Fortran compilers. +For these two suffixes, +the generic FORTRAN dialect will be selected. + + + +&SCons; itself does not invoke the preprocessor, +that is handled by the compiler, +but it adds &consvars; which are applicable to the preprocessor run. +You can see this difference by examining +&cv-link-FORTRANPPCOM; and &cv-link-FORTRANPPCOMSTR; +which are used instead of +&cv-link-FORTRANCOM; and &cv-link-FORTRANCOMSTR; for that dialect. + @@ -6726,10 +7675,10 @@ Cygwin supplies a set of tools and utilities that let users work on a -Windows system using a more POSIX-like environment. -The Cygwin tools, including Cygwin Python, +Windows system using a POSIX-like environment. +The Cygwin tools, including Cygwin &Python;, do this, in part, -by sharing an ability to interpret UNIX-like path names. +by sharing an ability to interpret POSIX-style path names. For example, the Cygwin tools will internally translate a Cygwin path name like /cygdrive/c/mydir @@ -6737,13 +7686,13 @@ of C:/mydir (equivalent to C:\mydir). -Versions of Python +Versions of &Python; that are built for native Windows execution, such as the python.org and ActiveState versions, -do not have the Cygwin path name semantics. -This means that using a native Windows version of Python +do not understand the Cygwin path name semantics. +This means that using a native Windows version of &Python; to build compiled programs using Cygwin tools -(such as &gcc;, &bison; and flex) +(such as &gcc;, &bison; and &flex;) may yield unpredictable results. "Mixing and matching" in this way can be made to work, @@ -6751,46 +7700,60 @@ in your SConscript files. In practice, users can sidestep -the issue by adopting the following rules: -When using &gcc;, -use the Cygwin-supplied Python interpreter +the issue by adopting the following guidelines: +When using Cygwin's &gcc; for compiling, +use the Cygwin-supplied &Python; interpreter to run &scons;; when using Microsoft Visual C/C++ -(or some other Windows compiler) -use the python.org or Microsoft Store or ActiveState version of Python -to run &scons;. +(or some other "native" Windows compiler) +use the python.org, Microsoft Store, ActiveState or other +native version of &Python; to run &scons;. + + + +This discussion largely applies to the msys2 environment +as well (with the use of the mingw compiler toolchain), +in particular the recommendation to use the msys2 version of +&Python; if running &scons; from inside an msys2 shell. + Windows: <filename>scons.bat</filename> file -On Windows systems, -&scons; is executed via a wrapper -scons.bat -file. -This has (at least) two ramifications: +On Windows, if &scons; is executed via a wrapper +scons.bat batch file, +there are (at least) two ramifications. +Note this is no longer the default - &scons; installed +via &Python;''s pip installer +will have an scons.exe which does +not have these limitations: + First, Windows command-line users that want to use variable assignment on the command line may have to put double quotes -around the assignments: +around the assignments, otherwise the +Windows command shell will consume those as +arguments to itself, not to &scons;: scons "FOO=BAR" "BAZ=BLEH" Second, the Cygwin shell does not -recognize this file as being the same -as an &scons; -command issued at the command-line prompt. -You can work around this either by -executing -scons.bat +recognize typing scons +at the command line prompt as referring to this wrapper. +You can work around this either by executing +scons.bat +(including the extension) from the Cygwin command line, or by creating a wrapper shell script named -scons. +scons which +invokes scons.bat. + @@ -6800,9 +7763,9 @@ The MinGW bin directory must be in your PATH environment variable or the -ENV['PATH'] &consvar; for &scons; +['ENV']['PATH'] &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 +Python; interpreter, &scons; will prefer the MinGW tools over the Cygwin tools, if they are both installed, regardless of the order of the bin directories in the PATH variable. If you have both MSVC and MinGW @@ -7401,11 +8364,17 @@ - + SCONSFLAGS -A string of options that will be used by &scons; -in addition to those passed on the command line. +A string containing options that will be used by &scons; +in addition to those passed on the command line. +Can be used to reduce frequent retyping of common options. +The contents of SCONSFLAGS are considered +before any passed command line options, +so the command line can be used to override +SCONSFLAGS options if necessary. + @@ -7414,8 +8383,8 @@ (Windows only). If set, save the shell environment variables generated when setting up the Microsoft Visual C++ compiler -(and/or Build Tools) to a file to give these settings, -which are expensive to generate, persistence +(and/or Build Tools) to a cache file, to give these settings, +which are relatively expensive to generate, persistence across &scons; invocations. Use of this option is primarily intended to aid performance in tightly controlled Continuous Integration setups. @@ -7423,7 +8392,7 @@ If set to a True-like value ("1", "true" or "True") will cache to a file named -.scons_msvc_cache in the user's home directory. +.scons_msvc_cache.json in the user's home directory. If set to a pathname, will use that pathname for the cache. Note: use this cache with caution as it @@ -7439,6 +8408,16 @@ Available since &scons; 3.1 (experimental). + + + QTDIR + +If using the &t-link-qt; tool, this is the path to +the Qt installation to build against. &SCons; respects this +setting because it is a long-standing convention in the Qt world, +where multiple Qt installations are possible. + + diff -Nru scons-4.0.1+dfsg/doc/overview.rst scons-4.4.0+dfsg/doc/overview.rst --- scons-4.0.1+dfsg/doc/overview.rst 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/overview.rst 2022-07-30 21:48:28.000000000 +0000 @@ -92,12 +92,19 @@ ======== 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 (````, ````, +```` and ````) 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 @@ -125,7 +132,7 @@ *f-link-foobar* which is a link to the description of the global Function -*f-env-link-foobar* +*f-link-env-foobar* which is a link to the description of the environment method @@ -134,12 +141,12 @@ :: 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 @@ 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 `` ... ``. +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 @@ *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 -Nru scons-4.0.1+dfsg/doc/reference/html.xsl scons-4.4.0+dfsg/doc/reference/html.xsl --- scons-4.0.1+dfsg/doc/reference/html.xsl 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/reference/html.xsl 2022-07-30 21:48:28.000000000 +0000 @@ -24,11 +24,14 @@ --> + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> - + + + @@ -52,5 +55,97 @@ set toc,title - + + + + + + + + + + + + + + + + + + + + <xsl:copy-of select="$title"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru scons-4.0.1+dfsg/doc/SConscript scons-4.4.0+dfsg/doc/SConscript --- scons-4.0.1+dfsg/doc/SConscript 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/SConscript 2022-07-30 21:48:28.000000000 +0000 @@ -2,8 +2,9 @@ # SConscript file for building SCons documentation. # +# 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,7 +23,7 @@ # 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. +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE import os.path import re @@ -80,7 +81,7 @@ # # --- Helpers --- # -def writeVersionXml(verfile, date, ver, rev): +def writeVersionXml(verfile, date, ver, rev, copyright_years): """ Helper function: Write a version.xml file. """ try: os.unlink(verfile) @@ -98,7 +99,8 @@ -""" % (date, ver, rev)) + +""" % (date, ver, rev, copyright_years)) # The names of the target files for the MAN pages @@ -155,9 +157,9 @@ # for this run. Ignore it for dependency purposes so we don't # rebuild all the docs every time just because the date changes. # - date, ver, rev = env.Dictionary('DATE', 'VERSION', 'REVISION') + date, ver, rev, copyright_years = env.Dictionary('DATE', 'VERSION', 'REVISION', 'COPYRIGHT_YEARS') version_xml = File(os.path.join(build, "version.xml")) - writeVersionXml(str(version_xml), date, ver, rev) + writeVersionXml(str(version_xml), date, ver, rev, copyright_years) import shutil import SCons.Builder diff -Nru scons-4.0.1+dfsg/doc/scons.mod scons-4.4.0+dfsg/doc/scons.mod --- scons-4.0.1+dfsg/doc/scons.mod 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/scons.mod 2022-07-30 21:48:28.000000000 +0000 @@ -1,16 +1,39 @@ - + Aegis"> Ant"> @@ -44,10 +62,11 @@ f77"> f90"> f95"> +flex"> gas"> gcc"> g77"> -gXX"> +g++"> Jam"> jar"> javac"> @@ -57,6 +76,7 @@ m4"> Make"> Make++"> +ninja"> pdflatex"> pdftex"> Python"> @@ -64,7 +84,7 @@ rmic"> ScCons"> sleep"> -swig"> +SWIG"> tar"> tex"> touch"> @@ -72,11 +92,7 @@ zip"> - + Action"> ActionBase"> @@ -103,12 +119,7 @@ Wrapper"> - - + --config"> --debug=duplicate"> @@ -126,23 +137,15 @@ --tree"> -Q"> - + implicit_cache"> implicit_deps_changed"> implicit_deps_unchanged"> - - + build"> Makefile"> @@ -158,10 +161,9 @@ src"> + @@ -282,10 +284,14 @@ UnknownOptions"> UnknownVariables"> + + subst"> + + Message"> Result"> CheckCHeader"> @@ -305,21 +311,18 @@ + IndexError"> NameError"> str"> zipfile"> -Cache"> - +Cache"> - + ARGLIST"> ARGUMENTS"> @@ -328,12 +331,7 @@ DEFAULT_TARGETS"> - - + BUILDERMAP"> COLOR"> @@ -347,24 +345,14 @@ TARSUFFIX"> + - +PATH"> +PYTHONPATH"> +SCONSFLAGS"> -PATH"> -PYTHONPATH"> -SCONSFLAGS"> - - - + allowed_values"> build_dir"> @@ -378,23 +366,13 @@ variant_dir"> - - + all"> none"> - - + BuildDir"> CFile"> @@ -421,14 +399,15 @@ VariantDir"> Zip"> - -Make"> + +Make"> - @@ -461,42 +440,37 @@ Dictionary"> -Emitter"> -emitter"> +Emitter"> +emitter"> -factory"> +factory"> -Generator"> -generator"> +Generator"> +generator"> -Nodes"> +Nodes"> -signature"> -build signature"> +content signature"> +content signatures"> +build signature"> true"> false"> typedef"> - ---> +action="> +batch_key="> +cmdstr="> +exitstatfunc="> +strfunction="> +varlist="> -action="> -batch_key="> -cmdstr="> -exitstatfunc="> -strfunction="> -varlist="> - + bar"> common1.c"> @@ -531,30 +505,20 @@ prog.exe"> stdio.h"> - + +"> #"> - + -announce@scons.tigris.org"> scons-dev@scons.org"> scons-users@scons.org"> - + diff -Nru scons-4.0.1+dfsg/doc/sphinx/conf.py scons-4.4.0+dfsg/doc/sphinx/conf.py --- scons-4.0.1+dfsg/doc/sphinx/conf.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/sphinx/conf.py 2022-07-30 21:48:28.000000000 +0000 @@ -59,6 +59,10 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# Since 0.99, rst2pdf says: "twoColumn isn't part of the default styles +# in 0.99. You need to add the twocolumn style file." +pdf_stylesheets = ['twocolumn'] + # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # @@ -69,25 +73,26 @@ # General information about the project. project = 'SCons' -copyright = '2020, SCons Project' +copyright = '2021, SCons Project' author = 'SCons Project Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # -# TODO: fill these in externally +from SCons import __version__ +# The full version, including alpha/beta/rc tags: +release = __version__ # The short X.Y version. -version = '4.0' -# The full version, including alpha/beta/rc tags. -release = '4.0.0' +major, minor, _ = __version__.split('.') +version = '.'.join([major, minor]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff -Nru scons-4.0.1+dfsg/doc/user/add-method.xml scons-4.4.0+dfsg/doc/user/add-method.xml --- scons-4.0.1+dfsg/doc/user/add-method.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/add-method.xml 2022-07-30 21:48:28.000000000 +0000 @@ -18,11 +18,13 @@ 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"> -Pseudo-Builders: the AddMethod function +Extending &SCons;: Pseudo-Builders and the AddMethod function - - Although &SCons; provides many useful methods @@ -151,14 +81,14 @@ -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') +bld = Builder(action='foobuild < $SOURCE > $TARGET') All the above line does is create a free-standing &Builder; object. - The next section will show us how to actually use it. + The next section will show how to actually use it. @@ -175,7 +105,7 @@ for files to be built. This is done through the &cv-link-BUILDERS; &consvar; in an environment. - The &cv-BUILDERS; variable is a Python dictionary + The &cv-link-BUILDERS; variable is a &Python; dictionary that maps the names by which you want to call various &Builder; objects to the objects themselves. For example, if we want to call the @@ -187,10 +117,10 @@ -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env = Environment(BUILDERS = {'Foo' : bld}) import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +bld=Builder(action = 'foobuild < $SOURCE > $TARGET') +env = Environment(BUILDERS={'Foo': bld}) +env.AppendENVPath('PATH', os.getcwd()) env.Foo('file.foo', 'file.input') @@ -202,8 +132,8 @@ -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env = Environment(BUILDERS = {'Foo' : bld}) +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env = Environment(BUILDERS={'Foo': bld}) @@ -261,14 +191,17 @@ --> -import SCons.Defaults; SCons.Defaults.ConstructionEnvironment['TOOLS'] = {}; bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env = Environment(BUILDERS = {'Foo' : bld}) +import SCons.Defaults + +SCons.Defaults.ConstructionEnvironment['TOOLS'] = {} +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env = Environment(BUILDERS = {'Foo' : bld}) +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') @@ -288,18 +221,18 @@ To be able to use both our own defined &Builder; objects and the default &Builder; objects in the same &consenv;, - you can either add to the &cv-BUILDERS; variable + you can either add to the &cv-link-BUILDERS; variable using the &Append; function: -env = Environment() import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env.Append(BUILDERS = {'Foo' : bld}) +env = Environment() +env.AppendENVPath('PATH', os.getcwd()) +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env.Append(BUILDERS={'Foo': bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') @@ -316,8 +249,8 @@ env = Environment() -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') -env.Append(BUILDERS = {'Foo' : bld}) +bld = Builder(action='foobuild < $SOURCE > $TARGET') +env.Append(BUILDERS={'Foo': bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') @@ -331,7 +264,7 @@ env = Environment() -bld = Builder(action = 'foobuild < $SOURCE > $TARGET') +bld = Builder(action='foobuild < $SOURCE > $TARGET') env['BUILDERS']['Foo'] = bld env.Foo('file.foo', 'file.input') env.Program('hello.c') @@ -363,8 +296,8 @@ suffixes to the target and/or the source file. For example, rather than having to specify explicitly that you want the Foo - &Builder; to build the file.foo - target file from the file.input source file, + &Builder; to build the file.foo + target file from the file.input source file, you can give the .foo and .input suffixes to the &Builder;, making for more compact and readable calls to @@ -374,12 +307,14 @@ -bld = Builder(action = 'foobuild < $SOURCE > $TARGET', - suffix = '.foo', - src_suffix = '.input') -env = Environment(BUILDERS = {'Foo' : bld}) import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +bld = Builder( + action='foobuild < $SOURCE > $TARGET', + suffix='.foo', + src_suffix='.input', +) +env = Environment(BUILDERS={'Foo': bld}) +env.AppendENVPath('PATH', os.getcwd()) env.Foo('file1') env.Foo('file2') @@ -395,10 +330,12 @@ -bld = Builder(action = 'foobuild < $SOURCE > $TARGET', - suffix = '.foo', - src_suffix = '.input') -env = Environment(BUILDERS = {'Foo' : bld}) +bld = Builder( + action='foobuild < $SOURCE > $TARGET', + suffix='.foo', + src_suffix='.input', +) +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file1') env.Foo('file2') @@ -424,7 +361,7 @@ In &SCons;, you don't have to call an external command to build a file. - You can, instead, define a Python function + You can, instead, define a &Python; function that a &Builder; object can invoke to build your target file (or files). Such a &buildfunc; definition looks like: @@ -446,7 +383,7 @@ - target + target @@ -455,14 +392,14 @@ the target or targets to be built by this function. The file names of these target(s) - may be extracted using the Python &str; function. + may be extracted using the &Python; &str; function. - source + source @@ -471,21 +408,21 @@ the sources to be used by this function to build the targets. The file names of these source(s) - may be extracted using the Python &str; function. + may be extracted using the &Python; &str; function. - env + env The &consenv; used for building the target(s). The function may use any of the - environment's construction variables + environment's &consvars; in any way to affect how it builds the targets. @@ -509,7 +446,7 @@ - Once you've defined the Python function + Once you've defined the &Python; function that will build your target file, defining a &Builder; object for it is as simple as specifying the name of the function, @@ -525,10 +462,13 @@ def build_function(target, source, env): # Code to build "target" from "source" return None -bld = Builder(action = build_function, - suffix = '.foo', - src_suffix = '.input') -env = Environment(BUILDERS = {'Foo' : bld}) + +bld = Builder( + action=build_function, + suffix='.foo', + src_suffix='.input', +) +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file') @@ -539,7 +479,7 @@ And notice that the output changes slightly, - reflecting the fact that a Python function, + reflecting the fact that a &Python; function, not an external command, is now called to build the target file: @@ -557,8 +497,8 @@ &SCons; Builder objects can create an action "on the fly" - by using a function called a &generator;. - (Note: this is not the same thing as a Python generator function + by using a function called a &Generator;. + (Note: this is not the same thing as a &Python; generator function described in PEP 255) This provides a great deal of flexibility to construct just the right list of commands @@ -581,7 +521,7 @@ - source + source @@ -591,7 +531,7 @@ by the command or other action generated by this function. The file names of these source(s) - may be extracted using the Python &str; function. + may be extracted using the &Python; &str; function. @@ -599,7 +539,7 @@ - target + target @@ -609,7 +549,7 @@ by the command or other action generated by this function. The file names of these target(s) - may be extracted using the Python &str; function. + may be extracted using the &Python; &str; function. @@ -617,14 +557,14 @@ - env + env The &consenv; used for building the target(s). - The generator may use any of the - environment's construction variables + The &generator; may use any of the + environment's &consvars; in any way to determine what command or other action to return. @@ -634,13 +574,13 @@ - for_signature + for_signature A flag that specifies whether the - generator is being called to contribute to a build signature, + &generator; is being called to contribute to a &buildsig;, as opposed to actually executing the command. @@ -664,21 +604,24 @@ Once you've defined a &generator;, you create a &Builder; to use it - by specifying the generator keyword argument - instead of action. + by specifying the generator keyword argument + instead of action. +import os def generate_actions(source, target, env, for_signature): return 'foobuild < %s > %s' % (source[0], target[0]) -bld = Builder(generator = generate_actions, - suffix = '.foo', - src_suffix = '.input') -env = Environment(BUILDERS = {'Foo' : bld}) -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + +bld = Builder( + generator=generate_actions, + suffix='.foo', + src_suffix='.input', +) +env = Environment(BUILDERS={'Foo': bld}) +env.AppendENVPath('PATH', os.getcwd()) env.Foo('file') @@ -692,10 +635,13 @@ def generate_actions(source, target, env, for_signature): return 'foobuild < %s > %s' % (source[0], target[0]) -bld = Builder(generator = generate_actions, - suffix = '.foo', - src_suffix = '.input') -env = Environment(BUILDERS = {'Foo' : bld}) + +bld = Builder( + generator=generate_actions, + suffix='.foo', + src_suffix='.input', +) +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file') @@ -706,9 +652,9 @@ Note that it's illegal to specify both an - action + action and a - generator + generator for a &Builder;. @@ -726,7 +672,7 @@ that takes as its arguments the list of the targets passed to the builder, the list of the sources passed to the builder, - and the construction environment. + and the &consenv;. The emitter function should return the modified lists of targets that should be built and sources from which the targets will be built. @@ -736,7 +682,7 @@ For example, suppose you want to define a Builder - that always calls a foobuild program, + that always calls a foobuild program, and you want to automatically add a new target file named new_target @@ -749,17 +695,20 @@ +import os def modify_targets(target, source, env): target.append('new_target') source.append('new_source') return target, source -bld = Builder(action = 'foobuild $TARGETS - $SOURCES', - suffix = '.foo', - src_suffix = '.input', - emitter = modify_targets) -env = Environment(BUILDERS = {'Foo' : bld}) -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + +bld = Builder( + action='foobuild $TARGETS - $SOURCES', + suffix='.foo', + src_suffix='.input', + emitter=modify_targets, +) +env = Environment(BUILDERS={'Foo': bld}) +env.AppendENVPath('PATH', os.getcwd()) env.Foo('file') @@ -778,16 +727,19 @@ target.append('new_target') source.append('new_source') return target, source -bld = Builder(action = 'foobuild $TARGETS - $SOURCES', - suffix = '.foo', - src_suffix = '.input', - emitter = modify_targets) -env = Environment(BUILDERS = {'Foo' : bld}) + +bld = Builder( + action='foobuild $TARGETS - $SOURCES', + suffix='.foo', + src_suffix='.input', + emitter=modify_targets, +) +env = Environment(BUILDERS={'Foo': bld}) env.Foo('file') - + And would yield the following output: @@ -799,34 +751,36 @@ One very flexible thing that you can do is - use a construction variable to specify - different emitter functions for different - construction variable. + use a &consvar; to specify + different emitter functions for different &consenvs;. To do this, specify a string - containing a construction variable + containing a &consvar; expansion as the emitter when you call - the &Builder; function, - and set that construction variable to + the &f-link-Builder; function, + and set that &consvar; to the desired emitter function - in different construction environments: + in different &consenvs;: -bld = Builder(action = './my_command $SOURCES > $TARGET', - suffix = '.foo', - src_suffix = '.input', - emitter = '$MY_EMITTER') +bld = Builder( + action='./my_command $SOURCES > $TARGET', + suffix='.foo', + src_suffix='.input', + emitter='$MY_EMITTER', +) + def modify1(target, source, env): return target, source + ['modify1.in'] + def modify2(target, source, env): return target, source + ['modify2.in'] -env1 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify1) -env2 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify2) + +env1 = Environment(BUILDERS={'Foo': bld}, MY_EMITTER=modify1) +env2 = Environment(BUILDERS={'Foo': bld}, MY_EMITTER=modify2) env1.Foo('file1') env2.Foo('file2') @@ -863,7 +817,93 @@ - - -
- - SCons User's Guide Copyright (c) 2004-2020 The SCons Foundation - -
- - - diff -Nru scons-4.0.1+dfsg/doc/user/depends.xml scons-4.4.0+dfsg/doc/user/depends.xml --- scons-4.0.1+dfsg/doc/user/depends.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/depends.xml 2022-07-30 21:48:28.000000000 +0000 @@ -22,7 +22,9 @@ + With nested or namespaced tools we can use the dot notation + to specify a sub-directory that the tool is located under. + # namespaced target -env = Environment(tools = ['SubDir1.SubDir2.SomeTool'], toolpath = ['/opt/SomeToolPath']) +env = Environment( + tools=['SubDir1.SubDir2.SomeTool'], + toolpath=['/opt/SomeToolPath'] +) env.SomeTool(targets, sources) # With this example the search locations would include @@ -1856,26 +2074,21 @@ ./site_scons/site_tools/SubDir1/SubDir2/SomeTool/__init__.py - - For python2 It's important to note when creating tools within sub-directories, - there needs to be a __init__.py file within each directory. - This file can just be empty. - This is the same constraint used by python when loading modules - from within sub-directories (packages). - For python3 this appears to be no longer a requirement. - -
+
Using sys.path within the toolpath - If we want to access tools externally to scons on the sys.path - (one example would be tools installed via the pip package manager) - One way to do this is to use sys.path with the toolpath. - - One thing to watch out for with this approach is that sys.path - can sometimes contains paths to .egg files instead of directories. + If we want to access tools external to &scons; which are findable + via sys.path + (for example, tools installed via Python's pip package manager), + it is possible to use sys.path with the toolpath. + + One thing to watch out for with this approach is that + sys.path + can sometimes contains paths to .egg + files instead of directories. So we need to filter those out with this approach. @@ -1884,16 +2097,20 @@ searchpaths = [] for item in sys.path: - if os.path.isdir(item): searchpaths.append(item) + if os.path.isdir(item): + searchpaths.append(item) -env = Environment(tools = ['someinstalledpackage.SomeTool'], toolpath = searchpaths) +env = Environment( + tools=['someinstalledpackage.SomeTool'], + toolpath=searchpaths +) env.SomeTool(targets, sources) - By using sys.path with the toolpath argument - and by using the nested syntax we can have scons search - packages installed via pip for Tools. + By using sys.path with the toolpath argument + and by using the nested syntax we can have &scons; search + packages installed via pip for Tools. @@ -1914,29 +2131,40 @@ In some cases you may want to use a tool located within a installed external pip package. - This is possible by the use of sys.path with the toolpath. + This is possible by the use of + sys.path with the toolpath. However in that situation you need to provide a prefix to the toolname - to indicate where it is located within sys.path + to indicate where it is located within sys.path. searchpaths = [] for item in sys.path: - if os.path.isdir(item): searchpaths.append(item) -env = Environment(tools = ['tools_example.subdir1.subdir2.SomeTool'], toolpath = searchpaths) + if os.path.isdir(item): + searchpaths.append(item) +env = Environment( + tools=['tools_example.subdir1.subdir2.SomeTool'], + toolpath=searchpaths +) env.SomeTool(targets, sources) - To avoid the use of a prefix within the name of the tool or filtering sys.path for directories, - we can use the PyPackageDir(modulename) function to locate the directory of the python package. - PyPackageDir returns a Dir object which represents the path of the directory + To avoid the use of a prefix within the name of the tool or filtering + sys.path for directories, + we can use &f-link-PyPackageDir; function to locate the directory of + the python package. + &f-PyPackageDir; returns a Dir object which represents the path of the + directory for the python package / module specified as a parameter. # namespaced target using sys.path -env = Environment(tools = ['SomeTool'], toolpath = [PyPackageDir('tools_example.subdir1.subdir2')]) +env = Environment( + tools=['SomeTool'], + toolpath=[PyPackageDir('tools_example.subdir1.subdir2')] +) env.SomeTool(targets, sources) diff -Nru scons-4.0.1+dfsg/doc/user/external.xml scons-4.4.0+dfsg/doc/user/external.xml --- scons-4.0.1+dfsg/doc/user/external.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/external.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,158 +1,420 @@ - %scons; + + %scons; - - %builders-mod; - - %functions-mod; - - %tools-mod; - - %variables-mod; + + %builders-mod; + + %functions-mod; + + %tools-mod; + + %variables-mod; -]> + ]> -Using SCons with other build tools + Using SCons with other build tools - - - - - Sometimes a project needs to interact with other projects - in various ways. For example, many open source projects - make use of components from other open source projects, - and want to use those in their released form, not recode - their builds into &SCons;. As another example, sometimes - the flexibility and power of &SCons; is useful for managing the - overall project, but developers might like faster incremental - builds when making small changes by using a different tool. - - - - - - This chapter shows some techniques for interacting with other - projects and tools effectively from within &SCons;. - - - -
- Creating a Compilation Database + --> - Tooling which wants to perform analysis and modification - of source code often needs to know not only the source code - itself, but also how it will be compiled, as the compilation line - affects the behavior of macros, includes, etc. &SCons; has a - record of this information once it has run, in the form of - Actions associated with the sources, and can emit this information - so tools can use it. + Sometimes a project needs to interact with other projects + in various ways. For example, many open source projects + make use of components from other open source projects, + and want to use those in their released form, not recode + their builds into &SCons;. As another example, sometimes + the flexibility and power of &SCons; is useful for managing the + overall project, but developers might like faster incremental + builds when making small changes by using a different tool. - The Clang project has defined a JSON Compilation Database. - This database is in common use as input into Clang tools - and many IDEs and editors as well. - See - - JSON Compilation Database Format Specification - - for complete information. &SCons; can emit a - compilation database in this format - by enabling the &t-link-compilation_db; tool - and calling the &b-link-CompilationDatabase; builder - (available since 4.0). + This chapter shows some techniques for interacting with other + projects and tools effectively from within &SCons;. - +
+ Creating a Compilation Database - The compilation database can be populated with - source and target files either with paths relative - to the top of the build, or using absolute paths. - This is controlled by - COMPILATIONDB_USE_ABSPATH=(True|False) - which defaults to False. + - + Tooling to perform analysis and modification + of source code often needs to know not only the source code + itself, but also how it will be compiled, as the compilation line + affects the behavior of macros, includes, etc. &SCons; has a + record of this information once it has run, in the form of + Actions associated with the sources, and can emit this information + so tools can use it. + + + + + + The Clang project has defined a JSON Compilation Database. + This database is in common use as input into Clang tools + and many IDEs and editors as well. + See + + JSON Compilation Database Format Specification + + for complete information. &SCons; can emit a + compilation database in this format + by enabling the &t-link-compilation_db; tool + and calling the &b-link-CompilationDatabase; builder + (available since &scons; 4.0). + + + + + + The compilation database can be populated with + source and output files either with paths relative + to the top of the build, or using absolute paths. + This is controlled by + COMPILATIONDB_USE_ABSPATH=(True|False) + which defaults to False. + The entries in this file can be filtered by using + + COMPILATIONDB_PATH_FILTER='pattern' + where the filter pattern is a string following the &Python; + + fnmatch + + syntax. + This filtering can be used for outputting different + build variants to different compilation database files. + + + + - + The following example illustrates generating a compilation + database containing absolute paths: - Example of absolute paths for target and source: + - - - + + env = Environment(COMPILATIONDB_USE_ABSPATH=True) env.Tool('compilation_db') -env.CompilationDatabase('compile_commands.json') - +env.CompilationDatabase() +env.Program('hello.c') + + + int main(int argc, char* argv[]) + { + return 0; + } + + + + + scons -Q + + + + compile_commands.json + contains: + - + [ { - "command": "gcc -o test_main.o -c test_main.c", + "command": "gcc -o hello.o -c hello.c", "directory": "/home/user/sandbox", - "file": "/home/user/sandbox/test_main.c", - "target": "/home/user/sandbox/test_main.o" + "file": "/home/user/sandbox/hello.c", + "output": "/home/user/sandbox/hello.o" } ] - + - + - Example of relative paths for target and source: + Notice that the generated database contains only an entry for + the hello.c/hello.o pairing, + and nothing for the generation of the final executable + hello + - the transformation of + hello.o + to + hello + does not have any information that affects interpretation + of the source code, + so it is not interesting to the compilation database. + + + + + + Although it can be a little surprising at first glance, + a compilation database target is, like any other target, + subject to &scons; target selection rules. + This means if you set a default target (that does not + include the compilation database), or use command-line + targets, it might not be selected for building. + This can actually be an advantage, since you don't + necessarily want to regenerate the compilation database + every build. + The following example + shows selecting relative paths (the default) + for output and source, + and also giving a non-default name to the database. + In order to be able to generate the database separately from building, + an alias is set referring to the database, + which can then be used as a target - here we are only + building the compilation database target, not the code. - + - + + env = Environment() env.Tool('compilation_db') -env.CompilationDatabase('compile_commands.json') - - +cdb = env.CompilationDatabase('compile_database.json') +Alias('cdb', cdb) +env.Program('test_main.c') + + + #include "test_main.h" + int main(int argc, char* argv[]) + { + return 0; + } + + + /* dummy include file */ + + + + + scons -Q cdb + + + + compile_database.json contains: + + + [ { "command": "gcc -o test_main.o -c test_main.c", "directory": "/home/user/sandbox", "file": "test_main.c", - "target": "test_main.o" + "output": "test_main.o" + } +] + + + + The following (incomplete) example shows using filtering + to separate build variants. + In the case of using variants, + you want different compilation databases for each, + since the build parameters differ, so the code analysis + needs to see the correct build lines for the 32-bit build + and 64-bit build hinted at here. + For simplicity of presentation, + the example omits the setup details of the variant directories: + + + +env = Environment() +env.Tool("compilation_db") + +env1 = env.Clone() +env1["COMPILATIONDB_PATH_FILTER"] = "build/linux32/*" +env1.CompilationDatabase("compile_commands-linux32.json") + +env2 = env.Clone() +env2["COMPILATIONDB_PATH_FILTER"] = "build/linux64/*" +env2.CompilationDatabase('compile_commands-linux64.json') + + + + compile_commands-linux32.json + contains: + + + +[ + { + "command": "gcc -o hello.o -c hello.c", + "directory": "/home/mats/github/scons/exp/compdb", + "file": "hello.c", + "output": "hello.o" + } +] + + + + compile_commands-linux64.json contains: + + + +[ + { + "command": "gcc -m64 -o build/linux64/test_main.o -c test_main.c", + "directory": "/home/user/sandbox", + "file": "test_main.c", + "output": "build/linux64/test_main.o" } ] - + + +
+ +
+ Ninja Build Generator + + + This is an experimental new feature. + It is subject to change and/or removal without a depreciation cycle. + -
+ + Loading the &t-link-ninja; tool into SCons will make significant changes + in SCons' normal functioning. + + + + + SCons will no longer execute any commands directly and will only create the build.ninja and + run ninja. + + + + + Any targets specified on the command line will be passed along to &ninja; + + + + + To enable this feature you'll need to use one of the following: + + + +# On the command line --experimental=ninja + +# Or in your SConstruct +SetOption('experimental', 'ninja') + + + + + Ninja is a small build system that tries to be fast + by not making decisions. &SCons; can at times be slow + because it makes lots of decisions to carry out its goal + of "correctness". The two tools can be paired to benefit + some build scenarios: by using the &t-link-ninja; tool, + &SCons; can generate the build file &ninja; uses (basically + doing the decision-making ahead of time and recording that + for &ninja;), and can invoke &ninja; to perform a build. + For situations where relationships are not changing, such + as edit/build/debug iterations, this works fine and should + provide considerable speedups for more complex builds. + The implication is if there are larger changes taking place, + &ninja; is not as appropriate - but you can always use &SCons; + to regenerate the build file. You are NOT advised to use + this for production builds. + + + + To use the &t-link-ninja; tool you'll need to first install the + &Python; &ninja; package, as the tool depends on being able to do an + import of the package. + This can be done via: + + + +# In a virtualenv, or "python" is the native executable: +python -m pip install ninja + +# Windows using Python launcher: +py -m pip install ninja + +# Anaconda: +conda install -c conda-forge ninja + + + + Reminder that like any non-default tool, you need to initialize it before use + (e.g. env.Tool('ninja')). + + + + It is not expected that the &b-link-Ninja; builder will work for all builds at this point. It is still under active + development. If you find that your build doesn't work with &ninja; please bring this to the users mailing list + or + #scons-help + channel on our Discord server. + + + + Specifically if your build has many (or even any) &Python; function actions you may find that the &ninja; build + will be slower as it will run &ninja;, which will then run SCons for each target created by a &Python; action. + To alleviate some of these, especially those &Python; based actions built into SCons there is special logic to + implement those actions via shell commands in the &ninja; build file. + + + + When &ninja; runs the generated &ninja; build file, &ninja; will launch &scons; as a daemon and feed commands + to that &scons; process which &ninja; is unable to build directly. This daemon will stay alive until + explicitly killed, or it times out. The timeout is set by &cv-link-NINJA_SCONS_DAEMON_KEEP_ALIVE; . + + + + The daemon will be restarted if any &SConscript; file(s) change or the build changes in a way that &ninja; determines + it needs to regenerate the build.ninja file + + + See: + + + + + Ninja Build System + + + + + Ninja File Format Specification + + + +
diff -Nru scons-4.0.1+dfsg/doc/user/factories.xml scons-4.4.0+dfsg/doc/user/factories.xml --- scons-4.0.1+dfsg/doc/user/factories.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/factories.xml 2022-07-30 21:48:28.000000000 +0000 @@ -147,17 +147,20 @@ -Command("file.out", "file.in", - [ - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Copy("$TARGET", "tempfile"), - ]) +Command( + "file.out", + "file.in", + action=[ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ], +) + -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +def_env = DefaultEnvironment() +def_env.AppendENVPath('PATH', Dir('.')) SConscript('S') file.in @@ -216,18 +219,21 @@ -Command("file.out", "file.in", - [ - Delete("tempfile"), - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Copy("$TARGET", "tempfile"), - ]) +Command( + "file.out", + "file.in", + action=[ + Delete("tempfile"), + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ], +) + -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +def_env = DefaultEnvironment() +def_env.AppendENVPath('PATH', Dir('.')) SConscript('S') file.in @@ -257,11 +263,14 @@ -Command("file.out", "file.in", - [ - Delete("$TARGET"), - Copy("$TARGET", "$SOURCE") - ]) +Command( + "file.out", + "file.in", + action=[ + Delete("$TARGET"), + Copy("$TARGET", "$SOURCE"), + ], +) file.in @@ -311,17 +320,20 @@ -Command("file.out", "file.in", - [ - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Move("$TARGET", "tempfile"), - ]) +Command( + "file.out", + "file.in", + action=[ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Move("$TARGET", "tempfile"), + ], +) + -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +def_env = DefaultEnvironment() +def_env.AppendENVPath('PATH', Dir('.')) SConscript('S') file.in @@ -355,16 +367,16 @@ -Command("file.out", "file.in", - [ - Copy("$TARGET", "$SOURCE"), - Touch("$TARGET"), - ]) +Command( + "file.out", + "file.in", + action=[ + Copy("$TARGET", "$SOURCE"), + Touch("$TARGET"), + ] +) -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() SConscript('S') file.in @@ -399,20 +411,23 @@ -Command("file.out", "file.in", - [ - Delete("tempdir"), - Mkdir("tempdir"), - Copy("tempdir/${SOURCE.file}", "$SOURCE"), - "process tempdir", - Move("$TARGET", "tempdir/output_file"), - Delete("tempdir"), - ]) +Command( + "file.out", + "file.in", + action=[ + Delete("tempdir"), + Mkdir("tempdir"), + Copy("tempdir/${SOURCE.file}", "$SOURCE"), + "process tempdir", + Move("$TARGET", "tempdir/output_file"), + Delete("tempdir"), + ], +) + -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +def_env = DefaultEnvironment() +def_env.AppendENVPath('PATH', Dir('.')) SConscript('S') file.in @@ -449,11 +464,14 @@ -Command("file.out", "file.in", - [ - Copy("$TARGET", "$SOURCE"), - Chmod("$TARGET", 0o755), - ]) +Command( + "file.out", + "file.in", + action=[ + Copy("$TARGET", "$SOURCE"), + Chmod("$TARGET", 0o755), + ] +) file.in diff -Nru scons-4.0.1+dfsg/doc/user/file-removal.xml scons-4.4.0+dfsg/doc/user/file-removal.xml --- scons-4.0.1+dfsg/doc/user/file-removal.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/file-removal.xml 2022-07-30 21:48:28.000000000 +0000 @@ -202,10 +202,10 @@ t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE') Clean(t, 'foo.log') + -env = DefaultEnvironment() -import os -env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() +def_env = DefaultEnvironment() +def_env.AppendENVPath('PATH', Dir('.')) SConscript('S') diff -Nru scons-4.0.1+dfsg/doc/user/hierarchy.xml scons-4.4.0+dfsg/doc/user/hierarchy.xml --- scons-4.0.1+dfsg/doc/user/hierarchy.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/hierarchy.xml 2022-07-30 21:48:28.000000000 +0000 @@ -303,8 +303,7 @@ -SConscript(['prog1/SConscript', - 'prog2/SConscript']) +SConscript(['prog1/SConscript', 'prog2/SConscript']) env = Environment() @@ -384,7 +383,7 @@
- Top-Level Path Names in Subsidiary &SConscript; Files + Top-Relative Path Names in Subsidiary &SConscript; Files @@ -397,8 +396,7 @@ You can tell &SCons; to interpret a path name as relative to the top-level &SConstruct; directory, not the local directory of the &SConscript; file, - by appending a &hash; (hash mark) - to the beginning of the path name: + by prepending a &hash; (hash mark) in front of the path name: @@ -446,6 +444,52 @@ + + + A couple of notes on top-relative paths: + + + + + &SCons; doesn't care whether you add a slash after the &hash;. + Some people consider '#/lib/foo1.c' + more readable than '#lib/foo1.c', + but they're functionally equivalent. + + + + + + The top-relative syntax is only + evaluated by &SCons;, the &Python; language itself does not + understand about it. This becomes immediately obvious + if you like to use print for debugging, + or write a Python function that wants to evaluate a path. + You can force &SCons; to evaluate a top-relative path by + creating a Node object from it: + + + + + + + + +path = "#/include" + +print("path =", path) +print("force-interpreted path =", Entry(path)) + + + + Which shows: + + + scons -Q + + + +
diff -Nru scons-4.0.1+dfsg/doc/user/html.xsl scons-4.4.0+dfsg/doc/user/html.xsl --- scons-4.0.1+dfsg/doc/user/html.xsl 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/html.xsl 2022-07-30 21:48:28.000000000 +0000 @@ -25,11 +25,14 @@ --> + + @@ -64,4 +67,87 @@ + + + + + + + + + + <xsl:copy-of select="$title"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru scons-4.0.1+dfsg/doc/user/java.xml scons-4.4.0+dfsg/doc/user/java.xml --- scons-4.0.1+dfsg/doc/user/java.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/java.xml 2022-07-30 21:48:28.000000000 +0000 @@ -270,7 +270,7 @@ After building the class files, it's common to collect them into a Java archive (.jar) file, - which you do by calling the &b-link-Jar; Builder method. + which you do by calling the &b-link-Jar; Builder. If you want to just collect all of the class files within a subdirectory, you can just specify that subdirectory @@ -488,8 +488,8 @@ Although it's more convenient to use the list of class files returned by - the &b-Java; Builder - as the source of a call to the &b-JavaH; Builder, + the &b-link-Java; Builder + as the source of a call to the &b-link-JavaH; Builder, you can specify the list of class files by hand, if you prefer. @@ -502,11 +502,13 @@ -Java(target = 'classes', source = 'src/pkg/sub') -class_file_list = ['classes/pkg/sub/Example1.class', - 'classes/pkg/sub/Example2.class', - 'classes/pkg/sub/Example3.class'] -JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes') +Java(target='classes', source='src/pkg/sub') +class_file_list = [ + 'classes/pkg/sub/Example1.class', + 'classes/pkg/sub/Example2.class', + 'classes/pkg/sub/Example3.class', +] +JavaH(target='native', source=class_file_list, JAVACLASSDIR='classes') package pkg.sub; @@ -560,8 +562,8 @@ -classes = Java(target = 'classes', source = 'src/pkg/sub') -JavaH(target = File('native.h'), source = classes) +classes = Java(target='classes', source='src/pkg/sub') +JavaH(target=File('native.h'), source=classes) package pkg.sub; @@ -595,7 +597,7 @@ Because &SCons; assumes by default - that the target of the &b-JavaH; builder is a directory, + that the target of the &b-link-JavaH; builder is a directory, you need to use the &File; function to make sure that &SCons; doesn't create a directory named native.h. @@ -609,6 +611,17 @@ scons -Q + + + Note that the the javah command was + removed from the JDK as of JDK 10, and the approved method + (available since JDK 8) is to use javac + to generate native headers at the same time as the Java source + code is compiled.. As such the &b-link-JavaH; builder + is of limited utility in later Java versions. + + +
diff -Nru scons-4.0.1+dfsg/doc/user/less-simple.xml scons-4.4.0+dfsg/doc/user/less-simple.xml --- scons-4.0.1+dfsg/doc/user/less-simple.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/less-simple.xml 2022-07-30 21:48:28.000000000 +0000 @@ -189,7 +189,7 @@ (&SCons; puts the output file name to the left of the source file names so that the order mimics that of an - assignment statement: "program = source files".) + assignment statement: program = source files.) This makes our example: @@ -462,31 +462,29 @@ &SCons; also allows you to identify the output file and input source files - using Python keyword arguments. - The output file is known as the - target, - and the source file(s) are known (logically enough) as the - source. + using Python keyword arguments + target and + source. The Python syntax for this is: src_files = Split('main.c file1.c file2.c') -Program(target = 'program', source = src_files) +Program(target='program', source=src_files) Because the keywords explicitly identify - what each argument is, - you can actually reverse the order if you prefer: + what each argument is, the order does + not matter and you can reverse it if you prefer: src_files = Split('main.c file1.c file2.c') -Program(source = src_files, target = 'program') +Program(source=src_files, target='program') @@ -644,65 +642,6 @@ -
- -
- Overriding construction variables when calling a Builder - - - - It is possible to override or add construction variables - when calling a builder method by passing additional keyword arguments. - These overridden or added variables will only be in effect when - building the target, so they will not affect other parts of the build. - For example, if you want to add additional libraries for just one program: - - - - -env.Program('hello', 'hello.c', LIBS=['gl', 'glut']) - - - - - or generate a shared library with a non-standard suffix: - - - - -env.SharedLibrary('word', 'word.cpp', - SHLIBSUFFIX='.ocx', - LIBSUFFIXES=['.ocx']) - - - - - It is also possible to use the parse_flags - keyword argument in an override to merge command-line - style arguments into the appropriate construction - variables (see &f-link-env-MergeFlags;). - - - - - - This example adds 'include' to &cv-link-CPPPATH;, - 'EBUG' to &cv-link-CPPDEFINES;, and 'm' to &cv-link-LIBS;. - - - - -env = Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm') - - - - - Within the call to the builder action the environment is not cloned, - instead an OverrideEnvironment() is created which is more - light weight than a whole Environment() - - -
diff -Nru scons-4.0.1+dfsg/doc/user/main.xml scons-4.4.0+dfsg/doc/user/main.xml --- scons-4.0.1+dfsg/doc/user/main.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/main.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,7 +1,9 @@ - This chapter describes the &MergeFlags;, &ParseFlags;, and &ParseConfig; methods of a &consenv;. + This chapter describes the &MergeFlags;, &ParseFlags;, and &ParseConfig; + methods of a &consenv;, as well as the parse_flags + keyword argument to methods that construct environments. + - @@ -104,60 +100,34 @@ - - - - - + + - - - + - - - - + + - + - + + + + + diff -Nru scons-4.0.1+dfsg/doc/user/MANIFEST scons-4.4.0+dfsg/doc/user/MANIFEST --- scons-4.0.1+dfsg/doc/user/MANIFEST 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/MANIFEST 2022-07-30 21:48:28.000000000 +0000 @@ -13,7 +13,6 @@ caching.xml command-line.xml cons.pl -copyright.xml depends.xml environments.xml errors.xml @@ -36,6 +35,7 @@ output.xml parseconfig.xml parseflags.xml +parse_flags_arg.xml preface.xml python.xml repositories.xml @@ -43,6 +43,7 @@ scanners.xml sconf.xml separate.xml +sideeffect.xml simple.xml tasks.xml tools.xml diff -Nru scons-4.0.1+dfsg/doc/user/mergeflags.xml scons-4.4.0+dfsg/doc/user/mergeflags.xml --- scons-4.0.1+dfsg/doc/user/mergeflags.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/mergeflags.xml 2022-07-30 21:48:28.000000000 +0000 @@ -2,7 +2,7 @@ %scons; - + %builders-mod; @@ -21,7 +21,9 @@ is an internal &SCons; object which automatically converts - the options we specified as a string into a list. + the options you specify as a string into a list. env = Environment() -env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) -flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] } +env.Append(CPPPATH=['/include', '/usr/local/include', '/usr/include']) +flags = {'CPPPATH': ['/usr/opt/include', '/usr/local/include']} env.MergeFlags(flags) -print(env['CPPPATH']) +print("CPPPATH:", env['CPPPATH']) @@ -119,9 +126,9 @@ [TODO: for when we make CLVar public] is a Python list, not a CLVar, --> - is a normal Python list, - so we must specify its values as a list - in the dictionary we pass to the &MergeFlags; function. + is a normal &Python; list, + so you should give its values as a list + in the dictionary you pass to the &MergeFlags; function. @@ -135,11 +142,11 @@ env = Environment() -env.Append(CCFLAGS = '-option -O3 -O1') -env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) +env.Append(CCFLAGS='-option -O3 -O1') +env.Append(CPPPATH=['/include', '/usr/local/include', '/usr/include']) env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include') -print(env['CCFLAGS']) -print(env['CPPPATH']) +print("CCFLAGS:", env['CCFLAGS']) +print("CPPPATH:", env['CPPPATH']) @@ -152,8 +159,8 @@ In the combined example above, &ParseFlags; has sorted the options into their corresponding variables and returned a dictionary for &MergeFlags; to apply - to the construction variables - in the specified construction environment. + to the &consvars; + in the specified &consenv;. diff -Nru scons-4.0.1+dfsg/doc/user/misc.xml scons-4.4.0+dfsg/doc/user/misc.xml --- scons-4.0.1+dfsg/doc/user/misc.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/misc.xml 2022-07-30 21:48:28.000000000 +0000 @@ -625,6 +625,9 @@
+ + +
Virtual environments (virtualenvs) diff -Nru scons-4.0.1+dfsg/doc/user/nodes.xml scons-4.4.0+dfsg/doc/user/nodes.xml --- scons-4.0.1+dfsg/doc/user/nodes.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/nodes.xml 2022-07-30 21:48:28.000000000 +0000 @@ -21,26 +21,28 @@ diff -Nru scons-4.0.1+dfsg/doc/user/output.xml scons-4.4.0+dfsg/doc/user/output.xml --- scons-4.0.1+dfsg/doc/user/output.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/output.xml 2022-07-30 21:48:28.000000000 +0000 @@ -197,7 +197,7 @@
-
+
Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables diff -Nru scons-4.0.1+dfsg/doc/user/parseconfig.xml scons-4.4.0+dfsg/doc/user/parseconfig.xml --- scons-4.0.1+dfsg/doc/user/parseconfig.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/parseconfig.xml 2022-07-30 21:48:28.000000000 +0000 @@ -2,7 +2,7 @@ %scons; - + %builders-mod; @@ -21,7 +21,9 @@ + + + + It is also possible to merge &consvar; values from arguments + given to the &f-link-Environment; call itself. + If the parse_flags keyword argument + is given, its value is distributed to &consvars; in the + new environment in the same way as + described for the &MergeFlags; method. + This also works when calling &f-link-env-Clone;, + as well as in overrides to builder methods + (see ). + + + + + +env = Environment(parse_flags="-I/opt/include -L/opt/lib -lfoo") +for k in ('CPPPATH', 'LIBPATH', 'LIBS'): + print("%s:" % k, env.get(k)) +env.Program("f1.c") + + +int main() { return 0; } + + + + + scons -Q + + +
diff -Nru scons-4.0.1+dfsg/doc/user/parseflags.xml scons-4.4.0+dfsg/doc/user/parseflags.xml --- scons-4.0.1+dfsg/doc/user/parseflags.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/parseflags.xml 2022-07-30 21:48:28.000000000 +0000 @@ -2,7 +2,7 @@ %scons; - + %builders-mod; @@ -21,7 +21,9 @@ - +
+ How to Use this Guide - XXX history of SCons + This guide intends to coach you how to use &SCons; effectively + and efficiently, by providing a range of examples and usage scenarios. + As such it is not exactly a tutorial (as usually those build + a single example topic from start to finish), but if you are + just starting with &SCons; it is recommended + you step through the first 10 chapters + in sequence as this will give a solid + grounding in the principles of working with &SCons;. + If you follow that trail, you can feel free to initially skip + sections on extending &SCons;, such as + Writing your own Decider Function, + and come back to those if the need arises. -
- - --> + - -
A Caveat About This Guide's Completeness - One word of warning as you read through this Guide: - Like too much Open Source software out there, - the &SCons; documentation isn't always - kept up-to-date with the available features. - In other words, - there's a lot that &SCons; can do that + &SCons; is a volunteer-run open source project. + As such, the &SCons; documentation isn't always + completely up-to-date with all the available features - + somehow it's almost harder to write high quality, easy to + use documentation than it is to implement a feature in software. + In other words, there may be a lot that &SCons; can do that isn't yet covered in this User's Guide. - (Come to think of it, - that also describes a lot of proprietary software, doesn't it?) - Although this User's Guide isn't as complete as we'd like it to be, - our development process does emphasize + Although this User's Guide may not be as complete as it could be, + the development process does emphasize making sure that the &SCons; man page is kept up-to-date with new features. So if you're trying to figure out how to do something @@ -418,7 +427,6 @@ The best way to contact people involved with SCons, - including the author, is through the SCons mailing lists. @@ -439,8 +447,17 @@ - If you want to receive announcements about &SCons;, - join the low-volume &scons-announce; mailing list. + For quicker, informal questions, discussion, etc. the project + operated a Discord server at + + and a Libera.chat IRC channel at + + (the former channel at irc.freenode.net is now unused). + Certain discussions may also be moved by administrators from + mailing list or chat to + + GitHub Discussions for greater permanence and easier + finding. diff -Nru scons-4.0.1+dfsg/doc/user/scanners.xml scons-4.4.0+dfsg/doc/user/scanners.xml --- scons-4.0.1+dfsg/doc/user/scanners.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/scanners.xml 2022-07-30 21:48:28.000000000 +0000 @@ -17,11 +17,13 @@ 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"> -Writing Scanners +Extending &SCons;: Writing Your Own Scanners - + + + You can enable this separation by establishing one or more + variant directory trees + that are used to perform the build in, and thus provide a unique + home for object files, libraries, and executable programs, etc. + for a specific flavor, or variant, of build. &SCons; tracks + targets by their path, so when the variant directory is included, + objects belonging to "Controller A" can have different + build instructions than those belonging to "Controller B" without + triggering ping-ponging rebuilds. + + - 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 - variant directory 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. - 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. @@ -162,11 +106,11 @@ 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: @@ -193,20 +137,25 @@ ls src scons -Q + ls src ls build - 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 build/hello.o - in the &build; subdirectory, + and the executable file + build/hello + 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 build/hello.c file - to create the object file. + to create the object file, + and that file is now seen in &build;. @@ -215,7 +164,7 @@ What's happened is that &SCons; has duplicated 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. @@ -227,13 +176,13 @@ - &SCons; duplicates source files in variant directory trees - because it's the most straightforward way to guarantee a correct build - regardless of include-file directory paths, - relative references between files, - or tool support for putting files in different locations, - 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 in that directory. + 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. @@ -312,13 +261,13 @@ duplicating the source files and everything will work just fine. You can disable the default &SCons; behavior - by specifying duplicate=0 + by specifying duplicate=False when you call the &SConscript; function: -SConscript('src/SConscript', variant_dir='build', duplicate=0) +SConscript('src/SConscript', variant_dir='build', duplicate=False) @@ -395,14 +344,14 @@ - You can specify the same duplicate=0 argument + You can specify the same duplicate=False argument that you can specify for an &SConscript; call: -VariantDir('build', 'src', duplicate=0) +VariantDir('build', 'src', duplicate=False) env = Environment() env.Program('build/hello.c') @@ -432,8 +381,10 @@ 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 src/SConscript looks like this: @@ -490,7 +441,7 @@ - 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 src/SConscript @@ -558,4 +509,6 @@ --> + + diff -Nru scons-4.0.1+dfsg/doc/user/sideeffect.xml scons-4.4.0+dfsg/doc/user/sideeffect.xml --- scons-4.0.1+dfsg/doc/user/sideeffect.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/user/sideeffect.xml 2022-07-30 21:48:28.000000000 +0000 @@ -2,7 +2,7 @@ %scons; - + %builders-mod; @@ -13,11 +13,11 @@ %variables-mod; ]> - -Sideeffect files +Declaring Additional Outputs: the &f-SideEffect; Function - - The &variant_dir; keyword argument of @@ -76,9 +52,15 @@ 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 variant_dir + path dynamically: @@ -90,13 +72,15 @@ 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 @@ scons -Q OS=windows - - +
diff -Nru scons-4.0.1+dfsg/doc/version.xml scons-4.4.0+dfsg/doc/version.xml --- scons-4.0.1+dfsg/doc/version.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/doc/version.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,7 +1,7 @@ - - - - + + + + diff -Nru scons-4.0.1+dfsg/.github/ISSUE_TEMPLATE/config.yml scons-4.4.0+dfsg/.github/ISSUE_TEMPLATE/config.yml --- scons-4.0.1+dfsg/.github/ISSUE_TEMPLATE/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/.github/ISSUE_TEMPLATE/config.yml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +blank_issues_enabled: false diff -Nru scons-4.0.1+dfsg/.github/workflows/experimental_tests.yml scons-4.4.0+dfsg/.github/workflows/experimental_tests.yml --- scons-4.0.1+dfsg/.github/workflows/experimental_tests.yml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/.github/workflows/experimental_tests.yml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,50 @@ +# This is a basic workflow to help you get started with Actions + +name: Test Experimental Features + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + + strategy: + matrix: + os: ['ubuntu-latest', 'windows-latest'] + + # The type of runner that the job will run on + runs-on: ${{ matrix.os }} + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up MinGW + uses: egor-tensin/setup-mingw@v2 + if: matrix.os == 'windows-latest' + with: + platform: x64 + + - name: Set up Python 3.8 ${{ matrix.os }} + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies including ninja ${{ matrix.os }} + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install ninja psutil + # sudo apt-get update + - name: Test experimental packages ${{ matrix.os }} + run: | + python runtest.py test/import.py test/ninja diff -Nru scons-4.0.1+dfsg/.github/workflows/runtest.yml scons-4.4.0+dfsg/.github/workflows/runtest.yml --- scons-4.0.1+dfsg/.github/workflows/runtest.yml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/.github/workflows/runtest.yml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,50 @@ +# This is a basic workflow to help you get started with Actions + +name: Linux Testing + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + + strategy: + matrix: + os: ['ubuntu-latest'] + + # The type of runner that the job will run on + runs-on: ${{ matrix.os }} + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Python 3.8 ${{ matrix.os }} + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies including ninja ${{ matrix.os }} + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install ninja psutil + # sudo apt-get update + - name: runtest ${{ matrix.os }} + run: | + python runtest.py -a -j 2 + - name: Archive Failed tests + uses: actions/upload-artifact@v2 + with: + name: linux-failed-tests + path: | + failed_tests.log diff -Nru scons-4.0.1+dfsg/.github/workflows/scons-package.yml scons-4.4.0+dfsg/.github/workflows/scons-package.yml --- scons-4.0.1+dfsg/.github/workflows/scons-package.yml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/.github/workflows/scons-package.yml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,51 @@ +# This action builds SCons, mainly to make sure the docs generate. + +name: SCons Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + #python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + sudo apt-get update + sudo apt-get -y install docbook-xml docbook-xsl xsltproc fop docbook-xsl-doc-pdf + # try to keeo the texlive install as small as we can to save some time/space + sudo apt-get -y --no-install-recommends install texlive biber texmaker ghostscript texlive-latex-base texlive-latex-extra texlive-bibtex-extra texlive-font-utils latexmk + # This is disabled until the run can be configured to only + # check the code that matters, else we fail on non-essentials + # like the bench/ stuff. + #- name: Lint with flake8 + # run: | + # # stop the build if there are Python syntax errors or undefined names + # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Update Doc sources (some parts are generated) + run: | + python bin/docs-update-generated.py + python bin/docs-validate.py + python bin/docs-create-example-outputs.py + - name: Build SCons packages + run: | + python scripts/scons.py + - name: Verify package + run: | + ls -l build/dist + python build/scons-local/scons.py --version diff -Nru scons-4.0.1+dfsg/.gitignore scons-4.4.0+dfsg/.gitignore --- scons-4.0.1+dfsg/.gitignore 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.gitignore 2022-07-30 21:48:28.000000000 +0000 @@ -34,7 +34,7 @@ # SCons files -.sconsign.* +.sconsign* # Tool output .coverage @@ -52,3 +52,7 @@ # Mac junk **/.DS_Store + + +# SCons specific +*.1 diff -Nru scons-4.0.1+dfsg/lgtm.yml scons-4.4.0+dfsg/lgtm.yml --- scons-4.0.1+dfsg/lgtm.yml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/lgtm.yml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,135 @@ +########################################################################################## +# Customize file classifications. # +# Results from files under any classifier will be excluded from LGTM # +# statistics. # +########################################################################################## + +########################################################################################## +# Use the `path_classifiers` block to define changes to the default classification of # +# files. # +########################################################################################## + +path_classifiers: + docs: + - doc + - bin + test: + # Override LGTM's default classification of test files by excluding all files. + - exclude: / + # Classify all files in the top-level directories test/ and testing/ as test code. + - test + - testing + # Classify all files with suffix `.Test.py` as test code. + - "**/*.Test.py" + # and the test runner + - runtest.py + # The default behavior is to tag all files created during the + # build as `generated`. Results are hidden for generated code. You can tag + # further files as being generated by adding them to the `generated` section. + generated: + - build + # By default, all files not checked into the repository are considered to be + # 'generated'. + # The default behavior is to tag library code as `library`. Results are hidden + # for library code. You can tag further files as being library code by adding them + # to the `library` section. + library: + - exclude: path/to/libary/code/**/*.c + # The default behavior is to tag template files as `template`. Results are hidden + # for template files. You can tag further files as being template files by adding + # them to the `template` section. + template: + - template + # Define your own category, for example: 'some_custom_category'. + bench: + - bench + - timings + +######################################################################################### +# Define changes to the default code extraction process. # +# Each block configures the extraction of a single language, and modifies actions in a # +# named step. Every named step includes automatic default actions, # +# except for the 'prepare' step. The steps are performed in the following sequence: # +# prepare # +# after_prepare # +# configure (C/C++ only) # +# python_setup (Python only) # +# before_index # +# index # +########################################################################################## + +######################################################################################### +# Environment variables available to the steps: # +######################################################################################### + +# LGTM_SRC +# The root of the source tree. +# LGTM_WORKSPACE +# An existing (initially empty) folder outside the source tree. +# Used for temporary download and setup commands. + +######################################################################################### +# Use the extraction block to define changes to the default code extraction process # +# for one or more languages. The settings for each language are defined in a child # +# block, with one or more steps. # +######################################################################################### + +extraction: + javascript: + # The `prepare` step exists for customization on LGTM.com only. + # prepare: + # packages: + # - example_package + # Add an `after-prepare` step if you need to run commands after the prepare step. + # Each command should be listed on a separate line. + after_prepare: + - export PATH=$LGTM_WORKSPACE/tools:$PATH + # The `index` step extracts information from the files in the codebase. + index: + # Specify a list of files and folders to extract. + # Default: The project root directory. + include: + - src/js + # Specify a list of files and folders to exclude from extraction. + exclude: + - SCons/Tool/docbook/docbook-xsl-1.76.1 + + # Define settings for Python analysis + ###################################### + python: + # The `prepare` step exists for customization on LGTM.com only. + # prepare: + # # The `packages` section is valid for LGTM.com only. It names packages to + # # be installed. + # packages: libpng-dev + # This step is useful for Python analysis where you want to prepare the + # environment for the `python_setup` step without changing the default behavior + # for that step. + after_prepare: + - export PATH=$LGTM_WORKSPACE/tools:$PATH + # This sets up the Python interpreter and virtual environment, ready for the + # `index` step to extract the codebase. + python_setup: + # Specify packages that should NOT be installed despite being mentioned in the + # requirements.txt file. + # Default: no package marked for exclusion. + exclude_requirements: + - pywin32 + - readme-renderer + - sphinx<3.5.0 + - sphinx_rtd_theme + - lxml==4.6.3 + - rst2pdf + # Specify a list of pip packages to install. + # If any of these packages cannot be installed, the extraction will fail. + requirements: + #- Pillow + # Specify a list of requirements text files to use to set up the environment, + # or false for none. Default: any requirements.txt, test-requirements.txt, + # and similarly named files identified in the codebase are used. + requirements_files: + - required-packages.txt + # Specify a setup.py file to use to set up the environment, or false for none. + # Default: any setup.py files identified in the codebase are used in preference + # to any requirements text files. + #setup_py: new-setup.py diff -Nru scons-4.0.1+dfsg/LICENSE scons-4.4.0+dfsg/LICENSE --- scons-4.0.1+dfsg/LICENSE 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/LICENSE 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2001 - 2020 The SCons Foundation +Copyright (c) 2001 - 2021 The SCons Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff -Nru scons-4.0.1+dfsg/MANIFEST.in scons-4.4.0+dfsg/MANIFEST.in --- scons-4.0.1+dfsg/MANIFEST.in 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/MANIFEST.in 2022-07-30 21:48:28.000000000 +0000 @@ -3,6 +3,8 @@ # For license file include LICENSE +include scons.1 sconsign.1 scons-time.1 +recursive-include build/doc/man *.1 diff -Nru scons-4.0.1+dfsg/README-local scons-4.4.0+dfsg/README-local --- scons-4.0.1+dfsg/README-local 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/README-local 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,3 @@ -# __COPYRIGHT__ SCons - a software construction tool @@ -47,6 +46,9 @@ Running SCons requires Python 3.5 or higher. There should be no other dependencies or requirements to run SCons. +As of SCons 4.2.0 support for Python 3.5 is deprecated and will be removed +with the next major release. + The default SCons configuration assumes use of the Microsoft Visual C++ compiler suite on WIN32 systems (either through the Visual Studio product, or through the separate Build Tools), and assumes a C compiler diff -Nru scons-4.0.1+dfsg/README-package.rst scons-4.4.0+dfsg/README-package.rst --- scons-4.0.1+dfsg/README-package.rst 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/README-package.rst 2022-07-30 21:48:28.000000000 +0000 @@ -1,8 +1,8 @@ -SCons - a software construction tool +SCons - a Software Construction Tool #################################### .. image:: https://img.shields.io/badge/IRC-scons-blue.svg - :target: http://webchat.freenode.net/?channels=%23scons&uio=d4 + :target: https://web.libera.chat/#scons :alt: IRC .. image:: https://img.shields.io/sourceforge/dm/scons.svg @@ -13,8 +13,8 @@ :target: https://sourceforge.net/projects/scons :alt: Sourceforge Total Downloads -.. image:: https://travis-ci.org/SCons/scons.svg?branch=master - :target: https://travis-ci.org/SCons/scons +.. image:: https://travis-ci.com/SCons/scons.svg?branch=master + :target: https://travis-ci.com/SCons/scons :alt: Travis CI build status .. image:: https://ci.appveyor.com/api/projects/status/github/SCons/scons?svg=true&branch=master @@ -25,38 +25,111 @@ :target: https://codecov.io/gh/SCons/scons :alt: CodeCov Coverage Status -About SCons ------------ +.. image:: https://github.com/SCons/scons/workflows/SCons%20Build/badge.svg + :target: https://github.com/SCons/scons/actions?query=workflow%3A%22SCons+Build%22 + :alt: Github Actions -This is SCons, a tool for building software (and other files). SCons is -implemented in Python, and its "configuration files" are actually Python -scripts, allowing you to use the full power of a real scripting language -to solve build problems. You do not, however, need to know Python to -use SCons effectively. -Documentation -------------- +What is SCons? +============== -Documentation for SCons is available at: +SCons is an Open Source software construction tool which orchestrates the construction of software +(and other tangible products such as documentation files) by determining which +component pieces must be built or rebuilt and invoking the necessary +commands to build them. + + +Features: + + * Configuration files are Python scripts - + use the power of a real programming language + to solve build problems; no complex domain-specific language to learn. + * Reliable, automatic dependency analysis built-in for C, C++ and Fortran. + No more "make depend" or "make clean" to get all of the dependencies. + Dependency analysis is easily extensible through user-defined + dependency Scanners for other languages or file types. + * Built-in support for C, C++, D, Java, Fortran, Yacc, Lex, Qt and SWIG, + and building TeX and LaTeX documents. + Easily extensible through user-defined Builders for other languages + or file types. + * Building from central repositories of source code and/or pre-built targets. + * Built-in support for Microsoft Visual Studio, including generation of + .dsp, .dsw, .sln and .vcproj files. + * Reliable detection of build changes using cryptographic hashes; + optionally can configure other algorithms including traditional timestamps. + * Support for parallel builds - can keep multiple jobs running + simultaneously regardless of directory hierarchy. + * Integrated Autoconf-like support for finding #include files, libraries, + functions and typedefs. + * Global view of all dependencies - no more multiple build passes or + reordering targets to build everything. + * Ability to share built files in a cache to speed up multiple builds. + * Designed from the ground up for cross-platform builds, and known to + work on Linux, other POSIX systems (including AIX, BSD systems, + HP/UX, IRIX and Solaris), Windows 7/8/10, MacOS, and OS/2. + * Written in Python. - http://www.scons.org/documentation.html -Requirements ------------- +Documentation +============= -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. +Documentation for SCons is available at +http://www.scons.org/documentation.html. +Execution Requirements +====================== + +Running SCons requires Python 3.6 or higher. There should be no other +dependencies or requirements to run standard SCons. +The last release to support Python 3.5 was 4.2.0. + +Some experimental features may require additional Python packages +to be installed - at the moment the Ninja feature requires the +supporting `ninja package `_. + +The default SCons configuration assumes use of the Microsoft Visual C++ +compiler suite on Win32 systems, and assumes a C compiler named ``cc``, a C++ +compiler named ``c++``, and a Fortran compiler named ``gfortran`` (such as found +in the GNU Compiler Collection) on any other type of system. You may +override these default values by appropriate configuration of variables +in a Construction Environment, or in the case of Cygwin on a Win32 system, +by selecting the 'cygwin' platform, which will set some of those Construction +Variables for you. + By default, SCons knows how to search for available programming tools on -various systems--see the SCons man page for details. You may, of course, -override the default SCons choices made by appropriate configuration of -Environment construction variables. +various systems - see the +`SCons man page `_ +for details. You can override +the default SCons choices made by appropriate configuration of +construction variables. -Licensing -========= +Installation Requirements +========================= + +SCons has no installation dependencies beyond a compatible version +of Python. The tools which will be used to to actually construct the +project, such as compilers, documentation production tools, etc. +should of course be installed by the appropriate means. + + +Getting Started Using SCons +=========================== + +If you're new to SCons, the first couple of chapters of the +`SCons User Guide `_ +provide an excellent starting spot. + + +Contributing to SCons +===================== + +Please see `CONTRIBUTING `_. + + +License +======= SCons is distributed under the MIT license, a full copy of which is available in the LICENSE file. @@ -68,13 +141,10 @@ The SCons project welcomes bug reports and feature requests. Please make sure you send email with the problem or feature request to -the SCons users mailing list: - - Join via: http://two.pairlist.net/mailman/listinfo/scons-users - -Or the SCons Discord server #scons-help channel - - Server URL: https://discord.gg/bXVpWAy +the SCons users mailing list, which you can join at +https://two.pairlist.net/mailman/listinfo/scons-users, +or on the SCons Discord server in +`#scons-help `_. Once you have discussed your issue on the users mailing list and the community has confirmed that it is either a new bug or a duplicate of an @@ -82,22 +152,18 @@ to file a new bug or to add yourself to the CC list for an existing bug You can explore the list of existing bugs, which may include workarounds -for the problem you've run into on GitHub Issues: - - https://github.com/SCons/scons/issues +for the problem you've run into, on the +`GitHub issue tracker `_. Mailing Lists ============= An active mailing list for developers of SCons is available. You may -send questions or comments to the list at: +send questions or comments to the list at scons-dev@scons.org. - scons-dev@scons.org - -You may subscribe to the developer's mailing list using form on this page: - - http://two.pairlist.net/mailman/listinfo/scons-dev +You may subscribe to the developer's mailing list using the form at +https://two.pairlist.net/mailman/listinfo/scons-dev. Subscription to the developer's mailing list is by approval. In practice, no one is refused list membership, but we reserve the right to limit membership @@ -113,22 +179,15 @@ If you find SCons helpful, please consider making a donation (of cash, software, or hardware) to support continued work on the project. Information -is available at: - - http://www.scons.org/donate.html - -or via GitHub Sponsors button on - - https://github.com/scons/scons +is available at https://www.scons.org/donate.html +or the GitHub Sponsors button on https://github.com/scons/scons. For More Information ==================== -Check the SCons web site at: - - http://www.scons.org/ +Check the SCons web site at https://www.scons.org/ -Copyright (c) 2001 - 2020 The SCons Foundation +Copyright (c) 2001 - 2021 The SCons Foundation diff -Nru scons-4.0.1+dfsg/README.rst scons-4.4.0+dfsg/README.rst --- scons-4.0.1+dfsg/README.rst 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/README.rst 2022-07-30 21:48:28.000000000 +0000 @@ -1,8 +1,8 @@ -SCons - a software construction tool +SCons - a Software Construction Tool #################################### .. image:: https://img.shields.io/badge/IRC-scons-blue.svg - :target: http://webchat.freenode.net/?channels=%23scons&uio=d4 + :target: https://web.libera.chat/#scons :alt: IRC .. image:: https://img.shields.io/sourceforge/dm/scons.svg @@ -13,8 +13,8 @@ :target: https://sourceforge.net/projects/scons :alt: Sourceforge Total Downloads -.. image:: https://travis-ci.org/SCons/scons.svg?branch=master - :target: https://travis-ci.org/SCons/scons +.. image:: https://travis-ci.com/SCons/scons.svg?branch=master + :target: https://travis-ci.com/SCons/scons :alt: Travis CI build status .. image:: https://ci.appveyor.com/api/projects/status/github/SCons/scons?svg=true&branch=master @@ -25,528 +25,176 @@ :target: https://codecov.io/gh/SCons/scons :alt: CodeCov Coverage Status +.. image:: https://github.com/SCons/scons/workflows/SCons%20Build/badge.svg + :target: https://github.com/SCons/scons/actions?query=workflow%3A%22SCons+Build%22 + :alt: Github Actions -Welcome to the SCons development tree. The real purpose of this tree is to -package SCons for production distribution in a variety of formats, not just to -hack SCons code. - -If all you want to do is install and run SCons, it will be easier for you to -download and install the scons-{version}.tar.gz or scons-{version}.zip package -rather than to work with the packaging logic in this tree. - -To the extent that this tree is about building SCons packages, the *full* -development cycle is not just to test the code directly, but to package SCons, -unpack the package, "install" SCons in a test subdirectory, and then to run -the tests against the unpacked and installed software. This helps eliminate -problems caused by, for example, failure to update the list of files to be -packaged. - -For just working on making an individual change to the SCons source, however, -you don't actually need to build or install SCons; you *can* actually edit and -execute SCons in-place. See the following sections below for more -information: - - `Making Changes`_ - How to edit and execute SCons in-place. - - `Debugging`_ - Tips for debugging problems in SCons. - - `Testing`_ - How to use the automated regression tests. - - `Development Workflow`_ - An example of how to put the edit/execute/test pieces - together in a reasonable development workflow. + +What is SCons? +============== + +SCons is an Open Source software construction tool which orchestrates the construction of software +(and other tangible products such as documentation files) by determining which +component pieces must be built or rebuilt and invoking the necessary +commands to build them. + + +Features: + + * Configuration files are Python scripts - + use the power of a real programming language + to solve build problems; no complex domain-specific language to learn. + * Reliable, automatic dependency analysis built-in for C, C++ and FORTRAN. + No more "make depend" or "make clean" to get all of the dependencies. + Dependency analysis is easily extensible through user-defined + dependency Scanners for other languages or file types. + * Built-in support for C, C++, D, Java, FORTRAN, Yacc, Lex, Qt and SWIG, + and building TeX and LaTeX documents. + Easily extensible through user-defined Builders for other languages + or file types. + * Building from central repositories of source code and/or pre-built targets. + * Built-in support for Microsoft Visual Studio, including generation of + .dsp, .dsw, .sln and .vcproj files. + * Reliable detection of build changes using cryptographic hashes; + optionally can configure other algorithms including traditional timestamps. + * Support for parallel builds - can keep multiple jobs running + simultaneously regardless of directory hierarchy. + * Integrated Autoconf-like support for finding #include files, libraries, + functions and typedefs. + * Global view of all dependencies - no more multiple build passes or + reordering targets to build everything. + * Ability to share built files in a cache to speed up multiple builds. + * Designed from the ground up for cross-platform builds, and known to + work on Linux, other POSIX systems (including AIX, BSD systems, + HP/UX, IRIX and Solaris), Windows 7/8/10, MacOS, and OS/2. + * Written in Python. + + +Documentation +============= + +Documentation for SCons is available at +http://www.scons.org/documentation.html. Latest Version ============== -Before going further, you can check that the package you have is the latest -version at the SCons download page: - - http://www.scons.org/pages/download.html +If you already have SCons installed, you can check that the package you have +is the latest version at the +`SCons download page `_. 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. +Running SCons requires Python 3.6 or higher. There should be no other +dependencies or requirements to run standard SCons. +The last release to support Python 3.5 was 4.2.0. + +Some experimental features may require additional Python packages +to be installed - at the moment the Ninja feature requires the +supporting `ninja package `_. The default SCons configuration assumes use of the Microsoft Visual C++ -compiler suite on Win32 systems, and assumes a C compiler named 'cc', a C++ -compiler named 'c++', and a Fortran compiler named 'gfortran' (such as found -in the GNU C compiler suite) on any other type of system. You may, of course, -override these default values by appropriate configuration of Environment -construction variables. +compiler suite on Win32 systems, and assumes a C compiler named ``cc``, a C++ +compiler named ``c++``, and a FORTRAN compiler named ``gfortran`` (such as found +in the GNU Compiler Collection) on any other type of system. You may +override these default values by appropriate configuration of variables +in a Construction Environment, or in the case of Cygwin on a Win32 system, +by selecting the 'cygwin' platform, which will set some of those Construction +Variables for you. By default, SCons knows how to search for available programming tools on -various systems--see the SCons man page for details. You may, of course, -override the default SCons choices made by appropriate configuration of -Environment construction variables. +various systems - see the +`SCons man page `_ +for details. You can override +the default SCons choices made by appropriate configuration of +construction variables. Installation Requirements ========================= -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):: - - $ setenv MYSCONS=`pwd` - $ python $MYSCONS/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] - - -You can use the -C option to have SCons change directory to another location -where you already have a build configuration set up:: - - $ python scripts/scons.py -C /some/other/location [arguments] - -For simplicity in the following examples, we will only show the bootstrap.py -approach. +SCons has no installation dependencies beyond a compatible version +of Python. The tools which will be used to to actually construct the +project, such as compilers, documentation production tools, etc. +should of course be installed by the appropriate means. Installation ============ - Note: You don't need to build SCons packages or install SCons if you just - want to work on developing a patch. See the sections about `Making - Changes`_ and `Testing`_ below if you just want to submit a bug fix or - some new functionality. - -Assuming your system satisfies the installation requirements in the previous -section, install SCons from this package by first populating the build/scons/ -subdirectory. (For an easier way to install SCons, without having to populate -this directory, use the scons-{version}.tar.gz or scons-{version}.zip -package.) +The preferred way to install SCons is through the Python installer, ``pip`` +(or equivalent alternatives, such as the Anaconda installer, ``conda``). +You can install either from a wheel package or from the source directory. +To work on a project that builds using SCons, installation lets you +just use ``scons`` as a command and not worry about things. In this +case, we usually suggest using a virtualenv, to isolate the Python +environment to that project +(some notes on that: +`Python Packaging User Guide: Creating and using virtual environments +`_). +Some installation examples:: -Install the built SCons files ------------------------------ + # to do a system-level install: + $ python -m pip install --user scons -Any of the above commands will populate the build/scons/ directory with the -necessary files and directory structure to use the Python-standard setup -script as follows on Linux or UNIX:: + # Windows variant, assuming Python Launcher: + C:\Users\me> py -m pip install --user scons - # python setup.py install + # inside a virtualenv it's safe to use bare pip: + (myvenv) $ pip install scons -Or on Windows:: + # install in a virtualenv from a wheel file: + (myvenv) $ pip install SCons-4.3.0-py3-none-any.whl - C:\scons>python setup.py install + # install in a virtualenv from source directory: + (myvenv) $ pip install --editable . -By default, the above commands will do the following: +Note that on Windows, SCons installed via ``pip`` puts an executable +``scons.exe`` in the script directory of the Python installation, +or in a shadow script directory if you did a User Install. +To run ``scons`` as a command, you'll need this in your search path. -- Install scripts named "scons" and "sconsign" scripts in the default system - script directory (/usr/bin or C:\\Python\*\\Scripts, for example). +Fortunately, ``pip`` will warn you about this - pay attention to any +messages during installation like this:: -- Install "scons-3.1.2.exe" and "scons.exe" executables in the Python - prefix directory on Windows (C:\\Python\*, for example). + WARNING: The scripts scons-configure-cache.exe, scons.exe and sconsign.exe + are installed in 'C:\Users\me\AppData\Roaming\Python\Python310\Scripts' + which is not on PATH. + Consider adding this directory to PATH or, if you prefer to suppress this warning, + use --no-warn-script-location. -- Install the SCons build engine (a Python module) in the standard Python library directory - (/usr/lib/python\*/site-packages or C:\\Python*\\Lib\\site-packages). +If you are running on a system which uses a package manager +(for example most Linux distributions), you may, at your option, +use the package manager (e.g. ``apt``, ``dnf``, ``yum``, +``zypper``, ``brew``, ``pacman`` etc.) to install a version +of SCons. Some distributions keep up to date with SCons releases +very quickly, while others may delay, so the version of SCons +you want to run may factor into your choice. -Making Changes -============== - -Because SCons is implemented in a scripting language, you don't need to build -it in order to make changes and test them. - -Virtually all of the SCons functionality exists in the "build engine," the -SCons subdirectory hierarchy that contains all of the modules that -make up SCons. The scripts/scons.py wrapper script exists mainly to find -the appropriate build engine library and then execute it. - -In order to make your own changes locally and test them by hand, simply edit -modules in the local SCons subdirectory tree and then running -(see the section above about `Executing SCons Without Installing`_):: - $ python scripts/scons.py [arguments] +Getting Started Using SCons +=========================== -If you want to be able to just execute your modified version of SCons from the -command line, you can make it executable and add its directory to your $PATH -like so:: +If you're new to SCons, the first couple of chapters of the +`SCons User Guide `_ +provide an excellent starting spot. - $ chmod 755 scripts/scons.py - $ export PATH=$PATH:`pwd`/scripts -You should then be able to run this version of SCons by just typing "scons.py" -at your UNIX or Linux command line. - -Note that the regular SCons development process makes heavy use of automated -testing. See the `Testing`_ and `Development Workflow`_ sections below for more -information about the automated regression tests and how they can be used in a -development cycle to validate that your changes don't break existing -functionality. - - -Debugging -========= +Contributing to SCons +===================== -Python comes with a good interactive debugger. When debugging changes by hand -(i.e., when not using the automated tests), you can invoke SCons under control -of the Python debugger by specifying the --debug=pdb option:: - - $ scons --debug=pdb [arguments] - > /home/knight/scons/SCons/Script/Main.py(927)_main() - -> default_warnings = [ SCons.Warnings.CorruptSConsignWarning, - (Pdb) - -Once in the debugger, you can set breakpoints at lines in files in the build -engine modules by providing the path name of the file relative to the -top directory (that is, including the SCons/ as the first directory -component):: - - (Pdb) b SCons/Tool/msvc.py:158 - -The debugger also supports single stepping, stepping into functions, printing -variables, etc. - -Trying to debug problems found by running the automated tests (see the -`Testing`_ section, below) is more difficult, because the test automation -harness re-invokes SCons and captures output. Consequently, there isn't an -easy way to invoke the Python debugger in a useful way on any particular SCons -call within a test script. - -The most effective technique for debugging problems that occur during an -automated test is to use the good old tried-and-true technique of adding -statements to print tracing information. But note that you can't just use -the "print" function, or even "sys.stdout.write()" because those change the -SCons output, and the automated tests usually look for matches of specific -output strings to decide if a given SCons invocation passes the test - -so these additions may cause apparent failures different than the one you -are trying to debug. - -To deal with this, SCons supports a Trace() function that (by default) will -print messages to your console screen ("/dev/tty" on UNIX or Linux, "con" on -Windows). By adding Trace() calls to the SCons source code:: - - def sample_method(self, value): - from SCons.Debug import Trace - Trace('called sample_method(%s, %s)\n' % (self, value)) - -You can then run automated tests that print any arbitrary information you wish -about what's going on inside SCons, without interfering with the test -automation. - -The Trace() function can also redirect its output to a file, rather than the -screen:: - - def sample_method(self, value): - from SCons.Debug import Trace - Trace('called sample_method(%s, %s)\n' % (self, value), - file='trace.out') - -Where the Trace() function sends its output is stateful: once you use the -"file=" argument, all subsequent calls to Trace() send their output to the -same file, until another call with a "file=" argument is reached. +Please see ``_ -Testing +License ======= -Tests are run by the runtest.py script in this directory. - -There are two types of tests in this package: - -1. Unit tests for individual SCons modules live underneath the SCons - subdirectory and have the same base name as the module with "Tests.py" - appended--for example, the unit test for the Builder.py module is the - BuilderTests.py script. - -2. End-to-end tests of SCons live in the test/ subdirectory. - -You may specifically list one or more tests to be run:: - - $ python runtest.py SCons/BuilderTests.py - - $ python runtest.py test/option-j.py test/Program.py - -You also use the -f option to execute just the tests listed in a specified -text file:: - - $ cat testlist.txt - test/option-j.py - test/Program.py - $ python runtest.py -f testlist.txt - -One test must be listed per line, and any lines that begin with '#' will be -ignored (allowing you, for example, to comment out tests that are currently -passing and then uncomment all of the tests in the file for a final validation -run). - -The runtest.py script also takes a -a option that searches the tree for all of -the tests and runs them:: - - $ python runtest.py -a - -If more than one test is run, the runtest.py script prints a summary of how -many tests passed, failed, or yielded no result, and lists any unsuccessful -tests. - -The above invocations all test directly the files underneath the SCons/ -subdirectory, and do not require that a build be performed first. - -Development Workflow -==================== - - Caveat: The point of this section isn't to describe one dogmatic workflow. - Just running the test suite can be time-consuming, and getting a patch to - pass all of the tests can be more so. If you're genuinely blocked, it may - make more sense to submit a patch with a note about which tests still - fail, and how. Someone else may be able to take your "initial draft" and - figure out how to improve it to fix the rest of the tests. So there's - plenty of room for use of good judgement. - -The various techniques described in the above sections can be combined to -create simple and effective workflows that allow you to validate that patches -you submit to SCons don't break existing functionality and have adequate -testing, thereby increasing the speed with which they can be integrated. - -For example, suppose your project's SCons configuration is blocked by an SCons -bug, and you decide you want to fix it and submit the patch. Here's one -possible way to go about doing that (using UNIX/Linux as the development -platform, Windows users can translate as appropriate)): - -- Change to the top of your checked-out SCons tree. - -- Confirm that the bug still exists in this version of SCons by using the -C - option to run the broken build:: - - $ python scripts/scons.py -C /home/me/broken_project . - -- Fix the bug in SCons by editing appropriate module files underneath - SCons. - -- Confirm that you've fixed the bug affecting your project:: - - $ python scripts/scons.py -C /home/me/broken_project . - -- Test to see if your fix had any unintended side effects that break existing - functionality:: - - $ python runtest.py -a -o test.log - - Be patient, there are more than 1100 test scripts in the whole suite. If you - are on UNIX/Linux, you can use:: - - $ python runtest.py -a | tee test.log - - instead so you can monitor progress from your terminal. - - If any test scripts fail, they will be listed in a summary at the end of the - log file. Some test scripts may also report NO RESULT because (for example) - your local system is the wrong type or doesn't have some installed utilities - necessary to run the script. In general, you can ignore the NO RESULT list, - beyond having checked once that the tests that matter to your change are - actually being executed on your test system! - -- Cut-and-paste the list of failed tests into a file:: - - $ cat > failed.txt - test/failed-test-1.py - test/failed-test-2.py - test/failed-test-3.py - ^D - $ - -- Now debug the test failures and fix them, either by changing SCons, or by - making necessary changes to the tests (if, for example, you have a strong - reason to change functionality, or if you find that the bug really is in the - test script itself). After each change, use the runtest.py -f option to - examine the effects of the change on the subset of tests that originally - failed:: - - $ [edit] - $ python runtest.py -f failed.txt - - Repeat this until all of the tests that originally failed now pass. - -- Now you need to go back and validate that any changes you made while getting - the tests to pass didn't break the fix you originally put in, and didn't - introduce any *additional* unintended side effects that broke other tests:: - - $ python scripts/scons.py -C /home/me/broken_project . - $ python runtest.py -a -o test.log - - If you find any newly-broken tests, add them to your "failed.txt" file and - go back to the previous step. - -Of course, the above is only one suggested workflow. In practice, there is a -lot of room for judgment and experience to make things go quicker. For -example, if you're making a change to just the Java support, you might start -looking for regressions by just running the test/Java/\*.py tests instead of -running all of "runtest.py -a". - - -Building Packages -================= - -We use SCons (version 3.1.2 or later) to build its own packages. If you -already have an appropriate version of SCons installed on your system, you can -build everything by simply running it:: - - $ scons - -If you don't have SCons already installed on your -system, you can use the supplied bootstrap.py script (see the section above -about `Executing SCons Without Installing`_):: - - $ python scripts/scons.py build/scons - -Depending on the utilities installed on your system, any or all of the -following packages will be built:: - - SCons-4.0.0-py3-none-any.whl - SCons-4.0.0.tar.gz - SCons-4.0.0.zip - scons-doc-4.0.0.tar.gz - scons-local-4.0.0.tar.gz - scons-local-4.0.0.zip - -The SConstruct file is supposed to be smart enough to avoid trying to build -packages for which you don't have the proper utilities installed. - -If you receive a build error, please report it to the scons-devel mailing list -and open a bug report on the SCons bug tracker. - -Note that in addition to creating the above packages, the default build will -also unpack one or more of the packages for testing. - - -Contents of this Package -======================== - -Not guaranteed to be up-to-date (but better than nothing): - -bench/ - A subdirectory for benchmarking scripts, used to perform timing tests - to decide what specific idioms are most efficient for various parts of - the code base. We check these in so they're available in case we have - to revisit any of these decisions in the future. - -bin/ - Miscellaneous utilities used in SCons development. Right now, - some of the stuff here includes: - - - a script that runs pychecker on our source tree; - - - a script that counts source and test files and numbers of lines in each; - - - a prototype script for capturing sample SCons output in xml files; - - - a script that can profile and time a packaging build of SCons itself; - - - a copy of xml_export, which can retrieve project data from SourceForge; - and - - - scripts and a Python module for translating the SCons home-brew XML - documentation tags into DocBook and man page format - - -bootstrap.py - Obsolete packaging logic. - - -debian/ - Files needed to construct a Debian package. The contents of this directory - are dictated by the Debian Policy Manual - (http://www.debian.org/doc/debian-policy). The package will not be - accepted into the Debian distribution unless the contents of this - directory satisfy the relevant Debian policies. - -doc/ - SCons documentation. A variety of things here, in various stages of - (in)completeness. - -LICENSE - A copy of the copyright and terms under which SCons is distributed (the - Open Source Initiative-approved MIT license). - -LICENSE-local - A copy of the copyright and terms under which SCons is distributed for - inclusion in the scons-local-{version} packages. This is the same as - LICENSE with a preamble that specifies the licensing terms are for SCons - itself, not any other package that includes SCons. - -README.rst - What you're looking at right now. - -README-local - A README file for inclusion in the scons-local-{version} packages. - Similar to this file, but stripped down and modified for people looking at - including SCons in their shipped software. - -runtest.py - Script for running SCons tests. By default, this will run a test against - the code in the local SCons tree, so you don't have to do a build before - testing your changes. - -SConstruct - The file describing to SCons how to build the SCons distribution. - - (It has been pointed out that it's hard to find the SCons API in this - SConstruct file, and that it looks a lot more like a pure Python script - than a build configuration file. That's mainly because all of the magick - we have to perform to deal with all of the different packaging formats - requires a lot of pure Python manipulation. In other words, don't look at - this file for an example of how easy it is to use SCons to build "normal" - software.) - -SCons/ - Where the actual source code is kept, of course. - -test/ - End-to-end tests of the SCons utility itself. These are separate from the - individual module unit tests, which live side-by-side with the modules - under SCons. - -testing/ - SCons testing framework. - -Documentation -============= - -See the RELEASE.txt file for notes about this specific release, including -known problems. See the CHANGES.txt file for a list of changes since the -previous release. - -The doc/man/scons.1 man page is included in this package, and contains a -section of small examples for getting started using SCons. - -Additional documentation for SCons is available at: - - http://www.scons.org/documentation.html - -Documentation toolchain -======================= - -For an overview see https://github.com/SCons/scons/blob/master/doc/overview.rst - -Licensing -========= - SCons is distributed under the MIT license, a full copy of which is available -in the LICENSE file. +in the ``_ file. Reporting Bugs @@ -555,40 +203,51 @@ The SCons project welcomes bug reports and feature requests. Please make sure you send email with the problem or feature request to -the SCons users mailing list, which you can join via the link below: - - http://two.pairlist.net/mailman/listinfo/scons-users +the SCons users mailing list, which you can join at +https://two.pairlist.net/mailman/listinfo/scons-users, +or on the SCons Discord server in +`#scons-help `_. Once you have discussed your issue on the users mailing list and the community has confirmed that it is either a new bug or a duplicate of an existing bug, then please follow the instructions the community provides -to file a new bug or to add yourself to the CC list for an existing bug +(including the issue template presented by GitHub) +to file a new bug or to add yourself to the CC list for an existing bug. You can explore the list of existing bugs, which may include workarounds -for the problem you've run into on GitHub Issues: - - https://github.com/SCons/scons/issues +for the problem you've run into, on the +`GitHub issue tracker `_. +Bug-fix Policy +-------------- -Mailing Lists -============= +At this time, the application of bug-fix pull requests *normally* happens +at the head of the main branch. In other words fixes are likely to appear +in the next regular release and there probably won't be a bugfix update +to a past release. Consumers are of course free to internally maintain +releases on their own by taking submitted patches and applying them. -An active mailing list for developers of SCons is available. You may -send questions or comments to the list at: - scons-dev@scons.org +Mailing Lists and Other Contacts +================================ -You may subscribe to the developer's mailing list using form on this page: +In addition to the scons-users list, an active mailing list for developers +of SCons is available. You may send questions or comments to the list +at scons-dev@scons.org. - http://two.pairlist.net/mailman/listinfo/scons-dev +You may subscribe to the developer's mailing list using the form at +https://two.pairlist.net/mailman/listinfo/scons-dev. The same page +contains archives of past postings. Subscription to the developer's mailing list is by approval. In practice, no one is refused list membership, but we reserve the right to limit membership in the future and/or weed out lurkers. -There are other mailing lists available for SCons users, for notification of -SCons code changes, and for notification of updated bug reports and project -documents. Please see our mailing lists page for details. +There are other ways to contact the SCons community. An active Discord +server is the most direct. The server includes a channel for code +notifications and other GitHub events (``#github-update``), +if those are of interest. See the website for more contact information: +https://scons.org/contact.html. Donations @@ -596,21 +255,14 @@ If you find SCons helpful, please consider making a donation (of cash, software, or hardware) to support continued work on the project. Information -is available at: - - http://www.scons.org/donate.html - -or - -GitHub Sponsors button on https://github.com/scons/scons +is available at https://www.scons.org/donate.html +or the GitHub Sponsors button on https://github.com/scons/scons. For More Information ==================== -Check the SCons web site at: - - http://www.scons.org/ +Check the SCons web site at https://www.scons.org/ Author Info @@ -639,5 +291,4 @@ \... and many others. -Copyright (c) 2001 - 2020 The SCons Foundation - +Copyright (c) 2001 - 2021 The SCons Foundation diff -Nru scons-4.0.1+dfsg/README-SF.rst scons-4.4.0+dfsg/README-SF.rst --- scons-4.0.1+dfsg/README-SF.rst 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/README-SF.rst 2022-07-30 21:48:28.000000000 +0000 @@ -48,8 +48,10 @@ ====================== 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. + +As of SCons 4.2.0 support for Python 3.5 is deprecated and will be removed +with the next major release. 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++ @@ -391,12 +393,12 @@ Depending on the utilities installed on your system, any or all of the following packages will be built:: - SCons-4.0.0-py3-none-any.whl - SCons-4.1.0.devyyyymmdd.tar.gz - SCons-4.1.0.devyyyymmdd.zip - scons-doc-4.1.0.devyyyymmdd.tar.gz - scons-local-4.1.0.devyyyymmdd.tar.gz - scons-local-4.1.0.devyyyymmdd.zip + SCons-4.2.0-py3-none-any.whl + SCons-4.3.0ayyyymmdd.tar.gz + SCons-4.3.0ayyyymmdd.zip + scons-doc-4.3.0ayyyymmdd.tar.gz + scons-local-4.3.0ayyyymmdd.tar.gz + scons-local-4.3.0ayyyymmdd.zip The SConstruct file is supposed to be smart enough to avoid trying to build packages for which you don't have the proper utilities installed. @@ -610,5 +612,5 @@ \... and many others. -Copyright (c) 2001 - 2020 The SCons Foundation +Copyright (c) 2001 - 2021 The SCons Foundation diff -Nru scons-4.0.1+dfsg/ReleaseConfig scons-4.4.0+dfsg/ReleaseConfig --- scons-4.0.1+dfsg/ReleaseConfig 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/ReleaseConfig 2022-07-30 21:48:28.000000000 +0000 @@ -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__" - # # After updating this file, run bin/update-release-info.py . # @@ -32,14 +31,14 @@ # 'final', the patchlevel is set to the release date. This value is # mandatory and must be present in this file. #version_tuple = (2, 2, 0, 'final', 0) -version_tuple = (4, 0, 1) +version_tuple = (4, 3, 0, 'a', 0) # Python versions prior to unsupported_python_version cause a fatal error # when that version is used. Python versions prior to deprecate_python_version # cause a warning to be issued (assuming it's not disabled). These values are # mandatory and must be present in the configuration file. -unsupported_python_version = (3, 4, 0) -deprecated_python_version = (3, 4, 0) +unsupported_python_version = (3, 6, 0) +deprecated_python_version = (3, 6, 0) # If release_date is (yyyy, mm, dd, hh, mm, ss), that is used as the release # date and time. If release_date is (yyyy, mm, dd), it is used for the @@ -51,7 +50,7 @@ #month_year = 'December 2012' # If copyright years is not given, the release year is used as the end. -copyright_years = '2001 - 2020' +copyright_years = '2001 - 2021' # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/RELEASE.txt scons-4.4.0+dfsg/RELEASE.txt --- scons-4.0.1+dfsg/RELEASE.txt 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/RELEASE.txt 2022-07-30 21:48:28.000000000 +0000 @@ -1,54 +1,264 @@ - A new SCons release, 4.0.1, is now available - on the SCons download page: +A new SCons release, 4.4.0, is now available +on the SCons download page: - https://scons.org/pages/download.html + https://scons.org/pages/download.html - Here is a summary of the changes since 4.0.1: +Here is a summary of the changes since 4.3.0: - NEW FUNCTIONALITY - - - Added Environment() variable TEMPFILEDIR which allows setting the directory which temp - files createdby TEMPFILEMUNGE are created in. - - DEPRECATED FUNCTIONALITY - - - N/A - - CHANGED/ENHANCED EXISTING FUNCTIONALITY - - - N/A - - FIXES - - - Fix fortran tools to set SHFORTRAN variables to $FORTRAN, similarly SHF77, SHF90, SHF95, - SHF03 and SHF08 will default to the variables $F77, $F90, $F95, $F03 and $F08 respectively. - If you were depending on changing the value of FORTRAN (or $F[0-9][0-9]) having no effect - on the value of SHFORTRAN, this change will break that. The values of FORTRAN, F77, F90, - F95, F03, F08 and SHFORTRAN, SHF77 (etc.) now are not overridden in generate if alredy set - by the user. - - Fix subprocess execution of 'lslpp' on AIX to produce text standard i/o. - - Re-do the fix for suncxx tool (Oracle Studio compiler) now that only Python 3 is supported, - to avoid decoding errors. - - IMPROVEMENTS - - - N/A - - PACKAGING - - - N/A - - DOCUMENTATION - - - N/A - - DEVELOPMENT - - - N/A - - Thanks to the following contributors listed below for their contributions to this release. - -git shortlog --no-merges -ns 4.0.0..HEAD - 12 William Deegan - 2 Rob Boehne - 1 Clemens Tolboom +NOTE: If you build with Python 3.10.0 and then rebuild with 3.10.1 (or higher), you may + see unexpected rebuilds. This is due to Python internals changing which changed + the signature of a Python Action Function. + + +NEW FUNCTIONALITY +----------------- + +- Added MSVC_USE_SCRIPT_ARGS Environment variable which specifies command line arguments + to pass to the script specified by MSVC_USE_SCRIPT. +- Added Configure.CheckMember() checker to check if struct/class has the specified member. +- Added SHELL_ENV_GENERATORS construction variable. This variable should be set to a list + (or an iterable) which contains functions to be called in order + when constructing the execution environment (Generally this is the shell environment + variables). This allows the user to customize how (for example) PATH is constructed. + Note that these are called for every build command run by SCons. It could have considerable + performance impact if not used carefully. +- Added MSVC_USE_SETTINGS construction variable to pass a dictionary to configure the msvc compiler + system environment as an alternative to bypassing Visual Studio autodetection entirely. +- Added MSVC_SDK_VERSION construction variable which allows building with a specific Microsoft + SDK version. This variable is used with the msvc batch file determined via autodetection. Refer + to the documentation for additional requirements and validation details. +- Added MSVC_TOOLSET_VERSION construction variable which allows building with a specific toolset + version. This variable is used with the msvc batch file determined via autodetection. This + variable does not affect the autodetection and selection of msvc instances. The toolset version + is applied after an msvc instance is selected. This could be the default version of msvc. Refer + to the documentation for additional requirements and validation details. Addresses issue #3265, + issue #3664, and pull request #4149. +- Added MSVC_SPECTRE_LIBS construction variable which allows building with spectre-mitigated + Visual C++ libraries. This variable is used with the msvc batch file determined via autodetection. + Refer to the documentation for additional requirements and validation details. +- Added MSVC_SCRIPT_ARGS construction variable which specifies command line arguments that are + passed to the msvc batch file determined via autodetection. Refer to the documentation for + additional requirements and validation details. Addresses enhancement issue #4106. +- Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon. + Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs. + NOTE: Test for this requires python psutil module. It will be skipped if not present. +- Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args. + This can also be set in your Environment(). +- Added a global policy setting and an environment construction variable for specifying the + action to be taken when an msvc request cannot be satisfied. The available options are "error", + "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be + set and retrieved via the functions msvc_set_notfound_policy and msvc_get_notfound_policy, + respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment + construction variable is MSVC_NOTFOUND_POLICY. When defined, the environment construction + variable overrides the global policy setting for a given environment. When the active policy + is "error" or "exception", an MSVCVersionNotFound exception is raised. When the active policy + is "warning" or "warn", a VisualCMissingWarning warning is issued and the constructed + environment is likely incomplete. When the active policy is "ignore" or "suppress", no action + is taken and the constructed environment is likely incomplete. As implemented, the default + global policy is "warning". The ability to set the global policy via an SCons command-line + option may be added in a future enhancement. +- Added a global policy setting and an environment construction variable for specifying the + action to be taken when msvc script errors are detected. The available options are "error", + "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be + set and retrieved via the functions msvc_set_scripterror_policy and msvc_get_scripterror_policy, + respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment + construction variable is MSVC_SCRIPTERROR_POLICY. When defined, the environment construction + variable overrides the global policy setting for a given environment. When the active policy + is "error" or "exception", an MSVCScriptExecutionError exception is raised when msvc batch file + errors are detected. When the active policy is "warning" or "warn", an MSVCScriptExecutionWarning + warning is issued when msvc batch file errors are detected. When the active policy is "ignore" or + "suppress", msvc batch error messages are suppressed. As implemented, the default global policy + is "ignore". The ability to set the global policy via an SCons command-line option may be added + in a future enhancement. +- Added experimental function msvc_query_version_toolset to SCons.Tool.MSCommon. Given a version + specification, this function will return an msvc version and an msvc toolset version. The msvc + toolset version may be None. The msvc version and msvc toolset version can be used in the + environment construction variables MSVC_VERSION and MSVC_TOOLSET_VERSION, respectively. The + version specification may be an msvc version or an msvc toolset version. This is a proxy for + using an msvc toolset version to select an msvc instance. This function may be removed when an + msvc toolset version is used during msvc instance selection. +- Fortran: a new construction variable FORTRANCOMMONFLAGS is added which is + applied to all Fortran dialects, to enable global (all-dialect) settings. +- lex: two new construction variables are introduced (LEX_HEADER_ILE + and LEX_TABLES_FILE) as the preferred way of specifying extra files that + the tool can generate. +- yacc: two new construction variables are introduced (YACC_HEADER_FILE + and YACC_GRAPH_FILE) as the preferred way of specifying extra files that + the tool can generate (applies only when using GNU flex and GNU bison). + + +CHANGED/ENHANCED EXISTING FUNCTIONALITY +--------------------------------------- + +- On Windows, %AllUsersProfile%\scons\site_scons is now the default "system" + location for a site_scons directory. + %AllUsersProfile%\Application Data\scons\site_scons will continue to work. + There does not seem to be any existing convention to use an + "Application Data" subdirectory here. +- Action._subproc() can now be used as a python context manager to ensure that the + POpen object is properly closed. +- SCons help (-H) no longer prints the "ignored for compatibility" options, + which are still listed in the manpage. +- Help is now sensitive to the size of the terminal window: the width of the + help text will scale to wider (or narrower) terminals than 80 characters. +- Ninja: Changed generated build.ninja file to run SCons only build Actions via + a SCons Deamon. Added logic for starting and connecting to SCons daemon (currently + only used for ninja) +- The change to "content" and "content-timestamp" Decider names is reflected + in the User Guide as well, since the hash function may be other than md5 + (tidying up from earlier change) +- If the (experimental) SCONS_CACHE_MSVC_CONFIG feature is used, it will now + attempt a sanity check for the cached compiler information, and regenerate + it if needed. Previously, this cache would fail if a compiler upgrade caused + a change to internal paths (e.g. upgrading from 17.1 to 17.2 causes + a necessary path component in some of the cached vars to need to 14.32.31326 + instead of 14.31.31103), and the cache file needed to be manually removed. + The default cachefile name is now "scons_msvc_cache.json" rather than + ".scons_msvc_cache" so there should be no transition problem if using the + default; if using a custom cache file name, the cache should still be + manually removed if there are problems to transition to the new style. +- Ninja: Update ninja file generation to only create response files for build commands + which exceed MAXLINELENGTH +- Update the debug output written to stdout for MSVC initialization which is enabled + by setting SCONS_MSCOMMON_DEBUG=- to use the logging module. Also changed the debug + output format written to stdout to include more information about the source for each + message of MSVC initialization debugging output. A single space was added before the + message for all debugging output records written to stdout and to files. +- Ninja: Made ninja tool force the ninja file as the only target. Also improved the default + targets setup and made sure there is always a default target for + the ninja file, which excludes targets that start and stop the daemon. +- Ninja: Update ninja tool so targets passed to SCons are propgated to ninja when scons + automatically executes ninja. +- Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. +- The build argument (i.e., x86) is no longer passed to the MSVC 6.0 to 7.1 batch + files. This may improve the effectiveness of the internal msvc cache when using + MSVC detection and when bypassing MSVC detection as the MSVC 6.0 to 7.1 batch files + do not expect any arguments. +- Propagate the OS and windir environment variables from the system environment to the msvc + environment. The OS and windir environment variables are used in the MSVC 6.0 batch file + and the SDK 6.0-7.1 SetEnv.cmd batch files. Inclusion of the OS and windir environment + variables eliminates some partial paths and warnings generated by the MSVC 6.0 and SDK + 6.0-7.1 batch files when the variables are not defined. + Note: Attempting to run the SDK 6.0-7.1 batch files directly via MSVC_USE_SCRIPT can lead to + build failures and/or incomplete build environments. The SDK 6.0-7.1 batch files + require delayed expansion to be enabled which is currently not supported and is + typically not enabled by default on the host system. The batch files may also require + environment variables that are not included by default in the msvc environment. +- An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier. + Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013 + and earlier. Refer to the documentation for additional requirements and validation details. + MSVC_UWP_APP was extended to accept True, False, and None in addition to '1' and '0'. +- Ninja: added option "--skip-ninja-regen" to enable skipping regeneration of the ninja file + if scons can determine the ninja file doesnot need to be regenerated, which will also + skip restarting the scons daemon. Note this option is could result in incorrect rebuilds + if scons Glob or scons generated files are used in ninja build target's command lines. +- Tool loading used to have a special case for Jython, it no longer does. This effectively + means SCons doesn't work with Jython, which has in reality been the case ever since + SCons dropped Python 2 support - there is still no timeline for Jython switching to + Python 3 compatibility. + + +FIXES +----- +- Fix a number of Python ResourceWarnings which are issued when running SCons and/or it's tests + with python 3.9 (or higher) +- Ninja: Fix issue where Configure files weren't being properly processed when build run + via ninja. +- Fixed crash in C scanner's dictify_CPPDEFINES() function which happens if + AppendUnique is called on CPPPATH. (Issue #4108). +- Added default values for source and target arguments to _defines() function. This + is used to expand CPPDEFINES (and others). Previous change added those arguments + with no defaults, so old usage where _defines() was called without source and target + arguments would yield an exception. This issue was found via qt4 and qt5 tools in + scons-contrib https://github.com/SCons/scons-contrib/issues/45 +- Fix issue where if you only had mingw installed on a Windows system and no MSVC compiler, and + did not explicitly request the mingw tool, mingw tool initialization would fail and set the + default compiler to MSVC which wasn't installed, yielding broken build. + Updated mingw tool so that the generate and exists methods use the same mingw search paths + (issue #4134). +- Ninja: Added NINJA_GENERATED_SOURCE_ALIAS_NAME which allows user to specify an + Alias() which the ninja tool can use to determine which files are generated sources. + If this is not set by the user then the ninja tool will still dynamically determine + which files are generated sources based on NINJA_GENERATED_SOURCE_SUFFIXES, and create + a phony target _ninja_generated_sources. Generated sources will be built first by + ninja. This is needed because ninja cannot determine which generated sources are + required by other build targets. Code contributed by MongoDB. +- Added special case for ninja scons daemon to work in win32 python3.6 environments. + This particular environment does a bad job managing popen standard file handles, so + some special workarounds are needed. +- Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT. + Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected + format. Compiler tools will also configure the variable automatically. +- Fix issue where Express versions of the MSVC compiler were not detected due to differences + in initial msvc detection and msvc batch file determination when configuring the build + environment. This could lead to build failures when only an MSVC Express instance is installed + and the MSVC version is not explicitly specified (issue #2668 and issue #2697). +- Restore the ability of the content-timestamp decider to see that a + a source which is a symlink has changed if the file-system target of + that link has been modified (issue #3880) +- Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry + to connect to the server during start up. +- Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. +- The system environment variable names imported for MSVC 7.0 and 6.0 were updated to be + consistent with the variables names defined by their respective installers. This fixes an + error caused when bypassing MSVC detection by specifying the MSVC 7.0 batch file directly. +- lex: Fixed an issue with the lex tool where file arguments specified to either "--header-file=" + or "--tables-file=" which included a space in the path to the file would be processed incorrectly +- Modify the MSCommon logger configuration to be independent of the root logger. This fixes an issue + when multiple loggers are created and the MSCommon logger added computed fields to the root logger + that are not present in other logging instances. +- Modify the MSVC_USE_SCRIPT_ARGS test fixture to disable the msvc cache. This fixes an issue where + the MSVC_USE_SCRIPT_ARGS test for success relied on a debug log message that was not produced when + the msvc cache file exists and the test keys are already in the cache as the msvc script invocation + was bypassed. +- Suppress issuing a warning when there are no installed Visual Studio instances for the default + tools configuration (issue #2813). When msvc is the default compiler because there are no + compilers installed, a build may fail due to the cl.exe command not being recognized. At + present, there is no easy way to detect during msvc initialization if the default environment + will be used later to build a program and/or library. There is no error/warning issued for the + default tools as there are legitimate SCons uses that do not require a c compiler. + +IMPROVEMENTS +------------ + +- Verify that a user specified msvc script (via MSVC_USE_SCRIPT) exists and raise an + exception immediately when the user specified msvc script does not exist. +- Add cache-debug messages for push failures. +- Ninja: Added ninja mingw support and improved ninja CommandGeneratorAction support. +- Command-line help is now sensitive to the size of the terminal window: the + width of the help text will scale for terminals other than 80 chars wide. +- Refactor the msvc code so that the same data structures are used during initial msvc detection + and msvc batch file determination when configuring the build environment. Simplify the msvc + code by eliminating special case handling primarily due to the differences between the full + versions and express versions of visual studio. +- Small refactor of scons daemons using a shared StateInfo class for communication + between the scons interactive thread and the http server thread. Added error handling + for scons interactive failing to startup. +- Ninja: Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log. +- Ninja: Ensure that all targets set as default via Default() in SConstruct/SConscripts are + default targets in the generated ninja.build file. + + +PACKAGING +--------- + +- Added project_url for mailing lists and Discord +- Updated setup.cfg to remove Python 3.5 and add Python 3.10 + + +Thanks to the following contributors listed below for their contributions to this release. +========================================================================================== +.. code-block:: text + + git shortlog --no-merges -ns 4.3.0..HEAD + git shortlog --no-merges -ns 4.3.0..HEAD + 174 Joseph Brill + 126 Mats Wichmann + 93 William Deegan + 64 Daniel Moody + 4 SergBobrovsky + 2 dependabot[bot] + 1 djh + 1 Ivan Kravets + 1 Vishwajith-K + 1 Zhichang Yu diff -Nru scons-4.0.1+dfsg/requirements.txt scons-4.4.0+dfsg/requirements.txt --- scons-4.0.1+dfsg/requirements.txt 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/requirements.txt 2022-07-30 21:48:28.000000000 +0000 @@ -4,7 +4,16 @@ # Can be used with twinecheck # See: https://github.com/pypa/readme_renderer readme-renderer -sphinx +#sphinx<=5.0.0 +sphinx>=5.1.1 sphinx_rtd_theme -lxml==4.5.0 -rst2pdf \ No newline at end of file +rst2pdf +# for now keep pinning "known working" lxml, +# it's been a troublesome component in the past. +lxml==4.9.1 +rst2pdf +ninja + +# Needed for test/Parallel/failed-build/failed-build.py +# Also for test/ninja/shutdown_scons_daemon.py +psutil diff -Nru scons-4.0.1+dfsg/runtest.py scons-4.4.0+dfsg/runtest.py --- scons-4.0.1+dfsg/runtest.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/runtest.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,76 +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 -# - 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-*). +"""runtest - wrapper script for running SCons tests -""" -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) - -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. - -k --no-progress Suppress count and percent progress messages. - -l --list List available tests and exit. - -n --no-exec No execute, just print command lines. - --nopipefiles Do not use the "file pipe" workaround for Popen() - for starting tests. WARNING: use only when too much - file traffic is giving you trouble AND you can be - sure that none of your tests create output >65K - 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. - --runner CLASS Alternative test runner class for unit tests. - -s --short-progress Short progress, prints only the command line. - and a percentage value, based on the total and - current number of tests. - -t --time Print test execution time. - -v VERSION Specify the SCons version. - --verbose=LEVEL Set verbose level: - 1 = print executed commands, - 2 = print commands and non-zero output, - 3 = print commands and all output. - -X Test script is executable, don't feed to Python. - -x --exec SCRIPT Test SCRIPT. - --xml file Save results to file in SCons XML format. - --exclude-list FILE List of tests to exclude in the current selection. - Use to exclude tests when using the -a option. +The SCons test suite consists of: -Environment Variables: - PRESERVE, PRESERVE_{PASS,FAIL,NO_RESULT}: preserve test subdirs - TESTCMD_VERBOSE: turn on verbosity in TestCommand + * unit tests - *Tests.py files from the SCons/ dir + * end-to-end tests - *.py files in the test/ directory that + require the custom SCons framework from testing/ + +This script adds SCons/ and testing/ directories to PYTHONPATH, +performs test discovery and processes tests according to options. """ -import getopt +# TODO: normalize requested and testlist/exclude paths for easier comparison. +# e.g.: "runtest foo/bar" on windows will produce paths like foo/bar\test.py +# this is hard to match with excludelists, and makes those both os.sep-specific +# and command-line-typing specific. + +import argparse import glob import os import re @@ -81,175 +30,218 @@ import threading import time from abc import ABC, abstractmethod -from optparse import OptionParser, BadOptionError +from pathlib import Path from queue import Queue cwd = os.getcwd() -baseline = None -builddir = os.path.join(cwd, 'build') -external = 0 -devmode = False -debug = '' -execute_tests = True -jobs = 1 -list_only = False -printcommand = True -package = None -print_passed_summary = False +debug = None scons = None -scons_exec = False -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 -script = sys.argv[0].split("/")[-1] +script = os.path.basename(sys.argv[0]) usagestr = """\ -Usage: %(script)s [OPTIONS] [TEST ...] - %(script)s -h|--help +%(script)s [OPTIONS] [TEST ...] """ % locals() -helpstr = usagestr + __doc__ +epilogstr = """\ +Environment Variables: + PRESERVE, PRESERVE_{PASS,FAIL,NO_RESULT}: preserve test subdirs + TESTCMD_VERBOSE: turn on verbosity in TestCommand\ +""" -# "Pass-through" option parsing -- an OptionParser that ignores -# unknown options and lets them pile up in the leftover argument -# list. Useful to gradually port getopt to optparse. - -class PassThroughOptionParser(OptionParser): - def _process_long_opt(self, rargs, values): - try: - OptionParser._process_long_opt(self, rargs, values) - except BadOptionError as err: - self.largs.append(err.opt_str) - def _process_short_opts(self, rargs, values): - try: - OptionParser._process_short_opts(self, rargs, values) - except BadOptionError as err: - self.largs.append(err.opt_str) - -parser = PassThroughOptionParser(add_help_option=False) -parser.add_option('-a', '--all', action='store_true', help="Run all tests.") -parser.add_option('-o', '--output', - help="Save the output from a test run to the log file.") -parser.add_option('--runner', metavar='class', - help="Test runner class for unit tests.") -parser.add_option('--xml', help="Save results to file in SCons XML format.") -(options, args) = parser.parse_args() - -# print("options:", options) -# print("args:", args) - - -opts, args = getopt.getopt( - args, - "b:dDef:hj:klnP:p:qsv:Xx:t", - [ - "baseline=", - "builddir=", - "debug", - "devmode", - "external", - "file=", - "help", - "no-progress", - "jobs=", - "list", - "no-exec", - "nopipefiles", - "package=", - "passed", - "python=", - "quiet", - "quit-on-failure", - "short-progress", - "time", - "version=", - "exec=", - "verbose=", - "exclude-list=", - ], +parser = argparse.ArgumentParser( + usage=usagestr, epilog=epilogstr, allow_abbrev=False, + formatter_class=argparse.RawDescriptionHelpFormatter ) -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') - if os.path.exists(pdb): - debug = pdb - break - elif o in ['-D', '--devmode']: - devmode = True - elif o in ['-e', '--external']: - external = True - elif o in ['-f', '--file']: - if not os.path.isabs(a): - a = os.path.join(cwd, a) - testlistfile = a - elif o in ['-h', '--help']: - print(helpstr) - sys.exit(0) - elif o in ['-j', '--jobs']: - jobs = int(a) - # don't let tests write stdout/stderr directly if multi-job, - # or outputs will interleave and be hard to read - catch_output = True - elif o in ['-k', '--no-progress']: - print_progress = False - elif o in ['-l', '--list']: - list_only = True - elif o in ['-n', '--no-exec']: - 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']: - python = a - elif o in ['-q', '--quiet']: - printcommand = False - suppress_output = catch_output = True - elif o in ['--quit-on-failure']: - quit_on_failure = True - elif o in ['-s', '--short-progress']: - print_progress = True - suppress_output = catch_output = True - elif o in ['-t', '--time']: - print_times = True - elif o in ['--verbose']: - os.environ['TESTCMD_VERBOSE'] = a - elif o in ['-v', '--version']: - version = a - elif o in ['-X']: - scons_exec = True - elif o in ['-x', '--exec']: - scons = a - elif o in ['--exclude-list']: - excludelistfile = a +# test selection options: +testsel = parser.add_argument_group(description='Test selection options:') +testsel.add_argument(metavar='TEST', nargs='*', dest='testlist', + help="Select TEST(s) (tests and/or directories) to run") +testlisting = testsel.add_mutually_exclusive_group() +testlisting.add_argument('-f', '--file', metavar='FILE', dest='testlistfile', + help="Select only tests in FILE") +testlisting.add_argument('-a', '--all', action='store_true', + help="Select all tests") +testlisting.add_argument('--retry', action='store_true', + help="Rerun the last failed tests in 'failed_tests.log'") +testsel.add_argument('--exclude-list', metavar="FILE", dest='excludelistfile', + help="""Exclude tests in FILE from current selection""") +testtype = testsel.add_mutually_exclusive_group() +testtype.add_argument('--e2e-only', action='store_true', + help="Exclude unit tests from selection") +testtype.add_argument('--unit-only', action='store_true', + help="Exclude end-to-end tests from selection") + +# miscellaneous options +parser.add_argument('-b', '--baseline', metavar='BASE', + help="Run test scripts against baseline BASE.") +parser.add_argument('-d', '--debug', action='store_true', + help="Run test scripts under the Python debugger.") +parser.add_argument('-D', '--devmode', action='store_true', + help="Run tests in Python's development mode (Py3.7+ only).") +parser.add_argument('-e', '--external', action='store_true', + help="Run the script in external mode (for external Tools)") +parser.add_argument('-j', '--jobs', metavar='JOBS', default=1, type=int, + help="Run tests in JOBS parallel jobs (0 for cpu_count).") +parser.add_argument('-l', '--list', action='store_true', dest='list_only', + help="List available tests and exit.") +parser.add_argument('-n', '--no-exec', action='store_false', + dest='execute_tests', + help="No execute, just print command lines.") +parser.add_argument('--nopipefiles', action='store_false', + dest='allow_pipe_files', + help="""Do not use the "file pipe" workaround for subprocess + for starting tests. See source code for warnings.""") +parser.add_argument('-P', '--python', metavar='PYTHON', + help="Use the specified Python interpreter.") +parser.add_argument('--quit-on-failure', action='store_true', + help="Quit on any test failure.") +parser.add_argument('--runner', metavar='CLASS', + help="Test runner class for unit tests.") +parser.add_argument('-X', dest='scons_exec', action='store_true', + help="Test script is executable, don't feed to Python.") +parser.add_argument('-x', '--exec', metavar="SCRIPT", + help="Test using SCRIPT as path to SCons.") +parser.add_argument('--faillog', dest='error_log', metavar="FILE", + default='failed_tests.log', + help="Log failed tests to FILE (enabled by default, " + "default file 'failed_tests.log')") +parser.add_argument('--no-faillog', dest='error_log', + action='store_const', const=None, + default='failed_tests.log', + help="Do not log failed tests to a file") + +parser.add_argument('--no-ignore-skips', dest='dont_ignore_skips', + action='store_true', + default=False, + help="If any tests are skipped, exit status 2") + +outctl = parser.add_argument_group(description='Output control options:') +outctl.add_argument('-k', '--no-progress', action='store_false', + dest='print_progress', + help="Suppress count and progress percentage messages.") +outctl.add_argument('--passed', action='store_true', + dest='print_passed_summary', + help="Summarize which tests passed.") +outctl.add_argument('-q', '--quiet', action='store_false', + dest='printcommand', + help="Don't print the test being executed.") +outctl.add_argument('-s', '--short-progress', action='store_true', + help="""Short progress, prints only the command line + and a progress percentage.""") +outctl.add_argument('-t', '--time', action='store_true', dest='print_times', + help="Print test execution time.") +outctl.add_argument('--verbose', metavar='LEVEL', type=int, choices=range(1, 4), + help="""Set verbose level + (1=print executed commands, + 2=print commands and non-zero output, + 3=print commands and all output).""") +# maybe add? +# outctl.add_argument('--version', action='version', version='%s 1.0' % script) + +logctl = parser.add_argument_group(description='Log control options:') +logctl.add_argument('-o', '--output', metavar='LOG', help="Save console output to LOG.") +logctl.add_argument('--xml', metavar='XML', help="Save results to XML in SCons XML format.") + +# process args and handle a few specific cases: +args = parser.parse_args() + +# we can't do this check with an argparse exclusive group, since those +# only work with optional args, and the cmdline tests (args.testlist) +# are not optional args, +if args.testlist and (args.testlistfile or args.all or args.retry): + sys.stderr.write( + parser.format_usage() + + "error: command line tests cannot be combined with -f/--file, -a/--all or --retry\n" + ) + sys.exit(1) + +if args.retry: + args.testlistfile = 'failed_tests.log' +if args.testlistfile: + # args.testlistfile changes from a string to a pathlib Path object + try: + p = Path(args.testlistfile) + # TODO simplify when Py3.5 dropped + if sys.version_info.major == 3 and sys.version_info.minor < 6: + args.testlistfile = p.resolve() + else: + args.testlistfile = p.resolve(strict=True) + except FileNotFoundError: + sys.stderr.write( + parser.format_usage() + + 'error: -f/--file testlist file "%s" not found\n' % p + ) + sys.exit(1) -class Unbuffered(): - """ class to arrange for stdout/stderr to be unbuffered """ +if args.excludelistfile: + # args.excludelistfile changes from a string to a pathlib Path object + try: + p = Path(args.excludelistfile) + # TODO simplify when Py3.5 dropped + if sys.version_info.major == 3 and sys.version_info.minor < 6: + args.excludelistfile = p.resolve() + else: + args.excludelistfile = p.resolve(strict=True) + except FileNotFoundError: + sys.stderr.write( + parser.format_usage() + + 'error: --exclude-list file "%s" not found\n' % p + ) + sys.exit(1) + +if args.jobs == 0: + try: + # on Linux, check available rather then physical CPUs + args.jobs = len(os.sched_getaffinity(0)) + except AttributeError: + # Windows + args.jobs = os.cpu_count() + +# sanity check +if args.jobs == 0: + sys.stderr.write( + parser.format_usage() + + "Unable to detect CPU count, give -j a non-zero value\n" + ) + sys.exit(1) + +if args.jobs > 1 or args.output: + # 1. don't let tests write stdout/stderr directly if multi-job, + # else outputs will interleave and be hard to read. + # 2. If we're going to write a logfile, we also need to catch the output. + catch_output = True + +if not args.printcommand: + suppress_output = catch_output = True + +if args.verbose: + os.environ['TESTCMD_VERBOSE'] = str(args.verbose) + +if args.short_progress: + args.print_progress = True + suppress_output = catch_output = True + +if args.debug: + # TODO: add a way to pass a specific debugger + debug = "pdb" + +if args.exec: + scons = args.exec + +# --- setup stdout/stderr --- +class Unbuffered: def __init__(self, file): self.file = file + def write(self, arg): self.file.write(arg) self.file.flush() + def __getattr__(self, attr): return getattr(self.file, attr) @@ -259,50 +251,68 @@ # possible alternative: switch to using print, and: # print = functools.partial(print, flush) -if options.output: - logfile = open(options.output, 'w') - class Tee(): +if args.output: + class Tee: def __init__(self, openfile, stream): self.file = openfile self.stream = stream + def write(self, data): self.file.write(data) self.stream.write(data) + + def flush(self, data): + self.file.flush(data) + self.stream.flush(data) + + logfile = open(args.output, 'w') + # this is not ideal: we monkeypatch stdout/stderr a second time + # (already did for Unbuffered), so here we can't easily detect what + # state we're in on closedown. Just hope it's okay... sys.stdout = Tee(logfile, sys.stdout) sys.stderr = Tee(logfile, sys.stderr) # --- define helpers ---- -if sys.platform in ('win32', 'cygwin'): - def whereis(file): - pathext = [''] + os.environ['PATHEXT'].split(os.pathsep) - for d in os.environ['PATH'].split(os.pathsep): - f = os.path.join(d, file) - for ext in pathext: - fext = f + ext - if os.path.isfile(fext): - return fext - return None - -else: - def whereis(file): - for d in os.environ['PATH'].split(os.pathsep): - f = os.path.join(d, file) - if os.path.isfile(f): - try: - st = os.stat(f) - except OSError: - continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: - return f - return None +if sys.platform == 'win32': + # thanks to Eryk Sun for this recipe + import ctypes + + shlwapi = ctypes.OleDLL('shlwapi') + shlwapi.AssocQueryStringW.argtypes = ( + ctypes.c_ulong, # flags + ctypes.c_ulong, # str + ctypes.c_wchar_p, # pszAssoc + ctypes.c_wchar_p, # pszExtra + ctypes.c_wchar_p, # pszOut + ctypes.POINTER(ctypes.c_ulong), # pcchOut + ) + + ASSOCF_NOTRUNCATE = 0x00000020 + ASSOCF_INIT_IGNOREUNKNOWN = 0x00000400 + ASSOCSTR_COMMAND = 1 + ASSOCSTR_EXECUTABLE = 2 + E_POINTER = ctypes.c_long(0x80004003).value + + def get_template_command(filetype, verb=None): + flags = ASSOCF_INIT_IGNOREUNKNOWN | ASSOCF_NOTRUNCATE + assoc_str = ASSOCSTR_COMMAND + cch = ctypes.c_ulong(260) + while True: + buf = (ctypes.c_wchar * cch.value)() + try: + shlwapi.AssocQueryStringW( + flags, assoc_str, filetype, verb, buf, ctypes.byref(cch) + ) + except OSError as e: + if e.winerror != E_POINTER: + raise + continue + break + return buf.value -sp.append(builddir) -sp.append(cwd) -# _ws = re.compile(r'\s') - def escape(s): if _ws.search(s): s = '"' + s + '"' @@ -313,12 +323,14 @@ 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... - if allow_pipe_files: + if args.allow_pipe_files: # The subprocess.Popen() suffers from a well-known # problem. Data for stdout/stderr is read into a # memory buffer of fixed size, 65K which is not very much. @@ -327,18 +339,22 @@ # be able to write the rest of its output. Hang! # In order to work around this, we follow a suggestion # by Anders Pearson in - # http://http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/ + # https://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') # Start subprocess... - cp = subprocess.run(command_args, - stdout=tmp_stdout, - stderr=tmp_stderr, - shell=False) + cp = subprocess.run( + command_args, + stdout=tmp_stdout, + stderr=tmp_stderr, + shell=False, + env=env, + ) try: # Rewind to start of files @@ -368,11 +384,15 @@ # (but the subprocess isn't writing anything there). # Hence a deadlock. # Be dragons here! Better don't use this! - def spawn_it(command_args): - cp = subprocess.run(command_args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=False) + + def spawn_it(command_args, env): + cp = subprocess.run( + command_args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + env=env, + ) return cp.stdout, cp.stderr, cp.returncode @@ -400,8 +420,8 @@ 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,21 +434,25 @@ 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): + if args.allow_pipe_files: + + def execute(self, env): # Create temporary files tmp_stdout = tempfile.TemporaryFile(mode='w+t') tmp_stderr = tempfile.TemporaryFile(mode='w+t') # Start subprocess... - cp = subprocess.run(self.command_str.split(), - stdout=tmp_stdout, - stderr=tmp_stderr, - shell=False) + cp = subprocess.run( + self.command_str.split(), + stdout=tmp_stdout, + stderr=tmp_stderr, + shell=False, + env=env, + ) self.status = cp.returncode try: @@ -443,14 +467,16 @@ tmp_stdout.close() tmp_stderr.close() else: - def execute(self): - cp = subprocess.run(self.command_str.split(), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=False) - self.status = cp.returncode - self.stdout = cp.stdout - self.stderr = cp.stderr + + def execute(self, env): + cp = subprocess.run( + self.command_str.split(), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + env=env, + ) + self.status, self.stdout, self.stderr = cp.returncode, cp.stdout, cp.stderr class XML(PopenExecutor): """ Test class for tests that will output in scons xml """ @@ -472,92 +498,110 @@ f.write(' \n' % self.total_time) f.write(' \n') -if options.xml: +if args.xml: Test = XML else: Test = SystemExecutor # --- start processing --- -sd = None -tools_dir = None -ld = None - -if not baseline or baseline == '.': - base = cwd -elif baseline == '-': +if not args.baseline or args.baseline == '.': + baseline = cwd +elif args.baseline == '-': print("This logic used to checkout from svn. It's been removed. If you used this, please let us know on devel mailing list, IRC, or discord server") sys.exit(-1) else: - base = baseline - -scons_runtest_dir = base + baseline = args.baseline +scons_runtest_dir = baseline -if not external: - scons_script_dir = sd or os.path.join(base, 'scripts') - scons_tools_dir = tools_dir or os.path.join(base, 'bin') - scons_lib_dir = ld or base +if not args.external: + scons_script_dir = os.path.join(baseline, 'scripts') + scons_tools_dir = os.path.join(baseline, 'bin') + scons_lib_dir = baseline else: - scons_script_dir = sd or '' - scons_tools_dir = tools_dir or '' - scons_lib_dir = ld or '' - -pythonpath_dir = scons_lib_dir + scons_script_dir = '' + scons_tools_dir = '' + scons_lib_dir = '' + +testenv = { + 'SCONS_RUNTEST_DIR': scons_runtest_dir, + 'SCONS_TOOLS_DIR': scons_tools_dir, + 'SCONS_SCRIPT_DIR': scons_script_dir, + 'SCONS_CWD': cwd, +} if scons: # Let the version of SCons that the -x option pointed to find # its own modules. - os.environ['SCONS'] = scons + testenv['SCONS'] = scons elif scons_lib_dir: # Because SCons is really aggressive about finding its modules, # it sometimes finds SCons modules elsewhere on the system. # This forces SCons to use the modules that are being tested. - os.environ['SCONS_LIB_DIR'] = scons_lib_dir + testenv['SCONS_LIB_DIR'] = scons_lib_dir -if scons_exec: - os.environ['SCONS_EXEC'] = '1' +if args.scons_exec: + testenv['SCONS_EXEC'] = '1' -if external: - os.environ['SCONS_EXTERNAL_TEST'] = '1' +if args.external: + testenv['SCONS_EXTERNAL_TEST'] = '1' -os.environ['SCONS_RUNTEST_DIR'] = scons_runtest_dir -os.environ['SCONS_SCRIPT_DIR'] = scons_script_dir -os.environ['SCONS_TOOLS_DIR'] = scons_tools_dir -os.environ['SCONS_CWD'] = cwd -os.environ['SCONS_VERSION'] = version +# Insert scons path and path for testing framework to PYTHONPATH +scriptpath = os.path.dirname(os.path.realpath(__file__)) +frameworkpath = os.path.join(scriptpath, 'testing', 'framework') +testenv['PYTHONPATH'] = os.pathsep.join((scons_lib_dir, frameworkpath)) +pythonpath = os.environ.get('PYTHONPATH') +if pythonpath: + testenv['PYTHONPATH'] = testenv['PYTHONPATH'] + os.pathsep + pythonpath + +if sys.platform == 'win32': + # Windows doesn't support "shebang" lines directly (the Python launcher + # and Windows Store version do, but you have to get them launched first) + # so to directly launch a script we depend on an assoc for .py to work. + # Some systems may have none, and in some cases IDE programs take over + # the assoc. Detect this so the small number of tests affected can skip. + try: + python_assoc = get_template_command('.py') + except OSError: + python_assoc = None + if not python_assoc or "py" not in python_assoc: + testenv['SCONS_NO_DIRECT_SCRIPT'] = '1' -old_pythonpath = os.environ.get('PYTHONPATH') +os.environ.update(testenv) # Clear _JAVA_OPTIONS which java tools output to stderr when run breaking tests if '_JAVA_OPTIONS' in os.environ: del os.environ['_JAVA_OPTIONS'] -# FIXME: the following is necessary to pull in half of the testing -# harness from $srcdir/etc. Those modules should be transfered -# to testing/, in which case this manipulation of PYTHONPATH -# should be able to go away. -pythonpaths = [pythonpath_dir] - -scriptpath = os.path.dirname(os.path.realpath(__file__)) - -# Add path for testing framework to PYTHONPATH -pythonpaths.append(os.path.join(scriptpath, 'testing', 'framework')) - - -os.environ['PYTHONPATH'] = os.pathsep.join(pythonpaths) - -if old_pythonpath: - os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + \ - os.pathsep + \ - 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): @@ -576,111 +620,103 @@ def find_e2e_tests(directory): """ Look for end-to-end tests """ result = [] - for dirpath, dirnames, filenames in os.walk(directory): # Skip folders containing a sconstest.skip file if 'sconstest.skip' in filenames: continue - try: - with open(os.path.join(dirpath, ".exclude_tests")) as f: - excludes = [e.split("#", 1)[0].strip() for e in f.readlines()] - except EnvironmentError: - excludes = [] + + # Slurp in any tests in exclude lists + excludes = [] + if ".exclude_tests" in filenames: + p = Path(dirpath).joinpath(".exclude_tests") + # TODO simplify when Py3.5 dropped + if sys.version_info.major == 3 and sys.version_info.minor < 6: + excludefile = p.resolve() + else: + excludefile = p.resolve(strict=True) + with excludefile.open() as f: + excludes = scanlist(f) + for fname in filenames: if fname.endswith(".py") and fname not in excludes: result.append(os.path.join(dirpath, fname)) + return sorted(result) -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] +# initial selection: +unittests = [] +endtests = [] +if args.testlistfile: + with args.testlistfile.open() as f: + 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: + if args.all: testpaths = ['SCons', 'test'] - elif args: - testpaths = args + elif args.testlist: + testpaths = args.testlist for tp in testpaths: # 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 = sorted(unittests + endtests) - tests.extend(unittests) - tests.extend(endtests) - tests.sort() + +# Remove exclusions: +if args.e2e_only: + tests = [t for t in tests if not t.endswith("Tests.py")] +if args.unit_only: + tests = [t for t in tests if t.endswith("Tests.py")] +if args.excludelistfile: + with args.excludelistfile.open() 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. + sys.stderr.write(parser.format_usage() + """ +error: 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: +if args.list_only: for t in tests: sys.stdout.write(t.path + "\n") sys.exit(0) -if not python: +if not args.python: if os.name == 'java': - python = os.path.join(sys.prefix, 'jython') + args.python = os.path.join(sys.prefix, 'jython') else: - python = sys.executable -os.environ["python_executable"] = python + args.python = sys.executable +os.environ["python_executable"] = args.python + +if args.print_times: -if print_times: def print_time(fmt, tm): sys.stdout.write(fmt % tm) + else: + def print_time(fmt, tm): pass @@ -697,10 +733,9 @@ 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 @@ -720,30 +755,41 @@ if io_lock: io_lock.release() - if quit_on_failure and t.status == 1: + if args.quit_on_failure and t.status == 1: print("Exiting due to error") print(t.status) sys.exit(1) 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: - command_args.append(debug) - if devmode and sys.version_info >= (3, 7, 0): - command_args.append('-X dev') + command_args.extend(['-m', debug]) + if args.devmode and sys.version_info >= (3, 7, 0): + command_args.append('-X dev') command_args.append(t.path) - if options.runner and t.path in unittests: + if args.runner and t.path in unittests: # 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) - if printcommand: - if print_progress: + command_args.append('--runner ' + args.runner) + t.command_args = [escape(args.python)] + command_args + t.command_str = " ".join(t.command_args) + if args.printcommand: + if args.print_progress: t.headline += "%d/%d (%.2f%s) %s\n" % ( - t.num, - total_num_tests, + t.num, total_num_tests, float(t.num) * 100.0 / float(total_num_tests), "%", t.command_str, @@ -753,29 +799,33 @@ 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() + if args.execute_tests: + t.execute(env) t.test_time = time_func() - test_start_time log_result(t, io_lock=io_lock) class RunTest(threading.Thread): - """ Test Runner class + """ Test Runner class. One instance will be created for each job thread in multi-job mode """ - 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) + def __init__(self, queue=None, io_lock=None, group=None, target=None, name=None): + super().__init__(group=group, target=target, name=name) self.queue = queue self.io_lock = io_lock @@ -784,14 +834,14 @@ run_test(t, io_lock=self.io_lock, run_async=True) self.queue.task_done() -if jobs > 1: - print("Running tests using %d jobs" % jobs) +if args.jobs > 1: + print("Running tests using %d jobs" % args.jobs) testq = Queue() for t in tests: testq.put(t) testlock = threading.Lock() # Start worker threads to consume the queue - threads = [RunTest(queue=testq, io_lock=testlock) for _ in range(jobs)] + threads = [RunTest(queue=testq, io_lock=testlock) for _ in range(args.jobs)] for t in threads: t.daemon = True t.start() @@ -810,8 +860,9 @@ fail = [t for t in tests if t.status == 1] no_result = [t for t in tests if t.status == 2] -if len(tests) != 1 and execute_tests: - if passed and print_passed_summary: +# print summaries, but only if multiple tests were run +if len(tests) != 1 and args.execute_tests: + if passed and args.print_passed_summary: if len(passed) == 1: sys.stdout.write("\nPassed the following test:\n") else: @@ -833,21 +884,30 @@ paths = [x.path for x in no_result] sys.stdout.write("\t" + "\n\t".join(paths) + "\n") -if options.xml: - if options.xml == '-': +# save the fails to a file +if args.error_log: + with open(args.error_log, "w") as f: + if fail: + paths = [x.path for x in fail] + for test in paths: + print(test, file=f) + # if there are no fails, file will be cleared + +if args.xml: + if args.output == '-': f = sys.stdout else: - f = open(options.xml, 'w') + f = open(args.xml, 'w') tests[0].header(f) #f.write("test_result = [\n") for t in tests: t.write(f) tests[0].footer(f) #f.write("];\n") - if options.xml != '-': + if args.output != '-': f.close() -if options.output: +if args.output: if isinstance(sys.stdout, Tee): sys.stdout.file.close() if isinstance(sys.stderr, Tee): @@ -855,7 +915,8 @@ if fail: sys.exit(1) -elif no_result: +elif no_result and args.dont_ignore_skips: + # if no fails, but skips were found sys.exit(2) else: sys.exit(0) diff -Nru scons-4.0.1+dfsg/SCons/Action.py scons-4.4.0+dfsg/SCons/Action.py --- scons-4.0.1+dfsg/SCons/Action.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Action.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,11 +1,34 @@ -"""SCons.Action +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -This encapsulates information about executing any sort of action that +"""SCons Actions. + +Information about executing any sort of action that can build one or more target Nodes (typically files) from one or more source Nodes (also typically files) given a specific Environment. The base class here is ActionBase. The base class supplies just a few -OO utility methods and some generic methods for displaying information +utility methods and some generic methods for displaying information about an Action in response to the various commands that control printing. A second-level base class is _ActionAction. This extends ActionBase @@ -31,7 +54,7 @@ get_contents() Fetches the "contents" of an Action for signature calculation - plus the varlist. This is what gets MD5 checksummed to decide + plus the varlist. This is what gets checksummed to decide if a target needs to be rebuilt because its action changed. genstring() @@ -60,7 +83,7 @@ get_presig() Fetches the "contents" of a subclass for signature calculation. The varlist is added to this to produce the Action's contents. - TODO(?): Change this to always return ascii/bytes and not unicode (or py3 strings) + TODO(?): Change this to always return bytes and not str? strfunction() Returns a substituted string representation of the Action. @@ -77,36 +100,12 @@ """ -# __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 import sys import subprocess from subprocess import DEVNULL -import itertools import inspect from collections import OrderedDict @@ -122,9 +121,9 @@ class _null: pass -print_actions = 1 -execute_actions = 1 -print_actions_presub = 0 +print_actions = True +execute_actions = True +print_actions_presub = False # Use pickle protocol 1 when pickling functions for signature # otherwise python3 and python2 will yield different pickles @@ -145,7 +144,7 @@ def default_exitstatfunc(s): return s -strip_quotes = re.compile('^[\'"](.*)[\'"]$') +strip_quotes = re.compile(r'^[\'"](.*)[\'"]$') def _callable_contents(obj): @@ -756,6 +755,29 @@ return default_ENV +def _resolve_shell_env(env, target, source): + """ + First get default environment. + Then if SHELL_ENV_GENERATORS is set and is iterable, + call each callable in that list to allow it to alter + the created execution environment. + """ + ENV = get_default_ENV(env) + shell_gen = env.get('SHELL_ENV_GENERATORS') + if shell_gen: + try: + shell_gens = iter(shell_gen) + except TypeError: + raise SCons.Errors.UserError("SHELL_ENV_GENERATORS must be iteratable.") + else: + ENV = ENV.copy() + for generator in shell_gens: + ENV = generator(env, target, source, ENV) + if not isinstance(ENV, dict): + raise SCons.Errors.UserError(f"SHELL_ENV_GENERATORS function: {generator} must return a dict.") + return ENV + + def _subproc(scons_env, cmd, error='ignore', **kw): """Wrapper for subprocess which pulls from construction env. @@ -800,9 +822,25 @@ if error == 'raise': raise # return a dummy Popen instance that only returns error class dummyPopen: - def __init__(self, e): self.exception = e - def communicate(self, input=None): return ('', '') - def wait(self): return -self.exception.errno + def __init__(self, e): + self.exception = e + # Add the following two to enable using the return value as a context manager + # for example + # with Action._subproc(...) as po: + # logic here which uses po + + def __enter__(self): + return self + + def __exit__(self, *args): + pass + + def communicate(self, input=None): + return ('', '') + + def wait(self): + return -self.exception.errno + stdin = None class f: def read(self): return '' @@ -833,7 +871,7 @@ # variables. if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandAction') - _ActionAction.__init__(self, **kw) + super().__init__(**kw) if is_List(cmd): if [c for c in cmd if is_List(c)]: raise TypeError("CommandAction should be given only " @@ -909,7 +947,7 @@ escape = env.get('ESCAPE', lambda x: x) - ENV = get_default_ENV(env) + ENV = _resolve_shell_env(env, target, source) # Ensure that the ENV values are all strings: for key, value in ENV.items(): @@ -968,7 +1006,7 @@ if is_String(icd) and icd[:1] == '$': icd = env.subst(icd) - if not icd or str(icd).lower in ('0', 'none', 'false', 'no', 'off'): + if not icd or str(icd).lower() in ('0', 'none', 'false', 'no', 'off'): return [] try: @@ -976,7 +1014,7 @@ except ValueError: icd_int = None - if (icd_int and icd_int > 1) or icd == 'all': + if (icd_int and icd_int > 1) or str(icd).lower() == 'all': # An integer value greater than 1 specifies the number of entries # to scan. "all" means to scan all. return self._get_implicit_deps_heavyweight(target, source, env, executor, icd_int) @@ -1216,7 +1254,7 @@ # This is weird, just do the best we can. self.funccontents = _object_contents(execfunction) - _ActionAction.__init__(self, **kw) + super().__init__(**kw) def function_name(self): try: diff -Nru scons-4.0.1+dfsg/SCons/ActionTests.py scons-4.4.0+dfsg/SCons/ActionTests.py --- scons-4.0.1+dfsg/SCons/ActionTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/ActionTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -72,16 +71,16 @@ if 'ACTPY_PIPE' in os.environ: if 'PIPE_STDOUT_FILE' in os.environ: - with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f: - stdout_msg = f.read() + with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f: + stdout_msg = f.read() else: - stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:]) - sys.stdout.write( stdout_msg ) + stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:]) + sys.stdout.write(stdout_msg) if 'PIPE_STDERR_FILE' in os.environ: - with open(os.environ['PIPE_STDERR_FILE'], 'r') as f: - stderr_msg = f.read() + with open(os.environ['PIPE_STDERR_FILE'], 'r') as f: + stderr_msg = f.read() else: - stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:]) + stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:]) sys.stderr.write(stderr_msg) sys.exit(0) """) @@ -114,8 +113,9 @@ return self.literal def escape(self, escape_func): - """Escape the string with the supplied function. The - function is expected to take an arbitrary string, then + """Escape the string with the supplied function. + + The function is expected to take an arbitrary string, then return it with all special characters escaped and ready for passing to the command interpreter. @@ -158,8 +158,8 @@ def __setitem__(self, item, value): self.d[item] = value - def has_key(self, item): - return item in self.d + def __contains__(self, key): + return key in self.d def get(self, key, value=None): return self.d.get(key, value) @@ -252,8 +252,8 @@ def test_positional_args(pos_callback, cmd, **kw): - """Test that Action() returns the expected type and that positional args work. - """ + """Test that Action returns the expected type and positional args work.""" + act = SCons.Action.Action(cmd, **kw) pos_callback(act) assert act.varlist == (), act.varlist @@ -294,7 +294,7 @@ test_varlist(pos_callback, none, cmd, None, **kw) - """Test handling of bad cmdstrfunc arguments """ + # Test handling of bad cmdstrfunc arguments try: a = SCons.Action.Action(cmd, [], **kw) except SCons.Errors.UserError as e: @@ -311,8 +311,7 @@ """Test the Action() factory function""" def test_FunctionAction(self): - """Test the Action() factory's creation of FunctionAction objects - """ + """Test the Action() factory's creation of FunctionAction objects.""" def foo(): pass @@ -326,8 +325,7 @@ test_positional_args(func_action, [foo]) def test_CommandAction(self): - """Test the Action() factory's creation of CommandAction objects - """ + """Test the Action() factory's creation of CommandAction objects.""" def cmd_action(a): assert isinstance(a, SCons.Action.CommandAction), a @@ -344,8 +342,8 @@ test_positional_args(line_action, [["explicit", "command", "line"]]) def test_ListAction(self): - """Test the Action() factory's creation of ListAction objects - """ + """Test the Action() factory's creation of ListAction objects.""" + a1 = SCons.Action.Action(["x", "y", "z", ["a", "b", "c"]]) assert isinstance(a1, SCons.Action.ListAction), a1 assert a1.varlist == (), a1.varlist @@ -402,8 +400,7 @@ assert a5.list[1].strfunction == foo, a5.list[1].strfunction def test_CommandGeneratorAction(self): - """Test the Action() factory's creation of CommandGeneratorAction objects - """ + """Test the Action factory's creation of CommandGeneratorAction objects.""" def foo(): pass @@ -414,8 +411,7 @@ test_positional_args(gen_action, foo, generator=1) def test_LazyCmdGeneratorAction(self): - """Test the Action() factory's creation of lazy CommandGeneratorAction objects - """ + """Test the Action factory's creation of lazy CommandGeneratorAction objects.""" def lazy_action(a): assert isinstance(a, SCons.Action.LazyAction), a @@ -426,8 +422,8 @@ test_positional_args(lazy_action, "${FOO}") def test_no_action(self): - """Test when the Action() factory can't create an action object - """ + """Test when the Action() factory can't create an action object.""" + try: a5 = SCons.Action.Action(1) except TypeError: @@ -436,8 +432,8 @@ assert 0, "Should have thrown a TypeError creating Action from an int." def test_reentrance(self): - """Test the Action() factory when the action is already an Action object - """ + """Test the Action factory when the action is already an Action object.""" + a1 = SCons.Action.Action("foo") a2 = SCons.Action.Action(a1) assert a2 is a1, a2 @@ -446,8 +442,7 @@ class _ActionActionTestCase(unittest.TestCase): def test__init__(self): - """Test creation of _ActionAction objects - """ + """Test creation of _ActionAction objects.""" def func1(): pass @@ -520,8 +515,7 @@ assert a.varlist is t, a.varlist def test_dup_keywords(self): - """Test handling of both cmdstr and strfunction arguments - """ + """Test handling of both cmdstr and strfunction arguments.""" def func(): pass @@ -536,8 +530,8 @@ raise Exception("did not catch expected UserError") def test___cmp__(self): - """Test Action comparison - """ + """Test Action comparison.""" + a1 = SCons.Action.Action("x") a2 = SCons.Action.Action("x") assert a1 == a2 @@ -546,8 +540,8 @@ assert a2 != a3 def test_print_cmd_lines(self): - """Test the print_cmd_lines() method - """ + """Test the print_cmd_lines() method.""" + save_stdout = sys.stdout try: @@ -566,8 +560,8 @@ sys.stdout = save_stdout def test___call__(self): - """Test calling an Action - """ + """Test calling an Action.""" + save_stdout = sys.stdout save_print_actions = SCons.Action.print_actions @@ -754,8 +748,8 @@ SCons.Action.execute_actions = save_execute_actions def test_presub_lines(self): - """Test the presub_lines() method - """ + """Test the presub_lines() method.""" + env = Environment() a = SCons.Action.Action("x") s = a.presub_lines(env) @@ -876,8 +870,8 @@ class CommandActionTestCase(unittest.TestCase): def test___init__(self): - """Test creation of a command Action - """ + """Test creation of a command Action.""" + a = SCons.Action.CommandAction(["xyzzy"]) assert a.cmd_list == ["xyzzy"], a.cmd_list assert a.cmdstr is _null, a.cmdstr @@ -887,8 +881,8 @@ assert a.cmdstr == "cadabra", a.cmdstr def test___str__(self): - """Test fetching the pre-substitution string for command Actions - """ + """Test fetching the pre-substitution string for command Actions.""" + env = Environment() act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE') s = str(act) @@ -901,8 +895,7 @@ assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s def test_genstring(self): - """Test the genstring() method for command Actions - """ + """Test the genstring() method for command Actions.""" env = Environment() t1 = DummyNode('t1') @@ -939,8 +932,7 @@ assert s == expect, s def test_strfunction(self): - """Test fetching the string representation of command Actions - """ + """Test fetching the string representation of command Actions.""" env = Environment() t1 = DummyNode('t1') @@ -1091,9 +1083,8 @@ assert s == "foo bar", s def test_execute(self): - """Test execution of command Actions + """Test execution of command Actions.""" - """ try: env = self.env except AttributeError: @@ -1248,8 +1239,7 @@ assert r == 0, r def test_set_handler(self): - """Test setting the command handler... - """ + """Test setting the command handler...""" class Test: def __init__(self): @@ -1300,8 +1290,7 @@ assert t.executed == ['**xyzzy**'], t.executed def test_get_contents(self): - """Test fetching the contents of a command Action - """ + """Test fetching the contents of a command Action.""" def CmdGen(target, source, env, for_signature): assert for_signature @@ -1372,16 +1361,54 @@ c = a.get_contents(target=t, source=s, env=env) assert c == b"s4 s5", c + def test_get_implicit_deps(self): + """Test getting the implicit dependencies of a command Action.""" + + class SpecialEnvironment(Environment): + def WhereIs(self, prog): + return prog + + class fs: + def File(name): + return name + + env = SpecialEnvironment() + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), [_python_]) + + for false_like_value in [False, 0, None, "None", "False", "0", "NONE", "FALSE", "off", "OFF", "NO", "no"]: + env = SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES=false_like_value) + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), []) + + env = SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES="$SUBST_VALUE", SUBST_VALUE=false_like_value) + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), []) + + for true_like_value in [True, 1, "True", "TRUE", "1"]: + env = SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES=true_like_value) + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), [_python_]) + + env = SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES="$SUBST_VALUE", SUBST_VALUE=true_like_value) + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), [_python_]) + + for all_like_Value in ["all", "ALL", 2, "2"]: + env = SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES=all_like_Value) + a = SCons.Action.CommandAction([_python_, exit_py]) + self.assertEqual(a.get_implicit_deps(target=[], source=[], env=env), [_python_, exit_py]) + class CommandGeneratorActionTestCase(unittest.TestCase): def factory(self, act, **kw): """Pass any keywords as a dict""" + return SCons.Action.CommandGeneratorAction(act, kw) def test___init__(self): - """Test creation of a command generator Action - """ + """Test creation of a command generator Action.""" def f(target, source, env): pass @@ -1390,8 +1417,7 @@ assert a.generator == f def test___str__(self): - """Test the pre-substitution strings for command generator Actions - """ + """Test the pre-substitution strings for command generator Actions.""" def f(target, source, env, for_signature, self=self): # See if "env" is really a construction environment (or @@ -1408,8 +1434,7 @@ assert s == 'FOO', s def test_genstring(self): - """Test the command generator Action genstring() method - """ + """Test the command generator Action genstring() method.""" def f(target, source, env, for_signature, self=self): dummy = env['dummy'] @@ -1423,8 +1448,7 @@ assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s def test_execute(self): - """Test executing a command generator Action - """ + """Test executing a command generator Action.""" def f(target, source, env, for_signature, self=self): dummy = env['dummy'] @@ -1483,8 +1507,7 @@ assert self.rfile_called def test_get_contents(self): - """Test fetching the contents of a command generator Action - """ + """Test fetching the contents of a command generator Action.""" def f(target, source, env, for_signature): foo = env['foo'] @@ -1504,8 +1527,7 @@ assert c == b"guux FFF BBB test", c def test_get_contents_of_function_action(self): - """Test contents of a CommandGeneratorAction-generated FunctionAction - """ + """Test contents of a CommandGeneratorAction-generated FunctionAction.""" def LocalFunc(): pass @@ -1517,6 +1539,8 @@ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'), } meth_matches = [ @@ -1534,12 +1558,12 @@ a = self.factory(f_global) c = a.get_contents(target=[], source=[], env=env) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr( + assert c == func_matches[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr( func_matches[sys.version_info[:2]]) a = self.factory(f_local) c = a.get_contents(target=[], source=[], env=env) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr( + assert c == func_matches[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr( func_matches[sys.version_info[:2]]) def f_global2(target, source, env, for_signature): @@ -1562,8 +1586,7 @@ class FunctionActionTestCase(unittest.TestCase): def test___init__(self): - """Test creation of a function Action - """ + """Test creation of a function Action.""" def func1(): pass @@ -1586,8 +1609,7 @@ assert a.strfunction == func3, a.strfunction def test___str__(self): - """Test the __str__() method for function Actions - """ + """Test the __str__() method for function Actions.""" def func1(): pass @@ -1605,8 +1627,8 @@ assert s == "class1(target, source, env)", s def test_execute(self): - """Test executing a function Action - """ + """Test executing a function Action.""" + self.inc = 0 def f(target, source, env): @@ -1684,8 +1706,7 @@ assert self.string_it def test_get_contents(self): - """Test fetching the contents of a function Action - """ + """Test fetching the contents of a function Action.""" def LocalFunc(): pass @@ -1696,6 +1717,8 @@ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'), } @@ -1705,6 +1728,8 @@ (3, 7): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 8): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 9): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 10): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 11): bytearray(b'1, 1, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'), } def factory(act, **kw): @@ -1712,20 +1737,23 @@ a = factory(GlobalFunc) c = a.get_contents(target=[], source=[], env=Environment()) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) a = factory(LocalFunc) c = a.get_contents(target=[], source=[], env=Environment()) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) matches_foo = func_matches[sys.version_info[:2]] + b'foo' a = factory(GlobalFunc, varlist=['XYZ']) c = a.get_contents(target=[], source=[], env=Environment()) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) # assert c in func_matches, repr(c) c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo')) @@ -1736,8 +1764,9 @@ a = factory(GlobalFunc, varlist='XYZ') c = a.get_contents(target=[], source=[], env=Environment()) # assert c in func_matches, repr(c) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo')) assert c in matches_foo, repr(c) @@ -1757,12 +1786,12 @@ lc = LocalClass() a = factory(lc.LocalMethod) c = a.get_contents(target=[], source=[], env=Environment()) - assert c == meth_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - meth_matches[sys.version_info[:2]]) + assert ( + c == meth_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(meth_matches[sys.version_info[:2]]) def test_strfunction(self): - """Test the FunctionAction.strfunction() method - """ + """Test the FunctionAction.strfunction() method.""" def func(): pass @@ -1786,8 +1815,7 @@ class ListActionTestCase(unittest.TestCase): def test___init__(self): - """Test creation of a list of subsidiary Actions - """ + """Test creation of a list of subsidiary Actions.""" def func(): pass @@ -1799,8 +1827,7 @@ assert a.list[2].list[0].cmd_list == 'y' def test___str__(self): - """Test the __str__() method for a list of subsidiary Actions - """ + """Test the __str__() method for a list of subsidiary Actions.""" def f(target, source, env): pass @@ -1813,8 +1840,7 @@ assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s def test_genstring(self): - """Test the genstring() method for a list of subsidiary Actions - """ + """Test the genstring() method for a list of subsidiary Actions.""" def f(target, source, env): pass @@ -1828,8 +1854,7 @@ assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s def test_execute(self): - """Test executing a list of subsidiary Actions - """ + """Test executing a list of subsidiary Actions.""" self.inc = 0 def f(target, source, env): @@ -1865,8 +1890,8 @@ assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c def test_get_contents(self): - """Test fetching the contents of a list of subsidiary Actions - """ + """Test fetching the contents of a list of subsidiary Actions.""" + self.foo = 0 def gen(target, source, env, for_signature): @@ -1884,8 +1909,8 @@ class LazyActionTestCase(unittest.TestCase): def test___init__(self): - """Test creation of a lazy-evaluation Action - """ + """Test creation of a lazy-evaluation Action.""" + # Environment variable references should create a special type # of LazyAction that lazily evaluates the variable for whether # it's a string or something else before doing anything. @@ -1898,8 +1923,7 @@ assert a10.var == 'FOO', a10.var def test_genstring(self): - """Test the lazy-evaluation Action genstring() method - """ + """Test the lazy-evaluation Action genstring() method.""" def f(target, source, env): pass @@ -1913,8 +1937,7 @@ assert s == 'xxx', s def test_execute(self): - """Test executing a lazy-evaluation Action - """ + """Test executing a lazy-evaluation Action.""" def f(target, source, env): s = env['s'] @@ -1930,16 +1953,15 @@ assert c == "act.py: 'lazy'\n", c def test_get_contents(self): - """Test fetching the contents of a lazy-evaluation Action - """ + """Test fetching the contents of a lazy-evaluation Action.""" + a = SCons.Action.Action("${FOO}") env = Environment(FOO=[["This", "is", "a", "test"]]) c = a.get_contents(target=[], source=[], env=env) assert c == b"This is a test", c def test_get_contents_of_function_action(self): - """Test fetching the contents of a lazy-evaluation FunctionAction - """ + """Test fetching the contents of a lazy-evaluation FunctionAction.""" def LocalFunc(): pass @@ -1950,6 +1972,8 @@ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), (3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'), } meth_matches = [ @@ -1965,21 +1989,24 @@ env = Environment(FOO=factory(GlobalFunc)) c = a.get_contents(target=[], source=[], env=env) # assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) env = Environment(FOO=factory(LocalFunc)) c = a.get_contents(target=[], source=[], env=env) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) # matches_foo = [x + b"foo" for x in func_matches] matches_foo = func_matches[sys.version_info[:2]] + b'foo' env = Environment(FOO=factory(GlobalFunc, varlist=['XYZ'])) c = a.get_contents(target=[], source=[], env=env) - assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - func_matches[sys.version_info[:2]]) + assert ( + c == func_matches[sys.version_info[:2]] + ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]]) env['XYZ'] = 'foo' c = a.get_contents(target=[], source=[], env=env) @@ -1989,6 +2016,7 @@ class ActionCallerTestCase(unittest.TestCase): def test___init__(self): """Test creation of an ActionCaller""" + ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO': 4, 'BAR': 5}) assert ac.parent == 1, ac.parent assert ac.args == [2, 3], ac.args @@ -2009,20 +2037,25 @@ (3, 7): b'd\x00S\x00', (3, 8): b'd\x00S\x00', (3, 9): b'd\x00S\x00', - + (3, 10): b'd\x00S\x00', + (3, 11): b'\x97\x00d\x00S\x00', } af = SCons.Action.ActionFactory(GlobalFunc, strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - matches[sys.version_info[:2]]) + assert c == matches[sys.version_info[:2]], ( + f"Got\n{c!r}\nExpected one of \n" + + repr(matches[sys.version_info[:2]]) + ) af = SCons.Action.ActionFactory(LocalFunc, strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - matches[sys.version_info[:2]]) + assert c == matches[sys.version_info[:2]], ( + f"Got\n{c!r}\nExpected one of \n" + + repr(matches[sys.version_info[:2]]) + ) class LocalActFunc: def __call__(self): @@ -2031,14 +2064,18 @@ af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - matches[sys.version_info[:2]]) + assert c == matches[sys.version_info[:2]], ( + f"Got\n{c!r}\nExpected one of \n" + + repr(matches[sys.version_info[:2]]) + ) af = SCons.Action.ActionFactory(LocalActFunc(), strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr( - matches[sys.version_info[:2]]) + assert c == matches[sys.version_info[:2]], ( + f"Got\n{c!r}\nExpected one of \n" + + repr(matches[sys.version_info[:2]]) + ) matches = [ b"", @@ -2048,13 +2085,12 @@ af = SCons.Action.ActionFactory(str, strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c == "" or \ - c == "" or \ - c == "", repr(c) + assert c in ("", "", ""), repr(c) # ^^ class str for python3 def test___call__(self): """Test calling an ActionCaller""" + actfunc_args = [] def actfunc(a1, a2, a3, args=actfunc_args): @@ -2082,6 +2118,7 @@ def test_strfunction(self): """Test calling the ActionCaller strfunction() method""" + strfunc_args = [] def actfunc(a1, a2, a3, a4): @@ -2118,6 +2155,7 @@ def test___call__(self): """Test calling whatever's returned from an ActionFactory""" + actfunc_args = [] strfunc_args = [] @@ -2134,12 +2172,12 @@ class ActionCompareTestCase(unittest.TestCase): - def test_1_solo_name(self): """Test Lazy Cmd Generator Action get_name alone. Basically ensures we can locate the builder, comparing it to itself along the way.""" + bar = SCons.Builder.Builder(action={}) env = Environment(BUILDERS={'BAR': bar}) name = bar.get_name(env) @@ -2150,12 +2188,12 @@ Ensure that we can compare builders (and thereby actions) to each other safely.""" + foo = SCons.Builder.Builder(action='$FOO', suffix='.foo') bar = SCons.Builder.Builder(action={}) assert foo != bar assert foo.action != bar.action - env = Environment(BUILDERS={'FOO': foo, - 'BAR': bar}) + env = Environment(BUILDERS={'FOO': foo, 'BAR': bar}) name = foo.get_name(env) assert name == 'FOO', name name = bar.get_name(env) @@ -2173,10 +2211,7 @@ bar = SCons.Builder.Builder(action={}, suffix={None: '.bar'}) bar.add_action('.cow', "$MOO") dog = SCons.Builder.Builder(suffix='.bar') - - env = Environment(BUILDERS={'FOO': foo, - 'BAR': bar, - 'DOG': dog}) + env = Environment(BUILDERS={'FOO': foo, 'BAR': bar, 'DOG': dog}) assert foo.get_name(env) == 'FOO', foo.get_name(env) assert bar.get_name(env) == 'BAR', bar.get_name(env) @@ -2195,7 +2230,6 @@ class ObjectContentsTestCase(unittest.TestCase): - def test_function_contents(self): """Test that Action._function_contents works""" @@ -2203,18 +2237,25 @@ """A test function""" return a - # Since the python bytecode has per version differences, we need different expected results per version + # Since the python bytecode has per version differences, + # we need different expected results per version expected = { - (3, 5): bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'), - (3, 6): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), - (3, 7): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), - (3, 8): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), - (3, 9): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), + (3, 5): (bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()')), + (3, 6): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')), + (3, 7): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')), + (3, 8): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')), + (3, 9): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')), + (3, 10): ( + bytearray(b'3, 3, 0, 0,(N.),(),(|\x00S\x00),(),()'), + bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), + ), # 3.10.1, 3.10.2 + (3, 11): bytearray(b'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'), } c = SCons.Action._function_contents(func1) - assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr( - expected[sys.version_info[:2]]) + assert c in expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr( + expected[sys.version_info[:2]] + ) def test_object_contents(self): """Test that Action._object_contents works""" @@ -2225,22 +2266,34 @@ # c = SCons.Action._object_instance_content(o) - # Since the python bytecode has per version differences, we need different expected results per version + # Since the python bytecode has per version differences, + # we need different expected results per version expected = { (3, 5): bytearray( - b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"), + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}" + ), (3, 6): bytearray( - b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"), + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}" + ), (3, 7): bytearray( - b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"), + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}" + ), (3, 8): bytearray( - b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"), + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}" + ), (3, 9): bytearray( - b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"), + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}" + ), + (3, 10): bytearray( + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}" + ), + (3, 11): bytearray( + b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x97\x00d\x01|\x00_\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02|\x00_\x01\x00\x00\x00\x00\x00\x00\x00\x00d\x00S\x00),(),(),2, 2, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()}}{{{a=a,b=b}}}"), } - assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr( - expected[sys.version_info[:2]]) + assert c == expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr( + expected[sys.version_info[:2]] + ) def test_code_contents(self): """Test that Action._code_contents works""" @@ -2250,24 +2303,43 @@ # Since the python bytecode has per version differences, we need different expected results per version expected = { - (3, 5): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'), - (3, 6): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'), - (3, 7): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'), - (3, 8): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'), - (3, 9): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'), + (3, 5): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)' + ), + (3, 6): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)' + ), + (3, 7): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)' + ), + (3, 8): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)' + ), + (3, 9): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)' + ), + (3, 10): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)' + ), + (3, 11): bytearray( + b'0, 0, 0, 0,(Hello, World!),(print),(\x97\x00\x02\x00e\x00d\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x01S\x00)'), } - assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(expected[ - sys.version_info[:2]]) + assert c == expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr( + expected[sys.version_info[:2]] + ) def test_uncaught_exception_bubbles(self): """Test that _subproc bubbles uncaught exceptions""" + try: - pobj = SCons.Action._subproc(Environment(), - None, - stdin='devnull', - stderr='devnull', - stdout=subprocess.PIPE) + pobj = SCons.Action._subproc( + Environment(), + None, + stdin='devnull', + stderr='devnull', + stdout=subprocess.PIPE, + ) pobj.wait() except EnvironmentError: pass diff -Nru scons-4.0.1+dfsg/SCons/Action.xml scons-4.4.0+dfsg/SCons/Action.xml --- scons-4.0.1+dfsg/SCons/Action.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Action.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ + +Do not put library search directives directly +into &cv-LINKFLAGS; or &cv-SHLINKFLAGS; +as the result will be non-portable. + +
+ + +Note: +directory names in &cv-LIBPATH; will be looked-up relative to the +directory of the SConscript file +when they are used in a command. +To force &scons; +to look-up a directory relative to the root of the source tree use +the # prefix: @@ -472,8 +498,7 @@ The directory look-up can also be forced using the -&Dir;() -function: +&f-link-Dir; function: @@ -484,16 +509,15 @@ The directory list will be added to command lines through the automatically-generated -&cv-_LIBDIRFLAGS; +&cv-link-_LIBDIRFLAGS; construction variable, which is constructed by respectively prepending and appending the values of the -&cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX; +&cv-link-LIBDIRPREFIX; and &cv-link-LIBDIRSUFFIX; construction variables -to the beginning and end -of each directory in &cv-LIBPATH;. +to each directory in &cv-LIBPATH;. Any command lines you define that need -the LIBPATH directory list should +the &cv-LIBPATH; directory list should include &cv-_LIBDIRFLAGS;: @@ -507,24 +531,32 @@ A list of one or more libraries -that will be linked with -any executable programs -created by this environment. +that will be added to the link line +for linking with any executable program, shared library, or loadable module +created by the &consenv; or override. +String-valued library names should include +only the library base names, +without prefixes such as lib +or suffixes such as .so or .dll. The library list will be added to command lines through the automatically-generated -&cv-_LIBFLAGS; -construction variable, +&cv-_LIBFLAGS; &consvar; which is constructed by respectively prepending and appending the values of the -&cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX; -construction variables -to the beginning and end -of each filename in &cv-LIBS;. +&cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX; &consvars; +to each library name in &cv-LIBS;. +Library name strings should not include a +path component, instead the compiler will be +directed to look for libraries in the paths +specified by &cv-link-LIBPATH;. + + + Any command lines you define that need -the LIBS library list should +the &cv-LIBS; library list should include &cv-_LIBFLAGS;: @@ -534,12 +566,12 @@ If you add a -File +File object to the &cv-LIBS; list, the name of that file will be added to &cv-_LIBFLAGS;, -and thus the link line, as is, without +and thus to the link line, as-is, without &cv-LIBLINKPREFIX; or &cv-LIBLINKSUFFIX;. diff -Nru scons-4.0.1+dfsg/SCons/Environment.py scons-4.4.0+dfsg/SCons/Environment.py --- scons-4.0.1+dfsg/SCons/Environment.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Environment.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -57,8 +53,26 @@ import SCons.SConsign import SCons.Subst import SCons.Tool -import SCons.Util import SCons.Warnings +from SCons.Util import ( + AppendPath, + CLVar, + LogicalLines, + MethodWrapper, + PrependPath, + Split, + WhereIs, + flatten, + is_Dict, + is_List, + is_Sequence, + is_String, + is_Tuple, + semi_deepcopy, + semi_deepcopy_dict, + to_String_for_subst, + uniquer_hashables, +) class _Null: pass @@ -72,37 +86,37 @@ CleanTargets = {} CalculatorArgs = {} -semi_deepcopy = SCons.Util.semi_deepcopy -semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict - def alias_builder(env, target, source): pass -AliasBuilder = SCons.Builder.Builder(action = alias_builder, - target_factory = SCons.Node.Alias.default_ans.Alias, - source_factory = SCons.Node.FS.Entry, - multi = 1, - is_explicit = None, - name='AliasBuilder') +AliasBuilder = SCons.Builder.Builder( + action=alias_builder, + target_factory=SCons.Node.Alias.default_ans.Alias, + source_factory=SCons.Node.FS.Entry, + multi=True, + is_explicit=None, + name='AliasBuilder', +) def apply_tools(env, tools, toolpath): # Store the toolpath in the Environment. + # This is expected to work even if no tools are given, so do this first. if toolpath is not None: env['toolpath'] = toolpath - if not tools: return + # Filter out null tools from the list. for tool in [_f for _f in tools if _f]: - if SCons.Util.is_List(tool) or isinstance(tool, tuple): - toolname = tool[0] - toolargs = tool[1] # should be a dict of kw args - tool = env.Tool(toolname, **toolargs) + if is_List(tool) or is_Tuple(tool): + # toolargs should be a dict of kw args + toolname, toolargs, *rest = tool + _ = env.Tool(toolname, **toolargs) else: - env.Tool(tool) + _ = env.Tool(tool) # These names are (or will be) controlled by SCons; users should never -# set or override them. This warning can optionally be turned off, +# set or override them. The warning can optionally be turned off, # but scons will still ignore the illegal variable names even if it's off. reserved_construction_var_names = [ 'CHANGED_SOURCES', @@ -119,7 +133,7 @@ #'HOST_OS', #'HOST_ARCH', #'HOST_CPU', - ] +] def copy_non_reserved_keywords(dict): result = semi_deepcopy(dict) @@ -184,46 +198,15 @@ # 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. - -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) +# +# Note: MethodWrapper moved to SCons.Util as it was needed there +# and otherwise we had a circular import problem. class BuilderWrapper(MethodWrapper): """ @@ -248,11 +231,11 @@ if source is _null: source = target target = None - if target is not None and not SCons.Util.is_List(target): + if target is not None and not is_List(target): target = [target] - if source is not None and not SCons.Util.is_List(source): + if source is not None and not is_List(source): source = [source] - return MethodWrapper.__call__(self, target, source, *args, **kw) + return super().__call__(target, source, *args, **kw) def __repr__(self): return '' % repr(self.name) @@ -292,12 +275,12 @@ the Builders. We need to do this because every time someone changes the Builders in the Environment's BUILDERS dictionary, we must update the Environment's attributes.""" - def __init__(self, dict, env): + def __init__(self, mapping, env): # Set self.env before calling the superclass initialization, # because it will end up calling our other methods, which will # need to point the values in this dictionary to self.env. self.env = env - UserDict.__init__(self, dict) + super().__init__(mapping) def __semi_deepcopy__(self): # These cannot be copied since they would both modify the same builder object, and indeed @@ -311,15 +294,15 @@ pass else: self.env.RemoveMethod(method) - UserDict.__setitem__(self, item, val) + super().__setitem__(item, val) BuilderWrapper(self.env, val, item) def __delitem__(self, item): - UserDict.__delitem__(self, item) + super().__delitem__(item) delattr(self.env, item) - def update(self, dict): - for i, v in dict.items(): + def update(self, mapping): + for i, v in mapping.items(): self.__setitem__(i, v) @@ -387,8 +370,7 @@ self._special_set['SCANNERS'] = _set_SCANNERS # Freeze the keys of self._special_set in a list for use by - # methods that need to check. (Empirically, list scanning has - # gotten better than dict.has_key() in Python 2.5.) + # methods that need to check. self._special_set_keys = list(self._special_set.keys()) def __eq__(self, other): @@ -410,10 +392,9 @@ # # The "key in self._special_set_keys" test here seems to perform # pretty well for the number of keys we have. A hard-coded - # list works a little better in Python 2.5, but that has the + # list worked a little better in Python 2.5, but that has the # disadvantage of maybe getting out of sync if we ever add more - # variable names. Using self._special_set.has_key() works a - # little better in Python 2.4, but is worse than this test. + # variable names. # So right now it seems like a good trade-off, but feel free to # revisit this with bench/env.__setitem__.py as needed (and # as newer versions of Python come out). @@ -424,21 +405,16 @@ # key and we don't need to check. If we do check, using a # global, pre-compiled regular expression directly is more # efficient than calling another function or a method. - if key not in self._dict \ - and not _is_valid_var.match(key): - raise UserError("Illegal construction variable `%s'" % key) + if key not in self._dict and not _is_valid_var.match(key): + raise UserError("Illegal construction variable `%s'" % key) self._dict[key] = value def get(self, key, default=None): """Emulates the get() method of dictionaries.""" return self._dict.get(key, default) - def has_key(self, key): - """Emulates the has_key() method of dictionaries.""" - return key in self._dict - def __contains__(self, key): - return self._dict.__contains__(key) + return key in self._dict def keys(self): """Emulates the keys() method of dictionaries.""" @@ -452,6 +428,10 @@ """Emulates the items() method of dictionaries.""" return self._dict.items() + def setdefault(self, key, default=None): + """Emulates the setdefault() method of dictionaries.""" + return self._dict.setdefault(key, default) + def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): if node_factory is _null: node_factory = self.fs.File @@ -461,24 +441,24 @@ if not args: return [] - args = SCons.Util.flatten(args) + args = flatten(args) nodes = [] for v in args: - if SCons.Util.is_String(v): + if is_String(v): n = None for l in lookup_list: n = l(v) if n is not None: break if n is not None: - if SCons.Util.is_String(n): + if is_String(n): # n = self.subst(n, raw=1, **kw) kw['raw'] = 1 n = self.subst(n, **kw) if node_factory: n = node_factory(n) - if SCons.Util.is_List(n): + if is_List(n): nodes.extend(n) else: nodes.append(n) @@ -486,7 +466,7 @@ # v = node_factory(self.subst(v, raw=1, **kw)) kw['raw'] = 1 v = node_factory(self.subst(v, **kw)) - if SCons.Util.is_List(v): + if is_List(v): nodes.extend(v) else: nodes.append(v) @@ -522,7 +502,7 @@ nkw = {} for k, v in kw.items(): k = self.subst(k, raw, target, source) - if SCons.Util.is_String(v): + if is_String(v): v = self.subst(v, raw, target, source) nkw[k] = v return nkw @@ -541,7 +521,7 @@ """Substitute a path list, turning EntryProxies into Nodes and leaving Nodes (and other objects) as-is.""" - if not SCons.Util.is_List(path): + if not is_List(path): path = [path] def s(obj): @@ -554,23 +534,23 @@ try: get = obj.get except AttributeError: - obj = SCons.Util.to_String_for_subst(obj) + obj = to_String_for_subst(obj) else: obj = get() return obj r = [] for p in path: - if SCons.Util.is_String(p): + if is_String(p): p = self.subst(p, target=target, source=source, conv=s) - if SCons.Util.is_List(p): + if is_List(p): if len(p) == 1: p = p[0] else: # We have an object plus a string, or multiple # objects that we need to smush together. No choice # but to make them into a string. - p = ''.join(map(SCons.Util.to_String_for_subst, p)) + p = ''.join(map(to_String_for_subst, p)) else: p = s(p) r.append(p) @@ -578,20 +558,38 @@ subst_target_source = subst - def backtick(self, command): + + def backtick(self, command) -> str: + """Emulate command substitution. + + Provides behavior conceptually like POSIX Shell notation + for running a command in backquotes (backticks) by running + ``command`` and returning the resulting output string. + + This is not really a public API any longer, it is provided for the + use of :meth:`ParseFlags` (which supports it using a syntax of + !command) and :meth:`ParseConfig`. + + Raises: + OSError: if the external command returned non-zero exit status. + """ + import subprocess + # common arguments - kw = { 'stdin' : 'devnull', - 'stdout' : subprocess.PIPE, - 'stderr' : subprocess.PIPE, - 'universal_newlines' : True, - } + kw = { + "stdin": "devnull", + "stdout": subprocess.PIPE, + "stderr": subprocess.PIPE, + "universal_newlines": True, + } # if the command is a list, assume it's been quoted # othewise force a shell - if not SCons.Util.is_List(command): kw['shell'] = True + if not is_List(command): + kw["shell"] = True # run constructed command p = SCons.Action._subproc(self, command, **kw) - out,err = p.communicate() + out, err = p.communicate() status = p.wait() if err: sys.stderr.write("" + err) @@ -599,6 +597,7 @@ raise OSError("'%s' exited %d" % (command, status)) return out + def AddMethod(self, function, name=None): """ Adds the specified function as a method of this construction @@ -638,32 +637,38 @@ 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; + def ParseFlags(self, *flags) -> dict: + """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-style toolchain, + such as might have been generated by one of the {foo}-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 = { - 'ASFLAGS' : SCons.Util.CLVar(''), - 'CFLAGS' : SCons.Util.CLVar(''), - 'CCFLAGS' : SCons.Util.CLVar(''), - 'CXXFLAGS' : SCons.Util.CLVar(''), + mapping = { + 'ASFLAGS' : CLVar(''), + 'CFLAGS' : CLVar(''), + 'CCFLAGS' : CLVar(''), + 'CXXFLAGS' : CLVar(''), 'CPPDEFINES' : [], - 'CPPFLAGS' : SCons.Util.CLVar(''), + 'CPPFLAGS' : CLVar(''), 'CPPPATH' : [], - 'FRAMEWORKPATH' : SCons.Util.CLVar(''), - 'FRAMEWORKS' : SCons.Util.CLVar(''), + 'FRAMEWORKPATH' : CLVar(''), + 'FRAMEWORKS' : CLVar(''), 'LIBPATH' : [], 'LIBS' : [], - 'LINKFLAGS' : SCons.Util.CLVar(''), + 'LINKFLAGS' : CLVar(''), 'RPATH' : [], } @@ -672,7 +677,7 @@ if not arg: return - if not SCons.Util.is_String(arg): + if not is_String(arg): for t in arg: do_parse(t) return @@ -681,12 +686,12 @@ arg = self.backtick(arg[1:]) # utility function to deal with -D option - def append_define(name, dict = dict): + def append_define(name, mapping=mapping): t = name.split('=') if len(t) == 1: - dict['CPPDEFINES'].append(name) + mapping['CPPDEFINES'].append(name) else: - dict['CPPDEFINES'].append([t[0], '='.join(t[1:])]) + mapping['CPPDEFINES'].append([t[0], '='.join(t[1:])]) # Loop through the flags and add them to the appropriate option. # This tries to strike a balance between checking for all possible @@ -716,64 +721,67 @@ append_define(arg) elif append_next_arg_to == '-include': t = ('-include', self.fs.File(arg)) - dict['CCFLAGS'].append(t) + mapping['CCFLAGS'].append(t) elif append_next_arg_to == '-imacros': t = ('-imacros', self.fs.File(arg)) - dict['CCFLAGS'].append(t) + mapping['CCFLAGS'].append(t) elif append_next_arg_to == '-isysroot': t = ('-isysroot', arg) - dict['CCFLAGS'].append(t) - dict['LINKFLAGS'].append(t) + mapping['CCFLAGS'].append(t) + mapping['LINKFLAGS'].append(t) elif append_next_arg_to == '-isystem': t = ('-isystem', arg) - dict['CCFLAGS'].append(t) + mapping['CCFLAGS'].append(t) elif append_next_arg_to == '-iquote': t = ('-iquote', arg) - dict['CCFLAGS'].append(t) + mapping['CCFLAGS'].append(t) elif append_next_arg_to == '-idirafter': t = ('-idirafter', arg) - dict['CCFLAGS'].append(t) + mapping['CCFLAGS'].append(t) elif append_next_arg_to == '-arch': t = ('-arch', arg) - dict['CCFLAGS'].append(t) - dict['LINKFLAGS'].append(t) + mapping['CCFLAGS'].append(t) + mapping['LINKFLAGS'].append(t) + elif append_next_arg_to == '--param': + t = ('--param', arg) + mapping['CCFLAGS'].append(t) else: - dict[append_next_arg_to].append(arg) + mapping[append_next_arg_to].append(arg) append_next_arg_to = None elif not arg[0] in ['-', '+']: - dict['LIBS'].append(self.fs.File(arg)) + mapping['LIBS'].append(self.fs.File(arg)) elif arg == '-dylib_file': - dict['LINKFLAGS'].append(arg) + mapping['LINKFLAGS'].append(arg) append_next_arg_to = 'LINKFLAGS' elif arg[:2] == '-L': if arg[2:]: - dict['LIBPATH'].append(arg[2:]) + mapping['LIBPATH'].append(arg[2:]) else: append_next_arg_to = 'LIBPATH' elif arg[:2] == '-l': if arg[2:]: - dict['LIBS'].append(arg[2:]) + mapping['LIBS'].append(arg[2:]) else: append_next_arg_to = 'LIBS' elif arg[:2] == '-I': if arg[2:]: - dict['CPPPATH'].append(arg[2:]) + mapping['CPPPATH'].append(arg[2:]) else: append_next_arg_to = 'CPPPATH' elif arg[:4] == '-Wa,': - dict['ASFLAGS'].append(arg[4:]) - dict['CCFLAGS'].append(arg) + mapping['ASFLAGS'].append(arg[4:]) + mapping['CCFLAGS'].append(arg) elif arg[:4] == '-Wl,': if arg[:11] == '-Wl,-rpath=': - dict['RPATH'].append(arg[11:]) + mapping['RPATH'].append(arg[11:]) elif arg[:7] == '-Wl,-R,': - dict['RPATH'].append(arg[7:]) + mapping['RPATH'].append(arg[7:]) elif arg[:6] == '-Wl,-R': - dict['RPATH'].append(arg[6:]) + mapping['RPATH'].append(arg[6:]) else: - dict['LINKFLAGS'].append(arg) + mapping['LINKFLAGS'].append(arg) elif arg[:4] == '-Wp,': - dict['CPPFLAGS'].append(arg) + mapping['CPPFLAGS'].append(arg) elif arg[:2] == '-D': if arg[2:]: append_define(arg[2:]) @@ -782,57 +790,75 @@ elif arg == '-framework': append_next_arg_to = 'FRAMEWORKS' elif arg[:14] == '-frameworkdir=': - dict['FRAMEWORKPATH'].append(arg[14:]) + mapping['FRAMEWORKPATH'].append(arg[14:]) elif arg[:2] == '-F': if arg[2:]: - dict['FRAMEWORKPATH'].append(arg[2:]) + mapping['FRAMEWORKPATH'].append(arg[2:]) else: append_next_arg_to = 'FRAMEWORKPATH' - elif arg in ['-mno-cygwin', - '-pthread', - '-openmp', - '-fmerge-all-constants', - '-fopenmp']: - dict['CCFLAGS'].append(arg) - dict['LINKFLAGS'].append(arg) + elif arg in ( + '-mno-cygwin', + '-pthread', + '-openmp', + '-fmerge-all-constants', + '-fopenmp', + ): + mapping['CCFLAGS'].append(arg) + mapping['LINKFLAGS'].append(arg) elif arg == '-mwindows': - dict['LINKFLAGS'].append(arg) + mapping['LINKFLAGS'].append(arg) elif arg[:5] == '-std=': if '++' in arg[5:]: - key='CXXFLAGS' + key = 'CXXFLAGS' else: - key='CFLAGS' - dict[key].append(arg) + key = 'CFLAGS' + mapping[key].append(arg) elif arg[0] == '+': - dict['CCFLAGS'].append(arg) - dict['LINKFLAGS'].append(arg) - elif arg in ['-include', '-imacros', '-isysroot', '-isystem', '-iquote', '-idirafter', '-arch']: + mapping['CCFLAGS'].append(arg) + mapping['LINKFLAGS'].append(arg) + elif arg in [ + '-include', + '-imacros', + '-isysroot', + '-isystem', + '-iquote', + '-idirafter', + '-arch', + '--param', + ]: append_next_arg_to = arg else: - dict['CCFLAGS'].append(arg) + mapping['CCFLAGS'].append(arg) for arg in flags: do_parse(arg) - return dict + return mapping - 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) -> None: + """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 one with + flags distributed into appropriate construction variables. + See :meth:`ParseFlags`. - if dict is None: - dict = self - if not SCons.Util.is_Dict(args): + Args: + args: flags to merge + unique: merge flags rather than appending (default: True). + When merging, path variables are retained from the front, + other construction variables from the end. + """ + if not 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 = Split(value) try: orig = self[key] except KeyError: @@ -869,7 +895,6 @@ 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): @@ -882,15 +907,19 @@ return f(dependency, target, prev_ni, repo_node) -def default_copy_from_cache(src, dst): - f = SCons.Defaults.DefaultEnvironment().copy_from_cache - return f(src, dst) +def default_copy_from_cache(env, src, dst): + return SCons.CacheDir.CacheDir.copy_from_cache(env, src, dst) + + +def default_copy_to_cache(env, src, dst): + return SCons.CacheDir.CacheDir.copy_to_cache(env, src, dst) class Base(SubstitutionEnvironment): - """Base class for "real" construction Environments. These are the - primary objects used to communicate dependency and construction - information to the build engine. + """Base class for "real" 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 @@ -911,17 +940,19 @@ # dictionary functionality that we actually need and use. ####################################################################### - def __init__(self, - platform=None, - tools=None, - toolpath=None, - variables=None, - parse_flags = None, - **kw): - """ - Initialization of a basic SCons construction environment, - including setting up special construction variables like BUILDER, - PLATFORM, etc., and searching for and applying available Tools. + def __init__( + self, + platform=None, + tools=None, + toolpath=None, + variables=None, + parse_flags=None, + **kw + ): + """Initialization of a basic SCons construction environment. + + Sets up special construction variables like BUILDER, + PLATFORM, etc., and searches for and applies available Tools. Note that we do *not* call the underlying base class (SubsitutionEnvironment) initialization, because we need to @@ -946,7 +977,7 @@ self.decide_target = default_decide_target self.decide_source = default_decide_source - self.copy_from_cache = default_copy_from_cache + self.cache_timestamp_newer = False self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) @@ -954,18 +985,18 @@ platform = self._dict.get('PLATFORM', None) if platform is None: platform = SCons.Platform.Platform() - if SCons.Util.is_String(platform): + if is_String(platform): platform = SCons.Platform.Platform(platform) self._dict['PLATFORM'] = str(platform) platform(self) - self._dict['HOST_OS'] = self._dict.get('HOST_OS',None) - self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None) - - # Now set defaults for TARGET_{OS|ARCH} - self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None) - self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None) - + # these should be set by the platform, backstop just in case + self._dict['HOST_OS'] = self._dict.get('HOST_OS', None) + self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH', None) + + # these are not currently set by the platform, give them a default + self._dict['TARGET_OS'] = self._dict.get('TARGET_OS', None) + self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH', None) # Apply the passed-in and customizable variables to the # environment before calling the tools, because they may use @@ -1005,7 +1036,8 @@ 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. @@ -1020,17 +1052,36 @@ except KeyError: return None + def validate_CacheDir_class(self, custom_class=None): + """Validate the passed custom CacheDir class, or if no args are passed, + validate the custom CacheDir class from the environment. + """ + + if custom_class is None: + custom_class = self.get("CACHEDIR_CLASS", SCons.CacheDir.CacheDir) + if not issubclass(custom_class, SCons.CacheDir.CacheDir): + raise UserError("Custom CACHEDIR_CLASS %s not derived from CacheDir" % str(custom_class)) + return custom_class + def get_CacheDir(self): try: path = self._CacheDir_path except AttributeError: path = SCons.Defaults.DefaultEnvironment()._CacheDir_path + + cachedir_class = self.validate_CacheDir_class() try: - if path == self._last_CacheDir_path: + if (path == self._last_CacheDir_path + # this checks if the cachedir class type has changed from what the + # instantiated cache dir type is. If the are exactly the same we + # can just keep using the existing one, otherwise the user is requesting + # something new, so we will re-instantiate below. + and type(self._last_CacheDir) is cachedir_class): return self._last_CacheDir except AttributeError: pass - cd = SCons.CacheDir.CacheDir(path) + + cd = cachedir_class(path) self._last_CacheDir_path = path self._last_CacheDir = cd return cd @@ -1082,7 +1133,7 @@ # claim they can scan the same suffix, earlier scanners # in the list will overwrite later scanners, so that # the result looks like a "first match" to the user. - if not SCons.Util.is_List(scanners): + if not is_List(scanners): scanners = [scanners] else: scanners = scanners[:] # copy so reverse() doesn't mod original @@ -1112,11 +1163,24 @@ except KeyError: pass - def _update(self, dict): - """Update an environment's values directly, bypassing the normal - checks that occur when users try to set items. + def _update(self, other): + """Private method to update an environment's consvar dict directly. + + Bypasses the normal checks that occur when users try to set items. + """ + self._dict.update(other) + + def _update_onlynew(self, other): + """Private method to add new items to an environment's consvar dict. + + Only adds items from `other` whose keys do not already appear in + the existing dict; values from `other` are not used for replacement. + Bypasses the normal checks that occur when users try to set items. """ - self._dict.update(dict) + for k, v in other.items(): + if k not in self._dict: + self._dict[k] = v + def get_src_sig_type(self): try: @@ -1144,104 +1208,106 @@ ####################################################################### def Append(self, **kw): - """Append values to existing construction variables - in an Environment. + """Append values to construction variables in an Environment. + + The variable is created if it is not already present. """ + kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - # It would be easier on the eyes to write this using - # "continue" statements whenever we finish processing an item, - # but Python 1.5.2 apparently doesn't let you use "continue" - # within try:-except: blocks, so we have to nest our code. try: - if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]): + if key == 'CPPDEFINES' and is_String(self._dict[key]): self._dict[key] = [self._dict[key]] orig = self._dict[key] except KeyError: - # No existing variable in the environment, so just set - # it to the new value. - if key == 'CPPDEFINES' and SCons.Util.is_String(val): + # No existing var in the environment, so set to the new value. + if key == 'CPPDEFINES' and is_String(val): self._dict[key] = [val] else: self._dict[key] = val - else: + continue + + try: + # Check if the original looks like a dict: has .update? + update_dict = orig.update + except AttributeError: try: - # Check if the original looks like a dictionary. - # If it is, we can't just try adding the value because - # dictionaries don't have __add__() methods, and - # things like UserList will incorrectly coerce the - # original dict to a list (which we don't want). - update_dict = orig.update - except AttributeError: + # Just try to add them together. This will work + # in most cases, when the original and new values + # are compatible types. + self._dict[key] = orig + val + except (KeyError, TypeError): try: - # Most straightforward: just try to add them - # together. This will work in most cases, when the - # original and new values are of compatible types. - self._dict[key] = orig + val - except (KeyError, TypeError): - try: - # Check if the original is a list. - add_to_orig = orig.append - except AttributeError: - # The original isn't a list, but the new - # value is (by process of elimination), - # so insert the original in the new value - # (if there's one to insert) and replace - # the variable with it. - if orig: - val.insert(0, orig) - self._dict[key] = val + # Check if the original is a list: has .append? + add_to_orig = orig.append + except AttributeError: + # The original isn't a list, but the new + # value is (by process of elimination), + # so insert the original in the new value + # (if there's one to insert) and replace + # the variable with it. + if orig: + val.insert(0, orig) + self._dict[key] = val + else: + # The original is a list, so append the new + # value to it (if there's a value to append). + if val: + add_to_orig(val) + continue + + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + # We can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + if is_List(val): + if key == 'CPPDEFINES': + tmp = [] + for (k, v) in orig.items(): + if v is not None: + tmp.append((k, v)) else: - # The original is a list, so append the new - # value to it (if there's a value to append). - if val: - add_to_orig(val) + tmp.append((k,)) + orig = tmp + orig += val + self._dict[key] = orig else: - # The original looks like a dictionary, so update it - # based on what we think the value looks like. - if SCons.Util.is_List(val): - if key == 'CPPDEFINES': - tmp = [] - for (k, v) in orig.items(): - if v is not None: - tmp.append((k, v)) - else: - tmp.append((k,)) - orig = tmp - orig += val - self._dict[key] = orig - else: - for v in val: - orig[v] = None + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if is_Dict(val): + for k, v in val.items(): + orig[k] = v else: - try: - update_dict(val) - except (AttributeError, TypeError, ValueError): - if SCons.Util.is_Dict(val): - for k, v in val.items(): - orig[k] = v - else: - orig[val] = None + orig[val] = None + self.scanner_map_delete(kw) - # allow Dirs and strings beginning with # for top-relative - # Note this uses the current env's fs (in self). def _canonicalize(self, path): - if not SCons.Util.is_String(path): # typically a Dir + """Allow Dirs and strings beginning with # for top-relative. + + Note this uses the current env's fs (in self). + """ + if not is_String(path): # typically a Dir path = str(path) if path and path[0] == '#': path = str(self.fs.Dir(path)) return path - def AppendENVPath(self, name, newpath, envname = 'ENV', - sep = os.pathsep, delete_existing=0): - """Append path elements to the path 'name' in the 'ENV' + def AppendENVPath(self, name, newpath, envname='ENV', + sep=os.pathsep, delete_existing=False): + """Append path elements to the path *name* in the *envname* dictionary for this environment. Will only add any particular path once, and will normpath and normcase all paths to help assure this. This can also handle the case where the env variable is a list instead of a string. - If delete_existing is 0, a newpath which is already in the path + If *delete_existing* is False, a *newpath* element already in the path will not be moved to the end (it will be left where it is). """ @@ -1249,46 +1315,44 @@ if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] - nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing, - canonicalize=self._canonicalize) + nv = AppendPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: self._dict[envname] = {} self._dict[envname][name] = nv - def AppendUnique(self, delete_existing=0, **kw): + def AppendUnique(self, delete_existing=False, **kw): """Append values to existing construction variables in an Environment, if they're not already there. - If delete_existing is 1, removes existing values first, so + If delete_existing is True, removes existing values first, so values move to end. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - if SCons.Util.is_List(val): + if is_List(val): val = _delete_duplicates(val, delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(val): + elif is_Dict(self._dict[key]) and is_Dict(val): self._dict[key].update(val) - elif SCons.Util.is_List(val): + elif is_List(val): dk = self._dict[key] if key == 'CPPDEFINES': tmp = [] for i in val: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) val = tmp # Construct a list of (key, value) tuples. - if SCons.Util.is_Dict(dk): + if is_Dict(dk): tmp = [] for (k, v) in dk.items(): if v is not None: @@ -1296,23 +1360,23 @@ else: tmp.append((k,)) dk = tmp - elif SCons.Util.is_String(dk): + elif is_String(dk): dk = [(dk,)] else: tmp = [] for i in dk: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) dk = tmp else: - if not SCons.Util.is_List(dk): + if not is_List(dk): dk = [dk] if delete_existing: dk = [x for x in dk if x not in val] @@ -1321,22 +1385,22 @@ self._dict[key] = dk + val else: dk = self._dict[key] - if SCons.Util.is_List(dk): + if is_List(dk): if key == 'CPPDEFINES': tmp = [] for i in dk: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) dk = tmp # Construct a list of (key, value) tuples. - if SCons.Util.is_Dict(val): + if is_Dict(val): tmp = [] for (k, v) in val.items(): if v is not None: @@ -1344,7 +1408,7 @@ else: tmp.append((k,)) val = tmp - elif SCons.Util.is_String(val): + elif is_String(val): val = [(val,)] if delete_existing: dk = list(filter(lambda x, val=val: x not in val, dk)) @@ -1363,9 +1427,9 @@ self._dict[key] = dk + [val] else: if key == 'CPPDEFINES': - if SCons.Util.is_String(dk): + if is_String(dk): dk = [dk] - elif SCons.Util.is_Dict(dk): + elif is_Dict(dk): tmp = [] for (k, v) in dk.items(): if v is not None: @@ -1373,12 +1437,12 @@ else: tmp.append((k,)) dk = tmp - if SCons.Util.is_String(val): + if is_String(val): if val in dk: val = [] else: val = [val] - elif SCons.Util.is_Dict(val): + elif is_Dict(val): tmp = [] for i,j in val.items(): if j is not None: @@ -1392,8 +1456,9 @@ self.scanner_map_delete(kw) def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw): - """Return a copy of a construction Environment. The - copy is like a Python "deep copy"--that is, independent + """Return a copy of a construction Environment. + + The copy is like a Python "deep copy"--that is, independent copies are made recursively of each objects--except that a reference is copied when an object is not deep-copyable (like a function). There are no references to any mutable @@ -1432,7 +1497,8 @@ 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 @@ -1462,23 +1528,16 @@ def _changed_timestamp_match(self, dependency, target, prev_ni, repo_node=None): return dependency.changed_timestamp_match(target, prev_ni, repo_node) - def _copy_from_cache(self, src, dst): - return self.fs.copy(src, dst) - - def _copy2_from_cache(self, src, dst): - return self.fs.copy2(src, dst) - def Decider(self, function): - copy_function = self._copy2_from_cache + self.cache_timestamp_newer = False if function in ('MD5', 'content'): - if not SCons.Util.md5: - raise UserError("MD5 signatures are not available in this version of Python.") + # TODO: Handle if user requests MD5 and not content with deprecation notice function = self._changed_content - elif function == 'MD5-timestamp': + elif function in ('MD5-timestamp', 'content-timestamp'): function = self._changed_timestamp_then_content elif function in ('timestamp-newer', 'make'): function = self._changed_timestamp_newer - copy_function = self._copy_from_cache + self.cache_timestamp_newer = True elif function == 'timestamp-match': function = self._changed_timestamp_match elif not callable(function): @@ -1490,19 +1549,16 @@ self.decide_target = function self.decide_source = function - self.copy_from_cache = copy_function - def Detect(self, progs): - """Return the first available program in progs. + """Return the first available program from one or more possibilities. - :param progs: one or more command names to check for - :type progs: str or list - :returns str: first name from progs that can be found. + Args: + progs (str or list): one or more command names to check for """ - if not SCons.Util.is_List(progs): - progs = [ progs ] + if not is_List(progs): + progs = [progs] for prog in progs: path = self.WhereIs(prog) if path: return prog @@ -1510,7 +1566,7 @@ def Dictionary(self, *args): - """Return construction variables from an environment. + r"""Return construction variables from an environment. Args: \*args (optional): variable names to look up @@ -1538,10 +1594,10 @@ Args: key (optional): if None, format the whole dict of variables. Else format the value of `key` (Default value = None) - format (optional): specify the format to serialize to. + format (str, optional): specify the format to serialize to. `"pretty"` generates a pretty-printed string, `"json"` a JSON-formatted string. - (Default value = None, equivalent to `"pretty"`) + (Default value = `"pretty"`) """ if key: @@ -1587,31 +1643,38 @@ prefix = self.subst('$'+prefix) for path in paths: - dir,name = os.path.split(str(path)) + name = os.path.basename(str(path)) if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: return path - def ParseConfig(self, command, function=None, unique=1): - """ - Use the specified function to parse the output of the command - in order to modify the current environment. The 'command' can - be a string or a list of strings representing a command and - its arguments. 'Function' is an optional argument that takes - the environment, the output of the command, and the unique flag. - If no function is specified, MergeFlags, which treats the output - as the result of a typical 'X-config' command (i.e. gtk-config), - will merge the output into the appropriate variables. + + def ParseConfig(self, command, function=None, unique=True): + """Parse the result of running a command to update construction vars. + + Use ``function`` to parse the output of running ``command`` + in order to modify the current environment. + + Args: + command: a string or a list of strings representing a command + and its arguments. + function: called to process the result of ``command``, which will + be passed as ``args``. If ``function`` is omitted or ``None``, + :meth:`MergeFlags` is used. Takes 3 args ``(env, args, unique)`` + unique: whether no duplicate values are allowed (default true) """ if function is None: + def parse_conf(env, cmd, unique=unique): return env.MergeFlags(cmd, unique) + function = parse_conf - if SCons.Util.is_List(command): + if is_List(command): command = ' '.join(command) command = self.subst(command) - return function(self, self.backtick(command)) + return function(self, self.backtick(command), unique) + - 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" @@ -1624,7 +1687,7 @@ filename = self.subst(filename) try: with open(filename, 'r') as fp: - lines = SCons.Util.LogicalLines(fp).readlines() + lines = LogicalLines(fp).readlines() except IOError: if must_exist: raise @@ -1656,79 +1719,79 @@ return SCons.Platform.Platform(platform)(self) def Prepend(self, **kw): - """Prepend values to existing construction variables - in an Environment. + """Prepend values to construction variables in an Environment. + + The variable is created if it is not already present. """ + kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - # It would be easier on the eyes to write this using - # "continue" statements whenever we finish processing an item, - # but Python 1.5.2 apparently doesn't let you use "continue" - # within try:-except: blocks, so we have to nest our code. try: orig = self._dict[key] except KeyError: - # No existing variable in the environment, so just set - # it to the new value. + # No existing var in the environment so set to the new value. self._dict[key] = val - else: + continue + + try: + # Check if the original looks like a dict: has .update? + update_dict = orig.update + except AttributeError: try: - # Check if the original looks like a dictionary. - # If it is, we can't just try adding the value because - # dictionaries don't have __add__() methods, and - # things like UserList will incorrectly coerce the - # original dict to a list (which we don't want). - update_dict = orig.update - except AttributeError: + # Just try to add them together. This will work + # in most cases, when the original and new values + # are compatible types. + self._dict[key] = val + orig + except (KeyError, TypeError): try: - # Most straightforward: just try to add them - # together. This will work in most cases, when the - # original and new values are of compatible types. - self._dict[key] = val + orig - except (KeyError, TypeError): - try: - # Check if the added value is a list. - add_to_val = val.append - except AttributeError: - # The added value isn't a list, but the - # original is (by process of elimination), - # so insert the the new value in the original - # (if there's one to insert). - if val: - orig.insert(0, val) - else: - # The added value is a list, so append - # the original to it (if there's a value - # to append). - if orig: - add_to_val(orig) - self._dict[key] = val - else: - # The original looks like a dictionary, so update it - # based on what we think the value looks like. - if SCons.Util.is_List(val): - for v in val: - orig[v] = None + # Check if the added value is a list: has .append? + add_to_val = val.append + except AttributeError: + # The added value isn't a list, but the + # original is (by process of elimination), + # so insert the the new value in the original + # (if there's one to insert). + if val: + orig.insert(0, val) else: - try: - update_dict(val) - except (AttributeError, TypeError, ValueError): - if SCons.Util.is_Dict(val): - for k, v in val.items(): - orig[k] = v - else: - orig[val] = None + # The added value is a list, so append + # the original to it (if there's a value + # to append) and replace the original. + if orig: + add_to_val(orig) + self._dict[key] = val + continue + + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + # We can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + if is_List(val): + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None + self.scanner_map_delete(kw) - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, - delete_existing=1): - """Prepend path elements to the path 'name' in the 'ENV' + def PrependENVPath(self, name, newpath, envname='ENV', + sep=os.pathsep, delete_existing=True): + """Prepend path elements to the path *name* in the *envname* dictionary for this environment. Will only add any particular path once, and will normpath and normcase all paths to help assure this. This can also handle the case where the env variable is a list instead of a string. - If delete_existing is 0, a newpath which is already in the path + If *delete_existing* is False, a *newpath* component already in the path will not be moved to the front (it will be left where it is). """ @@ -1736,7 +1799,7 @@ if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] - nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing, + nv = PrependPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: @@ -1744,24 +1807,23 @@ self._dict[envname][name] = nv - def PrependUnique(self, delete_existing=0, **kw): + def PrependUnique(self, delete_existing=False, **kw): """Prepend values to existing construction variables in an Environment, if they're not already there. - If delete_existing is 1, removes existing values first, so + If delete_existing is True, removes existing values first, so values move to front. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - if SCons.Util.is_List(val): + if is_List(val): val = _delete_duplicates(val, not delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(val): + elif is_Dict(self._dict[key]) and is_Dict(val): self._dict[key].update(val) - elif SCons.Util.is_List(val): + elif is_List(val): dk = self._dict[key] - if not SCons.Util.is_List(dk): + if not is_List(dk): dk = [dk] if delete_existing: dk = [x for x in dk if x not in val] @@ -1770,7 +1832,7 @@ self._dict[key] = val + dk else: dk = self._dict[key] - if SCons.Util.is_List(dk): + if is_List(dk): # By elimination, val is not a list. Since dk is a # list, wrap val in a list first. if delete_existing: @@ -1834,35 +1896,38 @@ def _find_toolpath_dir(self, tp): return self.fs.Dir(self.subst(tp)).srcnode().get_abspath() - def Tool(self, tool, toolpath=None, **kw): - if SCons.Util.is_String(tool): + def Tool(self, tool, toolpath=None, **kwargs) -> SCons.Tool.Tool: + if is_String(tool): tool = self.subst(tool) if toolpath is None: toolpath = self.get('toolpath', []) toolpath = list(map(self._find_toolpath_dir, toolpath)) - tool = SCons.Tool.Tool(tool, toolpath, **kw) + tool = SCons.Tool.Tool(tool, toolpath, **kwargs) tool(self) + return tool - def WhereIs(self, prog, path=None, pathext=None, reject=[]): - """Find prog in the path. - """ + def WhereIs(self, prog, path=None, pathext=None, reject=None): + """Find prog in the path. """ + if not prog: # nothing to search for, just give up + return None if path is None: try: path = self['ENV']['PATH'] except KeyError: pass - elif SCons.Util.is_String(path): + elif is_String(path): path = self.subst(path) if pathext is None: try: pathext = self['ENV']['PATHEXT'] except KeyError: pass - elif SCons.Util.is_String(pathext): + elif is_String(pathext): pathext = self.subst(pathext) - prog = SCons.Util.CLVar(self.subst(prog)) # support "program --with-args" - path = SCons.Util.WhereIs(prog[0], path, pathext, reject) - if path: return path + prog = CLVar(self.subst(prog)) # support "program --with-args" + path = WhereIs(prog[0], path, pathext, reject) + if path: + return path return None ####################################################################### @@ -1875,7 +1940,7 @@ def Action(self, *args, **kw): def subst_string(a, self=self): - if SCons.Util.is_String(a): + if is_String(a): a = self.subst(a) return a nargs = list(map(subst_string, args)) @@ -1904,7 +1969,7 @@ def Alias(self, target, source=[], action=None, **kw): tlist = self.arg2nodes(target, self.ans.Alias) - if not SCons.Util.is_List(source): + if not is_List(source): source = [source] source = [_f for _f in source if _f] @@ -1967,12 +2032,21 @@ nkw = self.subst_kw(kw) return SCons.Builder.Builder(**nkw) - def CacheDir(self, path): - import SCons.CacheDir + def CacheDir(self, path, custom_class=None): if path is not None: path = self.subst(path) self._CacheDir_path = path + if custom_class: + self['CACHEDIR_CLASS'] = self.validate_CacheDir_class(custom_class) + + if SCons.Action.execute_actions: + # Only initialize the CacheDir if -n/-no_exec was NOT specified. + # Now initialized the CacheDir and prevent a race condition which can + # happen when there's no existing cache dir and you are building with + # multiple threads, but initializing it before the task walk starts + self.get_CacheDir() + def Clean(self, targets, files): global CleanTargets tlist = self.arg2nodes(targets, self.fs.Entry) @@ -2052,7 +2126,7 @@ """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.Dir(e, *args, **kw)) @@ -2061,7 +2135,7 @@ def PyPackageDir(self, modulename): s = self.subst(modulename) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.PyPackageDir(e)) @@ -2090,7 +2164,7 @@ """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.Entry(e, *args, **kw)) @@ -2118,7 +2192,7 @@ """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.File(e, *args, **kw)) @@ -2131,11 +2205,11 @@ return SCons.Node.FS.find_file(file, tuple(nodes)) def Flatten(self, sequence): - return SCons.Util.flatten(sequence) + return flatten(sequence) def GetBuildPath(self, files): result = list(map(str, self.arg2nodes(files, self.fs.Entry))) - if SCons.Util.is_List(files): + if is_List(files): return result else: return result[0] @@ -2199,13 +2273,13 @@ def Scanner(self, *args, **kw): nargs = [] for arg in args: - if SCons.Util.is_String(arg): + if is_String(arg): arg = self.subst(arg) nargs.append(arg) nkw = self.subst_kw(kw) - return SCons.Scanner.Base(*nargs, **nkw) + return SCons.Scanner.ScannerBase(*nargs, **nkw) - def SConsignFile(self, name=".sconsign", dbm_module=None): + def SConsignFile(self, name=SCons.SConsign.current_sconsign_filename(), dbm_module=None): if name is not None: name = self.subst(name) if not os.path.isabs(name): @@ -2223,15 +2297,21 @@ side_effects = self.arg2nodes(side_effect, self.fs.Entry) targets = self.arg2nodes(target, self.fs.Entry) + added_side_effects = [] for side_effect in side_effects: if side_effect.multiple_side_effect_has_builder(): raise UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect)) side_effect.add_source(targets) side_effect.side_effect = 1 self.Precious(side_effect) + added = False for target in targets: - target.side_effects.append(side_effect) - return side_effects + if side_effect not in target.side_effects: + target.side_effects.append(side_effect) + added = True + if added: + added_side_effects.append(side_effect) + return added_side_effects def Split(self, arg): """This function converts a string or list into a list of strings @@ -2247,9 +2327,9 @@ In all cases, the function returns a list of Nodes and strings.""" - if SCons.Util.is_List(arg): + if is_List(arg): return list(map(self.subst, arg)) - elif SCons.Util.is_String(arg): + elif is_String(arg): return self.subst(arg).split() else: return [self.subst(arg)] @@ -2293,7 +2373,7 @@ """ from SCons.Tool import install if install._UNIQUE_INSTALLED_FILES is None: - install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) + install._UNIQUE_INSTALLED_FILES = uniquer_hashables(install._INSTALLED_FILES) return install._UNIQUE_INSTALLED_FILES @@ -2318,10 +2398,13 @@ values from the overrides dictionary. """ - def __init__(self, subject, overrides={}): + def __init__(self, subject, overrides=None): if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.OverrideEnvironment') self.__dict__['__subject'] = subject - self.__dict__['overrides'] = overrides + if overrides is None: + self.__dict__['overrides'] = {} + else: + self.__dict__['overrides'] = overrides # Methods that make this class act like a proxy. def __getattr__(self, name): @@ -2334,7 +2417,7 @@ # 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 @@ -2376,23 +2459,20 @@ except KeyError: return self.__dict__['__subject'].get(key, default) - def has_key(self, key): - """Emulates the has_key() method of dictionaries.""" - try: - self.__dict__['overrides'][key] - return 1 - except KeyError: - return key in self.__dict__['__subject'] - def __contains__(self, key): - if self.__dict__['overrides'].__contains__(key): - return 1 - return self.__dict__['__subject'].__contains__(key) + if key in self.__dict__['overrides']: + return True + return key in self.__dict__['__subject'] - def Dictionary(self): + def Dictionary(self, *args): d = self.__dict__['__subject'].Dictionary().copy() d.update(self.__dict__['overrides']) - return d + if not args: + return d + dlist = [d[x] for x in args] + if len(dlist) == 1: + dlist = dlist[0] + return dlist def items(self): """Emulates the items() method of dictionaries.""" @@ -2406,12 +2486,27 @@ """Emulates the values() method of dictionaries.""" return self.Dictionary().values() + def setdefault(self, key, default=None): + """Emulates the setdefault() method of dictionaries.""" + try: + return self.__getitem__(key) + except KeyError: + self.__dict__['overrides'][key] = default + return default + # Overridden private construction environment methods. - def _update(self, dict): - """Update an environment's values directly, bypassing the normal - checks that occur when users try to set items. + def _update(self, other): + self.__dict__['overrides'].update(other) + + def _update_onlynew(self, other): + """Update a dict with new keys. + + Unlike the .update method, if the key is already present, + it is not replaced. """ - self.__dict__['overrides'].update(dict) + for k, v in other.items(): + if k not in self.__dict__['overrides']: + self.__dict__['overrides'][k] = v def gvars(self): return self.__dict__['__subject'].gvars() @@ -2453,28 +2548,35 @@ class _NoSubstitutionProxy(Environment): def __init__(self, subject): self.__dict__['__subject'] = subject + def __getattr__(self, name): return getattr(self.__dict__['__subject'], name) + def __setattr__(self, name, value): return setattr(self.__dict__['__subject'], name, value) + def executor_to_lvars(self, kwdict): if 'executor' in kwdict: kwdict['lvars'] = kwdict['executor'].get_lvars() del kwdict['executor'] else: kwdict['lvars'] = {} - def raw_to_mode(self, dict): + + def raw_to_mode(self, mapping): try: - raw = dict['raw'] + raw = mapping['raw'] except KeyError: pass else: - del dict['raw'] - dict['mode'] = raw + del mapping['raw'] + mapping['mode'] = raw + def subst(self, string, *args, **kwargs): return string + def subst_kw(self, kw, *args, **kwargs): return kw + def subst_list(self, string, *args, **kwargs): nargs = (string, self,) + args nkw = kwargs.copy() @@ -2482,6 +2584,7 @@ self.executor_to_lvars(nkw) self.raw_to_mode(nkw) return SCons.Subst.scons_subst_list(*nargs, **nkw) + def subst_target_source(self, string, *args, **kwargs): nargs = (string, self,) + args nkw = kwargs.copy() @@ -2489,6 +2592,7 @@ self.executor_to_lvars(nkw) self.raw_to_mode(nkw) return SCons.Subst.scons_subst(*nargs, **nkw) + return _NoSubstitutionProxy(subject) # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/EnvironmentTests.py scons-4.4.0+dfsg/SCons/EnvironmentTests.py --- scons-4.0.1+dfsg/SCons/EnvironmentTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/EnvironmentTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -32,10 +31,18 @@ from collections import UserDict as UD, UserList as UL import TestCmd -import TestUnit -from SCons.Environment import * import SCons.Warnings +from SCons.Environment import ( + Environment, + NoSubstitutionProxy, + OverrideEnvironment, + SubstitutionEnvironment, + is_valid_construction_var, +) +from SCons.Util import CLVar +from SCons.SConsign import current_sconsign_filename + def diff_env(env1, env2): s1 = "env1 = {\n" @@ -126,17 +133,6 @@ return self.name - -class CLVar(UL): - def __init__(self, seq): - if isinstance(seq, str): - seq = seq.split() - UL.__init__(self, seq) - def __add__(self, other): - return UL.__add__(self, CLVar(other)) - def __radd__(self, other): - return UL.__radd__(self, CLVar(other)) - class DummyNode: def __init__(self, name): self.name = name @@ -148,7 +144,7 @@ return self def test_tool( env ): - env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + env['_F77INCFLAGS'] = '${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}' class TestEnvironmentFixture: def TestEnvironment(self, *args, **kw): @@ -180,7 +176,6 @@ def test___cmp__(self): """Test comparing SubstitutionEnvironments.""" - env1 = SubstitutionEnvironment(XXX = 'x') env2 = SubstitutionEnvironment(XXX = 'x') env3 = SubstitutionEnvironment(XXX = 'xxx') @@ -203,8 +198,7 @@ assert env['XXX'] == 'x', env['XXX'] def test___setitem__(self): - """Test setting a variable in a SubstitutionEnvironment - """ + """Test setting a variable in a SubstitutionEnvironment.""" env1 = SubstitutionEnvironment(XXX = 'x') env2 = SubstitutionEnvironment(XXX = 'x', YYY = 'y') env1['YYY'] = 'y' @@ -216,12 +210,6 @@ assert env.get('XXX') == 'x', env.get('XXX') assert env.get('YYY') is None, env.get('YYY') - def test_has_key(self): - """Test the SubstitutionEnvironment has_key() method.""" - env = SubstitutionEnvironment(XXX = 'x') - assert 'XXX' in env - assert 'YYY' not in env - def test_contains(self): """Test the SubstitutionEnvironment __contains__() method.""" env = SubstitutionEnvironment(XXX = 'x') @@ -255,6 +243,13 @@ for k, v in testdata.items(): assert (k, v) in items, items + def test_setdefault(self): + """Test the SubstitutionEnvironment setdefault() method.""" + env = SubstitutionEnvironment(XXX = 'x') + assert env.setdefault('XXX', 'z') == 'x', env['XXX'] + assert env.setdefault('YYY', 'y') == 'y', env['YYY'] + assert 'YYY' in env + def test_arg2nodes(self): """Test the arg2nodes method.""" env = SubstitutionEnvironment() @@ -717,7 +712,7 @@ 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(): @@ -727,6 +722,18 @@ 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) @@ -782,33 +789,38 @@ 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 " + "-include /usr/include/foo5 " + "--param l1-cache-size=32 --param l2-cache-size=6144 " + "+DD64 " "-DFOO -DBAR=value -D BAZ " + ) d = env.ParseFlags(s) @@ -822,6 +834,8 @@ ('-isystem', '/usr/include/foo2'), ('-idirafter', '/usr/include/foo3'), ('-imacros', env.fs.File('/usr/include/foo4')), + ('-include', env.fs.File('/usr/include/foo5')), + ('--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'] @@ -847,24 +861,40 @@ 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="") + # 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'] + + # 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(CCFLAGS=None) - env.MergeFlags('-Y') - assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS'] - - 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 @@ -876,6 +906,7 @@ pass flags = {'CFLAGS': ['-pipe', '-pthread', '-g']} import copy + saveflags = copy.deepcopy(flags) env.MergeFlags(flags) self.assertEqual(flags, saveflags) @@ -967,14 +998,13 @@ assert called_it['source'] is None, called_it def test_BuilderWrapper_attributes(self): - """Test getting and setting of BuilderWrapper attributes - """ + """Test getting and setting of BuilderWrapper attributes.""" b1 = Builder() b2 = Builder() e1 = Environment() e2 = Environment() - e1.Replace(BUILDERS = {'b' : b1}) + e1.Replace(BUILDERS={'b': b1}) bw = e1.b assert bw.env is e1 @@ -1371,7 +1401,7 @@ env[k] = v def exists(env): - return 1 + return True """) env = self.TestEnvironment(tools = [('faketool', {'a':1, 'b':2, 'c':3})], @@ -1423,6 +1453,31 @@ assert env['TOOL2'] == 222, env assert env['XYZ'] == 'ddd', env + def test_default_copy_cache(self): + copied = False + + def copy2(self, src, dst): + nonlocal copied + copied = True + + save_copy_from_cache = SCons.CacheDir.CacheDir.copy_from_cache + SCons.CacheDir.CacheDir.copy_from_cache = copy2 + + save_copy_to_cache = SCons.CacheDir.CacheDir.copy_to_cache + SCons.CacheDir.CacheDir.copy_to_cache = copy2 + + env = self.TestEnvironment() + + SCons.Environment.default_copy_from_cache(env, 'test.in', 'test.out') + assert copied + + copied = False + SCons.Environment.default_copy_to_cache(env, 'test.in', 'test.out') + assert copied + + SCons.CacheDir.CacheDir.copy_from_cache = save_copy_from_cache + SCons.CacheDir.CacheDir.copy_to_cache = save_copy_to_cache + def test_concat(self): """Test _concat()""" e1 = self.TestEnvironment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) @@ -1437,6 +1492,9 @@ assert x == 'prea bsuf', x x = s("${_concat(PRE, LIST, SUF, __env__)}") assert x == 'preasuf prebsuf', x + x = s("${_concat(PRE, LIST, SUF, __env__,affect_signature=False)}", raw=True) + assert x == '$( preasuf prebsuf $)', x + def test_concat_nested(self): """Test _concat() on a nested substitution strings.""" @@ -1641,23 +1699,32 @@ def test_AppendENVPath(self): """Test appending to an ENV path.""" - env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, - MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}) + env1 = self.TestEnvironment( + ENV={'PATH': r'C:\dir\num\one;C:\dir\num\two'}, + MYENV={'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}, + ) # have to include the pathsep here so that the test will work on UNIX too. - env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';') - env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';') - env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';') - env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';', delete_existing=1) + env1.AppendENVPath('PATH', r'C:\dir\num\two', sep=';') + env1.AppendENVPath('PATH', r'C:\dir\num\three', sep=';') + env1.AppendENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';') + assert ( + env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three' + ), env1['ENV']['PATH'] + + env1.AppendENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';') + env1.AppendENVPath( + 'MYPATH', r'C:\mydir\num\one', 'MYENV', sep=';', delete_existing=1 + ) # this should do nothing since delete_existing is 0 - env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';') - assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three') - assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one') + assert ( + env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one' + ), env1['MYENV']['MYPATH'] - test = TestCmd.TestCmd(workdir = '') + test = TestCmd.TestCmd(workdir='') test.subdir('sub1', 'sub2') - p=env1['ENV']['PATH'] - env1.AppendENVPath('PATH','#sub1', sep = ';') - env1.AppendENVPath('PATH',env1.fs.Dir('sub2'), sep = ';') + p = env1['ENV']['PATH'] + env1.AppendENVPath('PATH', '#sub1', sep=';') + env1.AppendENVPath('PATH', env1.fs.Dir('sub2'), sep=';') assert env1['ENV']['PATH'] == p + ';sub1;sub2', env1['ENV']['PATH'] def test_AppendUnique(self): @@ -1738,39 +1805,39 @@ assert result == ['bar'], result def test_Clone(self): - """Test construction environment copying + """Test construction environment cloning. - Update the copy independently afterwards and check that + The clone should compare equal if there are no overrides. + Update the clone independently afterwards and check that the original remains intact (that is, no dangling references point to objects in the copied environment). Clone the original with some construction variable updates and check that the original remains intact and the copy has the updated values. """ - env1 = self.TestEnvironment(XXX = 'x', YYY = 'y') + env1 = self.TestEnvironment(XXX='x', YYY='y') env2 = env1.Clone() env1copy = env1.Clone() - assert env1copy == env1copy - assert env2 == env2 + assert env1copy == env1 + assert env2 == env1 env2.Replace(YYY = 'yyy') - assert env2 == env2 assert env1 != env2 assert env1 == env1copy - env3 = env1.Clone(XXX = 'x3', ZZZ = 'z3') - assert env3 == env3 + env3 = env1.Clone(XXX='x3', ZZZ='z3') + assert env3 != env1 assert env3.Dictionary('XXX') == 'x3' + assert env1.Dictionary('XXX') == 'x' assert env3.Dictionary('YYY') == 'y' assert env3.Dictionary('ZZZ') == 'z3' assert env1 == env1copy - # Ensure that lists and dictionaries are - # deep copied, but not instances. + # Ensure that lists and dictionaries are deep copied, but not instances class TestA: pass - env1 = self.TestEnvironment(XXX=TestA(), YYY = [ 1, 2, 3 ], - ZZZ = { 1:2, 3:4 }) - env2=env1.Clone() + + env1 = self.TestEnvironment(XXX=TestA(), YYY=[1, 2, 3], ZZZ={1: 2, 3: 4}) + env2 = env1.Clone() env2.Dictionary('YYY').append(4) env2.Dictionary('ZZZ')[5] = 6 assert env1.Dictionary('XXX') is env2.Dictionary('XXX') @@ -1780,20 +1847,18 @@ assert 5 not in env1.Dictionary('ZZZ') # - env1 = self.TestEnvironment(BUILDERS = {'b1' : Builder()}) + env1 = self.TestEnvironment(BUILDERS={'b1': Builder()}) assert hasattr(env1, 'b1'), "env1.b1 was not set" assert env1.b1.object == env1, "b1.object doesn't point to env1" env2 = env1.Clone(BUILDERS = {'b2' : Builder()}) - assert env2 is env2 - assert env2 == env2 + assert env2 != env1 assert hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1" assert env1.b1.object == env1, "b1.object was changed" assert not hasattr(env2, 'b1'), "b1 was not cleared from env2" assert hasattr(env2, 'b2'), "env2.b2 was not set" assert env2.b2.object == env2, "b2.object doesn't point to env2" - # Ensure that specifying new tools in a copied environment - # works. + # Ensure that specifying new tools in a copied environment works. def foo(env): env['FOO'] = 1 def bar(env): env['BAR'] = 2 def baz(env): env['BAZ'] = 3 @@ -1851,14 +1916,14 @@ 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' """) @@ -2010,6 +2075,10 @@ orig_backtick = env.backtick class my_backtick: + """mocked backtick routine so command is not actually issued. + + Just returns the string it was given. + """ def __init__(self, save_command, output): self.save_command = save_command self.output = output @@ -2073,6 +2142,32 @@ finally: env.backtick = orig_backtick + # check that we can pass our own function, + # and that it works for both values of unique + + def my_function(myenv, flags, unique=True): + import json + + args = json.loads(flags) + if unique: + myenv.AppendUnique(**args) + else: + myenv.Append(**args) + + json_str = '{"LIBS": ["yyy", "xxx", "yyy"]}' + + env = Environment(LIBS=['xxx']) + env2 = env.Clone() + env.backtick = my_backtick([], json_str) + env2.backtick = my_backtick([], json_str) + + env.ParseConfig("foo", my_function) + assert env['LIBS'] == ['xxx', 'yyy'], env['LIBS'] + + env2.ParseConfig("foo2", my_function, unique=False) + assert env2['LIBS'] == ['xxx', 'yyy', 'xxx', 'yyy'], env2['LIBS'] + + def test_ParseDepends(self): """Test the ParseDepends() method""" test = TestCmd.TestCmd(workdir = '') @@ -2304,23 +2399,32 @@ def test_PrependENVPath(self): """Test prepending to an ENV path.""" - env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, - MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}) + env1 = self.TestEnvironment( + ENV={'PATH': r'C:\dir\num\one;C:\dir\num\two'}, + MYENV={'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}, + ) # have to include the pathsep here so that the test will work on UNIX too. - env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') - env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';') - env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';') - env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';') + env1.PrependENVPath('PATH', r'C:\dir\num\two', sep=';') + env1.PrependENVPath('PATH', r'C:\dir\num\three', sep=';') + assert ( + env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one' + ), env1['ENV']['PATH'] + + env1.PrependENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';') + env1.PrependENVPath('MYPATH', r'C:\mydir\num\one', 'MYENV', sep=';') # this should do nothing since delete_existing is 0 - env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0) - assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one') - assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two') + env1.PrependENVPath( + 'MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';', delete_existing=0 + ) + assert ( + env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two' + ), env1['MYENV']['MYPATH'] - test = TestCmd.TestCmd(workdir = '') + test = TestCmd.TestCmd(workdir='') test.subdir('sub1', 'sub2') - p=env1['ENV']['PATH'] - env1.PrependENVPath('PATH','#sub1', sep = ';') - env1.PrependENVPath('PATH',env1.fs.Dir('sub2'), sep = ';') + p = env1['ENV']['PATH'] + env1.PrependENVPath('PATH', '#sub1', sep=';') + env1.PrependENVPath('PATH', env1.fs.Dir('sub2'), sep=';') assert env1['ENV']['PATH'] == 'sub2;sub1;' + p, env1['ENV']['PATH'] def test_PrependUnique(self): @@ -2450,17 +2554,19 @@ exc_caught = None try: - env.Tool('does_not_exist') - except SCons.Errors.SConsEnvironmentError: + tool = env.Tool('does_not_exist') + except SCons.Errors.UserError: exc_caught = 1 - assert exc_caught, "did not catch expected SConsEnvironmentError" + else: + assert isinstance(tool, SCons.Tool.Tool) + 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. @@ -2476,14 +2582,14 @@ 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' """) @@ -2531,6 +2637,8 @@ path = os.pathsep.join(pathdirs_1234) env = self.TestEnvironment(ENV = {'PATH' : path}) + wi = env.WhereIs('') + assert wi is None wi = env.WhereIs('xxx.exe') assert wi == test.workpath(sub3_xxx_exe), wi wi = env.WhereIs('xxx.exe', pathdirs_1243) @@ -2754,13 +2862,33 @@ def test_CacheDir(self): """Test the CacheDir() method""" - env = self.TestEnvironment(CD = 'CacheDir') - env.CacheDir('foo') - assert env._CacheDir_path == 'foo', env._CacheDir_path + test = TestCmd.TestCmd(workdir = '') + + test_cachedir = os.path.join(test.workpath(),'CacheDir') + test_cachedir_config = os.path.join(test_cachedir, 'config') + test_foo = os.path.join(test.workpath(), 'foo-cachedir') + test_foo_config = os.path.join(test_foo,'config') + test_foo1 = os.path.join(test.workpath(), 'foo1-cachedir') + test_foo1_config = os.path.join(test_foo1, 'config') + + env = self.TestEnvironment(CD = test_cachedir) + + env.CacheDir(test_foo) + assert env._CacheDir_path == test_foo, env._CacheDir_path + assert os.path.isfile(test_foo_config), "No file %s"%test_foo_config env.CacheDir('$CD') - assert env._CacheDir_path == 'CacheDir', env._CacheDir_path + assert env._CacheDir_path == test_cachedir, env._CacheDir_path + assert os.path.isfile(test_cachedir_config), "No file %s"%test_cachedir_config + + # Now verify that -n/-no_exec wil prevent the CacheDir/config from being created + import SCons.Action + SCons.Action.execute_actions = False + env.CacheDir(test_foo1) + assert env._CacheDir_path == test_foo1, env._CacheDir_path + assert not os.path.isfile(test_foo1_config), "No file %s"%test_foo1_config + def test_Clean(self): """Test the Clean() method""" @@ -2806,10 +2934,14 @@ def testFunc(env, target, source): assert str(target[0]) == 'foo.out' - assert 'foo1.in' in list(map(str, source)) and 'foo2.in' in list(map(str, source)), list(map(str, source)) + srcs = list(map(str, source)) + assert 'foo1.in' in srcs and 'foo2.in' in srcs, srcs return 0 + + # avoid spurious output from action + act = env.Action(testFunc, cmdstr=None) t = env.Command(target='foo.out', source=['foo1.in','foo2.in'], - action=testFunc)[0] + action=act)[0] assert t.builder is not None assert t.builder.action.__class__.__name__ == 'FunctionAction' t.build() @@ -3241,7 +3373,7 @@ assert dbms[-1] == 7, dbms env.SConsignFile() - assert fnames[-1] == os.path.join(os.sep, 'dir', '.sconsign'), fnames + assert fnames[-1] == os.path.join(os.sep, 'dir', current_sconsign_filename()), fnames assert dbms[-1] is None, dbms env.SConsignFile(None) @@ -3258,7 +3390,9 @@ foo = env.Object('foo.obj', 'foo.cpp')[0] bar = env.Object('bar.obj', 'bar.cpp')[0] - s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])[0] + s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'Entry', s.__class__.__name__ assert s.get_internal_path() == 'mylib.pdb' assert s.side_effect @@ -3267,7 +3401,9 @@ fff = env.Object('fff.obj', 'fff.cpp')[0] bbb = env.Object('bbb.obj', 'bbb.cpp')[0] - s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])[0] + s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'File', s.__class__.__name__ assert s.get_internal_path() == 'mylll.pdb' assert s.side_effect @@ -3276,13 +3412,21 @@ ggg = env.Object('ggg.obj', 'ggg.cpp')[0] ccc = env.Object('ccc.obj', 'ccc.cpp')[0] - s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])[0] + s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'Dir', s.__class__.__name__ assert s.get_internal_path() == 'mymmm.pdb' assert s.side_effect assert ggg.side_effects == [s], ggg.side_effects assert ccc.side_effects == [s], ccc.side_effects + # Verify that duplicate side effects are not allowed. + before = len(ggg.side_effects) + s = env.SideEffect('mymmm.pdb', ggg) + assert len(s) == 0, len(s) + assert len(ggg.side_effects) == before, len(ggg.side_effects) + def test_Split(self): """Test the Split() method""" env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb') @@ -3557,8 +3701,8 @@ assert env2.get('ZZZ') is None, env2.get('ZZZ') assert env3.get('ZZZ') == 'z3', env3.get('ZZZ') - def test_has_key(self): - """Test the OverrideEnvironment has_key() method""" + def test_contains(self): + """Test the OverrideEnvironment __contains__() method""" env, env2, env3 = self.envs assert 'XXX' in env, 'XXX' in env assert 'XXX' in env2, 'XXX' in env2 @@ -3570,28 +3714,27 @@ assert 'ZZZ' not in env2, 'ZZZ' in env2 assert 'ZZZ' in env3, 'ZZZ' in env3 - def test_contains(self): - """Test the OverrideEnvironment __contains__() method""" - env, env2, env3 = self.envs - assert 'XXX' in env - assert 'XXX' in env2 - assert 'XXX' in env3 - assert 'YYY' in env - assert 'YYY' in env2 - assert 'YYY' in env3 - assert 'ZZZ' not in env - assert 'ZZZ' not in env2 - assert 'ZZZ' in env3 - - def test_items(self): + def test_Dictionary(self): """Test the OverrideEnvironment Dictionary() method""" env, env2, env3 = self.envs + # nothing overrriden items = env.Dictionary() assert items == {'XXX' : 'x', 'YYY' : 'y'}, items + # env2 overrides XXX, YYY unchanged items = env2.Dictionary() assert items == {'XXX' : 'x2', 'YYY' : 'y'}, items + # env3 overrides XXX, YYY, adds ZZZ items = env3.Dictionary() assert items == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items + # test one-arg and multi-arg Dictionary + assert env3.Dictionary('XXX') == 'x3', env3.Dictionary('XXX') + xxx, yyy = env2.Dictionary('XXX', 'YYY') + assert xxx == 'x2', xxx + assert yyy == 'y', yyy + del env3['XXX'] + assert 'XXX' not in env3.Dictionary() + assert 'XXX' not in env2.Dictionary() + assert 'XXX' not in env.Dictionary() def test_items(self): """Test the OverrideEnvironment items() method""" @@ -3603,6 +3746,36 @@ items = sorted(env3.items()) assert items == [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items + def test_keys(self): + """Test the OverrideEnvironment keys() method""" + env, env2, env3 = self.envs + keys = sorted(env.keys()) + assert keys == ['XXX', 'YYY'], keys + keys = sorted(env2.keys()) + assert keys == ['XXX', 'YYY'], keys + keys = sorted(env3.keys()) + assert keys == ['XXX', 'YYY', 'ZZZ'], keys + + def test_values(self): + """Test the OverrideEnvironment values() method""" + env, env2, env3 = self.envs + values = sorted(env.values()) + assert values == ['x', 'y'], values + values = sorted(env2.values()) + assert values == ['x2', 'y'], values + values = sorted(env3.values()) + assert values == ['x3', 'y3', 'z3'], values + + def test_setdefault(self): + """Test the OverrideEnvironment setdefault() method.""" + env, env2, env3 = self.envs + # does not set for existing key + assert env2.setdefault('XXX', 'z') == 'x2', env2['XXX'] + # set/return using default for non-existing key + assert env2.setdefault('ZZZ', 'z2') == 'z2', env2['ZZZ'] + # set did not leak through to base env + assert 'ZZZ' not in env + def test_gvars(self): """Test the OverrideEnvironment gvars() method""" env, env2, env3 = self.envs @@ -3904,16 +4077,7 @@ 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 -Nru scons-4.0.1+dfsg/SCons/EnvironmentValues.py scons-4.4.0+dfsg/SCons/EnvironmentValues.py --- scons-4.0.1+dfsg/SCons/EnvironmentValues.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/EnvironmentValues.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 -Nru scons-4.0.1+dfsg/SCons/EnvironmentValuesTest.py scons-4.4.0+dfsg/SCons/EnvironmentValuesTest.py --- scons-4.0.1+dfsg/SCons/EnvironmentValuesTest.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/EnvironmentValuesTest.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Environment.xml scons-4.4.0+dfsg/SCons/Environment.xml --- scons-4.0.1+dfsg/SCons/Environment.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Environment.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ -(action, [cmd/str/fun, [var, ...]] [option=value, ...]) +(action, [output, [var, ...]] [key=value, ...]) @@ -276,54 +299,40 @@ -When called with the -AddMethod() -form, -adds the specified -function -to the specified -object -as the specified method -name. -When called using the -&f-env-AddMethod; form, -adds the specified -function -to the construction environment -env -as the specified method -name. -In both cases, if -name -is omitted or -None, -the name of the -specified -function -itself is used for the method name. +Adds function to an object as a method. +function will be called with an instance +object as the first argument as for other methods. +If name is given, it is used as +the name of the new method, else the name of +function is used. + + +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. -Examples: +More examples: -# 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') @@ -490,59 +499,175 @@ -Appends the specified keyword arguments -to the end of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the values of the construction variable -and the keyword argument are the same type, -then the two values will be simply added together. -Otherwise, the construction variable -and the value of the keyword argument -are both coerced to lists, -and the lists are added together. -(See also the &Prepend; method). +Intelligently append values to &consvars; in the &consenv; +named by env. +The &consvars; and values to add to them are passed as +key=val pairs (&Python; keyword arguments). +&f-env-Append; is designed to allow adding values +without normally having to know the data type of an existing &consvar;. +Regular &Python; syntax can also be used to manipulate the &consvar;, +but for that you must know the type of the &consvar;: +for example, different &Python; syntax is needed to combine +a list of values with a single string value, or vice versa. +Some pre-defined &consvars; do have type expectations +based on how &SCons; will use them, +for example &cv-link-CPPDEFINES; is normally a string or a list of strings, +but can be a string, +a list of strings, +a list of tuples, +or a dictionary, while &cv-link-LIBEMITTER; +would expect a callable or list of callables, +and &cv-link-BUILDERS; would expect a mapping type. +Consult the documentation for the various &consvars; for more details. + + + +The following descriptions apply to both the append +and prepend functions, the only difference being +the insertion point of the added values. + + +If env. does not have a &consvar; +indicated by key, +val +is added to the environment under that key as-is. + + + +val can be almost any type, +and &SCons; will combine it with an existing value into an appropriate type, +but there are a few special cases to be aware of. +When two strings are combined, +the result is normally a new string, +with the caller responsible for supplying any needed separation. +The exception to this is the &consvar; &cv-link-CPPDEFINES;, +in which each item will be postprocessed by adding a prefix +and/or suffix, +so the contents are treated as a list of strings, that is, +adding a string will result in a separate string entry, +not a combined string. For &cv-CPPDEFINES; as well as +for &cv-link-LIBS;, and the various *PATH; +variables, &SCons; will supply the compiler-specific +syntax (e.g. adding a -D or /D +prefix for &cv-CPPDEFINES;), so this syntax should be omitted when +adding values to these variables. +Example (gcc syntax shown in the expansion of &CPPDEFINES;): + + + +env = Environment(CXXFLAGS="-std=c11", CPPDEFINES="RELEASE") +print("CXXFLAGS={}, CPPDEFINES={}".format(env['CXXFLAGS'], env['CPPDEFINES'])) +# notice including a leading space in CXXFLAGS value +env.Append(CXXFLAGS=" -O", CPPDEFINES="EXTRA") +print("CXXFLAGS={}, CPPDEFINES={}".format(env['CXXFLAGS'], env['CPPDEFINES'])) +print("CPPDEFINES will expand to {}".format(env.subst("$_CPPDEFFLAGS"))) + + + +$ scons -Q +CXXFLAGS=-std=c11, CPPDEFINES=RELEASE +CXXFLAGS=-std=c11 -O, CPPDEFINES=['RELEASE', 'EXTRA'] +CPPDEFINES will expand to -DRELEASE -DEXTRA +scons: `.' is up to date. + + + +Because &cv-link-CPPDEFINES; is intended to +describe C/C++ pre-processor macro definitions, +it accepts additional syntax. +Preprocessor macros can be valued, or un-valued, as in +-DBAR=1 or +-DFOO. +The macro can be be supplied as a complete string including the value, +or as a tuple (or list) of macro, value, or as a dictionary. +Example (again gcc syntax in the expanded defines): + + + +env = Environment(CPPDEFINES="FOO") +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES="BAR=1") +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES=("OTHER", 2)) +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +env.Append(CPPDEFINES={"EXTRA": "arg"}) +print("CPPDEFINES={}".format(env['CPPDEFINES'])) +print("CPPDEFINES will expand to {}".format(env.subst("$_CPPDEFFLAGS"))) + + + +$ scons -Q +CPPDEFINES=FOO +CPPDEFINES=['FOO', 'BAR=1'] +CPPDEFINES=['FOO', 'BAR=1', ('OTHER', 2)] +CPPDEFINES=['FOO', 'BAR=1', ('OTHER', 2), {'EXTRA': 'arg'}] +CPPDEFINES will expand to -DFOO -DBAR=1 -DOTHER=2 -DEXTRA=arg +scons: `.' is up to date. + + + +Adding a string val +to a dictonary &consvar; will enter +val as the key in the dict, +and None as its value. +Using a tuple type to supply a key + value only works +for the special case of &cv-link-CPPDEFINES; +described above. + + + +Although most combinations of types work without +needing to know the details, some combinations +do not make sense and a &Python; exception will be raised. + + + +When using &f-env-Append; to modify &consvars; +which are path specifications (conventionally, +the names of such end in PATH), +it is recommended to add the values as a list of strings, +even if there is only a single string to add. +The same goes for adding library names to &cv-LIBS;. + +env.Append(CPPPATH=["#/include"]) + + -Example: +See also &f-link-env-AppendUnique;, +&f-link-env-Prepend; and &f-link-env-PrependUnique;. - -env.Append(CCFLAGS = ' -g', FOO = ['foo.yyy']) - -(name, newpath, [envname, sep, delete_existing]) +(name, newpath, [envname, sep, delete_existing=False]) -This appends new path elements to the given path in the -specified external environment -(ENV -by default). -This will only add -any particular path once (leaving the last one it encounters and -ignoring the rest, to preserve path order), -and to help assure this, -will normalize all paths (using -os.path.normpath +Append path elements specified by newpath +to the given search path string or list name +in mapping envname in the &consenv;. +Supplying envname is optional: +the default is the execution environment &cv-link-ENV;. +Optional sep is used as the search path separator, +the default is the platform's separator (os.pathsep). +A path element will only appear once. +Any duplicates in newpath are dropped, +keeping the last appearing (to preserve path order). +If delete_existing +is False (the default) +any addition duplicating an existing path element is ignored; +if delete_existing +is True the existing value will +be dropped and the path element will be added at the end. +To help maintain uniqueness all paths are normalized (using +os.path.normpath and -os.path.normcase). -This can also handle the -case where the given old path variable is a list instead of a -string, in which case a list will be returned instead of a string. - - - -If -delete_existing -is 0, then adding a path that already exists -will not move it to the end; it will stay where it is in the list. +os.path.normcase). @@ -550,37 +675,41 @@ -print 'before:',env['ENV']['INCLUDE'] +print('before:', env['ENV']['INCLUDE']) include_path = '/foo/bar:/foo' env.AppendENVPath('INCLUDE', include_path) -print 'after:',env['ENV']['INCLUDE'] +print('after:', env['ENV']['INCLUDE']) + -yields: +Yields: + before: /foo:/biz after: /biz:/foo/bar:/foo - + + + +See also &f-link-env-PrependENVPath;. + + -(key=val, [...], delete_existing=0) +(key=val, [...], delete_existing=False) -Appends the specified keyword arguments -to the end of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the construction variable being appended to is a list, -then any value(s) that already exist in the -construction variable will -not -be added again to the list. -However, if delete_existing is 1, -existing matching values are removed first, so -existing values in the arg list move to the end of the list. +Append values to &consvars; in the current &consenv;, +maintaining uniqueness. +Works like &f-link-env-Append; (see for details), +except that values already present in the &consvar; +will not be added again. +If delete_existing +is True, +the existing matching value is first removed, +and the requested value is added, +having the effect of moving such values to the end. @@ -588,8 +717,14 @@ -env.AppendUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) +env.AppendUnique(CCFLAGS='-g', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-Prepend; +and &f-link-env-PrependUnique;. + @@ -616,7 +751,7 @@ argument, at the time it is called using the construction variables in the -env +env construction environment through which &f-env-Builder; was called. The @@ -629,7 +764,7 @@ -(cache_dir) +(cache_dir, custom_class=None) @@ -648,6 +783,15 @@ +When specifying a +custom_class which should be a class type which is a subclass of +SCons.CacheDir.CacheDir, SCons will +internally invoke this class to use for performing caching operations. +This argument is optional and if left to default None, will use the +default SCons.CacheDir.CacheDir class. + + + Calling the environment method &f-link-env-CacheDir; limits the effect to targets built @@ -662,12 +806,12 @@ -When derived-file caching +When derived-file caching is being used and &scons; finds a derived file that needs to be rebuilt, it will first look in the cache to see if a -file with matching build signature exists +file with matching &buildsig; exists (indicating the input file(s) and build action(s) were identical to those for the current target), and if so, will retrieve the file from the cache. @@ -679,7 +823,7 @@ &scons; will build it and then place a copy of the built file in the cache, -identified by its build signature, for future use. +identified by its &buildsig;, for future use. @@ -723,7 +867,7 @@ cache_dir is used for a build, or to bring a cache up to date after -a build with cache updating disabled +a build with cache updating disabled ( or ) has been done. @@ -736,6 +880,13 @@ useful if inputs and/or outputs of some tool are impossible to predict or prohibitively large. + + +Note that (at this time) &SCons; provides no facilities +for managing the derived-file cache. It is up to the developer +to arrange for cache pruning, expiry, etc. if needed. + + @@ -823,7 +974,7 @@ env2 = env.Clone() -env3 = env.Clone(CCFLAGS = '-g') +env3 = env.Clone(CCFLAGS='-g') @@ -832,8 +983,10 @@ -def MyTool(env): env['FOO'] = 'bar' -env4 = env.Clone(tools = ['msvc', MyTool]) +def MyTool(env): + env['FOO'] = 'bar' + +env4 = env.Clone(tools=['msvc', MyTool]) @@ -918,7 +1071,7 @@ An action can be an external command, specified as a string, -or a callable Python object; +or a callable &Python; object; see the manpage section "Action Objects" for more complete information. Also note that a string specifying an external command @@ -1064,24 +1217,24 @@ -"MD5" +"content" Specifies that a target shall be considered out of date and rebuilt if the dependency's content has changed since the last time the target was built, -as determined be performing an MD5 checksum +as determined be performing an checksum on the dependency's contents and comparing it to the checksum recorded the last time the target was built. -content +MD5 can be used as a synonym for -MD5. +content, but it is deprecated. -"MD5-timestamp" +"content-timestamp" Specifies that a target shall be considered out of date and rebuilt @@ -1094,7 +1247,7 @@ rebuilt. This provides behavior very similar to the -MD5 +content behavior of always checksumming file contents, with an optimization of not checking the contents of files whose timestamps haven't changed. @@ -1107,6 +1260,9 @@ updates a file, and runs the build again, all within a single second. +MD5-timestamp +can be used as a synonym for +content-timestamp, but it is deprecated. @@ -1121,7 +1277,7 @@ # Use exact timestamp matches by default. Decider('timestamp-match') -# Use MD5 content signatures for any targets built +# Use hash content signatures for any targets built # with the attached construction environment. env.Decider('content') @@ -1129,7 +1285,7 @@ In addition to the above already-available functions, the function -argument may be a Python function you supply. +argument may be a &Python; function you supply. Such a function must accept the following four arguments: @@ -1174,7 +1330,7 @@ This can be consulted to match various file characteristics such as the timestamp, -size, or content signature. +size, or &contentsig;. @@ -1296,10 +1452,11 @@ progs may be a string or a list of strings. Returns the first value from progs that was found, or None. -Executable is searched by checking the paths specified -by env['ENV']['PATH']. +Executable is searched by checking the paths in the execution environment +(env['ENV']['PATH']). On Windows systems, additionally applies the filename suffixes found in -env['ENV']['PATHEXT'] +the execution environment +(env['ENV']['PATHEXT']) but will not include any such extension in the return value. &f-env-Detect; is a wrapper around &f-link-env-WhereIs;. @@ -1401,7 +1558,7 @@ -If key is +If key is None (the default) the entire dictionary of &consvars; is serialized. If supplied, it is taken as the name of a &consvar; @@ -1430,7 +1587,7 @@ -env=Environment() +env = Environment() print(env.Dump()) @@ -1459,52 +1616,64 @@ initialized with the specified key=value pairs. +The keyword arguments +parse_flags, +platform, +toolpath, +tools +and variables +are also specially recognized. +See the manpage section "Construction Environments" for more details. -(action, [strfunction, varlist]) +(action, [actionargs ...]) -Executes an Action object. -The specified +Executes an Action. action may be an Action object -(see manpage section "Action Objects" -for an explanation of behavior), or it may be a command-line string, list of commands, -or executable Python function, -each of which will be converted +or executable &Python; function, +each of which will first be converted into an Action object and then executed. Any additional arguments to &f-Execute; -(strfunction, varlist) are passed on to the &f-link-Action; factory function -which actually creates the Action object. -The exit value of the command -or return value of the Python function -will be returned. +which actually creates the Action object +(see the manpage section Action Objects +for a description). Example: + + + +Execute(Copy('file.out', 'file.in')) + + +&f-Execute; performs its action immediately, +as part of the SConscript-reading phase. +There are no sources or targets declared in an +&f-Execute; call, so any objects it manipulates +will not be tracked as part of the &SCons; dependency graph. +In the example above, neither +file.out nor +file.in will be tracked objects. -Note that +&f-Execute; returns the exit value of the command +or return value of the &Python; function. &scons; -will print an error message if the executed +prints an error message if the executed action -fails--that is, -exits with or returns a non-zero value. -&scons; -will +fails (exits with or returns a non-zero value), +however it does not, -however, -automatically terminate the build -if the specified -action -fails. +automatically terminate the build for such a failure. If you want the build to stop in response to a failed &f-Execute; call, @@ -1512,8 +1681,6 @@ -Execute(Copy('file.out', 'file.in')) - if Execute("mkdir sub/dir/ectory"): # The mkdir failed, don't try to build. Exit(1) @@ -1611,16 +1778,16 @@ -Install( '/bin', [ 'executable_a', 'executable_b' ] ) +Install('/bin', ['executable_a', 'executable_b']) # will return the file node list -# [ '/bin/executable_a', '/bin/executable_b' ] +# ['/bin/executable_a', '/bin/executable_b'] FindInstalledFiles() -Install( '/lib', [ 'some_library' ] ) +Install('/lib', ['some_library']) # will return the file node list -# [ '/bin/executable_a', '/bin/executable_b', '/lib/some_library' ] +# ['/bin/executable_a', '/bin/executable_b', '/lib/some_library'] FindInstalledFiles() @@ -1651,15 +1818,15 @@ -Program( 'src/main_a.c' ) -Program( 'src/main_b.c' ) -Program( 'main_c.c' ) +Program('src/main_a.c') +Program('src/main_b.c') +Program('main_c.c') # returns ['main_c.c', 'src/main_a.c', 'SConstruct', 'src/main_b.c'] FindSourceFiles() # returns ['src/main_b.c', 'src/main_a.c' ] -FindSourceFiles( 'src' ) +FindSourceFiles('src') @@ -1675,7 +1842,7 @@ -Takes a sequence (that is, a Python list or tuple) +Takes a sequence (that is, a &Python; list or tuple) that may contain nested sequences and returns a flattened list containing all of the individual elements in any sequence. @@ -1683,7 +1850,7 @@ the lists returned by calls to Builders; other Builders will automatically flatten lists specified as input, -but direct Python manipulation of +but direct &Python; manipulation of these lists does not. @@ -1703,7 +1870,7 @@ # the Builder will flatten the list automatically: Program(source = objects) -# If you need to manipulate the list directly using Python, you need to +# If you need to manipulate the list directly using &Python;, you need to # call Flatten() yourself, or otherwise handle nested lists: for object in Flatten(objects): print(str(object)) @@ -1927,8 +2094,8 @@ env.Ignore('foo', 'foo.c') env.Ignore('bar', ['bar1.h', 'bar2.h']) -env.Ignore('.','foobar.obj') -env.Ignore('bar','bar/foobar.obj') +env.Ignore('.', 'foobar.obj') +env.Ignore('bar', 'bar/foobar.obj') @@ -2005,9 +2172,9 @@ # Prepend a path to the shell PATH. -env.MergeShellPaths({'PATH':'/usr/local/bin'} ) +env.MergeShellPaths({'PATH': '/usr/local/bin'}) # Append two dirs to the shell INCLUDE. -env.MergeShellPaths({'INCLUDE':['c:/inc1', 'c:/inc2']}, prepend=0 ) +env.MergeShellPaths({'INCLUDE': ['c:/inc1', 'c:/inc2']}, prepend=0) @@ -2019,12 +2186,12 @@ -Merges the specified +Merges values from arg -values to the construction environment's construction variables. -If the +into &consvars; in the current &consenv;. +If arg -argument is not a dictionary, +is not a dictionary, it is converted to one by calling &f-link-env-ParseFlags; on the argument @@ -2039,19 +2206,17 @@ -By default, -duplicate values are eliminated; -you can, however, specify -unique=0 -to allow duplicate -values to be added. +If unique is true (the default), +duplicate values are not stored. When eliminating duplicate values, -any construction variables that end with +any &consvars; that end with the string PATH keep the left-most unique value. -All other construction variables keep +All other &consvars; keep the right-most unique value. +If unique is false, +values are added even if they are duplicates. @@ -2068,9 +2233,13 @@ # Combine an optimization flag with the flags returned from running pkg-config # twice and merge the result into the construction variables. -env.MergeFlags(['-O3', - '!pkg-config gtk+-2.0 --cflags --libs', - '!pkg-config libpng12 --cflags --libs']) +env.MergeFlags( + [ + '-O3', + '!pkg-config gtk+-2.0 --cflags --libs', + '!pkg-config libpng12 --cflags --libs', + ] +) @@ -2181,38 +2350,52 @@ -Calls the specified -function -to modify the environment as specified by the output of -command. -The default -function -is -&f-link-env-MergeFlags;, -which expects the output of a typical -*-config -command -(for example, -gtk-config) -and adds the options -to the appropriate construction variables. +Updates the current &consenv; with the values extracted +from the output of running external command, +by passing it to a helper function. +command may be a string +or a list of strings representing the command and +its arguments. +If function +is omitted or None, +&f-link-env-MergeFlags; is used. By default, duplicate values are not added to any construction variables; you can specify -unique=0 -to allow duplicate -values to be added. +unique=False +to allow duplicate values to be added. -Interpreted options -and the construction variables they affect -are as specified for the -&f-link-env-ParseFlags; -method (which this method calls). -See that method's description -for a table of options and construction variables. +command is executed using the +SCons execution environment (that is, the &consvar; +&cv-link-ENV; in the current &consenv;). +If command needs additional information +to operate properly, that needs to be set in the execution environment. +For example, pkg-config +may need a custom value set in the PKG_CONFIG_PATH +environment variable. + + + +&f-env-MergeFlags; needs to understand +the output produced by command +in order to distribute it to appropriate &consvars;. +&f-env-MergeFlags; uses a separate function to +do that processing - +see &f-link-env-ParseFlags; for the details, including a +a table of options and corresponding construction variables. +To provide alternative processing of the output of +command, +you can suppply a custom +function, +which must accept three arguments: +the &consenv; to modify, +a string argument containing the output from running +command, +and the optional +unique flag. @@ -2223,8 +2406,7 @@ -Parses the contents of the specified -filename +Parses the contents of filename as a list of dependencies in the style of &Make; or @@ -2235,27 +2417,21 @@ By default, it is not an error -if the specified -filename +if filename does not exist. The optional must_exist -argument may be set to a non-zero -value to have -scons -throw an exception and -generate an error if the file does not exist, +argument may be set to True +to have &SCons; +raise an exception if the file does not exist, or is otherwise inaccessible. The optional only_one -argument may be set to a non-zero -value to have -scons -thrown an exception and -generate an error +argument may be set to True +to have &SCons; raise an exception if the file contains dependency information for more than one target. This can provide a small sanity check @@ -2271,7 +2447,6 @@ -The filename and all of the files listed therein will be interpreted relative to @@ -2291,10 +2466,10 @@ Parses one or more strings containing -typical command-line flags for GCC tool chains +typical command-line flags for GCC-style tool chains and returns a dictionary with the flag values separated into the appropriate SCons construction variables. -This is intended as a companion to the +Intended as a companion to the &f-link-env-MergeFlags; method, but allows for the values in the returned dictionary to be modified, if necessary, @@ -2303,17 +2478,26 @@ &f-env-MergeFlags; will call this method if its argument is not a dictionary, so it is usually not necessary to call -&f-link-env-ParseFlags; +&f-env-ParseFlags; directly unless you want to manipulate the values.) If the first character in any string is -an exclamation mark (!), +an exclamation mark (!), the rest of the string is executed as a command, and the output from the command is parsed as GCC tool chain command-line flags and added to the resulting dictionary. +This can be used to call a *-config +command typical of the POSIX programming environment +(for example, +pkg-config). +Note that such a comamnd is executed using the +SCons execution environment; +if the command needs additional information, +that information needs to be explcitly provided. +See &f-link-ParseConfig; for more details. @@ -2375,18 +2559,22 @@ -(string) +(plat) + + +(plat) -The -&f-Platform; -form returns a callable object +When called as a global function, +returns a callable platform object +selected by plat +(defaults to the detected platform for the +current system) that can be used to initialize -a construction environment using the -platform keyword of the -&f-Environment; -function. +a construction environment by passing it as the +platform keyword argument to the +&f-link-Environment; function. @@ -2394,15 +2582,14 @@ -env = Environment(platform = Platform('win32')) +env = Environment(platform=Platform('win32')) -The -&f-env-Platform; -form applies the callable object for the specified platform -string -to the environment through which the method was called. +When called as a method of an environment, +calls the platform object indicated by +plat +to update that environment. @@ -2410,22 +2597,7 @@ -Note that the -win32 -platform adds the -SystemDrive -and -SystemRoot -variables from the user's external environment -to the construction environment's -&cv-link-ENV; -dictionary. -This is so that any executed commands -that use sockets to connect with other systems -(such as fetching source files from -external CVS repository specifications like -:pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons) -will work on Windows systems. +See the manpage section "Construction Environments" for more details. @@ -2436,19 +2608,10 @@ -Appends the specified keyword arguments -to the beginning of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the values of the construction variable -and the keyword argument are the same type, -then the two values will be simply added together. -Otherwise, the construction variable -and the value of the keyword argument -are both coerced to lists, -and the lists are added together. -(See also the Append method, above.) +Prepend values to &consvars; in the current &consenv;, +Works like &f-link-env-Append; (see for details), +except that values are added to the front, +rather than the end, of any existing value of the &consvar; @@ -2456,40 +2619,43 @@ -env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy']) +env.Prepend(CCFLAGS='-g ', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-AppendUnique; +and &f-link-env-PrependUnique;. + -(name, newpath, [envname, sep, delete_existing]) +(name, newpath, [envname, sep, delete_existing=True]) -This appends new path elements to the given path in the -specified external environment -(&cv-ENV; -by default). -This will only add -any particular path once (leaving the first one it encounters and -ignoring the rest, to preserve path order), -and to help assure this, -will normalize all paths (using -os.path.normpath +Prepend path elements specified by newpath +to the given search path string or list name +in mapping envname in the &consenv;. +Supplying envname is optional: +the default is the execution environment &cv-link-ENV;. +Optional sep is used as the search path separator, +the default is the platform's separator (os.pathsep). +A path element will only appear once. +Any duplicates in newpath are dropped, +keeping the first appearing (to preserve path order). +If delete_existing +is False +any addition duplicating an existing path element is ignored; +if delete_existing +is True (the default) the existing value will +be dropped and the path element will be inserted at the beginning. +To help maintain uniqueness all paths are normalized (using +os.path.normpath and -os.path.normcase). -This can also handle the -case where the given old path variable is a list instead of a -string, in which case a list will be returned instead of a string. - - - -If -delete_existing -is 0, then adding a path that already exists -will not move it to the beginning; -it will stay where it is in the list. +os.path.normcase). @@ -2497,42 +2663,44 @@ -print 'before:',env['ENV']['INCLUDE'] +print('before:', env['ENV']['INCLUDE']) include_path = '/foo/bar:/foo' env.PrependENVPath('INCLUDE', include_path) -print 'after:',env['ENV']['INCLUDE'] +print('after:', env['ENV']['INCLUDE']) - -The above example will print: - +Yields: - + before: /biz:/foo after: /foo/bar:/foo:/biz - + + + +See also &f-link-env-AppendENVPath;. + + -(key=val, delete_existing=0, [...]) +(key=val, delete_existing=False, [...]) -Appends the specified keyword arguments -to the beginning of construction variables in the environment. -If the Environment does not have -the specified construction variable, -it is simply added to the environment. -If the construction variable being appended to is a list, -then any value(s) that already exist in the -construction variable will -not -be added again to the list. -However, if delete_existing is 1, -existing matching values are removed first, so -existing values in the arg list move to the front of the list. +Prepend values to &consvars; in the current &consenv;, +maintaining uniqueness. +Works like &f-link-env-Append; (see for details), +except that values are added to the front, +rather than the end, of any existing value of the &consvar;, +and values already present in the &consvar; +will not be added again. +If delete_existing +is True, +the existing matching value is first removed, +and the requested value is inserted, +having the effect of moving such values to the front. @@ -2540,8 +2708,14 @@ -env.PrependUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) +env.PrependUnique(CCFLAGS='-g', FOO=['foo.yyy']) + + +See also &f-link-env-Append;, +&f-link-env-AppendUnique; +and &f-link-env-Prepend;. + @@ -2583,7 +2757,7 @@ -env.Replace(CCFLAGS = '-g', FOO = 'foo.xxx') +env.Replace(CCFLAGS='-g', FOO='foo.xxx') @@ -2673,7 +2847,7 @@ -(function, [argument, keys, path_function, node_class, node_factory, scan_check, recursive]) +(function, [name, argument, skeys, path_function, node_class, node_factory, scan_check, recursive]) @@ -2716,7 +2890,7 @@ don't necessarily exist locally.) You may enable and disable this ability by calling -SConscriptChdir() +&f-SConscriptChdir; multiple times. @@ -2736,58 +2910,76 @@ -([file, dbm_module]) +([name, dbm_module]) -This tells -&scons; -to store all file signatures -in the specified database -file. -If the -file -name is omitted, -.sconsign -is used by default. -(The actual file name(s) stored on disk -may have an appropriated suffix appended -by the -dbm_module.) -If -file -is not an absolute path name, -the file is placed in the same directory as the top-level -&SConstruct; -file. +Specify where to store the &SCons; file signature database, +and which database format to use. +This may be useful to specify alternate +database files and/or file locations for different types of builds. + + +The optional name argument +is the base name of the database file(s). +If not an absolute path name, +these are placed relative to the directory containing the +top-level &SConstruct; file. +The default is +.sconsign. +The actual database file(s) stored on disk +may have an appropriate suffix appended +by the chosen +dbm_module + + +The optional dbm_module +argument specifies which +&Python; database module to use +for reading/writing the file. +The module must be imported first; +then the imported module name +is passed as the argument. +The default is a custom +SCons.dblite +module that uses pickled +&Python; data structures, +which works on all &Python; versions. +See documentation of the &Python; +dbm module +for other available types. + + +If called with no arguments, +the database will default to +.sconsign.dblite +in the top directory of the project, +which is also the default if +if &f-SConsignFile; is not called. + + +The setting is global, so the only difference +between the global function and the environment method form +is variable expansion on name. +There should only be one active call to this +function/method in a given build setup. - If -file -is +name +is set to None, -then &scons; will store file signatures in a separate .sconsign file in each directory, -not in one global database file. -(This was the default behavior -prior to SCons 0.96.91 and 0.97.) - - - -The optional -dbm_module -argument can be used to specify -which Python database module -The default is to use a custom -SCons.dblite -module that uses pickled -Python data structures, -and which works on all Python versions. +not in a single combined database file. +This is a backwards-compatibility meaure to support +what was the default behavior +prior to &SCons; 0.97 (i.e. before 2008). +Use of this mode is discouraged and may be +deprecated in a future &SCons; release. @@ -2796,20 +2988,25 @@ # Explicitly stores signatures in ".sconsign.dblite" -# in the top-level SConstruct directory (the -# default behavior). +# in the top-level SConstruct directory (the default behavior). SConsignFile() # Stores signatures in the file "etc/scons-signatures" # relative to the top-level SConstruct directory. +# SCons will add a database suffix to this name. SConsignFile("etc/scons-signatures") # Stores signatures in the specified absolute file name. +# SCons will add a database suffix to this name. SConsignFile("/home/me/SCons/signatures") # Stores signatures in a separate .sconsign file # in each directory. SConsignFile(None) + +# Stores signatures in a GNU dbm format .sconsign file +import dbm.gnu +SConsignFile(dbm_module=dbm.gnu) @@ -2826,9 +3023,9 @@ -env.SetDefault(FOO = 'foo') - -if 'FOO' not in env: env['FOO'] = 'foo' +env.SetDefault(FOO='foo') +if 'FOO' not in env: + env['FOO'] = 'foo' @@ -2893,6 +3090,12 @@ &f-env-Clean; function. + + +This function returns the list of side effect Node objects that were successfully added. +If the list of side effects contained any side effects that had already been added, +they are not added and included in the returned list. + @@ -2900,16 +3103,20 @@ (arg) -Returns a list of file names or other objects. If arg is a string, -it will be split on strings of white-space characters -within the string, -making it easier to write long lists of file names. -If arg is already a list, -the list will be returned untouched. +splits on whitespace and returns a list of +strings without whitespace. +This mode is the most common case, +and can be used to split a list of filenames +(for example) rather than having to type them as a +list of individually quoted words. +If arg is a list or tuple +returns the list or tuple unchanged. If arg is any other type of object, -it will be returned as a list -containing just the object. +returns a list containing just the object. +These non-string cases do not actually do any spliting, +but allow an argument variable to be passed to +&f-Split; without having to first check its type. @@ -2920,9 +3127,9 @@ files = Split("f1.c f2.c f3.c") files = env.Split("f4.c f5.c f6.c") files = Split(""" - f7.c - f8.c - f9.c + f7.c + f8.c + f9.c """) @@ -2934,15 +3141,22 @@ -Performs construction variable interpolation -on the specified string or sequence argument -input. +Performs &consvar; interpolation +(substitution) +on input, +which can be a string or a sequence. +Substitutable elements take the form +${expression}, +although if there is no ambiguity in recognizing the element, +the braces can be omitted. +A literal $ can be entered by +using $$. By default, leading or trailing white space will -be removed from the result. +be removed from the result, and all sequences of white space will be compressed to a single space character. Additionally, any @@ -2961,9 +3175,8 @@ raw argument may be set to 2 -if you want to strip -all characters between -any +if you want to additionally discard +all characters between any $( and $) @@ -2972,7 +3185,7 @@ -If the input is a sequence +If input is a sequence (list or tuple), the individual elements of the sequence will be expanded, @@ -2997,7 +3210,7 @@ This is usually necessary if you are calling &f-env-subst; -from within a Python function used +from within a &Python; function used as an SCons action. @@ -3010,12 +3223,11 @@ may specify a conversion function that will be used in place of the default. -For example, if you want Python objects +For example, if you want &Python; objects (including SCons Nodes) -to be returned as Python objects, -you can use the Python -λ -idiom to pass in an unnamed function +to be returned as &Python; objects, +you can use a &Python; +lambda expression to pass in an unnamed function that simply returns its unconverted argument. @@ -3027,12 +3239,13 @@ print(env.subst("The C compiler is: $CC")) def compile(target, source, env): - sourceDir = env.subst("${SOURCE.srcdir}", - target=target, - source=source) + sourceDir = env.subst( + "${SOURCE.srcdir}", + target=target, + source=source + ) -source_nodes = env.subst('$EXPAND_TO_NODELIST', - conv=lambda x: x) +source_nodes = env.subst('$EXPAND_TO_NODELIST', conv=lambda x: x) @@ -3044,22 +3257,32 @@ -Runs the tool identified by -name, which is -searched for in standard locations and any -paths specified by the optional -toolpath, -to update a &consenv; with &consvars; -needed to use the mechanisms that tool describes. +Locates the tool specification module name +and returns a callable tool object for that tool. +The tool module is searched for in standard locations +and in any paths specified by the optional +toolpath parameter. +The standard locations are &SCons;' own internal +path for tools plus the toolpath, if any (see the +Tools section in the manual page +for more details). Any additional keyword arguments kwargs are passed -on to the tool module's generate function. +to the tool module's generate function +during tool object construction. -When called as a &consenv; method, -the tool module is called to update the -&consenv; and the name of the tool is +When called, the tool object +updates a &consenv; with &consvars; and arranges +any other initialization +needed to use the mechanisms that tool describes. + + + +When the &f-env-Tool; form is used, +the tool object is automatically called to update env +and the value of tool is appended to the &cv-link-TOOLS; &consvar; in that environment. @@ -3074,15 +3297,16 @@ -When called as a global function, -returns a callable tool object; -the tool is not called at this time, +When the global function &f-Tool; form is used, +the tool object is constructed but not called, as it lacks the context of an environment to update. -This tool object can be passed to an +The tool object can be passed to an &f-link-Environment; or &f-link-Clone; call as part of the tools keyword argument, +in which case the tool is applied to the environment being constructed, or it can be called directly, -passing a &consenv; to update as the argument. +in which case a &consenv; to update must be +passed as the argument. Either approach will also update the &cv-TOOLS; &consvar;. @@ -3095,11 +3319,17 @@ env = Environment(tools=[Tool('msvc')]) env = Environment() -t = Tool('msvc') -t(env) # adds 'msvc' to the TOOLS variable -u = Tool('opengl', toolpath = ['tools']) -u(env) # adds 'opengl' to the TOOLS variable +msvctool = Tool('msvc') +msvctool(env) # adds 'msvc' to the TOOLS variable +gltool = Tool('opengl', toolpath = ['tools']) +gltool(env) # adds 'opengl' to the TOOLS variable + + +Changed in &SCons; 4.2: &f-env-Tool; now returns +the tool object, previously it did not return +(i.e. returned None). + @@ -3109,7 +3339,7 @@ -Returns a Node object representing the specified Python value. Value +Returns a Node object representing the specified &Python; value. Value Nodes can be used as dependencies of targets. If the result of calling str(value) @@ -3153,8 +3383,8 @@ # 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. @@ -3167,7 +3397,7 @@ def build_value(target, source, env): # A function that "builds" a Python Value by updating - # the the Python value with the contents of the file + # the Python value with the contents of the file # specified as the source of the Builder call ($SOURCE). target[0].write(source[0].get_contents()) @@ -3188,128 +3418,110 @@ -Use the -&f-VariantDir; -function to create a copy of your sources in another location: -if a name under -variant_dir -is not found but exists under -src_dir, -the file or directory is copied to +Sets up a mapping to define a variant build directory in variant_dir. -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. - - - +src_dir may not be underneath +variant_dir. +A &f-VariantDir; mapping is global, even if called using the +&f-env-VariantDir; form. &f-VariantDir; can be called multiple times with the same src_dir -to set up multiple builds with different options -(variants). -The -src_dir -location must be in or underneath the SConstruct file's directory, and -variant_dir -may not be underneath -src_dir. - +to set up multiple variant builds with different options. -The default behavior is for -&scons; -to physically duplicate the source files in 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 -relative to the source file, -or individual compilers or other invoked tools are hard-coded -to put derived files in the same directory as source files. +Note if variant_dir +is not under the project top directory, +target selection rules will not pick targets in the +variant directory unless they are explicitly specified. +When files in variant_dir are referenced, +&SCons; backfills as needed with files from src_dir +to create a complete build directory. +By default, &SCons; +physically duplicates the source files, SConscript files, +and directory structure as needed into the variant directory. +Thus, a build performed in the variant directory is guaranteed to be identical +to a build performed in the source directory even if +intermediate source files are generated during the build, +or if preprocessors or other scanners search for included files +using paths relative to the source file, +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 variant_dir. 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 command-line option. -Moreover, only the files needed for the build are duplicated; -files and directories that are not used are not present in -variant_dir. -Duplicating the source tree may be disabled by setting the -duplicate +Duplicating the source files may be disabled by setting the +duplicate argument to -0 -(zero). +False. This will cause -&scons; +&SCons; to invoke Builders using the path names of source files in src_dir and the path names of derived files within variant_dir. -This is always more efficient than -duplicate=1, -and is usually safe for most builds -(but see above for cases that may cause problems). +This is more efficient than duplicating, +and is safe for most builds; +revert to duplicate=True +if it causes problems. -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 when used with a subsidiary SConscript file. +The subsidiary SConscript file must be called as if it were in variant_dir, regardless of the value of -duplicate. -This is how you tell -&scons; -which variant of a source tree to build: +duplicate. +When calling an SConscript file, you can use the +exports keyword argument +to pass parameters (individually or as an appropriately set up environment) +so the SConscript can pick up the right settings for that variant build. +The SConscript must &f-link-Import; these to use them. Example: +env1 = Environment(...settings for variant1...) +env2 = Environment(...settings for variant2...) + # run src/SConscript in two variant directories VariantDir('build/variant1', 'src') -SConscript('build/variant1/SConscript') +SConscript('build/variant1/SConscript', exports={"env": env1}) VariantDir('build/variant2', 'src') -SConscript('build/variant2/SConscript') +SConscript('build/variant2/SConscript', exports={"env": env2}) See also the -&f-link-SConscript; -function, described above, +&f-link-SConscript; function for another way to specify a variant directory in conjunction with calling a subsidiary SConscript file. -Examples: +More examples: # use names in the build directory, not the source directory VariantDir('build', 'src', duplicate=0) Program('build/prog', 'build/source.c') - - # this builds both the source and docs in a separate subtree VariantDir('build', '.', duplicate=0) SConscript(dirs=['build/src','build/doc']) - - # 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) @@ -3334,11 +3546,11 @@ path keyword argument, or if None (the default) the paths listed in the &consenv; -(env['ENV']['PATH']). +(env['ENV']['PATH']). The external environment's path list (os.environ['PATH']) is used as a fallback if the key -env['ENV']['PATH'] +env['ENV']['PATH'] does not exist. @@ -3347,11 +3559,11 @@ pathext keyword argument, or if None (the default) the pathname extensions listed in the &consenv; -(env['ENV']['PATHEXT']). +(env['ENV']['PATHEXT']). The external environment's pathname extensions list (os.environ['PATHEXT']) is used as a fallback if the key -env['ENV']['PATHEXT'] +env['ENV']['PATHEXT'] does not exist. diff -Nru scons-4.0.1+dfsg/SCons/Errors.py scons-4.4.0+dfsg/SCons/Errors.py --- scons-4.0.1+dfsg/SCons/Errors.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Errors.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -102,8 +99,8 @@ self.action = action self.command = command - Exception.__init__(self, node, errstr, status, exitstatus, filename, - executor, action, command, exc_info) + super().__init__(node, errstr, status, exitstatus, filename, + executor, action, command, exc_info) def __str__(self): if self.filename: @@ -131,7 +128,7 @@ self.node = node self.status = status self.exitstatus = status - Exception.__init__(self, *args) + super().__init__(*args) def convert_to_BuildError(status, exc_info=None): """Convert a return code to a BuildError Exception. diff -Nru scons-4.0.1+dfsg/SCons/ErrorsTests.py scons-4.4.0+dfsg/SCons/ErrorsTests.py --- scons-4.0.1+dfsg/SCons/ErrorsTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/ErrorsTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,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 errno -import os -import sys import unittest import SCons.Errors diff -Nru scons-4.0.1+dfsg/SCons/Executor.py scons-4.4.0+dfsg/SCons/Executor.py --- scons-4.0.1+dfsg/SCons/Executor.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Executor.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,16 +20,17 @@ # 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 -import SCons.Debug -from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize import SCons.Util from SCons.compat import NoSlotsPyPy +import SCons.Debug +from SCons.Debug import logInstanceCreation class Batch: """Remembers exact association between targets @@ -68,10 +63,6 @@ def __getitem__(self, i): nl = self.func() return nl[i] - def __getslice__(self, i, j): - nl = self.func() - i, j = max(i, 0), max(j, 0) - return nl[i:j] def __str__(self): nl = self.func() return str(nl) @@ -279,10 +270,8 @@ return self.get_lvars()[targets_string] def set_action_list(self, action): - import SCons.Util if not SCons.Util.is_List(action): if not action: - import SCons.Errors raise SCons.Errors.UserError("Executor must have an action.") action = [action] self.action_list = action diff -Nru scons-4.0.1+dfsg/SCons/ExecutorTests.py scons-4.4.0+dfsg/SCons/ExecutorTests.py --- scons-4.0.1+dfsg/SCons/ExecutorTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/ExecutorTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/exitfuncs.py scons-4.4.0+dfsg/SCons/exitfuncs.py --- scons-4.0.1+dfsg/SCons/exitfuncs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/exitfuncs.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 diff -Nru scons-4.0.1+dfsg/SCons/__init__.py scons-4.4.0+dfsg/SCons/__init__.py --- scons-4.0.1+dfsg/SCons/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,9 +1,9 @@ -__version__="4.0.1" -__copyright__="Copyright (c) 2001 - 2020 The SCons Foundation" +__version__="4.4.0" +__copyright__="Copyright (c) 2001 - 2022 The SCons Foundation" __developer__="bdbaddog" -__date__="2020-07-17 01:50:03" -__buildsys__="ProDog2020" -__revision__="c289977f8b34786ab6c334311e232886da7e8df1" -__build__="c289977f8b34786ab6c334311e232886da7e8df1" +__date__="Sat, 30 Jul 2022 14:11:34 -0700" +__buildsys__="M1Dog2021" +__revision__="fc8d0ec215ee6cba8bc158ad40c099be0b598297" +__build__="fc8d0ec215ee6cba8bc158ad40c099be0b598297" # make sure compatibility is always in place import SCons.compat # noqa \ No newline at end of file diff -Nru scons-4.0.1+dfsg/SCons/Job.py scons-4.4.0+dfsg/SCons/Job.py --- scons-4.0.1+dfsg/SCons/Job.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Job.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -37,6 +33,7 @@ import signal import SCons.Errors +import SCons.Warnings # The default stack size (in kilobytes) of the threads used to execute # jobs in parallel. @@ -143,7 +140,7 @@ self.job.taskmaster.stop() self.job.interrupted.set() else: - os._exit(2) + os._exit(2) # pylint: disable=protected-access self.old_sigint = signal.signal(signal.SIGINT, handler) self.old_sigterm = signal.signal(signal.SIGTERM, handler) @@ -151,15 +148,22 @@ self.old_sighup = signal.signal(signal.SIGHUP, handler) except AttributeError: pass + if (self.old_sigint is None) or (self.old_sigterm is None) or \ + (hasattr(self, "old_sighup") and self.old_sighup is None): + msg = "Overwritting previous signal handler which was not installed from Python. " + \ + "Will not be able to reinstate and so will return to default handler." + SCons.Warnings.warn(SCons.Warnings.SConsWarning, msg) def _reset_sig_handler(self): """Restore the signal handlers to their previous state (before the call to _setup_sig_handler().""" - - signal.signal(signal.SIGINT, self.old_sigint) - signal.signal(signal.SIGTERM, self.old_sigterm) + sigint_to_use = self.old_sigint if self.old_sigint is not None else signal.SIG_DFL + sigterm_to_use = self.old_sigterm if self.old_sigterm is not None else signal.SIG_DFL + signal.signal(signal.SIGINT, sigint_to_use) + signal.signal(signal.SIGTERM, sigterm_to_use) try: - signal.signal(signal.SIGHUP, self.old_sighup) + sigterm_to_use = self.old_sighup if self.old_sighup is not None else signal.SIG_DFL + signal.signal(signal.SIGHUP, sigterm_to_use) except AttributeError: pass @@ -234,8 +238,8 @@ and a boolean indicating whether the task executed successfully. """ def __init__(self, requestQueue, resultsQueue, interrupted): - threading.Thread.__init__(self) - self.setDaemon(1) + super().__init__() + self.daemon = True self.requestQueue = requestQueue self.resultsQueue = resultsQueue self.interrupted = interrupted @@ -393,7 +397,7 @@ if task.needs_execute(): # dispatch task self.tp.put(task) - jobs = jobs + 1 + jobs += 1 else: task.executed() task.postprocess() @@ -404,7 +408,7 @@ # back and put the next batch of tasks on the queue. while True: task, ok = self.tp.get() - jobs = jobs - 1 + jobs -= 1 if ok: task.executed() diff -Nru scons-4.0.1+dfsg/SCons/JobTests.py scons-4.4.0+dfsg/SCons/JobTests.py --- scons-4.0.1+dfsg/SCons/JobTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/JobTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ 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 @@ try: import threading - except: + except ImportError: raise NoThreadsException() taskmaster = Taskmaster(num_tasks, self, RandomTask) @@ -411,13 +410,13 @@ class testnode (SCons.Node.Node): def __init__(self): - SCons.Node.Node.__init__(self) + super().__init__() self.expect_to_be = SCons.Node.executed self.ninfo = DummyNodeInfo() class goodnode (testnode): def __init__(self): - SCons.Node.Node.__init__(self) + super().__init__() self.expect_to_be = SCons.Node.up_to_date self.ninfo = DummyNodeInfo() @@ -431,7 +430,7 @@ class badnode (goodnode): def __init__(self): - goodnode.__init__(self) + super().__init__() self.expect_to_be = SCons.Node.failed def build(self, **kw): raise Exception('badnode exception') diff -Nru scons-4.0.1+dfsg/SCons/__main__.py scons-4.4.0+dfsg/SCons/__main__.py --- scons-4.0.1+dfsg/SCons/__main__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/__main__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Memoize.py scons-4.4.0+dfsg/SCons/Memoize.py --- scons-4.0.1+dfsg/SCons/Memoize.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Memoize.py 2022-07-30 21:48:28.000000000 +0000 @@ -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. @@ -160,7 +159,7 @@ def __init__(self, cls_name, method_name, keymaker): """ """ - Counter.__init__(self, cls_name, method_name) + super().__init__(cls_name, method_name) self.keymaker = keymaker def count(self, *args, **kw): """ Counts whether the computed key value is already present diff -Nru scons-4.0.1+dfsg/SCons/MemoizeTests.py scons-4.4.0+dfsg/SCons/MemoizeTests.py --- scons-4.0.1+dfsg/SCons/MemoizeTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/MemoizeTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Node/Alias.py scons-4.4.0+dfsg/SCons/Node/Alias.py --- scons-4.0.1+dfsg/SCons/Node/Alias.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/Alias.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,16 +20,18 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Alias nodes. + +This creates a hash of global Aliases (dummy targets). +""" import collections import SCons.Errors import SCons.Node import SCons.Util -from SCons.Util import MD5signature +from SCons.Util import hash_signature class AliasNameSpace(collections.UserDict): def Alias(self, name, **kw): @@ -105,7 +99,7 @@ BuildInfo = AliasBuildInfo def __init__(self, name): - SCons.Node.Node.__init__(self) + super().__init__() self.name = name self.changed_since_last_build = 1 self.store_info = 0 @@ -167,7 +161,7 @@ pass contents = self.get_contents() - csig = MD5signature(contents) + csig = hash_signature(contents) self.get_ninfo().csig = csig return csig diff -Nru scons-4.0.1+dfsg/SCons/Node/AliasTests.py scons-4.4.0+dfsg/SCons/Node/AliasTests.py --- scons-4.0.1+dfsg/SCons/Node/AliasTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/AliasTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Node/FS.py scons-4.4.0+dfsg/SCons/Node/FS.py --- scons-4.0.1+dfsg/SCons/Node/FS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/FS.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,32 +20,39 @@ # 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 codecs import fnmatch +import importlib.util import os import re import shutil import stat import sys import time -import codecs from itertools import chain -import importlib.util +from typing import Optional import SCons.Action import SCons.Debug -from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize import SCons.Node import SCons.Node.Alias import SCons.Subst import SCons.Util -from SCons.Util import MD5signature, MD5filesignature, MD5collect import SCons.Warnings - -from SCons.Debug import Trace +from SCons.Debug import logInstanceCreation, Trace +from SCons.Util import hash_signature, hash_file_signature, hash_collect print_duplicate = 0 @@ -86,7 +82,7 @@ of the underlying Entry involved in an AttributeError exception. """ def __init__(self, entry_proxy, attribute): - AttributeError.__init__(self) + super().__init__() self.entry_proxy = entry_proxy self.attribute = attribute def __str__(self): @@ -259,7 +255,7 @@ def _copy_func(fs, src, dest): shutil.copy2(src, dest) st = fs.stat(src) - fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + fs.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE) Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy', @@ -439,7 +435,7 @@ # 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): @@ -447,6 +443,11 @@ return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), entry.name + "_abspath") + def __get_relpath(self): + entry = self.get() + return SCons.Subst.SpecialAttrWrapper(entry.get_relpath(), + entry.name + "_relpath") + def __get_filebase(self): name = self.get().name return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0], @@ -515,6 +516,7 @@ "srcdir" : __get_srcdir, "dir" : __get_dir, "abspath" : __get_abspath, + "relpath" : __get_relpath, "filebase" : __get_filebase, "suffix" : __get_suffix, "file" : __get_file, @@ -577,7 +579,7 @@ signatures.""" if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Base') - SCons.Node.Node.__init__(self) + super().__init__() # Filenames and paths are probably reused and are intern'ed to save some memory. # Filename with extension as it was specified when the object was @@ -731,10 +733,7 @@ return SCons.Node._rexists_map[self._func_rexists](self) def getmtime(self): - if self.islink(): - st = self.lstat() - else: - st = self.stat() + st = self.stat() if st: return st[stat.ST_MTIME] @@ -742,32 +741,28 @@ return None def getsize(self): - if self.islink(): - st = self.lstat() - else: - st = self.stat() + st = self.stat() if st: - return st[stat.ST_SIZE] + return st.st_size else: return None def isdir(self): st = self.stat() - return st is not None and stat.S_ISDIR(st[stat.ST_MODE]) + return st is not None and stat.S_ISDIR(st.st_mode) def isfile(self): st = self.stat() - return st is not None and stat.S_ISREG(st[stat.ST_MODE]) + return st is not None and stat.S_ISREG(st.st_mode) if hasattr(os, 'symlink'): def islink(self): - try: st = self.fs.lstat(self.get_abspath()) - except os.error: return 0 - return stat.S_ISLNK(st[stat.ST_MODE]) + st = self.lstat() + return st is not None and stat.S_ISLNK(st.st_mode) else: def islink(self): - return 0 # no symlinks + return False # no symlinks def is_under(self, dir): if self is dir: @@ -836,6 +831,10 @@ """Get the absolute path of the file.""" return self.dir.entry_labspath(self.name) + def get_relpath(self): + """Get the path of the file relative to the root SConstruct file's directory.""" + return os.path.relpath(self.dir.entry_abspath(self.name), self.fs.SConstruct_dir.get_abspath()) + def get_internal_path(self): if self.dir._path == '.': return self.name @@ -943,10 +942,11 @@ # Dict that provides a simple backward compatibility # layer for the Node attributes 'abspath', 'labspath', -# 'path', 'tpath' and 'path_elements'. +# 'relpath', 'path', 'tpath' and 'path_elements'. # @see Base.__getattr__ above node_bwcomp = {'abspath' : Base.get_abspath, 'labspath' : Base.get_labspath, + 'relpath' : Base.get_relpath, 'path' : Base.get_internal_path, 'tpath' : Base.get_tpath, 'path_elements' : Base.get_path_elements, @@ -976,7 +976,7 @@ 'contentsig'] def __init__(self, name, directory, fs): - Base.__init__(self, name, directory, fs) + super().__init__(name, directory, fs) self._func_exists = 3 self._func_get_contents = 1 @@ -985,7 +985,7 @@ def disambiguate(self, must_exist=None): """ - """ + """ if self.isfile(): self.__class__ = File self._morph() @@ -1111,56 +1111,81 @@ needs to use os.chdir() directly to avoid recursion. Will we really need this one? """ - #def chdir(self, path): - # return os.chdir(path) + def chmod(self, path, mode): return os.chmod(path, mode) + def copy(self, src, dst): return shutil.copy(src, dst) + def copy2(self, src, dst): return shutil.copy2(src, dst) + def exists(self, path): return os.path.exists(path) + def getmtime(self, path): return os.path.getmtime(path) + def getsize(self, path): return os.path.getsize(path) + def isdir(self, path): return os.path.isdir(path) + def isfile(self, path): return os.path.isfile(path) + def link(self, src, dst): return os.link(src, dst) + def lstat(self, path): return os.lstat(path) + def listdir(self, path): return os.listdir(path) - def makedirs(self, path): - return os.makedirs(path) - def mkdir(self, path): - return os.mkdir(path) + + def scandir(self, path): + return os.scandir(path) + + def makedirs(self, path, mode=0o777, exist_ok=False): + return os.makedirs(path, mode=mode, exist_ok=exist_ok) + + def mkdir(self, path, mode=0o777): + return os.mkdir(path, mode=mode) + def rename(self, old, new): return os.rename(old, new) + def stat(self, path): return os.stat(path) + def symlink(self, src, dst): return os.symlink(src, dst) + def open(self, path): return open(path) + def unlink(self, path): return os.unlink(path) if hasattr(os, 'symlink'): + def islink(self, path): return os.path.islink(path) + else: + def islink(self, path): - return 0 # no symlinks + return False # no symlinks if hasattr(os, 'readlink'): + def readlink(self, file): return os.readlink(file) + else: + def readlink(self, file): return '' @@ -1543,7 +1568,7 @@ def __init__(self, name, directory, fs): if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Dir') - Base.__init__(self, name, directory, fs) + super().__init__(name, directory, fs) self._morph() def _morph(self): @@ -1870,7 +1895,7 @@ node is called which has a child directory, the child directory should return the hash of its contents.""" contents = self.get_contents() - return MD5signature(contents) + return hash_signature(contents) def do_duplicate(self, src): pass @@ -1908,7 +1933,7 @@ return self.srcdir return Base.srcnode(self) - def get_timestamp(self): + def get_timestamp(self) -> int: """Return the latest timestamp from among our children""" stamp = 0 for kid in self.children(): @@ -1916,11 +1941,11 @@ stamp = kid.get_timestamp() return stamp - def get_abspath(self): + def get_abspath(self) -> str: """Get the absolute path of the file.""" return self._abspath - def get_labspath(self): + def get_labspath(self) -> str: """Get the absolute path of the file.""" return self._labspath @@ -2532,7 +2557,7 @@ if key != 'dependency_map' and hasattr(self, 'dependency_map'): del self.dependency_map - return super(FileBuildInfo, self).__setattr__(key, value) + return super().__setattr__(key, value) def convert_to_sconsign(self): """ @@ -2634,7 +2659,8 @@ NodeInfo = FileNodeInfo BuildInfo = FileBuildInfo - md5_chunksize = 64 + # Although the command-line argument is in kilobytes, this is in bytes. + hash_chunksize = 65536 def diskcheck_match(self): diskcheck_match(self, self.isdir, @@ -2642,7 +2668,7 @@ def __init__(self, name, directory, fs): if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.File') - Base.__init__(self, name, directory, fs) + super().__init__(name, directory, fs) self._morph() def Entry(self, name): @@ -2697,11 +2723,13 @@ def scanner_key(self): return self.get_suffix() - def get_contents(self): + def get_contents(self) -> bytes: + """Return the contents of the file as bytes.""" return SCons.Node._get_contents_map[self._func_get_contents](self) - def get_text_contents(self): - """ + def get_text_contents(self) -> str: + """Return the contents of the file in text form. + This attempts to figure out what the encoding of the text is based upon the BOM bytes, and then decodes the contents so that it's a valid python string. @@ -2725,18 +2753,17 @@ try: return contents.decode('latin-1') except UnicodeDecodeError as e: - return contents.decode('utf-8', error='backslashreplace') + return contents.decode('utf-8', errors='backslashreplace') - - def get_content_hash(self): + def get_content_hash(self) -> str: """ - Compute and return the MD5 hash for this file. + Compute and return the hash for this file. """ if not self.rexists(): - return MD5signature('') + return hash_signature(SCons.Util.NOFILE) fname = self.rfile().get_abspath() try: - cs = MD5filesignature(fname, chunksize=File.md5_chunksize * 1024) + cs = hash_file_signature(fname, chunksize=File.hash_chunksize) except EnvironmentError as e: if not e.filename: e.filename = fname @@ -2744,7 +2771,7 @@ return cs @SCons.Memoize.CountMethodCall - def get_size(self): + def get_size(self) -> int: try: return self._memo['get_size'] except KeyError: @@ -2753,14 +2780,14 @@ if self.rexists(): size = self.rfile().getsize() else: - size = 0 + # sentinel value for doesn't exist, even in repository + size = -1 self._memo['get_size'] = size - return size @SCons.Memoize.CountMethodCall - def get_timestamp(self): + def get_timestamp(self) -> int: try: return self._memo['get_timestamp'] except KeyError: @@ -2772,7 +2799,6 @@ timestamp = 0 self._memo['get_timestamp'] = timestamp - return timestamp convert_copy_attrs = [ @@ -2784,7 +2810,6 @@ 'ninfo', ] - convert_sig_attrs = [ 'bsourcesigs', 'bimplicitsigs', @@ -3177,7 +3202,7 @@ # SIGNATURE SUBSYSTEM # - def get_max_drift_csig(self): + def get_max_drift_csig(self) -> Optional[str]: """ Returns the content signature currently stored for this node if it's been unmodified longer than the max_drift value, or the @@ -3203,15 +3228,8 @@ return None - def get_csig(self): - """ - Generate a node's content signature, the digested signature - of its content. - - node - the node - cache - alternate node to use for the signature cache - returns - the content signature - """ + def get_csig(self) -> str: + """Generate a node's content signature.""" ninfo = self.get_ninfo() try: return ninfo.csig @@ -3220,9 +3238,11 @@ csig = self.get_max_drift_csig() if csig is None: - try: - if self.get_size() < File.md5_chunksize: + size = self.get_size() + if size == -1: + contents = SCons.Util.NOFILE + elif size < File.hash_chunksize: contents = self.get_contents() else: csig = self.get_content_hash() @@ -3234,7 +3254,7 @@ csig = '' else: if not csig: - csig = SCons.Util.MD5signature(contents) + csig = SCons.Util.hash_signature(contents) ninfo.csig = csig @@ -3621,9 +3641,10 @@ except AttributeError: pass - cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self) + cache = self.get_build_env().get_CacheDir() + cachedir, cachefile = cache.cachepath(self) if not self.exists() and cachefile and os.path.exists(cachefile): - self.cachedir_csig = MD5filesignature(cachefile, File.md5_chunksize * 1024) + self.cachedir_csig = cache.get_cachedir_csig(self) else: self.cachedir_csig = self.get_csig() return self.cachedir_csig @@ -3643,7 +3664,7 @@ executor = self.get_executor() - result = self.contentsig = MD5signature(executor.get_contents()) + result = self.contentsig = hash_signature(executor.get_contents()) return result def get_cachedir_bsig(self): @@ -3674,7 +3695,7 @@ sigs.append(self.get_internal_path()) # Merge this all into a single signature - result = self.cachesig = MD5collect(sigs) + result = self.cachesig = hash_collect(sigs) return result default_fs = None @@ -3728,7 +3749,10 @@ return None def _find_file_key(self, filename, paths, verbose=None): - return (filename, paths) + # Note: paths could be a list, which is not hashable. If it is, convert + # it to a tuple, which is hashable. + paths_entry = tuple(paths) if isinstance(paths, list) else paths + return (filename, paths_entry) @SCons.Memoize.CountDictCall(_find_file_key) def find_file(self, filename, paths, verbose=None): diff -Nru scons-4.0.1+dfsg/SCons/Node/FSTests.py scons-4.4.0+dfsg/SCons/Node/FSTests.py --- scons-4.0.1+dfsg/SCons/Node/FSTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/FSTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -33,7 +31,6 @@ import stat from TestCmd import TestCmd, IS_WINDOWS -import TestUnit import SCons.Errors import SCons.Node.FS @@ -411,8 +408,8 @@ None) os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE) st = os.stat(test.workpath('build/foo')) - assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \ - stat.S_IMODE(st[stat.ST_MODE]) + assert (stat.S_IMODE(st.st_mode) & stat.S_IWRITE), \ + stat.S_IMODE(st.st_mode) # This used to generate a UserError when we forbid the source # directory from being outside the top-level SConstruct dir. @@ -774,7 +771,7 @@ mtime = st[stat.ST_MTIME] assert ni.timestamp == mtime, (ni.timestamp, mtime) - size = st[stat.ST_SIZE] + size = st.st_size assert ni.size == size, (ni.size, size) import time @@ -786,7 +783,7 @@ mtime = st[stat.ST_MTIME] assert ni.timestamp != mtime, (ni.timestamp, mtime) - size = st[stat.ST_SIZE] + size = st.st_size assert ni.size != size, (ni.size, size) @@ -1694,7 +1691,6 @@ 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:] @@ -2058,6 +2054,65 @@ assert g.get_csig() + " g" == files[2], files assert s.get_csig() + " sub" == files[3], files + def test_hash_chunksize(self): + """ + Test verifying that File.get_csig() correctly uses hash_chunksize. This + variable is documented as the hash chunksize in kilobytes. This test + verifies that if the file size is less than the hash chunksize, + get_contents() is called; otherwise, it verifies that get_contents() + is not called. + """ + chunksize_bytes = SCons.Node.FS.File.hash_chunksize + test = self.test + + test.subdir('chunksize_dir') + test.write(['chunksize_dir', 'f1'], 'a' * (chunksize_bytes // 1024 - 1)) + test.write(['chunksize_dir', 'f2'], 'a' * (chunksize_bytes // 1024)) + test.write(['chunksize_dir', 'f3'], 'a' * (chunksize_bytes + 1)) + + dir = self.fs.Dir('chunksize_dir') + f1 = dir.File('f1') + f2 = dir.File('f2') + f3 = dir.File('f3') + + # Expect f1 and f2 to call get_contents(), while f3 will not because it + # should do reads of chunksize kilobytes at a time. + expected_get_contents_calls = {f1, f2} + self.actual_get_contents_calls = 0 + + def get_contents_override(file_object): + self.actual_get_contents_calls += 1 + if file_object in expected_get_contents_calls: + return file_object._old_get_contents() + else: + raise Exception('get_contents was unexpectedly called on node ' + '%s' % file_object) + + SCons.Node.FS.File._old_get_contents = SCons.Node.FS.File.get_contents + SCons.Node.FS.File.get_contents = get_contents_override.__get__( + None, SCons.Node.FS) + + # Call get_csig() to test get_contents() usage. The actual results of + # the calls to get_csig() are not relevant for this test. If an + # exception is raised, we must first reset the get_contents function + # before reraising it or other tests will fail too. + exception = None + try: + f1.get_csig() + f2.get_csig() + f3.get_csig() + except Exception as e: + exception = e + + SCons.Node.FS.File.get_contents = SCons.Node.FS.File._old_get_contents + delattr(SCons.Node.FS.File, '_old_get_contents') + + if exception: + raise exception + + assert self.actual_get_contents_calls == len(expected_get_contents_calls), \ + self.actual_get_contents_calls + def test_implicit_re_scans(self): """Test that adding entries causes a directory to be re-scanned """ @@ -2513,7 +2568,7 @@ class ChangedNode(SCons.Node.FS.File): def __init__(self, name, directory=None, fs=None): - SCons.Node.FS.File.__init__(self, name, directory, fs) + super().__init__(name, directory, fs) self.name = name self.Tag('found_includes', []) self.stored_info = None @@ -2553,7 +2608,7 @@ class ChangedEnvironment(SCons.Environment.Base): def __init__(self): - SCons.Environment.Base.__init__(self) + super().__init__() self.decide_source = self._changed_timestamp_then_content class FakeNodeInfo: @@ -2630,8 +2685,11 @@ print("%15s -> csig:%s" % (i3.name, i3.ninfo.csig)) print("%15s -> csig:%s" % (i4.name, i4.ninfo.csig)) - self.assertEqual(i2.name, i2.ninfo.csig, - "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig) + self.assertEqual( + i2.name, + i2.ninfo.csig, + "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig, + ) class GlobTestCase(_tempdirTestCase): @@ -3617,7 +3675,8 @@ f9 = fs.File('f9') r = f9.get_cachedir_csig() - assert r == 'd41d8cd98f00b204e9800998ecf8427e', r + exsig = SCons.Util.MD5signature(SCons.Util.NOFILE) + assert r == exsig, r class clearTestCase(unittest.TestCase): @@ -3666,6 +3725,13 @@ assert not f.exists() assert not f.rexists() assert str(f) == test.workpath('f'), str(f) + # Now verify clear() resets optional File-specific attributes + optional_attrs = ['cachedir_csig', 'cachesig', 'contentsig'] + for attr in optional_attrs: + setattr(f, attr, 'xyz') + f.clear() + for attr in optional_attrs: + assert not hasattr(f, attr), attr class disambiguateTestCase(unittest.TestCase): diff -Nru scons-4.0.1+dfsg/SCons/Node/__init__.py scons-4.4.0+dfsg/SCons/Node/__init__.py --- scons-4.0.1+dfsg/SCons/Node/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,28 +21,35 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__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 - -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest +from itertools import chain, zip_longest import SCons.Debug -from SCons.Debug import logInstanceCreation import SCons.Executor import SCons.Memoize -import SCons.Util -from SCons.Util import MD5signature - -from SCons.Debug import Trace - from SCons.compat import NoSlotsPyPy +from SCons.Debug import logInstanceCreation, Trace +from SCons.Util import hash_signature, is_List, UniqueList, render_tree print_duplicate = 0 @@ -781,7 +768,7 @@ # Handle issue where builder emits more than one target and # the source file for the builder is generated. # in that case only the first target was getting it's .implicit - # cleared when the source file is built (second scan). + # cleared when the source file is built (second scan). # leaving only partial implicits from scan before source file is generated # typically the compiler only. Then scanned files are appended # This is persisted to sconsign and rebuild causes false rebuilds @@ -823,25 +810,21 @@ 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. - - 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. + 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. - @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) @@ -877,10 +860,12 @@ self.clear_memoized_values() self.ninfo = self.new_ninfo() self.executor_cleanup() - try: - delattr(self, '_calculated_sig') - except AttributeError: - pass + for attr in ['cachedir_csig', 'cachesig', 'contentsig']: + try: + delattr(self, attr) + except AttributeError: + pass + self.cached = 0 self.includes = None def clear_memoized_values(self): @@ -900,7 +885,7 @@ than simply examining the builder attribute directly ("if node.builder: ..."). When the builder attribute is examined directly, it ends up calling __getattr__ for both the __len__ - and __nonzero__ attributes on instances of our Builder Proxy + and __bool__ attributes on instances of our Builder Proxy class(es), generating a bazillion extra calls and slowing things down immensely. """ @@ -953,6 +938,19 @@ """ Returns true if this node is an sconscript """ return self in SConscriptNodes + def is_conftest(self): + """ Returns true if this node is an conftest node""" + try: + self.attributes.conftest_node + except AttributeError: + return False + return True + + def check_attributes(self, name): + """ Simple API to check if the node.attributes for name has been set""" + return getattr(getattr(self, "attributes", None), name, None) + + def alter_targets(self): """Return a list of alternate targets for this Node. """ @@ -1173,7 +1171,7 @@ if self.has_builder(): binfo.bact = str(executor) - binfo.bactsig = MD5signature(executor.get_contents()) + binfo.bactsig = hash_signature(executor.get_contents()) if self._specific_sources: sources = [s for s in self.sources if s not in ignore_set] @@ -1211,7 +1209,7 @@ return self.ninfo.csig except AttributeError: ninfo = self.get_ninfo() - ninfo.csig = MD5signature(self.get_contents()) + ninfo.csig = hash_signature(self.get_contents()) return self.ninfo.csig def get_cachedir_csig(self): @@ -1280,7 +1278,7 @@ self._add_child(self.depends, self.depends_set, depend) except TypeError as e: e = e.args[0] - if SCons.Util.is_List(e): + if is_List(e): s = list(map(str, e)) else: s = str(e) @@ -1289,7 +1287,7 @@ def add_prerequisite(self, prerequisite): """Adds prerequisites""" if self.prerequisites is None: - self.prerequisites = SCons.Util.UniqueList() + self.prerequisites = UniqueList() self.prerequisites.extend(prerequisite) self._children_reset() @@ -1299,7 +1297,7 @@ self._add_child(self.ignore, self.ignore_set, depend) except TypeError as e: e = e.args[0] - if SCons.Util.is_List(e): + if is_List(e): s = list(map(str, e)) else: s = str(e) @@ -1313,7 +1311,7 @@ self._add_child(self.sources, self.sources_set, source) except TypeError as e: e = e.args[0] - if SCons.Util.is_List(e): + if is_List(e): s = list(map(str, e)) else: s = str(e) @@ -1502,7 +1500,7 @@ if self.has_builder(): contents = self.get_executor().get_contents() - newsig = MD5signature(contents) + newsig = hash_signature(contents) if bi.bactsig != newsig: if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig)) result = True @@ -1557,7 +1555,7 @@ path = None def f(node, env=env, scanner=scanner, path=path): return node.get_found_includes(env, scanner, path) - return SCons.Util.render_tree(s, f, 1) + return render_tree(s, f, 1) else: return None diff -Nru scons-4.0.1+dfsg/SCons/Node/NodeTests.py scons-4.4.0+dfsg/SCons/Node/NodeTests.py --- scons-4.0.1+dfsg/SCons/Node/NodeTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/NodeTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -163,7 +160,7 @@ class ListBuilder(Builder): def __init__(self, *nodes): - Builder.__init__(self) + super().__init__() self.nodes = nodes def execute(self, target, source, env): if hasattr(self, 'status'): @@ -203,7 +200,7 @@ simulate a real, functional Node subclass. """ def __init__(self, name): - SCons.Node.Node.__init__(self) + super().__init__() self.name = name self.Tag('found_includes', []) def __str__(self): @@ -584,7 +581,7 @@ def test_get_csig(self): """Test generic content signature calculation """ - + class TestNodeInfo(SCons.Node.NodeInfoBase): __slots__ = ('csig',) try: @@ -595,7 +592,7 @@ node = SCons.Node.Node() node._func_get_contents = 4 result = node.get_csig() - assert result == '550a141f12de6341fba65b0ad0433500', result + assert result in ('550a141f12de6341fba65b0ad0433500', '9a3e61b6bcc8abec08f195526c3132d5a4a98cc0', '3538a1ef2e113da64249eea7bd068b585ec7ce5df73b2d1e319d8c9bf47eb314'), result finally: SCons.Node.Node.NodeInfo = SCons.Node.NodeInfoBase @@ -612,7 +609,7 @@ node = SCons.Node.Node() node._func_get_contents = 4 result = node.get_cachedir_csig() - assert result == '15de21c670ae7c3f6f3f1f37029303c9', result + assert result in ('15de21c670ae7c3f6f3f1f37029303c9', 'cfa1150f1787186742a9a884b73a43d8cf219f9b', '91a73fd806ab2c005c13b4dc19130a884e909dea3f72d46e30266fe1a1f588d8'), result finally: SCons.Node.Node.NodeInfo = SCons.Node.NodeInfoBase @@ -623,7 +620,7 @@ __slots__ = ('csig',) SCons.Node.Node.NodeInfo = TestNodeInfo node = SCons.Node.Node() - + binfo = node.get_binfo() assert isinstance(binfo, SCons.Node.BuildInfoBase), binfo @@ -1229,7 +1226,7 @@ """Test the get_string() method.""" class TestNode(MyNode): def __init__(self, name, sig): - MyNode.__init__(self, name) + super().__init__(name) self.sig = sig def for_signature(self): @@ -1257,6 +1254,19 @@ assert not n.is_sconscript() assert n2.is_sconscript() + def test_conftests(self): + """Test the is_conftest() function.""" + # check nodes are not sconscript unless added to the list + n=SCons.Node.Node() + n2=SCons.Node.Node() + assert not n.is_conftest() + assert not n2.is_conftest() + + # add node to sconscript list and verify + n2.attributes.conftest_node = 1 + assert not n.is_conftest() + assert n2.is_conftest() + def test_Annotate(self): """Test using an interface-specific Annotate function.""" def my_annotate(node, self=self): @@ -1287,6 +1297,7 @@ n.includes = 'testincludes' n.Tag('found_includes', {'testkey':'testvalue'}) n.implicit = 'testimplicit' + n.cached = 1 x = MyExecutor() n.set_executor(x) @@ -1294,6 +1305,7 @@ n.clear() assert n.includes is None, n.includes + assert n.cached == 0, n.cached assert x.cleaned_up def test_get_subst_proxy(self): diff -Nru scons-4.0.1+dfsg/SCons/Node/Python.py scons-4.4.0+dfsg/SCons/Node/Python.py --- scons-4.0.1+dfsg/SCons/Node/Python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/Python.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -89,7 +83,7 @@ BuildInfo = ValueBuildInfo def __init__(self, value, built_value=None, name=None): - SCons.Node.Node.__init__(self) + super().__init__() self.value = value self.changed_since_last_build = 6 self.store_info = 0 @@ -135,7 +129,7 @@ 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 @@ -144,27 +138,13 @@ ###TODO: something reasonable about universal newlines contents = str(self.value) for kid in self.children(None): - contents = contents + kid.get_contents().decode() + # Get csig() value of child as this is more efficent + contents = contents + kid.get_csig() return contents - def get_contents(self): - """ - 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 changed_since_last_build(self, target, prev_ni): - cur_csig = self.get_csig() - try: - return cur_csig != prev_ni.csig - except AttributeError: - return 1 + def get_contents(self) -> bytes: + """Get contents for signature calculations.""" + return self.get_text_contents().encode() def get_csig(self, calc=None): """Because we're a Python value node and don't have a real diff -Nru scons-4.0.1+dfsg/SCons/Node/PythonTests.py scons-4.4.0+dfsg/SCons/Node/PythonTests.py --- scons-4.0.1+dfsg/SCons/Node/PythonTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Node/PythonTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/PathList.py scons-4.4.0+dfsg/SCons/PathList.py --- scons-4.0.1+dfsg/SCons/PathList.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/PathList.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/PathListTests.py scons-4.4.0+dfsg/SCons/PathListTests.py --- scons-4.0.1+dfsg/SCons/PathListTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/PathListTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,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 sys import unittest -import TestUnit - import SCons.PathList @@ -189,16 +184,7 @@ 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 -Nru scons-4.0.1+dfsg/SCons/Platform/aix.py scons-4.4.0+dfsg/SCons/Platform/aix.py --- scons-4.0.1+dfsg/SCons/Platform/aix.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/aix.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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,14 +65,14 @@ or ('/' not in xlc and filename.endswith('/' + xlc)): xlcVersion = fileset.split()[1] xlcPath, sep, xlc = filename.rpartition('/') - pass - pass return (xlcPath, xlc, xlcVersion) def generate(env): posix.generate(env) #Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion env['MAXLINELENGTH'] = 21576 + env['SHLIBSUFFIX'] = '.a' + env['HOST_OS'] = 'aix' # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Platform/cygwin.py scons-4.4.0+dfsg/SCons/Platform/cygwin.py --- scons-4.0.1+dfsg/SCons/Platform/cygwin.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/cygwin.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -56,6 +52,7 @@ env['TEMPFILE'] = TempFileMunge env['TEMPFILEPREFIX'] = '@' env['MAXLINELENGTH'] = 2048 + env['HOST_OS'] = 'cygwin' # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Platform/darwin.py scons-4.4.0+dfsg/SCons/Platform/darwin.py --- scons-4.0.1+dfsg/SCons/Platform/darwin.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/darwin.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -38,6 +34,7 @@ def generate(env): posix.generate(env) env['SHLIBSUFFIX'] = '.dylib' + env['HOST_OS'] = 'darwin' # put macports paths at front to override Apple's versions, fink path is after # For now let people who want Macports or Fink tools specify it! # env['ENV']['PATH'] = '/opt/local/bin:/opt/local/sbin:' + env['ENV']['PATH'] + ':/sw/bin' @@ -48,7 +45,7 @@ # make sure this works on Macs with Tiger or earlier try: dirlist = os.listdir('/etc/paths.d') - except: + except FileNotFoundError: dirlist = [] for file in dirlist: diff -Nru scons-4.0.1+dfsg/SCons/Platform/hpux.py scons-4.4.0+dfsg/SCons/Platform/hpux.py --- scons-4.0.1+dfsg/SCons/Platform/hpux.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/hpux.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -39,6 +35,9 @@ #Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion env['MAXLINELENGTH'] = 2045000 + env['SHLIBSUFFIX'] = '.sl' + env['HOST_OS'] = 'hpux' + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/SCons/Platform/__init__.py scons-4.4.0+dfsg/SCons/Platform/__init__.py --- scons-4.0.1+dfsg/SCons/Platform/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -56,7 +53,7 @@ def platform_default(): - """Return the platform string for our execution environment. + r"""Return the platform string for our execution environment. The returned value should map to one of the SCons/Platform/\*.py files. Since scons is architecture independent, though, we don't @@ -86,7 +83,7 @@ return sys.platform -def platform_module(name = platform_default()): +def platform_module(name=platform_default()): """Return the imported module for the platform. This looks for a module name that matches the specified argument. @@ -94,27 +91,41 @@ our execution environment. """ full_name = 'SCons.Platform.' + name - if full_name not in sys.modules: - if os.name == 'java': - eval(full_name) - else: + try: + return sys.modules[full_name] + except KeyError: + try: + # the specific platform module is a relative import + mod = importlib.import_module("." + name, __name__) + except ModuleNotFoundError: try: - # the specific platform module is a relative import - mod = importlib.import_module("." + name, __name__) - except ImportError: - try: - import zipimport - importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] ) + # This support was added to enable running inside + # a py2exe bundle a long time ago - unclear if it's + # still needed. It is *not* intended to load individual + # platform modules stored in a zipfile. + import zipimport + + platform = sys.modules['SCons.Platform'].__path__[0] + importer = zipimport.zipimporter(platform) + if not hasattr(importer, 'find_spec'): + # zipimport only added find_spec, exec_module in 3.10, + # unlike importlib, where they've been around since 3.4. + # If we don't have 'em, use the old way. mod = importer.load_module(full_name) - except ImportError: - raise SCons.Errors.UserError("No platform named '%s'" % name) - setattr(SCons.Platform, name, mod) - return sys.modules[full_name] + else: + spec = importer.find_spec(full_name) + mod = importlib.util.module_from_spec(spec) + importer.exec_module(mod) + sys.modules[full_name] = mod + except zipimport.ZipImportError: + raise SCons.Errors.UserError("No platform named '%s'" % name) + + setattr(SCons.Platform, name, mod) + return mod def DefaultToolList(platform, env): - """Select a default tool list for the specified platform. - """ + """Select a default tool list for the specified platform.""" return SCons.Tool.tool_list(platform, env) @@ -133,7 +144,7 @@ class TempFileMunge: """Convert long command lines to use a temporary file. - You can set an Environment variable (usually `TEMPFILE`) to this, + You can set an Environment variable (usually ``TEMPFILE``) to this, then call it with a string argument, and it will perform temporary file substitution on it. This is used to circumvent limitations on the length of command lines. Example:: @@ -143,20 +154,42 @@ By default, the name of the temporary file used begins with a prefix of '@'. This may be configured for other tool chains by - setting the TEMPFILEPREFIX variable. Example:: + setting the ``TEMPFILEPREFIX`` variable. Example:: env["TEMPFILEPREFIX"] = '-@' # diab compiler env["TEMPFILEPREFIX"] = '-via' # arm tool chain env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint You can configure the extension of the temporary file through the - TEMPFILESUFFIX variable, which defaults to '.lnk' (see comments + ``TEMPFILESUFFIX`` variable, which defaults to '.lnk' (see comments in the code below). Example:: env["TEMPFILESUFFIX"] = '.lnt' # PC Lint Entries in the temporary file are separated by the value of the - TEMPFILEARGJOIN variable, which defaults to an OS-appropriate value. + ``TEMPFILEARGJOIN`` variable, which defaults to an OS-appropriate value. + + A default argument escape function is ``SCons.Subst.quote_spaces``. + If you need to apply extra operations on a command argument before + writing to a temporary file(fix Windows slashes, normalize paths, etc.), + please set `TEMPFILEARGESCFUNC` variable to a custom function. Example:: + + import sys + import re + from SCons.Subst import quote_spaces + + WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + + + def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if sys.platform != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + + + env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func """ def __init__(self, cmd, cmdstr = None): @@ -191,9 +224,20 @@ # 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 @@ -227,13 +271,18 @@ # Windows path names. rm = 'del' - prefix = env.subst('$TEMPFILEPREFIX') - if not prefix: + if 'TEMPFILEPREFIX' in env: + prefix = env.subst('$TEMPFILEPREFIX') + else: prefix = '@' - args = list(map(SCons.Subst.quote_spaces, cmd[1:])) - join_char = env.get('TEMPFILEARGJOIN',' ') - os.write(fd, bytearray(join_char.join(args) + "\n",'utf-8')) + tempfile_esc_func = env.get('TEMPFILEARGESCFUNC', SCons.Subst.quote_spaces) + args = [ + tempfile_esc_func(arg) + for arg in cmd[1:] + ] + join_char = env.get('TEMPFILEARGJOIN', ' ') + os.write(fd, bytearray(join_char.join(args) + "\n", 'utf-8')) os.close(fd) # XXX Using the SCons.Action.print_actions value directly @@ -260,14 +309,18 @@ 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): @@ -289,8 +342,8 @@ def Platform(name = platform_default()): - """Select a canned Platform specification. - """ + """Select a canned Platform specification.""" + module = platform_module(name) spec = PlatformSpec(name, module.generate) return spec diff -Nru scons-4.0.1+dfsg/SCons/Platform/__init__.xml scons-4.4.0+dfsg/SCons/Platform/__init__.xml --- scons-4.0.1+dfsg/SCons/Platform/__init__.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/__init__.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,277 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -A function that will be called to escape shell special characters in -command lines. The function should take one argument: the command line -string to escape; and should return the escaped command line. - - - - - - - -The prefix used for (static) library file names. -A default value is set for each platform -(posix, win32, os2, etc.), -but the value is overridden by individual tools -(ar, mslib, sgiar, sunar, tlib, etc.) -to reflect the names of the libraries they create. - - - - - - - -A list of all legal prefixes for library file names. -When searching for library dependencies, -SCons will look for files with these prefixes, -the base library name, -and suffixes in the &cv-LIBSUFFIXES; list. - - - - - - - -The suffix used for (static) library file names. -A default value is set for each platform -(posix, win32, os2, etc.), -but the value is overridden by individual tools -(ar, mslib, sgiar, sunar, tlib, etc.) -to reflect the names of the libraries they create. - - - - - - - -A list of all legal suffixes for library file names. -When searching for library dependencies, -SCons will look for files with prefixes, in the &cv-LIBPREFIXES; list, -the base library name, -and these suffixes. - - - - - - - -The prefix used for (static) object file names. - - - - - - - -The suffix used for (static) object file names. - - - - - - - -The name of the platform used to create the Environment. If no platform is -specified when the Environment is created, -&scons; -autodetects the platform. - - - -env = Environment(tools = []) -if env['PLATFORM'] == 'cygwin': - Tool('mingw')(env) -else: - Tool('msvc')(env) - - - - - - - - The name of the host operating system used to create the Environment. - If a platform is specified when creating the Environment, then - that Platform's logic will handle setting this value. - This value is immutable, and should not be changed by the user after - the Environment is initialized. - Currently only set for Win32. - - - - - - - - The name of the host hardware architecture used to create the Environment. - If a platform is specified when creating the Environment, then - that Platform's logic will handle setting this value. - This value is immutable, and should not be changed by the user after - the Environment is initialized. - Currently only set for Win32. - - - - - - - - The name of the target operating system for the compiled objects - created by this Environment. - This defaults to the value of HOST_OS, and the user can override it. - Currently only set for Win32. - - - - - - - - The name of the target hardware architecture for the compiled objects - created by this Environment. - This defaults to the value of HOST_ARCH, and the user can override it. - Currently only set for Win32. - - - - - - - - -The prefix used for executable file names. - - - - - - - -The suffix used for executable file names. - - - - - - - -A string naming the shell program that will be passed to the -&cv-SPAWN; -function. -See the -&cv-SPAWN; -construction variable for more information. - - - - - - - -The prefix used for shared library file names. - - - - - - - -The suffix used for shared library file names. - - - - - - - -The prefix used for shared object file names. - - - - - - - -The suffix used for shared object file names. - - - - - - - -The prefix for a temporary file used -to store lines lines longer than $MAXLINELENGTH -as operations which call out to a shell will fail -if the line is too long, which particularly -impacts linking. -The default is '@', which works for the Microsoft -and GNU toolchains on Windows. -Set this appropriately for other toolchains, -for example '-@' for the diab compiler -or '-via' for ARM toolchain. - - - - - - - -The suffix used for the temporary file name -used for long command lines. The name should -include the dot ('.') if one is wanted as -it will not be added automatically. -The default is '.lnk'. - - - - - - - -The string (or character) to be used to join the arguments passed to TEMPFILE when command line exceeds the limit set by &cv-MAXLINELENGTH;. -The default value is a space. However for MSVC, MSLINK the default is a line seperator characters as defined by os.linesep. -Note this value is used literally and not expanded by the subst logic. - - - - - - - -The directory to create the tempfile in. - - - - diff -Nru scons-4.0.1+dfsg/SCons/Platform/irix.py scons-4.4.0+dfsg/SCons/Platform/irix.py --- scons-4.0.1+dfsg/SCons/Platform/irix.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/irix.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,14 +20,19 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__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 def generate(env): posix.generate(env) + env['HOST_OS'] = 'irix' # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Platform/mingw.py scons-4.4.0+dfsg/SCons/Platform/mingw.py --- scons-4.0.1+dfsg/SCons/Platform/mingw.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/mingw.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ MINGW_DEFAULT_PATHS = [ r'C:\msys64', r'C:\msys' - ] \ No newline at end of file + ] diff -Nru scons-4.0.1+dfsg/SCons/Platform/os2.py scons-4.4.0+dfsg/SCons/Platform/os2.py --- scons-4.0.1+dfsg/SCons/Platform/os2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/os2.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 -Nru scons-4.0.1+dfsg/SCons/Platform/PlatformTests.py scons-4.4.0+dfsg/SCons/Platform/PlatformTests.py --- scons-4.0.1+dfsg/SCons/Platform/PlatformTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/PlatformTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -53,6 +50,8 @@ assert env['PROGSUFFIX'] == '.exe', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'cygwin', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('os2') assert str(p) == 'os2', p @@ -60,6 +59,8 @@ p(env) assert env['PROGSUFFIX'] == '.exe', env assert env['LIBSUFFIX'] == '.lib', env + assert env['HOST_OS'] == 'os2', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('posix') assert str(p) == 'posix', p @@ -68,6 +69,8 @@ assert env['PROGSUFFIX'] == '', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'posix', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('irix') assert str(p) == 'irix', p @@ -76,6 +79,8 @@ assert env['PROGSUFFIX'] == '', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'irix', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('aix') assert str(p) == 'aix', p @@ -84,6 +89,8 @@ assert env['PROGSUFFIX'] == '', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'aix', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('sunos') assert str(p) == 'sunos', p @@ -92,6 +99,8 @@ assert env['PROGSUFFIX'] == '', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'sunos', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('hpux') assert str(p) == 'hpux', p @@ -100,6 +109,8 @@ assert env['PROGSUFFIX'] == '', env assert env['LIBSUFFIX'] == '.a', env assert env['SHELL'] == 'sh', env + assert env['HOST_OS'] == 'hpux', env + assert env['HOST_ARCH'] != '', env p = SCons.Platform.Platform('win32') assert str(p) == 'win32', p @@ -107,19 +118,46 @@ p(env) assert env['PROGSUFFIX'] == '.exe', env assert env['LIBSUFFIX'] == '.lib', env - assert str + assert env['HOST_OS'] == 'win32', env + assert env['HOST_ARCH'] != '', env + 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) assert env != {}, env + def test_win32_no_arch_shell_variables(self): + """ + Test that a usable HOST_ARCH is available when + neither: PROCESSOR_ARCHITEW6432 nor PROCESSOR_ARCHITECTURE + is set for SCons.Platform.win32.get_architecture() + """ + + # Save values if defined + PA_6432 = os.environ.get('PROCESSOR_ARCHITEW6432') + PA = os.environ.get('PROCESSOR_ARCHITECTURE') + if PA_6432: + del(os.environ['PROCESSOR_ARCHITEW6432']) + if PA: + del(os.environ['PROCESSOR_ARCHITECTURE']) + + p = SCons.Platform.win32.get_architecture() + + # restore values + if PA_6432: + os.environ['PROCESSOR_ARCHITEW6432']=PA_6432 + if PA: + os.environ['PROCESSOR_ARCHITECTURE']=PA + + assert p.arch != '', 'SCons.Platform.win32.get_architecture() not setting arch' + assert p.synonyms != '', 'SCons.Platform.win32.get_architecture() not setting synonyms' + class TempFileMungeTestCase(unittest.TestCase): def test_MAXLINELENGTH(self): @@ -159,7 +197,7 @@ assert cmd != defined_cmd, cmd def test_TEMPFILEARGJOINBYTE(self): - """ + """ Test argument join byte TEMPFILEARGJOINBYTE """ @@ -193,14 +231,45 @@ SCons.Action.print_actions = old_actions assert file_content != env['TEMPFILEARGJOINBYTE'].join(['test','command','line']) + def test_TEMPFILEARGESCFUNC(self): + """ + Test a custom TEMPFILEARGESCFUNC + """ + + def _tempfile_arg_esc_func(arg): + return str(arg).replace("line", "newarg") + + defined_cmd = "a $VERY $OVERSIMPLIFIED line" + t = SCons.Platform.TempFileMunge(defined_cmd) + env = SCons.Environment.SubstitutionEnvironment(tools=[]) + # Setting the line length high enough... + env['MAXLINELENGTH'] = 5 + env['VERY'] = 'test' + env['OVERSIMPLIFIED'] = 'command' + + # For tempfilemunge to operate. + old_actions = SCons.Action.print_actions + SCons.Action.print_actions = 0 + env['TEMPFILEARGESCFUNC'] = _tempfile_arg_esc_func + cmd = t(None, None, env, 0) + # print("CMD is: %s"%cmd) + + with open(cmd[-1], 'rb') as f: + file_content = f.read() + # print("Content is:[%s]"%file_content) + # # ...and restoring its setting. + SCons.Action.print_actions = old_actions + assert b"newarg" in file_content 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 +289,14 @@ 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 -Nru scons-4.0.1+dfsg/SCons/Platform/Platform.xml scons-4.4.0+dfsg/SCons/Platform/Platform.xml --- scons-4.0.1+dfsg/SCons/Platform/Platform.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/Platform.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,400 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +A function that will be called to escape shell special characters in +command lines. The function should take one argument: the command line +string to escape; and should return the escaped command line. + + + + + + + +The prefix used for (static) library file names. +A default value is set for each platform +(posix, win32, os2, etc.), +but the value is overridden by individual tools +(ar, mslib, sgiar, sunar, tlib, etc.) +to reflect the names of the libraries they create. + + + + + + + +A list of all legal prefixes for library file names. +When searching for library dependencies, +SCons will look for files with these prefixes, +the base library name, +and suffixes from the &cv-link-LIBSUFFIXES; list. + + + + + + + +The suffix used for (static) library file names. +A default value is set for each platform +(posix, win32, os2, etc.), +but the value is overridden by individual tools +(ar, mslib, sgiar, sunar, tlib, etc.) +to reflect the names of the libraries they create. + + + + + + + +A list of all legal suffixes for library file names. +When searching for library dependencies, +SCons will look for files with prefixes from the &cv-link-LIBPREFIXES; list, +the base library name, +and these suffixes. + + + + + + + +The prefix used for (static) object file names. + + + + + + + +The suffix used for (static) object file names. + + + + + + + + The name of the platform used to create this &consenv;. + &SCons; sets this when initializing the platform, + which by default is auto-detected + (see the platform + argument to &f-link-Environment;). + + + +env = Environment(tools=[]) +if env['PLATFORM'] == 'cygwin': + Tool('mingw')(env) +else: + Tool('msvc')(env) + + + + + + + + The name of the host operating system for the platform + used to create this &consenv;. + The platform code sets this when initializing + (see &cv-link-PLATFORM; and the + platform argument to &f-link-Environment;). + + + Should be considered immutable. + &cv-HOST_OS; is not currently used by &SCons;, + but the option is reserved to do so in future + + + + + + + + The name of the operating system that objects + created using this &consenv; should target. + Can be set when creating a &consenv; by passing as a keyword + argument in the &f-link-Environment; call;. + + + &cv-TARGET_OS; is not currently used by &SCons; + but the option is reserved to do so in future + + + + + + + + The name of the host hardware architecture + used to create this &consenv;. + The platform code sets this when initializing + (see &cv-link-PLATFORM; and the + platform argument to &f-link-Environment;). + Note the detected name of the architecture may not be identical to + that returned by the &Python; + platform.machine method. + + + On the win32 platform, + if the Microsoft Visual C++ compiler is available, + &t-link-msvc; tool setup is done using + &cv-HOST_ARCH; and &cv-link-TARGET_ARCH;. + Changing the values at any later time will not cause + the tool to be reinitialized. + Valid host arch values are + x86 and arm + for 32-bit hosts and + amd64 and x86_64 + for 64-bit hosts. + + + Should be considered immutable. + &cv-HOST_ARCH; is not currently used by other platforms, + but the option is reserved to do so in future + + + + + + + + The name of the hardware architecture that objects + created using this &consenv; should target. + Can be set when creating a &consenv; by passing as a keyword + argument in the &f-link-Environment; call. + + + On the win32 platform, + if the Microsoft Visual C++ compiler is available, + &t-link-msvc; tool setup is done using + &cv-link-HOST_ARCH; and &cv-TARGET_ARCH;. + If a value is not specified, + will be set to the same value as &cv-link-HOST_ARCH;. + Changing the value after the environment is initialized + will not cause the tool to be reinitialized. + Compiled objects will be in the target architecture if + the compilation system supports generating for that target. + The latest compiler which can fulfill the requirement will + be selected, unless a different version is directed by the + value of the &cv-link-MSVC_VERSION; &consvar;. + + + On the win32/msvc combination, valid target arch values are + x86, + arm, + i386 + for 32-bit targets and + amd64, + arm64, + x86_64 + and ia64 (Itanium) + for 64-bit targets. + For example, if you want to compile 64-bit binaries, you would set + TARGET_ARCH='x86_64' when creating the &consenv;. + Note that not all target architectures are + supported for all Visual Studio / MSVC versions. + Check the relevant Microsoft documentation. + + + &cv-TARGET_ARCH; is not currently used by other compilation tools, + but the option is reserved to do so in future + + + + + + + +The prefix used for executable file names. + + + + + + + +The suffix used for executable file names. + + + + + + + +A string naming the shell program that will be passed to the +&cv-SPAWN; +function. +See the +&cv-SPAWN; +construction variable for more information. + + + + + + + +The prefix used for shared library file names. + + + + + + + +The suffix used for shared library file names. + + + + + + + +The prefix used for shared object file names. + + + + + + + +The suffix used for shared object file names. + + + + + + + +A callable object used to handle overly long command line strings, +since operations which call out to a shell will fail +if the line is longer than the shell can accept. +This tends to particularly impact linking. +The tempfile object stores the command line in a temporary +file in the appropriate format, and returns +an alternate command line so the invoked tool will make +use of the contents of the temporary file. +If you need to replace the default tempfile object, +the callable should take into account the settings of +&cv-link-MAXLINELENGTH;, +&cv-link-TEMPFILEPREFIX;, +&cv-link-TEMPFILESUFFIX;, +&cv-link-TEMPFILEARGJOIN;, +&cv-link-TEMPFILEDIR; +and +&cv-link-TEMPFILEARGESCFUNC;. + + + + + + + +The prefix for the name of the temporary file used +to store command lines exceeding &cv-link-MAXLINELENGTH;. +The default prefix is '@', which works for the Microsoft +and GNU toolchains on Windows. +Set this appropriately for other toolchains, +for example '-@' for the diab compiler +or '-via' for ARM toolchain. + + + + + + + +The suffix for the name of the temporary file used +to store command lines exceeding &cv-link-MAXLINELENGTH;. +The suffix should include the dot ('.') if one is wanted as +it will not be added automatically. +The default is .lnk. + + + + + + + +The string to use to join the arguments passed to +&cv-link-TEMPFILE; when the command line exceeds the limit set by +&cv-link-MAXLINELENGTH;. +The default value is a space. +However for MSVC, MSLINK the default is a line separator +as defined by os.linesep. +Note this value is used literally and not expanded by the subst logic. + + + + + + + +The directory to create the long-lines temporary file in. + + + + + + + +The default argument escape function is +SCons.Subst.quote_spaces. +If you need to apply extra operations on a command argument +(to fix Windows slashes, normalize paths, etc.) +before writing to the temporary file, +you can set the &cv-TEMPFILEARGESCFUNC; variable to a custom function. +Such a function takes a single string argument and returns +a new string with any modifications applied. +Example: + + + +import sys +import re +from SCons.Subst import quote_spaces + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if sys.platform != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + +env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Platform/posix.py scons-4.4.0+dfsg/SCons/Platform/posix.py --- scons-4.0.1+dfsg/SCons/Platform/posix.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/posix.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,18 +20,17 @@ # 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 platform import subprocess -import sys -import select -import SCons.Util from SCons.Platform import TempFileMunge from SCons.Platform.virtualenv import ImportVirtualenv from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv @@ -91,7 +82,7 @@ if 'ENV' not in env: env['ENV'] = {} - env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin' + env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin:/snap/bin' env['OBJPREFIX'] = '' env['OBJSUFFIX'] = '.o' env['SHOBJPREFIX'] = '$OBJPREFIX' @@ -104,6 +95,8 @@ env['SHLIBSUFFIX'] = '.so' env['LIBPREFIXES'] = [ '$LIBPREFIX' ] env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ] + env['HOST_OS'] = 'posix' + env['HOST_ARCH'] = platform.machine() env['PSPAWN'] = pspawn env['SPAWN'] = spawn env['SHELL'] = 'sh' diff -Nru scons-4.0.1+dfsg/SCons/Platform/posix.xml scons-4.4.0+dfsg/SCons/Platform/posix.xml --- scons-4.0.1+dfsg/SCons/Platform/posix.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Platform/posix.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -(variable) - - - -Returns a function -(actually a callable Python object) -intended to be used as the -path_function -of a Scanner object. -The returned object will look up the specified -variable -in a construction environment -and treat the construction variable's value as a list of -directory paths that should be searched -(like -&cv-link-CPPPATH;, -&cv-link-LIBPATH;, -etc.). - - - -Note that use of -&f-FindPathDirs; -is generally preferable to -writing your own -path_function -for the following reasons: -1) The returned list will contain all appropriate directories -found in source trees -(when -&f-link-VariantDir; -is used) -or in code repositories -(when -&f-Repository; -or the - -option are used). -2) scons will identify expansions of -variable -that evaluate to the same list of directories as, -in fact, the same list, -and avoid re-scanning the directories for files, -when possible. - - - -Example: - - - -def my_scan(node, env, path, arg): - # Code to scan file contents goes here... - return include_files - -scanner = Scanner(name = 'myscanner', - function = my_scan, - path_function = FindPathDirs('MYPATH')) - - - - - diff -Nru scons-4.0.1+dfsg/SCons/Scanner/Java.py scons-4.4.0+dfsg/SCons/Scanner/Java.py --- scons-4.0.1+dfsg/SCons/Scanner/Java.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/Java.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,99 @@ +# 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 os + +import SCons.Node +import SCons.Node.FS +import SCons.Scanner +import SCons.Util + + +def _subst_libs(env, libs): + """ + Substitute environment variables and split into list. + """ + if SCons.Util.is_String(libs): + libs = env.subst(libs) + if SCons.Util.is_String(libs): + libs = libs.split() + elif SCons.Util.is_Sequence(libs): + _libs = [] + for lib in libs: + _libs += _subst_libs(env, lib) + libs = _libs + else: + # libs is an object (Node, for example) + libs = [libs] + return libs + + +def _collect_classes(list, dirname, files): + for fname in files: + if os.path.splitext(fname)[1] == ".class": + list.append(os.path.join(str(dirname), fname)) + + +def scan(node, env, libpath=()): + """Scan for files on the JAVACLASSPATH. + + The classpath can contain: + - Explicit paths to JAR/Zip files + - Wildcards (*) + - Directories which contain classes in an unnamed package + - Parent directories of the root package for classes in a named package + + Class path entries that are neither directories nor archives (.zip or JAR files) nor the asterisk (*) wildcard character are ignored. + """ + classpath = env.get('JAVACLASSPATH', []) + classpath = _subst_libs(env, classpath) + + result = [] + for path in classpath: + if SCons.Util.is_String(path) and "*" in path: + libs = env.Glob(path) + else: + libs = [path] + + for lib in libs: + if os.path.isdir(str(lib)): + # grab the in-memory nodes + env.Dir(lib).walk(_collect_classes, result) + # now the on-disk ones + for root, dirs, files in os.walk(str(lib)): + _collect_classes(result, root, files) + else: + result.append(lib) + + return list(filter(lambda x: os.path.splitext(str(x))[1] in [".class", ".zip", ".jar"], result)) + + +def JavaScanner(): + return SCons.Scanner.Base(scan, 'JavaScanner', + skeys=['.java']) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/SCons/Scanner/JavaTests.py scons-4.4.0+dfsg/SCons/Scanner/JavaTests.py --- scons-4.0.1+dfsg/SCons/Scanner/JavaTests.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/JavaTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,160 @@ +# 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 +import collections +import os + +import TestCmd + +import SCons.Scanner.Java +import SCons.Node.FS +import SCons.Warnings + + +test = TestCmd.TestCmd(workdir = '') +test.subdir('com') + +files = [ + 'bootclasspath.jar', + 'classpath.jar', + 'Test.class', + 'com/Test.class' +] + +for fname in files: + test.write(fname, "\n") + + +class DummyEnvironment(collections.UserDict): + def __init__(self,**kw): + collections.UserDict.__init__(self) + self.data.update(kw) + self.fs = SCons.Node.FS.FS(test.workpath('')) + self['ENV'] = {} + + def Dictionary(self, *args): + return self.data + + def subst(self, strSubst, target=None, source=None, conv=None): + if strSubst[0] == '$': + return self.data[strSubst[1:]] + return strSubst + + def subst_path(self, path, target=None, source=None, conv=None): + if not isinstance(path, list): + path = [path] + return list(map(self.subst, path)) + + def has_key(self, key): + return key in self.Dictionary() + + def get_calculator(self): + return None + + def get_factory(self, factory): + return factory or self.fs.File + + def Dir(self, filename): + return self.fs.Dir(filename) + + def File(self, filename): + return self.fs.File(filename) + + def Glob(self, path): + return self.fs.Glob(path) + + +class DummyNode: + def __init__(self, name): + self.name = name + + def rexists(self): + return 1 + + def __str__(self): + return self.name + + +global my_normpath +my_normpath = os.path.normpath + +if os.path.normcase('foo') == os.path.normcase('FOO'): + my_normpath = os.path.normcase + +def deps_match(self, deps, headers): + scanned = sorted(map(my_normpath, list(map(str, deps)))) + expect = sorted(map(my_normpath, headers)) + self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned)) + + +class JavaScannerEmptyClasspath(unittest.TestCase): + def runTest(self): + path = [] + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=path) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = [] + deps_match(self, deps, expected) + + +class JavaScannerClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath('classpath.jar')]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['classpath.jar'] + deps_match(self, deps, expected) + + +class JavaScannerWildcardClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath('*')]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['bootclasspath.jar', 'classpath.jar', 'Test.class'] + deps_match(self, deps, expected) + + +class JavaScannerDirClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath()]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['Test.class', 'com/Test.class'] + deps_match(self, deps, expected) + + + +if __name__ == "__main__": + unittest.main() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/SCons/Scanner/LaTeX.py scons-4.4.0+dfsg/SCons/Scanner/LaTeX.py --- scons-4.0.1+dfsg/SCons/Scanner/LaTeX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/LaTeX.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,15 +20,16 @@ # 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 -import SCons.Scanner +import SCons.Node.FS import SCons.Util +import SCons.Warnings +from . import ScannerBase, FindPathDirs # list of graphics file extensions for TeX and LaTeX TexGraphics = ['.eps', '.ps'] @@ -84,6 +80,7 @@ """ def __init__(self, variable): self.variable = variable + def __call__(self, env, dir=None, target=None, source=None, argument=None): import SCons.PathList try: @@ -96,7 +93,6 @@ return tuple(dir.Rfindalldirs(path)) - def LaTeXScanner(): """ Return a prototype Scanner instance for scanning LaTeX source files @@ -109,6 +105,7 @@ recursive = 0) return ds + def PDFLaTeXScanner(): """ Return a prototype Scanner instance for scanning LaTeX source files @@ -121,9 +118,9 @@ recursive = 0) return ds -class LaTeX(SCons.Scanner.Base): - """ - Class for scanning LaTeX files for included files. + +class LaTeX(ScannerBase): + """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 @@ -178,7 +175,7 @@ 'includefrom', 'subincludefrom', 'inputfrom', 'subinputfrom'] - def __init__(self, name, suffixes, graphics_extensions, *args, **kw): + def __init__(self, name, suffixes, graphics_extensions, *args, **kwargs): regex = r''' \\( include @@ -225,8 +222,7 @@ def __init__(self, dictionary): self.dictionary = {} for k,n in dictionary.items(): - self.dictionary[k] = ( SCons.Scanner.FindPathDirs(n), - FindENVPathDirs(n) ) + self.dictionary[k] = (FindPathDirs(n), FindENVPathDirs(n)) def __call__(self, env, dir=None, target=None, source=None, argument=None): @@ -240,25 +236,28 @@ return tuple(di.items()) class LaTeXScanCheck: - """Skip all but LaTeX source files, i.e., do not scan *.eps, - *.pdf, *.jpg, etc. + """Skip all but LaTeX source files. + + Do not scan *.eps, *.pdf, *.jpg, etc. """ + def __init__(self, suffixes): self.suffixes = suffixes + def __call__(self, node, env): current = not node.has_builder() or node.is_up_to_date() scannable = node.get_suffix() in env.subst_list(self.suffixes)[0] # Returning false means that the file is not scanned. return scannable and current - kw['function'] = _scan - kw['path_function'] = FindMultiPathDirs(LaTeX.keyword_paths) - kw['recursive'] = 0 - kw['skeys'] = suffixes - kw['scan_check'] = LaTeXScanCheck(suffixes) - kw['name'] = name + kwargs['function'] = _scan + kwargs['path_function'] = FindMultiPathDirs(LaTeX.keyword_paths) + kwargs['recursive'] = 0 + kwargs['skeys'] = suffixes + kwargs['scan_check'] = LaTeXScanCheck(suffixes) + kwargs['name'] = name - SCons.Scanner.Base.__init__(self, *args, **kw) + super().__init__(*args, **kwargs) def _latex_names(self, include_type, filename): if include_type == 'input': @@ -399,10 +398,10 @@ inc_type, inc_subdir, inc_filename = include try: - if seen[inc_filename] == 1: + if seen[inc_filename]: continue except KeyError: - seen[inc_filename] = 1 + seen[inc_filename] = True # # Handle multiple filenames in include[1] @@ -412,13 +411,16 @@ # Do not bother with 'usepackage' warnings, as they most # likely refer to system-level files if inc_type != 'usepackage': - SCons.Warnings.warn(SCons.Warnings.DependencyWarning, - "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) + SCons.Warnings.warn( + SCons.Warnings.DependencyWarning, + "No dependency generated for file: %s " + "(included from: %s) -- file not found" % (i, node), + ) else: sortkey = self.sort_key(n) nodes.append((sortkey, n)) # recurse down - queue.extend( self.scan(n, inc_subdir) ) + queue.extend(self.scan(n, inc_subdir)) return [pair[1] for pair in sorted(nodes)] diff -Nru scons-4.0.1+dfsg/SCons/Scanner/LaTeXTests.py scons-4.4.0+dfsg/SCons/Scanner/LaTeXTests.py --- scons-4.0.1+dfsg/SCons/Scanner/LaTeXTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/LaTeXTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -86,7 +82,7 @@ # copied from CTest.py class DummyEnvironment(collections.UserDict): def __init__(self, **kw): - collections.UserDict.__init__(self) + super().__init__() self.data.update(kw) self.fs = SCons.Node.FS.FS(test.workpath('')) diff -Nru scons-4.0.1+dfsg/SCons/Scanner/Prog.py scons-4.4.0+dfsg/SCons/Scanner/Prog.py --- scons-4.0.1+dfsg/SCons/Scanner/Prog.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/Prog.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,29 +20,26 @@ # 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 -import SCons.Scanner import SCons.Util +from . import ScannerBase, FindPathDirs # global, set by --debug=findlibs print_find_libs = None -def ProgramScanner(**kw): +def ProgramScanner(**kwargs): """Return a prototype Scanner instance for scanning executable files for static-lib dependencies""" - kw['path_function'] = SCons.Scanner.FindPathDirs('LIBPATH') - ps = SCons.Scanner.Base(scan, "ProgramScanner", **kw) + kwargs['path_function'] = FindPathDirs('LIBPATH') + ps = ScannerBase(scan, "ProgramScanner", **kwargs) 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 @@ 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 -Nru scons-4.0.1+dfsg/SCons/Scanner/ProgTests.py scons-4.4.0+dfsg/SCons/Scanner/ProgTests.py --- scons-4.0.1+dfsg/SCons/Scanner/ProgTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/ProgTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -60,7 +57,7 @@ else: return [self._dict[x] for x in args] - def has_key(self, key): + def __contains__(self, key): return key in self.Dictionary() def __getitem__(self,key): diff -Nru scons-4.0.1+dfsg/SCons/Scanner/Python.py scons-4.4.0+dfsg/SCons/Scanner/Python.py --- scons-4.0.1+dfsg/SCons/Scanner/Python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/Python.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,14 +20,25 @@ # 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 import re -import SCons.Scanner + +import SCons.Node.FS +import SCons.Util +from . import ScannerBase # Capture python "from a import b" and "import a" statements. from_cre = re.compile(r'^\s*from\s+([^\s]+)\s+import\s+(.*)', re.M) @@ -55,8 +54,7 @@ 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) @@ -87,6 +85,40 @@ return all_matches +def find_import(import_path, search_paths): + """ + Finds the specified import in the various search paths. + For an import of "p", it could either result in a file named p.py or + p/__init__.py. We can't do two consecutive searches for p then p.py + because the first search could return a result that is lower in the + search_paths precedence order. As a result, it is safest to iterate over + search_paths and check whether p or p.py exists in each path. This allows + us to cleanly respect the precedence order. + + If the import is found, returns a tuple containing: + 1. Discovered dependency node (e.g. p/__init__.py or p.py) + 2. True if the import was a package, False if the import was a module. + 3. The Dir node in search_paths that the import is relative to. + If the import is not found, returns a tuple containing (None, False, None). + Callers should check for failure by checking whether the first entry in the + tuple is not None. + """ + for search_path in search_paths: + paths = [search_path] + # Note: if the same import is present as a package and a module, Python + # prefers the package. As a result, we always look for x/__init__.py + # before looking for x.py. + node = SCons.Node.FS.find_file(import_path + '/__init__.py', paths) + if node: + return node, True, search_path + else: + node = SCons.Node.FS.find_file(import_path + '.py', paths) + if node: + return node, False, search_path + + return None, False, None + + def scan(node, env, path=()): # cache the includes list in node so we only scan it once: if node.includes is not None: @@ -97,10 +129,10 @@ # if the same header is included many times. node.includes = list(map(SCons.Util.silent_intern, includes)) - # XXX TODO: Sort? nodes = [] if callable(path): path = path() + for module, imports in includes: is_relative = module.startswith('.') if is_relative: @@ -113,56 +145,69 @@ for i in itertools.repeat(None, num_parents): current_dir = current_dir.up() - search_paths = [current_dir.abspath] + search_paths = [current_dir] search_string = module_lstripped else: - search_paths = path + search_paths = [env.Dir(p) for p in path] search_string = module - module_components = search_string.split('.') - for search_path in search_paths: - candidate_path = os.path.join(search_path, *module_components) - # The import stored in "module" could refer to a directory or file. - import_dirs = [] - if os.path.isdir(candidate_path): - import_dirs = module_components - - # Because this resolved to a directory, there is a chance that - # additional imports (e.g. from module import A, B) could refer - # to files to import. - if imports: - for imp in imports: - file = os.path.join(candidate_path, imp + '.py') - if os.path.isfile(file): - nodes.append(file) - elif os.path.isfile(candidate_path + '.py'): - nodes.append(candidate_path + '.py') - import_dirs = module_components[:-1] - - # We can ignore imports because this resolved to a file. Any - # additional imports (e.g. from module.file import A, B) would - # only refer to functions in this file. - - # Take a dependency on all __init__.py files from all imported - # packages unless it's a relative import. If it's a relative - # import, we don't need to take the dependency because Python - # requires that all referenced packages have already been imported, - # which means that the dependency has already been established. - if import_dirs and not is_relative: - for i in range(len(import_dirs)): - init_components = module_components[:i+1] + ['__init__.py'] - init_path = os.path.join(search_path, *(init_components)) - if os.path.isfile(init_path): - nodes.append(init_path) - break + # If there are no paths, there is no point in parsing includes for this + # iteration of the loop. + if not search_paths: + continue + + module_components = [x for x in search_string.split('.') if x] + package_dir = None + hit_dir = None + if not module_components: + # This is just a "from . import x". + package_dir = search_paths[0] + else: + # Translate something like "import x.y" to a call to find_import + # with 'x/y' as the path. find_import will then determine whether + # we can find 'x/y/__init__.py' or 'x/y.py'. + import_node, is_dir, hit_dir = find_import( + '/'.join(module_components), search_paths) + if import_node: + nodes.append(import_node) + if is_dir: + package_dir = import_node.dir + + # If the statement was something like "from x import y, z", whether we + # iterate over imports depends on whether x was a package or module. + # If it was a module, y and z are just functions so we don't need to + # search for them. If it was a package, y and z are either packages or + # modules and we do need to search for them. + if package_dir and imports: + for i in imports: + import_node, _, _ = find_import(i, [package_dir]) + if import_node: + nodes.append(import_node) + + # Take a dependency on all __init__.py files from all imported + # packages unless it's a relative import. If it's a relative + # import, we don't need to take the dependency because Python + # requires that all referenced packages have already been imported, + # which means that the dependency has already been established. + if hit_dir and not is_relative: + import_dirs = module_components + for i in range(len(import_dirs)): + init_path = '/'.join(import_dirs[:i+1] + ['__init__.py']) + init_node = SCons.Node.FS.find_file(init_path, [hit_dir]) + if init_node and init_node not in nodes: + nodes.append(init_node) return sorted(nodes) PythonSuffixes = ['.py'] -PythonScanner = SCons.Scanner.Base(scan, name='PythonScanner', - skeys=PythonSuffixes, - path_function=path_function, recursive=1) +PythonScanner = ScannerBase( + scan, + name='PythonScanner', + skeys=PythonSuffixes, + path_function=path_function, + recursive=True, +) # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Scanner/PythonTests.py scons-4.4.0+dfsg/SCons/Scanner/PythonTests.py --- scons-4.0.1+dfsg/SCons/Scanner/PythonTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/PythonTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,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. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +""" +Unit tests for the Python scanner. These tests validate proper working of the +Python scanner by confirming that the results of the scan match expectations. + +The absolute path tests have strongly-defined behavior in that there is no real +ambiguity to what they should result in. For example, if you import package x, +you expect to get x/__init__.py as a dependency. + +The relative path tests that reach into ancestor directories do have some +ambiguity in whether to depend upon __init__.py in those referenced ancestor +directories. Python only allows these kinds of relative imports if the file is +part of a package, in which case those ancestor directories' __init__.py files +have already been imported. +""" import SCons.compat @@ -53,9 +66,9 @@ # Copied from LaTeXTests.py. class DummyEnvironment(collections.UserDict): - def __init__(self, **kw): - collections.UserDict.__init__(self) - self.data.update(kw) + def __init__(self, **kwargs): + super().__init__() + self.data.update(kwargs) self.fs = SCons.Node.FS.FS(test.workpath('')) self['ENV'] = {} @@ -228,9 +241,6 @@ 'nested1/nested2/nested3/imports_grandparent_module.py') path = s.path(env, source=[node]) deps = s(node, env, path) - # Note: there is some ambiguity here in what the scanner should return. - # Relative imports require that the referenced packages have already - # been imported. files = ['nested1/module.py'] deps_match(self, deps, files) @@ -255,7 +265,59 @@ 'nested1/nested2/nested3/imports_parent_then_submodule.py') path = s.path(env, source=[node]) deps = s(node, env, path) - files = ['nested1/nested2a/module.py'] + files = ['nested1/nested2a/__init__.py', 'nested1/nested2a/module.py'] + deps_match(self, deps, files) + + +class PythonScannerTestImportsModuleWithFunc(unittest.TestCase): + def runTest(self): + """ + This test case tests the following import statement: + `from simple_package.module1 import somefunc` with somefunc.py existing + in the same folder as module1.py. It validates that the scanner doesn't + accidentally take a dependency somefunc.py. + """ + env = DummyEnvironment() + s = SCons.Scanner.Python.PythonScanner + env['ENV']['PYTHONPATH'] = test.workpath('') + deps = s(env.File('from_import_simple_package_module1_func.py'), env, + lambda : s.path(env)) + files = ['simple_package/__init__.py', 'simple_package/module1.py'] + deps_match(self, deps, files) + + +class PythonScannerTestFromNested1ImportNested2(unittest.TestCase): + def runTest(self): + """ + This test case tests the following import statement: + `from nested1 import module, nested2`. In this test, module is a Python + module and nested2 is a package. Validates that the scanner can handle + such mixed imports. + """ + env = DummyEnvironment() + s = SCons.Scanner.Python.PythonScanner + env['ENV']['PYTHONPATH'] = test.workpath('') + deps = s(env.File('from_nested1_import_multiple.py'), env, + lambda : s.path(env)) + files = ['nested1/__init__.py', 'nested1/module.py', + 'nested1/nested2/__init__.py'] + deps_match(self, deps, files) + + +class PythonScannerTestImportUnknownFiles(unittest.TestCase): + def runTest(self): + """ + This test case tests importing files that are not found. If Python + really can't find those files, it will fail. But this is intended to + test the various failure paths in the scanner to make sure that they + don't raise exceptions. + """ + env = DummyEnvironment() + s = SCons.Scanner.Python.PythonScanner + env['ENV']['PYTHONPATH'] = test.workpath('') + deps = s(env.File('imports_unknown_files.py'), env, + lambda : s.path(env)) + files = [] deps_match(self, deps, files) diff -Nru scons-4.0.1+dfsg/SCons/Scanner/RC.py scons-4.4.0+dfsg/SCons/Scanner/RC.py --- scons-4.0.1+dfsg/SCons/Scanner/RC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/RC.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 +from . import ClassicCPP 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 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 = ClassicCPP( + "ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re, recursive=no_tlb + ) + return resScanner # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/Scanner/RCTests.py scons-4.4.0+dfsg/SCons/Scanner/RCTests.py --- scons-4.0.1+dfsg/SCons/Scanner/RCTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/RCTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -74,9 +71,9 @@ # define some helpers: class DummyEnvironment(collections.UserDict): - def __init__(self,**kw): - collections.UserDict.__init__(self) - self.data.update(kw) + def __init__(self, **kwargs): + super().__init__() + self.data.update(kwargs) self.fs = SCons.Node.FS.FS(test.workpath('')) def Dictionary(self, *args): @@ -92,8 +89,8 @@ path = [path] return list(map(self.subst, path)) - def has_key(self, key): - return key in self.Dictionary() + def __contains__(self, key): + return key in self.data def get_calculator(self): return None @@ -158,13 +155,6 @@ 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 -Nru scons-4.0.1+dfsg/SCons/Scanner/ScannerTests.py scons-4.4.0+dfsg/SCons/Scanner/ScannerTests.py --- scons-4.0.1+dfsg/SCons/Scanner/ScannerTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/ScannerTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,26 +21,23 @@ # 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 +from SCons.Scanner import ScannerBase, Selector, Classic, ClassicCPP, Current, FindPathDirs class DummyFS: def File(self, name): return DummyNode(name) class DummyEnvironment(collections.UserDict): - def __init__(self, dict=None, **kw): - collections.UserDict.__init__(self, dict) - self.data.update(kw) + def __init__(self, mapping=None, **kwargs): + super().__init__(mapping) + self.data.update(kwargs) self.fs = DummyFS() def subst(self, strSubst, target=None, source=None, conv=None): if strSubst[0] == '$': @@ -60,12 +58,25 @@ def __init__(self, name, search_result=()): self.name = name self.search_result = tuple(search_result) + def rexists(self): - return 1 + return True + def __str__(self): return self.name + def Rfindalldirs(self, pathlist): return self.search_result + pathlist + def __repr__(self): + return self.name + def __eq__(self, other): + return self.name == other.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.name == other.name class FindPathDirsTestCase(unittest.TestCase): def test_FindPathDirs(self): @@ -76,7 +87,7 @@ env.fs._cwd = DummyNode('cwd') dir = DummyNode('dir', ['xxx']) - fpd = SCons.Scanner.FindPathDirs('LIBPATH') + fpd = FindPathDirs('LIBPATH') result = fpd(env) assert str(result) == "('foo',)", result result = fpd(env, dir) @@ -88,25 +99,25 @@ """Test creation of Scanner objects""" def func(self): pass - s = SCons.Scanner.Base(func) - assert isinstance(s, SCons.Scanner.Base), s - s = SCons.Scanner.Base({}) - assert isinstance(s, SCons.Scanner.Base), s + s = ScannerBase(func) + assert isinstance(s, ScannerBase), s + s = ScannerBase({}) + assert isinstance(s, ScannerBase), s - s = SCons.Scanner.Base(func, name='fooscan') + s = ScannerBase(func, name='fooscan') assert str(s) == 'fooscan', str(s) - s = SCons.Scanner.Base({}, name='barscan') + s = ScannerBase({}, name='barscan') assert str(s) == 'barscan', str(s) - s = SCons.Scanner.Base(func, name='fooscan', argument=9) + s = ScannerBase(func, name='fooscan', argument=9) assert str(s) == 'fooscan', str(s) assert s.argument == 9, s.argument - s = SCons.Scanner.Base({}, name='fooscan', argument=888) + s = ScannerBase({}, name='fooscan', argument=888) assert str(s) == 'fooscan', str(s) assert s.argument == 888, s.argument -class BaseTestCase(unittest.TestCase): +class ScannerBaseTestCase(unittest.TestCase): class skey_node: def __init__(self, key): @@ -144,7 +155,7 @@ self.assertFalse(hasattr(self, "arg"), "an argument was given when it shouldn't have been") def test___call__dict(self): - """Test calling Scanner.Base objects with a dictionary""" + """Test calling ScannerBase objects with a dictionary""" called = [] def s1func(node, env, path, called=called): called.append('s1func') @@ -154,9 +165,9 @@ called.append('s2func') called.append(node) return [] - s1 = SCons.Scanner.Base(s1func) - s2 = SCons.Scanner.Base(s2func) - selector = SCons.Scanner.Base({'.x' : s1, '.y' : s2}) + s1 = ScannerBase(s1func) + s2 = ScannerBase(s2func) + selector = ScannerBase({'.x' : s1, '.y' : s2}) nx = self.skey_node('.x') env = DummyEnvironment() selector(nx, env, []) @@ -167,7 +178,7 @@ assert called == ['s2func', ny], called def test_path(self): - """Test the Scanner.Base path() method""" + """Test the ScannerBase path() method""" def pf(env, cwd, target, source, argument=None): return "pf: %s %s %s %s %s" % \ (env.VARIABLE, cwd, target[0], source[0], argument) @@ -177,17 +188,17 @@ target = DummyNode('target') source = DummyNode('source') - s = SCons.Scanner.Base(self.func, path_function=pf) + s = ScannerBase(self.func, path_function=pf) p = s.path(env, 'here', [target], [source]) assert p == "pf: v1 here target source None", p - s = SCons.Scanner.Base(self.func, path_function=pf, argument="xyz") + s = ScannerBase(self.func, path_function=pf, argument="xyz") p = s.path(env, 'here', [target], [source]) assert p == "pf: v1 here target source xyz", p def test_positional(self): - """Test the Scanner.Base class using positional arguments""" - s = SCons.Scanner.Base(self.func, "Pos") + """Test the ScannerBase class using positional arguments""" + s = ScannerBase(self.func, "Pos") env = DummyEnvironment() env.VARIABLE = "var1" self.test(s, env, DummyNode('f1.cpp'), ['f1.h', 'f1.hpp']) @@ -197,8 +208,8 @@ self.test(s, env, DummyNode('i1.cpp'), ['i1.h', 'i1.hpp']) def test_keywords(self): - """Test the Scanner.Base class using keyword arguments""" - s = SCons.Scanner.Base(function = self.func, name = "Key") + """Test the ScannerBase class using keyword arguments""" + s = ScannerBase(function = self.func, name = "Key") env = DummyEnvironment() env.VARIABLE = "var2" self.test(s, env, DummyNode('f2.cpp'), ['f2.h', 'f2.hpp']) @@ -209,9 +220,9 @@ self.test(s, env, DummyNode('i2.cpp'), ['i2.h', 'i2.hpp']) def test_pos_opt(self): - """Test the Scanner.Base class using both position and optional arguments""" + """Test the ScannerBase class using both position and optional arguments""" arg = "this is the argument" - s = SCons.Scanner.Base(self.func, "PosArg", arg) + s = ScannerBase(self.func, "PosArg", arg) env = DummyEnvironment() env.VARIABLE = "var3" self.test(s, env, DummyNode('f3.cpp'), ['f3.h', 'f3.hpp'], arg) @@ -221,10 +232,9 @@ self.test(s, env, DummyNode('i3.cpp'), ['i3.h', 'i3.hpp'], arg) def test_key_opt(self): - """Test the Scanner.Base class using both keyword and optional arguments""" + """Test the ScannerBase class using both keyword and optional arguments""" arg = "this is another argument" - s = SCons.Scanner.Base(function = self.func, name = "KeyArg", - argument = arg) + s = ScannerBase(function = self.func, name = "KeyArg", argument = arg) env = DummyEnvironment() env.VARIABLE = "var4" self.test(s, env, DummyNode('f4.cpp'), ['f4.h', 'f4.hpp'], arg) @@ -234,29 +244,29 @@ self.test(s, env, DummyNode('i4.cpp'), ['i4.h', 'i4.hpp'], arg) def test___cmp__(self): - """Test the Scanner.Base class __cmp__() method""" - s = SCons.Scanner.Base(self.func, "Cmp") + """Test the ScannerBase class __cmp__() method""" + s = ScannerBase(self.func, "Cmp") assert s is not None def test_hash(self): - """Test the Scanner.Base class __hash__() method""" - s = SCons.Scanner.Base(self.func, "Hash") - dict = {} - dict[s] = 777 + """Test the ScannerBase class __hash__() method""" + s = ScannerBase(self.func, "Hash") + mapping = {} + mapping[s] = 777 i = hash(id(s)) - h = hash(list(dict.keys())[0]) + h = hash(list(mapping)[0]) self.assertTrue(h == i, "hash Scanner base class expected %s, got %s" % (i, h)) def test_scan_check(self): - """Test the Scanner.Base class scan_check() method""" + """Test the ScannerBase class scan_check() method""" def my_scan(filename, env, target, *args): return [] def check(node, env, s=self): s.checked[str(node)] = 1 return 1 env = DummyEnvironment() - s = SCons.Scanner.Base(my_scan, "Check", scan_check = check) + s = ScannerBase(my_scan, "Check", scan_check = check) self.checked = {} path = s.path(env) scanned = s(DummyNode('x'), env, path) @@ -264,56 +274,49 @@ "did not call check function") def test_recursive(self): - """Test the Scanner.Base class recursive flag""" + """Test the ScannerBase class recursive flag""" nodes = [1, 2, 3, 4] - s = SCons.Scanner.Base(function = self.func) + s = ScannerBase(function = self.func) n = s.recurse_nodes(nodes) - self.assertTrue(n == [], - "default behavior returned nodes: %s" % n) + self.assertTrue(n == [], "default behavior returned nodes: %s" % n) - s = SCons.Scanner.Base(function = self.func, recursive = None) + s = ScannerBase(function = self.func, recursive = None) n = s.recurse_nodes(nodes) - self.assertTrue(n == [], - "recursive = None returned nodes: %s" % n) + self.assertTrue(n == [], "recursive = None returned nodes: %s" % n) - s = SCons.Scanner.Base(function = self.func, recursive = 1) + s = ScannerBase(function = self.func, recursive = 1) n = s.recurse_nodes(nodes) - self.assertTrue(n == n, - "recursive = 1 didn't return all nodes: %s" % n) + self.assertTrue(n == n, "recursive = 1 didn't return all nodes: %s" % n) def odd_only(nodes): return [n for n in nodes if n % 2] - s = SCons.Scanner.Base(function = self.func, recursive = odd_only) + s = ScannerBase(function = self.func, recursive = odd_only) n = s.recurse_nodes(nodes) - self.assertTrue(n == [1, 3], - "recursive = 1 didn't return all nodes: %s" % n) + self.assertTrue(n == [1, 3], "recursive = 1 didn't return all nodes: %s" % n) def test_get_skeys(self): - """Test the Scanner.Base get_skeys() method""" - s = SCons.Scanner.Base(function = self.func) + """Test the ScannerBase get_skeys() method""" + s = ScannerBase(function = self.func) sk = s.get_skeys() - self.assertTrue(sk == [], - "did not initialize to expected []") + self.assertTrue(sk == [], "did not initialize to expected []") - s = SCons.Scanner.Base(function = self.func, skeys = ['.1', '.2']) + s = ScannerBase(function = self.func, skeys = ['.1', '.2']) sk = s.get_skeys() - self.assertTrue(sk == ['.1', '.2'], - "sk was %s, not ['.1', '.2']") + self.assertTrue(sk == ['.1', '.2'], "sk was %s, not ['.1', '.2']") - s = SCons.Scanner.Base(function = self.func, skeys = '$LIST') + s = ScannerBase(function = self.func, skeys = '$LIST') env = DummyEnvironment(LIST = ['.3', '.4']) sk = s.get_skeys(env) - self.assertTrue(sk == ['.3', '.4'], - "sk was %s, not ['.3', '.4']") + self.assertTrue(sk == ['.3', '.4'], "sk was %s, not ['.3', '.4']") def test_select(self): - """Test the Scanner.Base select() method""" - scanner = SCons.Scanner.Base(function = self.func) + """Test the ScannerBase select() method""" + scanner = ScannerBase(function = self.func) s = scanner.select('.x') assert s is scanner, s - selector = SCons.Scanner.Base({'.x' : 1, '.y' : 2}) + selector = ScannerBase({'.x' : 1, '.y' : 2}) s = selector.select(self.skey_node('.x')) assert s == 1, s s = selector.select(self.skey_node('.y')) @@ -322,8 +325,8 @@ assert s is None, s def test_add_scanner(self): - """Test the Scanner.Base add_scanner() method""" - selector = SCons.Scanner.Base({'.x' : 1, '.y' : 2}) + """Test the ScannerBase add_scanner() method""" + selector = ScannerBase({'.x' : 1, '.y' : 2}) s = selector.select(self.skey_node('.z')) assert s is None, s selector.add_scanner('.z', 3) @@ -331,11 +334,11 @@ assert s == 3, s def test___str__(self): - """Test the Scanner.Base __str__() method""" - scanner = SCons.Scanner.Base(function = self.func) + """Test the ScannerBase __str__() method""" + scanner = ScannerBase(function = self.func) s = str(scanner) assert s == 'NONE', s - scanner = SCons.Scanner.Base(function = self.func, name = 'xyzzy') + scanner = ScannerBase(function = self.func, name = 'xyzzy') s = str(scanner) assert s == 'xyzzy', s @@ -350,9 +353,9 @@ def test___init__(self): """Test creation of Scanner.Selector object""" - s = SCons.Scanner.Selector({}) - assert isinstance(s, SCons.Scanner.Selector), s - assert s.dict == {}, s.dict + s = Selector({}) + assert isinstance(s, Selector), s + assert s.mapping == {}, s.mapping def test___call__(self): """Test calling Scanner.Selector objects""" @@ -365,9 +368,9 @@ called.append('s2func') called.append(node) return [] - s1 = SCons.Scanner.Base(s1func) - s2 = SCons.Scanner.Base(s2func) - selector = SCons.Scanner.Selector({'.x' : s1, '.y' : s2}) + s1 = ScannerBase(s1func) + s2 = ScannerBase(s2func) + selector = Selector({'.x' : s1, '.y' : s2}) nx = self.skey_node('.x') env = DummyEnvironment() selector(nx, env, []) @@ -379,7 +382,7 @@ def test_select(self): """Test the Scanner.Selector select() method""" - selector = SCons.Scanner.Selector({'.x' : 1, '.y' : 2}) + selector = Selector({'.x' : 1, '.y' : 2}) s = selector.select(self.skey_node('.x')) assert s == 1, s s = selector.select(self.skey_node('.y')) @@ -389,7 +392,7 @@ def test_add_scanner(self): """Test the Scanner.Selector add_scanner() method""" - selector = SCons.Scanner.Selector({'.x' : 1, '.y' : 2}) + selector = Selector({'.x' : 1, '.y' : 2}) s = selector.select(self.skey_node('.z')) assert s is None, s selector.add_scanner('.z', 3) @@ -428,7 +431,7 @@ node.func_called = 1 return [] env = DummyEnvironment() - s = SCons.Scanner.Current(func) + s = Current(func) path = s.path(env) hnb = HasNoBuilder() s(hnb, env, path) @@ -461,7 +464,7 @@ def test_find_include(self): """Test the Scanner.Classic find_include() method""" env = DummyEnvironment() - s = SCons.Scanner.Classic("t", ['.suf'], 'MYPATH', r'^my_inc (\S+)') + s = Classic("t", ['.suf'], 'MYPATH', r'^my_inc (\S+)') def _find_file(filename, paths): return paths[0]+'/'+filename @@ -479,7 +482,7 @@ def test_name(self): """Test setting the Scanner.Classic name""" - s = SCons.Scanner.Classic("my_name", ['.s'], 'MYPATH', r'^my_inc (\S+)') + s = Classic("my_name", ['.s'], 'MYPATH', r'^my_inc (\S+)') assert s.name == "my_name", s.name def test_scan(self): @@ -500,7 +503,7 @@ def get_dir(self): return self._dir - class MyScanner(SCons.Scanner.Classic): + class MyScanner(Classic): def find_include(self, include, source_dir, path): return include, include @@ -564,7 +567,7 @@ nodes = [1, 2, 3, 4] - s = SCons.Scanner.Classic("Test", [], None, "", function=self.func, recursive=1) + s = Classic("Test", [], None, "", function=self.func, recursive=1) n = s.recurse_nodes(nodes) self.assertTrue(n == n, "recursive = 1 didn't return all nodes: %s" % n) @@ -572,7 +575,7 @@ def odd_only(nodes): return [n for n in nodes if n % 2] - s = SCons.Scanner.Classic("Test", [], None, "", function=self.func, recursive=odd_only) + s = Classic("Test", [], None, "", function=self.func, recursive=odd_only) n = s.recurse_nodes(nodes) self.assertTrue(n == [1, 3], "recursive = 1 didn't return all nodes: %s" % n) @@ -582,7 +585,7 @@ def test_find_include(self): """Test the Scanner.ClassicCPP find_include() method""" env = DummyEnvironment() - s = SCons.Scanner.ClassicCPP("Test", [], None, "") + s = ClassicCPP("Test", [], None, "") def _find_file(filename, paths): return paths[0]+'/'+filename @@ -611,14 +614,16 @@ tclasses = [ FindPathDirsTestCase, ScannerTestCase, - BaseTestCase, + ScannerBaseTestCase, SelectorTestCase, CurrentTestCase, ClassicTestCase, ClassicCPPTestCase, ] for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') + loader = unittest.TestLoader() + loader.testMethodPrefix = 'test_' + names = loader.getTestCaseNames(tclass) suite.addTests(list(map(tclass, names))) return suite diff -Nru scons-4.0.1+dfsg/SCons/Scanner/Scanner.xml scons-4.4.0+dfsg/SCons/Scanner/Scanner.xml --- scons-4.0.1+dfsg/SCons/Scanner/Scanner.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/Scanner.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,91 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +(variable) + + + +Returns a function +(actually a callable Python object) +intended to be used as the +path_function +of a Scanner object. +The returned object will look up the specified +variable +in a construction environment +and treat the construction variable's value as a list of +directory paths that should be searched +(like +&cv-link-CPPPATH;, +&cv-link-LIBPATH;, +etc.). + + + +Note that use of +&f-FindPathDirs; +is generally preferable to +writing your own +path_function +for the following reasons: +1) The returned list will contain all appropriate directories +found in source trees +(when +&f-link-VariantDir; +is used) +or in code repositories +(when +&f-Repository; +or the + +option are used). +2) scons will identify expansions of +variable +that evaluate to the same list of directories as, +in fact, the same list, +and avoid re-scanning the directories for files, +when possible. + + + +Example: + + + +def my_scan(node, env, path, arg): + # Code to scan file contents goes here... + return include_files + +scanner = Scanner(name = 'myscanner', + function = my_scan, + path_function = FindPathDirs('MYPATH')) + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Scanner/SWIG.py scons-4.4.0+dfsg/SCons/Scanner/SWIG.py --- scons-4.0.1+dfsg/SCons/Scanner/SWIG.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Scanner/SWIG.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,17 +20,16 @@ # 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 +from . import ClassicCPP -SWIGSuffixes = [ '.i' ] +SWIGSuffixes = ['.i'] def SWIGScanner(): expr = r'^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)' - scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr) + scanner = ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr) return scanner # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/SConf.py scons-4.4.0+dfsg/SCons/SConf.py --- scons-4.0.1+dfsg/SCons/SConf.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/SConf.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -77,6 +73,9 @@ CACHE=2 # force all tests to be taken from cache (raise an error, if necessary) cache_mode = AUTO +def _set_conftest_node(node): + node.attributes.conftest_node = 1 + def SetCacheMode(mode): """Set the Configure cache mode. mode must be one of "auto", "force", or "cache".""" @@ -136,14 +135,14 @@ env.SConfigHBuilder(k, env.Value(v)) -class SConfWarning(SCons.Warnings.Warning): +class SConfWarning(SCons.Warnings.SConsWarning): pass SCons.Warnings.enableWarningClass(SConfWarning) # some error definitions class SConfError(SCons.Errors.UserError): def __init__(self,msg): - SCons.Errors.UserError.__init__(self,msg) + super().__init__(msg) class ConfigureDryRunError(SConfError): """Raised when a file or directory needs to be updated during a Configure @@ -153,13 +152,13 @@ msg = 'Cannot create configure directory "%s" within a dry-run.' % str(target) else: msg = 'Cannot update configure test "%s" within a dry-run.' % str(target) - SConfError.__init__(self,msg) + super().__init__(msg) class ConfigureCacheError(SConfError): """Raised when a use explicitely requested the cache feature, but the test is run the first time.""" def __init__(self,target): - SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target)) + super().__init__('"%s" is not yet built and cache is forced.' % str(target)) # define actions for building text files @@ -238,8 +237,10 @@ bi. """ if not isinstance(bi, SConfBuildInfo): - SCons.Warnings.warn(SConfWarning, - "The stored build information has an unexpected class: %s" % bi.__class__) + SCons.Warnings.warn( + SConfWarning, + "The stored build information has an unexpected class: %s" % bi.__class__ + ) else: self.display("The original builder output was:\n" + (" |" + str(bi.string)).replace("\n", "\n |")) @@ -449,6 +450,7 @@ 'CheckFunc' : CheckFunc, 'CheckType' : CheckType, 'CheckTypeSize' : CheckTypeSize, + 'CheckMember' : CheckMember, 'CheckDeclaration' : CheckDeclaration, 'CheckHeader' : CheckHeader, 'CheckCHeader' : CheckCHeader, @@ -520,6 +522,7 @@ # we override the store_info() method with a null place-holder # so we really control how it gets written. for n in nodes: + _set_conftest_node(n) n.store_info = 0 if not hasattr(n, 'attributes'): n.attributes = SCons.Node.Node.Attrs() @@ -532,6 +535,7 @@ for c in n.children(scan=False): # Keep debug code here. # print("Checking [%s] for builders and then setting keep_targetinfo"%c) + _set_conftest_node(c) if c.has_builder(): n.store_info = 0 if not hasattr(c, 'attributes'): @@ -596,39 +600,43 @@ nodesToBeBuilt = [] sourcetext = self.env.Value(text) + _set_conftest_node(sourcetext) f = "conftest" if text is not None: - textSig = SCons.Util.MD5signature(sourcetext) + textSig = SCons.Util.hash_signature(sourcetext) textSigCounter = str(_ac_build_counter[textSig]) _ac_build_counter[textSig] += 1 f = "_".join([f, textSig, textSigCounter]) textFile = self.confdir.File(f + extension) + _set_conftest_node(textFile) textFileNode = self.env.SConfSourceBuilder(target=textFile, source=sourcetext) nodesToBeBuilt.extend(textFileNode) source = textFile target = textFile.File(f + "SConfActionsContentDummyTarget") + _set_conftest_node(target) else: source = None target = None action = builder.builder.action.get_contents(target=target, source=[source], env=self.env) - actionsig = SCons.Util.MD5signature(action) + actionsig = SCons.Util.hash_signature(action) f = "_".join([f, actionsig]) pref = self.env.subst( builder.builder.prefix ) suff = self.env.subst( builder.builder.suffix ) target = self.confdir.File(pref + f + suff) + _set_conftest_node(target) try: # Slide our wrapper into the construction environment as # the SPAWN function. self.env['SPAWN'] = self.pspawn_wrapper - nodes = builder(target = target, source = source) + nodes = builder(target = target, source = source, SCONF_NODE=True) if not SCons.Util.is_List(nodes): nodes = [nodes] nodesToBeBuilt.extend(nodes) @@ -985,6 +993,13 @@ context.did_show_result = 1 return not res +def CheckMember(context, aggregate_member, header = None, language = None): + '''Returns the status (False : failed, True : ok).''' + res = SCons.Conftest.CheckMember(context, aggregate_member, header=header, language=language) + context.did_show_result = 1 + return not res + + def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'): # used by CheckHeader and CheckLibWithHeader to produce C - #include # statements from the specified header (list) diff -Nru scons-4.0.1+dfsg/SCons/SConfTests.py scons-4.4.0+dfsg/SCons/SConfTests.py --- scons-4.0.1+dfsg/SCons/SConfTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/SConfTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,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 io import os import re import sys -from types import * +from types import ModuleType import unittest import TestCmd @@ -162,6 +158,9 @@ def get_contents(self, target, source, env): return 'MyBuilder-MyAction $SOURCE $TARGET' + class Attrs: + __slots__ = ('shared', '__dict__') + class MyBuilder(SCons.Builder.BuilderBase): def __init__(self): self.prefix = '' @@ -169,7 +168,7 @@ # need action because temporary file name uses hash of actions get_contents() self.action = MyAction() - def __call__(self, env, target, source): + def __call__(self, env, target, source, *args, **kw): class MyNode: def __init__(self, name): self.name = name @@ -178,6 +177,7 @@ self.side_effects = [] self.builder = None self.prerequisites = None + self.attributes = Attrs() def disambiguate(self): return self def has_builder(self): @@ -725,6 +725,27 @@ finally: sconf.Finish() + def test_CheckMember(self): + """Test SConf.CheckMember() + """ + self._resetSConfState() + sconf = self.SConf.SConf(self.scons_env, + conf_dir=self.test.workpath('config.tests'), + log_file=self.test.workpath('config.log')) + + try: + # CheckMember() + r = sconf.CheckMember('struct timespec.tv_sec', '#include ') + assert r, "did not find timespec.tv_sec" + r = sconf.CheckMember('struct timespec.tv_nano', '#include ') + assert not r, "unexpectedly found struct timespec.tv_nano" + r = sconf.CheckMember('hopefullynomember') + assert not r, "unexpectedly found hopefullynomember :%s" % r + + finally: + sconf.Finish() + + def test_(self): """Test SConf.CheckType() """ diff -Nru scons-4.0.1+dfsg/SCons/SConsign.py scons-4.4.0+dfsg/SCons/SConsign.py --- scons-4.0.1+dfsg/SCons/SConsign.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/SConsign.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,25 +20,28 @@ # 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 import os import pickle +import time import SCons.dblite import SCons.Warnings - from SCons.compat import PICKLE_PROTOCOL +from SCons.Util import print_time def corrupt_dblite_warning(filename): - SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, - "Ignoring corrupt .sconsign file: %s"%filename) + SCons.Warnings.warn( + SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt .sconsign file: %s" % filename, + ) -SCons.dblite.ignore_corrupt_dbfiles = 1 +SCons.dblite.IGNORE_CORRUPT_DBFILES = True SCons.dblite.corruption_warning = corrupt_dblite_warning # XXX Get rid of the global array so this becomes re-entrant. @@ -57,12 +55,29 @@ # extension the underlying DB module will add). DataBase = {} DB_Module = SCons.dblite -DB_Name = ".sconsign" +DB_Name = None DB_sync_list = [] +def current_sconsign_filename(): + hash_format = SCons.Util.get_hash_format() + current_hash_algorithm = SCons.Util.get_current_hash_algorithm_used() + # if the user left the options defaulted AND the default algorithm set by + # SCons is md5, then set the database name to be the special default name + # + # otherwise, if it defaults to something like 'sha1' or the user explicitly + # set 'md5' as the hash format, set the database name to .sconsign_ + # eg .sconsign_sha1, etc. + if hash_format is None and current_hash_algorithm == 'md5': + return ".sconsign" + else: + return ".sconsign_" + current_hash_algorithm def Get_DataBase(dir): global DataBase, DB_Module, DB_Name + + if DB_Name is None: + DB_Name = current_sconsign_filename() + top = dir.fs.Top if not os.path.isabs(DB_Name) and top.repositories: mode = "c" @@ -103,6 +118,10 @@ def write(): global sig_files + + if print_time(): + start_time = time.perf_counter() + for sig_file in sig_files: sig_file.write(sync=0) for db in DB_sync_list: @@ -119,6 +138,10 @@ else: closemethod() + if print_time(): + elapsed = time.perf_counter() - start_time + print('Total SConsign sync time: %f seconds' % elapsed) + class SConsignEntry: """ @@ -146,7 +169,7 @@ def __getstate__(self): state = getattr(self, '__dict__', {}).copy() for obj in type(self).mro(): - for name in getattr(obj,'__slots__',()): + for name in getattr(obj, '__slots__', ()): if hasattr(self, name): state[name] = getattr(self, name) @@ -159,7 +182,7 @@ def __setstate__(self, state): for key, value in state.items(): - if key not in ('_version_id','__weakref__'): + if key not in ('_version_id', '__weakref__'): setattr(self, key, value) @@ -225,7 +248,7 @@ determined by the database module. """ def __init__(self, dir): - Base.__init__(self) + super().__init__() self.dir = dir @@ -296,7 +319,7 @@ """ fp - file pointer to read entries from """ - Base.__init__(self) + super().__init__() if not fp: return @@ -321,7 +344,7 @@ """ self.dir = dir - self.sconsign = os.path.join(dir.get_internal_path(), '.sconsign') + self.sconsign = os.path.join(dir.get_internal_path(), current_sconsign_filename()) try: fp = open(self.sconsign, 'rb') @@ -329,7 +352,7 @@ fp = None try: - Dir.__init__(self, fp, dir) + super().__init__(fp, dir) except KeyboardInterrupt: raise except Exception: diff -Nru scons-4.0.1+dfsg/SCons/SConsignTests.py scons-4.4.0+dfsg/SCons/SConsignTests.py --- scons-4.0.1+dfsg/SCons/SConsignTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/SConsignTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,20 +20,15 @@ # 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 -import TestUnit import SCons.dblite - import SCons.SConsign +from SCons.Util import get_hash_format, get_current_hash_algorithm_used class BuildInfo: def merge(self, object): @@ -300,7 +296,10 @@ file = test.workpath('sconsign_file') assert SCons.SConsign.DataBase == {}, SCons.SConsign.DataBase - assert SCons.SConsign.DB_Name == ".sconsign", SCons.SConsign.DB_Name + if get_hash_format() is None and get_current_hash_algorithm_used() == 'md5': + assert SCons.SConsign.DB_Name == ".sconsign", SCons.SConsign.DB_Name + else: + assert SCons.SConsign.DB_Name == ".sconsign_{}".format(get_current_hash_algorithm_used()), SCons.SConsign.DB_Name assert SCons.SConsign.DB_Module is SCons.dblite, SCons.SConsign.DB_Module SCons.SConsign.File(file) @@ -382,18 +381,7 @@ 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 -Nru scons-4.0.1+dfsg/SCons/Script/__init__.py scons-4.4.0+dfsg/SCons/Script/__init__.py --- scons-4.0.1+dfsg/SCons/Script/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -69,7 +60,7 @@ import SCons.Warnings try: SCons.Memoize.EnableMemoization() - except SCons.Warnings.Warning: + except SCons.Warnings.SConsWarning: # Some warning was thrown. Arrange for it to be displayed # or not after warnings are configured. from . import Main @@ -134,7 +125,6 @@ #profiling = Main.profiling #repositories = Main.repositories -# from . import SConscript _SConscript = SConscript @@ -152,7 +142,7 @@ Platform = SCons.Platform.Platform Virtualenv = SCons.Platform.virtualenv.Virtualenv Return = _SConscript.Return -Scanner = SCons.Scanner.Base +Scanner = SCons.Scanner.ScannerBase Tool = SCons.Tool.Tool WhereIs = SCons.Util.WhereIs @@ -265,7 +255,7 @@ if help_text is None: if append: s = StringIO() - PrintHelp(s) + PrintHelp(s) help_text = s.getvalue() s.close() else: @@ -282,7 +272,11 @@ _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 -Nru scons-4.0.1+dfsg/SCons/Script/Interactive.py scons-4.4.0+dfsg/SCons/Script/Interactive.py --- scons-4.0.1+dfsg/SCons/Script/Interactive.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/Interactive.py 2022-07-30 21:48:28.000000000 +0000 @@ -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: # @@ -31,7 +29,7 @@ # of its own, which might or might not be a good thing. Nevertheless, # here are some enhancements that will probably be requested some day # and are worth keeping in mind (assuming this takes off): -# +# # - A command to re-read / re-load the SConscript files. This may # involve allowing people to specify command-line options (e.g. -f, # -I, --no-site-dir) that affect how the SConscript files are read. @@ -259,7 +257,12 @@ # from SCons.Debug import Trace # Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count)) - SCons.SConsign.Reset() + # TODO: REMOVE WPD DEBUG 02/14/2022 + # This call was clearing the list of sconsign files to be written, so it would + # only write the results of the first build command. All others wouldn't be written + # to .SConsign. + # Pretty sure commenting this out is the correct fix. + # SCons.SConsign.Reset() SCons.Script.Main.progress_display("scons: done clearing node information.") def do_clean(self, argv): diff -Nru scons-4.0.1+dfsg/SCons/Script/Main.py scons-4.4.0+dfsg/SCons/Script/Main.py --- scons-4.0.1+dfsg/SCons/Script/Main.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/Main.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 +minimum_python_version = (3, 6, 0) +deprecated_python_version = (3, 6, 0) import SCons.compat @@ -47,8 +44,8 @@ import sys import time import traceback -import sysconfig import platform +import threading import SCons.CacheDir import SCons.Debug @@ -67,14 +64,16 @@ import SCons.Warnings import SCons.Script.Interactive +from SCons import __version__ as SConsVersion + # Global variables first_command_start = None last_command_end = None -print_objects = 0 -print_memoizer = 0 -print_stacktrace = 0 -print_time = 0 -print_action_timestamps = 0 +print_objects = False +print_memoizer = False +print_stacktrace = False +print_time = False +print_action_timestamps = False sconscript_time = 0 cumulative_command_time = 0 exit_status = 0 # final exit status, assume success by default @@ -83,17 +82,6 @@ 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 @@ -186,7 +174,9 @@ display('scons: ' + message) def prepare(self): - self.progress(self.targets[0]) + if not isinstance(self.progress, SCons.Util.Null): + for target in self.targets: + self.progress(target) return SCons.Taskmaster.OutOfDateTask.prepare(self) def needs_execute(self): @@ -208,11 +198,20 @@ global last_command_end finish_time = time.time() last_command_end = finish_time - cumulative_command_time = cumulative_command_time+finish_time-start_time + cumulative_command_time += finish_time - start_time if print_action_timestamps: - sys.stdout.write("Command execution start timestamp: %s: %f\n"%(str(self.node), start_time)) - sys.stdout.write("Command execution end timestamp: %s: %f\n"%(str(self.node), finish_time)) - sys.stdout.write("Command execution time: %s: %f seconds\n"%(str(self.node), finish_time-start_time)) + sys.stdout.write( + "Command execution start timestamp: %s: %f\n" + % (str(self.node), start_time) + ) + sys.stdout.write( + "Command execution end timestamp: %s: %f\n" + % (str(self.node), finish_time) + ) + sys.stdout.write( + "Command execution time: %s: %f seconds\n" + % (str(self.node), (finish_time - start_time)) + ) def do_failed(self, status=2): _BuildFailures.append(self.exception[1]) @@ -454,7 +453,7 @@ return sys.version.split()[0] def python_version_unsupported(version=sys.version_info): - return version < unsupported_python_version + return version < minimum_python_version def python_version_deprecated(version=sys.version_info): return version < deprecated_python_version @@ -671,22 +670,22 @@ if print_objects: SCons.Debug.track_instances = True if "presub" in debug_values: - SCons.Action.print_actions_presub = 1 + SCons.Action.print_actions_presub = True if "stacktrace" in debug_values: - print_stacktrace = 1 + print_stacktrace = True if "stree" in debug_values: options.tree_printers.append(TreePrinter(status=True)) if "time" in debug_values: - print_time = 1 + print_time = True if "action-timestamps" in debug_values: - print_time = 1 - print_action_timestamps = 1 + print_time = True + print_action_timestamps = True if "tree" in debug_values: options.tree_printers.append(TreePrinter()) if "prepare" in debug_values: - SCons.Taskmaster.print_prepare = 1 + SCons.Taskmaster.print_prepare = True if "duplicate" in debug_values: - SCons.Node.print_duplicate = 1 + SCons.Node.print_duplicate = True def _create_path(plist): path = '.' @@ -779,7 +778,7 @@ raise -def _load_all_site_scons_dirs(topdir, verbose=None): +def _load_all_site_scons_dirs(topdir, verbose=False): """Load all of the predefined site_scons dir. Order is significant; we load them in order from most generic (machine-wide) to most specific (topdir). @@ -791,13 +790,12 @@ return os.path.expanduser('~/'+d) if platform == 'win32' or platform == 'cygwin': - # Note we use $ here instead of %...% because older - # pythons (prior to 2.6?) didn't expand %...% on Windows. - # This set of dirs should work on XP, Vista, 7 and later. sysdirs=[ - os.path.expandvars('$ALLUSERSPROFILE\\Application Data\\scons'), - os.path.expandvars('$USERPROFILE\\Local Settings\\Application Data\\scons')] - appdatadir = os.path.expandvars('$APPDATA\\scons') + os.path.expandvars('%AllUsersProfile%\\scons'), + # TODO older path, kept for compat + os.path.expandvars('%AllUsersProfile%\\Application Data\\scons'), + os.path.expandvars('%LocalAppData%\\scons')] + appdatadir = os.path.expandvars('%AppData%\\scons') if appdatadir not in sysdirs: sysdirs.append(appdatadir) sysdirs.append(homedir('.scons')) @@ -972,10 +970,12 @@ if options.no_progress or options.silent: progress_display.set_mode(0) - if options.site_dir: - _load_site_scons_dir(d.get_internal_path(), options.site_dir) - elif not options.no_site_dir: + # if site_dir unchanged from default None, neither --site-dir + # nor --no-site-dir was seen, use SCons default + if options.site_dir is None: _load_all_site_scons_dirs(d.get_internal_path()) + elif options.site_dir: # if a dir was set, use it + _load_site_scons_dir(d.get_internal_path(), options.site_dir) if options.include_dir: sys.path = options.include_dir + sys.path @@ -987,14 +987,17 @@ # This would then cause subtle bugs, as already happened in #2971. if options.interactive: SCons.Node.interactive = True - - # That should cover (most of) the options. Next, set up the variables - # that hold command-line arguments, so the SConscript files that we - # read and execute have access to them. + # That should cover (most of) the options. + # Next, set up the variables that hold command-line arguments, + # so the SConscript files that we read and execute have access to them. + # TODO: for options defined via AddOption which take space-separated + # option-args, the option-args will collect into targets here, + # because we don't yet know to do any different. targets = [] xmit_args = [] for a in parser.largs: - if a[:1] == '-': + # Skip so-far unrecognized options, and empty string args + if a.startswith('-') or a in ('', '""', "''"): continue if '=' in a: xmit_args.append(a) @@ -1023,7 +1026,8 @@ progress_display("scons: Reading SConscript files ...") - start_time = time.time() + if print_time: + start_time = time.time() try: for script in scripts: SCons.Script._SConscript._SConscript(fs, script) @@ -1036,8 +1040,9 @@ revert_io() sys.stderr.write("scons: *** %s Stop.\n" % e) sys.exit(2) - global sconscript_time - sconscript_time = time.time() - start_time + if print_time: + global sconscript_time + sconscript_time = time.time() - start_time progress_display("scons: done reading SConscript files.") @@ -1111,8 +1116,11 @@ SCons.Job.explicit_stack_size = options.stack_size + # Hash format and chunksize are set late to support SetOption being called + # in a SConscript or SConstruct file. + SCons.Util.set_hash_format(options.hash_format) if options.md5_chunksize: - SCons.Node.FS.File.md5_chunksize = options.md5_chunksize + SCons.Node.FS.File.hash_chunksize = options.md5_chunksize * 1024 platform = SCons.Platform.platform_module() @@ -1284,16 +1292,19 @@ # 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: @@ -1343,8 +1354,7 @@ 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: @@ -1365,7 +1375,8 @@ # disable that warning. if python_version_unsupported(): msg = "scons: *** SCons version %s does not run under Python version %s.\n" - sys.stderr.write(msg % (SCons.__version__, python_version_string())) + sys.stderr.write(msg % (SConsVersion, python_version_string())) + sys.stderr.write("scons: *** Minimum Python version is %d.%d.%d\n" %minimum_python_version) sys.exit(1) parts = ["SCons by Steven Knight et al.:\n"] diff -Nru scons-4.0.1+dfsg/SCons/Script/MainTests.py scons-4.4.0+dfsg/SCons/Script/MainTests.py --- scons-4.0.1+dfsg/SCons/Script/MainTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/MainTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,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 unittest -import SCons.Errors -import SCons.Script.Main - # Unit tests of various classes within SCons.Script.Main.py. # # Most of the tests of this functionality are actually end-to-end scripts diff -Nru scons-4.0.1+dfsg/SCons/Script/Main.xml scons-4.4.0+dfsg/SCons/Script/Main.xml --- scons-4.0.1+dfsg/SCons/Script/Main.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/Main.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ + + + + + + + Settable name + Command-line options + Notes + + + + + + clean + + , + , + + + + + + diskcheck + + + + + duplicate + + + + + experimental + + since 4.2 + + + + hash_chunksize + + + Actually sets md5_chunksize. + since 4.2 + + + + + hash_format + + since 4.2 + + + + help + , + + + + implicit_cache + + + + + implicit_deps_changed + + + Also sets implicit_cache. + (settable since 4.2) + + + + + implicit_deps_unchanged + + + Also sets implicit_cache. + (settable since 4.2) + + + + + max_drift + + + + + md5_chunksize + + + + + no_exec + + , + , + , + , + + + + + + no_progress + + See + + If no_progress is set via &f-SetOption; + in an SConscript file + (but not if set in a site_init.py file) + there will still be an initial status message about + reading SConscript files since &SCons; has + to start reading them before it can see the + &f-SetOption;. + + + + + + + num_jobs + , + + + + random + + + + + silent + + , + , + + + + + + stack_size + + + + + warn + + + + + + Example: -SetOption('max_drift', 1) +SetOption('max_drift', 0) diff -Nru scons-4.0.1+dfsg/SCons/Script/SConscript.py scons-4.4.0+dfsg/SCons/Script/SConscript.py --- scons-4.0.1+dfsg/SCons/Script/SConscript.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/SConscript.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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 @@ -40,13 +34,11 @@ import SCons.Node.FS import SCons.Platform import SCons.SConf -import SCons.Script.Main import SCons.Tool 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 @@ -156,31 +148,37 @@ def handle_missing_SConscript(f, must_exist=None): """Take appropriate action on missing file in SConscript() call. - Print a warning or raise an exception on missing file. + Print a warning or raise an exception on missing file, unless + missing is explicitly allowed by the *must_exist* value. On first warning, print a deprecation message. Args: f (str): path of missing configuration file - must_exist (bool): raise exception if file does not exist + must_exist (bool): if true, fail. If false, but not ``None``, + allow the file to be missing. The default is ``None``, + which means issue the warning. The default is deprecated. Raises: - UserError if 'must_exist' is True or if global - SCons.Script._no_missing_sconscript is True. + UserError: if *must_exist* is true or if global + :data:`SCons.Script._no_missing_sconscript` is true. """ if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False): msg = "Fatal: missing SConscript '%s'" % f.get_internal_path() raise SCons.Errors.UserError(msg) - if SCons.Script._warn_missing_sconscript_deprecated: - msg = "Calling missing SConscript without error is deprecated.\n" + \ - "Transition by adding must_exist=0 to SConscript calls.\n" + \ - "Missing SConscript '%s'" % f.get_internal_path() - SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) - SCons.Script._warn_missing_sconscript_deprecated = False - else: - msg = "Ignoring missing SConscript '%s'" % f.get_internal_path() - SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) + if must_exist is None: + if SCons.Script._warn_missing_sconscript_deprecated: + msg = ( + "Calling missing SConscript without error is deprecated.\n" + "Transition by adding must_exist=False to SConscript calls.\n" + "Missing SConscript '%s'" % f.get_internal_path() + ) + SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) + SCons.Script._warn_missing_sconscript_deprecated = False + else: + msg = "Ignoring missing SConscript '%s'" % f.get_internal_path() + SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) def _SConscript(fs, *files, **kw): top = fs.Top @@ -280,7 +278,7 @@ try: try: if Main.print_time: - time1 = time.time() + start_time = time.perf_counter() scriptdata = _file_.read() scriptname = _file_.name _file_.close() @@ -289,11 +287,12 @@ pass finally: if Main.print_time: - time2 = time.time() - print('SConscript:%s took %0.3f ms' % (f.get_abspath(), (time2 - time1) * 1000.0)) + elapsed = time.perf_counter() - start_time + print('SConscript:%s took %0.3f ms' % (f.get_abspath(), elapsed * 1000.0)) if old_file is not None: call_stack[-1].globals.update({__file__:old_file}) + else: handle_missing_SConscript(f, kw.get('must_exist', None)) diff -Nru scons-4.0.1+dfsg/SCons/Script/SConscriptTests.py scons-4.4.0+dfsg/SCons/Script/SConscriptTests.py --- scons-4.0.1+dfsg/SCons/Script/SConscriptTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/SConscriptTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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.Script.SConscript # all of the SConscript.py tests are in test/SConscript.py diff -Nru scons-4.0.1+dfsg/SCons/Script/SConscript.xml scons-4.4.0+dfsg/SCons/Script/SConscript.xml --- scons-4.0.1+dfsg/SCons/Script/SConscript.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Script/SConscript.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ -(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist]) - +(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist]) + -Execute one or more subsidiary SConscript (configuration) files. +Executes one or more subsidiary SConscript (configuration) files. There are two ways to call the &f-SConscript; function. -The first calling style -is to explicitly specify one or more -scripts -as the first argument. +The first calling style is to supply +one or more SConscript file names +as the first (positional) argument. A single script may be specified as a string; -multiple scripts must be specified as a list +multiple scripts must be specified as a list of strings (either explicitly or as created by a function like &f-link-Split;). Examples: -SConscript('SConscript') # run SConscript in the current directory +SConscript('SConscript') # run SConscript in the current directory SConscript('src/SConscript') # run SConscript in the src directory SConscript(['src/SConscript', 'doc/SConscript']) config = SConscript('MyConfig.py') -The second way to call -&f-SConscript; -is to specify a list of (sub)directory names -as a -dirs=subdirs -keyword argument. +The other calling style is to omit the positional argument naming +scripts and instead specify a list of directory names using the +dirs keyword argument. In this case, &scons; will @@ -414,14 +404,14 @@ You may specify a name other than &SConscript; by supplying an optional -name=script +name=scriptname keyword argument. The first three examples below have the same effect as the first three examples above: -SConscript(dirs='.') # run SConscript in the current directory -SConscript(dirs='src') # run SConscript in the src directory +SConscript(dirs='.') # run SConscript in the current directory +SConscript(dirs='src') # run SConscript in the src directory SConscript(dirs=['src', 'doc']) SConscript(dirs=['sub1', 'sub2'], name='MySConscript') @@ -429,8 +419,12 @@ The optional exports -argument provides a string or list of strings representing +keyword argument provides a string or list of strings representing variable names, or a dictionary of named values, to export. +For the first calling style only, a second positional argument +will be interpreted as exports; the +second calling style must use the keyword argument form +for exports. These variables are locally exported only to the called SConscript file(s) and do not affect the global pool of variables managed by the @@ -454,38 +448,24 @@ If the optional variant_dir argument is present, it causes an effect equivalent to the -&f-link-VariantDir; function. +&f-link-VariantDir; function, +but in effect only within the scope of the &f-SConscript; call. The variant_dir -argument is interpreted relative to the directory of the calling -SConscript file. -The optional -duplicate argument is -interpreted as for &f-link-VariantDir;. -If variant_dir -is omitted, the duplicate argument is ignored. -See the description of -&f-link-VariantDir; -below for additional details and restrictions. - - - -If -variant_dir -is present, -the source directory is the directory in which the -SConscript -file resides and the -SConscript +argument is interpreted relative to the directory of the +calling SConscript file. +The source directory is the directory in which the +called SConscript +file resides and the SConscript file is evaluated as if it were in the variant_dir -directory: +directory. Thus: SConscript('src/SConscript', variant_dir='build') -is equivalent to +is equivalent to: @@ -494,9 +474,8 @@ -This later paradigm is often used when the sources are -in the same directory as the -&SConstruct;: +If the sources are in the same directory as the +&SConstruct;, @@ -504,7 +483,7 @@ -is equivalent to +is equivalent to: @@ -513,6 +492,17 @@ +The optional +duplicate argument is +interpreted as for &f-link-VariantDir;. +If the variant_dir argument +is omitted, the duplicate argument is ignored. +See the description of +&f-link-VariantDir; +for additional details and restrictions. + + + CFILESUFFIX + CCDEPFLAGS PLATFORM @@ -215,4 +216,16 @@ + + + +Options to pass to C or C++ compiler to generate list of dependency files. + + + This is set only by compilers which support this functionality. (&t-link-gcc;, &t-link-clang;, and &t-link-msvc; currently) + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/clang.py scons-4.4.0+dfsg/SCons/Tool/clang.py --- scons-4.0.1+dfsg/SCons/Tool/clang.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/clang.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,17 +1,6 @@ -# -*- coding: utf-8; -*- - -"""SCons.Tool.clang - -Tool-specific initialization for clang. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# 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,9 +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__" +"""Tool-specific initialization for clang. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" # Based on SCons/Tool/gcc.py by PaweÅ‚ Tomulik 2014 as a separate tool. # Brought into the SCons mainline by Russel Winder 2017. @@ -41,7 +34,6 @@ import os import re import subprocess -import sys import SCons.Util import SCons.Tool.cc @@ -51,6 +43,7 @@ compilers = ['clang'] + def generate(env): """Add Builders and construction variables for clang to an Environment.""" SCons.Tool.cc.generate(env) @@ -66,7 +59,6 @@ # Set-up ms tools paths msvc_setup_env_once(env) - env['CC'] = env.Detect(compilers) or 'clang' if env['PLATFORM'] in ['cygwin', 'win32']: env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') @@ -75,7 +67,7 @@ # determine compiler version if env['CC']: - #pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'], + # pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'], pipe = SCons.Action._subproc(env, [env['CC'], '--version'], stdin='devnull', stderr='devnull', @@ -84,12 +76,15 @@ # 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) + env['CCDEPFLAGS'] = '-MMD -MF ${TARGET}.d' + env["NINJA_DEPFILE_PARSE_FORMAT"] = 'clang' + + def exists(env): return env.Detect(compilers) diff -Nru scons-4.0.1+dfsg/SCons/Tool/clang.xml scons-4.4.0+dfsg/SCons/Tool/clang.xml --- scons-4.0.1+dfsg/SCons/Tool/clang.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/clang.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ +--> COMPILATIONDB_USE_ABSPATH + COMPILATIONDB_PATH_FILTER - The &b-CompilationDatabase; builder writes a JSON formatted compilation - database according to the - LLVM specification - which is consumed by a number of clang tools, editors, and other tools. - - - If you don't specify any files, the builder will default to compile_commands.json. - - - If you specify a single file as below - -env.CompilationDatabase('my_output.json') - - SCons will automatically use that as the target file. - If you specify more than one source, the source list will be ignored. - - - You should not specify source files. The &b-CompilationDatabase; builder instruments SCons to collect them from all - the C, C++, assembly source/target pairs. - - - NOTE: You must load the &t-compilation_db; tool prior to specifying any part of your build or some source/target - files will not show up in your output file. - + &b-CompilationDatabase; is a special builder which + adds a target to create a JSON formatted + compilation database compatible with + clang tooling + (see the + LLVM specification). + This database is suitable for consumption by various + tools and editors who can use it to obtain build and + dependency information which otherwise would be + internal to &SCons;. + The builder does not require any source files to be specified, + rather it arranges to emit information about all + of the C, C++ and assembler source/output pairs + identified in the build that are not excluded by the + optional filter &cv-link-COMPILATIONDB_PATH_FILTER;. + The target is subject to the usual &SCons; target + selection rules. + + + If called with no arguments, + the builder will default to a target name of + compile_commands.json. + + + If called with a single positional argument, + &scons; will "deduce" the target name from that source + argument, giving it the same name, and then + ignore the source. + This is the usual way to call the builder if a + non-default target name is wanted. + + + If called with either the target= + or source= keyword arguments, + the value of the argument is taken as the target name. + If called with both, the target= + value is used and source= is ignored. + If called with multiple sources, + the source list will be ignored, + since there is no way to deduce what the intent was; + in this case the default target name will be used. + + + + You must load the &t-compilation_db; tool prior to specifying + any part of your build or some source/output + files will not show up in the compilation database. + + Available since &scons; 4.0. @@ -77,7 +103,8 @@ - The string displayed when CompilationDatabase builder's action is run. + The string displayed when the &b-link-CompilationDatabase; + builder's action is run. @@ -85,15 +112,31 @@ - This is a boolean flag to instruct &b-link-CompilationDatabase; to - write the file and target members - in the compilation database with absolute or relative paths. + A boolean flag to instruct &b-link-CompilationDatabase; + whether to write the file and + output members + in the compilation database using absolute or relative paths. The default value is False (use relative paths) + + + + + A string which instructs &b-link-CompilationDatabase; to + only include entries where the output member + matches the pattern in the filter string using fnmatch, which + uses glob style wildcards. + + + + The default value is an empty string '', which disables filtering. + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/cxx.py scons-4.4.0+dfsg/SCons/Tool/cxx.py --- scons-4.0.1+dfsg/SCons/Tool/cxx.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/cxx.py 2022-07-30 21:48:28.000000000 +0000 @@ -8,8 +8,6 @@ """ # -# __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,11 +28,8 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os.path -import SCons.Tool import SCons.Defaults import SCons.Util diff -Nru scons-4.0.1+dfsg/SCons/Tool/cyglink.py scons-4.4.0+dfsg/SCons/Tool/cyglink.py --- scons-4.0.1+dfsg/SCons/Tool/cyglink.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/cyglink.py 2022-07-30 21:48:28.000000000 +0000 @@ -8,225 +8,203 @@ """ -import re -import os +from SCons.Tool.linkCommon import StringizeLibSymlinks, EmitLibSymlinks +from SCons.Util import CLVar, is_String +from . import gnulink -import SCons.Action -import SCons.Util -import SCons.Tool -#MAYBE: from . import gnulink -from . import gnulink -from . import link +def cyglink_lib_emitter(target, source, env, **kw): + verbose = True -def _lib_generator(target, source, env, for_signature, **kw): - try: cmd = kw['cmd'] - except KeyError: cmd = SCons.Util.CLVar(['$SHLINK']) - - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' - - dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) - if dll: cmd.extend(['-o', dll]) - - cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH']) - - implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX') - if implib: - cmd.extend([ - '-Wl,--out-implib='+implib.get_string(for_signature), - '-Wl,--export-all-symbols', - '-Wl,--enable-auto-import', - '-Wl,--whole-archive', '$SOURCES', - '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS' - ]) + if 'variable_prefix' in kw: + var_prefix = kw['variable_prefix'] else: - cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + var_prefix = 'SHLIB' - return [cmd] + no_import_lib = env.get('no_import_lib', False) + if verbose: + print("cyglink_lib_emitter: target[0]={!r}".format(target[0].get_path())) -def shlib_generator(target, source, env, for_signature): - return _lib_generator(target, source, env, for_signature, - varprefix='SHLIB', - cmd = SCons.Util.CLVar(['$SHLINK'])) + if not no_import_lib: + # Specify import lib and add to targets -def ldmod_generator(target, source, env, for_signature): - return _lib_generator(target, source, env, for_signature, - varprefix='LDMODULE', - cmd = SCons.Util.CLVar(['$LDMODULE'])) + import_lib = env.subst('$%s_IMPLIBNAME' % var_prefix, target=target, source=source) + import_lib_target = env.fs.File(import_lib) + import_lib_target.attributes.shared = 1 + target.append(import_lib_target) -def _lib_emitter(target, source, env, **kw): - Verbose = False + if verbose: + print("cyglink_lib_emitter: import_lib={}".format(import_lib)) + print("cyglink_lib_emitter: target=%s" % target) - if Verbose: - print("_lib_emitter: target[0]=%r" % target[0].get_path()) + for tgt in target: + if is_String(tgt): + tgt = env.File(tgt) + tgt.attributes.shared = 1 - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' + return target, source - 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) +def cyglink_ldmodule_emitter(target, source, env, **kw): + return cyglink_lib_emitter(target, source, env, variable_prefix='LDMODULE') - if Verbose: - print("_lib_emitter: dll=%r" % dll.get_path()) - if not dll or len(target) > 1: - raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) +def cyglink_shlib_symlink_emitter(target, source, env, **kw): + """ + On cygwin, we only create a symlink from the non-versioned implib to the versioned implib. + We don't version the shared library itself. + :param target: + :param source: + :param env: + :param kw: + :return: + """ + verbose = True - # 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 'variable_prefix' in kw: + var_prefix = kw['variable_prefix'] + else: + var_prefix = 'SHLIB' - if Verbose: - print("_lib_emitter: dll.name=%r" % dll.name) + no_import_lib = env.get('no_import_lib', False) + if no_import_lib in ['1', 'True', 'true', True]: + if verbose: + print("cyglink_shlib_symlink_emitter: no_import_lib=%s" % no_import_lib) + return target, source - orig_target = target - target = [env.fs.File(dll)] - target[0].attributes.shared = 1 + no_symlinks = env.subst('$%sNOVERSIONSYMLINKS' % var_prefix) + if no_symlinks in ['1', 'True', 'true', True]: + return target, source - if Verbose: - print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path()) + shlibversion = env.subst('$%sVERSION' % var_prefix) + if shlibversion: + if verbose: + print("cyglink_shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion)) - # Append an import lib target - if not no_import_lib: - # Create list of target libraries as strings - target_strings = env.ReplaceIxes(orig_target[0], - '%sPREFIX' % vp, '%sSUFFIX' % vp, - 'IMPLIBPREFIX', 'IMPLIBSUFFIX') - if Verbose: - print("_lib_emitter: target_strings=%r" % target_strings) - - implib_target = env.fs.File(target_strings) - if Verbose: - print("_lib_emitter: implib_target=%r" % implib_target.get_path()) - implib_target.attributes.shared = 1 - target.append(implib_target) - - symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') - if Verbose: - print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) - if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) - implib_target.attributes.shliblinks = symlinks - - return (target, source) - -def shlib_emitter(target, source, env): - return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib') - -def ldmod_emitter(target, source, env): - return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod') - -def _versioned_lib_suffix(env, suffix, version): - """Generate versioned shared library suffix from a unversioned one. - If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'""" - Verbose = False - if Verbose: - print("_versioned_lib_suffix: suffix= ", suffix) - print("_versioned_lib_suffix: version= ", version) - cygversion = re.sub(r'\.', '-', version) - if not suffix.startswith('-' + cygversion): - suffix = '-' + cygversion + suffix - if Verbose: - print("_versioned_lib_suffix: return suffix= ", suffix) - return suffix - -def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw): - return link._versioned_lib_name(env, libnode, version, prefix, suffix, - SCons.Tool.ImpLibPrefixGenerator, - SCons.Tool.ImpLibSuffixGenerator, - implib_libtype=kw['libtype']) - -def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): - """Generate link names that should be created for a versioned shared library. - Returns a list in the form [ (link, linktarget), ... ] - """ - Verbose = False + # The implib (added by the cyglink_lib_emitter) + imp_lib_node = target[1] + shlib_noversion_symlink = env.subst('$%s_NOVERSION_SYMLINK' % var_prefix, target=target[0], source=source) + + if verbose: + print("cyglink_shlib_symlink_emitter: shlib_noversion_symlink :%s" % shlib_noversion_symlink) + print("cyglink_shlib_symlink_emitter: imp_lib_node :%s" % imp_lib_node) + + symlinks = [(env.File(shlib_noversion_symlink), imp_lib_node)] + + if verbose: + print("cyglink_shlib_symlink_emitter: symlinks={!r}".format( + ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]) + )) + + if symlinks: + # This does the actual symlinking + EmitLibSymlinks(env, symlinks, target[0]) + + # This saves the information so if the versioned shared library is installed + # it can faithfully reproduce the correct symlinks + target[0].attributes.shliblinks = symlinks - if Verbose: - print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path()) - print("_versioned_implib_symlinks: version=%r" % version) + return target, source - try: libtype = kw['libtype'] - except KeyError: libtype = 'ShLib' +def cyglink_ldmod_symlink_emitter(target, source, env, **kw): + return cyglink_shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE') - linkdir = os.path.dirname(libnode.get_path()) - if Verbose: - print("_versioned_implib_symlinks: linkdir=%r" % linkdir) - name = SCons.Tool.ImpLibNameGenerator(env, libnode, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') - if Verbose: - print("_versioned_implib_symlinks: name=%r" % name) +def cyglink_shlibversion(target, source, env, for_signature): + var_prefix = 'SHLIB' + var = '%sVERSION' % var_prefix + if var not in env: + return '' - major = version.split('.')[0] + version = env.subst("$%s" % var, target=target, source=source) + version = version.replace('.', '-') + return "." + version - link0 = env.fs.File(os.path.join(linkdir, name)) - symlinks = [(link0, libnode)] - if Verbose: - print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) +def cyglink_ldmodule_version(target, source, env, for_signature): + var_prefix = 'LDMODULE' + var = '%sVERSION' % var_prefix + if var not in env: + return '' - return symlinks + version = env.subst("$%s" % var, target=target, source=source) + version = version.replace('.', '-') + return "." + version + + +def _implib_pre_flags(target, source, env, for_signature): + no_import_lib = env.get('no_import_lib', False) + if no_import_lib in ['1', 'True', 'true', True]: + return '' + else: + return '-Wl,--out-implib=${TARGETS[1]} -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive' + + +def _implib_post_flags(target, source, env, for_signature): + no_import_lib = env.get('no_import_lib', False) + if no_import_lib in ['1', 'True', 'true', True]: + return '' + else: + return '-Wl,--no-whole-archive' -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'] = CLVar('-Wl,-no-undefined') - env['SHLINKCOM'] = shlib_action - env['LDMODULECOM'] = ldmod_action - env.Append(SHLIBEMITTER = [shlib_emitter]) - env.Append(LDMODULEEMITTER = [ldmod_emitter]) + env['SHLIBPREFIX'] = 'cyg' + env['SHLIBSUFFIX'] = '.dll' - env['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' - # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink... + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + + env['_IMPLIB_PRE_SOURCES'] = _implib_pre_flags + env['_IMPLIB_POST_SOURCES'] = _implib_post_flags + env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH ' \ + '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['LDMODULECOM'] = '$LDMODULE -o $TARGET $SHLINKFLAGS $__LDMODULEVERSIONFLAGS $__RPATH ' \ + '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + + # Overwrite emitters. Cyglink does things differently when creating symlinks + env['SHLIBEMITTER'] = [cyglink_lib_emitter, cyglink_shlib_symlink_emitter] + env['LDMODULEEMITTER'] = [cyglink_ldmodule_emitter, cyglink_ldmod_symlink_emitter] + + # This is the non versioned shlib filename + # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME + env['SHLIB_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_shlib_stem${IMPLIBSUFFIX}' + env['LDMODULE_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${IMPLIBSUFFIX}' + + env['SHLIB_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_shlib_stem${_SHLIB_IMPLIBSUFFIX}' + env['LDMODULE_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${_LDMODULE_IMPLIBSUFFIX}' + + env['_cyglink_shlibversion'] = cyglink_shlibversion + env['_SHLIB_IMPLIBSUFFIX'] = '${_cyglink_shlibversion}${IMPLIBSUFFIX}' + env['_SHLIBSUFFIX'] = '${_cyglink_shlibversion}${SHLIBSUFFIX}' - # 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'), - } + env['_cyglink_ldmodule_version'] = cyglink_ldmodule_version + env['_LDMODULESUFFIX'] = '${_cyglink_ldmodule_version}${LDMODULESUFFIX}' + env['_LDMODULE_IMPLIBSUFFIX'] = '${_cyglink_ldmodule_version}${IMPLIBSUFFIX}' + + # Remove variables set by default initialization which aren't needed/used by cyglink # 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 + for rv in ['_SHLIBSONAME', '_LDMODULESONAME']: + if rv in env: + del env[rv] + def exists(env): return gnulink.exists(env) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/SCons/Tool/DCommon.py scons-4.4.0+dfsg/SCons/Tool/DCommon.py --- scons-4.0.1+dfsg/SCons/Tool/DCommon.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/DCommon.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,13 +1,6 @@ -"""SCons.Tool.DCommon - -Common code for the various D tools. - -Coded by Russel Winder (russel@winder.org.uk) -2012-09-06 -""" - +# 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,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__" +"""SCons.Tool.DCommon + +Common code for the various D tools. + +Coded by Russel Winder (russel@winder.org.uk) +2012-09-06 +""" import os.path @@ -59,7 +57,6 @@ env.Clean(target[0], str(target[0]) + '.o') return target, source - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/SCons/Tool/DCommon.xml scons-4.4.0+dfsg/SCons/Tool/DCommon.xml --- scons-4.0.1+dfsg/SCons/Tool/DCommon.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/DCommon.xml 2022-07-30 21:48:28.000000000 +0000 @@ -257,14 +257,6 @@ - - - -DShLibSonameGenerator. - - - - @@ -319,18 +311,13 @@ - - - -SHDLIBVERSION. - - - -SHDLIBVERSIONFLAGS. +Extra flags added to &cv-link-SHDLINKCOM; when building versioned +&b-link-SharedLibrary;. These flags are only used when &cv-link-SHLIBVERSION; is +set. diff -Nru scons-4.0.1+dfsg/SCons/Tool/default.xml scons-4.4.0+dfsg/SCons/Tool/default.xml --- scons-4.0.1+dfsg/SCons/Tool/default.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/default.xml 2022-07-30 21:48:28.000000000 +0000 @@ -41,67 +41,79 @@ Some tools will not initialize if an underlying command is not found, and some tools are selected from a list of choices on a first-found basis. The finished tool list can be -examined by inspecting the TOOLS &consvar; +examined by inspecting the &cv-link-TOOLS; &consvar; in the &consenv;. -On all platforms, all tools from the following list -are selected whose respective conditions are met: -filesystem, wix, lex, yacc, rpcgen, swig, -jar, javac, javah, rmic, dvipdf, dvips, gs, -tex, latex, pdflatex, pdftex, tar, zip, textfile. +On all platforms, the tools from the following list +are selected if their respective conditions are met: + filesystem;, + wix, +&t-link-lex;, &t-link-yacc;, +&t-link-rpcgen;, &t-link-swig;, +&t-link-jar;, &t-link-javac;, &t-link-javah;, &t-link-rmic;, +&t-link-dvipdf;, &t-link-dvips;, &t-link-gs;, +&t-link-tex;, &t-link-latex;, &t-link-pdflatex;, &t-link-pdftex;, +&t-link-tar;, &t-link-zip;, &t-link-textfile;. On Linux systems, the default tools list selects (first-found): a C compiler from -gcc, intelc, icc, cc; +&t-link-gcc;, &t-link-intelc;, &t-link-icc;, &t-link-cc;; a C++ compiler from -g++, intelc, icc, cxx; +&t-link-gXX;, &t-link-intelc;, &t-link-icc;, &t-link-cXX;; an assembler from -gas, nasm, masm; +&t-link-gas;, &t-link-nasm;, &t-link-masm;; a linker from -gnulink, ilink; +&t-link-gnulink;, &t-link-ilink;; a Fortran compiler from -gfortran, g77, ifort, ifl, f95, f90, f77; -and a static archiver 'ar'. +&t-link-gfortran;, &t-link-g77;, &t-link-ifort;, &t-link-ifl;, +&t-link-f95;, &t-link-f90;, &t-link-f77;; +and a static archiver &t-link-ar;. It also selects all found from the list -m4, rpm. +&t-link-m4; + rpm. On Windows systems, the default tools list selects (first-found): a C compiler from -msvc, mingw, gcc, intelc, icl, icc, cc, bcc32; +&t-link-msvc;, &t-link-mingw;, &t-link-gcc;, &t-link-intelc;, +&t-link-icl;, &t-link-icc;, &t-link-cc;, &t-link-bcc32;; a C++ compiler from -msvc, intelc, icc, g++, cxx, bcc32; +&t-link-msvc;, &t-link-intelc;, &t-link-icc;, &t-link-gXX;, +&t-link-cXX;, &t-link-bcc32;; an assembler from -masm, nasm, gas, 386asm; +&t-link-masm;, &t-link-nasm;, &t-link-gas;, &t-link-386asm;; a linker from -mslink, gnulink, ilink, linkloc, ilink32; +&t-link-mslink;, &t-link-gnulink;, &t-link-ilink;, +&t-link-linkloc;, &t-link-ilink32;; a Fortran compiler from -gfortran, g77, ifl, cvf, f95, f90, fortran; +&t-link-gfortran;, &t-link-g77;, &t-link-ifl;, &t-link-cvf;, +&t-link-f95;, &t-link-f90;, &t-link-fortran;; and a static archiver from -mslib, ar, tlib; +&t-link-mslib;, &t-link-ar;, &t-link-tlib;; It also selects all found from the list -msvs, midl. +&t-link-msvs;, &t-link-midl;. On MacOS systems, the default tools list selects (first-found): a C compiler from -gcc, cc; +&t-link-gcc;, &t-link-cc;; a C++ compiler from -g++, cxx; -an assembler 'as'; +&t-link-gXX;, &t-link-cXX;; +an assembler &t-link-as;; a linker from -applelink, gnulink; +&t-link-applelink;, &t-link-gnulink;; a Fortran compiler from -gfortran, f95, f90, g77; -and a static archiver ar. +&t-link-gfortran;, &t-link-f95;, &t-link-f90;, &t-link-g77;; +and a static archiver &t-link-ar;. It also selects all found from the list -m4, rpm. +&t-link-m4;, + rpm. diff -Nru scons-4.0.1+dfsg/SCons/Tool/dmd.py scons-4.4.0+dfsg/SCons/Tool/dmd.py --- scons-4.0.1+dfsg/SCons/Tool/dmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/dmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -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.Tool.dmd Tool-specific initialization for the Digital Mars D compiler. @@ -49,33 +72,6 @@ """ -# -# __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 subprocess import SCons.Action import SCons.Builder @@ -128,7 +124,8 @@ 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 +136,8 @@ 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__)}' @@ -153,15 +151,7 @@ env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' # Support for versioned libraries - env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME' - 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 - # NOTE: this is only for further reference, currently $SHDLIBVERSION does - # not work, the user must use $SHLIBVERSION - env['SHDLIBVERSION'] = '$SHLIBVERSION' - env['SHDLIBVERSIONFLAGS'] = [] + env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHLIBSONAME' env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder( action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS', @@ -172,7 +162,6 @@ def exists(env): return env.Detect(['dmd', 'ldmd2', 'gdmd']) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/SCons/Tool/dmd.xml scons-4.4.0+dfsg/SCons/Tool/dmd.xml --- scons-4.0.1+dfsg/SCons/Tool/dmd.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/dmd.xml 2022-07-30 21:48:28.000000000 +0000 @@ -65,8 +65,6 @@ DLINKFLAGSUFFIX DRPATHPREFIX DRPATHSUFFIX -DShLibSonameGenerator -SHDLIBVERSION SHDLIBVERSIONFLAGS diff -Nru scons-4.0.1+dfsg/SCons/Tool/docbook/docbook.xml scons-4.4.0+dfsg/SCons/Tool/docbook/docbook.xml --- scons-4.0.1+dfsg/SCons/Tool/docbook/docbook.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/docbook/docbook.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,609 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + +This tool tries to make working with Docbook in SCons a little easier. +It provides several toolchains for creating different output formats, +like HTML or PDF. Contained in the package is +a distribution of the Docbook XSL stylesheets as of version 1.76.1. +As long as you don't specify your own stylesheets for customization, +these official versions are picked as default...which should reduce +the inevitable setup hassles for you. + +Implicit dependencies to images and XIncludes are detected automatically +if you meet the HTML requirements. The additional +stylesheet utils/xmldepend.xsl by Paul DuBois is used for this purpose. + +Note, that there is no support for XML catalog resolving offered! This tool calls +the XSLT processors and PDF renderers with the stylesheets you specified, that's it. +The rest lies in your hands and you still have to know what you're doing when +resolving names via a catalog. + +For activating the tool "docbook", you have to add its name to the Environment constructor, +like this + +env = Environment(tools=['docbook']) + +On its startup, the &t-docbook; tool tries to find a required xsltproc processor, and +a PDF renderer, e.g. fop. So make sure that these are added to your system's environment +PATH and can be called directly without specifying their full path. + +For the most basic processing of Docbook to HTML, you need to have installed + +the Python lxml +binding to libxml2, or + +a standalone XSLT processor, currently detected are xsltproc, saxon, saxon-xslt +and xalan. + + + +Rendering to PDF requires you to have one of the applications +fop or xep installed. + + +Creating a HTML or PDF document is very simple and straightforward. Say + +env = Environment(tools=['docbook']) +env.DocbookHtml('manual.html', 'manual.xml') +env.DocbookPdf('manual.pdf', 'manual.xml') + +to get both outputs from your XML source manual.xml. As a shortcut, you can +give the stem of the filenames alone, like this: + +env = Environment(tools=['docbook']) +env.DocbookHtml('manual') +env.DocbookPdf('manual') + +and get the same result. Target and source lists are also supported: + +env = Environment(tools=['docbook']) +env.DocbookHtml(['manual.html','reference.html'], ['manual.xml','reference.xml']) + +or even + +env = Environment(tools=['docbook']) +env.DocbookHtml(['manual','reference']) + +Whenever you leave out the list of sources, you may not specify a file extension! The +Tool uses the given names as file stems, and adds the suffixes for target and source files +accordingly. + + +The rules given above are valid for the Builders &b-link-DocbookHtml;, +&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the +&b-link-DocbookMan; transformation you +can specify a target name, but the actual output names are automatically +set from the refname entries in your XML source. + + +The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and +&b-link-DocbookSlidesHtml; are special, in that: + +they create a large set of files, where the exact names and their number depend +on the content of the source file, and + + +the main target is always named index.html, i.e. the output name for the +XSL transformation is not picked up by the stylesheets. + + + +As a result, there is simply no use in specifying a target HTML name. +So the basic syntax for these builders is always: + +env = Environment(tools=['docbook']) +env.DocbookHtmlhelp('manual') + + +If you want to use a specific XSL file, you can set the +additional xsl parameter to your +Builder call as follows: + +env.DocbookHtml('other.html', 'manual.xml', xsl='html.xsl') + +Since this may get tedious if you always use the same local naming for your customized XSL files, +e.g. html.xsl for HTML and pdf.xsl for PDF output, a set of +variables for setting the default XSL name is provided. These are: + +DOCBOOK_DEFAULT_XSL_HTML +DOCBOOK_DEFAULT_XSL_HTMLCHUNKED +DOCBOOK_DEFAULT_XSL_HTMLHELP +DOCBOOK_DEFAULT_XSL_PDF +DOCBOOK_DEFAULT_XSL_EPUB +DOCBOOK_DEFAULT_XSL_MAN +DOCBOOK_DEFAULT_XSL_SLIDESPDF +DOCBOOK_DEFAULT_XSL_SLIDESHTML + +and you can set them when constructing your environment: + + +env = Environment( + tools=['docbook'], + DOCBOOK_DEFAULT_XSL_HTML='html.xsl', + DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl', +) +env.DocbookHtml('manual') # now uses html.xsl + + + +DOCBOOK_DEFAULT_XSL_HTML +DOCBOOK_DEFAULT_XSL_HTMLCHUNKED +DOCBOOK_DEFAULT_XSL_HTMLHELP +DOCBOOK_DEFAULT_XSL_PDF +DOCBOOK_DEFAULT_XSL_EPUB +DOCBOOK_DEFAULT_XSL_MAN +DOCBOOK_DEFAULT_XSL_SLIDESPDF +DOCBOOK_DEFAULT_XSL_SLIDESHTML +DOCBOOK_XSLTPROC +DOCBOOK_XMLLINT +DOCBOOK_FOP +DOCBOOK_XSLTPROCFLAGS +DOCBOOK_XMLLINTFLAGS +DOCBOOK_FOPFLAGS +DOCBOOK_XSLTPROCPARAMS +DOCBOOK_XSLTPROCCOM +DOCBOOK_XMLLINTCOM +DOCBOOK_FOPCOM + + +DOCBOOK_XSLTPROCCOMSTR +DOCBOOK_XMLLINTCOMSTR +DOCBOOK_FOPCOMSTR + + + + + + + +The default XSLT file for the &b-link-DocbookHtml; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + + +The default XSLT file for the &b-link-DocbookHtmlChunked; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookHtmlhelp; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookPdf; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookEpub; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookMan; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookSlidesPdf; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The default XSLT file for the &b-link-DocbookSlidesHtml; builder within the +current environment, if no other XSLT gets specified via keyword. + + + + + + + +The path to the external executable xsltproc +(or saxon, xalan), if one of them +is installed. +Note, that this is only used as last fallback for XSL transformations, if +no lxml Python binding can be imported in the current system. + + + + + + + +The path to the external executable xmllint, if it's installed. +Note, that this is only used as last fallback for resolving +XIncludes, if no lxml Python binding can be imported +in the current system. + + + + + + + +The path to the PDF renderer fop or xep, +if one of them is installed (fop gets checked first). + + + + + + + +Additonal command-line flags for the external executable +xsltproc (or saxon, +xalan). + + + + + + + +Additonal command-line flags for the external executable +xmllint. + + + + + + + +Additonal command-line flags for the +PDF renderer fop or xep. + + + + + + + +Additonal parameters that are not intended for the XSLT processor executable, but +the XSL processing itself. By default, they get appended at the end of the command line +for saxon and saxon-xslt, respectively. + + + + + + + +The full command-line for the external executable +xsltproc (or saxon, +xalan). + + + + + + + +The full command-line for the external executable +xmllint. + + + + + + + +The full command-line for the +PDF renderer fop or xep. + + + + + + + +The string displayed when xsltproc is used to transform +an XML file via a given XSLT stylesheet. + + + + + + + +The string displayed when xmllint is used to resolve +XIncludes for a given XML file. + + + + + + + +The string displayed when a renderer like fop or +xep is used to create PDF output from an XML file. + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for HTML output. + +env = Environment(tools=['docbook']) +env.DocbookHtml('manual.html', 'manual.xml') + + +or simply + +env = Environment(tools=['docbook']) +env.DocbookHtml('manual') + + + + + + + +A pseudo-Builder providing a Docbook toolchain for chunked HTML output. +It supports the base.dir parameter. The +chunkfast.xsl file (requires "EXSLT") is used as the +default stylesheet. Basic syntax: + + +env = Environment(tools=['docbook']) +env.DocbookHtmlChunked('manual') + + +where manual.xml is the input file. + +If you use the root.filename +parameter in your own stylesheets you have to specify the new target name. +This ensures that the dependencies get correct, especially for the cleanup via scons -c: + +env = Environment(tools=['docbook']) +env.DocbookHtmlChunked('mymanual.html', 'manual', xsl='htmlchunk.xsl') + +Some basic support for the base.dir parameter +is provided. You can add the base_dir keyword to +your Builder call, and the given prefix gets prepended to all the +created filenames: + +env = Environment(tools=['docbook']) +env.DocbookHtmlChunked('manual', xsl='htmlchunk.xsl', base_dir='output/') + +Make sure that you don't forget the trailing slash for the base folder, else +your files get renamed only! + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for HTMLHELP output. +Its basic syntax is: + + +env = Environment(tools=['docbook']) +env.DocbookHtmlhelp('manual') + + +where manual.xml is the input file. + + +If you use the root.filename +parameter in your own stylesheets you have to specify the new target name. +This ensures that the dependencies get correct, especially for the cleanup via scons -c: + +env = Environment(tools=['docbook']) +env.DocbookHtmlhelp('mymanual.html', 'manual', xsl='htmlhelp.xsl') + +Some basic support for the base.dir parameter +is provided. You can add the base_dir keyword to +your Builder call, and the given prefix gets prepended to all the +created filenames: + +env = Environment(tools=['docbook']) +env.DocbookHtmlhelp('manual', xsl='htmlhelp.xsl', base_dir='output/') + +Make sure that you don't forget the trailing slash for the base folder, else +your files get renamed only! + + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for PDF output. + + +env = Environment(tools=['docbook']) +env.DocbookPdf('manual.pdf', 'manual.xml') + + + +or simply + + +env = Environment(tools=['docbook']) +env.DocbookPdf('manual') + + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for EPUB output. + + +env = Environment(tools=['docbook']) +env.DocbookEpub('manual.epub', 'manual.xml') + + + +or simply + + +env = Environment(tools=['docbook']) +env.DocbookEpub('manual') + + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for Man page output. +Its basic syntax is: + + +env = Environment(tools=['docbook']) +env.DocbookMan('manual') + + +where manual.xml is the input file. Note, that +you can specify a target name, but the actual output names are automatically +set from the refname entries in your XML source. + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for PDF slides output. + + +env = Environment(tools=['docbook']) +env.DocbookSlidesPdf('manual.pdf', 'manual.xml') + + + +or simply + + +env = Environment(tools=['docbook']) +env.DocbookSlidesPdf('manual') + + + + + + + +A pseudo-Builder, providing a Docbook toolchain for HTML slides output. + + +env = Environment(tools=['docbook']) +env.DocbookSlidesHtml('manual') + + +If you use the titlefoil.html parameter in +your own stylesheets you have to give the new target name. This ensures +that the dependencies get correct, especially for the cleanup via +scons -c: + +env = Environment(tools=['docbook']) +env.DocbookSlidesHtml('mymanual.html','manual', xsl='slideshtml.xsl') + + +Some basic support for the base.dir parameter +is provided. You +can add the base_dir keyword to your Builder +call, and the given prefix gets prepended to all the created filenames: + +env = Environment(tools=['docbook']) +env.DocbookSlidesHtml('manual', xsl='slideshtml.xsl', base_dir='output/') + +Make sure that you don't forget the trailing slash for the base folder, else +your files get renamed only! + + + + + + + + +A pseudo-Builder, for resolving XIncludes in a separate processing step. + + +env = Environment(tools=['docbook']) +env.DocbookXInclude('manual_xincluded.xml', 'manual.xml') + + + + + + + +A pseudo-Builder, applying a given XSL transformation to the input file. + + +env = Environment(tools=['docbook']) +env.DocbookXslt('manual_transformed.xml', 'manual.xml', xsl='transform.xslt') + + +Note, that this builder requires the xsl parameter +to be set. + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py scons-4.4.0+dfsg/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py --- scons-4.0.1+dfsg/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Tool/docbook/__init__.py scons-4.4.0+dfsg/SCons/Tool/docbook/__init__.py --- scons-4.0.1+dfsg/SCons/Tool/docbook/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/docbook/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -62,8 +62,20 @@ prefer_xsltproc = False # Regexs for parsing Docbook XML sources of MAN pages -re_manvolnum = re.compile("([^<]*)") -re_refname = re.compile("([^<]*)") +re_manvolnum = re.compile(r"([^<]*)") +re_refname = re.compile(r"([^<]*)") + +# +# lxml etree XSLT global max traversal depth +# + +lmxl_xslt_global_max_depth = 3100 + +if has_lxml and lmxl_xslt_global_max_depth: + def __lxml_xslt_set_global_max_depth(max_depth): + from lxml import etree + etree.XSLT.set_global_max_depth(max_depth) + __lxml_xslt_set_global_max_depth(lmxl_xslt_global_max_depth) # # Helper functions @@ -203,8 +215,8 @@ # # Scanners # -include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']') -sentity_re = re.compile('') +include_re = re.compile(r'fileref\\s*=\\s*["|\']([^\\n]*)["|\']') +sentity_re = re.compile(r'') def __xml_scan(node, env, path, arg): """ Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """ @@ -223,6 +235,7 @@ # Try to call xsltproc xsltproc = env.subst("$DOCBOOK_XSLTPROC") if xsltproc and xsltproc.endswith('xsltproc'): + # TODO: switch to _subproc or subprocess.run call result = env.backtick(' '.join([xsltproc, xsl_file, str(node)])) depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith(" - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - -This tool tries to make working with Docbook in SCons a little easier. -It provides several toolchains for creating different output formats, -like HTML or PDF. Contained in the package is -a distribution of the Docbook XSL stylesheets as of version 1.76.1. -As long as you don't specify your own stylesheets for customization, -these official versions are picked as default...which should reduce -the inevitable setup hassles for you. - -Implicit dependencies to images and XIncludes are detected automatically -if you meet the HTML requirements. The additional -stylesheet utils/xmldepend.xsl by Paul DuBois is used for this purpose. - -Note, that there is no support for XML catalog resolving offered! This tool calls -the XSLT processors and PDF renderers with the stylesheets you specified, that's it. -The rest lies in your hands and you still have to know what you're doing when -resolving names via a catalog. - -For activating the tool "docbook", you have to add its name to the Environment constructor, -like this - -env = Environment(tools=['docbook']) - -On its startup, the Docbook tool tries to find a required xsltproc processor, and -a PDF renderer, e.g. fop. So make sure that these are added to your system's environment -PATH and can be called directly, without specifying their full path. - -For the most basic processing of Docbook to HTML, you need to have installed - -the Python lxml binding to libxml2, or - - -a standalone XSLT processor, currently detected are xsltproc, saxon, saxon-xslt -and xalan. - - - -Rendering to PDF requires you to have one of the applications -fop or xep installed. - - -Creating a HTML or PDF document is very simple and straightforward. Say - -env = Environment(tools=['docbook']) -env.DocbookHtml('manual.html', 'manual.xml') -env.DocbookPdf('manual.pdf', 'manual.xml') - -to get both outputs from your XML source manual.xml. As a shortcut, you can -give the stem of the filenames alone, like this: - -env = Environment(tools=['docbook']) -env.DocbookHtml('manual') -env.DocbookPdf('manual') - -and get the same result. Target and source lists are also supported: - -env = Environment(tools=['docbook']) -env.DocbookHtml(['manual.html','reference.html'], ['manual.xml','reference.xml']) - -or even - -env = Environment(tools=['docbook']) -env.DocbookHtml(['manual','reference']) - -Whenever you leave out the list of sources, you may not specify a file extension! The -Tool uses the given names as file stems, and adds the suffixes for target and source files -accordingly. - - -The rules given above are valid for the Builders &b-link-DocbookHtml;, -&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the -&b-link-DocbookMan; transformation you -can specify a target name, but the actual output names are automatically -set from the refname entries in your XML source. - - -The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and -&b-link-DocbookSlidesHtml; are special, in that: - -they create a large set of files, where the exact names and their number depend -on the content of the source file, and - - -the main target is always named index.html, i.e. the output name for the -XSL transformation is not picked up by the stylesheets. - - - -As a result, there is simply no use in specifying a target HTML name. -So the basic syntax for these builders is always: - -env = Environment(tools=['docbook']) -env.DocbookHtmlhelp('manual') - - -If you want to use a specific XSL file, you can set the -additional xsl parameter to your -Builder call as follows: - -env.DocbookHtml('other.html', 'manual.xml', xsl='html.xsl') - -Since this may get tedious if you always use the same local naming for your customized XSL files, -e.g. html.xsl for HTML and pdf.xsl for PDF output, a set of -variables for setting the default XSL name is provided. These are: - -DOCBOOK_DEFAULT_XSL_HTML -DOCBOOK_DEFAULT_XSL_HTMLCHUNKED -DOCBOOK_DEFAULT_XSL_HTMLHELP -DOCBOOK_DEFAULT_XSL_PDF -DOCBOOK_DEFAULT_XSL_EPUB -DOCBOOK_DEFAULT_XSL_MAN -DOCBOOK_DEFAULT_XSL_SLIDESPDF -DOCBOOK_DEFAULT_XSL_SLIDESHTML - -and you can set them when constructing your environment: - -env = Environment(tools=['docbook'], - DOCBOOK_DEFAULT_XSL_HTML='html.xsl', - DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl') -env.DocbookHtml('manual') # now uses html.xsl - - - -DOCBOOK_DEFAULT_XSL_HTML -DOCBOOK_DEFAULT_XSL_HTMLCHUNKED -DOCBOOK_DEFAULT_XSL_HTMLHELP -DOCBOOK_DEFAULT_XSL_PDF -DOCBOOK_DEFAULT_XSL_EPUB -DOCBOOK_DEFAULT_XSL_MAN -DOCBOOK_DEFAULT_XSL_SLIDESPDF -DOCBOOK_DEFAULT_XSL_SLIDESHTML -DOCBOOK_XSLTPROC -DOCBOOK_XMLLINT -DOCBOOK_FOP -DOCBOOK_XSLTPROCFLAGS -DOCBOOK_XMLLINTFLAGS -DOCBOOK_FOPFLAGS -DOCBOOK_XSLTPROCPARAMS -DOCBOOK_XSLTPROCCOM -DOCBOOK_XMLLINTCOM -DOCBOOK_FOPCOM - - -DOCBOOK_XSLTPROCCOMSTR -DOCBOOK_XMLLINTCOMSTR -DOCBOOK_FOPCOMSTR - - - - - - - -The default XSLT file for the &b-link-DocbookHtml; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - - -The default XSLT file for the &b-link-DocbookHtmlChunked; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookHtmlhelp; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookPdf; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookEpub; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookMan; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookSlidesPdf; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The default XSLT file for the &b-link-DocbookSlidesHtml; builder within the -current environment, if no other XSLT gets specified via keyword. - - - - - - - -The path to the external executable xsltproc -(or saxon, xalan), if one of them -is installed. -Note, that this is only used as last fallback for XSL transformations, if -no lxml Python binding can be imported in the current system. - - - - - - - -The path to the external executable xmllint, if it's installed. -Note, that this is only used as last fallback for resolving -XIncludes, if no lxml Python binding can be imported -in the current system. - - - - - - - -The path to the PDF renderer fop or xep, -if one of them is installed (fop gets checked first). - - - - - - - -Additonal command-line flags for the external executable -xsltproc (or saxon, -xalan). - - - - - - - -Additonal command-line flags for the external executable -xmllint. - - - - - - - -Additonal command-line flags for the -PDF renderer fop or xep. - - - - - - - -Additonal parameters that are not intended for the XSLT processor executable, but -the XSL processing itself. By default, they get appended at the end of the command line -for saxon and saxon-xslt, respectively. - - - - - - - -The full command-line for the external executable -xsltproc (or saxon, -xalan). - - - - - - - -The full command-line for the external executable -xmllint. - - - - - - - -The full command-line for the -PDF renderer fop or xep. - - - - - - - -The string displayed when xsltproc is used to transform -an XML file via a given XSLT stylesheet. - - - - - - - -The string displayed when xmllint is used to resolve -XIncludes for a given XML file. - - - - - - - -The string displayed when a renderer like fop or -xep is used to create PDF output from an XML file. - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for HTML output. - -env = Environment(tools=['docbook']) -env.DocbookHtml('manual.html', 'manual.xml') - - -or simply - -env = Environment(tools=['docbook']) -env.DocbookHtml('manual') - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for chunked HTML output. -It supports the base.dir parameter. The -chunkfast.xsl file (requires "EXSLT") is used as the -default stylesheet. Basic syntax: - - -env = Environment(tools=['docbook']) -env.DocbookHtmlChunked('manual') - - -where manual.xml is the input file. - -If you use the root.filename -parameter in your own stylesheets you have to specify the new target name. -This ensures that the dependencies get correct, especially for the cleanup via scons -c: - -env = Environment(tools=['docbook']) -env.DocbookHtmlChunked('mymanual.html', 'manual', xsl='htmlchunk.xsl') - -Some basic support for the base.dir is provided. You -can add the base_dir keyword to your Builder -call, and the given prefix gets prepended to all the created filenames: - -env = Environment(tools=['docbook']) -env.DocbookHtmlChunked('manual', xsl='htmlchunk.xsl', base_dir='output/') - -Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for HTMLHELP output. -Its basic syntax is: - - -env = Environment(tools=['docbook']) -env.DocbookHtmlhelp('manual') - - -where manual.xml is the input file. - - -If you use the root.filename -parameter in your own stylesheets you have to specify the new target name. -This ensures that the dependencies get correct, especially for the cleanup via scons -c: - -env = Environment(tools=['docbook']) -env.DocbookHtmlhelp('mymanual.html', 'manual', xsl='htmlhelp.xsl') - -Some basic support for the base.dir parameter -is provided. You can add the base_dir keyword to -your Builder call, and the given prefix gets prepended to all the -created filenames: - -env = Environment(tools=['docbook']) -env.DocbookHtmlhelp('manual', xsl='htmlhelp.xsl', base_dir='output/') - -Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! - - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for PDF output. - - -env = Environment(tools=['docbook']) -env.DocbookPdf('manual.pdf', 'manual.xml') - - - -or simply - - -env = Environment(tools=['docbook']) -env.DocbookPdf('manual') - - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for EPUB output. - - -env = Environment(tools=['docbook']) -env.DocbookEpub('manual.epub', 'manual.xml') - - - -or simply - - -env = Environment(tools=['docbook']) -env.DocbookEpub('manual') - - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for Man page output. -Its basic syntax is: - - -env = Environment(tools=['docbook']) -env.DocbookMan('manual') - - -where manual.xml is the input file. Note, that -you can specify a target name, but the actual output names are automatically -set from the refname entries in your XML source. - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for PDF slides output. - - -env = Environment(tools=['docbook']) -env.DocbookSlidesPdf('manual.pdf', 'manual.xml') - - - -or simply - - -env = Environment(tools=['docbook']) -env.DocbookSlidesPdf('manual') - - - - - - - -A pseudo-Builder, providing a Docbook toolchain for HTML slides output. - - -env = Environment(tools=['docbook']) -env.DocbookSlidesHtml('manual') - - -If you use the titlefoil.html parameter in -your own stylesheets you have to give the new target name. This ensures -that the dependencies get correct, especially for the cleanup via -scons -c: - -env = Environment(tools=['docbook']) -env.DocbookSlidesHtml('mymanual.html','manual', xsl='slideshtml.xsl') - - -Some basic support for the base.dir parameter -is provided. You -can add the base_dir keyword to your Builder -call, and the given prefix gets prepended to all the created filenames: - -env = Environment(tools=['docbook']) -env.DocbookSlidesHtml('manual', xsl='slideshtml.xsl', base_dir='output/') - -Make sure that you don't forget the trailing slash for the base folder, else -your files get renamed only! - - - - - - - - -A pseudo-Builder, for resolving XIncludes in a separate processing step. - - -env = Environment(tools=['docbook']) -env.DocbookXInclude('manual_xincluded.xml', 'manual.xml') - - - - - - - -A pseudo-Builder, applying a given XSL transformation to the input file. - - -env = Environment(tools=['docbook']) -env.DocbookXslt('manual_transformed.xml', 'manual.xml', xsl='transform.xslt') - - -Note, that this builder requires the xsl parameter -to be set. - - - - - diff -Nru scons-4.0.1+dfsg/SCons/Tool/dvipdf.py scons-4.4.0+dfsg/SCons/Tool/dvipdf.py --- scons-4.0.1+dfsg/SCons/Tool/dvipdf.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/dvipdf.py 2022-07-30 21:48:28.000000000 +0000 @@ -111,9 +111,6 @@ env['DVIPDFFLAGS'] = SCons.Util.CLVar('') env['DVIPDFCOM'] = 'cd ${TARGET.dir} && $DVIPDF $DVIPDFFLAGS ${SOURCE.file} ${TARGET.file}' - # Deprecated synonym. - env['PDFCOM'] = ['$DVIPDFCOM'] - def exists(env): SCons.Tool.tex.generate_darwin(env) return env.Detect('dvipdf') diff -Nru scons-4.0.1+dfsg/SCons/Tool/dvipdf.xml scons-4.4.0+dfsg/SCons/Tool/dvipdf.xml --- scons-4.0.1+dfsg/SCons/Tool/dvipdf.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/dvipdf.xml 2022-07-30 21:48:28.000000000 +0000 @@ -73,12 +73,4 @@ - - - -A deprecated synonym for &cv-link-DVIPDFCOM;. - - - - diff -Nru scons-4.0.1+dfsg/SCons/Tool/dvi.xml scons-4.4.0+dfsg/SCons/Tool/dvi.xml --- scons-4.0.1+dfsg/SCons/Tool/dvi.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/dvi.xml 2022-07-30 21:48:28.000000000 +0000 @@ -26,7 +26,7 @@ -Attaches the &b-DVI; builder to the +Attaches the &b-link-DVI; builder to the construction environment. diff -Nru scons-4.0.1+dfsg/SCons/Tool/f03.py scons-4.4.0+dfsg/SCons/Tool/f03.py --- scons-4.0.1+dfsg/SCons/Tool/f03.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/f03.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.f03 - -Tool-specific initialization for the generic Posix f03 Fortran compiler. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# 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,14 +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__" +"""Tool-specific initialization for the generic Posix f03 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" -import SCons.Defaults -import SCons.Tool -import SCons.Util -from . import fortran from SCons.Tool.FortranCommon import add_all_to_env, add_f03_to_env compilers = ['f03'] diff -Nru scons-4.0.1+dfsg/SCons/Tool/f03.xml scons-4.4.0+dfsg/SCons/Tool/f03.xml --- scons-4.0.1+dfsg/SCons/Tool/f03.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/f03.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Builds a C source file given a lex (.l) -or yacc (.y) input file. -The suffix specified by the &cv-link-CFILESUFFIX; &consvar; -(.c by default) -is automatically added to the target -if it is not already present. -Example: - - - -# builds foo.c -env.CFile(target = 'foo.c', source = 'foo.l') -# builds bar.c -env.CFile(target = 'bar', source = 'bar.y') - - - - - - - -Builds a C++ source file given a lex (.ll) -or yacc (.yy) -input file. -The suffix specified by the &cv-link-CXXFILESUFFIX; &consvar; -(.cc by default) -is automatically added to the target -if it is not already present. -Example: - - - -# builds foo.cc -env.CXXFile(target = 'foo.cc', source = 'foo.ll') -# builds bar.cc -env.CXXFile(target = 'bar', source = 'bar.yy') - - - - - - - -A synonym for the -&b-StaticLibrary; -builder method. - - - - - - - -On most systems, -this is the same as -&b-SharedLibrary;. -On Mac OS X (Darwin) platforms, -this creates a loadable module bundle. - - - - - - - -A synonym for the -&b-StaticObject; -builder method. - - - - - - - -Builds an executable given one or more object files -or C, C++, D, or Fortran source files. -If any C, C++, D or Fortran source files are specified, -then they will be automatically -compiled to object files using the -&b-Object; -builder method; -see that builder method's description for -a list of legal source file suffixes -and how they are interpreted. -The target executable file prefix, -specified by the &cv-link-PROGPREFIX; &consvar; -(nothing by default), -and suffix, -specified by the &cv-link-PROGSUFFIX; &consvar; -(by default, .exe on Windows systems, -nothing on POSIX systems), -are automatically added to the target if not already present. -Example: - - - -env.Program(target='foo', source=['foo.o', 'bar.c', 'baz.f']) - - - - - - - -Builds a shared library -(.so on a POSIX system, -.dll on Windows) -given one or more object files -or C, C++, D or Fortran source files. -If any source files are given, -then they will be automatically -compiled to object files. -The target library file prefix, -specified by the &cv-link-SHLIBPREFIX; &consvar; -(by default, lib on POSIX systems, -nothing on Windows systems), -and suffix, -specified by the &cv-link-SHLIBSUFFIX; &consvar; -(by default, .dll on Windows systems, -.so on POSIX systems), -are automatically added to the target if not already present. -Example: - - - -env.SharedLibrary(target='bar', source=['bar.c', 'foo.o']) - - - -On Windows systems, the -&b-SharedLibrary; -builder method will always build an import library -(.lib) -in addition to the shared library (.dll), -adding a .lib library with the same basename -if there is not already a .lib file explicitly -listed in the targets. - - - -On Cygwin systems, the -&b-SharedLibrary; -builder method will always build an import library -(.dll.a) -in addition to the shared library (.dll), -adding a .dll.a library with the same basename -if there is not already a .dll.a file explicitly -listed in the targets. - - - -Any object files listed in the -source -must have been built for a shared library -(that is, using the -&b-SharedObject; -builder method). -&scons; -will raise an error if there is any mismatch. - - - -On some platforms, there is a distinction between a shared library -(loaded automatically by the system to resolve external references) -and a loadable module (explicitly loaded by user action). -For maximum portability, use the &b-link-LoadableModule; builder for the latter. - - - -When the &cv-link-SHLIBVERSION; &consvar; is defined, a versioned -shared library is created. This modifies &cv-link-SHLINKFLAGS; as required, -adds the version number to the library name, and creates any -symbolic links that are needed. - - - -env.SharedLibrary(target='bar', source=['bar.c', 'foo.o'], SHLIBVERSION='1.5.2') - - - -On a POSIX system, versions with a single token create exactly one symlink: -libbar.so.6 would have symlink libbar.so only. -On a POSIX system, versions with two or more -tokens create exactly two symlinks: libbar.so.2.3.1 would have symlinks -libbar.so and libbar.so.2; on a Darwin (OSX) system the library would be -libbar.2.3.1.dylib and the link would be libbar.dylib. - - - -On Windows systems, specifying -register=1 -will cause the .dll to be -registered after it is built. -The command that is run is determined by the &cv-link-REGSVR; &consvar; -(regsvr32 by default), -and the flags passed are determined by &cv-link-REGSVRFLAGS;. By -default, &cv-link-REGSVRFLAGS; includes the option, -to prevent dialogs from popping -up and requiring user attention when it is run. If you change -&cv-link-REGSVRFLAGS;, be sure to include the option. -For example, - - - -env.SharedLibrary(target='bar', source=['bar.cxx', 'foo.obj'], register=1) - - - -will register bar.dll as a COM object -when it is done linking it. - - - - - - - -Builds an object file intended for -inclusion in a shared library. -Source files must have one of the same set of extensions -specified above for the -&b-StaticObject; -builder method. -On some platforms building a shared object requires additional -compiler option -(e.g. for gcc) -in addition to those needed to build a -normal (static) object, but on some platforms there is no difference between a -shared object and a normal (static) one. When there is a difference, SCons -will only allow shared objects to be linked into a shared library, and will -use a different suffix for shared objects. On platforms where there is no -difference, SCons will allow both normal (static) -and shared objects to be linked into a -shared library, and will use the same suffix for shared and normal -(static) objects. -The target object file prefix, -specified by the &cv-link-SHOBJPREFIX; &consvar; -(by default, the same as &cv-link-OBJPREFIX;), -and suffix, -specified by the &cv-link-SHOBJSUFFIX; &consvar;, -are automatically added to the target if not already present. -Examples: - - - -env.SharedObject(target='ddd', source='ddd.c') -env.SharedObject(target='eee.o', source='eee.cpp') -env.SharedObject(target='fff.obj', source='fff.for') - - - -Note that the source files will be scanned -according to the suffix mappings in the -SourceFileScanner -object. -See the section "Scanner Objects," -below, for more information. - - - - - - - -Builds a static library given one or more object files -or C, C++, D or Fortran source files. -If any source files are given, -then they will be automatically -compiled to object files. -The static library file prefix, -specified by the &cv-link-LIBPREFIX; &consvar; -(by default, lib on POSIX systems, -nothing on Windows systems), -and suffix, -specified by the &cv-link-LIBSUFFIX; &consvar; -(by default, .lib on Windows systems, -.a on POSIX systems), -are automatically added to the target if not already present. -Example: - - - -env.StaticLibrary(target='bar', source=['bar.c', 'foo.o']) - - - -Any object files listed in the -source -must have been built for a static library -(that is, using the -&b-StaticObject; -builder method). -&scons; -will raise an error if there is any mismatch. - - - - - - - -Builds a static object file -from one or more C, C++, D, or Fortran source files. -Source files must have one of the following extensions: - - - - .asm assembly language file - .ASM assembly language file - .c C file - .C Windows: C file - POSIX: C++ file - .cc C++ file - .cpp C++ file - .cxx C++ file - .cxx C++ file - .c++ C++ file - .C++ C++ file - .d D file - .f Fortran file - .F Windows: Fortran file - POSIX: Fortran file + C pre-processor - .for Fortran file - .FOR Fortran file - .fpp Fortran file + C pre-processor - .FPP Fortran file + C pre-processor - .m Object C file - .mm Object C++ file - .s assembly language file - .S Windows: assembly language file - ARM: CodeSourcery Sourcery Lite - .sx assembly language file + C pre-processor - POSIX: assembly language file + C pre-processor - .spp assembly language file + C pre-processor - .SPP assembly language file + C pre-processor - - - -The target object file prefix, -specified by the &cv-link-OBJPREFIX; &consvar; -(nothing by default), -and suffix, -specified by the &cv-link-OBJSUFFIX; &consvar; -(.obj on Windows systems, -.o on POSIX systems), -are automatically added to the target if not already present. -Examples: - - - -env.StaticObject(target='aaa', source='aaa.c') -env.StaticObject(target='bbb.o', source='bbb.c++') -env.StaticObject(target='ccc.obj', source='ccc.f') - - - -Note that the source files will be scanned -according to the suffix mappings in the -SourceFileScanner -object. -See the section "Scanner Objects," -below, for more information. - - - - - - - -The version number of the C compiler. -This may or may not be set, -depending on the specific C compiler being used. - - - - - - - -The suffix for C source files. -This is used by the internal CFile builder -when generating C files from Lex (.l) or YACC (.y) input files. -The default suffix, of course, is -.c -(lower case). -On case-insensitive systems (like Windows), -SCons also treats -.C -(upper case) files -as C files. - - - - - - - -The version number of the C++ compiler. -This may or may not be set, -depending on the specific C++ compiler being used. - - - - - - - -The suffix for C++ source files. -This is used by the internal CXXFile builder -when generating C++ files from Lex (.ll) or YACC (.yy) input files. -The default suffix is -.cc. -SCons also treats files with the suffixes -.cpp, -.cxx, -.c++, -and -.C++ -as C++ files, -and files with -.mm -suffixes as Objective C++ files. -On case-sensitive systems (Linux, UNIX, and other POSIX-alikes), -SCons also treats -.C -(upper case) files -as C++ files. - - - - - - - -Used to override &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; when -generating versioned import library for a shared library/loadable module. If -undefined, the &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; is used to -determine the version of versioned import library. - - - - - - - -Contains the emitter specification for the -&b-link-StaticLibrary; builder. -The manpage section "Builder Objects" contains -general information on specifying emitters. - - - - - - - -When this &consvar; is defined, a versioned loadable module -is created by &b-link-LoadableModule; builder. This activates the -&cv-link-_LDMODULEVERSIONFLAGS; and thus modifies the &cv-link-LDMODULECOM; as -required, adds the version number to the library name, and creates the symlinks -that are needed. &cv-link-LDMODULEVERSION; versions should exist in the same -format as &cv-link-SHLIBVERSION;. - - - - - - - -Contains the emitter specification for the -&b-link-LoadableModule; builder. -The manpage section "Builder Objects" contains -general information on specifying emitters. - - - - - - - -Contains the emitter specification for the -&b-link-SharedLibrary; builder. -The manpage section "Builder Objects" contains -general information on specifying emitters. - - - - - - - -Contains the emitter specification for the -&b-link-Program; builder. -The manpage section "Builder Objects" contains -general information on specifying emitters. - - - - - - - -When this &consvar; is defined, a versioned shared library -is created by the &b-link-SharedLibrary; builder. This activates the -&cv-link-_SHLIBVERSIONFLAGS; and thus modifies the &cv-link-SHLINKCOM; as -required, adds the version number to the library name, and creates the symlinks -that are needed. &cv-link-SHLIBVERSION; versions should exist as alpha-numeric, -decimal-delimited values as defined by the regular expression "\w+[\.\w+]*". -Example &cv-link-SHLIBVERSION; values include '1', '1.2.3', and '1.2.gitaa412c8b'. - - - - - diff -Nru scons-4.0.1+dfsg/SCons/Tool/install.py scons-4.4.0+dfsg/SCons/Tool/install.py --- scons-4.0.1+dfsg/SCons/Tool/install.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/install.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,14 +1,6 @@ -"""SCons.Tool.install - -Tool-specific initialization for the install tool. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# 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,17 +20,28 @@ # 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__" + +""" Tool-specific initialization for the install tool. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os -from shutil import copy2, copymode, copystat +import stat +from shutil import copy2, copystat import SCons.Action import SCons.Tool import SCons.Util +from SCons.Subst import SUBST_RAW +from SCons.Tool.linkCommon import ( + StringizeLibSymlinks, + CreateLibSymlinks, + EmitLibSymlinks, +) -# # We keep track of *all* installed files. _INSTALLED_FILES = [] _UNIQUE_INSTALLED_FILES = None @@ -119,12 +122,17 @@ continue # otherwise let the copy occurs. copy2 will raise an error if os.path.isdir(srcname): - scons_copytree(srcname, dstname, symlinks, ignore, - copy_function, dirs_exist_ok) + scons_copytree(srcname, dstname, symlinks=symlinks, + ignore=ignore, copy_function=copy_function, + ignore_dangling_symlinks=ignore_dangling_symlinks, + dirs_exist_ok=dirs_exist_ok) else: copy_function(srcname, dstname) elif os.path.isdir(srcname): - scons_copytree(srcname, dstname, symlinks, ignore, copy_function, dirs_exist_ok) + scons_copytree(srcname, dstname, symlinks=symlinks, + ignore=ignore, copy_function=copy_function, + ignore_dangling_symlinks=ignore_dangling_symlinks, + dirs_exist_ok=dirs_exist_ok) else: # Will raise a SpecialFileError for unsupported file types copy_function(srcname, dstname) @@ -147,11 +155,14 @@ # # Functions doing the actual work of the Install Builder. # -def copyFunc(dest, source, env): - """Install a source file or directory into a destination by copying, +def copyFunc(dest, source, env) -> int: + """Install a source file or directory into a destination by copying. - Mode/permissions bits will be copied as well. + Mode/permissions bits will be copied as well, except that the target + will be made writable. + Returns: + POSIX-style error code - 0 for success, non-zero for fail """ if os.path.isdir(source): if os.path.exists(dest): @@ -164,19 +175,24 @@ scons_copytree(source, dest, dirs_exist_ok=True) else: copy2(source, dest) - copymode(source, dest) + st = os.stat(source) + os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) return 0 # # Functions doing the actual work of the InstallVersionedLib Builder. # -def copyFuncVersionedLib(dest, source, env): - """Install a versioned library into a destination by copying, +def copyFuncVersionedLib(dest, source, env) -> int: + """Install a versioned library into a destination by copying. - Mode/permissions bits will be copied as well. Any required symbolic links for other library names are created. + Mode/permissions bits will be copied as well, except that the target + will be made writable. + + Returns: + POSIX-style error code - 0 for success, non-zero for fail """ if os.path.isdir(source): raise SCons.Errors.UserError("cannot install directory `%s' as a version library" % str(source) ) @@ -187,7 +203,8 @@ except: pass copy2(source, dest) - copymode(source, dest) + st = os.stat(source) + os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) installShlibLinks(dest, source, env) return 0 @@ -213,43 +230,63 @@ 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): - """Install a source file into a target using the function specified - as the INSTALL construction variable.""" +def installFunc(target, source, env) -> int: + """Install a source file into a target. + + Uses the function specified in the INSTALL construction variable. + + Returns: + POSIX-style error code - 0 for success, non-zero for fail + """ + try: install = env['INSTALL'] except KeyError: raise SCons.Errors.UserError('Missing INSTALL construction variable.') - assert len(target)==len(source), \ - "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target))) - for t,s in zip(target,source): - if install(t.get_path(),s.get_path(),env): + assert len(target) == len(source), ( + "Installing source %s into target %s: " + "target and source lists must have same length." + % (list(map(str, source)), list(map(str, target))) + ) + for t, s in zip(target, source): + if install(t.get_path(), s.get_path(), env): return 1 return 0 -def installFuncVersionedLib(target, source, env): - """Install a versioned library into a target using the function specified - as the INSTALLVERSIONEDLIB construction variable.""" +def installFuncVersionedLib(target, source, env) -> int: + """Install a versioned library into a target. + + Uses the function specified in the INSTALL construction variable. + + Returns: + POSIX-style error code - 0 for success, non-zero for fail + """ + try: install = env['INSTALLVERSIONEDLIB'] except KeyError: - raise SCons.Errors.UserError('Missing INSTALLVERSIONEDLIB construction variable.') - - assert len(target)==len(source), \ - "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target))) - for t,s in zip(target,source): + raise SCons.Errors.UserError( + 'Missing INSTALLVERSIONEDLIB construction variable.' + ) + + assert len(target) == len(source), ( + "Installing source %s into target %s: " + "target and source lists must have same length." + % (list(map(str, source)), list(map(str, target))) + ) + for t, s in zip(target, source): if hasattr(t.attributes, 'shlibname'): tpath = os.path.join(t.get_dir(), t.attributes.shlibname) else: tpath = t.get_path() - if install(tpath,s.get_path(),env): + if install(tpath, s.get_path(), env): return 1 return 0 @@ -257,7 +294,7 @@ def stringFunc(target, source, env): installstr = env.get('INSTALLSTR') if installstr: - return env.subst_target_source(installstr, 0, target, source) + return env.subst_target_source(installstr, SUBST_RAW, target, source) target = str(target[0]) source = str(source[0]) if os.path.isdir(source): @@ -292,7 +329,7 @@ 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) @@ -416,9 +453,9 @@ action = install_action, target_factory = target_factory.Entry, source_factory = env.fs.Entry, - multi = 1, + multi = True, emitter = [ add_targets_to_INSTALLED_FILES, ], - source_scanner = SCons.Scanner.Base( {}, name = 'Install', recursive = False ), + source_scanner = SCons.Scanner.ScannerBase({}, name='Install', recursive=False), name = 'InstallBuilder') global BaseVersionedInstallBuilder @@ -433,7 +470,7 @@ action = installVerLib_action, target_factory = target_factory.Entry, source_factory = env.fs.Entry, - multi = 1, + multi = True, emitter = [ add_versioned_targets_to_INSTALLED_FILES, ], name = 'InstallVersionedBuilder') @@ -456,12 +493,12 @@ try: env['INSTALL'] except KeyError: - env['INSTALL'] = copyFunc + env['INSTALL'] = copyFunc try: env['INSTALLVERSIONEDLIB'] except KeyError: - env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib + env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib def exists(env): return 1 diff -Nru scons-4.0.1+dfsg/SCons/Tool/intelc.py scons-4.4.0+dfsg/SCons/Tool/intelc.py --- scons-4.0.1+dfsg/SCons/Tool/intelc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/intelc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,16 +1,6 @@ -"""SCons.Tool.icl - -Tool-specific initialization for the Intel C/C++ compiler. -Supports Linux and Windows compilers, v7 and up. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,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. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import math, sys, os.path, glob, string, re +"""Tool-specific initialization for the Intel C/C++ compiler. + +Supports Linux and Windows compilers, v7 and up. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +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 @@ -173,9 +175,7 @@ except SCons.Util.RegError: raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) - except SCons.Util.RegError: - raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) - except SCons.Util.WinError: + except (SCons.Util.RegError, OSError): raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) # Get the value: @@ -199,7 +199,7 @@ try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, keyname) - except SCons.Util.WinError: + except OSError: # For version 13 or later, check for default instance UUID if is_win64: keyname = 'Software\\WoW6432Node\\Intel\\Suites' @@ -208,7 +208,7 @@ try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, keyname) - except SCons.Util.WinError: + except OSError: return [] i = 0 versions = [] @@ -448,22 +448,28 @@ if not topdir: # Normally this is an error, but it might not be if the compiler is # on $PATH and the user is importing their env. - class ICLTopDirWarning(SCons.Warnings.Warning): + class ICLTopDirWarning(SCons.Warnings.SConsWarning): pass - if (is_mac or is_linux) and not env.Detect('icc') or \ - is_windows and not env.Detect('icl'): + if ( + ((is_mac or is_linux) and not env.Detect('icc')) + or (is_windows and not env.Detect('icl')) + ): SCons.Warnings.enableWarningClass(ICLTopDirWarning) - SCons.Warnings.warn(ICLTopDirWarning, - "Failed to find Intel compiler for version='%s', abi='%s'"% - (str(version), str(abi))) + SCons.Warnings.warn( + ICLTopDirWarning, + "Failed to find Intel compiler for version='%s', abi='%s'" + % (str(version), str(abi)), + ) else: # should be cleaned up to say what this other version is # since in this case we have some other Intel compiler installed SCons.Warnings.enableWarningClass(ICLTopDirWarning) - SCons.Warnings.warn(ICLTopDirWarning, - "Can't find Intel compiler top dir for version='%s', abi='%s'"% - (str(version), str(abi))) + SCons.Warnings.warn( + ICLTopDirWarning, + "Can't find Intel compiler top dir for version='%s', abi='%s'" + % (str(version), str(abi)), + ) if topdir: archdir={'x86_64': 'intel64', @@ -569,14 +575,17 @@ if not licdir: licdir = defaultlicdir if not os.path.exists(licdir): - class ICLLicenseDirWarning(SCons.Warnings.Warning): + class ICLLicenseDirWarning(SCons.Warnings.SConsWarning): pass SCons.Warnings.enableWarningClass(ICLLicenseDirWarning) - SCons.Warnings.warn(ICLLicenseDirWarning, - "Intel license dir was not found." - " Tried using the INTEL_LICENSE_FILE environment variable (%s), the registry (%s) and the default path (%s)." - " Using the default path as a last resort." - % (envlicdir, reglicdir, defaultlicdir)) + SCons.Warnings.warn( + ICLLicenseDirWarning, + "Intel license dir was not found. " + "Tried using the INTEL_LICENSE_FILE environment variable " + "(%s), the registry (%s) and the default path (%s). " + "Using the default path as a last resort." + % (envlicdir, reglicdir, defaultlicdir) + ) env['ENV']['INTEL_LICENSE_FILE'] = licdir def exists(env): diff -Nru scons-4.0.1+dfsg/SCons/Tool/intelc.xml scons-4.4.0+dfsg/SCons/Tool/intelc.xml --- scons-4.0.1+dfsg/SCons/Tool/intelc.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/intelc.xml 2022-07-30 21:48:28.000000000 +0000 @@ -28,9 +28,9 @@ Sets construction variables for the Intel C/C++ compiler (Linux and Windows, version 7 and later). -Calls the &t-gcc; or &t-msvc; +Calls the &t-link-gcc; or &t-link-msvc; (on Linux and Windows, respectively) -to set underlying variables. +tool to set underlying variables. @@ -48,7 +48,7 @@ -Set by the "intelc" Tool +Set by the &t-link-intelc; Tool to the major version number of the Intel C compiler selected for use. diff -Nru scons-4.0.1+dfsg/SCons/Tool/jar.py scons-4.4.0+dfsg/SCons/Tool/jar.py --- scons-4.0.1+dfsg/SCons/Tool/jar.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/jar.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.jar - -Tool-specific initialization for jar. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# 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,18 +20,28 @@ # 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__" +"""Tool-specific initialization for jar. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + import os +from typing import List +import SCons.Node +import SCons.Node.FS import SCons.Subst +import SCons.Tool import SCons.Util +import SCons.Warnings from SCons.Node.FS import _my_normcase from SCons.Tool.JavaCommon import get_java_install_dirs -def jarSources(target, source, env, for_signature): +def jarSources(target, source, env, for_signature) -> List[str]: """Only include sources that are not a manifest file.""" try: env['JARCHDIR'] @@ -54,21 +55,22 @@ result = [] for src in source: contents = src.get_text_contents() - if not contents.startswith("Manifest-Version"): - if jarchdir_set: - _chdir = jarchdir - else: - try: - _chdir = src.attributes.java_classdir - except AttributeError: - _chdir = None - if _chdir: - # If we are changing the dir with -C, then sources should - # be relative to that directory. - src = SCons.Subst.Literal(src.get_path(_chdir)) - result.append('-C') - result.append(_chdir) - result.append(src) + if contents.startswith("Manifest-Version"): + continue + if jarchdir_set: + _chdir = jarchdir + else: + try: + _chdir = src.attributes.java_classdir + except AttributeError: + _chdir = None + if _chdir: + # If we are changing the dir with -C, then sources should + # be relative to that directory. + src = SCons.Subst.Literal(src.get_path(_chdir)) + result.append('-C') + result.append(_chdir) + result.append(src) return result def jarManifest(target, source, env, for_signature): @@ -79,7 +81,7 @@ return src return '' -def jarFlags(target, source, env, for_signature): +def jarFlags(target, source, env, for_signature) -> str: """If we have a manifest, make sure that the 'm' flag is specified.""" jarflags = env.subst('$JARFLAGS', target=target, source=source) @@ -91,29 +93,34 @@ break return jarflags -def Jar(env, target = None, source = [], *args, **kw): - """ - A pseudo-Builder wrapper around the separate Jar sources{File,Dir} - Builders. +def Jar(env, target=None, source=[], *args, **kw): + """The Jar Builder. + + This is a pseudo-Builder wrapper around the separate jar builders + depending on whether the sources are a file list or a directory. """ + # TODO: W1113: Keyword argument before variable positional arguments list in the definition of Jar function + # TODO: W0102: Dangerous default value [] as argument # jar target should not be a list so assume they passed # no target and want implicit target to be made and the arg # was actaully the list of sources if SCons.Util.is_List(target) and source == []: - SCons.Warnings.Warning("Making implicit target jar file, " + - "and treating the list as sources") + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + "Making implicit target jar file, and treating the list as sources" + ) source = target target = None - # mutiple targets pass so build each target the same from the + # mutiple targets passed so build each target the same from the # same source #TODO Maybe this should only be done once, and the result copied # for each target since it should result in the same? if SCons.Util.is_List(target) and SCons.Util.is_List(source): jars = [] for single_target in target: - jars += env.Jar( target = single_target, source = source, *args, **kw) + jars += env.Jar(target=single_target, source=source, *args, **kw) return jars # they passed no target so make a target implicitly @@ -122,8 +129,12 @@ # make target from the first source file target = os.path.splitext(str(source[0]))[0] + env.subst('$JARSUFFIX') except: + # TODO: W0702: No exception type(s) specified # something strange is happening but attempt anyways - SCons.Warnings.Warning("Could not make implicit target from sources, using directory") + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + "Could not make implicit target from sources, using directory" + ) target = os.path.basename(str(env.Dir('.'))) + env.subst('$JARSUFFIX') # make lists out of our target and sources @@ -141,64 +152,68 @@ # if its already a class file then it can be used as a # source for jar, otherwise turn it into a class file then # return the source - def file_to_class(s): - if _my_normcase(str(s)).endswith(java_suffix): - return env.JavaClassFile(source = s, *args, **kw) - else: - return [env.fs.File(s)] + def file_to_class(src): + if _my_normcase(str(src)).endswith(java_suffix): + return env.JavaClassFile(source=src, *args, **kw) + return [env.fs.File(src)] # function for calling the JavaClassDir builder if a directory is # passed as a source to Jar builder. The JavaClassDir builder will - # return an empty list if there were not target classes built from + # return an empty list if there were no target classes built from # the directory, in this case assume the user wanted the directory # copied into the jar as is (it contains other files such as - # resources or class files compiled from proir commands) + # resources or class files compiled from prior commands) # TODO: investigate the expexcted behavior for directories that # have mixed content, such as Java files along side other files # files. - def dir_to_class(s): - dir_targets = env.JavaClassDir(source = s, *args, **kw) + def dir_to_class(src): + dir_targets = env.JavaClassDir(source=src, *args, **kw) if dir_targets == []: # no classes files could be built from the source dir # so pass the dir as is. - return [env.fs.Dir(s)] - else: - return dir_targets + return [env.fs.Dir(src)] + return dir_targets # loop through the sources and handle each accordingly # the goal here is to get all the source files into a class # file or a directory that contains class files - for s in SCons.Util.flatten(source): - s = env.subst(s) - if isinstance(s, SCons.Node.FS.Base): - if isinstance(s, SCons.Node.FS.File): + for src in SCons.Util.flatten(source): + src = env.subst(src) + if isinstance(src, SCons.Node.FS.Base): + if isinstance(src, SCons.Node.FS.File): # found a file so make sure its a class file - target_nodes.extend(file_to_class(s)) + target_nodes.extend(file_to_class(src)) else: # found a dir so get the class files out of it - target_nodes.extend(dir_to_class(s)) + target_nodes.extend(dir_to_class(src)) else: try: # source is string try to convert it to file - target_nodes.extend(file_to_class(env.fs.File(s))) + target_nodes.extend(file_to_class(env.fs.File(src))) continue except: + # TODO: W0702: No exception type(s) specified pass try: # source is string try to covnert it to dir - target_nodes.extend(dir_to_class(env.fs.Dir(s))) + target_nodes.extend(dir_to_class(env.fs.Dir(src))) continue except: + # TODO: W0702: No exception type(s) specified pass - SCons.Warnings.Warning("File: " + str(s) + " could not be identified as File or Directory, skipping.") - - # at this point all our sources have been converted to classes or directories of class - # so pass it to the Jar builder - return env.JarFile(target = target, source = target_nodes, *args, **kw) + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + ("File: " + str(src) + + " could not be identified as File or Directory, skipping.") + ) + + # at this point all our sources have been converted to classes or + # directories of class so pass it to the Jar builder + return env.JarFile(target=target, source=target_nodes, *args, **kw) -def generate(env): +def generate(env) -> None: """Add Builders and construction variables for jar to an Environment.""" SCons.Tool.CreateJarBuilder(env) @@ -216,14 +231,14 @@ jar_bin_dir = os.path.dirname(jar) env.AppendENVPath('PATH', jar_bin_dir) - env['JAR'] = 'jar' - env['JARFLAGS'] = SCons.Util.CLVar('cf') - env['_JARFLAGS'] = jarFlags + env['JAR'] = 'jar' + env['JARFLAGS'] = SCons.Util.CLVar('cf') + env['_JARFLAGS'] = jarFlags env['_JARMANIFEST'] = jarManifest env['_JARSOURCES'] = jarSources - env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' - env['JARCOM'] = "${TEMPFILE('$_JARCOM','$JARCOMSTR')}" - env['JARSUFFIX'] = '.jar' + env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' + env['JARCOM'] = "${TEMPFILE('$_JARCOM','$JARCOMSTR')}" + env['JARSUFFIX'] = '.jar' def exists(env): # As reported by Jan Nijtmans in issue #2730, the simple @@ -232,7 +247,7 @@ # stop trying to detect an executable (analogous to the # javac Builder). # TODO: Come up with a proper detect() routine...and enable it. - return 1 + return True # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Tool/JavaCommon.py scons-4.4.0+dfsg/SCons/Tool/JavaCommon.py --- scons-4.0.1+dfsg/SCons/Tool/JavaCommon.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/JavaCommon.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,11 +1,6 @@ -"""SCons.Tool.JavaCommon - -Stuff for processing Java. - -""" - +# 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,16 +20,16 @@ # 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__" +"""Common routines for processing Java. """ import os -import os.path import re import glob +from pathlib import Path +from typing import List -java_parsing = 1 +java_parsing = True default_java_version = '1.4' @@ -43,13 +38,18 @@ scopeStateVersions = ('1.8',) # Glob patterns for use in finding where the JDK is. -# These are pairs, *dir_glob used in the general case, -# *version_dir_glob if matching only a specific version. -# For now only used for Windows. -java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin' +# +# These are pairs, (*dir_glob, *version_dir_glob) depending on whether +# a JDK version was requested or not. +# For now only used for Windows, which doesn't install JDK in a +# path that would be in env['ENV']['PATH']. The specific tool will +# add the discovered path to this. Since Oracle changed the rules, +# there are many possible vendors, we can't guess them all, but take a shot. +java_win32_dir_glob = 'C:/Program Files*/*/*jdk*/bin' + # On windows, since Java 9, there is a dash between 'jdk' and the version # string that wasn't there before. this glob should catch either way. -java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk*%s*/bin' +java_win32_version_dir_glob = 'C:/Program Files*/*/*jdk*%s*/bin' # Glob patterns for use in finding where the JDK headers are. # These are pairs, *dir_glob used in the general case, @@ -59,14 +59,17 @@ java_linux_include_dirs_glob = [ '/usr/lib/jvm/default-java/include', - '/usr/lib/jvm/java-*/include' + '/usr/lib/jvm/java-*/include', + '/opt/oracle-jdk-bin-*/include', + '/opt/openjdk-bin-*/include', + '/usr/lib/openjdk-*/include', ] # Need to match path like below (from Centos 7) # /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/ java_linux_version_include_dirs_glob = [ '/usr/lib/jvm/java-*-sun-%s*/include', '/usr/lib/jvm/java-%s*-openjdk*/include', - '/usr/java/jdk%s*/include' + '/usr/java/jdk%s*/include', ] if java_parsing: @@ -87,9 +90,10 @@ # 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: @@ -97,9 +101,27 @@ interfaces, and anonymous inner classes.""" def __init__(self, version=default_java_version): - - if version not in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', - '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'): + if version not in ( + '1.1', + '1.2', + '1.3', + '1.4', + '1.5', + '1.6', + '1.7', + '1.8', + '5', + '6', + '9.0', + '10.0', + '11.0', + '12.0', + '13.0', + '14.0', + '15.0', + '16.0', + '17.0', + ): msg = "Java version %s not supported" % version raise NotImplementedError(msg) @@ -206,7 +228,24 @@ if self.version in ('1.1', '1.2', '1.3', '1.4'): clazz = self.listClasses[0] self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) - elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'): + # TODO: shouldn't need to repeat versions here and in OuterState + elif self.version in ( + '1.5', + '1.6', + '1.7', + '1.8', + '5', + '6', + '9.0', + '10.0', + '11.0', + '12.0', + '13.0', + '14.0', + '15.0', + '16.0', + '17.0', + ): self.stackAnonClassBrackets.append(self.brackets) className = [] className.extend(self.listClasses) @@ -442,49 +481,82 @@ return os.path.split(fn) -def get_java_install_dirs(platform, version=None): - """ - Find the java jdk installation directories. +def get_java_install_dirs(platform, version=None) -> List[str]: + """ Find possible java jdk installation directories. - This list is intended to supply as "default paths" for use when looking - up actual java binaries. + Returns a list for use as `default_paths` when looking up actual + java binaries with :meth:`SCons.Tool.find_program_path`. + The paths are sorted by version, latest first. + + Args: + platform: selector for search algorithm. + version: if not None, restrict the search to this version. - :param platform: selector for search algorithm. - :param version: If specified, only look for java sdk's of this version - :return: list of default paths for java. + Returns: + list of default paths for jdk. """ - paths = [] if platform == 'win32': + paths = [] if version: paths = glob.glob(java_win32_version_dir_glob % version) else: paths = glob.glob(java_win32_dir_glob) - else: - # other platforms, do nothing for now - pass - return sorted(paths) + def win32getvnum(java): + """ Generates a sort key for win32 jdk versions. + We'll have gotten a path like ...something/*jdk*/bin because + that is the pattern we glob for. To generate the sort key, + extracts the next-to-last component, then trims it further if + it had a complex name, like 'java-1.8.0-openjdk-1.8.0.312-1', + to try and put it on a common footing with the more common style, + which looks like 'jdk-11.0.2'. + + This is certainly fragile, and if someone has a 9.0 it won't + sort right since this will still be alphabetic, BUT 9.0 was + not an LTS release and is 30 mos out of support as this note + is written so just assume it will be okay. + """ + d = Path(java).parts[-2] + if not d.startswith('jdk'): + d = 'jdk' + d.rsplit('jdk', 1)[-1] + return d + + return sorted(paths, key=win32getvnum, reverse=True) + + # other platforms, do nothing for now: we expect the standard + # paths to be enough to find a jdk (e.g. use alternatives system) + return [] + + +def get_java_include_paths(env, javac, version) -> List[str]: + """Find java include paths for JNI building. + + Cannot be called in isolation - `javac` refers to an already detected + compiler. Normally would would call :func:`get_java_install_dirs` first + and then do lookups on the paths it returns before calling us. + + Args: + env: construction environment, used to extract platform. + javac: path to detected javac. + version: if not None, restrict the search to this version. -def get_java_include_paths(env, javac, version): + Returns: + list of include directory paths. """ - Find java include paths for JNI building. - :param env: construction environment, used to extract platform. - :param javac: path to detected javac. - :return: list of paths. - """ - - paths = [] if not javac: - # there are no paths if we've not detected javac. - pass - elif env['PLATFORM'] == 'win32': - # on Windows, we have the right path to javac, so look locally + return [] + + # on Windows, we have a path to the actual javac, so look locally + if env['PLATFORM'] == 'win32': javac_bin_dir = os.path.dirname(javac) java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include')) paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')] + + # for the others, we probably found something which isn't in the JDK dir, + # so use the predefined patterns to glob for an include directory. elif env['PLATFORM'] == 'darwin': if not version: paths = [java_macos_include_dir_glob] @@ -499,10 +571,10 @@ for p in java_linux_version_include_dirs_glob: base_paths.extend(glob.glob(p % version)) + paths = [] for p in base_paths: paths.extend([p, os.path.join(p, 'linux')]) - # print("PATHS:%s"%paths) return paths # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/Tool/JavaCommonTests.py scons-4.4.0+dfsg/SCons/Tool/JavaCommonTests.py --- scons-4.0.1+dfsg/SCons/Tool/JavaCommonTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/JavaCommonTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 fnmatch @@ -97,7 +94,7 @@ """Test class names with $ in them""" input = """\ -public class BadDep { +public class BadDep { public void new$rand () {} } """ @@ -484,6 +481,43 @@ 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 +566,7 @@ * Detected. */ class InnerOK { InnerOK () { } } - + { System.out.println("a number: " + 1000.0 + ""); } @@ -638,24 +672,43 @@ Verify that the java path globs work with specific examples. :return: """ - from SCons.Tool.JavaCommon import java_linux_include_dirs_glob, java_linux_version_include_dirs_glob, java_win32_dir_glob, java_win32_version_dir_glob, java_macos_include_dir_glob, java_macos_version_include_dir_glob + from SCons.Tool.JavaCommon import ( + java_linux_include_dirs_glob, + java_linux_version_include_dirs_glob, + java_win32_dir_glob, + java_win32_version_dir_glob, + java_macos_include_dir_glob, + java_macos_version_include_dir_glob, + ) # Test windows globs win_java_dirs = [ - ('C:/Program Files/Java/jdk1.8.0_201/bin', '1.8.0'), - ('C:/Program Files/Java/jdk-11.0.2/bin', '11.0.2'), - ('C:/Program Files/Java/jdk1.7.0_80/bin', '1.7.0') + (r'C:/Program Files/Java/jdk1.8.0_201/bin', '1.8.0'), + (r'C:/Program Files/Java/jdk-11.0.2/bin', '11.0.2'), + (r'C:/Program Files/AdoptOpenJDK/jdk-16.0.1.9-hotspot/bin', '16.0.1'), + (r'C:/Program Files/Microsoft/jdk-17.0.0.35-hotspot/bin', '17.0.0'), + (r'C:/Program Files/OpenJDK/openjdk-11.0.13_8/bin', '11.0.13'), + (r'C:/Program Files/RedHat/java-1.8.0-openjdk-1.8.0.312-1/bin', '1.8.0'), + (r'C:/Program Files/RedHat/java-11-openjdk-11.0.13-1/bin', '11.0.13'), ] for (wjd, version) in win_java_dirs: if not fnmatch.fnmatch(wjd, java_win32_dir_glob): - self.fail("Didn't properly match %s with pattern %s" % (wjd, java_win32_dir_glob)) + self.fail( + "Didn't properly match %s with pattern %s" + % (wjd, java_win32_dir_glob) + ) if not fnmatch.fnmatch(wjd, java_win32_version_dir_glob % version): - self.fail("Didn't properly match %s with version (%s) specific pattern %s" % ( - wjd, version, java_win32_version_dir_glob % version)) + self.fail( + "Didn't properly match %s with version (%s) specific pattern %s" + % (wjd, version, java_win32_version_dir_glob % version) + ) non_win_java_include_dirs = [ - ('/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include', '1.8.0'), + ( + '/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include', + '1.8.0', + ), ('/usr/lib/jvm/java-1.8.0-openjdk-amd64/include', '1.8.0'), ('/usr/lib/jvm/java-8-openjdk-amd64/include', '8'), ] @@ -663,7 +716,7 @@ # Test non-windows/non-macos globs for (wjd, version) in non_win_java_include_dirs: match = False - globs_tried =[] + globs_tried = [] for jlig in java_linux_include_dirs_glob: globs_tried.append(jlig) @@ -672,36 +725,52 @@ break if not match: - self.fail("Didn't properly match %s with pattern %s" % (wjd, globs_tried)) + self.fail( + "Didn't properly match %s with pattern %s" % (wjd, globs_tried) + ) match = False globs_tried = [] for jlvig in java_linux_version_include_dirs_glob: - globs_tried.append(jlvig%version) + globs_tried.append(jlvig % version) if fnmatch.fnmatch(wjd, jlvig % version): match = True break if not match: - self.fail("Didn't properly match %s with version (%s) specific pattern %s" % ( - wjd, version, globs_tried)) + self.fail( + "Didn't properly match %s with version (%s) specific pattern %s" + % (wjd, version, globs_tried) + ) # Test macos globs # Test windows globs macos_java_dirs = [ # ('/System/Library/Frameworks/JavaVM.framework/Headers/', None), - ('/System/Library/Frameworks/JavaVM.framework/Versions/11.0.2/Headers/', '11.0.2'), + ( + '/System/Library/Frameworks/JavaVM.framework/Versions/11.0.2/Headers/', + '11.0.2', + ), ] - if not fnmatch.fnmatch('/System/Library/Frameworks/JavaVM.framework/Headers/', java_macos_include_dir_glob): - self.fail("Didn't properly match %s with pattern %s" % ('/System/Library/Frameworks/JavaVM.framework/Headers/', java_macos_include_dir_glob)) + if not fnmatch.fnmatch( + '/System/Library/Frameworks/JavaVM.framework/Headers/', + java_macos_include_dir_glob, + ): + self.fail( + "Didn't properly match %s with pattern %s" + % ( + '/System/Library/Frameworks/JavaVM.framework/Headers/', + java_macos_include_dir_glob, + ) + ) for (wjd, version) in macos_java_dirs: if not fnmatch.fnmatch(wjd, java_macos_version_include_dir_glob % version): - self.fail("Didn't properly match %s with version (%s) specific pattern %s" % ( - wjd, version, java_macos_version_include_dir_glob % version)) - - + self.fail( + "Didn't properly match %s with version (%s) specific pattern %s" + % (wjd, version, java_macos_version_include_dir_glob % version) + ) if __name__ == "__main__": diff -Nru scons-4.0.1+dfsg/SCons/Tool/javac.py scons-4.4.0+dfsg/SCons/Tool/javac.py --- scons-4.0.1+dfsg/SCons/Tool/javac.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/javac.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.javac - -Tool-specific initialization for javac. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,7 +21,16 @@ # 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.Tool.javac + +Tool-specific initialization for javac. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + import os import os.path @@ -157,6 +157,7 @@ default = [default] path = path + default if path: + path = SCons.Util.flatten(path) return [self.opt, os.pathsep.join(map(str, path))] else: return [] @@ -220,23 +221,24 @@ else: javac = SCons.Tool.find_program_path(env, 'javac') - env['JAVAINCLUDES'] = get_java_include_paths(env, javac, version) - - env['JAVAC'] = 'javac' - env['JAVACFLAGS'] = SCons.Util.CLVar('') - env['JAVABOOTCLASSPATH'] = [] - env['JAVACLASSPATH'] = [] - env['JAVASOURCEPATH'] = [] - env['_javapathopt'] = pathopt - env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' - env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' - env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' - env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' - env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' - env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM','$JAVACCOMSTR')}" - env['JAVACLASSSUFFIX'] = '.class' - env['JAVASUFFIX'] = '.java' + env.SetDefault( + JAVAC='javac', + JAVACFLAGS=SCons.Util.CLVar(''), + JAVAINCLUDES=get_java_include_paths(env, javac, version), + JAVACLASSSUFFIX='.class', + JAVASUFFIX='.java', + JAVABOOTCLASSPATH=[], + JAVACLASSPATH=[], + JAVASOURCEPATH=[], + ) + env['_javapathopt'] = pathopt + env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' + env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' + env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' + env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' + env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' + env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM','$JAVACCOMSTR')}" def exists(env): return 1 diff -Nru scons-4.0.1+dfsg/SCons/Tool/javacTests.py scons-4.4.0+dfsg/SCons/Tool/javacTests.py --- scons-4.0.1+dfsg/SCons/Tool/javacTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/javacTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -97,6 +97,11 @@ ['-foopath', '/foo'], '/foo', '') + + def test_list_within_list(self): + self.assert_pathopt(['-foopath', os.pathsep.join(['/foo','/bar'])], + ['/foo', ['/bar']]) + if __name__ == "__main__": unittest.main() diff -Nru scons-4.0.1+dfsg/SCons/Tool/javac.xml scons-4.4.0+dfsg/SCons/Tool/javac.xml --- scons-4.0.1+dfsg/SCons/Tool/javac.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/javac.xml 2022-07-30 21:48:28.000000000 +0000 @@ -215,15 +215,6 @@ ; on Windows). - - - Note that this currently just adds the specified - directory via the option. - &SCons; does not currently search the - &cv-JAVACLASSPATH; directories for dependency - .class - files. - @@ -278,27 +269,32 @@ - Specifies the Java version being used by the &b-Java; builder. - This is not currently used to select one - version of the Java compiler vs. another. - Instead, you should set this to specify the version of Java - supported by your &javac; compiler. - The default is 1.4. - - - + Specifies the Java version being used by the &b-link-Java; + builder. Set this to specify the version of Java targeted + by the &javac; compiler. This is sometimes necessary because Java 1.5 changed the file names that are created for nested anonymous inner classes, which can cause a mismatch with the files that &SCons; expects will be generated by the &javac; compiler. - Setting &cv-JAVAVERSION; to - 1.5 - (or 1.6, as appropriate) - can make &SCons; realize that a Java 1.5 or 1.6 - build is actually up to date. + Setting &cv-JAVAVERSION; to a version greater than + 1.4 makes &SCons; realize that a build + with such a compiler is actually up to date. + The default is 1.4. + + + While this is not primarily intended for + selecting one version of the Java compiler vs. another, + it does have that effect on the Windows platform. A + more precise approach is to set &cv-link-JAVAC; (and related + &consvars; for related utilities) to the path to the specific + Java compiler you want, if that is not the default compiler. + On non-Windows platforms, the + alternatives system may provide a + way to adjust the default Java compiler without + having to specify explicit paths. - + diff -Nru scons-4.0.1+dfsg/SCons/Tool/javah.py scons-4.4.0+dfsg/SCons/Tool/javah.py --- scons-4.0.1+dfsg/SCons/Tool/javah.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/javah.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.javah - -Tool-specific initialization for javah. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,16 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# +"""SCons.Tool.javah + +Tool-specific initialization for javah. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path @@ -130,12 +128,15 @@ javah_bin_dir = os.path.dirname(javah) env.AppendENVPath('PATH', javah_bin_dir) - env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator - env['JAVAH'] = 'javah' - env['JAVAHFLAGS'] = SCons.Util.CLVar('') - env['_JAVAHCLASSPATH'] = getJavaHClassPath - env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG $_JAVAHCLASSPATH ${SOURCES.attributes.java_classname}' - env['JAVACLASSSUFFIX'] = '.class' + env.SetDefault( + JAVAH='javah', + JAVAHFLAGS=SCons.Util.CLVar(''), + JAVACLASSSUFFIX='.class', + JAVASUFFIX='.java', + ) + env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator + env['_JAVAHCLASSPATH'] = getJavaHClassPath + env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG $_JAVAHCLASSPATH ${SOURCES.attributes.java_classname}' def exists(env): return env.Detect('javah') diff -Nru scons-4.0.1+dfsg/SCons/Tool/javah.xml scons-4.4.0+dfsg/SCons/Tool/javah.xml --- scons-4.0.1+dfsg/SCons/Tool/javah.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/javah.xml 2022-07-30 21:48:28.000000000 +0000 @@ -90,6 +90,27 @@ JAVACLASSDIR="classes", ) + + + +Java versions starting with 10.0 no longer use the +javah command for generating JNI +headers/sources, and indeed have removed the command entirely +(see Java Enhancement Proposal +JEP 313), +making this tool harder to use for that purpose. +&SCons; may autodiscover a javah +belonging to an older release if there are multiple Java +versions on the system, which will lead to incorrect results. +To use with a newer Java, override the default values of &cv-link-JAVAH; +(to contain the path to the javac) +and &cv-link-JAVAHFLAGS; (to contain at least a +flag) and note that generating headers with +javac requires supplying source +.java files only, +not .class files. + +
diff -Nru scons-4.0.1+dfsg/SCons/Tool/ldc.py scons-4.4.0+dfsg/SCons/Tool/ldc.py --- scons-4.0.1+dfsg/SCons/Tool/ldc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ldc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,27 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + """SCons.Tool.ldc Tool-specific initialization for the LDC compiler. @@ -23,33 +47,7 @@ LIBS - Same as for the linker. (libraries to pull into the .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__" - -import os -import subprocess import SCons.Action import SCons.Builder @@ -129,15 +127,8 @@ env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' # Support for versioned libraries - env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME' - 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 - # NOTE: this is only for further reference, currently $SHDLIBVERSION does - # not work, the user must use $SHLIBVERSION - env['SHDLIBVERSION'] = '$SHLIBVERSION' - env['SHDLIBVERSIONFLAGS'] = [] + env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHLIBSONAME' + env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder( action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of=$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS', diff -Nru scons-4.0.1+dfsg/SCons/Tool/ldc.xml scons-4.4.0+dfsg/SCons/Tool/ldc.xml --- scons-4.0.1+dfsg/SCons/Tool/ldc.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ldc.xml 2022-07-30 21:48:28.000000000 +0000 @@ -65,8 +65,6 @@ DLINKFLAGSUFFIX DRPATHPREFIX DRPATHSUFFIX -DShLibSonameGenerator -SHDLIBVERSION SHDLIBVERSIONFLAGS diff -Nru scons-4.0.1+dfsg/SCons/Tool/lex.py scons-4.4.0+dfsg/SCons/Tool/lex.py --- scons-4.0.1+dfsg/SCons/Tool/lex.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/lex.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.lex - -Tool-specific initialization for lex. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,19 +20,30 @@ # 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__" +"""Tool-specific initialization for lex. + +This tool should support multiple lex implementations, +but is in actuality biased towards GNU Flex. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path import sys +from typing import Optional import SCons.Action import SCons.Tool -import SCons.Util +import SCons.Warnings from SCons.Platform.mingw import MINGW_DEFAULT_PATHS from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS from SCons.Platform.win32 import CHOCO_DEFAULT_PATH +from SCons.Util import CLVar, to_String + +DEFAULT_PATHS = CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR") @@ -50,53 +52,77 @@ else: BINS = ["flex", "lex"] -def lexEmitter(target, source, env): - sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0])) +def lexEmitter(target, source, env) -> tuple: + """Adds extra files generated by lex program to target list.""" + + sourceBase, sourceExt = os.path.splitext(to_String(source[0])) if sourceExt == ".lm": # If using Objective-C target = [sourceBase + ".m"] # the extension is ".m". - # This emitter essentially tries to add to the target all extra - # files generated by flex. - - # Different options that are used to trigger the creation of extra files. - fileGenOptions = ["--header-file=", "--tables-file="] - - lexflags = env.subst("$LEXFLAGS", target=target, source=source) - for option in SCons.Util.CLVar(lexflags): - for fileGenOption in fileGenOptions: + # With --header-file and ----tables-file, the file to write is defined + # by the option argument. Extract this and include in the list of targets. + # NOTE: a filename passed to the command this way is not modified by SCons, + # and so will be interpreted relative to the project top directory at + # execution time, while the name added to the target list will be + # interpreted relative to the SConscript directory - a possible mismatch. + # + # These are GNU flex-only options. + # TODO: recognize --outfile also? + file_gen_options = ["--header-file=", "--tables-file="] + lexflags = env.subst_list("$LEXFLAGS", target=target, source=source) + for option in lexflags[0]: + for fileGenOption in file_gen_options: l = len(fileGenOption) if option[:l] == fileGenOption: # A file generating option is present, so add the # file name to the target list. - fileName = option[l:].strip() - target.append(fileName) - return (target, source) + file_name = option[l:].strip() + target.append(file_name) + + lexheaderfile = env.subst("$LEX_HEADER_FILE", target=target, source=source) + if lexheaderfile: + target.append(lexheaderfile) + # rewrite user-supplied file string with a node, we need later + env.Replace(LEX_HEADER_FILE=env.File(lexheaderfile)) + + lextablesfile = env.subst("$LEX_TABLES_FILE", target=target, source=source) + if lextablesfile: + target.append(lextablesfile) + # rewrite user-supplied file string with a node, we need later + env.Replace(LEX_TABLES_FILE=env.File(lextablesfile)) + + return target, source + -def get_lex_path(env, append_paths=False): +def get_lex_path(env, append_paths=False) -> Optional[str]: """ - Find the path to the lex tool, searching several possible names + Returns the path to the lex tool, searching several possible names. - Only called in the Windows case, so the default_path - can be Windows-specific + Only called in the Windows case, so the `default_path` argument to + :func:`find_program_path` can be Windows-specific. - :param env: current construction environment - :param append_paths: if set, add the path to the tool to PATH - :return: path to lex tool, if found + Args: + env: current construction environment + append_paths: if set, add the path to the tool to PATH """ for prog in BINS: bin_path = SCons.Tool.find_program_path( env, prog, - default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + default_paths=DEFAULT_PATHS, + add_path=append_paths, + ) if bin_path: - if append_paths: - env.AppendENVPath('PATH', os.path.dirname(bin_path)) return bin_path - SCons.Warnings.Warning('lex tool requested, but lex or flex binary not found in ENV PATH') + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + 'lex tool requested, but lex or flex binary not found in ENV PATH' + ) -def generate(env): + +def generate(env) -> None: """Add Builders and construction variables for lex to an Environment.""" c_file, cxx_file = SCons.Tool.createCFileBuilders(env) @@ -115,20 +141,28 @@ cxx_file.add_action(".ll", LexAction) cxx_file.add_emitter(".ll", lexEmitter) - env["LEXFLAGS"] = SCons.Util.CLVar("") - if sys.platform == 'win32': - # ignore the return - we do not need the full path here + # ignore the return, all we need is for the path to be added _ = get_lex_path(env, append_paths=True) - env["LEX"] = env.Detect(BINS) - if not env.get("LEXUNISTD"): - env["LEXUNISTD"] = SCons.Util.CLVar("") - env["LEXCOM"] = "$LEX $LEXUNISTD $LEXFLAGS -t $SOURCES > $TARGET" + + env.SetDefault( + LEX=env.Detect(BINS), + LEXFLAGS=CLVar(""), + LEX_HEADER_FILE="", + LEX_TABLES_FILE="", + ) + + if sys.platform == 'win32': + env.SetDefault(LEXUNISTD=CLVar("")) + env["LEXCOM"] = "$LEX $LEXUNISTD $LEXFLAGS $_LEX_HEADER $_LEX_TABLES -t $SOURCES > $TARGET" else: - env["LEX"] = env.Detect(BINS) - env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET" + env["LEXCOM"] = "$LEX $LEXFLAGS $_LEX_HEADER $_LEX_TABLES -t $SOURCES > $TARGET" + + env['_LEX_HEADER'] = '${LEX_HEADER_FILE and "--header-file=" + str(LEX_HEADER_FILE)}' + env['_LEX_TABLES'] = '${LEX_TABLES_FILE and "--tables-file=" + str(LEX_TABLES_FILE)}' + -def exists(env): +def exists(env) -> Optional[str]: if sys.platform == 'win32': return get_lex_path(env) else: diff -Nru scons-4.0.1+dfsg/SCons/Tool/lex.xml scons-4.4.0+dfsg/SCons/Tool/lex.xml --- scons-4.0.1+dfsg/SCons/Tool/lex.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/lex.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ @@ -73,6 +96,7 @@ PCH PCHSTOP PDB +MSVC_NOTFOUND_POLICY @@ -80,13 +104,13 @@ Builds a Microsoft Visual C++ precompiled header. -Calling this builder method +Calling this builder returns a list of two targets: the PCH as the first element, and the object file as the second element. Normally the object file is ignored. -This builder method is only +This builder is only provided when Microsoft Visual C++ is being used as the compiler. -The PCH builder method is generally used in -conjunction with the PCH construction variable to force object files to use +The &b-PCH; builder is generally used in +conjunction with the &cv-link-PCH; construction variable to force object files to use the precompiled header: @@ -210,7 +234,7 @@ -env['PCH'] = 'StdAfx.pch' +env['PCH'] = File('StdAfx.pch') @@ -219,7 +243,7 @@ The command line used by the -&b-PCH; +&b-link-PCH; builder to generated a precompiled header. @@ -238,8 +262,8 @@ A construction variable that, when expanded, -adds the /yD flag to the command line -only if the &cv-PDB; construction variable is set. +adds the flag to the command line +only if the &cv-link-PDB; construction variable is set. @@ -292,7 +316,7 @@ -The flags passed to the resource compiler by the RES builder. +The flags passed to the resource compiler by the &b-link-RES; builder. @@ -306,9 +330,9 @@ by the resource compiler. The value of &cv-RCINCFLAGS; is created by respectively prepending and appending -&cv-RCINCPREFIX; and &cv-RCINCSUFFIX; +&cv-link-RCINCPREFIX; and &cv-link-RCINCSUFFIX; to the beginning and end -of each directory in &cv-CPPPATH;. +of each directory in &cv-link-CPPPATH;. @@ -319,8 +343,8 @@ The prefix (flag) used to specify an include directory on the resource compiler command line. This will be prepended to the beginning of each directory -in the &cv-CPPPATH; construction variable -when the &cv-RCINCFLAGS; variable is expanded. +in the &cv-link-CPPPATH; construction variable +when the &cv-link-RCINCFLAGS; variable is expanded. @@ -331,8 +355,8 @@ The suffix used to specify an include directory on the resource compiler command line. This will be appended to the end of each directory -in the &cv-CPPPATH; construction variable -when the &cv-RCINCFLAGS; variable is expanded. +in the &cv-link-CPPPATH; construction variable +when the &cv-link-RCINCFLAGS; variable is expanded. @@ -347,12 +371,20 @@ If &cv-MSVC_VERSION; is not set, SCons will (by default) select the latest version of Visual C/C++ installed on your system. If the specified version isn't installed, tool initialization will fail. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. + + + +&cv-MSVC_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_VERSION; must be set before the first msvc tool is +loaded into the environment. Valid values for Windows are +14.3, 14.2, 14.1, 14.1Exp, @@ -381,7 +413,7 @@ -Use a batch script to set up Microsoft Visual Studio compiler. +Use a batch script to set up the Microsoft Visual C++ compiler. @@ -394,102 +426,201 @@ %PATH%) for supplying to the build. This can be useful to force the use of a compiler version that &SCons; does not detect. +&cv-link-MSVC_USE_SCRIPT_ARGS; provides arguments passed to this script. Setting &cv-MSVC_USE_SCRIPT; to None bypasses the Visual Studio autodetection entirely; -use this if you are running SCons in a Visual Studio cmd +use this if you are running SCons in a Visual Studio cmd window and importing the shell's environment variables - that is, if you are sure everything is set correctly already and you don't want &SCons; to change anything. -&cv-MSVC_USE_SCRIPT; overrides &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;. +&cv-MSVC_USE_SCRIPT; ignores &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;. - + -Sets the host architecture for Visual Studio compiler. If not set, -default to the detected host architecture: note that this may depend -on the python you are using. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. +Provides arguments passed to the script &cv-link-MSVC_USE_SCRIPT;. + + + + -Valid values are the same as for &cv-link-TARGET_ARCH;. +Use a dictionary to set up the Microsoft Visual C++ compiler. -This is currently only used on Windows, but in the future it may be -used on other OSes as well. +&cv-MSVC_USE_SETTINGS; is ignored when &cv-link-MSVC_USE_SCRIPT; is defined +and/or when &cv-MSVC_USE_SETTINGS; is set to None. - - - - + -Sets the target architecture for Visual Studio compiler (i.e. the arch -of the binaries generated by the compiler). If not set, default to -&cv-link-HOST_ARCH;, or, if that is unset, to the architecture of the -running machine's OS (note that the python build or architecture has no -effect). -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. -This is currently only used on Windows, but in the future it will be -used on other OSes as well. -If this is set and &cv-link-MSVC_VERSION; is not set, this will search for -all installed MSVC's that support the &cv-TARGET_ARCH;, selecting the -latest version for use. +The dictionary is used to populate the environment with the relevant variables +(typically %INCLUDE%, %LIB%, and %PATH%) +for supplying to the build. This can be useful to force the use of a compiler environment +that &SCons; does not configure correctly. This is an alternative to manually configuring +the environment when bypassing Visual Studio autodetection entirely by setting +&cv-link-MSVC_USE_SCRIPT; to None. -On Windows, valid target values are -x86, -arm, -i386 -for 32-bit targets and -amd64, -arm64, -em64t, -x86_64 -and ia64 (Itanium) -for 64-bit targets. -Note that not all target architectures are -supported for all Visual Studio / MSVC versions -check the relevant Microsoft documentation. +Here is an example of configuring a build environment using the Microsoft Visual C/C++ compiler +included in the Microsoft SDK on a 64-bit host and building for a 64-bit architecture: + +# Microsoft SDK 6.0 (MSVC 8.0): 64-bit host and 64-bit target +msvc_use_settings = { + "PATH": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Bin\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin", + "C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727", + "C:\\Windows\\system32", + "C:\\Windows", + "C:\\Windows\\System32\\Wbem", + "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\" + ], + "INCLUDE": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include\\Sys", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include\\gl", + ], + "LIB": [ + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Lib\\x64", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Lib\\x64", + ], + "LIBPATH": [], + "VSCMD_ARG_app_plat": [], + "VCINSTALLDIR": [], + "VCToolsInstallDir": [] +} + +# Specifying MSVC_VERSION is recommended +env = Environment(MSVC_VERSION='8.0', MSVC_USE_SETTINGS=msvc_use_settings) + -For example, if you want to compile 64-bit binaries, you would set -TARGET_ARCH='x86_64' in your SCons environment. +Important usage details: + + + +&cv-MSVC_USE_SETTINGS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_USE_SETTINGS; must be set before the first msvc tool is +loaded into the environment. + + + + +The dictionary content requirements are based on the internal msvc implementation and +therefore may change at any time. + +The burden is on the user to ensure the dictionary contents are minimally sufficient to +ensure successful builds. + + + + + + + + -Build libraries for a Universal Windows Platform (UWP) Application. +Build with the Universal Windows Platform (UWP) application Visual C++ libraries. -If &cv-MSVC_UWP_APP; is set, the Visual Studio environment will be set up to point -to the Windows Store compatible libraries and Visual Studio runtimes. In doing so, +The valid values for &cv-MSVC_UWP_APP; are: True, +'1', False, '0', +or None. + + + +When &cv-MSVC_UWP_APP; is enabled (i.e., True or +'1'), the Visual C++ environment will be set up to point +to the Windows Store compatible libraries and Visual C++ runtimes. In doing so, any libraries that are built will be able to be used in a UWP App and published to the Windows Store. -This flag will only have an effect with Visual Studio 2015 or later. -This variable must be passed as an argument to the Environment() -constructor; setting it later has no effect. + + -Valid values are '1' or '0' +An exception is raised when any of the following conditions are satisfied: + + +&cv-MSVC_UWP_APP; is enabled for Visual Studio 2013 and earlier. + + +&cv-MSVC_UWP_APP; is enabled and a UWP argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via &cv-MSVC_UWP_APP; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + + + +Example - A Visual Studio 2022 build for the Universal Windows Platform: + +env = Environment(MSVC_VERSION='14.3', MSVC_UWP_APP=True) + + + + +Important usage details: + + + +&cv-MSVC_UWP_APP; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_UWP_APP; must be set before the first msvc tool is +loaded into the environment. + + + + +The existence of the UWP libraries is not verified when &cv-MSVC_UWP_APP; is enabled +which could result in build failures. + +The burden is on the user to ensure the requisite UWP libraries are installed. + + + @@ -544,5 +675,741 @@ + + + +Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not detected. + + + + The &cv-MSVC_NOTFOUND_POLICY; specifies the &scons; behavior when no msvc versions are detected or + when the requested msvc version is not detected. + + + +The valid values for &cv-MSVC_NOTFOUND_POLICY; and the corresponding &scons; behavior are: + + + + + +'Error' or 'Exception' + + +Raise an exception when no msvc versions are detected or when the requested msvc version is not detected. + + + + + +'Warning' or 'Warn' + + +Issue a warning and continue when no msvc versions are detected or when the requested msvc version is not detected. +Depending on usage, this could result in build failure(s). + + + + + +'Ignore' or 'Suppress' + + +Take no action and continue when no msvc versions are detected or when the requested msvc version is not detected. +Depending on usage, this could result in build failure(s). + + + + + + + +Note: in addition to the camel case values shown above, lower case and upper case values are accepted as well. + + + +The &cv-MSVC_NOTFOUND_POLICY; is applied when any of the following conditions are satisfied: + + +&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified), +and the default tools list contains one or more of the msvc tools. + + +&cv-MSVC_VERSION; is specified, the default tools list is explicitly specified (e.g., tools=['default']), +and the default tools list contains one or more of the msvc tools. + + +A non-default tools list is specified that contains one or more of the msvc tools (e.g., tools=['msvc', 'mslink']). + + + + + +The &cv-MSVC_NOTFOUND_POLICY; is ignored when any of the following conditions are satisfied: + + +&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified). + + +&cv-MSVC_VERSION; is not specified and the default tools list is explicitly specified (e.g., tools=['default']). + + +A non-default tool list is specified that does not contain any of the msvc tools (e.g., tools=['mingw']). + + + + + +Important usage details: + + + +&cv-MSVC_NOTFOUND_POLICY; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_NOTFOUND_POLICY; must be set before the first msvc tool is +loaded into the environment. + + + + + + +When &cv-MSVC_NOTFOUND_POLICY; is not specified, the default &scons; behavior is to issue a warning and continue +subject to the conditions listed above. The default &scons; behavior may change in the future. + + + + + + + + +Specify the &scons; behavior when Microsoft Visual C/C++ batch file errors are detected. + + + +The &cv-MSVC_SCRIPTERROR_POLICY; specifies the &scons; behavior when msvc batch file errors are +detected. +When &cv-MSVC_SCRIPTERROR_POLICY; is not specified, the default &scons; behavior is to suppress +msvc batch file error messages. + + +The root cause of msvc build failures may be difficult to diagnose. In these situations, setting +the &scons; behavior to issue a warning when msvc batch file errors are detected may +produce additional diagnostic information. + + + +The valid values for &cv-MSVC_SCRIPTERROR_POLICY; and the corresponding &scons; behavior are: + + + + + +'Error' or 'Exception' + + +Raise an exception when msvc batch file errors are detected. + + + + + +'Warning' or 'Warn' + + +Issue a warning when msvc batch file errors are detected. + + + + + +'Ignore' or 'Suppress' + + +Suppress msvc batch file error messages. + + + + + + + +Note: in addition to the camel case values shown above, lower case and upper case values are accepted as well. + + + +Example 1 - A Visual Studio 2022 build with user-defined script arguments: + +env = environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['8.1', 'store', '-vcvars_ver=14.1']) +env.Program('hello', ['hello.c'], CCFLAGS='/MD', LIBS=['kernel32', 'user32', 'runtimeobject']) + + + + +Example 1 - Output fragment: + +... +link /nologo /OUT:_build001\hello.exe kernel32.lib user32.lib runtimeobject.lib _build001\hello.obj +LINK : fatal error LNK1104: cannot open file 'MSVCRT.lib' +... + + + + +Example 2 - A Visual Studio 2022 build with user-defined script arguments and the script error policy set +to issue a warning when msvc batch file errors are detected: + +env = environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['8.1', 'store', '-vcvars_ver=14.1'], MSVC_SCRIPTERROR_POLICY='warn') +env.Program('hello', ['hello.c'], CCFLAGS='/MD', LIBS=['kernel32', 'user32', 'runtimeobject']) + + + + +Example 2 - Output fragment: + +... +scons: warning: vc script errors detected: +[ERROR:vcvars.bat] The UWP Application Platform requires a Windows 10 SDK. +[ERROR:vcvars.bat] WindowsSdkDir = "C:\Program Files (x86)\Windows Kits\8.1\" +[ERROR:vcvars.bat] host/target architecture is not supported : { x64 , x64 } +... +link /nologo /OUT:_build001\hello.exe kernel32.lib user32.lib runtimeobject.lib _build001\hello.obj +LINK : fatal error LNK1104: cannot open file 'MSVCRT.lib' + + + + +Important usage details: + + + +&cv-MSVC_SCRIPTERROR_POLICY; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SCRIPTERROR_POLICY; must be set before the first msvc tool is +loaded into the environment. + + + +Due to &scons; implementation details, not all Windows system environment variables are propagated +to the environment in which the msvc batch file is executed. Depending on Visual Studio version +and installation options, non-fatal msvc batch file error messages may be generated for ancillary +tools which may not affect builds with the msvc compiler. For this reason, caution is recommended +when setting the script error policy to raise an exception (e.g., 'Error'). + + + + + + + + + + + +Pass user-defined arguments to the Visual C++ batch file determined via autodetection. + + + +&cv-MSVC_SCRIPT_ARGS; is available for msvc batch file arguments that do not have first-class support +via construction variables or when there is an issue with the appropriate construction variable validation. +When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;) +rather than &cv-MSVC_SCRIPT_ARGS; arguments. + + + +The valid values for &cv-MSVC_SCRIPT_ARGS; are: None, a string, +or a list of strings. + + + +The &cv-MSVC_SCRIPT_ARGS; value is converted to a scalar string (i.e., "flattened"). +The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined +via autodetection subject to the validation conditions listed below. + + + +&cv-MSVC_SCRIPT_ARGS; is ignored when the value is None and when the +result from argument conversion is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SCRIPT_ARGS; is specified for Visual Studio 2013 and earlier. + + + +Multiple SDK version arguments (e.g., '10.0.20348.0') are specified +in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument +(e.g., '10.0.20348.0') is specified in &cv-MSVC_SCRIPT_ARGS;. +Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and &cv-MSVC_SCRIPT_ARGS; +are not allowed. + + + +Multiple toolset version arguments (e.g., '-vcvars_ver=14.29') +are specified in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument +(e.g., '-vcvars_ver=14.29') is specified in &cv-MSVC_SCRIPT_ARGS;. +Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and +&cv-MSVC_SCRIPT_ARGS; are not allowed. + + + +Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre') +are specified in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument +(e.g., '-vcvars_spectre_libs=spectre') is specified in +&cv-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS; +and &cv-MSVC_SCRIPT_ARGS; are not allowed. + + + +Multiple UWP arguments (e.g., uwp or store) are specified +in &cv-MSVC_SCRIPT_ARGS;. + + + +&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or +store) is specified in &cv-MSVC_SCRIPT_ARGS;. Multiple UWP declarations +via &cv-link-MSVC_UWP_APP; and &cv-MSVC_SCRIPT_ARGS; are not allowed. + + + + + + +Example 1 - A Visual Studio 2022 build with an SDK version and a toolset version +specified with a string argument: + +env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS='10.0.20348.0 -vcvars_ver=14.29.30133') + + + + +Example 2 - A Visual Studio 2022 build with an SDK version and a toolset version +specified with a list argument: + +env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['10.0.20348.0', '-vcvars_ver=14.29.30133']) + + + + +Important usage details: + + + +&cv-MSVC_SCRIPT_ARGS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SCRIPT_ARGS; must be set before the first msvc tool is +loaded into the environment. + + + +Other than checking for multiple declarations as described above, &cv-MSVC_SCRIPT_ARGS; arguments +are not validated. + + + + +Erroneous, inconsistent, and/or version incompatible &cv-MSVC_SCRIPT_ARGS; arguments are likely +to result in build failures for reasons that are not readily apparent and may be difficult to diagnose. + +The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent +and compatible with the version of msvc selected. + + + + + + + + + + + +Build with a specific version of the Microsoft Software Development Kit (SDK). + + + +The valid values for &cv-MSVC_SDK_VERSION; are: None +or a string containing the requested SDK version (e.g., '10.0.20348.0'). + + + +&cv-MSVC_SDK_VERSION; is ignored when the value is None and when +the value is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SDK_VERSION; is specified for Visual Studio 2013 and earlier. + + + +&cv-MSVC_SDK_VERSION; is specified and an SDK version argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via &cv-MSVC_SDK_VERSION; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + +The &cv-MSVC_SDK_VERSION; specified does not match any of the supported formats: + + +'10.0.XXXXX.Y' [SDK 10.0] + + +'8.1' [SDK 8.1] + + + + + +The system folder for the corresponding &cv-MSVC_SDK_VERSION; version is not found. +The requested SDK version does not appear to be installed. + + + +The &cv-MSVC_SDK_VERSION; version does not appear to support the requested platform +type (i.e., UWP or Desktop). The requested SDK version +platform type components do not appear to be installed. + + + +The &cv-MSVC_SDK_VERSION; version is 8.1, the platform type is +UWP, and the build tools selected are from Visual Studio 2017 +and later (i.e., &cv-link-MSVC_VERSION; must be '14.0' or &cv-link-MSVC_TOOLSET_VERSION; +must be '14.0'). + + + + + + +Example 1 - A Visual Studio 2022 build with a specific Windows SDK version: + +env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0') + + + + +Example 2 - A Visual Studio 2022 build with a specific SDK version for the Universal Windows Platform: + +env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0', MSVC_UWP_APP=True) + + + + +Important usage details: + + + +&cv-MSVC_SDK_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SDK_VERSION; must be set before the first msvc tool is +loaded into the environment. + + + + +Should a SDK 10.0 version be installed that does not follow the naming scheme above, the +SDK version will need to be specified via &cv-link-MSVC_SCRIPT_ARGS; until the version number +validation format can be extended. + + + + +Should an exception be raised indicating that the SDK version is not found, verify that +the requested SDK version is installed with the necessary platform type components. + + + +There is a known issue with the Microsoft libraries when the target architecture is +ARM64 and a Windows 11 SDK (version '10.0.22000.0' and later) is used +with the v141 build tools and older v142 toolsets +(versions '14.28.29333' and earlier). Should build failures arise with these combinations +of settings due to unresolved symbols in the Microsoft libraries, &cv-MSVC_SDK_VERSION; may be employed to +specify a Windows 10 SDK (e.g., '10.0.20348.0') for the build. + + + + + + + + + + + +Build with a specific Visual C++ toolset version. + + + +Specifying &cv-MSVC_TOOLSET_VERSION; does not affect the autodetection and selection +of msvc instances. The &cv-MSVC_TOOLSET_VERSION; is applied after +an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION; +is not specified. + + + +The valid values for &cv-MSVC_TOOLSET_VERSION; are: None +or a string containing the requested toolset version (e.g., '14.29'). + + + +&cv-MSVC_TOOLSET_VERSION; is ignored when the value is None and when +the value is an empty string. The validation conditions below do not apply. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_TOOLSET_VERSION; is specified for Visual Studio 2015 and earlier. + + + +&cv-MSVC_TOOLSET_VERSION; is specified and a toolset version argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via &cv-MSVC_TOOLSET_VERSION; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + + +The &cv-MSVC_TOOLSET_VERSION; specified does not match any of the supported formats: + + + + + +'XX.Y' + + + +'XX.YY' + + + +'XX.YY.ZZZZZ' + + + +'XX.YY.Z' to 'XX.YY.ZZZZ' + +[&scons; extension not directly supported by the msvc batch files and may be removed in the future] + + + + +'XX.YY.ZZ.N' [SxS format] + + + +'XX.YY.ZZ.NN' [SxS format] + + + + + + + +The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified +is for Visual Studio 2013 and earlier (e.g., '12.0'). + + + +The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified +is greater than the msvc version selected (e.g., '99.0'). + + + +A system folder for the corresponding &cv-MSVC_TOOLSET_VERSION; version is not found. +The requested toolset version does not appear to be installed. + + + + + + +Toolset selection details: + + + +When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number: +the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION; +prefix is selected. + + + +When &cv-MSVC_TOOLSET_VERSION; is specified using the major msvc version prefix +(i.e., 'XX.Y') and the major msvc version is that of the latest release of +Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version. + +In the latest release of Visual Studio, the default Visual C++ toolset version is not necessarily the +toolset with the largest version number. + + + + + + +Example 1 - A default Visual Studio build with a partial toolset version specified: + +env = Environment(MSVC_TOOLSET_VERSION='14.2') + + + + +Example 2 - A default Visual Studio build with a partial toolset version specified: + +env = Environment(MSVC_TOOLSET_VERSION='14.29') + + + + +Example 3 - A Visual Studio 2022 build with a full toolset version specified: + +env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133') + + + + +Example 4 - A Visual Studio 2022 build with an SxS toolset version specified: + +env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11') + + + + +Important usage details: + + + +&cv-MSVC_TOOLSET_VERSION; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_TOOLSET_VERSION; must be set before the first msvc tool is +loaded into the environment. + + + + +The existence of the toolset host architecture and target architecture folders are not verified +when &cv-MSVC_TOOLSET_VERSION; is specified which could result in build failures. + +The burden is on the user to ensure the requisite toolset target architecture build tools are installed. + + + + + + + + + + + +Build with the spectre-mitigated Visual C++ libraries. + + + +The valid values for &cv-MSVC_SPECTRE_LIBS; are: True, +False, or None. + + + +When &cv-MSVC_SPECTRE_LIBS; is enabled (i.e., True), +the Visual C++ environment will include the paths to the spectre-mitigated implementations +of the Microsoft Visual C++ libraries. + + + +An exception is raised when any of the following conditions are satisfied: + + + +&cv-MSVC_SPECTRE_LIBS; is enabled for Visual Studio 2015 and earlier. + + + +&cv-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument is specified in +&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-MSVC_SPECTRE_LIBS; +and &cv-link-MSVC_SCRIPT_ARGS; are not allowed. + + + +&cv-MSVC_SPECTRE_LIBS; is enabled and the platform type is UWP. There +are no spectre-mitigated libraries for Universal Windows Platform (UWP) applications or +components. + + + + + + +Example - A Visual Studio 2022 build with spectre mitigated Visual C++ libraries: + +env = Environment(MSVC_VERSION='14.3', MSVC_SPECTRE_LIBS=True) + + + + +Important usage details: + + + +&cv-MSVC_SPECTRE_LIBS; must be passed as an argument to the &f-link-Environment; +constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is +loaded via the default tools list or via a tools list passed to the +&f-link-Environment; constructor. +Otherwise, &cv-MSVC_SPECTRE_LIBS; must be set before the first msvc tool is +loaded into the environment. + + + +Additional compiler switches (e.g., /Qspectre) are necessary for including +spectre mitigations when building user artifacts. Refer to the Visual Studio documentation for +details. + + + + +The existence of the spectre libraries host architecture and target architecture folders are not +verified when &cv-MSVC_SPECTRE_LIBS; is enabled which could result in build failures. + +The burden is on the user to ensure the requisite libraries with spectre mitigations are installed. + + + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/msvs.py scons-4.4.0+dfsg/SCons/Tool/msvs.py --- scons-4.0.1+dfsg/SCons/Tool/msvs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/msvs.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.msvs - -Tool-specific initialization for Microsoft Visual Studio project files. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,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 +""" Tool-specific initialization for Microsoft Visual Studio project files. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import base64 import uuid @@ -48,10 +43,11 @@ import SCons.PathList import SCons.Util import SCons.Warnings - -from .MSCommon import msvc_exists, msvc_setup_env_once from SCons.Defaults import processDefines from SCons.compat import PICKLE_PROTOCOL +from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once + +tool_name = 'msvs' ############################################################################## # Below here are the classes and functions for generation of @@ -326,7 +322,7 @@ self.usrhead = V9UserHeader self.usrconf = V9UserConfiguration self.usrdebg = V9DebugSettings - _UserGenerator.__init__(self, dspfile, source, env) + super().__init__(dspfile, source, env) def UserProject(self): confkeys = sorted(self.configs.keys()) @@ -385,7 +381,10 @@ def __init__(self, dspfile, source, env): version_num, suite = msvs_parse_version(env['MSVS_VERSION']) - if version_num >= 14.2: + if version_num >= 14.3: + # Visual Studio 2022 is considered to be version 17. + self.versionstr = '17.0' + elif version_num >= 14.2: # Visual Studio 2019 is considered to be version 16. self.versionstr = '16.0' elif version_num >= 14.1: @@ -398,7 +397,7 @@ self.usrhead = V10UserHeader self.usrconf = V10UserConfiguration self.usrdebg = V10DebugSettings - _UserGenerator.__init__(self, dspfile, source, env) + super().__init__(dspfile, source, env) def UserProject(self): confkeys = sorted(self.configs.keys()) @@ -607,6 +606,7 @@ config.platform = 'Win32' self.configs[variant] = config + # DEBUG: leave enabled, test/MSVS/CPPPATH-dirs.py expects this print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") for i in range(len(variants)): @@ -781,7 +781,7 @@ data = pickle.loads(datas) except KeyboardInterrupt: raise - except: + except Exception: return # unable to unpickle any data for some reason self.configs.update(data) @@ -1444,7 +1444,9 @@ '\t\n' % str(self.sconscript)) def Parse(self): - print("_GenerateV10DSP.Parse()") + # DEBUG + # print("_GenerateV10DSP.Parse()") + pass def Build(self): try: @@ -1487,7 +1489,7 @@ class _GenerateV7DSW(_DSWGenerator): """Generates a Solution file for MSVS .NET""" def __init__(self, dswfile, source, env): - _DSWGenerator.__init__(self, dswfile, source, env) + super().__init__(dswfile, source, env) self.file = None self.version = self.env['MSVS_VERSION'] @@ -1530,7 +1532,8 @@ config.platform = 'Win32' self.configs[variant] = config - print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") + # DEBUG + # print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") if 'variant' not in env: raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ @@ -1601,7 +1604,10 @@ def PrintSolution(self): """Writes a solution file""" self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr) - if self.version_num >= 14.2: + if self.version_num >= 14.3: + # Visual Studio 2022 is considered to be version 17. + self.file.write('# Visual Studio 17\n') + elif self.version_num >= 14.2: # Visual Studio 2019 is considered to be version 16. self.file.write('# Visual Studio 16\n') elif self.version_num > 14.0: @@ -2073,7 +2079,7 @@ env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"' # Set-up ms tools paths for default version - msvc_setup_env_once(env) + msvc_setup_env_once(env, tool=tool_name) if 'MSVS_VERSION' in env: version_num, suite = msvs_parse_version(env['MSVS_VERSION']) @@ -2103,7 +2109,7 @@ env['SCONS_HOME'] = os.environ.get('SCONS_HOME') def exists(env): - return msvc_exists(env) + return msvc_setup_env_tool(env, tool=tool_name) # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Tool/msvsTests.py scons-4.4.0+dfsg/SCons/Tool/msvsTests.py --- scons-4.0.1+dfsg/SCons/Tool/msvsTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/msvsTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -412,9 +412,6 @@ def __contains__(self, key): return key in self.dict - def has_key(self, name): - return name in self.dict - def get(self, name, value=None): if name in self.dict: return self.dict[name] @@ -564,17 +561,20 @@ rv = key.keyarray[index] except IndexError: raise SCons.Util.RegError -# print "Enum Key",key.name,"[",index,"] =>",rv + # DEBUG + # print "Enum Key",key.name,"[",index,"] =>",rv return rv def DummyEnumValue(key, index): rv = key.valindex(index) -# print "Enum Value",key.name,"[",index,"] =>",rv + # DEBUG + # print "Enum Value",key.name,"[",index,"] =>",rv return rv def DummyQueryValue(key, value): rv = key.value(value) -# print "Query Value",key.name+"\\"+value,"=>",rv + # DEBUG + # print "Query Value",key.name+"\\"+value,"=>",rv return rv def DummyExists(path): @@ -726,8 +726,18 @@ for param_cppdefines, expected_cppdefines in tests_cppdefines: for param_cpppaths, expected_cpppaths in tests_cpppaths: for param_cppflags, expected_cppflags in tests_cppflags: - print('Testing %s. with :\n variant = %s \n cmdargs = "%s" \n cppdefines = "%s" \n cpppaths = "%s" \n cppflags = "%s"' % \ - (str_function_test, list_variant, param_cmdargs, param_cppdefines, param_cpppaths, param_cppflags)) + # DEBUG: + # print( + # 'Testing %s. with :\n variant = %s \n cmdargs = "%s" \n cppdefines = "%s" \n cpppaths = "%s" \n cppflags = "%s"' + # % ( + # str_function_test, + # list_variant, + # param_cmdargs, + # param_cppdefines, + # param_cpppaths, + # param_cppflags, + # ) + # ) param_configs = [] expected_configs = {} for platform in ['Win32', 'x64']: @@ -959,7 +969,8 @@ ] for test_class in test_classes: - print("TEST: ", test_class.__doc__) + # DEBUG + # print("TEST: ", test_class.__doc__) back_osenv = copy.deepcopy(os.environ) try: # XXX: overriding the os.environ is bad, but doing it @@ -971,7 +982,9 @@ if k in os.environ: del os.environ[k] - suite = unittest.makeSuite(test_class, 'test_') + loader = unittest.TestLoader() + loader.testMethodPrefix = 'test_' + suite = loader.loadTestsFromTestCase(test_class) if not TestUnit.cli.get_runner()().run(suite).wasSuccessful(): exit_val = 1 finally: diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/Globals.py scons-4.4.0+dfsg/SCons/Tool/ninja/Globals.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/Globals.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/Globals.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +# 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.Action + +NINJA_RULES = "__NINJA_CUSTOM_RULES" +NINJA_POOLS = "__NINJA_CUSTOM_POOLS" +NINJA_CUSTOM_HANDLERS = "__NINJA_CUSTOM_HANDLERS" +NINJA_BUILD = "NINJA_BUILD" +NINJA_WHEREIS_MEMO = {} +NINJA_STAT_MEMO = {} +NINJA_DEFAULT_TARGETS = [] +NINJA_CMDLINE_TARGETS = [] +__NINJA_RULE_MAPPING = {} + +# These are the types that get_command can do something with +COMMAND_TYPES = ( + SCons.Action.CommandAction, + SCons.Action.CommandGeneratorAction, +) +ninja_builder_initialized = False diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/__init__.py scons-4.4.0+dfsg/SCons/Tool/ninja/__init__.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,508 @@ +# MIT License +# +# Copyright 2020 MongoDB Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +"""Generate build.ninja files from SCons aliases.""" + +import importlib +import os +import traceback +import subprocess +import sys + +import SCons +import SCons.Script +import SCons.Tool.ninja.Globals +from SCons.Script import GetOption + +from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS, NINJA_CMDLINE_TARGETS +from .Methods import register_custom_handler, register_custom_rule_mapping, register_custom_rule, register_custom_pool, \ + set_build_node_callback, get_generic_shell_command, CheckNinjaCompdbExpand, get_command, \ + gen_get_response_file_command +from .Overrides import ninja_hack_linkcom, ninja_hack_arcom, NinjaNoResponseFiles, ninja_always_serial, AlwaysExecAction +from .Utils import ninja_add_command_line_options, \ + ninja_noop, ninja_print_conf_log, ninja_csig, ninja_contents, ninja_stat, ninja_whereis, NinjaExperimentalWarning + +try: + import ninja + NINJA_BINARY = ninja.__file__ +except ImportError: + NINJA_BINARY = False +else: + from .NinjaState import NinjaState + +NINJA_STATE = None + + +def ninja_builder(env, target, source): + """Generate a build.ninja for source.""" + if not isinstance(source, list): + source = [source] + if not isinstance(target, list): + target = [target] + + # We have no COMSTR equivalent so print that we're generating + # here. + print("Generating:", str(target[0])) + + generated_build_ninja = target[0].get_abspath() + try: + NINJA_STATE.generate() + except Exception: + raise SCons.Errors.BuildError( + errstr=f"ERROR: an exception occurred while generating the ninja file:\n{traceback.format_exc()}", + node=target) + + if env["PLATFORM"] == "win32": + # TODO: Is this necessary as you set env variable in the ninja build file per target? + # this is not great, its doesn't consider specific + # node environments, which means on linux the build could + # behave differently, because on linux you can set the environment + # per command in the ninja file. This is only needed if + # running ninja directly from a command line that hasn't + # had the environment setup (vcvarsall.bat) + with open('run_ninja_env.bat', 'w') as f: + for key in env['ENV']: + f.write('set {}={}\n'.format(key, env['ENV'][key])) + f.write('{} -f {} %*\n'.format(NINJA_STATE.ninja_bin_path, generated_build_ninja)) + cmd = ['run_ninja_env.bat'] + + else: + cmd = [NINJA_STATE.ninja_bin_path, '-f', generated_build_ninja] + + if str(env.get("NINJA_DISABLE_AUTO_RUN")).lower() not in ['1', 'true']: + num_jobs = env.get('NINJA_MAX_JOBS', env.GetOption("num_jobs")) + cmd += ['-j' + str(num_jobs)] + env.get('NINJA_CMD_ARGS', '').split() + NINJA_CMDLINE_TARGETS + print(f"ninja will be run with command line targets: {' '.join(NINJA_CMDLINE_TARGETS)}") + print("Executing:", str(' '.join(cmd))) + + # execute the ninja build at the end of SCons, trying to + # reproduce the output like a ninja build would + def execute_ninja(): + + proc = subprocess.Popen(cmd, + stderr=sys.stderr, + stdout=subprocess.PIPE, + universal_newlines=True, + env=os.environ if env["PLATFORM"] == "win32" else env['ENV'] + ) + for stdout_line in iter(proc.stdout.readline, ""): + yield stdout_line + proc.stdout.close() + return_code = proc.wait() + if return_code: + raise subprocess.CalledProcessError(return_code, 'ninja') + + erase_previous = False + for output in execute_ninja(): + output = output.strip() + if erase_previous: + sys.stdout.write('\x1b[2K') # erase previous line + sys.stdout.write("\r") + else: + sys.stdout.write(os.linesep) + sys.stdout.write(output) + sys.stdout.flush() + # this will only erase ninjas [#/#] lines + # leaving warnings and other output, seems a bit + # prone to failure with such a simple check + erase_previous = output.startswith('[') + sys.stdout.write("\n") + + +def options(opts): + """ + Add command line Variables for Ninja builder. + """ + opts.AddVariables( + ("NINJA_CMD_ARGS", "Arguments to pass to ninja"), + ) + +def exists(env): + """Enable if called.""" + + if 'ninja' not in GetOption('experimental'): + return False + + # This variable disables the tool when storing the SCons command in the + # generated ninja file to ensure that the ninja tool is not loaded when + # SCons should do actual work as a subprocess of a ninja build. The ninja + # tool is very invasive into the internals of SCons and so should never be + # enabled when SCons needs to build a target. + if env.get("__NINJA_NO", "0") == "1": + return False + + # pypi ninja module detection done at top of file during import ninja. + if NINJA_BINARY: + return NINJA_BINARY + else: + raise SCons.Warnings.SConsWarning("Failed to import ninja, attempt normal SCons build.") + + +def ninja_emitter(target, source, env): + """ fix up the source/targets """ + + ninja_file = env.File(env.subst("$NINJA_FILE_NAME")) + ninja_file.attributes.ninja_file = True + + # Someone called env.Ninja('my_targetname.ninja') + if not target and len(source) == 1: + target = source + + # Default target name is $NINJA_PREFIX.$NINJA.SUFFIX + if not target: + target = [ninja_file, ] + + # No source should have been passed. Drop it. + if source: + source = [] + + return target, source + + +def generate(env): + """Generate the NINJA builders.""" + global NINJA_STATE, NINJA_CMDLINE_TARGETS + + if 'ninja' not in GetOption('experimental'): + return + + if not SCons.Tool.ninja.Globals.ninja_builder_initialized: + SCons.Tool.ninja.Globals.ninja_builder_initialized = True + + ninja_add_command_line_options() + + if not NINJA_BINARY: + raise SCons.Warnings.SConsWarning("Failed to import ninja, attempt normal SCons build.") + + env["NINJA_DISABLE_AUTO_RUN"] = env.get("NINJA_DISABLE_AUTO_RUN", GetOption('disable_execute_ninja')) + env["NINJA_FILE_NAME"] = env.get("NINJA_FILE_NAME", "build.ninja") + + # Add the Ninja builder. + always_exec_ninja_action = AlwaysExecAction(ninja_builder, {}) + ninja_builder_obj = SCons.Builder.Builder(action=always_exec_ninja_action, + emitter=ninja_emitter) + env.Append(BUILDERS={"Ninja": ninja_builder_obj}) + + env["NINJA_ALIAS_NAME"] = env.get("NINJA_ALIAS_NAME", "generate-ninja") + env['NINJA_DIR'] = env.Dir(env.get("NINJA_DIR", '#/.ninja')) + env["NINJA_SCONS_DAEMON_KEEP_ALIVE"] = env.get("NINJA_SCONS_DAEMON_KEEP_ALIVE", 180000) + + if GetOption("disable_ninja"): + env.SConsignFile(os.path.join(str(env['NINJA_DIR']), '.ninja.sconsign')) + + # here we allow multiple environments to construct rules and builds + # into the same ninja file + if NINJA_STATE is None: + ninja_file = env.Ninja() + env['NINJA_FILE'] = ninja_file[0] + env.AlwaysBuild(ninja_file) + + # We need to force SCons to only build the ninja target when ninja tool is loaded. + # The ninja tool is going to 'rip the guts out' of scons and make it basically unable + # to do anything in terms of building, so any targets besides the ninja target will + # end up doing nothing besides causing confusion. We save the targets however, so that + # SCons and invoke ninja to build them in lieu of the user. + NINJA_CMDLINE_TARGETS = SCons.Script.BUILD_TARGETS + SCons.Script.BUILD_TARGETS = SCons.Script.TargetList(env.Alias("$NINJA_ALIAS_NAME", ninja_file)) + else: + if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]: + SCons.Warnings.SConsWarning("Generating multiple ninja files not supported, set ninja file name before tool initialization.") + ninja_file = [NINJA_STATE.ninja_file] + + + def ninja_generate_deps(env): + """Return a list of SConscripts + TODO: Should we also include files loaded from site_scons/*** + or even all loaded modules? https://stackoverflow.com/questions/4858100/how-to-list-imported-modules + TODO: Do we want this to be Nodes? + """ + return sorted([str(s) for s in SCons.Node.SConscriptNodes]) + + env['_NINJA_REGENERATE_DEPS_FUNC'] = ninja_generate_deps + + env['NINJA_REGENERATE_DEPS'] = env.get('NINJA_REGENERATE_DEPS', '${_NINJA_REGENERATE_DEPS_FUNC(__env__)}') + + # This adds the required flags such that the generated compile + # commands will create depfiles as appropriate in the Ninja file. + if 'CCDEPFLAGS' not in env: + # Issue some warning here + pass + else: + env.Append(CCFLAGS='$CCDEPFLAGS') + + env.AddMethod(CheckNinjaCompdbExpand, "CheckNinjaCompdbExpand") + + # Provide a way for custom rule authors to easily access command + # generation. + env.AddMethod(get_generic_shell_command, "NinjaGetGenericShellCommand") + env.AddMethod(get_command, "NinjaGetCommand") + env.AddMethod(gen_get_response_file_command, "NinjaGenResponseFileProvider") + env.AddMethod(set_build_node_callback, "NinjaSetBuildNodeCallback") + + # Provides a way for users to handle custom FunctionActions they + # want to translate to Ninja. + env[NINJA_CUSTOM_HANDLERS] = {} + env.AddMethod(register_custom_handler, "NinjaRegisterFunctionHandler") + + # Provides a mechanism for inject custom Ninja rules which can + # then be mapped using NinjaRuleMapping. + env[NINJA_RULES] = {} + env.AddMethod(register_custom_rule, "NinjaRule") + + # Provides a mechanism for inject custom Ninja pools which can + # be used by providing the NINJA_POOL="name" as an + # OverrideEnvironment variable in a builder call. + env[NINJA_POOLS] = {} + env.AddMethod(register_custom_pool, "NinjaPool") + + # Add the ability to register custom NinjaRuleMappings for Command + # builders. We don't store this dictionary in the env to prevent + # accidental deletion of the CC/XXCOM mappings. You can still + # overwrite them if you really want to but you have to explicit + # about it this way. The reason is that if they were accidentally + # deleted you would get a very subtly incorrect Ninja file and + # might not catch it. + env.AddMethod(register_custom_rule_mapping, "NinjaRuleMapping") + + # on windows we need to change the link action + ninja_hack_linkcom(env) + + # Normally in SCons actions for the Program and *Library builders + # will return "${*COM}" as their pre-subst'd command line. However + # if a user in a SConscript overwrites those values via key access + # like env["LINKCOM"] = "$( $ICERUN $)" + env["LINKCOM"] then + # those actions no longer return the "bracketted" string and + # instead return something that looks more expanded. So to + # continue working even if a user has done this we map both the + # "bracketted" and semi-expanded versions. + def robust_rule_mapping(var, rule, tool): + provider = gen_get_response_file_command(env, rule, tool) + env.NinjaRuleMapping("${" + var + "}", provider) + + # some of these construction vars could be generators, e.g. + # CommandGeneratorAction, so if the var is not a string, we + # can't parse the generated string. + if isinstance(env.get(var), str): + env.NinjaRuleMapping(env.get(var, None), provider) + + robust_rule_mapping("CCCOM", "CC", "$CC") + robust_rule_mapping("SHCCCOM", "CC", "$CC") + robust_rule_mapping("CXXCOM", "CXX", "$CXX") + robust_rule_mapping("SHCXXCOM", "CXX", "$CXX") + robust_rule_mapping("LINKCOM", "LINK", "$LINK") + robust_rule_mapping("SHLINKCOM", "LINK", "$SHLINK") + robust_rule_mapping("ARCOM", "AR", "$AR") + + # Make SCons node walk faster by preventing unnecessary work + env.Decider("timestamp-match") + + # Used to determine if a build generates a source file. Ninja + # requires that all generated sources are added as order_only + # dependencies to any builds that *might* use them. + # TODO: switch to using SCons to help determine this (Github Issue #3624) + env["NINJA_GENERATED_SOURCE_SUFFIXES"] = env.get('NINJA_GENERATED_SOURCE_SUFFIXES', [".h", ".hpp"]) + + # Force ARCOM so use 's' flag on ar instead of separately running ranlib + ninja_hack_arcom(env) + + if GetOption('disable_ninja'): + return env + + print("Initializing ninja tool... this feature is experimental. SCons internals and all environments will be affected.") + print(f"SCons running in ninja mode. {env['NINJA_FILE']} will be generated.") + # This is the point of no return, anything after this comment + # makes changes to SCons that are irreversible and incompatible + # with a normal SCons build. We return early if __NINJA_NO=1 has + # been given on the command line (i.e. by us in the generated + # ninja file) here to prevent these modifications from happening + # when we want SCons to do work. Everything before this was + # necessary to setup the builder and other functions so that the + # tool can be unconditionally used in the users's SCons files. + + if not exists(env): + return + + # Set a known variable that other tools can query so they can + # behave correctly during ninja generation. + env["GENERATING_NINJA"] = True + + # These methods are no-op'd because they do not work during ninja + # generation, expected to do no work, or simply fail. All of which + # are slow in SCons. So we overwrite them with no logic. + SCons.Node.FS.File.make_ready = ninja_noop + SCons.Node.FS.File.prepare = ninja_noop + SCons.Node.FS.File.push_to_cache = ninja_noop + SCons.Executor.Executor.prepare = ninja_noop + SCons.Taskmaster.Task.prepare = ninja_noop + SCons.Node.FS.File.built = ninja_noop + SCons.Node.Node.visited = ninja_noop + + # We make lstat a no-op because it is only used for SONAME + # symlinks which we're not producing. + SCons.Node.FS.LocalFS.lstat = ninja_noop + + # This is a slow method that isn't memoized. We make it a noop + # since during our generation we will never use the results of + # this or change the results. + SCons.Node.FS.is_up_to_date = ninja_noop + + # We overwrite stat and WhereIs with eternally memoized + # implementations. See the docstring of ninja_stat and + # ninja_whereis for detailed explanations. + SCons.Node.FS.LocalFS.stat = ninja_stat + SCons.Util.WhereIs = ninja_whereis + + # Monkey patch get_csig and get_contents for some classes. It + # slows down the build significantly and we don't need contents or + # content signatures calculated when generating a ninja file since + # we're not doing any SCons caching or building. + SCons.Executor.Executor.get_contents = ninja_contents( + SCons.Executor.Executor.get_contents + ) + SCons.Node.Alias.Alias.get_contents = ninja_contents( + SCons.Node.Alias.Alias.get_contents + ) + SCons.Node.FS.File.get_contents = ninja_contents(SCons.Node.FS.File.get_contents) + SCons.Node.FS.File.get_csig = ninja_csig(SCons.Node.FS.File.get_csig) + SCons.Node.FS.Dir.get_csig = ninja_csig(SCons.Node.FS.Dir.get_csig) + SCons.Node.Alias.Alias.get_csig = ninja_csig(SCons.Node.Alias.Alias.get_csig) + + # Ignore CHANGED_SOURCES and CHANGED_TARGETS. We don't want those + # to have effect in a generation pass because the generator + # shouldn't generate differently depending on the current local + # state. Without this, when generating on Windows, if you already + # had a foo.obj, you would omit foo.cpp from the response file. Do the same for UNCHANGED. + SCons.Executor.Executor._get_changed_sources = SCons.Executor.Executor._get_sources + SCons.Executor.Executor._get_changed_targets = SCons.Executor.Executor._get_targets + SCons.Executor.Executor._get_unchanged_sources = SCons.Executor.Executor._get_sources + SCons.Executor.Executor._get_unchanged_targets = SCons.Executor.Executor._get_targets + + # Replace false action messages with nothing. + env["PRINT_CMD_LINE_FUNC"] = ninja_print_conf_log + + # This reduces unnecessary subst_list calls to add the compiler to + # the implicit dependencies of targets. Since we encode full paths + # in our generated commands we do not need these slow subst calls + # as executing the command will fail if the file is not found + # where we expect it. + env["IMPLICIT_COMMAND_DEPENDENCIES"] = False + + # This makes SCons more aggressively cache MD5 signatures in the + # SConsign file. + # TODO: WPD shouldn't this be set to 0? + env.SetOption("max_drift", 1) + + # The Serial job class is SIGNIFICANTLY (almost twice as) faster + # than the Parallel job class for generating Ninja files. So we + # monkey the Jobs constructor to only use the Serial Job class. + SCons.Job.Jobs.__init__ = ninja_always_serial + + ninja_syntax = importlib.import_module(".ninja_syntax", package='ninja') + + if NINJA_STATE is None: + NINJA_STATE = NinjaState(env, ninja_file[0], ninja_syntax) + + # TODO: this is hacking into scons, preferable if there were a less intrusive way + # We will subvert the normal builder execute to make sure all the ninja file is dependent + # on all targets generated from any builders + SCons_Builder_BuilderBase__execute = SCons.Builder.BuilderBase._execute + + def NinjaBuilderExecute(self, env, target, source, overwarn={}, executor_kw={}): + # this ensures all environments in which a builder executes from will + # not create list actions for linking on windows + ninja_hack_linkcom(env) + targets = SCons_Builder_BuilderBase__execute(self, env, target, source, overwarn=overwarn, executor_kw=executor_kw) + + if not SCons.Util.is_List(target): + target = [target] + + for target in targets: + if target.check_attributes('ninja_file') is None and not target.is_conftest(): + env.Depends(ninja_file, targets) + return targets + SCons.Builder.BuilderBase._execute = NinjaBuilderExecute + + # Here we monkey patch the Task.execute method to not do a bunch of + # unnecessary work. If a build is a regular builder (i.e not a conftest and + # not our own Ninja builder) then we add it to the NINJA_STATE. Otherwise we + # build it like normal. This skips all of the caching work that this method + # would normally do since we aren't pulling any of these targets from the + # cache. + # + # In the future we may be able to use this to actually cache the build.ninja + # file once we have the upstream support for referencing SConscripts as File + # nodes. + def ninja_execute(self): + + target = self.targets[0] + if target.get_env().get('NINJA_SKIP'): + return + if target.check_attributes('ninja_file') is None: + NINJA_STATE.add_build(target) + else: + target.build() + + SCons.Taskmaster.Task.execute = ninja_execute + + # Make needs_execute always return true instead of determining out of + # date-ness. + SCons.Script.Main.BuildTask.needs_execute = lambda x: True + + def ninja_Set_Default_Targets(env, tlist): + """ + Record the default targets if they were ever set by the user. Ninja + will need to write the default targets and make sure not to include + the scons daemon shutdown target. + """ + SCons.Script._Get_Default_Targets = SCons.Script._Set_Default_Targets_Has_Been_Called + SCons.Script.DEFAULT_TARGETS = ninja_file + for t in tlist: + if isinstance(t, SCons.Node.Node): + NINJA_DEFAULT_TARGETS.append(t) + else: + nodes = env.arg2nodes(t, env.fs.Entry) + NINJA_DEFAULT_TARGETS.extend(nodes) + SCons.Script._Set_Default_Targets = ninja_Set_Default_Targets + + # We will eventually need to overwrite TempFileMunge to make it + # handle persistent tempfiles or get an upstreamed change to add + # some configurability to it's behavior in regards to tempfiles. + # + # Set all three environment variables that Python's + # tempfile.mkstemp looks at as it behaves differently on different + # platforms and versions of Python. + # build_dir = env.subst("$NINJA_DIR") + # if build_dir == "": + # build_dir = "." + # os.environ["TMPDIR"] = env.Dir("{}/.response_files".format(build_dir)).get_abspath() + # os.environ["TEMP"] = os.environ["TMPDIR"] + # os.environ["TMP"] = os.environ["TMPDIR"] + # if not os.path.isdir(os.environ["TMPDIR"]): + # env.Execute(SCons.Defaults.Mkdir(os.environ["TMPDIR"])) + + env['TEMPFILEDIR'] = "$NINJA_DIR/.response_files" + env["TEMPFILE"] = NinjaNoResponseFiles + + env.Alias('run-ninja-scons-daemon', 'run_ninja_scons_daemon_phony') + env.Alias('shutdown-ninja-scons-daemon', 'shutdown_ninja_scons_daemon_phony') diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/Methods.py scons-4.4.0+dfsg/SCons/Tool/ninja/Methods.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/Methods.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/Methods.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,286 @@ +# 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 os +import shlex +import textwrap + +import SCons +from SCons.Subst import SUBST_CMD +from SCons.Tool.ninja import NINJA_CUSTOM_HANDLERS, NINJA_RULES, NINJA_POOLS +from SCons.Tool.ninja.Globals import __NINJA_RULE_MAPPING +from SCons.Tool.ninja.Utils import get_targets_sources, get_dependencies, get_order_only, get_outputs, get_inputs, \ + get_rule, get_path, generate_command, get_command_env, get_comstr + + +def register_custom_handler(env, name, handler): + """Register a custom handler for SCons function actions.""" + env[NINJA_CUSTOM_HANDLERS][name] = handler + + +def register_custom_rule_mapping(env, pre_subst_string, rule): + """Register a function to call for a given rule.""" + SCons.Tool.ninja.Globals.__NINJA_RULE_MAPPING[pre_subst_string] = rule + + +def register_custom_rule(env, rule, command, description="", deps=None, pool=None, use_depfile=False, use_response_file=False, response_file_content="$rspc"): + """Allows specification of Ninja rules from inside SCons files.""" + rule_obj = { + "command": command, + "description": description if description else "{} $out".format(rule), + } + + if use_depfile: + rule_obj["depfile"] = os.path.join(get_path(env['NINJA_DIR']), '$out.depfile') + + if deps is not None: + rule_obj["deps"] = deps + + if pool is not None: + rule_obj["pool"] = pool + + if use_response_file: + rule_obj["rspfile"] = "$out.rsp" + rule_obj["rspfile_content"] = response_file_content + + env[NINJA_RULES][rule] = rule_obj + + +def register_custom_pool(env, pool, size): + """Allows the creation of custom Ninja pools""" + env[NINJA_POOLS][pool] = size + + +def set_build_node_callback(env, node, callback): + if not node.is_conftest(): + node.attributes.ninja_build_callback = callback + + +def get_generic_shell_command(env, node, action, targets, sources, executor=None): + return ( + "GENERATED_CMD", + { + "cmd": generate_command(env, node, action, targets, sources, executor=executor), + "env": get_command_env(env, targets, sources), + }, + # Since this function is a rule mapping provider, it must return a list of dependencies, + # and usually this would be the path to a tool, such as a compiler, used for this rule. + # However this function is to generic to be able to reliably extract such deps + # from the command, so we return a placeholder empty list. It should be noted that + # generally this function will not be used solely and is more like a template to generate + # the basics for a custom provider which may have more specific options for a provider + # function for a custom NinjaRuleMapping. + [] + ) + + +def CheckNinjaCompdbExpand(env, context): + """ Configure check testing if ninja's compdb can expand response files""" + + # TODO: When would this be false? + context.Message('Checking if ninja compdb can expand response files... ') + ret, output = context.TryAction( + action='ninja -f $SOURCE -t compdb -x CMD_RSP > $TARGET', + extension='.ninja', + text=textwrap.dedent(""" + rule CMD_RSP + command = $cmd @$out.rsp > fake_output.txt + description = Building $out + rspfile = $out.rsp + rspfile_content = $rspc + build fake_output.txt: CMD_RSP fake_input.txt + cmd = echo + pool = console + rspc = "test" + """)) + result = '@fake_output.txt.rsp' not in output + context.Result(result) + return result + + +def get_command(env, node, action): # pylint: disable=too-many-branches + """Get the command to execute for node.""" + if node.env: + sub_env = node.env + else: + sub_env = env + executor = node.get_executor() + tlist, slist = get_targets_sources(node) + + # Generate a real CommandAction + if isinstance(action, SCons.Action.CommandGeneratorAction): + # pylint: disable=protected-access + action = action._generate(tlist, slist, sub_env, SUBST_CMD, executor=executor) + + variables = {} + + # since we will check the ninja rule map for this command str, we must make sure + # its string so its hashable. + comstr = str(get_comstr(sub_env, action, tlist, slist)) + if not comstr: + return None + + provider = __NINJA_RULE_MAPPING.get(comstr, get_generic_shell_command) + rule, variables, provider_deps = provider(sub_env, node, action, tlist, slist, executor=executor) + if node.get_env().get('NINJA_FORCE_SCONS_BUILD'): + rule = 'TEMPLATE' + + # Get the dependencies for all targets + implicit = list({dep for tgt in tlist for dep in get_dependencies(tgt)}) + + # Now add in the other dependencies related to the command, + # e.g. the compiler binary. The ninja rule can be user provided so + # we must do some validation to resolve the dependency path for ninja. + for provider_dep in provider_deps: + + provider_dep = sub_env.subst(provider_dep) + if not provider_dep: + continue + + # If the tool is a node, then SCons will resolve the path later, if its not + # a node then we assume it generated from build and make sure it is existing. + if isinstance(provider_dep, SCons.Node.Node) or os.path.exists(provider_dep): + implicit.append(provider_dep) + continue + + # in some case the tool could be in the local directory and be supplied without the ext + # such as in windows, so append the executable suffix and check. + prog_suffix = sub_env.get('PROGSUFFIX', '') + provider_dep_ext = provider_dep if provider_dep.endswith(prog_suffix) else provider_dep + prog_suffix + if os.path.exists(provider_dep_ext): + implicit.append(provider_dep_ext) + continue + + # Many commands will assume the binary is in the path, so + # we accept this as a possible input from a given command. + + provider_dep_abspath = sub_env.WhereIs(provider_dep) or sub_env.WhereIs(provider_dep, path=os.environ["PATH"]) + if provider_dep_abspath: + implicit.append(provider_dep_abspath) + continue + + # Possibly these could be ignore and the build would still work, however it may not always + # rebuild correctly, so we hard stop, and force the user to fix the issue with the provided + # ninja rule. + raise Exception("Could not resolve path for %s dependency on node '%s'" % (provider_dep, node)) + + ninja_build = { + "order_only": get_order_only(node), + "outputs": get_outputs(node), + "inputs": get_inputs(node), + "implicit": implicit, + "rule": get_rule(node, rule), + "variables": variables, + } + + # Don't use sub_env here because we require that NINJA_POOL be set + # on a per-builder call basis to prevent accidental strange + # behavior like env['NINJA_POOL'] = 'console' and sub_env can be + # the global Environment object if node.env is None. + # Example: + # + # Allowed: + # + # env.Command("ls", NINJA_POOL="ls_pool") + # + # Not allowed and ignored: + # + # env["NINJA_POOL"] = "ls_pool" + # env.Command("ls") + # + # TODO: Why not alloe env['NINJA_POOL'] ? (bdbaddog) + if node.env and node.env.get("NINJA_POOL", None) is not None: + ninja_build["pool"] = node.env["NINJA_POOL"] + + return ninja_build + + +def gen_get_response_file_command(env, rule, tool, tool_is_dynamic=False, custom_env={}): + """Generate a response file command provider for rule name.""" + + # If win32 using the environment with a response file command will cause + # ninja to fail to create the response file. Additionally since these rules + # generally are not piping through cmd.exe /c any environment variables will + # make CreateProcess fail to start. + # + # On POSIX we can still set environment variables even for compile + # commands so we do so. + use_command_env = not env["PLATFORM"] == "win32" + if "$" in tool: + tool_is_dynamic = True + + def get_response_file_command(env, node, action, targets, sources, executor=None): + if hasattr(action, "process"): + cmd_list, _, _ = action.process(targets, sources, env, executor=executor) + cmd_list = [str(c).replace("$", "$$") for c in cmd_list[0]] + else: + command = generate_command( + env, node, action, targets, sources, executor=executor + ) + cmd_list = shlex.split(command) + + if tool_is_dynamic: + tool_command = env.subst( + tool, target=targets, source=sources, executor=executor + ) + else: + tool_command = tool + + try: + # Add 1 so we always keep the actual tool inside of cmd + tool_idx = cmd_list.index(tool_command) + 1 + except ValueError: + raise Exception( + "Could not find tool {} in {} generated from {}".format( + tool, cmd_list, get_comstr(env, action, targets, sources) + ) + ) + + cmd, rsp_content = cmd_list[:tool_idx], cmd_list[tool_idx:] + + # Canonicalize the path to have forward (posix style) dir sep characters. + if os.altsep: + rsp_content = [rsp_content_item.replace(os.sep, os.altsep) for rsp_content_item in rsp_content] + rsp_content = ['"' + rsp_content_item + '"' for rsp_content_item in rsp_content] + rsp_content = " ".join(rsp_content) + + variables = {"rspc": rsp_content, rule: cmd} + if use_command_env: + variables["env"] = get_command_env(env, targets, sources) + + for key, value in custom_env.items(): + variables["env"] += env.subst( + "export %s=%s;" % (key, value), target=targets, source=sources, executor=executor + ) + " " + + if node.get_env().get('NINJA_FORCE_SCONS_BUILD'): + ret_rule = 'TEMPLATE' + else: + if len(' '.join(cmd_list)) < env.get('MAXLINELENGTH', 2048): + ret_rule = rule + else: + ret_rule = rule + '_RSP' + + return ret_rule, variables, [tool_command] + + return get_response_file_command diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_daemon_build.py scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_daemon_build.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_daemon_build.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_daemon_build.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" +This script is intended to execute a single build target. This script should be +called by ninja, passing the port, ninja dir, and build target via arguments. +The script then executes a simple get request to the scons daemon which is listening +on from localhost on the set port. +""" + +import http.client +import sys +import time +import os +import logging +import pathlib +import tempfile +import hashlib +import traceback +import socket + +ninja_builddir = pathlib.Path(sys.argv[2]) +daemon_dir = pathlib.Path(tempfile.gettempdir()) / ( + "scons_daemon_" + str(hashlib.md5(str(ninja_builddir).encode()).hexdigest()) +) +os.makedirs(daemon_dir, exist_ok=True) + +logging.basicConfig( + filename=daemon_dir / "scons_daemon_request.log", + filemode="a", + format="%(asctime)s %(message)s", + level=logging.DEBUG, +) + + +def log_error(msg): + logging.debug(msg) + sys.stderr.write(msg) + + +while True: + try: + if not os.path.exists(daemon_dir / "pidfile"): + if sys.argv[3] != '--exit': + logging.debug(f"ERROR: Server pid not found {daemon_dir / 'pidfile'} for request {sys.argv[3]}") + exit(1) + else: + logging.debug("WARNING: Unnecessary request to shutdown server, it's already shutdown.") + exit(0) + + logging.debug(f"Sending request: {sys.argv[3]}") + conn = http.client.HTTPConnection( + "127.0.0.1", port=int(sys.argv[1]), timeout=60 + ) + if sys.argv[3] == '--exit': + conn.request("GET", "/?exit=1") + else: + conn.request("GET", "/?build=" + sys.argv[3]) + response = None + + while not response: + try: + response = conn.getresponse() + except (http.client.RemoteDisconnected, http.client.ResponseNotReady, socket.timeout): + time.sleep(0.1) + except http.client.HTTPException: + log_error(f"Error: {traceback.format_exc()}") + exit(1) + else: + msg = response.read() + status = response.status + if status != 200: + log_error(msg.decode("utf-8")) + exit(1) + + logging.debug(f"Request Done: {sys.argv[3]}") + exit(0) + + except ConnectionRefusedError: + logging.debug(f"Server refused connection to build {sys.argv[3]}, maybe it was too busy, tring again: {traceback.format_exc()}") + time.sleep(0.1) + + except Exception: + log_error(f"Failed to send command: {traceback.format_exc()}") + exit(1) + + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_run_daemon.py scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_run_daemon.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_run_daemon.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_run_daemon.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" +This script is intended to be called by ninja to start up the scons daemon process. It will +launch the server and attempt to connect to it. This process needs to completely detach +from the spawned process so ninja can consider the build edge completed. It should be passed +the args which should be forwarded to the scons daemon process which could be any number of +# arguments. However the first few arguments are required to be port, ninja dir, and keep alive +timeout in seconds. + +The scons_daemon_dirty file acts as a pidfile marker letting this script quickly skip over +restarting the server if the server is running. The assumption here is the pidfile should only +exist if the server is running. +""" + +import subprocess +import sys +import os +import pathlib +import tempfile +import hashlib +import logging +import time +import http.client +import traceback +import socket + +ninja_builddir = pathlib.Path(sys.argv[2]) +daemon_dir = pathlib.Path(tempfile.gettempdir()) / ( + "scons_daemon_" + str(hashlib.md5(str(ninja_builddir).encode()).hexdigest()) +) +os.makedirs(daemon_dir, exist_ok=True) + +logging.basicConfig( + filename=daemon_dir / "scons_daemon.log", + filemode="a", + format="%(asctime)s %(message)s", + level=logging.DEBUG, +) + +def log_error(msg): + logging.debug(msg) + sys.stderr.write(msg) + +if not os.path.exists(ninja_builddir / "scons_daemon_dirty"): + cmd = [ + sys.executable, + str(pathlib.Path(__file__).parent / "ninja_scons_daemon.py"), + ] + sys.argv[1:] + logging.debug(f"Starting daemon with {' '.join(cmd)}") + + + # TODO: Remove the following when Python3.6 support is dropped. + if sys.platform == 'win32' and sys.version_info[0] == 3 and sys.version_info[1] == 6: + # on Windows with Python version 3.6, popen does not do a good job disconnecting + # the std handles and this make ninja hang because they stay open to the original + # process ninja launched. Here we can force the handles to be separated. + # See: https://docs.python.org/3.6/library/subprocess.html#subprocess.STARTUPINFO + # See Also: https://docs.python.org/3.6/library/subprocess.html#subprocess.Popen + # Note when you don't specify stdin, stdout, and/or stderr they default to None + # which indicates no output redirection will occur. + si = subprocess.STARTUPINFO() + si.dwFlags = subprocess.STARTF_USESTDHANDLES + p = subprocess.Popen( + cmd, close_fds=True, shell=False, startupinfo=si + ) + else: + p = subprocess.Popen( + cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=False, + ) + with open(daemon_dir / "pidfile", "w") as f: + f.write(str(p.pid)) + with open(ninja_builddir / "scons_daemon_dirty", "w") as f: + f.write(str(p.pid)) + + error_msg = f"ERROR: Failed to connect to scons daemon.\n Check {daemon_dir / 'scons_daemon.log'} for more info.\n" + + while True: + try: + logging.debug("Attempting to connect scons daemon") + conn = http.client.HTTPConnection( + "127.0.0.1", port=int(sys.argv[1]), timeout=60 + ) + conn.request("GET", "/?ready=true") + response = None + + try: + response = conn.getresponse() + except (http.client.RemoteDisconnected, http.client.ResponseNotReady, socket.timeout): + time.sleep(0.01) + except http.client.HTTPException: + log_error(f"Error: {traceback.format_exc()}") + exit(1) + else: + msg = response.read() + status = response.status + if status != 200: + log_error(msg.decode("utf-8")) + exit(1) + logging.debug("Server Responded it was ready!") + break + + except ConnectionRefusedError: + logging.debug(f"Server not ready, server PID: {p.pid}") + time.sleep(1) + if p.poll() is not None: + log_error(f"Server process died, aborting: {p.returncode}") + sys.exit(p.returncode) + except ConnectionResetError: + log_error("Server ConnectionResetError") + exit(1) + except Exception: + log_error(f"Error: {traceback.format_exc()}") + exit(1) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_scons_daemon.py scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_scons_daemon.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/ninja_scons_daemon.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/ninja_scons_daemon.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,367 @@ +#!/usr/bin/env python3 +# +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" +This script primarily consists of two threads, the http server thread and the scons interactive +process thread. The http server thread will listen on the passed port for http get request +which should indicate some action for the scons interactive process to take. + +The daemon will keep log files in a tmp directory correlated to the hash of the absolute path +of the ninja build dir passed. The daemon will also use a keep alive time to know when to shut +itself down after the passed timeout of no activity. Any time the server receives a get request, +the keep alive time will be reset. +""" + +import http.server +import socketserver +from urllib.parse import urlparse, parse_qs +import time +from threading import Condition +from subprocess import PIPE, Popen +import sys +import os +import threading +import queue +import pathlib +import logging +from timeit import default_timer as timer +import traceback +import tempfile +import hashlib +import signal + +port = int(sys.argv[1]) +ninja_builddir = pathlib.Path(sys.argv[2]) +daemon_keep_alive = int(sys.argv[3]) +args = sys.argv[4:] + +# TODO: Remove the following when Python3.6 support is dropped. +# Windows and Python36 passed nothing for the std handles because of issues with popen +# and its handles so we have to make some fake ones to prevent exceptions. +if sys.platform == 'win32' and sys.version_info[0] == 3 and sys.version_info[1] == 6: + from io import StringIO + sys.stderr = StringIO() + sys.stdout = StringIO() + +daemon_dir = pathlib.Path(tempfile.gettempdir()) / ( + "scons_daemon_" + str(hashlib.md5(str(ninja_builddir).encode()).hexdigest()) +) +os.makedirs(daemon_dir, exist_ok=True) +logging.basicConfig( + filename=daemon_dir / "scons_daemon.log", + filemode="a", + format="%(asctime)s %(message)s", + level=logging.DEBUG, +) + + +def daemon_log(message): + logging.debug(message) + + +def custom_readlines(handle, line_separator="\n", chunk_size=1): + buf = "" + while not handle.closed: + data = handle.read(chunk_size) + if not data: + break + buf += data.decode("utf-8") + if line_separator in buf: + chunks = buf.split(line_separator) + buf = chunks.pop() + for chunk in chunks: + yield chunk + line_separator + if buf.endswith("scons>>>"): + yield buf + buf = "" + + +def custom_readerr(handle, line_separator="\n", chunk_size=1): + buf = "" + while not handle.closed: + data = handle.read(chunk_size) + if not data: + break + buf += data.decode("utf-8") + if line_separator in buf: + chunks = buf.split(line_separator) + buf = chunks.pop() + for chunk in chunks: + yield chunk + line_separator + + +def enqueue_output(out, queue): + for line in iter(custom_readlines(out)): + queue.put(line) + out.close() + + +def enqueue_error(err, queue): + for line in iter(custom_readerr(err)): + queue.put(line) + err.close() + + +input_q = queue.Queue() +output_q = queue.Queue() +error_q = queue.Queue() + +building_cv = Condition() +error_cv = Condition() + +class StateInfo: + def __init__(self) -> None: + self.thread_error = False + self.finished_building = [] + self.error_nodes = [] + self.startup_failed = False + self.startup_output = '' + self.daemon_needs_to_shutdown = False + self.httpd = None + +shared_state = StateInfo() + +def sigint_func(signum, frame): + global shared_state + shared_state.daemon_needs_to_shutdown = True + +signal.signal(signal.SIGINT, sigint_func) + + +def daemon_thread_func(): + global shared_state + try: + args_list = args + ["--interactive"] + daemon_log(f"Starting daemon with args: {' '.join(args_list)}") + daemon_log(f"cwd: {os.getcwd()}") + + p = Popen(args_list, stdout=PIPE, stderr=PIPE, stdin=PIPE) + + t = threading.Thread(target=enqueue_output, args=(p.stdout, output_q)) + t.daemon = True + t.start() + + te = threading.Thread(target=enqueue_error, args=(p.stderr, error_q)) + te.daemon = True + te.start() + + daemon_ready = False + + building_node = None + startup_complete = False + + # While scons interactive process is stil running... + while p.poll() is None: + + # while there is scons output to process + while True: + try: + line = output_q.get(block=False, timeout=0.01) + except queue.Empty: + # breaks out of the output processing loop + break + else: + daemon_log("output: " + line.strip()) + if not startup_complete: + shared_state.startup_output += line + + if "scons: building terminated because of errors." in line: + error_output = "" + while True: + try: + error_output += error_q.get(block=False, timeout=0.01) + except queue.Empty: + break + shared_state.error_nodes += [{"node": building_node, "error": error_output}] + daemon_ready = True + building_node = None + with building_cv: + building_cv.notify() + + elif line == "scons>>>": + shared_state.startup_output = '' + startup_complete = True + + with error_q.mutex: + error_q.queue.clear() + daemon_ready = True + with building_cv: + building_cv.notify() + building_node = None + + # while there is input to process... + while daemon_ready and not input_q.empty(): + + try: + building_node = input_q.get(block=False, timeout=0.01) + except queue.Empty: + break + if "exit" in building_node: + daemon_log("input: " + "exit") + p.stdin.write("exit\n".encode("utf-8")) + p.stdin.flush() + with building_cv: + shared_state.finished_building += [building_node] + daemon_ready = False + shared_state.daemon_needs_to_shutdown = True + break + + else: + input_command = "build " + building_node + "\n" + daemon_log("input: " + input_command.strip()) + + p.stdin.write(input_command.encode("utf-8")) + p.stdin.flush() + with building_cv: + shared_state.finished_building += [building_node] + daemon_ready = False + + if shared_state.daemon_needs_to_shutdown: + break + time.sleep(0.01) + + # our scons process is done, make sure we are shutting down in this case + if not shared_state.daemon_needs_to_shutdown: + if not startup_complete: + shared_state.startup_failed = True + shared_state.daemon_needs_to_shutdown = True + + except Exception: + shared_state.thread_error = True + daemon_log("SERVER ERROR: " + traceback.format_exc()) + raise + + +daemon_thread = threading.Thread(target=daemon_thread_func) +daemon_thread.daemon = True +daemon_thread.start() + +logging.debug( + f"Starting request server on port {port}, keep alive: {daemon_keep_alive}" +) + +keep_alive_timer = timer() + +def server_thread_func(): + global shared_state + class S(http.server.BaseHTTPRequestHandler): + def do_GET(self): + global shared_state + global keep_alive_timer + try: + gets = parse_qs(urlparse(self.path).query) + + # process a request from ninja for a node for scons to build. + # Currently this is a serial process because scons interactive is serial + # is it was originally meant for a real human user to be providing input + # parallel input was never implemented. + build = gets.get("build") + if build: + keep_alive_timer = timer() + + daemon_log(f"Got request: {build[0]}") + input_q.put(build[0]) + + def pred(): + return build[0] in shared_state.finished_building + + with building_cv: + building_cv.wait_for(pred) + + for error_node in shared_state.error_nodes: + if error_node["node"] == build[0]: + self.send_response(500) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(error_node["error"].encode()) + return + + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + return + + # this message is used in server startup, to make sure the server launched + # successfully. If SCons interactive got to a input prompt (scons>>>), then + # the server is ready to start processing commands. Otherwise the server will + # send an error response back to ninja and shut itself down. + ready = gets.get("ready") + if ready: + if shared_state.startup_failed: + self.send_response(500) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(shared_state.startup_output.encode()) + return + + exitbuild = gets.get("exit") + if exitbuild: + input_q.put("exit") + + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + + except Exception: + shared_state.thread_error = True + daemon_log("SERVER ERROR: " + traceback.format_exc()) + raise + + def log_message(self, format, *args): + return + + socketserver.TCPServer.allow_reuse_address = True + shared_state.httpd = socketserver.TCPServer(("127.0.0.1", port), S) + shared_state.httpd.serve_forever() + + +server_thread = threading.Thread(target=server_thread_func) +server_thread.daemon = True +server_thread.start() + +while (timer() - keep_alive_timer < daemon_keep_alive + and not shared_state.thread_error + and not shared_state.daemon_needs_to_shutdown): + time.sleep(1) + +if shared_state.thread_error: + daemon_log(f"Shutting server on port {port} down because thread error.") +elif shared_state.daemon_needs_to_shutdown: + daemon_log("Server shutting down upon request.") +else: + daemon_log( + f"Shutting server on port {port} down because timed out: {daemon_keep_alive}" + ) +shared_state.httpd.shutdown() +if os.path.exists(ninja_builddir / "scons_daemon_dirty"): + os.unlink(ninja_builddir / "scons_daemon_dirty") +if os.path.exists(daemon_dir / "pidfile"): + os.unlink(daemon_dir / "pidfile") + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/NinjaState.py scons-4.4.0+dfsg/SCons/Tool/ninja/NinjaState.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/NinjaState.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/NinjaState.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,923 @@ +# 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 +# "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 io +import os +import pathlib +import signal +import tempfile +import shutil +import sys +import random +import filecmp +from os.path import splitext +from tempfile import NamedTemporaryFile +import ninja +import hashlib + +import SCons +from SCons.Script import COMMAND_LINE_TARGETS +from SCons.Util import wait_for_process_to_die +from SCons.Errors import InternalError +from .Globals import COMMAND_TYPES, NINJA_RULES, NINJA_POOLS, \ + NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS +from .Rules import _install_action_function, _mkdir_action_function, _lib_symlink_action_function, _copy_action_function +from .Utils import get_path, alias_to_ninja_build, generate_depfile, ninja_noop, get_order_only, \ + get_outputs, get_inputs, get_dependencies, get_rule, get_command_env, to_escaped_list, ninja_sorted_build +from .Methods import get_command + + +# pylint: disable=too-many-instance-attributes +class NinjaState: + """Maintains state of Ninja build system as it's translated from SCons.""" + + def __init__(self, env, ninja_file, ninja_syntax): + self.env = env + self.ninja_file = ninja_file + + self.ninja_bin_path = env.get('NINJA') + if not self.ninja_bin_path: + # default to using ninja installed with python module + ninja_bin = 'ninja.exe' if env["PLATFORM"] == "win32" else 'ninja' + self.ninja_bin_path = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + ninja_bin)) + if not os.path.exists(self.ninja_bin_path): + # couldn't find it, just give the bin name and hope + # its in the path later + self.ninja_bin_path = ninja_bin + self.ninja_syntax = ninja_syntax + self.writer_class = ninja_syntax.Writer + self.__generated = False + self.translator = SConsToNinjaTranslator(env) + self.generated_suffixes = env.get("NINJA_GENERATED_SOURCE_SUFFIXES", []) + + # List of generated builds that will be written at a later stage + self.builds = dict() + + # SCons sets this variable to a function which knows how to do + # shell quoting on whatever platform it's run on. Here we use it + # to make the SCONS_INVOCATION variable properly quoted for things + # like CCFLAGS + scons_escape = env.get("ESCAPE", lambda x: x) + + # The daemon port should be the same across runs, unless explicitly set + # or if the portfile is deleted. This ensures the ninja file is deterministic + # across regen's if nothings changed. The construction var should take preference, + # then portfile is next, and then otherwise create a new random port to persist in + # use. + scons_daemon_port = None + os.makedirs(get_path(self.env.get("NINJA_DIR")), exist_ok=True) + scons_daemon_port_file = str(pathlib.Path(get_path(self.env.get("NINJA_DIR"))) / "scons_daemon_portfile") + + if env.get('NINJA_SCONS_DAEMON_PORT') is not None: + scons_daemon_port = int(env.get('NINJA_SCONS_DAEMON_PORT')) + elif os.path.exists(scons_daemon_port_file): + with open(scons_daemon_port_file) as f: + scons_daemon_port = int(f.read()) + else: + scons_daemon_port = random.randint(10000, 60000) + + with open(scons_daemon_port_file, 'w') as f: + f.write(str(scons_daemon_port)) + + # if SCons was invoked from python, we expect the first arg to be the scons.py + # script, otherwise scons was invoked from the scons script + python_bin = '' + if os.path.basename(sys.argv[0]) == 'scons.py': + python_bin = ninja_syntax.escape(scons_escape(sys.executable)) + self.variables = { + "COPY": "cmd.exe /c 1>NUL copy" if sys.platform == "win32" else "cp", + 'PORT': scons_daemon_port, + 'NINJA_DIR_PATH': env.get('NINJA_DIR').abspath, + 'PYTHON_BIN': sys.executable, + 'NINJA_TOOL_DIR': pathlib.Path(__file__).parent, + 'NINJA_SCONS_DAEMON_KEEP_ALIVE': str(env.get('NINJA_SCONS_DAEMON_KEEP_ALIVE')), + "SCONS_INVOCATION": '{} {} --disable-ninja __NINJA_NO=1 $out'.format( + python_bin, + " ".join( + [ninja_syntax.escape(scons_escape(arg)) for arg in sys.argv if arg not in COMMAND_LINE_TARGETS] + ), + ), + "SCONS_INVOCATION_W_TARGETS": "{} {} NINJA_DISABLE_AUTO_RUN=1".format( + python_bin, " ".join([ + ninja_syntax.escape(scons_escape(arg)) + for arg in sys.argv + if arg != 'NINJA_DISABLE_AUTO_RUN=1']) + ), + # This must be set to a global default per: + # https://ninja-build.org/manual.html#_deps + # English Visual Studio will have the default below, + # otherwise the user can define the variable in the first environment + # that initialized ninja tool + "msvc_deps_prefix": env.get("NINJA_MSVC_DEPS_PREFIX", "Note: including file:") + } + + self.rules = { + "CMD": { + "command": "cmd /c $env$cmd $in $out" if sys.platform == "win32" else "$env$cmd $in $out", + "description": "Building $out", + "pool": "local_pool", + }, + "GENERATED_CMD": { + "command": "cmd /c $env$cmd" if sys.platform == "win32" else "$env$cmd", + "description": "Building $out", + "pool": "local_pool", + }, + # We add the deps processing variables to this below. We + # don't pipe these through cmd.exe on Windows because we + # use this to generate a compile_commands.json database + # which can't use the shell command as it's compile + # command. + "CC_RSP": { + "command": "$env$CC @$out.rsp", + "description": "Compiling $out", + "rspfile": "$out.rsp", + "rspfile_content": "$rspc", + }, + "CXX_RSP": { + "command": "$env$CXX @$out.rsp", + "description": "Compiling $out", + "rspfile": "$out.rsp", + "rspfile_content": "$rspc", + }, + "LINK_RSP": { + "command": "$env$LINK @$out.rsp", + "description": "Linking $out", + "rspfile": "$out.rsp", + "rspfile_content": "$rspc", + "pool": "local_pool", + }, + # Ninja does not automatically delete the archive before + # invoking ar. The ar utility will append to an existing archive, which + # can cause duplicate symbols if the symbols moved between object files. + # Native SCons will perform this operation so we need to force ninja + # to do the same. See related for more info: + # https://jira.mongodb.org/browse/SERVER-49457 + "AR_RSP": { + "command": "{}$env$AR @$out.rsp".format( + '' if sys.platform == "win32" else "rm -f $out && " + ), + "description": "Archiving $out", + "rspfile": "$out.rsp", + "rspfile_content": "$rspc", + "pool": "local_pool", + }, + "CC": { + "command": "$env$CC $rspc", + "description": "Compiling $out", + }, + "CXX": { + "command": "$env$CXX $rspc", + "description": "Compiling $out", + }, + "LINK": { + "command": "$env$LINK $rspc", + "description": "Linking $out", + "pool": "local_pool", + }, + "AR": { + "command": "{}$env$AR $rspc".format( + '' if sys.platform == "win32" else "rm -f $out && " + ), + "description": "Archiving $out", + "pool": "local_pool", + }, + "SYMLINK": { + "command": ( + "cmd /c mklink $out $in" + if sys.platform == "win32" + else "ln -s $in $out" + ), + "description": "Symlink $in -> $out", + }, + "INSTALL": { + "command": "$COPY $in $out", + "description": "Install $out", + "pool": "install_pool", + # On Windows cmd.exe /c copy does not always correctly + # update the timestamp on the output file. This leads + # to a stuck constant timestamp in the Ninja database + # and needless rebuilds. + # + # Adding restat here ensures that Ninja always checks + # the copy updated the timestamp and that Ninja has + # the correct information. + "restat": 1, + }, + "TEMPLATE": { + "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_daemon_build.py $PORT $NINJA_DIR_PATH $out", + "description": "Defer to SCons to build $out", + "pool": "local_pool", + "restat": 1 + }, + "EXIT_SCONS_DAEMON": { + "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_daemon_build.py $PORT $NINJA_DIR_PATH --exit", + "description": "Shutting down ninja scons daemon server", + "pool": "local_pool", + "restat": 1 + }, + "SCONS": { + "command": "$SCONS_INVOCATION $out", + "description": "$SCONS_INVOCATION $out", + "pool": "scons_pool", + # restat + # if present, causes Ninja to re-stat the command's outputs + # after execution of the command. Each output whose + # modification time the command did not change will be + # treated as though it had never needed to be built. This + # may cause the output's reverse dependencies to be removed + # from the list of pending build actions. + # + # We use restat any time we execute SCons because + # SCons calls in Ninja typically create multiple + # targets. But since SCons is doing it's own up to + # date-ness checks it may only update say one of + # them. Restat will find out which of the multiple + # build targets did actually change then only rebuild + # those targets which depend specifically on that + # output. + "restat": 1, + }, + + "SCONS_DAEMON": { + "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_run_daemon.py $PORT $NINJA_DIR_PATH $NINJA_SCONS_DAEMON_KEEP_ALIVE $SCONS_INVOCATION", + "description": "Starting scons daemon...", + "pool": "local_pool", + # restat + # if present, causes Ninja to re-stat the command's outputs + # after execution of the command. Each output whose + # modification time the command did not change will be + # treated as though it had never needed to be built. This + # may cause the output's reverse dependencies to be removed + # from the list of pending build actions. + # + # We use restat any time we execute SCons because + # SCons calls in Ninja typically create multiple + # targets. But since SCons is doing it's own up to + # date-ness checks it may only update say one of + # them. Restat will find out which of the multiple + # build targets did actually change then only rebuild + # those targets which depend specifically on that + # output. + "restat": 1, + }, + "REGENERATE": { + "command": "$SCONS_INVOCATION_W_TARGETS", + "description": "Regenerating $self", + "generator": 1, + "pool": "console", + "restat": 1, + }, + } + + if env['PLATFORM'] == 'darwin' and env.get('AR', "") == 'ar': + self.rules["AR"] = { + "command": "rm -f $out && $env$AR $rspc", + "description": "Archiving $out", + "pool": "local_pool", + } + self.pools = {"scons_pool": 1} + + def add_build(self, node): + if not node.has_builder(): + return False + + if isinstance(node, SCons.Node.Python.Value): + return False + + if isinstance(node, SCons.Node.Alias.Alias): + build = alias_to_ninja_build(node) + else: + build = self.translator.action_to_ninja_build(node) + + # Some things are unbuild-able or need not be built in Ninja + if build is None: + return False + + node_string = str(node) + if node_string in self.builds: + # TODO: If we work out a way to handle Alias() with same name as file this logic can be removed + # This works around adding Alias with the same name as a Node. + # It's not great way to workaround because it force renames the alias, + # but the alternative is broken ninja support. + warn_msg = f"Alias {node_string} name the same as File node, ninja does not support this. Renaming Alias {node_string} to {node_string}_alias." + if isinstance(node, SCons.Node.Alias.Alias): + for i, output in enumerate(build["outputs"]): + if output == node_string: + build["outputs"][i] += "_alias" + node_string += "_alias" + print(warn_msg) + elif self.builds[node_string]["rule"] == "phony": + for i, output in enumerate(self.builds[node_string]["outputs"]): + if output == node_string: + self.builds[node_string]["outputs"][i] += "_alias" + tmp_build = self.builds[node_string].copy() + del self.builds[node_string] + node_string += "_alias" + self.builds[node_string] = tmp_build + print(warn_msg) + else: + raise InternalError("Node {} added to ninja build state more than once".format(node_string)) + self.builds[node_string] = build + return True + + # TODO: rely on SCons to tell us what is generated source + # or some form of user scanner maybe (Github Issue #3624) + def is_generated_source(self, output): + """Check if output ends with a known generated suffix.""" + _, suffix = splitext(output) + return suffix in self.generated_suffixes + + def has_generated_sources(self, output): + """ + Determine if output indicates this is a generated header file. + """ + for generated in output: + if self.is_generated_source(generated): + return True + return False + + # pylint: disable=too-many-branches,too-many-locals + def generate(self): + """ + Generate the build.ninja. + + This should only be called once for the lifetime of this object. + """ + if self.__generated: + return + + num_jobs = self.env.get('NINJA_MAX_JOBS', self.env.GetOption("num_jobs")) + self.pools.update({ + "local_pool": num_jobs, + "install_pool": num_jobs / 2, + }) + + deps_format = self.env.get("NINJA_DEPFILE_PARSE_FORMAT", 'msvc' if self.env['PLATFORM'] == 'win32' else 'gcc') + for rule in ["CC", "CXX"]: + if deps_format == "msvc": + self.rules[rule]["deps"] = "msvc" + elif deps_format == "gcc" or deps_format == "clang": + self.rules[rule]["deps"] = "gcc" + self.rules[rule]["depfile"] = "$out.d" + else: + raise Exception(f"Unknown 'NINJA_DEPFILE_PARSE_FORMAT'={self.env['NINJA_DEPFILE_PARSE_FORMAT']}, use 'mvsc', 'gcc', or 'clang'.") + + for key, rule in self.env.get(NINJA_RULES, {}).items(): + # make a non response file rule for users custom response file rules. + if rule.get('rspfile') is not None: + self.rules.update({key + '_RSP': rule}) + non_rsp_rule = rule.copy() + del non_rsp_rule['rspfile'] + del non_rsp_rule['rspfile_content'] + self.rules.update({key: non_rsp_rule}) + else: + self.rules.update({key: rule}) + + self.pools.update(self.env.get(NINJA_POOLS, {})) + + content = io.StringIO() + ninja = self.writer_class(content, width=100) + + ninja.comment("Generated by scons. DO NOT EDIT.") + + ninja.variable("builddir", get_path(self.env.Dir(self.env['NINJA_DIR']).path)) + + for pool_name, size in sorted(self.pools.items()): + ninja.pool(pool_name, min(self.env.get('NINJA_MAX_JOBS', size), size)) + + for var, val in sorted(self.variables.items()): + ninja.variable(var, val) + + for rule, kwargs in sorted(self.rules.items()): + if self.env.get('NINJA_MAX_JOBS') is not None and 'pool' not in kwargs: + kwargs['pool'] = 'local_pool' + ninja.rule(rule, **kwargs) + + # If the user supplied an alias to determine generated sources, use that, otherwise + # determine what the generated sources are dynamically. + generated_sources_alias = self.env.get('NINJA_GENERATED_SOURCE_ALIAS_NAME') + generated_sources_build = None + + if generated_sources_alias: + generated_sources_build = self.builds.get(generated_sources_alias) + if generated_sources_build is None or generated_sources_build["rule"] != 'phony': + raise Exception( + "ERROR: 'NINJA_GENERATED_SOURCE_ALIAS_NAME' set, but no matching Alias object found." + ) + + if generated_sources_alias and generated_sources_build: + generated_source_files = sorted( + [] if not generated_sources_build else generated_sources_build['implicit'] + ) + + def check_generated_source_deps(build): + return ( + build != generated_sources_build + and set(build["outputs"]).isdisjoint(generated_source_files) + ) + else: + generated_sources_build = None + generated_source_files = sorted({ + output + # First find builds which have header files in their outputs. + for build in self.builds.values() + if self.has_generated_sources(build["outputs"]) + for output in build["outputs"] + # Collect only the header files from the builds with them + # in their output. We do this because is_generated_source + # returns True if it finds a header in any of the outputs, + # here we need to filter so we only have the headers and + # not the other outputs. + if self.is_generated_source(output) + }) + + if generated_source_files: + generated_sources_alias = "_ninja_generated_sources" + ninja.build( + outputs=generated_sources_alias, + rule="phony", + implicit=generated_source_files + ) + + def check_generated_source_deps(build): + return ( + not build["rule"] == "INSTALL" + and set(build["outputs"]).isdisjoint(generated_source_files) + and set(build.get("implicit", [])).isdisjoint(generated_source_files) + ) + + template_builders = [] + scons_compiledb = False + + if SCons.Script._Get_Default_Targets == SCons.Script._Set_Default_Targets_Has_Not_Been_Called: + all_targets = set() + else: + all_targets = None + + for build in [self.builds[key] for key in sorted(self.builds.keys())]: + if "compile_commands.json" in build["outputs"]: + scons_compiledb = True + + # this is for the no command line targets, no SCons default case. We want this default + # to just be all real files in the build. + if all_targets is not None and build['rule'] != 'phony': + all_targets = all_targets | set(build["outputs"]) + + if build["rule"] == "TEMPLATE": + template_builders.append(build) + continue + + if "implicit" in build: + build["implicit"].sort() + + # Don't make generated sources depend on each other. We + # have to check that none of the outputs are generated + # sources and none of the direct implicit dependencies are + # generated sources or else we will create a dependency + # cycle. + if ( + generated_source_files + and check_generated_source_deps(build) + ): + # Make all non-generated source targets depend on + # _generated_sources. We use order_only for generated + # sources so that we don't rebuild the world if one + # generated source was rebuilt. We just need to make + # sure that all of these sources are generated before + # other builds. + order_only = build.get("order_only", []) + order_only.append(generated_sources_alias) + build["order_only"] = order_only + if "order_only" in build: + build["order_only"].sort() + + # When using a depfile Ninja can only have a single output + # but SCons will usually have emitted an output for every + # thing a command will create because it's caching is much + # more complex than Ninja's. This includes things like DWO + # files. Here we make sure that Ninja only ever sees one + # target when using a depfile. It will still have a command + # that will create all of the outputs but most targets don't + # depend directly on DWO files and so this assumption is safe + # to make. + rule = self.rules.get(build["rule"]) + + # Some rules like 'phony' and other builtins we don't have + # listed in self.rules so verify that we got a result + # before trying to check if it has a deps key. + # + # Anything using deps or rspfile in Ninja can only have a single + # output, but we may have a build which actually produces + # multiple outputs which other targets can depend on. Here we + # slice up the outputs so we have a single output which we will + # use for the "real" builder and multiple phony targets that + # match the file names of the remaining outputs. This way any + # build can depend on any output from any build. + # + # We assume that the first listed output is the 'key' + # output and is stably presented to us by SCons. For + # instance if -gsplit-dwarf is in play and we are + # producing foo.o and foo.dwo, we expect that outputs[0] + # from SCons will be the foo.o file and not the dwo + # file. If instead we just sorted the whole outputs array, + # we would find that the dwo file becomes the + # first_output, and this breaks, for instance, header + # dependency scanning. + if rule is not None and (rule.get("deps") or rule.get("rspfile")): + first_output, remaining_outputs = ( + build["outputs"][0], + build["outputs"][1:], + ) + + if remaining_outputs: + ninja_sorted_build( + ninja, + outputs=remaining_outputs, rule="phony", implicit=first_output, + ) + + build["outputs"] = first_output + + # Optionally a rule can specify a depfile, and SCons can generate implicit + # dependencies into the depfile. This allows for dependencies to come and go + # without invalidating the ninja file. The depfile was created in ninja specifically + # for dealing with header files appearing and disappearing across rebuilds, but it can + # be repurposed for anything, as long as you have a way to regenerate the depfile. + # More specific info can be found here: https://ninja-build.org/manual.html#_depfile + if rule is not None and rule.get('depfile') and build.get('deps_files'): + path = build['outputs'] if SCons.Util.is_List(build['outputs']) else [build['outputs']] + generate_depfile(self.env, path[0], build.pop('deps_files', [])) + + if "inputs" in build: + build["inputs"].sort() + + ninja_sorted_build( + ninja, + **build + ) + + scons_daemon_dirty = str(pathlib.Path(get_path(self.env.get("NINJA_DIR"))) / "scons_daemon_dirty") + for template_builder in template_builders: + template_builder["implicit"] += [scons_daemon_dirty] + ninja_sorted_build( + ninja, + **template_builder + ) + + # We have to glob the SCons files here to teach the ninja file + # how to regenerate itself. We'll never see ourselves in the + # DAG walk so we can't rely on action_to_ninja_build to + # generate this rule even though SCons should know we're + # dependent on SCons files. + ninja_file_path = self.env.File(self.ninja_file).path + regenerate_deps = to_escaped_list(self.env, self.env['NINJA_REGENERATE_DEPS']) + + ninja_sorted_build( + ninja, + outputs=ninja_file_path, + rule="REGENERATE", + implicit=regenerate_deps, + variables={ + "self": ninja_file_path + } + ) + + ninja_sorted_build( + ninja, + outputs=regenerate_deps, + rule="phony", + variables={ + "self": ninja_file_path, + } + ) + + if not scons_compiledb: + # If we ever change the name/s of the rules that include + # compile commands (i.e. something like CC) we will need to + # update this build to reflect that complete list. + ninja_sorted_build( + ninja, + outputs="compile_commands.json", + rule="CMD", + pool="console", + implicit=[str(self.ninja_file)], + variables={ + "cmd": "{} -f {} -t compdb {}CC CXX > compile_commands.json".format( + # NINJA_COMPDB_EXPAND - should only be true for ninja + # This was added to ninja's compdb tool in version 1.9.0 (merged April 2018) + # https://github.com/ninja-build/ninja/pull/1223 + # TODO: add check in generate to check version and enable this by default if it's available. + self.ninja_bin_path, str(self.ninja_file), + '-x ' if self.env.get('NINJA_COMPDB_EXPAND', True) else '' + ) + }, + ) + + ninja_sorted_build( + ninja, + outputs="compiledb", rule="phony", implicit=["compile_commands.json"], + ) + + ninja_sorted_build( + ninja, + outputs=["run_ninja_scons_daemon_phony", scons_daemon_dirty], + rule="SCONS_DAEMON", + ) + + ninja.build( + "shutdown_ninja_scons_daemon_phony", + rule="EXIT_SCONS_DAEMON", + ) + + + if all_targets is None: + # Look in SCons's list of DEFAULT_TARGETS, find the ones that + # we generated a ninja build rule for. + all_targets = [str(node) for node in NINJA_DEFAULT_TARGETS] + else: + all_targets = list(all_targets) + + if len(all_targets) == 0: + all_targets = ["phony_default"] + ninja_sorted_build( + ninja, + outputs=all_targets, + rule="phony", + ) + + ninja.default([self.ninja_syntax.escape_path(path) for path in sorted(all_targets)]) + + with NamedTemporaryFile(delete=False, mode='w') as temp_ninja_file: + temp_ninja_file.write(content.getvalue()) + + if self.env.GetOption('skip_ninja_regen') and os.path.exists(ninja_file_path) and filecmp.cmp(temp_ninja_file.name, ninja_file_path): + os.unlink(temp_ninja_file.name) + else: + + daemon_dir = pathlib.Path(tempfile.gettempdir()) / ('scons_daemon_' + str(hashlib.md5(str(get_path(self.env["NINJA_DIR"])).encode()).hexdigest())) + pidfile = None + if os.path.exists(scons_daemon_dirty): + pidfile = scons_daemon_dirty + elif os.path.exists(daemon_dir / 'pidfile'): + pidfile = daemon_dir / 'pidfile' + + if pidfile: + with open(pidfile) as f: + pid = int(f.readline()) + try: + os.kill(pid, signal.SIGINT) + except OSError: + pass + + # wait for the server process to fully killed + # TODO: update wait_for_process_to_die() to handle timeout and then catch exception + # here and do something smart. + wait_for_process_to_die(pid) + + if os.path.exists(scons_daemon_dirty): + os.unlink(scons_daemon_dirty) + + shutil.move(temp_ninja_file.name, ninja_file_path) + + self.__generated = True + + +class SConsToNinjaTranslator: + """Translates SCons Actions into Ninja build objects.""" + + def __init__(self, env): + self.env = env + self.func_handlers = { + # Skip conftest builders + "_createSource": ninja_noop, + # SCons has a custom FunctionAction that just makes sure the + # target isn't static. We let the commands that ninja runs do + # this check for us. + "SharedFlagChecker": ninja_noop, + # The install builder is implemented as a function action. + # TODO: use command action #3573 + "installFunc": _install_action_function, + "MkdirFunc": _mkdir_action_function, + "Mkdir": _mkdir_action_function, + "LibSymlinksActionFunction": _lib_symlink_action_function, + "Copy": _copy_action_function + } + + self.loaded_custom = False + + # pylint: disable=too-many-return-statements + def action_to_ninja_build(self, node, action=None): + """Generate build arguments dictionary for node.""" + + if not self.loaded_custom: + self.func_handlers.update(self.env[NINJA_CUSTOM_HANDLERS]) + self.loaded_custom = True + + if node.builder is None: + return None + + if action is None: + action = node.builder.action + + if node.env and node.env.get("NINJA_SKIP"): + return None + + build = {} + env = node.env if node.env else self.env + + # Ideally this should never happen, and we do try to filter + # Ninja builders out of being sources of ninja builders but I + # can't fix every DAG problem so we just skip ninja_builders + # if we find one + if SCons.Tool.ninja.NINJA_STATE.ninja_file == str(node): + build = None + elif isinstance(action, SCons.Action.FunctionAction): + build = self.handle_func_action(node, action) + elif isinstance(action, SCons.Action.LazyAction): + # pylint: disable=protected-access + action = action._generate_cache(env) + build = self.action_to_ninja_build(node, action=action) + elif isinstance(action, SCons.Action.ListAction): + build = self.handle_list_action(node, action) + elif isinstance(action, COMMAND_TYPES): + build = get_command(env, node, action) + else: + return { + "rule": "TEMPLATE", + "order_only": get_order_only(node), + "outputs": get_outputs(node), + "inputs": get_inputs(node), + "implicit": get_dependencies(node, skip_sources=True), + } + + if build is not None: + build["order_only"] = get_order_only(node) + + # TODO: WPD Is this testing the filename to verify it's a configure context generated file? + if not node.is_conftest(): + node_callback = node.check_attributes("ninja_build_callback") + if callable(node_callback): + node_callback(env, node, build) + + return build + + def handle_func_action(self, node, action): + """Determine how to handle the function action.""" + name = action.function_name() + # This is the name given by the Subst/Textfile builders. So return the + # node to indicate that SCons is required. We skip sources here because + # dependencies don't really matter when we're going to shove these to + # the bottom of ninja's DAG anyway and Textfile builders can have text + # content as their source which doesn't work as an implicit dep in + # ninja. + if name == 'ninja_builder': + return None + + handler = self.func_handlers.get(name, None) + if handler is not None: + return handler(node.env if node.env else self.env, node) + elif name == "ActionCaller": + action_to_call = str(action).split('(')[0].strip() + handler = self.func_handlers.get(action_to_call, None) + if handler is not None: + return handler(node.env if node.env else self.env, node) + + SCons.Warnings.SConsWarning( + "Found unhandled function action {}, " + " generating scons command to build\n" + "Note: this is less efficient than Ninja," + " you can write your own ninja build generator for" + " this function using NinjaRegisterFunctionHandler".format(name) + ) + + return { + "rule": "TEMPLATE", + "order_only": get_order_only(node), + "outputs": get_outputs(node), + "inputs": get_inputs(node), + "implicit": get_dependencies(node, skip_sources=True), + } + + # pylint: disable=too-many-branches + def handle_list_action(self, node, action): + """TODO write this comment""" + results = [ + self.action_to_ninja_build(node, action=act) + for act in action.list + if act is not None + ] + results = [ + result for result in results if result is not None and result["outputs"] + ] + if not results: + return None + + # No need to process the results if we only got a single result + if len(results) == 1: + return results[0] + + all_outputs = list({output for build in results for output in build["outputs"]}) + dependencies = list({dep for build in results for dep in build.get("implicit", [])}) + + if results[0]["rule"] == "CMD" or results[0]["rule"] == "GENERATED_CMD": + cmdline = "" + for cmd in results: + + # Occasionally a command line will expand to a + # whitespace only string (i.e. ' '). Which is not a + # valid command but does not trigger the empty command + # condition if not cmdstr. So here we strip preceding + # and proceeding whitespace to make strings like the + # above become empty strings and so will be skipped. + if not cmd.get("variables") or not cmd["variables"].get("cmd"): + continue + + cmdstr = cmd["variables"]["cmd"].strip() + if not cmdstr: + continue + + # Skip duplicate commands + if cmdstr in cmdline: + continue + + if cmdline: + cmdline += " && " + + cmdline += cmdstr + + # Remove all preceding and proceeding whitespace + cmdline = cmdline.strip() + env = node.env if node.env else self.env + executor = node.get_executor() + if executor is not None: + targets = executor.get_all_targets() + else: + if hasattr(node, "target_peers"): + targets = node.target_peers + else: + targets = [node] + + # Make sure we didn't generate an empty cmdline + if cmdline: + ninja_build = { + "outputs": all_outputs, + "rule": get_rule(node, "GENERATED_CMD"), + "variables": { + "cmd": cmdline, + "env": get_command_env(env, targets, node.sources), + }, + "implicit": dependencies, + } + + if node.env and node.env.get("NINJA_POOL", None) is not None: + ninja_build["pool"] = node.env["pool"] + + return ninja_build + + elif results[0]["rule"] == "phony": + return { + "outputs": all_outputs, + "rule": "phony", + "implicit": dependencies, + } + + elif results[0]["rule"] == "INSTALL": + return { + "outputs": all_outputs, + "rule": get_rule(node, "INSTALL"), + "inputs": get_inputs(node), + "implicit": dependencies, + } + + return { + "rule": "TEMPLATE", + "order_only": get_order_only(node), + "outputs": get_outputs(node), + "inputs": get_inputs(node), + "implicit": get_dependencies(node, skip_sources=True), + } diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/ninja.xml scons-4.4.0+dfsg/SCons/Tool/ninja/ninja.xml --- scons-4.0.1+dfsg/SCons/Tool/ninja/ninja.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/ninja.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,416 @@ + + + + + %scons; + + %builders-mod; + + %functions-mod; + + %tools-mod; + + %variables-mod; + ]> + + + + + + + Sets up the &b-link-Ninja; builder, which generates a &ninja; build file, and then optionally runs &ninja;. + + + This is an experimental feature. + This functionality is subject to change and/or removal without a deprecation cycle. + + + + + + NINJA_DISABLE_AUTO_RUN + NINJA_ALIAS_NAME + NINJA_DIR + NINJA_COMPDB_EXPAND + NINJA_ENV_VAR_CACHE + NINJA_FILE_NAME + NINJA_GENERATED_SOURCE_SUFFIXES + NINJA_GENERATED_SOURCE_ALIAS_NAME + NINJA_MSVC_DEPS_PREFIX + NINJA_DEPFILE_PARSE_FORMAT + NINJA_POOL + NINJA_REGENERATE_DEPS + NINJA_SYNTAX + NINJA_FORCE_SCONS_BUILD + _NINJA_REGENERATE_DEPS_FUNC + + IMPLICIT_COMMAND_DEPENDENCIES + NINJA_SCONS_DAEMON_KEEP_ALIVE + NINJA_SCONS_DAEMON_PORT + NINJA_CMD_ARGS + + + + + + + + + + + + AR + ARCOM + ARFLAGS + CC + CCCOM + CCDEPFLAGS + CCFLAGS + CXX + CXXCOM + ESCAPE + LINK + LINKCOM + PLATFORM + RANLIB + RANLIBCOM + SHCCCOM + SHCXXCOM + SHLINK + SHLINKCOM + PROGSUFFIX + PRINT_CMD_LINE_FUNC + + + + + + + + + + + + + + A special builder which + adds a target to create a Ninja build file. + The builder does not require any source files to be specified. + + + This is an experimental feature. To enable it you must use one of the following methods + + + + +# On the command line +--experimental=ninja + +# Or in your SConstruct +SetOption('experimental', 'ninja') + + + This functionality is subject to change and/or removal without deprecation cycle. + + + To use this tool you need to install the &Python; &ninja; package, + as the tool by default depends on being able to do an + import of the package + + This can be done via: + +python -m pip install ninja + + + + + + + If called with no arguments, + the builder will default to a target name of + ninja.build. + + + If called with a single positional argument, + &scons; will "deduce" the target name from that source + argument, giving it the same name, and then + ignore the source. + This is the usual way to call the builder if a + non-default target name is wanted. + + + If called with either the + target= + or source= keyword arguments, + the value of the argument is taken as the target name. + If called with both, the + target= + value is used and source= is ignored. + If called with multiple sources, + the source list will be ignored, + since there is no way to deduce what the intent was; + in this case the default target name will be used. + + + Available since &scons; 4.2. + + + + + + + + + The list of source file suffixes which are generated by &SCons; build steps. + All source files which match these suffixes will be added to the _generated_sources alias in the output + &ninja; build file. + Then all other source files will be made to depend on this in the &ninja; build file, forcing the + generated sources to be built first. + + + + + + + + A string matching the name of a user defined alias which represents a list of all generated sources. + This will prevent the auto-detection of generated sources from &cv-NINJA_GENERATED_SOURCE_SUFFIXES;. + Then all other source files will be made to depend on this in the &ninja; build file, forcing the + generated sources to be built first. + + + + + + + + The msvc_deps_prefix string. + Propagates directly into the generated &ninja; build file. + From Ninja's docs: + defines the string which should be stripped from msvc's output + + + + + + + + Determines the type of format ninja should expect when parsing header + include depfiles. Can be , , or . + The option corresponds to format, and + or correspond to . + + + + + + + + The builddir value. + Propagates directly into the generated &ninja; build file. + From Ninja's docs: + + A directory for some Ninja output files. ... (You can also store other build output in this + directory.) + + The default value is .ninja. + + + + + + + + A generator function used to create a &ninja; depfile which + includes all the files which would require + &SCons; to be invoked if they change. + Or a list of said files. + + + + + + + + Boolean value to instruct &ninja; to expand the command line arguments normally put into + response files. + If true, prevents unexpanded lines in the compilation database like + gcc @rsp_file and instead yields expanded lines like + gcc -c -o myfile.o myfile.c -Ia -DXYZ. + + + Ninja's compdb tool added the flag in Ninja V1.9.0 + + + + + + + + A string that sets the environment for any environment variables that + differ between the OS environment and the &SCons; execution environment. + + + + It will be compatible with the default shell of the operating system. + + + + If not explicitly set, &SCons; will generate this dynamically from the + execution environment stored in the current &consenv; + (e.g. env['ENV']) + where those values differ from the existing shell.. + + + + + + + + Set the ninja_pool for this or all targets in scope for this env var. + + + + + + + + Boolean. Default: False. + If true, &SCons; will not run &ninja; automatically after creating the &ninja; build file. + + + + If not explicitly set, this will be set to True + if or + SetOption('disable_execute_ninja', True) is seen. + + + + + + + + + + The filename for the generated Ninja build file. + The default is ninja.build. + + + + + + + + The name of the alias target which will cause &SCons; to create the &ninja; build file, + and then (optionally) run &ninja;. + The default value is generate-ninja. + + + + + + + + The path to a custom ninja_syntax.py file which is used in generation. + The tool currently assumes you have &ninja; installed as a &Python; module and grabs the syntax file from that + installation if &cv-NINJA_SYNTAX; is not explicitly set. + + + + + + + + If true, causes the build nodes to callback to scons instead of using + &ninja; to build them. This is intended to be passed to the environment on the builder invocation. + It is useful if you have a build node which does something which is not easily translated into &ninja;. + + + + + + + + Internal value used to specify the function to call with argument env to generate the list of files + which if changed would require the &ninja; build file to be regenerated. + + + + + + + + The number of seconds for the SCons deamon launched by ninja to stay alive. + (Default: 180000) + + + + + + + + The TCP/IP port for the SCons daemon to listen on. + NOTE: You cannot use a port already being listened to on your build machine. + (Default: random number between 10000,60000) + + + + + + + + A string which will pass arguments through SCons to the ninja command when scons executes ninja. + Has no effect if &cv-NINJA_DISABLE_AUTO_RUN; is set. + + + This value can also be passed on the command line: + + +scons NINJA_CMD_ARGS=-v +or +scons NINJA_CMD_ARGS="-v -j 3" + + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/Overrides.py scons-4.4.0+dfsg/SCons/Tool/ninja/Overrides.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/Overrides.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/Overrides.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,96 @@ +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" +This module is to hold logic which overrides default SCons behaviors to enable +ninja file generation +""" +import SCons + + +def ninja_hack_linkcom(env): + # TODO: change LINKCOM and SHLINKCOM to handle embedding manifest exe checks + # without relying on the SCons hacks that SCons uses by default. + if env["PLATFORM"] == "win32": + from SCons.Tool.mslink import compositeLinkAction + + if env.get("LINKCOM", None) == compositeLinkAction: + env[ + "LINKCOM" + ] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows", "$LINKCOMSTR")}' + env[ + "SHLINKCOM" + ] = '${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_SHLINK_SOURCES", "$SHLINKCOMSTR")}' + + +def ninja_hack_arcom(env): + """ + Force ARCOM so use 's' flag on ar instead of separately running ranlib + """ + if env["PLATFORM"] != "win32" and env.get("RANLIBCOM"): + # There is no way to translate the ranlib list action into + # Ninja so add the s flag and disable ranlib. + # + # This is equivalent to Meson. + # https://github.com/mesonbuild/meson/blob/master/mesonbuild/linkers.py#L143 + old_arflags = str(env["ARFLAGS"]) + if "s" not in old_arflags: + old_arflags += "s" + + env["ARFLAGS"] = SCons.Util.CLVar([old_arflags]) + + # Disable running ranlib, since we added 's' above + env["RANLIBCOM"] = "" + + +class NinjaNoResponseFiles(SCons.Platform.TempFileMunge): + """Overwrite the __call__ method of SCons' TempFileMunge to not delete.""" + + def __call__(self, target, source, env, for_signature): + return self.cmd + + def _print_cmd_str(*_args, **_kwargs): + """Disable this method""" + pass + + +def ninja_always_serial(self, num, taskmaster): + """Replacement for SCons.Job.Jobs constructor which always uses the Serial Job class.""" + # We still set self.num_jobs to num even though it's a lie. The + # only consumer of this attribute is the Parallel Job class AND + # the Main.py function which instantiates a Jobs class. It checks + # if Jobs.num_jobs is equal to options.num_jobs, so if the user + # provides -j12 but we set self.num_jobs = 1 they get an incorrect + # warning about this version of Python not supporting parallel + # builds. So here we lie so the Main.py will not give a false + # warning to users. + self.num_jobs = num + self.job = SCons.Job.Serial(taskmaster) + + +# pylint: disable=too-few-public-methods +class AlwaysExecAction(SCons.Action.FunctionAction): + """Override FunctionAction.__call__ to always execute.""" + + def __call__(self, *args, **kwargs): + kwargs["execute"] = 1 + return super().__call__(*args, **kwargs) diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/Rules.py scons-4.4.0+dfsg/SCons/Tool/ninja/Rules.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/Rules.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/Rules.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,81 @@ +# 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. + +from .Utils import get_outputs, get_rule, get_inputs, get_dependencies + + +def _install_action_function(_env, node): + """Install files using the install or copy commands""" + return { + "outputs": get_outputs(node), + "rule": get_rule(node, "INSTALL"), + "inputs": get_inputs(node), + "implicit": get_dependencies(node), + } + + +def _mkdir_action_function(env, node): + return { + "outputs": get_outputs(node), + "rule": get_rule(node, "GENERATED_CMD"), + # implicit explicitly omitted, we translate these so they can be + # used by anything that depends on these but commonly this is + # hit with a node that will depend on all of the fake + # srcnode's that SCons will never give us a rule for leading + # to an invalid ninja file. + "variables": { + # On Windows mkdir "-p" is always on + "cmd": "mkdir {args}".format( + args = ' '.join(get_outputs(node)) + " & exit /b 0" if env["PLATFORM"] == "win32" else "-p " + ' '.join(get_outputs(node)), + ), + }, + } + + +def _copy_action_function(env, node): + return { + "outputs": get_outputs(node), + "inputs": get_inputs(node), + "rule": get_rule(node, "CMD"), + "variables": { + "cmd": "$COPY", + }, + } + + +def _lib_symlink_action_function(_env, node): + """Create shared object symlinks if any need to be created""" + symlinks = node.check_attributes("shliblinks") + + if not symlinks or symlinks is None: + return None + + outputs = [link.get_dir().rel_path(linktgt) for link, linktgt in symlinks] + inputs = [link.get_path() for link, _ in symlinks] + + return { + "outputs": outputs, + "inputs": inputs, + "rule": get_rule(node, "SYMLINK"), + "implicit": get_dependencies(node), + } diff -Nru scons-4.0.1+dfsg/SCons/Tool/ninja/Utils.py scons-4.4.0+dfsg/SCons/Tool/ninja/Utils.py --- scons-4.0.1+dfsg/SCons/Tool/ninja/Utils.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ninja/Utils.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,456 @@ +# 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 os +import shutil +from os.path import join as joinpath +from collections import OrderedDict + +import SCons +from SCons.Action import get_default_ENV, _string_from_cmd_list +from SCons.Script import AddOption +from SCons.Util import is_List, flatten_sequence + +class NinjaExperimentalWarning(SCons.Warnings.WarningOnByDefault): + pass + + +def ninja_add_command_line_options(): + """ + Add additional command line arguments to SCons specific to the ninja tool + """ + AddOption('--disable-execute-ninja', + dest='disable_execute_ninja', + metavar='BOOL', + action="store_true", + default=False, + help='Disable automatically running ninja after scons') + + AddOption('--disable-ninja', + dest='disable_ninja', + metavar='BOOL', + action="store_true", + default=False, + help='Disable ninja generation and build with scons even if tool is loaded. '+ + 'Also used by ninja to build targets which only scons can build.') + + AddOption('--skip-ninja-regen', + dest='skip_ninja_regen', + metavar='BOOL', + action="store_true", + default=False, + help='Allow scons to skip regeneration of the ninja file and restarting of the daemon. ' + + 'Care should be taken in cases where Glob is in use or SCons generated files are used in ' + + 'command lines.') + + +def is_valid_dependent_node(node): + """ + Return True if node is not an alias or is an alias that has children + + This prevents us from making phony targets that depend on other + phony targets that will never have an associated ninja build + target. + + We also have to specify that it's an alias when doing the builder + check because some nodes (like src files) won't have builders but + are valid implicit dependencies. + """ + if isinstance(node, SCons.Node.Alias.Alias): + return node.children() + + return not node.get_env().get("NINJA_SKIP") + + +def alias_to_ninja_build(node): + """Convert an Alias node into a Ninja phony target""" + return { + "outputs": get_outputs(node), + "rule": "phony", + "implicit": [ + get_path(src_file(n)) for n in node.children() if is_valid_dependent_node(n) + ], + } + + +def check_invalid_ninja_node(node): + return not isinstance(node, (SCons.Node.FS.Base, SCons.Node.Alias.Alias)) + + +def filter_ninja_nodes(node_list): + ninja_nodes = [] + for node in node_list: + if isinstance(node, (SCons.Node.FS.Base, SCons.Node.Alias.Alias)) and not node.get_env().get('NINJA_SKIP'): + ninja_nodes.append(node) + else: + continue + return ninja_nodes + + +def get_input_nodes(node): + if node.get_executor() is not None: + inputs = node.get_executor().get_all_sources() + else: + inputs = node.sources + return inputs + + +def invalid_ninja_nodes(node, targets): + result = False + for node_list in [node.prerequisites, get_input_nodes(node), node.children(), targets]: + if node_list: + result = result or any([check_invalid_ninja_node(node) for node in node_list]) + return result + + +def get_order_only(node): + """Return a list of order only dependencies for node.""" + if node.prerequisites is None: + return [] + return [get_path(src_file(prereq)) for prereq in filter_ninja_nodes(node.prerequisites)] + + +def get_dependencies(node, skip_sources=False): + """Return a list of dependencies for node.""" + if skip_sources: + return [ + get_path(src_file(child)) + for child in filter_ninja_nodes(node.children()) + if child not in node.sources + ] + return [get_path(src_file(child)) for child in filter_ninja_nodes(node.children())] + + +def get_inputs(node): + """Collect the Ninja inputs for node.""" + return [get_path(src_file(o)) for o in filter_ninja_nodes(get_input_nodes(node))] + + +def get_outputs(node): + """Collect the Ninja outputs for node.""" + executor = node.get_executor() + if executor is not None: + outputs = executor.get_all_targets() + else: + if hasattr(node, "target_peers"): + outputs = node.target_peers + else: + outputs = [node] + + outputs = [get_path(o) for o in filter_ninja_nodes(outputs)] + + return outputs + + +def get_targets_sources(node): + executor = node.get_executor() + if executor is not None: + tlist = executor.get_all_targets() + slist = executor.get_all_sources() + else: + if hasattr(node, "target_peers"): + tlist = node.target_peers + else: + tlist = [node] + slist = node.sources + + # Retrieve the repository file for all sources + slist = [rfile(s) for s in slist] + return tlist, slist + + +def get_path(node): + """ + Return a fake path if necessary. + + As an example Aliases use this as their target name in Ninja. + """ + if hasattr(node, "get_path"): + return node.get_path() + return str(node) + + +def rfile(node): + """ + Return the repository file for node if it has one. Otherwise return node + """ + if hasattr(node, "rfile"): + return node.rfile() + return node + + +def src_file(node): + """Returns the src code file if it exists.""" + if hasattr(node, "srcnode"): + src = node.srcnode() + if src.stat() is not None: + return src + return get_path(node) + + +def get_rule(node, rule): + tlist, slist = get_targets_sources(node) + if invalid_ninja_nodes(node, tlist): + return "TEMPLATE" + else: + return rule + + +def to_escaped_list(env, lst): + """ + Ninja tool function for returning an escaped list of strings from a subst + generator. + + env_var arg can be a list or a subst generator which returns a list. + """ + + # subst_list will take in either a raw list or a subst callable which generates + # a list, and return a list of CmdStringHolders which can be converted into raw strings. + # If a raw list was passed in, then scons_list will make a list of lists from the original + # values and even subst items in the list if they are substitutable. Flatten will flatten + # the list in that case, to ensure for either input we have a list of CmdStringHolders. + deps_list = env.Flatten(env.subst_list(lst)) + + # Now that we have the deps in a list as CmdStringHolders, we can convert them into raw strings + # and make sure to escape the strings to handle spaces in paths. We also will sort the result + # keep the order of the list consistent. + return sorted([dep.escape(env.get("ESCAPE", lambda x: x)) for dep in deps_list]) + + +def generate_depfile(env, node, dependencies): + """ + Ninja tool function for writing a depfile. The depfile should include + the node path followed by all the dependent files in a makefile format. + + dependencies arg can be a list or a subst generator which returns a list. + """ + + depfile = os.path.join(get_path(env['NINJA_DIR']), str(node) + '.depfile') + + depfile_contents = str(node) + ": " + ' '.join(to_escaped_list(env, dependencies)) + + need_rewrite = False + try: + with open(depfile, 'r') as f: + need_rewrite = (f.read() != depfile_contents) + except FileNotFoundError: + need_rewrite = True + + if need_rewrite: + os.makedirs(os.path.dirname(depfile) or '.', exist_ok=True) + with open(depfile, 'w') as f: + f.write(depfile_contents) + + +def ninja_noop(*_args, **_kwargs): + """ + A general purpose no-op function. + + There are many things that happen in SCons that we don't need and + also don't return anything. We use this to disable those functions + instead of creating multiple definitions of the same thing. + """ + return None + +def ninja_recursive_sorted_dict(build): + sorted_dict = OrderedDict() + for key, val in sorted(build.items()): + if isinstance(val, dict): + sorted_dict[key] = ninja_recursive_sorted_dict(val) + else: + sorted_dict[key] = val + return sorted_dict + + +def ninja_sorted_build(ninja, **build): + sorted_dict = ninja_recursive_sorted_dict(build) + ninja.build(**sorted_dict) + +def get_command_env(env, target, source): + """ + Return a string that sets the environment for any environment variables that + differ between the OS environment and the SCons command ENV. + + It will be compatible with the default shell of the operating system. + """ + try: + return env["NINJA_ENV_VAR_CACHE"] + except KeyError: + pass + + # Scan the ENV looking for any keys which do not exist in + # os.environ or differ from it. We assume if it's a new or + # differing key from the process environment then it's + # important to pass down to commands in the Ninja file. + ENV = SCons.Action._resolve_shell_env(env, target, source) + scons_specified_env = { + key: value + for key, value in ENV.items() + # TODO: Remove this filter, unless there's a good reason to keep. SCons's behavior shouldn't depend on shell's. + if key not in os.environ or os.environ.get(key, None) != value + } + + windows = env["PLATFORM"] == "win32" + command_env = "" + for key, value in scons_specified_env.items(): + # Ensure that the ENV values are all strings: + if is_List(value): + # If the value is a list, then we assume it is a + # path list, because that's a pretty common list-like + # value to stick in an environment variable: + value = flatten_sequence(value) + value = joinpath(map(str, value)) + else: + # If it isn't a string or a list, then we just coerce + # it to a string, which is the proper way to handle + # Dir and File instances and will produce something + # reasonable for just about everything else: + value = str(value) + + if windows: + command_env += "set '{}={}' && ".format(key, value) + else: + # We address here *only* the specific case that a user might have + # an environment variable which somehow gets included and has + # spaces in the value. These are escapes that Ninja handles. This + # doesn't make builds on paths with spaces (Ninja and SCons issues) + # nor expanding response file paths with spaces (Ninja issue) work. + value = value.replace(r' ', r'$ ') + command_env += "export {}='{}';".format(key, value) + + env["NINJA_ENV_VAR_CACHE"] = command_env + return command_env + + +def get_comstr(env, action, targets, sources): + """Get the un-substituted string for action.""" + # Despite being having "list" in it's name this member is not + # actually a list. It's the pre-subst'd string of the command. We + # use it to determine if the command we're about to generate needs + # to use a custom Ninja rule. By default this redirects CC, CXX, + # AR, SHLINK, and LINK commands to their respective rules but the + # user can inject custom Ninja rules and tie them to commands by + # using their pre-subst'd string. + if hasattr(action, "process"): + return action.cmd_list + + return action.genstring(targets, sources, env) + + +def generate_command(env, node, action, targets, sources, executor=None): + # Actions like CommandAction have a method called process that is + # used by SCons to generate the cmd_line they need to run. So + # check if it's a thing like CommandAction and call it if we can. + if hasattr(action, "process"): + cmd_list, _, _ = action.process(targets, sources, env, executor=executor) + cmd = _string_from_cmd_list(cmd_list[0]) + else: + # Anything else works with genstring, this is most commonly hit by + # ListActions which essentially call process on all of their + # commands and concatenate it for us. + genstring = action.genstring(targets, sources, env) + if executor is not None: + cmd = env.subst(genstring, executor=executor) + else: + cmd = env.subst(genstring, targets, sources) + + cmd = cmd.replace("\n", " && ").strip() + if cmd.endswith("&&"): + cmd = cmd[0:-2].strip() + + # Escape dollars as necessary + return cmd.replace("$", "$$") + + +def ninja_csig(original): + """Return a dummy csig""" + + def wrapper(self): + if isinstance(self, SCons.Node.Node) and self.is_sconscript(): + return original(self) + return "dummy_ninja_csig" + + return wrapper + + +def ninja_contents(original): + """Return a dummy content without doing IO""" + + def wrapper(self): + if isinstance(self, SCons.Node.Node) and (self.is_sconscript() or self.is_conftest()): + return original(self) + return bytes("dummy_ninja_contents", encoding="utf-8") + + return wrapper + + +def ninja_stat(_self, path): + """ + Eternally memoized stat call. + + SCons is very aggressive about clearing out cached values. For our + purposes everything should only ever call stat once since we're + running in a no_exec build the file system state should not + change. For these reasons we patch SCons.Node.FS.LocalFS.stat to + use our eternal memoized dictionary. + """ + + try: + return SCons.Tool.ninja.Globals.NINJA_STAT_MEMO[path] + except KeyError: + try: + result = os.stat(path) + except os.error: + result = None + + SCons.Tool.ninja.Globals.NINJA_STAT_MEMO[path] = result + return result + + +def ninja_whereis(thing, *_args, **_kwargs): + """Replace env.WhereIs with a much faster version""" + + # Optimize for success, this gets called significantly more often + # when the value is already memoized than when it's not. + try: + return SCons.Tool.ninja.Globals.NINJA_WHEREIS_MEMO[thing] + except KeyError: + # TODO: Fix this to respect env['ENV']['PATH']... WPD + # We do not honor any env['ENV'] or env[*] variables in the + # generated ninja file. Ninja passes your raw shell environment + # down to it's subprocess so the only sane option is to do the + # same during generation. At some point, if and when we try to + # upstream this, I'm sure a sticking point will be respecting + # env['ENV'] variables and such but it's actually quite + # complicated. I have a naive version but making it always work + # with shell quoting is nigh impossible. So I've decided to + # cross that bridge when it's absolutely required. + path = shutil.which(thing) + SCons.Tool.ninja.Globals.NINJA_WHEREIS_MEMO[thing] = path + return path + + +def ninja_print_conf_log(s, target, source, env): + """Command line print only for conftest to generate a correct conf log.""" + if target and target[0].is_conftest(): + action = SCons.Action._ActionAction() + action.print_cmd_line(s, target, source, env) diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging/__init__.py scons-4.4.0+dfsg/SCons/Tool/packaging/__init__.py --- scons-4.0.1+dfsg/SCons/Tool/packaging/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,12 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""SCons.Tool.Packaging - -SCons Packaging Tool. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""SCons Packaging Tool.""" import importlib from inspect import getfullargspec @@ -35,8 +31,8 @@ from SCons.Errors import UserError, SConsEnvironmentError from SCons.Script import AddOption, GetOption from SCons.Util import is_List, make_path_relative -from SCons.Variables import * -from SCons.Warnings import warn, Warning +from SCons.Variables import EnumVariable +from SCons.Warnings import warn, SConsWarning __all__ = [ @@ -221,10 +217,11 @@ env['BUILDERS']['Package'] = Package env['BUILDERS']['Tag'] = Tag + def exists(env): return 1 -# XXX + def options(opts): opts.AddVariables( EnumVariable('PACKAGETYPE', @@ -306,8 +303,11 @@ and file.builder.name in ["InstallBuilder", "InstallAsBuilder"]) if len([src for src in source if has_no_install_location(src)]): - warn(Warning, "there are files to package which have no\ - InstallBuilder attached, this might lead to irreproducible packages") + warn( + SConsWarning, + "there are files to package which have no InstallBuilder " + "attached, this might lead to irreproducible packages" + ) n_source = [] for s in source: diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging/__init__.xml scons-4.4.0+dfsg/SCons/Tool/packaging/__init__.xml --- scons-4.0.1+dfsg/SCons/Tool/packaging/__init__.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging/__init__.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,894 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for the &b-Package; Builder. - - - - - - - - - - - -Builds software distribution packages. -Packages consist of files to install and packaging information. -The former may be specified with the &source; parameter and may be left out, -in which case the &FindInstalledFiles; function will collect -all files that have an &b-Install; or &b-InstallAs; Builder attached. -If the ⌖ is not specified -it will be deduced from additional information given to this Builder. - - - -The packaging information is specified -with the help of construction variables documented below. -This information is called a tag to stress that -some of them can also be attached to files with the &Tag; function. -The mandatory ones will complain if they were not specified. -They vary depending on chosen target packager. - - - -The target packager may be selected with the "PACKAGETYPE" command line -option or with the &cv-PACKAGETYPE; construction variable. Currently -the following packagers available: - - -
- -msi - Microsoft Installer -rpm - RPM Package Manger -ipkg - Itsy Package Management System -tarbz2 - bzip2 compressed tar -targz - gzip compressed tar -tarxz - xz compressed tar -zip - zip file -src_tarbz2 - bzip2 compressed tar source -src_targz - gzip compressed tar source -src_tarxz - xz compressed tar source -src_zip - zip file source - -
- - -An updated list is always available under the -package_type option when -running scons --help -on a project that has packaging activated. - - - -env = Environment(tools=["default", "packaging"]) -env.Install("/bin/", "my_program") -env.Package( - NAME="foo", - VERSION="1.2.3", - PACKAGEVERSION=0, - PACKAGETYPE="rpm", - LICENSE="gpl", - SUMMARY="balalalalal", - DESCRIPTION="this should be really really long", - X_RPM_GROUP="Application/fu", - SOURCE_URL="http://foo.org/foo-1.2.3.tar.gz", -) - -
-
- - - - -Specifies the system architecture for which -the package is being built. -The default is the system architecture -of the machine on which SCons is running. -This is used to fill in the -Architecture: -field in an Ipkg -control file, -and the BuildArch: field -in the RPM .spec file, -as well as forming part of the name of a generated RPM package file. - - - - - - - -A hook for modifying the file that controls the packaging build -(the .spec for RPM, -the control for Ipkg, -the .wxs for MSI). -If set, the function will be called -after the SCons template for the file has been written. - - - - - - - -The name of a file containing the change log text -to be included in the package. -This is included as the -%changelog -section of the RPM -.spec file. - - - - - - - -A long description of the project being packaged. -This is included in the relevant section -of the file that controls the packaging build. - - - - - - - -A language-specific long description for -the specified lang. -This is used to populate a -%description -l -section of an RPM -.spec file. - - - - - - - -The abbreviated name, preferably the SPDX code, of the license under which -this project is released (GPL-3.0, LGPL-2.1, BSD-2-Clause etc.). -See http://www.opensource.org/licenses/alphabetical -for a list of license names and SPDX codes. - - - - - - - -Specfies the name of the project to package. - - - - - - - -Specifies the directory where all files in resulting archive will be -placed if applicable. The default value is "$NAME-$VERSION". - - - - - - - -Selects the package type to build. Currently these are available: - - -
- -msi - Microsoft Installer -rpm - RPM Package Manger -ipkg - Itsy Package Management System -tarbz2 - bzip2 compressed tar -targz - gzip compressed tar -tarxz - xz compressed tar -zip - zip file -src_tarbz2 - bzip2 compressed tar source -src_targz - gzip compressed tar source -src_tarxz - xz compressed tar source -src_zip - zip file source - -
- - -This may be overridden with the -command line option. - -
-
- - - - -The version of the package (not the underlying project). -This is currently only used by the rpm packager -and should reflect changes in the packaging, -not the underlying project code itself. - - - - - - - -The URL -(web address) -of the location from which the project was retrieved. -This is used to fill in the -Source: -field in the controlling information for Ipkg and RPM packages. - - - - - - - -A short summary of what the project is about. -This is used to fill in the -Summary: -field in the controlling information for Ipkg and RPM packages, -and as the -Description: -field in MSI packages. - - - - - - - -The person or organization who supply the packaged software. -This is used to fill in the -Vendor: -field in the controlling information for RPM packages, -and the -Manufacturer: -field in the controlling information for MSI packages. - - - - - - - -The version of the project, specified as a string. - - - - - - - - -This is used to fill in the -Depends: -field in the controlling information for Ipkg packages. - - - - - - - -This is used to fill in the -Description: -field in the controlling information for Ipkg packages. -The default value is -$SUMMARY\n$DESCRIPTION - - - - - - - -This is used to fill in the -Maintainer: -field in the controlling information for Ipkg packages. - - - - - - - -This is used to fill in the -Priority: -field in the controlling information for Ipkg packages. - - - - - - - -This is used to fill in the -Section: -field in the controlling information for Ipkg packages. - - - - - - - - - -This is used to fill in the -Language: -attribute in the controlling information for MSI packages. - - - - - - - -The text of the software license in RTF format. -Carriage return characters will be -replaced with the RTF equivalent \\par. - - - - - - - -TODO - - - - - - - - -This is used to fill in the -AutoReqProv: -field in the RPM -.spec file. - - - - - - - -internal, but overridable - - - - - - - -This is used to fill in the -BuildRequires: -field in the RPM -.spec file. -Note this should only be used on a host managed by rpm as the dependencies will not be resolvable at build time otherwise. - - - - - - - -internal, but overridable - - - - - - - -internal, but overridable - - - - - - - -This is used to fill in the -Conflicts: -field in the RPM -.spec file. - - - - - - - -This value is used as the default attributes -for the files in the RPM package. -The default value is -(-,root,root). - - - - - - - -This is used to fill in the -Distribution: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -Epoch: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -ExcludeArch: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -ExclusiveArch: -field in the RPM -.spec file. - - - - - - - -A list used to supply extra defintions or flags -to be added to the RPM .spec file. -Each item is added as-is with a carriage return appended. -This is useful if some specific RPM feature not otherwise -anticipated by SCons needs to be turned on or off. -Note if this variable is omitted, SCons will by -default supply the value -'%global debug_package %{nil}' -to disable debug package generation. -To enable debug package generation, include this -variable set either to None, or to a custom -list that does not include the default line. -Added in version 3.1. - - - -env.Package( - NAME="foo", - ... - X_RPM_EXTRADEFS=[ - "%define _unpackaged_files_terminate_build 0" - "%define _missing_doc_files_terminate_build 0" - ], - ... -) - - - - - - - - -This is used to fill in the -Group: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -Group(lang): -field in the RPM -.spec file. -Note that -lang -is not literal -and should be replaced by -the appropriate language code. - - - - - - - -This is used to fill in the -Icon: -field in the RPM -.spec file. - - - - - - - -internal, but overridable - - - - - - - -This is used to fill in the -Packager: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -Provides: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -%post: -section in the RPM -.spec file. - - - - - - - -This is used to fill in the -%pre: -section in the RPM -.spec file. - - - - - - - -This is used to fill in the -Prefix: -field in the RPM -.spec file. - - - - - - - -internal, but overridable - - - - - - - -This is used to fill in the -%postun: -section in the RPM -.spec file. - - - - - - - -This is used to fill in the -%preun: -section in the RPM -.spec file. - - - - - - - -This is used to fill in the -Requires: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -Serial: -field in the RPM -.spec file. - - - - - - - -This is used to fill in the -Url: -field in the RPM -.spec file. - - - - - - - - - - -(node, tags) - - - -Annotates file or directory Nodes with -information about how the -&b-link-Package; -Builder should package those files or directories. -All tags are optional. - - - -Examples: - - - -# makes sure the built library will be installed with 0o644 file -# access mode -Tag( Library( 'lib.c' ), UNIX_ATTR="0o644" ) - -# marks file2.txt to be a documentation file -Tag( 'file2.txt', DOC ) - - - - - - - -
diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging/msi.py scons-4.4.0+dfsg/SCons/Tool/packaging/msi.py --- scons-4.0.1+dfsg/SCons/Tool/packaging/msi.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging/msi.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,7 +32,7 @@ from SCons.Action import Action from SCons.Builder import Builder -from xml.dom.minidom import * +from xml.dom.minidom import Document from xml.sax.saxutils import escape from SCons.Tool.packaging import stripinstallbuilder diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging/packaging.xml scons-4.4.0+dfsg/SCons/Tool/packaging/packaging.xml --- scons-4.0.1+dfsg/SCons/Tool/packaging/packaging.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging/packaging.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,946 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +Sets construction variables for the &b-link-Package; Builder. +If this tool is enabled, the +command-line option is also enabled. + + + + + + + + + + + +Builds software distribution packages. +A package is a container format which +includes files to install along with metadata. +Packaging is optional, and must be enabled by specifying +the &t-link-packaging; tool. For example: + + + +env = Environment(tools=['default', 'packaging']) + + + +&SCons; can build packages in a number of well known packaging formats. +The target package type may be selected with the +the &cv-link-PACKAGETYPE; construction variable +or the command line option. +The package type may be a list, in which case &SCons; will attempt +to build packages for each type in the list. Example: + + + +env.Package(PACKAGETYPE=['src_zip', 'src_targz'], ...other args...) + + + +The currently supported packagers are: + + + + + +msiMicrosoft Installer package +rpmRPM Package Manger package +ipkgItsy Package Management package +tarbz2bzip2-compressed tar file +targzgzip-compressed tar file +tarxzxz-compressed tar file +zipzip file +src_tarbz2bzip2-compressed tar file suitable as source to another packager +src_targzgzip-compressed tar file suitable as source to another packager +src_tarxzxz-compressed tar file suitable as source to another packager +src_zipzip file suitable as source to another packager + + + + + +The file list to include in the package may be specified with +the &source; keyword argument. If omitted, +the &f-link-FindInstalledFiles; function is called behind the scenes +to select all files that have an &b-link-Install;, &b-link-InstallAs; +or &b-link-InstallVersionedLib; Builder attached. +If the ⌖ keyword argument is omitted, the target name(s) +will be deduced from the package type(s). + + + +The metadata comes partly from attributes of the files to be packaged, +and partly from packaging tags. +Tags can be passed as keyword arguments +to the &b-Package; builder call, +and may also be attached to files +(or more accurately, Nodes representing files) +with the &f-link-Tag; function. +Some package-level tags are mandatory, and will lead to errors if omitted. +The mandatory tags vary depending on the package type. + + + + +While packaging, the builder uses a temporary location named +by the value of the &cv-link-PACKAGEROOT; variable - +the package sources are copied there before packaging. + + + +Packaging example: + + + +env = Environment(tools=["default", "packaging"]) +env.Install("/bin/", "my_program") +env.Package( + NAME="foo", + VERSION="1.2.3", + PACKAGEVERSION=0, + PACKAGETYPE="rpm", + LICENSE="gpl", + SUMMARY="balalalalal", + DESCRIPTION="this should be really really long", + X_RPM_GROUP="Application/fu", + SOURCE_URL="https://foo.org/foo-1.2.3.tar.gz", +) + + + +In this example, the target /bin/my_program +created by the &b-Install; call would not be built by default +since it is not under the project top directory. +However, since no source +is specified to the &b-Package; builder, +it is selected for packaging by the default sources rule. +Since packaging is done using &cv-link-PACKAGEROOT;, no write is +actually done to the system's /bin directory, +and the target will be selected since +after rebasing to underneath &cv-PACKAGEROOT; it is now under +the top directory of the project. + + + + + + + + +Specifies the system architecture for which +the package is being built. +The default is the system architecture +of the machine on which SCons is running. +This is used to fill in the +Architecture: +field in an Ipkg +control file, +and the BuildArch: field +in the RPM .spec file, +as well as forming part of the name of a generated RPM package file. + +See the &b-link-Package; builder. + + + + + + +A hook for modifying the file that controls the packaging build +(the .spec for RPM, +the control for Ipkg, +the .wxs for MSI). +If set, the function will be called +after the SCons template for the file has been written. + +See the &b-link-Package; builder. + + + + + + +The name of a file containing the change log text +to be included in the package. +This is included as the +%changelog +section of the RPM +.spec file. + +See the &b-link-Package; builder. + + + + + + +A long description of the project being packaged. +This is included in the relevant section +of the file that controls the packaging build. + +See the &b-link-Package; builder. + + + + + + +A language-specific long description for +the specified lang. +This is used to populate a +%description -l +section of an RPM +.spec file. + +See the &b-link-Package; builder. + + + + + + +The abbreviated name, preferably the SPDX code, of the license under which +this project is released (GPL-3.0, LGPL-2.1, BSD-2-Clause etc.). +See + +http://www.opensource.org/licenses/alphabetical +for a list of license names and SPDX codes. + +See the &b-link-Package; builder. + + + + + + +Specfies the name of the project to package. + +See the &b-link-Package; builder. + + + + + + +Specifies the directory where all files in resulting archive will be +placed if applicable. The default value is &cv-NAME;-&cv-VERSION;. + +See the &b-link-Package; builder. + + + + + + +Selects the package type to build when using the &b-link-Package; +builder. May be a string or list of strings. See the docuentation +for the builder for the currently supported types. + + + +&cv-PACKAGETYPE; may be overridden with the +command line option. + +See the &b-link-Package; builder. + + + + + + +The version of the package (not the underlying project). +This is currently only used by the rpm packager +and should reflect changes in the packaging, +not the underlying project code itself. + +See the &b-link-Package; builder. + + + + + + +The URL +(web address) +of the location from which the project was retrieved. +This is used to fill in the +Source: +field in the controlling information for Ipkg and RPM packages. + +See the &b-link-Package; builder. + + + + + + +A short summary of what the project is about. +This is used to fill in the +Summary: +field in the controlling information for Ipkg and RPM packages, +and as the +Description: +field in MSI packages. + +See the &b-link-Package; builder. + + + + + + +The person or organization who supply the packaged software. +This is used to fill in the +Vendor: +field in the controlling information for RPM packages, +and the +Manufacturer: +field in the controlling information for MSI packages. + +See the &b-link-Package; builder. + + + + + + +The version of the project, specified as a string. + +See the &b-link-Package; builder. + + + + + + + +This is used to fill in the +Depends: +field in the controlling information for Ipkg packages. + +See the &b-link-Package; builder. + + + + + + +This is used to fill in the +Description: +field in the controlling information for Ipkg packages. +The default value is +&cv-SUMMARY;\n&cv-DESCRIPTION; + + + + + + + +This is used to fill in the +Maintainer: +field in the controlling information for Ipkg packages. + + + + + + + +This is used to fill in the +Priority: +field in the controlling information for Ipkg packages. + + + + + + + +This is used to fill in the +Section: +field in the controlling information for Ipkg packages. + + + + + + + +This is used to fill in the +Language: +attribute in the controlling information for MSI packages. + +See the &b-link-Package; builder. + + + + + + +The text of the software license in RTF format. +Carriage return characters will be +replaced with the RTF equivalent \\par. + +See the &b-link-Package; builder. + + + + + + +TODO + + + + + + + + +This is used to fill in the +AutoReqProv: +field in the RPM +.spec file. + +See the &b-link-Package; builder. + + + + + + +internal, but overridable + + + + + + + +This is used to fill in the +BuildRequires: +field in the RPM +.spec file. +Note this should only be used on a host managed by rpm as the dependencies will not be resolvable at build time otherwise. + + + + + + + +internal, but overridable + + + + + + + +internal, but overridable + + + + + + + +This is used to fill in the +Conflicts: +field in the RPM +.spec file. + + + + + + + +This value is used as the default attributes +for the files in the RPM package. +The default value is +(-,root,root). + + + + + + + +This is used to fill in the +Distribution: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +Epoch: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +ExcludeArch: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +ExclusiveArch: +field in the RPM +.spec file. + + + + + + + +A list used to supply extra defintions or flags +to be added to the RPM .spec file. +Each item is added as-is with a carriage return appended. +This is useful if some specific RPM feature not otherwise +anticipated by SCons needs to be turned on or off. +Note if this variable is omitted, SCons will by +default supply the value +'%global debug_package %{nil}' +to disable debug package generation. +To enable debug package generation, include this +variable set either to None, or to a custom +list that does not include the default line. +Added in version 3.1. + + + +env.Package( + NAME="foo", + ... + X_RPM_EXTRADEFS=[ + "%define _unpackaged_files_terminate_build 0" + "%define _missing_doc_files_terminate_build 0" + ], + ... +) + + + + + + + + +This is used to fill in the +Group: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +Group(lang): +field in the RPM +.spec file. +Note that +lang +is not literal +and should be replaced by +the appropriate language code. + + + + + + + +This is used to fill in the +Icon: +field in the RPM +.spec file. + + + + + + + +internal, but overridable + + + + + + + +This is used to fill in the +Packager: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +Provides: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +%post: +section in the RPM +.spec file. + + + + + + + +This is used to fill in the +%pre: +section in the RPM +.spec file. + + + + + + + +This is used to fill in the +Prefix: +field in the RPM +.spec file. + + + + + + + +internal, but overridable + + + + + + + +This is used to fill in the +%postun: +section in the RPM +.spec file. + + + + + + + +This is used to fill in the +%preun: +section in the RPM +.spec file. + + + + + + + +This is used to fill in the +Requires: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +Serial: +field in the RPM +.spec file. + + + + + + + +This is used to fill in the +Url: +field in the RPM +.spec file. + + + + + + + + + + +(node, tags) + + + +Annotates file or directory Nodes with +information about how the +&b-link-Package; +Builder should package those files or directories. +All Node-level tags are optional. + + + +Examples: + + + +# makes sure the built library will be installed with 644 file access mode +Tag(Library('lib.c'), UNIX_ATTR="0o644") + +# marks file2.txt to be a documentation file +Tag('file2.txt', DOC) + + + + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging/rpm.py scons-4.4.0+dfsg/SCons/Tool/packaging/rpm.py --- scons-4.0.1+dfsg/SCons/Tool/packaging/rpm.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging/rpm.py 2022-07-30 21:48:28.000000000 +0000 @@ -27,7 +27,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import SCons.Builder import SCons.Tool.rpmutils diff -Nru scons-4.0.1+dfsg/SCons/Tool/packaging.xml scons-4.4.0+dfsg/SCons/Tool/packaging.xml --- scons-4.0.1+dfsg/SCons/Tool/packaging.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/packaging.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -A framework for building binary and source packages. - - - - - - - -Builds a Binary Package of the given source files. - - - -env.Package(source = FindInstalledFiles()) - - - - - diff -Nru scons-4.0.1+dfsg/SCons/Tool/qt.py scons-4.4.0+dfsg/SCons/Tool/qt.py --- scons-4.0.1+dfsg/SCons/Tool/qt.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/qt.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,16 +1,6 @@ - -"""SCons.Tool.qt - -Tool-specific initialization for Qt. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,12 +20,16 @@ # 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__" + +"""Tool-specific initialization for Qt. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path import re -import glob import SCons.Action import SCons.Builder @@ -44,9 +38,10 @@ import SCons.Tool import SCons.Util import SCons.Tool.cxx +import SCons.Warnings cplusplus = SCons.Tool.cxx -class ToolQtWarning(SCons.Warnings.Warning): +class ToolQtWarning(SCons.Warnings.SConsWarning): pass class GeneratedMocFileNotIncluded(ToolQtWarning): @@ -264,7 +259,7 @@ result.append(dep) return result -uicScanner = SCons.Scanner.Base(uicScannerFunc, +uicScanner = SCons.Scanner.ScannerBase(uicScannerFunc, name = "UicScanner", node_class = SCons.Node.FS.File, node_factory = SCons.Node.FS.File, @@ -276,6 +271,10 @@ Action = SCons.Action.Action Builder = SCons.Builder.Builder + SCons.Warnings.warn( + SCons.Warnings.ToolQtDeprecatedWarning, "Tool module for Qt version 3 is deprecated" + ) + env.SetDefault(QTDIR = _detect(env), QT_BINPATH = os.path.join('$QTDIR', 'bin'), QT_CPPPATH = os.path.join('$QTDIR', 'include'), diff -Nru scons-4.0.1+dfsg/SCons/Tool/qt.xml scons-4.4.0+dfsg/SCons/Tool/qt.xml --- scons-4.0.1+dfsg/SCons/Tool/qt.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/qt.xml 2022-07-30 21:48:28.000000000 +0000 @@ -26,7 +26,90 @@ -Sets construction variables for building Qt applications. +Sets &consvars; for building Qt3 applications. + + + +This tool is only suitable for building targeted to Qt3, +which is obsolete +(the tool is deprecated since 4.3). +There are contributed tools for Qt4 and Qt5, see + +https://github.com/SCons/scons-contrib. +Qt4 has also passed end of life for standard support (in Dec 2015). + + + +Note paths for these &consvars; are assembled +using the os.path.join method +so they will have the appropriate separator at runtime, +but are listed here in the various +entries only with the '/' separator +for simplicity. + + + +In addition, the &consvars; +&cv-link-CPPPATH;, +&cv-link-LIBPATH; and +&cv-link-LIBS; may be modified +and the variables +&cv-link-PROGEMITTER;, &cv-link-SHLIBEMITTER; and &cv-link-LIBEMITTER; +are modified. Because the build-performance is affected when using this tool, +you have to explicitly specify it at Environment creation: + + + +Environment(tools=['default','qt']) + + + +The &t-qt; tool supports the following operations: + + + +Automatic moc file generation from header files. +You do not have to specify moc files explicitly, the tool does it for you. +However, there are a few preconditions to do so: Your header file must have +the same filebase as your implementation file and must stay in the same +directory. It must have one of the suffixes +.h, +.hpp, +.H, +.hxx, +.hh. +You can turn off automatic moc file generation by setting +&cv-link-QT_AUTOSCAN; to False. +See also the corresponding +&b-link-Moc; Builder. + + + +Automatic moc file generation from C++ files. +As described in the Qt documentation, include the moc file at the end of +the C++ file. Note that you have to include the file, which is generated +by the transformation +${QT_MOCCXXPREFIX}<basename>${QT_MOCCXXSUFFIX}, by default +<basename>.mo. A warning is generated after building the moc file if you +do not include the correct file. If you are using &f-link-VariantDir;, you may +need to specify duplicate=True. +You can turn off automatic moc file generation by setting &cv-QT_AUTOSCAN; to +False. See also the corresponding +&b-link-Moc; Builder. + + + +Automatic handling of .ui files. +The implementation files generated from .ui +files are handled much the same as yacc or lex files. +Each .ui file given as a source of &b-link-Program;, +&b-link-Library; or &b-link-SharedLibrary; +will generate three files: the declaration file, the +implementation file and a moc file. Because there are also generated headers, +you may need to specify duplicate=True in calls to +&f-link-VariantDir;. +See also the corresponding +&b-link-Uic; Builder. @@ -56,21 +139,23 @@ QT_MOCFROMCXXCOM +QTDIR -Builds an output file from a moc input file. Moc input files are either -header files or cxx files. This builder is only available after using the -tool 'qt'. See the &cv-link-QTDIR; variable for more information. +Builds an output file from a moc input file. +moc input files are either header files or C++ files. +This builder is only available after using the +tool &t-link-qt;. See the &cv-link-QTDIR; variable for more information. Example: -env.Moc('foo.h') # generates moc_foo.cc -env.Moc('foo.cpp') # generates foo.moc +env.Moc('foo.h') # generates moc_foo.cc +env.Moc('foo.cpp') # generates foo.moc @@ -79,11 +164,11 @@ Builds a header file, an implementation file and a moc file from an ui file. -and returns the corresponding nodes in the above order. -This builder is only available after using the tool 'qt'. Note: you can -specify .ui files directly as source -files to the &b-Program;, -&b-Library; and &b-SharedLibrary; builders +and returns the corresponding nodes in the that order. +This builder is only available after using the tool &t-link-qt;. +Note: you can specify .ui files directly as source +files to the &b-link-Program;, +&b-link-Library; and &b-link-SharedLibrary; builders without using this builder. Using this builder lets you override the standard naming conventions (be careful: prefixes are always prepended to names of built files; if you don't want prefixes, you may set them to ``). @@ -92,9 +177,11 @@ -env.Uic('foo.ui') # -> ['foo.h', 'uic_foo.cc', 'moc_foo.cc'] -env.Uic(target = Split('include/foo.h gen/uicfoo.cc gen/mocfoo.cc'), - source = 'foo.ui') # -> ['include/foo.h', 'gen/uicfoo.cc', 'gen/mocfoo.cc'] +env.Uic('foo.ui') # -> ['foo.h', 'uic_foo.cc', 'moc_foo.cc'] +env.Uic( + target=Split('include/foo.h gen/uicfoo.cc gen/mocfoo.cc'), + source='foo.ui' +) # -> ['include/foo.h', 'gen/uicfoo.cc', 'gen/mocfoo.cc'] @@ -102,66 +189,11 @@ -The qt tool tries to take this from os.environ. -It also initializes all QT_* -construction variables listed below. -(Note that all paths are constructed -with python's os.path.join() method, -but are listed here with the '/' separator -for easier reading.) -In addition, the construction environment -variables &cv-link-CPPPATH;, -&cv-link-LIBPATH; and -&cv-link-LIBS; may be modified -and the variables -&cv-link-PROGEMITTER;, &cv-link-SHLIBEMITTER; and &cv-link-LIBEMITTER; -are modified. Because the build-performance is affected when using this tool, -you have to explicitly specify it at Environment creation: - - - -Environment(tools=['default','qt']) - - - -The qt tool supports the following operations: - - - -Automatic moc file generation from header files. -You do not have to specify moc files explicitly, the tool does it for you. -However, there are a few preconditions to do so: Your header file must have -the same filebase as your implementation file and must stay in the same -directory. It must have one of the suffixes .h, .hpp, .H, .hxx, .hh. You -can turn off automatic moc file generation by setting QT_AUTOSCAN to 0. -See also the corresponding -&b-Moc;() -builder method. - - - -Automatic moc file generation from cxx files. -As stated in the qt documentation, include the moc file at the end of -the cxx file. Note that you have to include the file, which is generated -by the transformation ${QT_MOCCXXPREFIX}<basename>${QT_MOCCXXSUFFIX}, by default -<basename>.moc. A warning is generated after building the moc file, if you -do not include the correct file. If you are using VariantDir, you may -need to specify duplicate=1. You can turn off automatic moc file generation -by setting QT_AUTOSCAN to 0. See also the corresponding -&b-Moc; -builder method. - - - -Automatic handling of .ui files. -The implementation files generated from .ui files are handled much the same -as yacc or lex files. Each .ui file given as a source of Program, Library or -SharedLibrary will generate three files, the declaration file, the -implementation file and a moc file. Because there are also generated headers, -you may need to specify duplicate=1 in calls to VariantDir. -See also the corresponding -&b-Uic; -builder method. +The path to the Qt installation to build against. +If not already set, +&t-link-qt; tool tries to obtain this from +os.environ; +if not found there, it tries to make a guess. @@ -169,8 +201,8 @@ -Turn off scanning for mocable files. Use the Moc Builder to explicitly -specify files to run moc on. +Turn off scanning for mocable files. Use the &b-link-Moc; Builder to explicitly +specify files to run moc on. @@ -178,8 +210,8 @@ -The path where the qt binaries are installed. -The default value is '&cv-link-QTDIR;/bin'. +The path where the Qt binaries are installed. +The default value is '&cv-link-QTDIR;/bin'. @@ -187,9 +219,9 @@ -The path where the qt header files are installed. +The path where the Qt header files are installed. The default value is '&cv-link-QTDIR;/include'. -Note: If you set this variable to None, +Note: If you set this variable to None, the tool won't change the &cv-link-CPPPATH; construction variable. @@ -207,8 +239,10 @@ -Default value is 'qt'. You may want to set this to 'qt-mt'. Note: If you set -this variable to None, the tool won't change the &cv-link-LIBS; variable. +Default value is 'qt'. +You may want to set this to 'qt-mt'. +Note: If you set this variable to None, +the tool won't change the &cv-link-LIBS; variable. @@ -216,9 +250,9 @@ -The path where the qt libraries are installed. -The default value is '&cv-link-QTDIR;/lib'. -Note: If you set this variable to None, +The path where the Qt libraries are installed. +The default value is '&cv-link-QTDIR;/lib'. +Note: If you set this variable to None, the tool won't change the &cv-link-LIBPATH; construction variable. @@ -228,7 +262,7 @@ -Default value is '&cv-link-QT_BINPATH;/moc'. +Default value is '&cv-link-QT_BINPATH;/moc'. @@ -236,7 +270,8 @@ -Default value is ''. Prefix for moc output files, when source is a cxx file. +Default value is ''. +Prefix for moc output files when source is a C++ file. @@ -244,8 +279,8 @@ -Default value is '.moc'. Suffix for moc output files, when source is a cxx -file. +Default value is '.moc'. +Suffix for moc output files when source is a C++ file. @@ -253,8 +288,8 @@ -Default value is '-i'. These flags are passed to moc, when moccing a -C++ file. +Default value is '-i'. +These flags are passed to moc when moccing a C++ file. @@ -262,7 +297,7 @@ -Command to generate a moc file from a cpp file. +Command to generate a moc file from a C++ file. @@ -270,7 +305,7 @@ -The string displayed when generating a moc file from a cpp file. +The string displayed when generating a moc file from a C++ file. If this is not set, then &cv-link-QT_MOCFROMCXXCOM; (the command line) is displayed. @@ -287,7 +322,7 @@ -The string displayed when generating a moc file from a cpp file. +The string displayed when generating a moc file from a C++ file. If this is not set, then &cv-link-QT_MOCFROMHCOM; (the command line) is displayed. @@ -296,8 +331,8 @@ -Default value is ''. These flags are passed to moc, when moccing a header -file. +Default value is ''. These flags are passed to moc +when moccing a header file. @@ -305,7 +340,8 @@ -Default value is 'moc_'. Prefix for moc output files, when source is a header. +Default value is 'moc_'. +Prefix for moc output files when source is a header. @@ -313,8 +349,8 @@ -Default value is '&cv-link-CXXFILESUFFIX;'. Suffix for moc output files, when source is -a header. +Default value is '&cv-link-CXXFILESUFFIX;'. +Suffix for moc output files when source is a header. @@ -322,7 +358,7 @@ -Default value is '&cv-link-QT_BINPATH;/uic'. +Default value is '&cv-link-QT_BINPATH;/uic'. @@ -330,7 +366,7 @@ -Command to generate header files from .ui files. +Command to generate header files from .ui files. @@ -338,7 +374,7 @@ -The string displayed when generating header files from .ui files. +The string displayed when generating header files from .ui files. If this is not set, then &cv-link-QT_UICCOM; (the command line) is displayed. @@ -347,8 +383,8 @@ -Default value is ''. These flags are passed to uic, when creating a a h -file from a .ui file. +Default value is ''. These flags are passed to uic +when creating a header file from a .ui file. @@ -356,7 +392,8 @@ -Default value is ''. Prefix for uic generated header files. +Default value is ''. +Prefix for uic generated header files. @@ -364,7 +401,8 @@ -Default value is '.h'. Suffix for uic generated header files. +Default value is '.h'. +Suffix for uic generated header files. @@ -372,8 +410,9 @@ -Default value is ''. These flags are passed to uic, when creating a cxx -file from a .ui file. +Default value is ''. +These flags are passed to uic when creating a C++ +file from a .ui file. @@ -381,7 +420,8 @@ -Default value is 'uic_'. Prefix for uic generated implementation files. +Default value is 'uic_'. +Prefix for uic generated implementation files. @@ -398,7 +438,8 @@ -Default value is '.ui'. Suffix of designer input files. +Default value is '.ui'. +Suffix of designer input files. diff -Nru scons-4.0.1+dfsg/SCons/Tool/sgilink.py scons-4.4.0+dfsg/SCons/Tool/sgilink.py --- scons-4.0.1+dfsg/SCons/Tool/sgilink.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/sgilink.py 2022-07-30 21:48:28.000000000 +0000 @@ -9,8 +9,6 @@ """ # -# __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 @@ -31,7 +29,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util diff -Nru scons-4.0.1+dfsg/SCons/Tool/sunlink.py scons-4.4.0+dfsg/SCons/Tool/sunlink.py --- scons-4.0.1+dfsg/SCons/Tool/sunlink.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/sunlink.py 2022-07-30 21:48:28.000000000 +0000 @@ -8,7 +8,9 @@ """ # -# __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 @@ -30,13 +32,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os import os.path import SCons.Util - from . import link ccLinker = None @@ -56,19 +54,20 @@ ccLinker = linker break + def generate(env): """Add Builders and construction variables for Forte to an Environment.""" link.generate(env) - + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') env['RPATHPREFIX'] = '-R' env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' - # Support for versioned libraries - link._setup_versioned_lib_variables(env, tool = 'sunlink', use_soname = True) - env['LINKCALLBACKS'] = link._versioned_lib_callbacks() + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLIBSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' + def exists(env): return ccLinker diff -Nru scons-4.0.1+dfsg/SCons/Tool/swig.py scons-4.4.0+dfsg/SCons/Tool/swig.py --- scons-4.0.1+dfsg/SCons/Tool/swig.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/swig.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,14 +1,6 @@ -"""SCons.Tool.swig - -Tool-specific initialization for swig. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" +# MIT License # -# __COPYRIGHT__ +# 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,20 +20,25 @@ # 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__" +"""Tool-specific initialization for swig. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path -import sys import re import subprocess +import sys import SCons.Action import SCons.Defaults +import SCons.Node import SCons.Tool import SCons.Util -import SCons.Node +import SCons.Warnings verbose = False @@ -190,21 +187,26 @@ swig_bin_dir = os.path.dirname(swig) env.AppendENVPath('PATH', swig_bin_dir) else: - SCons.Warnings.Warning('swig tool requested, but binary not found in ENV PATH') + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + 'swig tool requested, but binary not found in ENV PATH' + ) if 'SWIG' not in env: env['SWIG'] = env.Detect(swigs) or swigs[0] - env['SWIGVERSION'] = _get_swig_version(env, env['SWIG']) - env['SWIGFLAGS'] = SCons.Util.CLVar('') + + env['SWIGVERSION'] = _get_swig_version(env, env['SWIG']) + env['SWIGFLAGS'] = SCons.Util.CLVar('') env['SWIGDIRECTORSUFFIX'] = '_wrap.h' - env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' + env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX' - env['_SWIGOUTDIR'] = r'${"-outdir \"%s\"" % SWIGOUTDIR}' - env['SWIGPATH'] = [] - env['SWIGINCPREFIX'] = '-I' - env['SWIGINCSUFFIX'] = '' - env['_SWIGINCFLAGS'] = '$( ${_concat(SWIGINCPREFIX, SWIGPATH, SWIGINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' - env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} ${_SWIGINCFLAGS} $SWIGFLAGS $SOURCES' + env['_SWIGOUTDIR'] = r'${"-outdir \"%s\"" % SWIGOUTDIR}' + env['SWIGPATH'] = [] + env['SWIGINCPREFIX'] = '-I' + env['SWIGINCSUFFIX'] = '' + env['_SWIGINCFLAGS'] = '${_concat(SWIGINCPREFIX, SWIGPATH, SWIGINCSUFFIX,' \ + '__env__, RDirs, TARGET, SOURCE, affect_signature=False)}' + env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} ${_SWIGINCFLAGS} $SWIGFLAGS $SOURCES' def exists(env): swig = env.get('SWIG') or env.Detect(['swig']) diff -Nru scons-4.0.1+dfsg/SCons/Tool/swig.xml scons-4.4.0+dfsg/SCons/Tool/swig.xml --- scons-4.0.1+dfsg/SCons/Tool/swig.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/swig.xml 2022-07-30 21:48:28.000000000 +0000 @@ -26,7 +26,7 @@ -Sets construction variables for the SWIG interface generator. +Sets construction variables for the &swig; interface compiler. @@ -50,7 +50,7 @@ -The scripting language wrapper and interface generator. +The name of the &swig; compiler to use. @@ -59,10 +59,11 @@ The suffix that will be used for intermediate C -source files generated by -the scripting language wrapper and interface generator. -The default value is -_wrap&cv-link-CFILESUFFIX;. +source files generated by &swig;. +The default value is '_wrap$CFILESUFFIX' - +that is, the concatenation of the string +_wrap +and the current C suffix &cv-link-CFILESUFFIX;. By default, this value is used whenever the option is @@ -78,8 +79,8 @@ The suffix that will be used for intermediate C++ header -files generated by the scripting language wrapper and interface generator. -These are only generated for C++ code when the SWIG 'directors' feature is +files generated by &swig;. +These are only generated for C++ code when the &swig; 'directors' feature is turned on. The default value is _wrap.h. @@ -90,8 +91,7 @@ -The command line used to call -the scripting language wrapper and interface generator. +The command line used to call &swig;. @@ -99,8 +99,7 @@ -The string displayed when calling -the scripting language wrapper and interface generator. +The string displayed when calling &swig;. If this is not set, then &cv-link-SWIGCOM; (the command line) is displayed. @@ -110,12 +109,13 @@ The suffix that will be used for intermediate C++ -source files generated by -the scripting language wrapper and interface generator. -The default value is -_wrap&cv-link-CFILESUFFIX;. +source files generated by &swig;. +The default value is '_wrap$CXXFILESUFFIX' - +that is, the concatenation of the string +_wrap +and the current C++ suffix &cv-link-CXXFILESUFFIX;. By default, this value is used whenever the --c++ + option is specified as part of the &cv-link-SWIGFLAGS; construction variable. @@ -126,22 +126,14 @@ -General options passed to -the scripting language wrapper and interface generator. -This is where you should set -, +General options passed to &swig;. +This is where you should set the target language +(, , -, -or whatever other options you want to specify to SWIG. -If you set the - -option in this variable, -&scons; -will, by default, -generate a C++ intermediate source file -with the extension that is specified as the -&cv-link-CXXFILESUFFIX; -variable. +, etc.) +and whatever other options you want to specify to &swig;, +such as the to generate C++ code +instead of C Code. @@ -150,7 +142,7 @@ An automatically-generated construction variable -containing the SWIG command-line options +containing the &swig; command-line options for specifying directories to be searched for included files. The value of &cv-_SWIGINCFLAGS; is created by respectively prepending and appending @@ -164,7 +156,7 @@ -The prefix used to specify an include directory on the SWIG command line. +The prefix used to specify an include directory on the &swig; command line. This will be prepended to the beginning of each directory in the &cv-SWIGPATH; construction variable when the &cv-_SWIGINCFLAGS; variable is automatically generated. @@ -175,7 +167,7 @@ -The suffix used to specify an include directory on the SWIG command line. +The suffix used to specify an include directory on the &swig; command line. This will be appended to the end of each directory in the &cv-SWIGPATH; construction variable when the &cv-_SWIGINCFLAGS; variable is automatically generated. @@ -186,8 +178,7 @@ -Specifies the output directory in which -the scripting language wrapper and interface generator +Specifies the output directory in which &swig; should place generated language-specific files. This will be used by SCons to identify the files that will be generated by the &swig; call, @@ -200,22 +191,24 @@ -The list of directories that the scripting language wrapper -and interface generate will search for included files. -The SWIG implicit dependency scanner will search these +The list of directories that &swig; +will search for included files. +&SCons;' SWIG implicit dependency scanner will search these directories for include files. The default value is an empty list. Don't explicitly put include directory -arguments in SWIGFLAGS; +arguments in &cv-link-SWIGFLAGS; the result will be non-portable and the directories will not be searched by the dependency scanner. -Note: directory names in SWIGPATH will be looked-up relative to the SConscript +Note: directory names in &cv-link-SWIGPATH; +will be looked-up relative to the SConscript directory when they are used in a command. To force &scons; -to look-up a directory relative to the root of the source tree use #: +to look-up a directory relative to the root of the source tree use +a top-relative path (#): @@ -258,7 +251,7 @@ -The version number of the SWIG tool. +The detected version string of the &swig; tool. diff -Nru scons-4.0.1+dfsg/SCons/Tool/tex.py scons-4.4.0+dfsg/SCons/Tool/tex.py --- scons-4.0.1+dfsg/SCons/Tool/tex.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/tex.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,16 +1,6 @@ -"""SCons.Tool.tex - -Tool-specific initialization for TeX. -Generates .dvi files from .tex files - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,8 +20,15 @@ # 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__" + +""" Tool-specific initialization for TeX. + +Generates .dvi files from .tex files + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path import re @@ -429,18 +426,23 @@ return result # Now decide if latex will need to be run again due to newglossary command. - for ig in range(len(newglossary_suffix)): - if check_MD5(suffix_nodes[newglossary_suffix[ig][2]],newglossary_suffix[ig][2]) or (count == 1): + for ng in newglossary_suffix: + if check_MD5(suffix_nodes[ng[2]], ng[2]) or (count == 1): # We must run makeindex if Verbose: print("Need to run makeindex for newglossary") - newglfile = suffix_nodes[newglossary_suffix[ig][2]] - MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR") + newglfile = suffix_nodes[ng[2]] + MakeNewGlossaryAction = SCons.Action.Action( + "$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" + % (ng[2], ng[0], ng[1]), + "$MAKENEWGLOSSARYCOMSTR", + ) result = MakeNewGlossaryAction(newglfile, newglfile, env) if result != 0: - check_file_error_message('%s (newglossary)' % env['MAKENEWGLOSSARY'], - newglossary_suffix[ig][0]) + check_file_error_message( + '%s (newglossary)' % env['MAKENEWGLOSSARY'], ng[0] + ) return result # Now decide if latex needs to be run yet again to resolve warnings. @@ -470,7 +472,7 @@ shutil.move(resultfilename,str(target[0])) # Original comment (when TEXPICTS was not restored): - # The TEXPICTS enviroment variable is needed by a dvi -> pdf step + # The TEXPICTS environment variable is needed by a dvi -> pdf step # later on Mac OSX so leave it # # It is also used when searching for pictures (implicit dependencies). @@ -490,21 +492,23 @@ return result -def LaTeXAuxAction(target = None, source= None, env=None): - result = InternalLaTeXAuxAction( LaTeXAction, target, source, env ) +def LaTeXAuxAction(target=None, source=None, env=None): + result = InternalLaTeXAuxAction(LaTeXAction, target, source, env) return result + LaTeX_re = re.compile("\\\\document(style|class)") -def is_LaTeX(flist,env,abspath): + +def is_LaTeX(flist, env, abspath) -> bool: """Scan a file list to decide if it's TeX- or LaTeX-flavored.""" # We need to scan files that are included in case the # \documentclass command is in them. # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS'] - savedpath = modify_env_var(env, 'TEXINPUTS', abspath) - paths = env['ENV']['TEXINPUTS'] + savedpath = modify_env_var(env, "TEXINPUTS", abspath) + paths = env["ENV"]["TEXINPUTS"] if SCons.Util.is_List(paths): pass else: @@ -514,54 +518,58 @@ # now that we have the path list restore the env if savedpath is _null: try: - del env['ENV']['TEXINPUTS'] + del env["ENV"]["TEXINPUTS"] except KeyError: - pass # was never set + pass # was never set else: - env['ENV']['TEXINPUTS'] = savedpath + env["ENV"]["TEXINPUTS"] = savedpath if Verbose: - print("is_LaTeX search path ",paths) - print("files to search :",flist) + print("is_LaTeX search path ", paths) + print("files to search: ", flist) # Now that we have the search path and file list, check each one + file_test = False for f in flist: if Verbose: - print(" checking for Latex source ",str(f)) + print(f" checking for Latex source {f}") content = f.get_text_contents() if LaTeX_re.search(content): if Verbose: - print("file %s is a LaTeX file" % str(f)) - return 1 + print(f"file {f} is a LaTeX file") + return True if Verbose: - print("file %s is not a LaTeX file" % str(f)) + print(f"file {f} is not a LaTeX file") # now find included files - inc_files = [ ] - inc_files.extend( include_re.findall(content) ) + inc_files = [] + inc_files.extend(include_re.findall(content)) if Verbose: - print("files included by '%s': "%str(f),inc_files) + print(f"files included by '{f}': ", inc_files) # inc_files is list of file names as given. need to find them # using TEXINPUTS paths. # search the included files for src in inc_files: - srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False) + srcNode = FindFile( + src, [".tex", ".ltx", ".latex"], paths, env, requireExt=False + ) # make this a list since is_LaTeX takes a list. - fileList = [srcNode,] + fileList = [srcNode] if Verbose: - print("FindFile found ",srcNode) + print("FindFile found ", srcNode) if srcNode is not None: file_test = is_LaTeX(fileList, env, abspath) # return on first file that finds latex is needed. if file_test: - return file_test + return True if Verbose: - print(" done scanning ",str(f)) + print(f" done scanning {f}") + + return False - return 0 def TeXLaTeXFunction(target = None, source= None, env=None): """A builder for TeX and LaTeX that scans the source file to @@ -786,8 +794,8 @@ file_basename = os.path.join(targetdir, 'bu*.aux') file_list = glob.glob(file_basename) # remove the suffix '.aux' - for i in range(len(file_list)): - file_list.append(SCons.Util.splitext(file_list[i])[0]) + for fl in file_list.copy(): + file_list.append(SCons.Util.splitext(fl)[0]) # for multibib we need a list of files if suffix_list[-1] == 'multibib': for multibibmatch in multibib_re.finditer(content): @@ -797,8 +805,8 @@ baselist = multibibmatch.group(1).split(',') if Verbose: print("multibib list ", baselist) - for i in range(len(baselist)): - file_list.append(os.path.join(targetdir, baselist[i])) + for bl in baselist: + file_list.append(os.path.join(targetdir, bl)) # now define the side effects for file_name in file_list: for suffix in suffix_list[:-1]: @@ -862,7 +870,7 @@ if platform.system() == 'Darwin': try: ospath = env['ENV']['PATHOSX'] - except: + except KeyError: ospath = None if ospath: env.AppendENVPath('PATH', ospath) diff -Nru scons-4.0.1+dfsg/SCons/Tool/textfile.py scons-4.4.0+dfsg/SCons/Tool/textfile.py --- scons-4.0.1+dfsg/SCons/Tool/textfile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/textfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ -# -*- 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 @@ -20,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. -# -__doc__ = """ +""" Textfile/Substfile builder for SCons. Create file 'target' which typically is a textfile. The 'source' @@ -44,12 +43,8 @@ is unpredictable whether the expansion will occur. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import SCons -import os -import re from SCons.Node import Node from SCons.Node.Python import Value @@ -60,6 +55,7 @@ LINESEP = '\n' + def _do_subst(node, subs): """ Fetch the node contents and replace all instances of the keys with @@ -76,8 +72,8 @@ 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 @@ -88,7 +84,7 @@ # prepare the line separator linesep = env['LINESEPARATOR'] if linesep is None: - linesep = LINESEP # os.linesep + linesep = LINESEP # os.linesep elif is_String(linesep): pass elif isinstance(linesep, Value): @@ -116,7 +112,7 @@ if callable(value): value = value() if is_String(value): - value = env.subst(value) + value = env.subst(value, raw=1) else: value = str(value) subs.append((k, value)) diff -Nru scons-4.0.1+dfsg/SCons/Tool/ToolTests.py scons-4.4.0+dfsg/SCons/Tool/ToolTests.py --- scons-4.0.1+dfsg/SCons/Tool/ToolTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/ToolTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 TestUnit @@ -47,8 +44,6 @@ def __setitem__(self, key, val): self.dict[key] = val def __contains__(self, key): - return self.dict.__contains__(key) - def has_key(self, key): return key in self.dict def subst(self, string, *args, **kwargs): return string @@ -84,30 +79,32 @@ 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): - """Test that find_program_path() does not alter PATH""" + """Test that find_program_path() alters PATH only if add_path is true""" env = DummyEnvironment() PHONY_PATHS = [ r'C:\cygwin64\bin', r'C:\cygwin\bin', '/usr/local/dummy/bin', - env.PHONY_PATH, # will be recognized by dummy WhereIs + env.PHONY_PATH, # will be recognized by dummy WhereIs ] env['ENV'] = {} env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin' @@ -115,9 +112,14 @@ _ = SCons.Tool.find_program_path(env, 'no_tool', default_paths=PHONY_PATHS) assert env['ENV']['PATH'] == pre_path, env['ENV']['PATH'] + _ = SCons.Tool.find_program_path(env, 'no_tool', default_paths=PHONY_PATHS, add_path=True) + assert env.PHONY_PATH in env['ENV']['PATH'], env['ENV']['PATH'] + if __name__ == "__main__": - suite = unittest.makeSuite(ToolTestCase, 'test_') + loader = unittest.TestLoader() + loader.testMethodPrefix = 'test_' + suite = loader.loadTestsFromTestCase(ToolTestCase) TestUnit.run(suite) # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/Tool/Tool.xml scons-4.4.0+dfsg/SCons/Tool/Tool.xml --- scons-4.0.1+dfsg/SCons/Tool/Tool.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/Tool.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,543 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +Builds a C source file given a lex (.l) +or yacc (.y) input file. +The suffix specified by the &cv-link-CFILESUFFIX; &consvar; +(.c by default) +is automatically added to the target +if it is not already present. +Example: + + + +# builds foo.c +env.CFile(target = 'foo.c', source = 'foo.l') +# builds bar.c +env.CFile(target = 'bar', source = 'bar.y') + + + + + + + +Builds a C++ source file given a lex (.ll) +or yacc (.yy) +input file. +The suffix specified by the &cv-link-CXXFILESUFFIX; &consvar; +(.cc by default) +is automatically added to the target +if it is not already present. +Example: + + + +# builds foo.cc +env.CXXFile(target = 'foo.cc', source = 'foo.ll') +# builds bar.cc +env.CXXFile(target = 'bar', source = 'bar.yy') + + + + + + + +A synonym for the +&b-StaticLibrary; +builder method. + + + + + + + +On most systems, +this is the same as +&b-SharedLibrary;. +On Mac OS X (Darwin) platforms, +this creates a loadable module bundle. + + + + + + + +A synonym for the +&b-StaticObject; +builder method. + + + + + + + +Builds an executable given one or more object files +or C, C++, D, or Fortran source files. +If any C, C++, D or Fortran source files are specified, +then they will be automatically +compiled to object files using the +&b-Object; +builder method; +see that builder method's description for +a list of legal source file suffixes +and how they are interpreted. +The target executable file prefix, +specified by the &cv-link-PROGPREFIX; &consvar; +(nothing by default), +and suffix, +specified by the &cv-link-PROGSUFFIX; &consvar; +(by default, .exe on Windows systems, +nothing on POSIX systems), +are automatically added to the target if not already present. +Example: + + + +env.Program(target='foo', source=['foo.o', 'bar.c', 'baz.f']) + + + + + + + +Builds a shared library +(.so on a POSIX system, +.dll on Windows) +given one or more object files +or C, C++, D or Fortran source files. +If any source files are given, +then they will be automatically +compiled to object files. +The target library file prefix, +specified by the &cv-link-SHLIBPREFIX; &consvar; +(by default, lib on POSIX systems, +nothing on Windows systems), +and suffix, +specified by the &cv-link-SHLIBSUFFIX; &consvar; +(by default, .dll on Windows systems, +.so on POSIX systems), +are automatically added to the target if not already present. +Example: + + + +env.SharedLibrary(target='bar', source=['bar.c', 'foo.o']) + + + +On Windows systems, the +&b-SharedLibrary; +builder method will always build an import library +(.lib) +in addition to the shared library (.dll), +adding a .lib library with the same basename +if there is not already a .lib file explicitly +listed in the targets. + + + +On Cygwin systems, the +&b-SharedLibrary; +builder method will always build an import library +(.dll.a) +in addition to the shared library (.dll), +adding a .dll.a library with the same basename +if there is not already a .dll.a file explicitly +listed in the targets. + + + +Any object files listed in the +source +must have been built for a shared library +(that is, using the +&b-SharedObject; +builder method). +&scons; +will raise an error if there is any mismatch. + + + +On some platforms, there is a distinction between a shared library +(loaded automatically by the system to resolve external references) +and a loadable module (explicitly loaded by user action). +For maximum portability, use the &b-link-LoadableModule; builder for the latter. + + + +When the &cv-link-SHLIBVERSION; &consvar; is defined, a versioned +shared library is created. This modifies &cv-link-SHLINKFLAGS; as required, +adds the version number to the library name, and creates any +symbolic links that are needed. + + + +env.SharedLibrary(target='bar', source=['bar.c', 'foo.o'], SHLIBVERSION='1.5.2') + + + +On a POSIX system, versions with a single token create exactly one symlink: +libbar.so.6 would have symlink libbar.so only. +On a POSIX system, versions with two or more +tokens create exactly two symlinks: libbar.so.2.3.1 would have symlinks +libbar.so and libbar.so.2; on a Darwin (OSX) system the library would be +libbar.2.3.1.dylib and the link would be libbar.dylib. + + + +On Windows systems, specifying +register=1 +will cause the .dll to be +registered after it is built. +The command that is run is determined by the &cv-link-REGSVR; &consvar; +(regsvr32 by default), +and the flags passed are determined by &cv-link-REGSVRFLAGS;. By +default, &cv-link-REGSVRFLAGS; includes the option, +to prevent dialogs from popping +up and requiring user attention when it is run. If you change +&cv-link-REGSVRFLAGS;, be sure to include the option. +For example, + + + +env.SharedLibrary(target='bar', source=['bar.cxx', 'foo.obj'], register=1) + + + +will register bar.dll as a COM object +when it is done linking it. + + + + + + + +Builds an object file intended for +inclusion in a shared library. +Source files must have one of the same set of extensions +specified above for the +&b-StaticObject; +builder method. +On some platforms building a shared object requires additional +compiler option +(e.g. for gcc) +in addition to those needed to build a +normal (static) object, but on some platforms there is no difference between a +shared object and a normal (static) one. When there is a difference, SCons +will only allow shared objects to be linked into a shared library, and will +use a different suffix for shared objects. On platforms where there is no +difference, SCons will allow both normal (static) +and shared objects to be linked into a +shared library, and will use the same suffix for shared and normal +(static) objects. +The target object file prefix, +specified by the &cv-link-SHOBJPREFIX; &consvar; +(by default, the same as &cv-link-OBJPREFIX;), +and suffix, +specified by the &cv-link-SHOBJSUFFIX; &consvar;, +are automatically added to the target if not already present. +Examples: + + + +env.SharedObject(target='ddd', source='ddd.c') +env.SharedObject(target='eee.o', source='eee.cpp') +env.SharedObject(target='fff.obj', source='fff.for') + + + +Note that the source files will be scanned +according to the suffix mappings in the +SourceFileScanner +object. +See the manpage section "Scanner Objects" +for more information. + + + + + + + +Builds a static library given one or more object files +or C, C++, D or Fortran source files. +If any source files are given, +then they will be automatically +compiled to object files. +The static library file prefix, +specified by the &cv-link-LIBPREFIX; &consvar; +(by default, lib on POSIX systems, +nothing on Windows systems), +and suffix, +specified by the &cv-link-LIBSUFFIX; &consvar; +(by default, .lib on Windows systems, +.a on POSIX systems), +are automatically added to the target if not already present. +Example: + + + +env.StaticLibrary(target='bar', source=['bar.c', 'foo.o']) + + + +Any object files listed in the +source +must have been built for a static library +(that is, using the +&b-StaticObject; +builder method). +&scons; +will raise an error if there is any mismatch. + + + + + + + +Builds a static object file +from one or more C, C++, D, or Fortran source files. +Source files must have one of the following extensions: + + + + .asm assembly language file + .ASM assembly language file + .c C file + .C Windows: C file + POSIX: C++ file + .cc C++ file + .cpp C++ file + .cxx C++ file + .cxx C++ file + .c++ C++ file + .C++ C++ file + .d D file + .f Fortran file + .F Windows: Fortran file + POSIX: Fortran file + C pre-processor + .for Fortran file + .FOR Fortran file + .fpp Fortran file + C pre-processor + .FPP Fortran file + C pre-processor + .m Object C file + .mm Object C++ file + .s assembly language file + .S Windows: assembly language file + ARM: CodeSourcery Sourcery Lite + .sx assembly language file + C pre-processor + POSIX: assembly language file + C pre-processor + .spp assembly language file + C pre-processor + .SPP assembly language file + C pre-processor + + + +The target object file prefix, +specified by the &cv-link-OBJPREFIX; &consvar; +(nothing by default), +and suffix, +specified by the &cv-link-OBJSUFFIX; &consvar; +(.obj on Windows systems, +.o on POSIX systems), +are automatically added to the target if not already present. +Examples: + + + +env.StaticObject(target='aaa', source='aaa.c') +env.StaticObject(target='bbb.o', source='bbb.c++') +env.StaticObject(target='ccc.obj', source='ccc.f') + + + +Note that the source files will be scanned +according to the suffix mappings in the +SourceFileScanner +object. +See the manpage section "Scanner Objects" +for more information. + + + + + + + +The version number of the C compiler. +This may or may not be set, +depending on the specific C compiler being used. + + + + + + + +The suffix for C source files. +This is used by the internal CFile builder +when generating C files from Lex (.l) or YACC (.y) input files. +The default suffix, of course, is +.c +(lower case). +On case-insensitive systems (like Windows), +SCons also treats +.C +(upper case) files +as C files. + + + + + + + +The version number of the C++ compiler. +This may or may not be set, +depending on the specific C++ compiler being used. + + + + + + + +The suffix for C++ source files. +This is used by the internal CXXFile builder +when generating C++ files from Lex (.ll) or YACC (.yy) input files. +The default suffix is +.cc. +SCons also treats files with the suffixes +.cpp, +.cxx, +.c++, +and +.C++ +as C++ files, +and files with +.mm +suffixes as Objective C++ files. +On case-sensitive systems (Linux, UNIX, and other POSIX-alikes), +SCons also treats +.C +(upper case) files +as C++ files. + + + + + + + +Used to override &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; when +generating versioned import library for a shared library/loadable module. If +undefined, the &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; is used to +determine the version of versioned import library. + + + + + + + +Contains the emitter specification for the +&b-link-StaticLibrary; builder. +The manpage section "Builder Objects" contains +general information on specifying emitters. + + + + + + + +When this &consvar; is defined, a versioned loadable module +is created by &b-link-LoadableModule; builder. This activates the +&cv-link-_LDMODULEVERSIONFLAGS; and thus modifies the &cv-link-LDMODULECOM; as +required, adds the version number to the library name, and creates the symlinks +that are needed. &cv-link-LDMODULEVERSION; versions should exist in the same +format as &cv-link-SHLIBVERSION;. + + + + + + + +Contains the emitter specification for the +&b-link-LoadableModule; builder. +The manpage section "Builder Objects" contains +general information on specifying emitters. + + + + + + + +Contains the emitter specification for the +&b-link-SharedLibrary; builder. +The manpage section "Builder Objects" contains +general information on specifying emitters. + + + + + + + +Contains the emitter specification for the +&b-link-Program; builder. +The manpage section "Builder Objects" contains +general information on specifying emitters. + + + + + + + +When this &consvar; is defined, a versioned shared library +is created by the &b-link-SharedLibrary; builder. This activates the +&cv-link-_SHLIBVERSIONFLAGS; and thus modifies the &cv-link-SHLINKCOM; as +required, adds the version number to the library name, and creates the symlinks +that are needed. &cv-link-SHLIBVERSION; versions should exist as alpha-numeric, +decimal-delimited values as defined by the regular expression "\w+[\.\w+]*". +Example &cv-link-SHLIBVERSION; values include '1', '1.2.3', and '1.2.gitaa412c8b'. + + + + + diff -Nru scons-4.0.1+dfsg/SCons/Tool/wixTests.py scons-4.4.0+dfsg/SCons/Tool/wixTests.py --- scons-4.0.1+dfsg/SCons/Tool/wixTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/wixTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -26,7 +26,6 @@ import unittest import os.path import os -import sys import SCons.Errors from SCons.Tool.wix import * diff -Nru scons-4.0.1+dfsg/SCons/Tool/xgettext.py scons-4.4.0+dfsg/SCons/Tool/xgettext.py --- scons-4.0.1+dfsg/SCons/Tool/xgettext.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/xgettext.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,9 +1,6 @@ -""" xgettext tool - -Tool specific initialization of `xgettext` tool. -""" - -# __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 @@ -24,7 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Tool specific initialization of `xgettext` tool.""" import os import re @@ -35,16 +32,20 @@ import SCons.Node.FS import SCons.Tool import SCons.Util +import SCons.Warnings from SCons.Builder import BuilderBase from SCons.Environment import _null from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS from SCons.Platform.mingw import MINGW_DEFAULT_PATHS -from SCons.Tool.GettextCommon import _POTargetFactory -from SCons.Tool.GettextCommon import RPaths, _detect_xgettext -from SCons.Tool.GettextCommon import _xgettext_exists +from SCons.Tool.GettextCommon import ( + _detect_xgettext, + _POTargetFactory, + RPaths, + _xgettext_exists, + # XgettextToolWarning, +) -############################################################################# class _CmdRunner: """ Callable object, which runs shell command storing its stdout and stderr to variables. It also provides `strfunction()` method, which shall be used by @@ -81,9 +82,6 @@ return s -############################################################################# - -############################################################################# def _update_pot_file(target, source, env): """ Action function for `POTUpdate` builder """ nop = lambda target, source, env: 0 @@ -160,9 +158,6 @@ return 0 -############################################################################# - -############################################################################# class _POTBuilder(BuilderBase): def _execute(self, env, target, source, *args): if not target: @@ -174,9 +169,6 @@ return BuilderBase._execute(self, env, target, source, *args) -############################################################################# - -############################################################################# def _scan_xgettext_from_files(target, source, env, files=None, path=None): """ Parses `POTFILES.in`-like file and returns list of extracted file names. """ @@ -226,9 +218,6 @@ return 0 -############################################################################# - -############################################################################# def _pot_update_emitter(target, source, env): """ Emitter function for `POTUpdate` builder """ if 'XGETTEXTFROM' in env: @@ -255,16 +244,10 @@ return target, source -############################################################################# - -############################################################################# def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw): return env._POTUpdateBuilder(target, source, **kw) -############################################################################# - -############################################################################# def _POTUpdateBuilder(env, **kw): """ Creates `POTUpdate` builder object """ kw['action'] = SCons.Action.Action(_update_pot_file, None) @@ -274,9 +257,6 @@ return _POTBuilder(**kw) -############################################################################# - -############################################################################# def generate(env, **kw): """ Generate `xgettext` tool """ @@ -286,7 +266,11 @@ xgettext_bin_dir = os.path.dirname(xgettext) env.AppendENVPath('PATH', xgettext_bin_dir) else: - SCons.Warnings.Warning('xgettext tool requested, but binary not found in ENV PATH') + SCons.Warnings.warn( + # XgettextToolWarning, # using this breaks test, so keep: + SCons.Warnings.SConsWarning, + 'xgettext tool requested, but binary not found in ENV PATH' + ) try: env['XGETTEXT'] = _detect_xgettext(env) except: @@ -338,9 +322,6 @@ env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS')) -############################################################################# - -############################################################################# def exists(env): """ Check, whether the tool exists """ try: @@ -348,7 +329,6 @@ except: return False -############################################################################# # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Tool/yacc.py scons-4.4.0+dfsg/SCons/Tool/yacc.py --- scons-4.0.1+dfsg/SCons/Tool/yacc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/yacc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,15 +1,6 @@ -"""SCons.Tool.yacc - -Tool-specific initialization for yacc. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# 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,19 +20,30 @@ # 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__" +"""Tool-specific initialization for yacc. + +This tool should support multiple yacc implementations, +but is in actuality biased towards GNU Bison. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path import sys +from typing import Optional import SCons.Defaults import SCons.Tool -import SCons.Util +import SCons.Warnings from SCons.Platform.mingw import MINGW_DEFAULT_PATHS from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS from SCons.Platform.win32 import CHOCO_DEFAULT_PATH +from SCons.Util import CLVar, to_String + +DEFAULT_PATHS = CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR") @@ -50,14 +52,16 @@ 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". +def _yaccEmitter(target, source, env, ysuf, hsuf) -> tuple: + """Adds extra files generated by yacc program to target list.""" + yaccflags = env.subst_list("$YACCFLAGS", target=target, source=source) + flags = yaccflags[0] + targetBase, targetExt = os.path.splitext(to_String(target[0])) + + 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. @@ -67,66 +71,88 @@ # If -g is specified on the command line, yacc will emit a .vcg # file with the same base name as the .y, .yacc, .ym or .yy file. if "-g" in flags: - base, ext = os.path.splitext(SCons.Util.to_String(source[0])) + base, ext = os.path.splitext(to_String(source[0])) target.append(base + env.subst("$YACCVCGFILESUFFIX")) # If -v is specified yacc will create the output debug file # which is not really source for any process, but should - # be noted and also be cleaned - # Bug #2558 + # be noted and also be cleaned (issue #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. - fileGenOptions = ["--defines=", "--graph="] + # With --defines and --graph, the file to write is defined by the option + # argument. Extract this and include in the list of targets. + # NOTE: a filename passed to the command this way is not modified by SCons, + # and so will be interpreted relative to the project top directory at + # execution time, while the name added to the target list will be + # interpreted relative to the SConscript directory - a possible mismatch. + # + # These are GNU bison-only options. + # Since bison 3.8, --header is the preferred name over --defines + fileGenOptions = ["--defines=", "--header=", "--graph="] for option in flags: for fileGenOption in fileGenOptions: l = len(fileGenOption) if option[:l] == fileGenOption: - # A file generating option is present, so add the file - # name to the list of targets. fileName = option[l:].strip() target.append(fileName) - return (target, source) + yaccheaderfile = env.subst("$YACC_HEADER_FILE", target=target, source=source) + if yaccheaderfile: + target.append(yaccheaderfile) + # rewrite user-supplied file string with a node, we need later + env.Replace(YACC_HEADER_FILE=env.File(yaccheaderfile)) + + yaccgraphfile = env.subst("$YACC_GRAPH_FILE", target=target, source=source) + if yaccgraphfile: + target.append(yaccgraphfile) + # rewrite user-supplied file string with a node, we need later + env.Replace(YACC_GRAPH_FILE=env.File(yaccgraphfile)) + + return target, source + -def yEmitter(target, source, env): +def yEmitter(target, source, env) -> tuple: return _yaccEmitter(target, source, env, ['.y', '.yacc'], '$YACCHFILESUFFIX') -def ymEmitter(target, source, env): + +def ymEmitter(target, source, env) -> tuple: return _yaccEmitter(target, source, env, ['.ym'], '$YACCHFILESUFFIX') -def yyEmitter(target, source, env): + +def yyEmitter(target, source, env) -> tuple: return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX') -def get_yacc_path(env, append_paths=False): + +def get_yacc_path(env, append_paths=False) -> Optional[str]: """ - Find the path to the yacc tool, searching several possible names + Returns the path to the yacc tool, searching several possible names. - Only called in the Windows case, so the default_path - can be Windows-specific + Only called in the Windows case, so the `default_path` argument to + :func:`find_program_path` can be Windows-specific. - :param env: current construction environment - :param append_paths: if set, add the path to the tool to PATH - :return: path to yacc tool, if found + Args: + env: current construction environment + append_paths: if true, add the path to the tool to PATH """ for prog in BINS: bin_path = SCons.Tool.find_program_path( env, prog, - default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + default_paths=DEFAULT_PATHS, + add_path=append_paths, + ) if bin_path: - if append_paths: - env.AppendENVPath('PATH', os.path.dirname(bin_path)) return bin_path - SCons.Warnings.Warning('yacc tool requested, but yacc or bison binary not found in ENV PATH') + + SCons.Warnings.warn( + SCons.Warnings.SConsWarning, + 'yacc tool requested, but yacc or bison binary not found in ENV PATH' + ) -def generate(env): +def generate(env) -> None: """Add Builders and construction variables for yacc to an Environment.""" c_file, cxx_file = SCons.Tool.createCFileBuilders(env) @@ -149,14 +175,25 @@ # 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) - env['YACCFLAGS'] = SCons.Util.CLVar('') - env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' + env.SetDefault( + YACC=env.Detect(BINS), + YACCFLAGS=CLVar(""), + YACC_HEADER_FILE="", + YACC_GRAPH_FILE="", + ) + + env['YACCCOM'] = '$YACC $YACCFLAGS $_YACC_HEADER $_YACC_GRAPH -o $TARGET $SOURCES' env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' env['YACCVCGFILESUFFIX'] = '.vcg' + env['_YACC_HEADER'] = '${YACC_HEADER_FILE and "--header=" + str(YACC_HEADER_FILE)}' + env['_YACC_GRAPH'] = '${YACC_GRAPH_FILE and "--graph=" + str(YACC_GRAPH_FILE)}' + + +def exists(env) -> Optional[str]: + if 'YACC' in env: + return env.Detect(env['YACC']) -def exists(env): if sys.platform == 'win32': return get_yacc_path(env) else: diff -Nru scons-4.0.1+dfsg/SCons/Tool/yacc.xml scons-4.4.0+dfsg/SCons/Tool/yacc.xml --- scons-4.0.1+dfsg/SCons/Tool/yacc.xml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Tool/yacc.xml 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ SCons.Warnings +# --> SCons.Errors +# Thus the local imports, which are annotated for pylint to show we mean it. -PYPY = hasattr(sys, 'pypy_translation_info') - -# Below not used? -# InstanceType = types.InstanceType -MethodType = types.MethodType -FunctionType = types.FunctionType +PYPY = hasattr(sys, 'pypy_translation_info') -def dictify(keys, values, result={}): - for k, v in zip(keys, values): - result[k] = v +# this string will be hashed if a Node refers to a file that doesn't exist +# in order to distinguish from a file that exists but is empty. +NOFILE = "SCONS_MAGIC_MISSING_FILE_STRING" + +# unused? +def dictify(keys, values, result=None) -> dict: + if result is None: + result = {} + result.update(zip(keys, values)) return result -_altsep = os.altsep -if _altsep is None and sys.platform == 'win32': +_ALTSEP = os.altsep +if _ALTSEP is None and sys.platform == 'win32': # My ActivePython 2.0.1 doesn't set os.altsep! What gives? - _altsep = '/' -if _altsep: + _ALTSEP = '/' +if _ALTSEP: def rightmost_separator(path, sep): - return max(path.rfind(sep), path.rfind(_altsep)) + return max(path.rfind(sep), path.rfind(_ALTSEP)) else: def rightmost_separator(path, sep): return path.rfind(sep) # First two from the Python Cookbook, just for completeness. # (Yeah, yeah, YAGNI...) -def containsAny(str, set): - """Check whether sequence str contains ANY of the items in set.""" - for c in set: - if c in str: return 1 - return 0 - -def containsAll(str, set): - """Check whether sequence str contains ALL of the items in set.""" - for c in set: - if c not in str: return 0 - return 1 - -def containsOnly(str, set): - """Check whether sequence str contains ONLY items in set.""" - for c in str: - if c not in set: return 0 - return 1 +def containsAny(s, pat) -> bool: + """Check whether string `s` contains ANY of the items in `pat`.""" + return any(c in s for c in pat) + +def containsAll(s, pat) -> bool: + """Check whether string `s` contains ALL of the items in `pat`.""" + return all(c in s for c in pat) + +def containsOnly(s, pat) -> bool: + """Check whether string `s` contains ONLY items in `pat`.""" + for c in s: + if c not in pat: + return False + return True -def splitext(path): - """Same as os.path.splitext() but faster.""" + +# TODO: Verify this method is STILL faster than os.path.splitext +def splitext(path) -> tuple: + """Split `path` into a (root, ext) pair. + + Same as :mod:`os.path.splitext` but faster. + """ sep = rightmost_separator(path, os.sep) dot = path.rfind('.') # An ext is only real if it has at least one non-digit char - if dot > sep and not containsOnly(path[dot:], "0123456789."): - return path[:dot],path[dot:] - else: - return path,"" + if dot > sep and not path[dot + 1:].isdigit(): + return path[:dot], path[dot:] + + return path, "" + +def updrive(path) -> str: + """Make the drive letter (if any) upper case. -def updrive(path): - """ - Make the drive letter (if any) upper case. This is useful because Windows is inconsistent on the case of the drive letter, which can cause inconsistencies when calculating command signatures. @@ -104,36 +112,24 @@ return path class NodeList(UserList): - """This class is almost exactly like a regular list of Nodes - (actually it can hold any object), with one important difference. - If you try to get an attribute from this list, it will return that - attribute from every item in the list. For example: + """A list of Nodes with special attribute retrieval. - >>> someList = NodeList([ ' foo ', ' bar ' ]) - >>> someList.strip() - [ 'foo', 'bar' ] - """ - -# def __init__(self, initlist=None): -# self.data = [] -# # print("TYPE:%s"%type(initlist)) -# if initlist is not None: -# # XXX should this accept an arbitrary sequence? -# if type(initlist) == type(self.data): -# self.data[:] = initlist -# elif isinstance(initlist, (UserList, NodeList)): -# self.data[:] = initlist.data[:] -# elif isinstance(initlist, Iterable): -# self.data = list(initlist) -# else: -# self.data = [ initlist,] + Unlike an ordinary list, access to a member's attribute returns a + `NodeList` containing the same attribute for each member. Although + this can hold any object, it is intended for use when processing + Nodes, where fetching an attribute of each member is very commone, + for example getting the content signature of each node. The term + "attribute" here includes the string representation. + Example: - def __nonzero__(self): - return len(self.data) != 0 + >>> someList = NodeList([' foo ', ' bar ']) + >>> someList.strip() + ['foo', 'bar'] + """ def __bool__(self): - return self.__nonzero__() + return bool(self.data) def __str__(self): return ' '.join(map(str, self.data)) @@ -141,59 +137,56 @@ def __iter__(self): return iter(self.data) - def __call__(self, *args, **kwargs): + def __call__(self, *args, **kwargs) -> 'NodeList': result = [x(*args, **kwargs) for x in self.data] return self.__class__(result) - def __getattr__(self, name): + def __getattr__(self, name) -> 'NodeList': + """Returns a NodeList of `name` from each member.""" result = [getattr(x, name) for x in self.data] return self.__class__(result) def __getitem__(self, index): - """ - This comes for free on py2, - but py3 slices of NodeList are returning a list - breaking slicing nodelist and refering to - properties and methods on contained object - """ -# return self.__class__(self.data[index]) - + """Returns one item, forces a `NodeList` if `index` is a slice.""" + # TODO: annotate return how? Union[] - don't know type of single item if isinstance(index, slice): - # Expand the slice object using range() - # limited by number of items in self.data - indices = index.indices(len(self.data)) - return self.__class__([self[x] for x in - range(*indices)]) - else: - # Return one item of the tart - return self.data[index] + return self.__class__(self.data[index]) + return self.data[index] _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$') -def get_environment_var(varstr): - """Given a string, first determine if it looks like a reference - to a single environment variable, like "$FOO" or "${FOO}". - If so, return that variable with no decorations ("FOO"). - If not, return None.""" - mo=_get_env_var.match(to_String(varstr)) +def get_environment_var(varstr) -> Optional[str]: + """Return undecorated construction variable string. + + Determine if `varstr` looks like a reference + to a single environment variable, like `"$FOO"` or `"${FOO}"`. + If so, return that variable with no decorations, like `"FOO"`. + If not, return `None`. + """ + + mo = _get_env_var.match(to_String(varstr)) if mo: var = mo.group(1) if var[0] == '{': return var[1:-1] - else: - return var - else: - return None + return var + + return None class DisplayEngine: + """A callable class used to display SCons messages.""" + print_it = True def __call__(self, text, append_newline=1): if not self.print_it: return - if append_newline: text = text + '\n' + + if append_newline: + text = text + '\n' + try: sys.stdout.write(str(text)) except IOError: @@ -210,16 +203,18 @@ self.print_it = mode +# TODO: W0102: Dangerous default value [] as argument (dangerous-default-value) def render_tree(root, child_func, prune=0, margin=[0], visited=None): - """ - Render a tree of nodes into an ASCII tree view. + """Render a tree of nodes into an ASCII tree view. - :Parameters: - - `root`: the root node of the tree - - `child_func`: the function called to get the children of a node - - `prune`: don't visit the same node twice - - `margin`: the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe. - - `visited`: a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune. + Args: + root: the root node of the tree + child_func: the function called to get the children of a node + prune: don't visit the same node twice + margin: the format of the left margin to use for children of `root`. + 1 results in a pipe, and 0 results in no pipe. + visited: a dictionary of visited nodes in the current branch if + `prune` is 0, or in the whole tree if `prune` is 1. """ rname = str(root) @@ -242,16 +237,21 @@ retval = retval + "+-" + rname + "\n" if not prune: visited = copy.copy(visited) - visited[rname] = 1 + visited[rname] = True - for i in range(len(children)): + for i, child in enumerate(children): margin.append(i < len(children)-1) - retval = retval + render_tree(children[i], child_func, prune, margin, visited) + retval = retval + render_tree(child, child_func, prune, margin, visited) margin.pop() return retval -IDX = lambda N: N and 1 or 0 +def IDX(n) -> bool: + """Generate in index into strings from the tree legends. + + These are always a choice between two, so bool works fine. + """ + return bool(n) # unicode line drawing chars: BOX_HORIZ = chr(0x2500) # '─' @@ -264,25 +264,37 @@ BOX_HORIZ_DOWN = chr(0x252c) # '┬' -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None, lastChild=False, singleLineDraw=False): - """ - Print a tree of nodes. This is like render_tree, except it prints - lines directly instead of creating a string representation in memory, - so that huge trees can be printed. - - :Parameters: - - `root` - the root node of the tree - - `child_func` - the function called to get the children of a node - - `prune` - don't visit the same node twice - - `showtags` - print status information to the left of each node line - - `margin` - the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe. - - `visited` - a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune. - - `singleLineDraw` - use line-drawing characters rather than ASCII. +# TODO: W0102: Dangerous default value [] as argument (dangerous-default-value) +def print_tree( + root, + child_func, + prune=0, + showtags=False, + margin=[0], + visited=None, + lastChild=False, + singleLineDraw=False, +): + """Print a tree of nodes. + + This is like func:`render_tree`, except it prints lines directly instead + of creating a string representation in memory, so that huge trees can + be handled. + + Args: + root: the root node of the tree + child_func: the function called to get the children of a node + prune: don't visit the same node twice + showtags: print status information to the left of each node line + margin: the format of the left margin to use for children of `root`. + 1 results in a pipe, and 0 results in no pipe. + visited: a dictionary of visited nodes in the current branch if + prune` is 0, or in the whole tree if `prune` is 1. + singleLineDraw: use line-drawing characters rather than ASCII. """ rname = str(root) - # Initialize 'visited' dict, if required if visited is None: visited = {} @@ -326,14 +338,11 @@ def MMM(m): if singleLineDraw: return [" ", BOX_VERT + " "][m] - else: - return [" ", "| "][m] - margins = list(map(MMM, margin[:-1])) + return [" ", "| "][m] + margins = list(map(MMM, margin[:-1])) children = child_func(root) - - cross = "+-" if singleLineDraw: cross = BOX_VERT_RIGHT + BOX_HORIZ # sign used to point to the leaf. @@ -360,15 +369,26 @@ # if this item has children: if children: - margin.append(1) # Initialize margin with 1 for vertical bar. + margin.append(1) # Initialize margin with 1 for vertical bar. idx = IDX(showtags) - _child = 0 # Initialize this for the first child. + _child = 0 # Initialize this for the first child. for C in children[:-1]: - _child = _child + 1 # number the children - print_tree(C, child_func, prune, idx, margin, visited, (len(children) - _child) <= 0 ,singleLineDraw) - margin[-1] = 0 # margins are with space (index 0) because we arrived to the last child. - print_tree(children[-1], child_func, prune, idx, margin, visited, True ,singleLineDraw) # for this call child and nr of children needs to be set 0, to signal the second phase. - margin.pop() # destroy the last margin added + _child = _child + 1 # number the children + print_tree( + C, + child_func, + prune, + idx, + margin, + visited, + (len(children) - _child) <= 0, + singleLineDraw, + ) + # margins are with space (index 0) because we arrived to the last child. + margin[-1] = 0 + # for this call child and nr of children needs to be set 0, to signal the second phase. + print_tree(children[-1], child_func, prune, idx, margin, visited, True, singleLineDraw) + margin.pop() # destroy the last margin added # Functions for deciding if things are like various types, mainly to @@ -384,6 +404,9 @@ # the global functions and constants used by these functions. This # transforms accesses to global variable into local variables # accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL). +# Since checkers dislike this, it's now annotated for pylint to flag +# (mostly for other readers of this code) we're doing this intentionally. +# TODO: PY3 check these are still valid choices for all of these funcs. DictTypes = (dict, UserDict) ListTypes = (list, UserList) @@ -391,31 +414,49 @@ # Handle getting dictionary views. SequenceTypes = (list, tuple, UserList, MappingView) -# TODO: PY3 check this benchmarking is still correct. # Note that profiling data shows a speed-up when comparing # explicitly with str instead of simply comparing # with basestring. (at least on Python 2.5.1) +# TODO: PY3 check this benchmarking is still correct. StringTypes = (str, UserString) # Empirically, it is faster to check explicitly for str than for basestring. BaseStringTypes = str -def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes): +def is_Dict( # pylint: disable=redefined-outer-name,redefined-builtin + obj, isinstance=isinstance, DictTypes=DictTypes +) -> bool: return isinstance(obj, DictTypes) -def is_List(obj, isinstance=isinstance, ListTypes=ListTypes): + +def is_List( # pylint: disable=redefined-outer-name,redefined-builtin + obj, isinstance=isinstance, ListTypes=ListTypes +) -> bool: return isinstance(obj, ListTypes) -def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes): + +def is_Sequence( # pylint: disable=redefined-outer-name,redefined-builtin + obj, isinstance=isinstance, SequenceTypes=SequenceTypes +) -> bool: return isinstance(obj, SequenceTypes) -def is_Tuple(obj, isinstance=isinstance, tuple=tuple): + +def is_Tuple( # pylint: disable=redefined-builtin + obj, isinstance=isinstance, tuple=tuple +) -> bool: return isinstance(obj, tuple) -def is_String(obj, isinstance=isinstance, StringTypes=StringTypes): + +def is_String( # pylint: disable=redefined-outer-name,redefined-builtin + obj, isinstance=isinstance, StringTypes=StringTypes +) -> bool: return isinstance(obj, StringTypes) -def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes): + +def is_Scalar( # pylint: disable=redefined-outer-name,redefined-builtin + obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes +) -> bool: + # Profiling shows that there is an impressive speed-up of 2x # when explicitly checking for strings instead of just not # sequence when the argument (i.e. obj) is already a string. @@ -424,21 +465,33 @@ # assumes that the obj argument is a string most of the time. return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes) -def do_flatten(sequence, result, isinstance=isinstance, - StringTypes=StringTypes, SequenceTypes=SequenceTypes): + +def do_flatten( + sequence, + result, + isinstance=isinstance, + StringTypes=StringTypes, + SequenceTypes=SequenceTypes, +): # pylint: disable=redefined-outer-name,redefined-builtin for item in sequence: if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): result.append(item) else: do_flatten(item, result) -def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, - SequenceTypes=SequenceTypes, do_flatten=do_flatten): + +def flatten( # pylint: disable=redefined-outer-name,redefined-builtin + obj, + isinstance=isinstance, + StringTypes=StringTypes, + SequenceTypes=SequenceTypes, + do_flatten=do_flatten, +) -> list: """Flatten a sequence to a non-nested list. - Flatten() converts either a single scalar or a nested sequence - to a non-nested list. Note that flatten() considers strings - to be scalars instead of sequences like Python would. + Converts either a single scalar or a nested sequence to a non-nested list. + Note that :func:`flatten` considers strings + to be scalars instead of sequences like pure Python would. """ if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes): return [obj] @@ -450,13 +503,19 @@ do_flatten(item, result) return result -def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, - SequenceTypes=SequenceTypes, do_flatten=do_flatten): + +def flatten_sequence( # pylint: disable=redefined-outer-name,redefined-builtin + sequence, + isinstance=isinstance, + StringTypes=StringTypes, + SequenceTypes=SequenceTypes, + do_flatten=do_flatten, +) -> list: """Flatten a sequence to a non-nested list. - Same as flatten(), but it does not handle the single scalar - case. This is slightly more efficient when one knows that - the sequence to flatten can not be a scalar. + Same as :func:`flatten`, but it does not handle the single scalar case. + This is slightly more efficient when one knows that the sequence + to flatten can not be a scalar. """ result = [] for item in sequence: @@ -469,41 +528,58 @@ # Generic convert-to-string functions. The wrapper # to_String_for_signature() will use a for_signature() method if the # specified object has one. -# +def to_String( # pylint: disable=redefined-outer-name,redefined-builtin + obj, + isinstance=isinstance, + str=str, + UserString=UserString, + BaseStringTypes=BaseStringTypes, +) -> str: + """Return a string version of obj.""" -def to_String(s, - isinstance=isinstance, str=str, - UserString=UserString, BaseStringTypes=BaseStringTypes): - if isinstance(s, BaseStringTypes): + if isinstance(obj, BaseStringTypes): # Early out when already a string! - return s - elif isinstance(s, UserString): - # s.data can only be a regular string. Please see the UserString initializer. - return s.data - else: - return str(s) + return obj - -def to_String_for_subst(s, - isinstance=isinstance, str=str, to_String=to_String, - BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes, - UserString=UserString): + if isinstance(obj, UserString): + # obj.data can only be a regular string. Please see the UserString initializer. + return obj.data + + return str(obj) + +def to_String_for_subst( # pylint: disable=redefined-outer-name,redefined-builtin + obj, + isinstance=isinstance, + str=str, + BaseStringTypes=BaseStringTypes, + SequenceTypes=SequenceTypes, + UserString=UserString, +) -> str: + """Return a string version of obj for subst usage.""" # Note that the test cases are sorted by order of probability. - if isinstance(s, BaseStringTypes): - return s - elif isinstance(s, SequenceTypes): - return ' '.join([to_String_for_subst(e) for e in s]) - elif isinstance(s, UserString): - # s.data can only a regular string. Please see the UserString initializer. - return s.data - else: - return str(s) + if isinstance(obj, BaseStringTypes): + return obj + + if isinstance(obj, SequenceTypes): + return ' '.join([to_String_for_subst(e) for e in obj]) + + if isinstance(obj, UserString): + # obj.data can only a regular string. Please see the UserString initializer. + return obj.data + return str(obj) + +def to_String_for_signature( # pylint: disable=redefined-outer-name,redefined-builtin + obj, to_String_for_subst=to_String_for_subst, AttributeError=AttributeError +) -> str: + """Return a string version of obj for signature usage. + + Like :func:`to_String_for_subst` but has special handling for + scons objects that have a :meth:`for_signature` method, and for dicts. + """ -def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, - AttributeError=AttributeError): try: f = obj.for_signature except AttributeError: @@ -513,8 +589,7 @@ # which was undefined until py3.6 (where it's by insertion order) was not wise. # TODO: Change code when floor is raised to PY36 return pprint.pformat(obj, width=1000000) - else: - return to_String_for_subst(obj) + return to_String_for_subst(obj) else: return f() @@ -532,71 +607,65 @@ # The dispatch table approach used here is a direct rip-off from the # normal Python copy module. -_semi_deepcopy_dispatch = d = {} - -def semi_deepcopy_dict(x, exclude = [] ): - copy = {} - for key, val in x.items(): - # The regular Python copy.deepcopy() also deepcopies the key, - # as follows: - # - # copy[semi_deepcopy(key)] = semi_deepcopy(val) - # - # Doesn't seem like we need to, but we'll comment it just in case. - if key not in exclude: - copy[key] = semi_deepcopy(val) - return copy -d[dict] = semi_deepcopy_dict - -def _semi_deepcopy_list(x): - return list(map(semi_deepcopy, x)) -d[list] = _semi_deepcopy_list - -def _semi_deepcopy_tuple(x): - return tuple(map(semi_deepcopy, x)) -d[tuple] = _semi_deepcopy_tuple +def semi_deepcopy_dict(obj, exclude=None) -> dict: + if exclude is None: + exclude = [] + return {k: semi_deepcopy(v) for k, v in obj.items() if k not in exclude} + +def _semi_deepcopy_list(obj) -> list: + return [semi_deepcopy(item) for item in obj] + +def _semi_deepcopy_tuple(obj) -> tuple: + return tuple(map(semi_deepcopy, obj)) + +_semi_deepcopy_dispatch = { + dict: semi_deepcopy_dict, + list: _semi_deepcopy_list, + tuple: _semi_deepcopy_tuple, +} -def semi_deepcopy(x): - copier = _semi_deepcopy_dispatch.get(type(x)) +def semi_deepcopy(obj): + copier = _semi_deepcopy_dispatch.get(type(obj)) if copier: - return copier(x) - else: - if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__): - return x.__semi_deepcopy__() - elif isinstance(x, UserDict): - return x.__class__(semi_deepcopy_dict(x)) - elif isinstance(x, UserList): - return x.__class__(_semi_deepcopy_list(x)) + return copier(obj) - return x + if hasattr(obj, '__semi_deepcopy__') and callable(obj.__semi_deepcopy__): + return obj.__semi_deepcopy__() + + if isinstance(obj, UserDict): + return obj.__class__(semi_deepcopy_dict(obj)) + + if isinstance(obj, UserList): + return obj.__class__(_semi_deepcopy_list(obj)) + + return obj class Proxy: - """A simple generic Proxy class, forwarding all calls to - subject. So, for the benefit of the python newbie, what does - this really mean? Well, it means that you can take an object, let's - call it 'objA', and wrap it in this Proxy class, with a statement - like this + """A simple generic Proxy class, forwarding all calls to subject. - proxyObj = Proxy(objA), + This means you can take an object, let's call it `'obj_a`, + and wrap it in this Proxy class, with a statement like this:: - Then, if in the future, you do something like this + proxy_obj = Proxy(obj_a) - x = proxyObj.var1, + Then, if in the future, you do something like this:: - since Proxy does not have a 'var1' attribute (but presumably objA does), - the request actually is equivalent to saying + x = proxy_obj.var1 - x = objA.var1 + since the :class:`Proxy` class does not have a :attr:`var1` attribute + (but presumably `objA` does), the request actually is equivalent to saying:: + + x = obj_a.var1 Inherit from this class to create a Proxy. - Note that, with new-style classes, this does *not* work transparently - for Proxy subclasses that use special .__*__() method names, because - those names are now bound to the class, not the individual instances. - You now need to know in advance which .__*__() method names you want - to pass on to the underlying Proxy object, and specifically delegate - their calls like this: + With Python 3.5+ this does *not* work transparently + for :class:`Proxy` subclasses that use special .__*__() method names, + because those names are now bound to the class, not the individual + instances. You now need to know in advance which special method names you + want to pass on to the underlying Proxy object, and specifically delegate + their calls like this:: class Foo(Proxy): __str__ = Delegate('__str__') @@ -607,8 +676,11 @@ self._subject = subject def __getattr__(self, name): - """Retrieve an attribute from the wrapped object. If the named - attribute doesn't exist, AttributeError is raised""" + """Retrieve an attribute from the wrapped object. + + Raises: + AttributeError: if attribute `name` doesn't exist. + """ return getattr(self._subject, name) def get(self): @@ -623,7 +695,7 @@ class Delegate: """A Python Descriptor class that delegates attribute fetches - to an underlying wrapped subject of a Proxy. Typical use: + to an underlying wrapped subject of a Proxy. Typical use:: class Foo(Proxy): __str__ = Delegate('__str__') @@ -634,88 +706,97 @@ def __get__(self, obj, cls): if isinstance(obj, cls): return getattr(obj._subject, self.attribute) - else: - return self -# attempt to load the windows registry module: -can_read_reg = 0 -try: - import winreg - - can_read_reg = 1 - hkey_mod = winreg + return self - RegOpenKeyEx = winreg.OpenKeyEx - RegEnumKey = winreg.EnumKey - RegEnumValue = winreg.EnumValue - RegQueryValueEx = winreg.QueryValueEx - 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 +class MethodWrapper: + """A generic Wrapper class that associates a method with an object. - except ImportError: - class _NoError(Exception): - pass - RegError = _NoError + 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 + :meth:`__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, obj, method, name=None): + if name is None: + name = method.__name__ + self.object = obj + 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) -# Make sure we have a definition of WindowsError so we can -# run platform-independent tests of Windows functionality on -# platforms other than Windows. (WindowsError is, in fact, an -# OSError subclass on Windows.) + 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 PlainWindowsError(OSError): - pass +# attempt to load the windows registry module: +can_read_reg = False try: - WinError = WindowsError -except NameError: - WinError = PlainWindowsError + import winreg + can_read_reg = True + hkey_mod = winreg + +except ImportError: + class _NoError(Exception): + pass + RegError = _NoError if can_read_reg: - HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT + HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE - HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER - HKEY_USERS = hkey_mod.HKEY_USERS + HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER + HKEY_USERS = hkey_mod.HKEY_USERS + + RegOpenKeyEx = winreg.OpenKeyEx + RegEnumKey = winreg.EnumKey + RegEnumValue = winreg.EnumValue + RegQueryValueEx = winreg.QueryValueEx + RegError = winreg.error def RegGetValue(root, key): - r"""This utility function returns a value in the registry - without having to open the key first. Only available on - Windows platforms with a version of Python that can read the - registry. Returns the same thing as - SCons.Util.RegQueryValueEx, except you just specify the entire - path to the value, and don't have to bother opening the key - first. So: + r"""Returns a registry value without having to open the key first. + + Only available on Windows platforms with a version of Python that + can read the registry. + + Returns the same thing as :func:`RegQueryValueEx`, except you just + specify the entire path to the value, and don't have to bother + opening the key first. So, instead of:: - Instead of: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion') - out = SCons.Util.RegQueryValueEx(k, - 'ProgramFilesDir') + out = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') + + You can write:: - You can write: out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir') """ # I would use os.path.split here, but it's not a filesystem # path... p = key.rfind('\\') + 1 - keyp = key[:p-1] # -1 to omit trailing slash + keyp = key[: p - 1] # -1 to omit trailing slash val = key[p:] k = RegOpenKeyEx(root, keyp) - return RegQueryValueEx(k,val) + return RegQueryValueEx(k, val) + + else: HKEY_CLASSES_ROOT = None HKEY_LOCAL_MACHINE = None @@ -723,14 +804,15 @@ HKEY_USERS = None def RegGetValue(root, key): - raise WinError + raise OSError def RegOpenKeyEx(root, key): - raise WinError + raise OSError + if sys.platform == 'win32': - def WhereIs(file, path=None, pathext=None, reject=[]): + def WhereIs(file, path=None, pathext=None, reject=None) -> Optional[str]: if path is None: try: path = os.environ['PATH'] @@ -749,10 +831,12 @@ if ext.lower() == file[-len(ext):].lower(): pathext = [''] break + if reject is None: + reject = [] if not is_List(reject) and not is_Tuple(reject): reject = [reject] - for dir in path: - f = os.path.join(dir, file) + for p in path: + f = os.path.join(p, file) for ext in pathext: fext = f + ext if os.path.isfile(fext): @@ -765,7 +849,7 @@ elif os.name == 'os2': - def WhereIs(file, path=None, pathext=None, reject=[]): + def WhereIs(file, path=None, pathext=None, reject=None) -> Optional[str]: if path is None: try: path = os.environ['PATH'] @@ -779,10 +863,12 @@ if ext.lower() == file[-len(ext):].lower(): pathext = [''] break + if reject is None: + reject = [] if not is_List(reject) and not is_Tuple(reject): reject = [reject] - for dir in path: - f = os.path.join(dir, file) + for p in path: + f = os.path.join(p, file) for ext in pathext: fext = f + ext if os.path.isfile(fext): @@ -795,8 +881,9 @@ else: - def WhereIs(file, path=None, pathext=None, reject=[]): - import stat + def WhereIs(file, path=None, pathext=None, reject=None) -> Optional[str]: + import stat # pylint: disable=import-outside-toplevel + if path is None: try: path = os.environ['PATH'] @@ -804,10 +891,12 @@ return None if is_String(path): path = path.split(os.pathsep) + if reject is None: + reject = [] if not is_List(reject) and not is_Tuple(reject): reject = [reject] - for d in path: - f = os.path.join(d, file) + for p in path: + f = os.path.join(p, file) if os.path.isfile(f): try: st = os.stat(f) @@ -825,35 +914,53 @@ continue return None -def PrependPath(oldpath, newpath, sep = os.pathsep, - delete_existing=1, canonicalize=None): - """This prepends newpath elements to the given oldpath. Will only - add any particular path once (leaving the first one it encounters - and ignoring the rest, to preserve path order), and will - os.path.normpath and os.path.normcase all paths to help assure - this. This can also handle the case where the given old path - variable is a list instead of a string, in which case a list will - be returned instead of a string. +WhereIs.__doc__ = """\ +Return the path to an executable that matches `file`. - Example: - Old Path: "/foo/bar:/foo" - New Path: "/biz/boom:/foo" - Result: "/biz/boom:/foo:/foo/bar" - - If delete_existing is 0, then adding a path that exists will - not move it to the beginning; it will stay where it is in the - list. +Searches the given `path` for `file`, respecting any filename +extensions `pathext` (on the Windows platform only), and +returns the full path to the matching command. If no +command is found, return ``None``. + +If `path` is not specified, :attr:`os.environ[PATH]` is used. +If `pathext` is not specified, :attr:`os.environ[PATHEXT]` +is used. Will not select any path name or names in the optional +`reject` list. +""" + +def PrependPath( + oldpath, newpath, sep=os.pathsep, delete_existing=True, canonicalize=None +) -> Union[list, str]: + """Prepends `newpath` path elements to `oldpath`. + + Will only add any particular path once (leaving the first one it + encounters and ignoring the rest, to preserve path order), and will + :mod:`os.path.normpath` and :mod:`os.path.normcase` all paths to help + assure this. This can also handle the case where `oldpath` + is a list instead of a string, in which case a list will be returned + instead of a string. For example: + + >>> p = PrependPath("/foo/bar:/foo", "/biz/boom:/foo") + >>> print(p) + /biz/boom:/foo:/foo/bar + + If `delete_existing` is ``False``, then adding a path that exists will + not move it to the beginning; it will stay where it is in the list. + + >>> p = PrependPath("/foo/bar:/foo", "/biz/boom:/foo", delete_existing=False) + >>> print(p) + /biz/boom:/foo/bar:/foo - If canonicalize is not None, it is applied to each element of - newpath before use. + If `canonicalize` is not ``None``, it is applied to each element of + `newpath` before use. """ orig = oldpath - is_list = 1 + is_list = True paths = orig if not is_List(orig) and not is_Tuple(orig): paths = paths.split(sep) - is_list = 0 + is_list = False if is_String(newpath): newpaths = newpath.split(sep) @@ -904,42 +1011,47 @@ if is_list: return paths - else: - return sep.join(paths) -def AppendPath(oldpath, newpath, sep = os.pathsep, - delete_existing=1, canonicalize=None): - """This appends new path elements to the given old path. Will - only add any particular path once (leaving the last one it - encounters and ignoring the rest, to preserve path order), and - will os.path.normpath and os.path.normcase all paths to help - assure this. This can also handle the case where the given old - path variable is a list instead of a string, in which case a list - will be returned instead of a string. + return sep.join(paths) - Example: - Old Path: "/foo/bar:/foo" - New Path: "/biz/boom:/foo" - Result: "/foo/bar:/biz/boom:/foo" +def AppendPath( + oldpath, newpath, sep=os.pathsep, delete_existing=True, canonicalize=None +) -> Union[list, str]: + """Appends `newpath` path elements to `oldpath`. + + Will only add any particular path once (leaving the last one it + encounters and ignoring the rest, to preserve path order), and will + :mod:`os.path.normpath` and :mod:`os.path.normcase` all paths to help + assure this. This can also handle the case where `oldpath` + is a list instead of a string, in which case a list will be returned + instead of a string. For example: + + >>> p = AppendPath("/foo/bar:/foo", "/biz/boom:/foo") + >>> print(p) + /foo/bar:/biz/boom:/foo - If delete_existing is 0, then adding a path that exists + If `delete_existing` is ``False``, then adding a path that exists will not move it to the end; it will stay where it is in the list. - If canonicalize is not None, it is applied to each element of - newpath before use. + >>> p = AppendPath("/foo/bar:/foo", "/biz/boom:/foo", delete_existing=False) + >>> print(p) + /foo/bar:/foo:/biz/boom + + If `canonicalize` is not ``None``, it is applied to each element of + `newpath` before use. """ orig = oldpath - is_list = 1 + is_list = True paths = orig if not is_List(orig) and not is_Tuple(orig): paths = paths.split(sep) - is_list = 0 + is_list = False if is_String(newpath): newpaths = newpath.split(sep) elif not is_List(newpath) and not is_Tuple(newpath): - newpaths = [ newpath ] # might be a Dir + newpaths = [newpath] # might be a Dir else: newpaths = newpath @@ -985,22 +1097,29 @@ if is_list: return paths - else: - return sep.join(paths) + + return sep.join(paths) def AddPathIfNotExists(env_dict, key, path, sep=os.pathsep): - """This function will take 'key' out of the dictionary - 'env_dict', then add the path 'path' to that key if it is not - already there. This treats the value of env_dict[key] as if it - has a similar format to the PATH variable...a list of paths - separated by tokens. The 'path' will get added to the list if it - is not already there.""" + """Add a path element to a construction variable. + + `key` is looked up in `env_dict`, and `path` is added to it if it + is not already present. `env_dict[key]` is assumed to be in the + format of a PATH variable: a list of paths separated by `sep` tokens. + Example: + + >>> env = {'PATH': '/bin:/usr/bin:/usr/local/bin'} + >>> AddPathIfNotExists(env, 'PATH', '/opt/bin') + >>> print(env['PATH']) + /opt/bin:/bin:/usr/bin:/usr/local/bin + """ + try: - is_list = 1 + is_list = True paths = env_dict[key] if not is_List(env_dict[key]): paths = paths.split(sep) - is_list = 0 + is_list = False if os.path.normcase(path) not in list(map(os.path.normcase, paths)): paths = [ path ] + paths if is_list: @@ -1011,52 +1130,100 @@ env_dict[key] = path if sys.platform == 'cygwin': - def get_native_path(path): - """Transforms an absolute path into a native path for the system. In - Cygwin, this converts from a Cygwin path to a Windows one.""" - with os.popen('cygpath -w ' + path) as p: - npath = p.read().replace('\n', '') - return npath + import subprocess # pylint: disable=import-outside-toplevel + + def get_native_path(path) -> str: + cp = subprocess.run(('cygpath', '-w', path), check=False, stdout=subprocess.PIPE) + return cp.stdout.decode().replace('\n', '') else: - def get_native_path(path): - """Transforms an absolute path into a native path for the system. - Non-Cygwin version, just leave the path alone.""" + def get_native_path(path) -> str: return path +get_native_path.__doc__ = """\ +Transform an absolute path into a native path for the system. + +In Cygwin, this converts from a Cygwin path to a Windows path, +without regard to whether `path` refers to an existing file +system object. For other platforms, `path` is unchanged. +""" + + display = DisplayEngine() -def Split(arg): +def Split(arg) -> list: + """Returns a list of file names or other objects. + + If `arg` is a string, it will be split on strings of white-space + characters within the string. If `arg` is already a list, the list + will be returned untouched. If `arg` is any other type of object, + it will be returned as a list containing just the object. + + >>> print(Split(" this is a string ")) + ['this', 'is', 'a', 'string'] + >>> print(Split(["stringlist", " preserving ", " spaces "])) + ['stringlist', ' preserving ', ' spaces '] + """ if is_List(arg) or is_Tuple(arg): return arg - elif is_String(arg): + + if is_String(arg): return arg.split() - else: - return [arg] + + return [arg] + class CLVar(UserList): - """A class for command-line construction variables. + """A container for command-line construction variables. - This is a list that uses Split() to split an initial string along - white-space arguments, and similarly to split any strings that get - added. This allows us to Do the Right Thing with Append() and - Prepend() (as well as straight Python foo = env['VAR'] + 'arg1 - arg2') regardless of whether a user adds a list or a string to a - command-line construction variable. + Forces the use of a list of strings intended as command-line + arguments. Like :class:`collections.UserList`, but the argument + passed to the initializter will be processed by the :func:`Split` + function, which includes special handling for string types: they + will be split into a list of words, not coereced directly to a list. + The same happens if a string is added to a :class:`CLVar`, + which allows doing the right thing with both + :func:`Append`/:func:`Prepend` methods, + as well as with pure Python addition, regardless of whether adding + a list or a string to a construction variable. + + Side effect: spaces will be stripped from individual string + arguments. If you need spaces preserved, pass strings containing + spaces inside a list argument. + + >>> u = UserList("--some --opts and args") + >>> print(len(u), repr(u)) + 22 ['-', '-', 's', 'o', 'm', 'e', ' ', '-', '-', 'o', 'p', 't', 's', ' ', 'a', 'n', 'd', ' ', 'a', 'r', 'g', 's'] + >>> c = CLVar("--some --opts and args") + >>> print(len(c), repr(c)) + 4 ['--some', '--opts', 'and', 'args'] + >>> c += " strips spaces " + >>> print(len(c), repr(c)) + 6 ['--some', '--opts', 'and', 'args', 'strips', 'spaces'] """ - def __init__(self, seq = []): - UserList.__init__(self, Split(seq)) + + def __init__(self, initlist=None): + super().__init__(Split(initlist if initlist is not None else [])) + def __add__(self, other): - return UserList.__add__(self, CLVar(other)) + return super().__add__(CLVar(other)) + def __radd__(self, other): - return UserList.__radd__(self, CLVar(other)) + return super().__radd__(CLVar(other)) + + def __iadd__(self, other): + return super().__iadd__(CLVar(other)) + def __str__(self): - return ' '.join(self.data) + # Some cases the data can contain Nodes, so make sure they + # processed to string before handing them over to join. + return ' '.join([str(d) for d in self.data]) class Selector(OrderedDict): """A callable ordered dictionary that maps file suffixes to dictionary values. We preserve the order in which items are added - so that get_suffix() calls always return the first suffix added.""" + so that :func:`get_suffix` calls always return the first suffix added. + """ def __call__(self, env, source, ext=None): if ext is None: try: @@ -1091,39 +1258,58 @@ if sys.platform == 'cygwin': # On Cygwin, os.path.normcase() lies, so just report back the # fact that the underlying Windows OS is case-insensitive. - def case_sensitive_suffixes(s1, s2): - return 0 + def case_sensitive_suffixes(s1, s2) -> bool: # pylint: disable=unused-argument + return False + else: - def case_sensitive_suffixes(s1, s2): - return (os.path.normcase(s1) != os.path.normcase(s2)) + def case_sensitive_suffixes(s1, s2) -> bool: + return os.path.normcase(s1) != os.path.normcase(s2) + + +def adjustixes(fname, pre, suf, ensure_suffix=False) -> str: + """Adjust filename prefixes and suffixes as needed. + + Add `prefix` to `fname` if specified. + Add `suffix` to `fname` if specified and if `ensure_suffix` is ``True`` + """ -def adjustixes(fname, pre, suf, ensure_suffix=False): if pre: path, fn = os.path.split(os.path.normpath(fname)) - if fn[:len(pre)] != pre: + + # Handle the odd case where the filename = the prefix. + # In that case, we still want to add the prefix to the file + if not fn.startswith(pre) or fn == pre: fname = os.path.join(path, pre + fn) # Only append a suffix if the suffix we're going to add isn't already # there, and if either we've been asked to ensure the specific suffix # is present or there's no suffix on it at all. - if suf and fname[-len(suf):] != suf and \ - (ensure_suffix or not splitext(fname)[1]): - fname = fname + suf + # Also handle the odd case where the filename = the suffix. + # in that case we still want to append the suffix + if suf and not fname.endswith(suf) and \ + (ensure_suffix or not splitext(fname)[1]): + fname = fname + suf return fname # 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.) +# Updated. This algorithm is used by some scanners and tools. -def unique(s): - """Return a list of the elements in s, but without duplicates. +def unique(seq): + """Return a list of the elements in seq without duplicates, ignoring order. - For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], - unique("abcabc") some permutation of ["a", "b", "c"], and - unique(([1, 2], [2, 3], [1, 2])) some permutation of - [[2, 3], [1, 2]]. + >>> mylist = unique([1, 2, 3, 1, 2, 3]) + >>> print(sorted(mylist)) + [1, 2, 3] + >>> mylist = unique("abcabc") + >>> print(sorted(mylist)) + ['a', 'b', 'c'] + >>> mylist = unique(([1, 2], [2, 3], [1, 2])) + >>> print(sorted(mylist)) + [[1, 2], [2, 3]] For best speed, all sequence elements should be hashable. Then unique() will usually work in linear time. @@ -1134,41 +1320,33 @@ usually work in O(N*log2(N)) time. If that's not possible either, the sequence elements must support - equality-testing. Then unique() will usually work in quadratic - time. + equality-testing. Then unique() will usually work in quadratic time. """ - n = len(s) - if n == 0: + if not seq: return [] # Try using a dict first, as that's the fastest and will usually # work. If it doesn't work, it will usually fail quickly, so it # usually doesn't cost much to *try* it. It requires that all the # sequence elements be hashable, and support equality comparison. - u = {} - try: - for x in s: - u[x] = 1 - except TypeError: - pass # move on to the next method - else: - return list(u.keys()) - del u - - # We can't hash all the elements. Second fastest is to sort, - # which brings the equal elements together; then duplicates are - # easy to weed out in a single pass. + # TODO: should be even faster: return(list(set(seq))) + with suppress(TypeError): + return list(dict.fromkeys(seq)) + + # We couldn't hash all the elements (got a TypeError). + # Next fastest is to sort, which brings the equal elements together; + # then duplicates are easy to weed out in a single pass. # NOTE: Python's list.sort() was designed to be efficient in the # presence of many duplicate elements. This isn't true of all # sort functions in all languages or libraries, so this approach # is more effective in Python than it may be elsewhere. + n = len(seq) try: - t = sorted(s) + t = sorted(seq) except TypeError: pass # move on to the next method else: - assert n > 0 last = t[0] lasti = i = 1 while i < n: @@ -1177,19 +1355,17 @@ lasti = lasti + 1 i = i + 1 return t[:lasti] - del t # Brute force is all that's left. u = [] - for x in s: + for x in seq: if x not in u: u.append(x) 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.) @@ -1202,28 +1378,27 @@ idfun = default_idfun seen = {} result = [] + result_append = result.append # perf: avoid repeated method lookups for item in seq: marker = idfun(item) - # in old Python versions: - # if seen.has_key(marker) - # but in new ones: - if marker in seen: continue + if marker in seen: + continue seen[marker] = 1 - result.append(item) + result_append(item) return result # A more efficient implementation of Alex's uniquer(), this avoids the # idfun() argument and function-call overhead by assuming that all -# items in the sequence are hashable. +# items in the sequence are hashable. Order-preserving. def uniquer_hashables(seq): seen = {} result = [] + result_append = result.append # perf: avoid repeated method lookups for item in seq: - #if not item in seen: if item not in seen: seen[item] = 1 - result.append(item) + result_append(item) return result @@ -1249,287 +1424,587 @@ class LogicalLines: """ Wrapper class for the logical_lines method. - Allows us to read all "logical" lines at once from a - given file object. + Allows us to read all "logical" lines at once from a given file object. """ def __init__(self, fileobj): self.fileobj = fileobj def readlines(self): - result = [l for l in logical_lines(self.fileobj)] - return result + return list(logical_lines(self.fileobj)) class UniqueList(UserList): - def __init__(self, seq = []): - UserList.__init__(self, seq) + """A list which maintains uniqueness. + + Uniquing is lazy: rather than being assured on list changes, it is fixed + up on access by those methods which need to act on a uniqe list to be + correct. That means things like "in" don't have to eat the uniquing time. + """ + def __init__(self, initlist=None): + super().__init__(initlist) self.unique = True + def __make_unique(self): if not self.unique: self.data = uniquer_hashables(self.data) self.unique = True + + def __repr__(self): + self.__make_unique() + return super().__repr__() + def __lt__(self, other): self.__make_unique() - return UserList.__lt__(self, other) + return super().__lt__(other) + def __le__(self, other): self.__make_unique() - return UserList.__le__(self, other) + return super().__le__(other) + def __eq__(self, other): self.__make_unique() - return UserList.__eq__(self, other) + return super().__eq__(other) + def __ne__(self, other): self.__make_unique() - return UserList.__ne__(self, other) + return super().__ne__(other) + def __gt__(self, other): self.__make_unique() - return UserList.__gt__(self, other) + return super().__gt__(other) + def __ge__(self, other): self.__make_unique() - return UserList.__ge__(self, other) - def __cmp__(self, other): - self.__make_unique() - return UserList.__cmp__(self, other) + return super().__ge__(other) + + # __contains__ doesn't need to worry about uniquing, inherit + def __len__(self): self.__make_unique() - return UserList.__len__(self) + return super().__len__() + def __getitem__(self, i): self.__make_unique() - return UserList.__getitem__(self, i) + return super().__getitem__(i) + def __setitem__(self, i, item): - UserList.__setitem__(self, i, item) - self.unique = False - def __getslice__(self, i, j): - self.__make_unique() - return UserList.__getslice__(self, i, j) - def __setslice__(self, i, j, other): - UserList.__setslice__(self, i, j, other) + super().__setitem__(i, item) self.unique = False + + # __delitem__ doesn't need to worry about uniquing, inherit + def __add__(self, other): - result = UserList.__add__(self, other) + result = super().__add__(other) result.unique = False return result + def __radd__(self, other): - result = UserList.__radd__(self, other) + result = super().__radd__(other) result.unique = False return result + def __iadd__(self, other): - result = UserList.__iadd__(self, other) + result = super().__iadd__(other) result.unique = False return result + def __mul__(self, other): - result = UserList.__mul__(self, other) + result = super().__mul__(other) result.unique = False return result + def __rmul__(self, other): - result = UserList.__rmul__(self, other) + result = super().__rmul__(other) result.unique = False return result + def __imul__(self, other): - result = UserList.__imul__(self, other) + result = super().__imul__(other) result.unique = False return result + def append(self, item): - UserList.append(self, item) + super().append(item) self.unique = False - def insert(self, i): - UserList.insert(self, i) + + def insert(self, i, item): + super().insert(i, item) self.unique = False + def count(self, item): self.__make_unique() - return UserList.count(self, item) - def index(self, item): + return super().count(item) + + def index(self, item, *args): self.__make_unique() - return UserList.index(self, item) + return super().index(item, *args) + def reverse(self): self.__make_unique() - UserList.reverse(self) + super().reverse() + + # TODO: Py3.8: def sort(self, /, *args, **kwds): def sort(self, *args, **kwds): self.__make_unique() - return UserList.sort(self, *args, **kwds) + return super().sort(*args, **kwds) + def extend(self, other): - UserList.extend(self, other) + super().extend(other) self.unique = False class Unbuffered: - """ - A proxy class that wraps a file object, flushing after every write, - and delegating everything else to the wrapped object. + """A proxy that wraps a file object, flushing after every write. + + Delegates everything else to the wrapped object. """ def __init__(self, file): self.file = file - self.softspace = 0 ## backward compatibility; not supported in Py3k + def write(self, arg): - try: + # Stdout might be connected to a pipe that has been closed + # by now. The most likely reason for the pipe being closed + # is that the user has press ctrl-c. It this is the case, + # then SCons is currently shutdown. We therefore ignore + # IOError's here so that SCons can continue and shutdown + # properly so that the .sconsign is correctly written + # before SCons exits. + with suppress(IOError): self.file.write(arg) self.file.flush() - except IOError: - # Stdout might be connected to a pipe that has been closed - # by now. The most likely reason for the pipe being closed - # is that the user has press ctrl-c. It this is the case, - # then SCons is currently shutdown. We therefore ignore - # IOError's here so that SCons can continue and shutdown - # properly so that the .sconsign is correctly written - # before SCons exits. - pass + + def writelines(self, arg): + with suppress(IOError): + self.file.writelines(arg) + self.file.flush() + def __getattr__(self, attr): return getattr(self.file, attr) -def make_path_relative(path): - """ makes an absolute path name to a relative pathname. - """ +def make_path_relative(path) -> str: + """Converts an absolute path name to a relative pathname.""" + if os.path.isabs(path): - drive_s,path = os.path.splitdrive(path) + drive_s, path = os.path.splitdrive(path) - import re if not drive_s: - path=re.compile("/*(.*)").findall(path)[0] + path=re.compile(r"/*(.*)").findall(path)[0] else: path=path[1:] - assert( not os.path.isabs( path ) ), path + assert not os.path.isabs(path), 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. - - Example:: - - a = A() - def f(self, x, y): - self.z = x + y - AddMethod(f, A, "add") - a.add(2, 4) - print(a.z) - AddMethod(lambda self, i: self.l[i], a, "listIndex") - print(a.listIndex(5)) + """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. + + >>> class A: + ... ... + + >>> a = A() + + >>> def f(self, x, y): + ... self.z = x + y + + >>> AddMethod(A, f, "add") + >>> a.add(2, 4) + >>> print(a.z) + 6 + >>> a.data = ['a', 'b', 'c', 'd', 'e', 'f'] + >>> AddMethod(a, lambda self, i: self.data[i], "listIndex") + >>> print(a.listIndex(3)) + d + """ 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): + +# Default hash function and format. SCons-internal. +DEFAULT_HASH_FORMATS = ['md5', 'sha1', 'sha256'] +ALLOWED_HASH_FORMATS = [] +_HASH_FUNCTION = None +_HASH_FORMAT = None + +def _attempt_init_of_python_3_9_hash_object(hash_function_object, sys_used=sys): + """Python 3.9 and onwards lets us initialize the hash function object with the + key "usedforsecurity"=false. This lets us continue to use algorithms that have + been deprecated either by FIPS or by Python itself, as the MD5 algorithm SCons + prefers is not being used for security purposes as much as a short, 32 char + hash that is resistant to accidental collisions. + + In prior versions of python, hashlib returns a native function wrapper, which + errors out when it's queried for the optional parameter, so this function + wraps that call. + + It can still throw a ValueError if the initialization fails due to FIPS + compliance issues, but that is assumed to be the responsibility of the caller. """ - Returns a function identical to the specified function, but with - the specified name. + if hash_function_object is None: + return None + + # https://stackoverflow.com/a/11887885 details how to check versions with the "packaging" library. + # however, for our purposes checking the version is greater than or equal to 3.9 is good enough, as + # the API is guaranteed to have support for the 'usedforsecurity' flag in 3.9. See + # https://docs.python.org/3/library/hashlib.html#:~:text=usedforsecurity for the version support notes. + if (sys_used.version_info.major > 3) or (sys_used.version_info.major == 3 and sys_used.version_info.minor >= 9): + return hash_function_object(usedforsecurity=False) + + # note that this can throw a ValueError in FIPS-enabled versions of Linux prior to 3.9 + # the OpenSSL hashlib will throw on first init here, but that is assumed to be responsibility of + # the caller to diagnose the ValueError & potentially display the error to screen. + return hash_function_object() + +def _set_allowed_viable_default_hashes(hashlib_used, sys_used=sys): + """Checks if SCons has ability to call the default algorithms normally supported. + + This util class is sometimes called prior to setting the user-selected hash algorithm, + meaning that on FIPS-compliant systems the library would default-initialize MD5 + and throw an exception in set_hash_format. A common case is using the SConf options, + which can run prior to main, and thus ignore the options.hash_format variable. + + This function checks the DEFAULT_HASH_FORMATS and sets the ALLOWED_HASH_FORMATS + to only the ones that can be called. In Python >= 3.9 this will always default to + MD5 as in Python 3.9 there is an optional attribute "usedforsecurity" set for the method. + + Throws if no allowed hash formats are detected. + """ + global ALLOWED_HASH_FORMATS + _last_error = None + # note: if you call this method repeatedly, example using timeout, this is needed. + # otherwise it keeps appending valid formats to the string + ALLOWED_HASH_FORMATS = [] + + for test_algorithm in DEFAULT_HASH_FORMATS: + _test_hash = getattr(hashlib_used, test_algorithm, None) + # we know hashlib claims to support it... check to see if we can call it. + if _test_hash is not None: + # the hashing library will throw an exception on initialization in FIPS mode, + # meaning if we call the default algorithm returned with no parameters, it'll + # throw if it's a bad algorithm, otherwise it will append it to the known + # good formats. + try: + _attempt_init_of_python_3_9_hash_object(_test_hash, sys_used) + ALLOWED_HASH_FORMATS.append(test_algorithm) + except ValueError as e: + _last_error = e + continue + + if len(ALLOWED_HASH_FORMATS) == 0: + from SCons.Errors import SConsEnvironmentError # pylint: disable=import-outside-toplevel + # chain the exception thrown with the most recent error from hashlib. + raise SConsEnvironmentError( + 'No usable hash algorithms found.' + 'Most recent error from hashlib attached in trace.' + ) from _last_error + return + +_set_allowed_viable_default_hashes(hashlib) + + +def get_hash_format(): + """Retrieves the hash format or ``None`` if not overridden. + + A return value of ``None`` + does not guarantee that MD5 is being used; instead, it means that the + default precedence order documented in :func:`SCons.Util.set_hash_format` + is respected. """ - return FunctionType(function.__code__, - function.__globals__, - name, - function.__defaults__) + return _HASH_FORMAT +def _attempt_get_hash_function(hash_name, hashlib_used=hashlib, sys_used=sys): + """Wrapper used to try to initialize a hash function given. -if hasattr(hashlib, 'md5'): - md5 = True + If successful, returns the name of the hash function back to the user. - def MD5signature(s): - """ - Generate md5 signature of a string + Otherwise returns None. + """ + try: + _fetch_hash = getattr(hashlib_used, hash_name, None) + if _fetch_hash is None: + return None + _attempt_init_of_python_3_9_hash_object(_fetch_hash, sys_used) + return hash_name + except ValueError: + # if attempt_init_of_python_3_9 throws, this is typically due to FIPS being enabled + # however, if we get to this point, the viable hash function check has either been + # bypassed or otherwise failed to properly restrict the user to only the supported + # functions. As such throw the UserError as an internal assertion-like error. + return None - :param s: either string or bytes. Normally should be bytes - :return: String of hex digits representing the signature - """ - m = hashlib.md5() +def set_hash_format(hash_format, hashlib_used=hashlib, sys_used=sys): + """Sets the default hash format used by SCons. - try: - m.update(to_bytes(s)) - except TypeError as e: - m.update(to_bytes(str(s))) + If `hash_format` is ``None`` or + an empty string, the default is determined by this function. - return m.hexdigest() + Currently the default behavior is to use the first available format of + the following options: MD5, SHA1, SHA256. + """ + global _HASH_FORMAT, _HASH_FUNCTION + + _HASH_FORMAT = hash_format + if hash_format: + hash_format_lower = hash_format.lower() + if hash_format_lower not in ALLOWED_HASH_FORMATS: + from SCons.Errors import UserError # pylint: disable=import-outside-toplevel + + # user can select something not supported by their OS but normally supported by + # SCons, example, selecting MD5 in an OS with FIPS-mode turned on. Therefore we first + # check if SCons supports it, and then if their local OS supports it. + if hash_format_lower in DEFAULT_HASH_FORMATS: + raise UserError('While hash format "%s" is supported by SCons, the ' + 'local system indicates only the following hash ' + 'formats are supported by the hashlib library: %s' % + (hash_format_lower, + ', '.join(ALLOWED_HASH_FORMATS)) + ) + else: + # the hash format isn't supported by SCons in any case. Warn the user, and + # if we detect that SCons supports more algorithms than their local system + # supports, warn the user about that too. + if ALLOWED_HASH_FORMATS == DEFAULT_HASH_FORMATS: + raise UserError('Hash format "%s" is not supported by SCons. Only ' + 'the following hash formats are supported: %s' % + (hash_format_lower, + ', '.join(ALLOWED_HASH_FORMATS)) + ) + else: + raise UserError('Hash format "%s" is not supported by SCons. ' + 'SCons supports more hash formats than your local system ' + 'is reporting; SCons supports: %s. Your local system only ' + 'supports: %s' % + (hash_format_lower, + ', '.join(DEFAULT_HASH_FORMATS), + ', '.join(ALLOWED_HASH_FORMATS)) + ) + + # this is not expected to fail. If this fails it means the set_allowed_viable_default_hashes + # function did not throw, or when it threw, the exception was caught and ignored, or + # the global ALLOWED_HASH_FORMATS was changed by an external user. + _HASH_FUNCTION = _attempt_get_hash_function(hash_format_lower, hashlib_used, sys_used) + + if _HASH_FUNCTION is None: + from SCons.Errors import UserError # pylint: disable=import-outside-toplevel + + raise UserError( + 'Hash format "%s" is not available in your Python interpreter. ' + 'Expected to be supported algorithm by set_allowed_viable_default_hashes, ' + 'Assertion error in SCons.' + % hash_format_lower + ) + else: + # Set the default hash format based on what is available, defaulting + # to the first supported hash algorithm (usually md5) for backwards compatibility. + # in FIPS-compliant systems this usually defaults to SHA1, unless that too has been + # disabled. + for choice in ALLOWED_HASH_FORMATS: + _HASH_FUNCTION = _attempt_get_hash_function(choice, hashlib_used, sys_used) - def MD5filesignature(fname, chunksize=65536): - """ - Generate the md5 signature of a file + if _HASH_FUNCTION is not None: + break + else: + # This is not expected to happen in practice. + from SCons.Errors import UserError # pylint: disable=import-outside-toplevel - :param fname: file to hash - :param chunksize: chunk size to read - :return: String of Hex digits representing the signature - """ - m = hashlib.md5() - with open(fname, "rb") as f: - while True: - blck = f.read(chunksize) - if not blck: - break - m.update(to_bytes(blck)) - return m.hexdigest() -else: - # if md5 algorithm not available, just return data unmodified - # could add alternative signature scheme here - md5 = False - - def MD5signature(s): - return str(s) - - def MD5filesignature(fname, chunksize=65536): - with open(fname, "rb") as f: - result = f.read() - return result + raise UserError( + 'Your Python interpreter does not have MD5, SHA1, or SHA256. ' + 'SCons requires at least one. Expected to support one or more ' + 'during set_allowed_viable_default_hashes.' + ) +# Ensure that this is initialized in case either: +# 1. This code is running in a unit test. +# 2. This code is running in a consumer that does hash operations while +# SConscript files are being loaded. +set_hash_format(None) -def MD5collect(signatures): + +def get_current_hash_algorithm_used(): + """Returns the current hash algorithm name used. + + Where the python version >= 3.9, this is expected to return md5. + If python's version is <= 3.8, this returns md5 on non-FIPS-mode platforms, and + sha1 or sha256 on FIPS-mode Linux platforms. + + This function is primarily useful for testing, where one expects a value to be + one of N distinct hashes, and therefore the test needs to know which hash to select. + """ + return _HASH_FUNCTION + +def _get_hash_object(hash_format, hashlib_used=hashlib, sys_used=sys): + """Allocates a hash object using the requested hash format. + + Args: + hash_format: Hash format to use. + + Returns: + hashlib object. + """ + if hash_format is None: + if _HASH_FUNCTION is None: + from SCons.Errors import UserError # pylint: disable=import-outside-toplevel + + raise UserError('There is no default hash function. Did you call ' + 'a hashing function before SCons was initialized?') + return _attempt_init_of_python_3_9_hash_object(getattr(hashlib_used, _HASH_FUNCTION, None), sys_used) + + if not hasattr(hashlib, hash_format): + from SCons.Errors import UserError # pylint: disable=import-outside-toplevel + + raise UserError( + 'Hash format "%s" is not available in your Python interpreter.' % + hash_format) + + return _attempt_init_of_python_3_9_hash_object(getattr(hashlib, hash_format), sys_used) + + +def hash_signature(s, hash_format=None): + """ + Generate hash signature of a string + + Args: + s: either string or bytes. Normally should be bytes + hash_format: Specify to override default hash format + + Returns: + String of hex digits representing the signature + """ + m = _get_hash_object(hash_format) + try: + m.update(to_bytes(s)) + except TypeError: + m.update(to_bytes(str(s))) + + return m.hexdigest() + + +def hash_file_signature(fname, chunksize=65536, hash_format=None): + """ + Generate the md5 signature of a file + + Args: + fname: file to hash + chunksize: chunk size to read + hash_format: Specify to override default hash format + + Returns: + String of Hex digits representing the signature + """ + + m = _get_hash_object(hash_format) + with open(fname, "rb") as f: + while True: + blck = f.read(chunksize) + if not blck: + break + m.update(to_bytes(blck)) + return m.hexdigest() + + +def hash_collect(signatures, hash_format=None): """ Collects a list of signatures into an aggregate signature. - signatures - a list of signatures - returns - the aggregate signature + Args: + signatures: a list of signatures + hash_format: Specify to override default hash format + + Returns: + the aggregate signature """ + if len(signatures) == 1: return signatures[0] - else: - return MD5signature(', '.join(signatures)) + + return hash_signature(', '.join(signatures), hash_format) + + +_MD5_WARNING_SHOWN = False + +def _show_md5_warning(function_name): + """Shows a deprecation warning for various MD5 functions.""" + + global _MD5_WARNING_SHOWN + + if not _MD5_WARNING_SHOWN: + import SCons.Warnings # pylint: disable=import-outside-toplevel + + SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, + "Function %s is deprecated" % function_name) + _MD5_WARNING_SHOWN = True + + +def MD5signature(s): + """Deprecated. Use :func:`hash_signature` instead.""" + + _show_md5_warning("MD5signature") + return hash_signature(s) + + +def MD5filesignature(fname, chunksize=65536): + """Deprecated. Use :func:`hash_file_signature` instead.""" + + _show_md5_warning("MD5filesignature") + return hash_file_signature(fname, chunksize) + + +def MD5collect(signatures): + """Deprecated. Use :func:`hash_collect` instead.""" + + _show_md5_warning("MD5collect") + return hash_collect(signatures) def silent_intern(x): """ - Perform sys.intern() on the passed argument and return the result. - If the input is ineligible the original argument is + Perform :mod:`sys.intern` on the passed argument and return the result. + If the input is ineligible for interning the original argument is returned and no exception is thrown. """ try: @@ -1540,8 +2015,7 @@ # 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: @@ -1556,8 +2030,6 @@ return self def __repr__(self): return "Null(0x%08X)" % id(self) - def __nonzero__(self): - return False def __bool__(self): return False def __getattr__(self, name): @@ -1582,10 +2054,7 @@ return self -del __revision__ - - -def to_bytes(s): +def to_bytes(s) -> bytes: if s is None: return b'None' if isinstance(s, (bytes, bytearray)): @@ -1594,7 +2063,7 @@ return bytes(s, 'utf-8') -def to_str(s): +def to_str(s) -> str: if s is None: return 'None' if is_String(s): @@ -1602,30 +2071,28 @@ return str(s, 'utf-8') -def cmp(a, b): - """ - Define cmp because it's no longer available in python3 - Works under python 2 as well - """ +def cmp(a, b) -> bool: + """A cmp function because one is no longer available in python3.""" return (a > b) - (a < b) -def get_env_bool(env, name, default=False): +def get_env_bool(env, name, default=False) -> bool: """Convert a construction variable to bool. - If the value of *name* in *env* is 'true', 'yes', 'y', 'on' (case + If the value of `name` in `env` is 'true', 'yes', 'y', 'on' (case insensitive) or anything convertible to int that yields non-zero then - return True; if 'false', 'no', 'n', 'off' (case insensitive) - or a number that converts to integer zero return False. - Otherwise, return *default*. + return ``True``; if 'false', 'no', 'n', 'off' (case insensitive) + or a number that converts to integer zero return ``False``. + Otherwise, return `default`. Args: env: construction environment, or any dict-like object name: name of the variable - default: value to return if *name* not in *env* or cannot + default: value to return if `name` not in `env` or cannot be converted (default: False) + Returns: - bool: the "truthiness" of *name* + the "truthiness" of `name` """ try: var = env[name] @@ -1636,19 +2103,62 @@ except ValueError: if str(var).lower() in ('true', 'yes', 'y', 'on'): return True - elif str(var).lower() in ('false', 'no', 'n', 'off'): + + if str(var).lower() in ('false', 'no', 'n', 'off'): return False - else: - return default + + return default -def get_os_env_bool(name, default=False): +def get_os_env_bool(name, default=False) -> bool: """Convert an environment variable to bool. Conversion is the same as for :func:`get_env_bool`. """ return get_env_bool(os.environ, name, default) + +def print_time(): + """Hack to return a value from Main if can't import Main.""" + # pylint: disable=redefined-outer-name,import-outside-toplevel + from SCons.Script.Main import print_time + return print_time + + +def wait_for_process_to_die(pid): + """ + Wait for specified process to die, or alternatively kill it + NOTE: This function operates best with psutil pypi package + TODO: Add timeout which raises exception + """ + # wait for the process to fully killed + try: + import psutil + while True: + if pid not in [proc.pid for proc in psutil.process_iter()]: + break + else: + time.sleep(0.1) + except ImportError: + # if psutil is not installed we can do this the hard way + while True: + if sys.platform == 'win32': + import ctypes + PROCESS_QUERY_INFORMATION = 0x1000 + processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, 0,pid) + if processHandle == 0: + break + else: + ctypes.windll.kernel32.CloseHandle(processHandle) + time.sleep(0.1) + else: + try: + os.kill(pid, 0) + except OSError: + break + else: + time.sleep(0.1) + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/SCons/UtilTests.py scons-4.4.0+dfsg/SCons/UtilTests.py --- scons-4.0.1+dfsg/SCons/UtilTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/UtilTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,23 +20,66 @@ # 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 functools import io import os import sys import unittest -from collections import UserDict, UserList, UserString +import unittest.mock +import hashlib +import warnings +from collections import UserDict, UserList, UserString, namedtuple import TestCmd import SCons.Errors +import SCons.compat +from SCons.Util import ( + ALLOWED_HASH_FORMATS, + AddPathIfNotExists, + AppendPath, + CLVar, + LogicalLines, + NodeList, + PrependPath, + Proxy, + Selector, + WhereIs, + _attempt_init_of_python_3_9_hash_object, + _attempt_get_hash_function, + _get_hash_object, + _set_allowed_viable_default_hashes, + adjustixes, + containsAll, + containsAny, + containsOnly, + dictify, + display, + flatten, + get_env_bool, + get_environment_var, + get_native_path, + get_os_env_bool, + hash_collect, + hash_signature, + is_Dict, + is_List, + is_String, + is_Tuple, + print_tree, + render_tree, + set_hash_format, + silent_intern, + splitext, + to_String, + to_bytes, + to_str, +) + +# These Util classes have no unit tests. Some don't make sense to test? +# DisplayEngine, Delegate, MethodWrapper, UniqueList, Unbuffered, Null, NullSeq -from SCons.Util import * class OutBuffer: def __init__(self): @@ -48,13 +92,13 @@ class dictifyTestCase(unittest.TestCase): def test_dictify(self): """Test the dictify() function""" - r = SCons.Util.dictify(['a', 'b', 'c'], [1, 2, 3]) + r = dictify(['a', 'b', 'c'], [1, 2, 3]) assert r == {'a': 1, 'b': 2, 'c': 3}, r r = {} - SCons.Util.dictify(['a'], [1], r) - SCons.Util.dictify(['b'], [2], r) - SCons.Util.dictify(['c'], [3], r) + dictify(['a'], [1], r) + dictify(['b'], [2], r) + dictify(['c'], [3], r) assert r == {'a': 1, 'b': 2, 'c': 3}, r @@ -195,11 +239,7 @@ 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() @@ -251,11 +291,6 @@ 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 @@ -499,10 +534,16 @@ # have to include the pathsep here so that the test will work on UNIX too. p1 = PrependPath(p1, r'C:\dir\num\two', sep=';') p1 = PrependPath(p1, r'C:\dir\num\three', sep=';') + assert p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one', p1 + p2 = PrependPath(p2, r'C:\mydir\num\three', sep=';') p2 = PrependPath(p2, r'C:\mydir\num\one', sep=';') - assert (p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one') - assert (p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two') + assert p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two', p2 + + # check (only) first one is kept if there are dupes in new + p3 = r'C:\dir\num\one' + p3 = PrependPath(p3, r'C:\dir\num\two;C:\dir\num\three;C:\dir\num\two', sep=';') + assert p3 == r'C:\dir\num\two;C:\dir\num\three;C:\dir\num\one', p3 def test_AppendPath(self): """Test appending to a path.""" @@ -511,10 +552,16 @@ # have to include the pathsep here so that the test will work on UNIX too. p1 = AppendPath(p1, r'C:\dir\num\two', sep=';') p1 = AppendPath(p1, r'C:\dir\num\three', sep=';') + assert p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three', p1 + p2 = AppendPath(p2, r'C:\mydir\num\three', sep=';') p2 = AppendPath(p2, r'C:\mydir\num\one', sep=';') - assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three') - assert (p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one') + assert p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one', p2 + + # check (only) last one is kept if there are dupes in new + p3 = r'C:\dir\num\one' + p3 = AppendPath(p3, r'C:\dir\num\two;C:\dir\num\three;C:\dir\num\two', sep=';') + assert p3 == r'C:\dir\num\one;C:\dir\num\three;C:\dir\num\two', p3 def test_PrependPathPreserveOld(self): """Test prepending to a path while preserving old paths""" @@ -522,7 +569,7 @@ # have to include the pathsep here so that the test will work on UNIX too. p1 = PrependPath(p1, r'C:\dir\num\two', sep=';', delete_existing=0) p1 = PrependPath(p1, r'C:\dir\num\three', sep=';') - assert (p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two') + assert p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two', p1 def test_AppendPathPreserveOld(self): """Test appending to a path while preserving old paths""" @@ -530,7 +577,7 @@ # have to include the pathsep here so that the test will work on UNIX too. p1 = AppendPath(p1, r'C:\dir\num\one', sep=';', delete_existing=0) p1 = AppendPath(p1, r'C:\dir\num\three', sep=';') - assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three') + assert p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three', p1 def test_addPathIfNotExists(self): """Test the AddPathIfNotExists() function""" @@ -558,101 +605,126 @@ def test_CLVar(self): """Test the command-line construction variable class""" - f = SCons.Util.CLVar('a b') - r = f + 'c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ' c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', ' c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', ' c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - f = SCons.Util.CLVar(['a b']) - - r = f + 'c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ' c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', 'c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', ' c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a b', ' c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - f = SCons.Util.CLVar(['a', 'b']) - - r = f + 'c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ' c d' - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c d'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', ' c d'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + ['c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', 'c', 'd'], r.data - assert str(r) == 'a b c d', str(r) - - r = f + [' c', 'd'] - assert isinstance(r, SCons.Util.CLVar), type(r) - assert r.data == ['a', 'b', ' c', 'd'], r.data - assert str(r) == 'a b c d', str(r) + # the default value should be an empty list + d = CLVar() + assert isinstance(d, CLVar), type(d) + assert d.data == [], d.data + assert str(d) == '', str(d) + + # input to CLVar is a string - should be split + f = CLVar('aa bb') + + r = f + 'cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ' cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', ' cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', ' cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + # input to CLVar is a list of one string, should not be split + f = CLVar(['aa bb']) + + r = f + 'cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ' cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', 'cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', ' cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa bb', ' cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + # input to CLVar is a list of strings + f = CLVar(['aa', 'bb']) + + r = f + 'cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ' cc dd' + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', ' cc dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + ['cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', 'cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + r = f + [' cc', 'dd'] + assert isinstance(r, CLVar), type(r) + assert r.data == ['aa', 'bb', ' cc', 'dd'], r.data + assert str(r) == 'aa bb cc dd', str(r) + + # make sure inplace adding a string works as well (issue 2399) + # UserList would convert the string to a list of chars + f = CLVar(['aa', 'bb']) + f += 'cc dd' + assert isinstance(f, CLVar), type(f) + assert f.data == ['aa', 'bb', 'cc', 'dd'], f.data + assert str(f) == 'aa bb cc dd', str(f) + + f = CLVar(['aa', 'bb']) + f += ' cc dd' + assert isinstance(f, CLVar), type(f) + assert f.data == ['aa', 'bb', 'cc', 'dd'], f.data + assert str(f) == 'aa bb cc dd', str(f) + def test_Selector(self): """Test the Selector class""" @@ -723,6 +795,11 @@ r = adjustixes('dir/file', 'pre-', '-suf') assert r == os.path.join('dir', 'pre-file-suf'), r + # Verify that the odd case when library name is specified as 'lib' + # doesn't yield lib.so, but yields the expected liblib.so + r = adjustixes('PREFIX', 'PREFIX', 'SUFFIX') + assert r == 'PREFIXPREFIXSUFFIX', "Failed handling when filename = PREFIX [r='%s']" % r + def test_containsAny(self): """Test the containsAny() function""" assert containsAny('*.py', '*?[]') @@ -766,24 +843,200 @@ assert id(s1) == id(s4) -class MD5TestCase(unittest.TestCase): +class HashTestCase(unittest.TestCase): def test_collect(self): """Test collecting a list of signatures into a new signature value """ - s = list(map(MD5signature, ('111', '222', '333'))) + for algorithm, expected in { + 'md5': ('698d51a19d8a121ce581499d7b701668', + '8980c988edc2c78cc43ccb718c06efd5', + '53fd88c84ff8a285eb6e0a687e55b8c7'), + 'sha1': ('6216f8a75fd5bb3d5f22b6f9958cdede3fc086c2', + '42eda1b5dcb3586bccfb1c69f22f923145271d97', + '2eb2f7be4e883ebe52034281d818c91e1cf16256'), + 'sha256': ('f6e0a1e2ac41945a9aa7ff8a8aaa0cebc12a3bcc981a929ad5cf810a090e11ae', + '25235f0fcab8767b7b5ac6568786fbc4f7d5d83468f0626bf07c3dbeed391a7a', + 'f8d3d0729bf2427e2e81007588356332e7e8c4133fae4bceb173b93f33411d17'), + }.items(): + # if the current platform does not support the algorithm we're looking at, + # skip the test steps for that algorithm, but display a warning to the user + if algorithm not in ALLOWED_HASH_FORMATS: + warnings.warn("Missing hash algorithm {} on this platform, cannot test with it".format(algorithm), ResourceWarning) + else: + hs = functools.partial(hash_signature, hash_format=algorithm) + s = list(map(hs, ('111', '222', '333'))) - assert '698d51a19d8a121ce581499d7b701668' == MD5collect(s[0:1]) - assert '8980c988edc2c78cc43ccb718c06efd5' == MD5collect(s[0:2]) - assert '53fd88c84ff8a285eb6e0a687e55b8c7' == MD5collect(s) + assert expected[0] == hash_collect(s[0:1], hash_format=algorithm) + assert expected[1] == hash_collect(s[0:2], hash_format=algorithm) + assert expected[2] == hash_collect(s, hash_format=algorithm) def test_MD5signature(self): """Test generating a signature""" - s = MD5signature('111') - assert '698d51a19d8a121ce581499d7b701668' == s, s + for algorithm, expected in { + 'md5': ('698d51a19d8a121ce581499d7b701668', + 'bcbe3365e6ac95ea2c0343a2395834dd'), + 'sha1': ('6216f8a75fd5bb3d5f22b6f9958cdede3fc086c2', + '1c6637a8f2e1f75e06ff9984894d6bd16a3a36a9'), + 'sha256': ('f6e0a1e2ac41945a9aa7ff8a8aaa0cebc12a3bcc981a929ad5cf810a090e11ae', + '9b871512327c09ce91dd649b3f96a63b7408ef267c8cc5710114e629730cb61f'), + }.items(): + # if the current platform does not support the algorithm we're looking at, + # skip the test steps for that algorithm, but display a warning to the user + if algorithm not in ALLOWED_HASH_FORMATS: + warnings.warn("Missing hash algorithm {} on this platform, cannot test with it".format(algorithm), ResourceWarning) + else: + s = hash_signature('111', hash_format=algorithm) + assert expected[0] == s, s + + s = hash_signature('222', hash_format=algorithm) + assert expected[1] == s, s - s = MD5signature('222') - assert 'bcbe3365e6ac95ea2c0343a2395834dd' == s, s +# this uses mocking out, which is platform specific, however, the FIPS +# behavior this is testing is also platform-specific, and only would be +# visible in hosts running Linux with the fips_mode kernel flag along +# with using OpenSSL. + +class FIPSHashTestCase(unittest.TestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + ############################### + # algorithm mocks, can check if we called with usedforsecurity=False for python >= 3.9 + self.fake_md5=lambda usedforsecurity=True: (usedforsecurity, 'md5') + self.fake_sha1=lambda usedforsecurity=True: (usedforsecurity, 'sha1') + self.fake_sha256=lambda usedforsecurity=True: (usedforsecurity, 'sha256') + ############################### + + ############################### + # hashlib mocks + md5Available = unittest.mock.Mock(md5=self.fake_md5) + del md5Available.sha1 + del md5Available.sha256 + self.md5Available=md5Available + + md5Default = unittest.mock.Mock(md5=self.fake_md5, sha1=self.fake_sha1) + del md5Default.sha256 + self.md5Default=md5Default + + sha1Default = unittest.mock.Mock(sha1=self.fake_sha1, sha256=self.fake_sha256) + del sha1Default.md5 + self.sha1Default=sha1Default + + sha256Default = unittest.mock.Mock(sha256=self.fake_sha256, **{'md5.side_effect': ValueError, 'sha1.side_effect': ValueError}) + self.sha256Default=sha256Default + + all_throw = unittest.mock.Mock(**{'md5.side_effect': ValueError, 'sha1.side_effect': ValueError, 'sha256.side_effect': ValueError}) + self.all_throw=all_throw + + no_algorithms = unittest.mock.Mock() + del no_algorithms.md5 + del no_algorithms.sha1 + del no_algorithms.sha256 + del no_algorithms.nonexist + self.no_algorithms=no_algorithms + + unsupported_algorithm = unittest.mock.Mock(unsupported=self.fake_sha256) + del unsupported_algorithm.md5 + del unsupported_algorithm.sha1 + del unsupported_algorithm.sha256 + del unsupported_algorithm.unsupported + self.unsupported_algorithm=unsupported_algorithm + ############################### + + ############################### + # system version mocks + VersionInfo = namedtuple('VersionInfo', 'major minor micro releaselevel serial') + v3_8 = VersionInfo(3, 8, 199, 'super-beta', 1337) + v3_9 = VersionInfo(3, 9, 0, 'alpha', 0) + v4_8 = VersionInfo(4, 8, 0, 'final', 0) + + self.sys_v3_8 = unittest.mock.Mock(version_info=v3_8) + self.sys_v3_9 = unittest.mock.Mock(version_info=v3_9) + self.sys_v4_8 = unittest.mock.Mock(version_info=v4_8) + ############################### + + def test_basic_failover_bad_hashlib_hash_init(self): + """Tests that if the hashing function is entirely missing from hashlib (hashlib returns None), + the hash init function returns None""" + assert _attempt_init_of_python_3_9_hash_object(None) is None + + def test_basic_failover_bad_hashlib_hash_get(self): + """Tests that if the hashing function is entirely missing from hashlib (hashlib returns None), + the hash get function returns None""" + assert _attempt_get_hash_function("nonexist", self.no_algorithms) is None + + def test_usedforsecurity_flag_behavior(self): + """Test usedforsecurity flag -> should be set to 'True' on older versions of python, and 'False' on Python >= 3.9""" + for version, expected in { + self.sys_v3_8: (True, 'md5'), + self.sys_v3_9: (False, 'md5'), + self.sys_v4_8: (False, 'md5'), + }.items(): + assert _attempt_init_of_python_3_9_hash_object(self.fake_md5, version) == expected + + def test_automatic_default_to_md5(self): + """Test automatic default to md5 even if sha1 available""" + for version, expected in { + self.sys_v3_8: (True, 'md5'), + self.sys_v3_9: (False, 'md5'), + self.sys_v4_8: (False, 'md5'), + }.items(): + _set_allowed_viable_default_hashes(self.md5Default, version) + set_hash_format(None, self.md5Default, version) + assert _get_hash_object(None, self.md5Default, version) == expected + + def test_automatic_default_to_sha256(self): + """Test automatic default to sha256 if other algorithms available but throw""" + for version, expected in { + self.sys_v3_8: (True, 'sha256'), + self.sys_v3_9: (False, 'sha256'), + self.sys_v4_8: (False, 'sha256'), + }.items(): + _set_allowed_viable_default_hashes(self.sha256Default, version) + set_hash_format(None, self.sha256Default, version) + assert _get_hash_object(None, self.sha256Default, version) == expected + + def test_automatic_default_to_sha1(self): + """Test automatic default to sha1 if md5 is missing from hashlib entirely""" + for version, expected in { + self.sys_v3_8: (True, 'sha1'), + self.sys_v3_9: (False, 'sha1'), + self.sys_v4_8: (False, 'sha1'), + }.items(): + _set_allowed_viable_default_hashes(self.sha1Default, version) + set_hash_format(None, self.sha1Default, version) + assert _get_hash_object(None, self.sha1Default, version) == expected + + def test_no_available_algorithms(self): + """expect exceptions on no available algorithms or when all algorithms throw""" + self.assertRaises(SCons.Errors.SConsEnvironmentError, _set_allowed_viable_default_hashes, self.no_algorithms) + self.assertRaises(SCons.Errors.SConsEnvironmentError, _set_allowed_viable_default_hashes, self.all_throw) + self.assertRaises(SCons.Errors.SConsEnvironmentError, _set_allowed_viable_default_hashes, self.unsupported_algorithm) + + def test_bad_algorithm_set_attempt(self): + """expect exceptions on user setting an unsupported algorithm selections, either by host or by SCons""" + + # nonexistant hash algorithm, not supported by SCons + _set_allowed_viable_default_hashes(self.md5Available) + self.assertRaises(SCons.Errors.UserError, set_hash_format, 'blah blah blah', hashlib_used=self.no_algorithms) + + # md5 is default-allowed, but in this case throws when we attempt to use it + _set_allowed_viable_default_hashes(self.md5Available) + self.assertRaises(SCons.Errors.UserError, set_hash_format, 'md5', hashlib_used=self.all_throw) + + # user attempts to use an algorithm that isn't supported by their current system but is supported by SCons + _set_allowed_viable_default_hashes(self.sha1Default) + self.assertRaises(SCons.Errors.UserError, set_hash_format, 'md5', hashlib_used=self.all_throw) + + # user attempts to use an algorithm that is supported by their current system but isn't supported by SCons + _set_allowed_viable_default_hashes(self.sha1Default) + self.assertRaises(SCons.Errors.UserError, set_hash_format, 'unsupported', hashlib_used=self.unsupported_algorithm) + + def tearDown(self): + """Return SCons back to the normal global state for the hashing functions.""" + _set_allowed_viable_default_hashes(hashlib, sys) + set_hash_format(None) class NodeListTestCase(unittest.TestCase): diff -Nru scons-4.0.1+dfsg/SCons/Variables/BoolVariable.py scons-4.4.0+dfsg/SCons/Variables/BoolVariable.py --- scons-4.0.1+dfsg/SCons/Variables/BoolVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/BoolVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,55 +20,74 @@ # 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__" +"""Variable type for true/false Variables. -__all__ = ['BoolVariable',] +Usage example:: + + opts = Variables() + opts.Add(BoolVariable('embedded', 'build for an embedded system', 0)) + ... + if env['embedded'] == 1: + ... +""" + +from typing import Tuple, Callable import SCons.Errors -__true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' ) -__false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none') +__all__ = ['BoolVariable',] +TRUE_STRINGS = ('y', 'yes', 'true', 't', '1', 'on' , 'all') +FALSE_STRINGS = ('n', 'no', 'false', 'f', '0', 'off', 'none') -def _text2bool(val): - """ - Converts strings to True/False depending on the 'truth' expressed by - the string. If the string can't be converted, the original value - will be returned. - See '__true_strings' and '__false_strings' for values considered - 'true' or 'false respectively. +def _text2bool(val) -> bool: + """Converts strings to True/False. - This is usable as 'converter' for SCons' Variables. + If *val* looks like it expresses a bool-like value, based on + the :data:`TRUE_STRINGS` and :data:`FALSE_STRINGS` tuples, + return the appropriate value. + + This is usable as a converter function for SCons Variables. + + Raises: + ValueError: if the string cannot be converted. """ + lval = val.lower() - if lval in __true_strings: return True - if lval in __false_strings: return False + if lval in TRUE_STRINGS: + return True + if lval in FALSE_STRINGS: + return False raise ValueError("Invalid value for boolean option: %s" % val) -def _validator(key, val, env): - """ - Validates the given value to be either '0' or '1'. - - This is usable as 'validator' for SCons' Variables. +def _validator(key, val, env) -> None: + """Validates the given value to be either true or false. + + This is usable as a validator function for SCons Variables. + + Raises: + KeyError: if key is not set in env + UserError: if key does not validate. """ if not env[key] in (True, False): raise SCons.Errors.UserError( - 'Invalid value for boolean option %s: %s' % (key, env[key])) + 'Invalid value for boolean option %s: %s' % (key, env[key]) + ) -def BoolVariable(key, help, default): - """ - The input parameters describe a boolean option, thus they are - returned with the correct converter and validator appended. The - 'help' text will by appended by '(yes|no) to show the valid - valued. The result is usable for input to opts.Add(). +def BoolVariable(key, help, default) -> Tuple[str, str, str, Callable, Callable]: + """Return a tuple describing a boolean SCons Variable. + + The input parameters describe a boolean option. Returns a tuple + including the correct converter and validator. + The *help* text will have ``(yes|no)`` automatically appended to show the + valid values. The result is usable as input to :meth:`Add`. """ - return (key, '%s (yes|no)' % help, default, - _validator, _text2bool) + help = '%s (yes|no)' % help + return (key, help, default, _validator, _text2bool) # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Variables/BoolVariableTests.py scons-4.4.0+dfsg/SCons/Variables/BoolVariableTests.py --- scons-4.0.1+dfsg/SCons/Variables/BoolVariableTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/BoolVariableTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Variables/EnumVariable.py scons-4.4.0+dfsg/SCons/Variables/EnumVariable.py --- scons-4.0.1+dfsg/SCons/Variables/EnumVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/EnumVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,51 +20,75 @@ # 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__" +"""Variable type for enumeration Variables. -__all__ = ['EnumVariable',] +Enumeration variables allow selection of one from a specified set of values. + +Usage example:: + + opts = Variables() + opts.Add( + EnumVariable( + 'debug', + help='debug output and symbols', + default='no', + allowed_values=('yes', 'no', 'full'), + map={}, + ignorecase=2, + ) + ) + ... + if env['debug'] == 'full': + ... +""" +from typing import Tuple, Callable import SCons.Errors -def _validator(key, val, env, vals): +__all__ = ['EnumVariable',] + + +def _validator(key, val, env, vals) -> None: if val not in vals: raise SCons.Errors.UserError( 'Invalid value for option %s: %s. Valid values are: %s' % (key, val, vals)) -def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0): - """ +def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0) -> Tuple[str, str, str, Callable, Callable]: + """Return a tuple describing an enumaration SCons Variable. + The input parameters describe an option with only certain values - allowed. They are returned with an appropriate converter and - validator appended. The result is usable for input to - Variables.Add(). + allowed. Returns A tuple including an appropriate converter and + validator. The result is usable as input to :meth:`Add`. - 'key' and 'default' are the values to be passed on to Variables.Add(). + *key* and *default* are passed directly on to :meth:`Add`. - 'help' will be appended by the allowed values automatically + *help* is the descriptive part of the help text, + and will have the allowed values automatically appended. - 'allowed_values' is a list of strings, which are allowed as values + *allowed_values* is a list of strings, which are the allowed values for this option. - The 'map'-dictionary may be used for converting the input value + The *map*-dictionary may be used for converting the input value into canonical values (e.g. for aliases). - 'ignorecase' defines the behaviour of the validator: - - If ignorecase == 0, the validator/converter are case-sensitive. - If ignorecase == 1, the validator/converter are case-insensitive. - If ignorecase == 2, the validator/converter is case-insensitive and the converted value will always be lower-case. + The value of *ignorecase* defines the behaviour of the validator: - The 'validator' tests whether the value is in the list of allowed values. The 'converter' converts input values - according to the given 'map'-dictionary (unmapped input values are returned unchanged). + * 0: the validator/converter are case-sensitive. + * 1: the validator/converter are case-insensitive. + * 2: the validator/converter is case-insensitive and the + converted value will always be lower-case. + + The *validator* tests whether the value is in the list of allowed values. + The *converter* converts input values according to the given + *map*-dictionary (unmapped input values are returned unchanged). """ help = '%s (%s)' % (help, '|'.join(allowed_values)) # define validator - if ignorecase >= 1: + if ignorecase: validator = lambda key, val, env: \ _validator(key, val.lower(), env, allowed_values) else: diff -Nru scons-4.0.1+dfsg/SCons/Variables/EnumVariableTests.py scons-4.4.0+dfsg/SCons/Variables/EnumVariableTests.py --- scons-4.0.1+dfsg/SCons/Variables/EnumVariableTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/EnumVariableTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Variables/__init__.py scons-4.4.0+dfsg/SCons/Variables/__init__.py --- scons-4.0.1+dfsg/SCons/Variables/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ # 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__" +"""Adds user-friendly customizable variables to an SCons build. """ import os.path import sys @@ -49,7 +44,7 @@ Holds all the options, updates the environment with the variables, and renders the help text. - If is_global is True, this is a singleton, create only once. + If *is_global* is true, this is a singleton, create only once. Args: files (optional): List of option configuration files to load @@ -69,7 +64,7 @@ self.args = args if not SCons.Util.is_List(files): if files: - files = [ files ] + files = [files,] else: files = [] self.files = files @@ -78,24 +73,27 @@ # create the singleton instance if is_global: self = Variables.instance - if not Variables.instance: Variables.instance=self - def _do_add(self, key, help="", default=None, validator=None, converter=None): + def _do_add(self, key, help="", default=None, validator=None, converter=None, **kwargs) -> None: + class Variable: pass option = Variable() - # if we get a list or a tuple, we take the first element as the + # If we get a list or a tuple, we take the first element as the # option key and store the remaining in aliases. if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): - option.key = key[0] - option.aliases = key[1:] + option.key = key[0] + option.aliases = list(key[1:]) else: - option.key = key - option.aliases = [ key ] + option.key = key + # TODO: normalize to not include key in aliases. Currently breaks tests. + option.aliases = [key,] + if not SCons.Environment.is_valid_construction_var(option.key): + raise SCons.Errors.UserError("Illegal Variables key `%s'" % str(option.key)) option.help = help option.default = default option.validator = validator @@ -105,43 +103,44 @@ # options might be added after the 'unknown' dict has been set up, # so we remove the key and all its aliases from that dict - for alias in list(option.aliases) + [ option.key ]: + for alias in option.aliases + [option.key,]: if alias in self.unknown: del self.unknown[alias] - def keys(self): - """ - Returns the keywords for the options - """ + def keys(self) -> list: + """Returns the keywords for the options.""" return [o.key for o in self.options] - def Add(self, key, help="", default=None, validator=None, converter=None, **kw): - """Add an option. + def Add(self, key, *args, **kwargs) -> None: + r""" Adds an option. - Args: - key: the name of the variable, or a list or tuple of arguments - help: optional help text for the options (Default value = "") - default: optional default value for option (Default value = None) - validator: optional function called to validate the option's value + Arguments: + key: the name of the variable, or a 5-tuple (or list). + If a tuple, and there are no additional arguments, + the tuple is unpacked into the four named kwargs from below. + If a tuple and there are additional arguments, the first word + of the tuple is taken as the key, and the remainder as aliases. + *args: optional positional arguments, corresponding to the four + named kwargs below. + + Keyword Args: + help: help text for the options (Default value = "") + default: default value for option (Default value = None) + validator: function called to validate the option's value (Default value = None) - converter: optional function to be called to convert the option's + converter: function to be called to convert the option's value before putting it in the environment. (Default value = None) - \*\*kw: keyword args, unused. + **kwargs: arbitrary keyword arguments used by the variable itself. """ - if SCons.Util.is_List(key) or isinstance(key, tuple): - self._do_add(*key) - return - - if not SCons.Util.is_String(key) or \ - not SCons.Environment.is_valid_construction_var(key): - raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'" % str(key)) + if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): + if not (len(args) or len(kwargs)): + return self._do_add(*key) - self._do_add(key, help, default, validator, converter) + return self._do_add(key, *args, **kwargs) - def AddVariables(self, *optlist): - """ - Add a list of options. + def AddVariables(self, *optlist) -> None: + """ Adds a list of options. Each list element is a tuple/list of arguments to be passed on to the underlying method for adding options. @@ -159,12 +158,13 @@ for o in optlist: self._do_add(*o) + def Update(self, env, args=None) -> None: + """ Updates an environment with the option variables. - def Update(self, env, args=None): - """ - Update an environment with the option variables. - - env - the environment to update. + Args: + env: the environment to update. + args (optional): a dictionary of keys and values to update + in *env*. If omitted, uses the variables from the commandline. """ values = {} @@ -197,7 +197,7 @@ for arg, value in args.items(): added = False for option in self.options: - if arg in list(option.aliases) + [ option.key ]: + if arg in option.aliases + [option.key,]: values[option.key] = value added = True if not added: @@ -211,7 +211,7 @@ except KeyError: pass - # Call the convert functions: + # apply converters for option in self.options: if option.converter and option.key in values: value = env.subst('${%s}'%option.key) @@ -224,36 +224,39 @@ raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x)) - # Finally validate the values: + # apply validators for option in self.options: if option.validator and option.key in values: option.validator(option.key, env.subst('${%s}'%option.key), env) - def UnknownVariables(self): - """ - Returns any options in the specified arguments lists that - were not known, declared options in this object. + def UnknownVariables(self) -> dict: + """ Returns unknown variables. + + Identifies options that were not known, declared options in this object. """ return self.unknown - def Save(self, filename, env): - """ - Saves all the options in the given file. This file can - then be used to load the options next run. This can be used - to create an option cache file. + def Save(self, filename, env) -> None: + """ Save the options to a file. + + Saves all the options which have non-default settings + to the given file as Python expressions. This file can + then be used to load the options for a subsequent run. + This can be used to create an option cache file. - filename - Name of the file to save into - env - the environment get the option values from + Args: + filename: Name of the file to save into + env: the environment get the option values from """ # Create the file and write out the header try: - fh = open(filename, 'w') - - try: + with open(filename, 'w') as fh: # Make an assignment in the file for each option # within the environment that was assigned a value - # other than the default. + # other than the default. We don't want to save the + # ones set to default: in case the SConscript settings + # change you would then pick up old defaults. for option in self.options: try: value = env[option.key] @@ -273,55 +276,58 @@ defaultVal = env.subst(SCons.Util.to_String(option.default)) if option.converter: - defaultVal = option.converter(defaultVal) + try: + defaultVal = option.converter(defaultVal) + except TypeError: + defaultVal = option.converter(defaultVal, env) if str(env.subst('${%s}' % option.key)) != str(defaultVal): fh.write('%s = %s\n' % (option.key, repr(value))) except KeyError: pass - finally: - fh.close() - except IOError as x: raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) - def GenerateHelpText(self, env, sort=None): - """ - Generate the help text for the options. + def GenerateHelpText(self, env, sort=None) -> str: + """ Generates the help text for the options. - env - an environment that is used to get the current values - of the options. - cmp - Either a function as follows: The specific sort function should take two arguments and return -1, 0 or 1 - or a boolean to indicate if it should be sorted. + Args: + env: an environment that is used to get the current values + of the options. + sort: Either a comparison function used for sorting + (must take two arguments and return -1, 0 or 1) + or a boolean to indicate if it should be sorted. """ if callable(sort): - options = sorted(self.options, key=cmp_to_key(lambda x,y: sort(x.key,y.key))) + options = sorted(self.options, key=cmp_to_key(lambda x, y: sort(x.key, y.key))) elif sort is True: options = sorted(self.options, key=lambda x: x.key) else: options = self.options - def format(opt, self=self, env=env): + def format_opt(opt, self=self, env=env) -> str: if opt.key in env: actual = env.subst('${%s}' % opt.key) else: actual = None return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases) - lines = [_f for _f in map(format, options) if _f] + lines = [_f for _f in map(format_opt, options) if _f] return ''.join(lines) - format = '\n%s: %s\n default: %s\n actual: %s\n' - format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' + fmt = '\n%s: %s\n default: %s\n actual: %s\n' + aliasfmt = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' - def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[]): + def FormatVariableHelpText(self, env, key, help, default, actual, aliases=None) -> str: + if aliases is None: + aliases = [] # Don't display the key name itself as an alias. aliases = [a for a in aliases if a != key] - if len(aliases)==0: - return self.format % (key, help, default, actual) + if aliases: + return self.aliasfmt % (key, help, default, actual, aliases) else: - return self.format_ % (key, help, default, actual, aliases) + return self.fmt % (key, help, default, actual) # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Variables/ListVariable.py scons-4.4.0+dfsg/SCons/Variables/ListVariable.py --- scons-4.0.1+dfsg/SCons/Variables/ListVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/ListVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,49 +21,86 @@ # 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__" +"""Variable type for list Variables. + +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', + help='libraries to build as shared libraries', + default='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. -__all__ = ['ListVariable',] - import collections +from typing import Tuple, Callable import SCons.Util +__all__ = ['ListVariable',] + class _ListVariable(collections.UserList): - def __init__(self, initlist=[], allowedElems=[]): - collections.UserList.__init__(self, [_f for _f in initlist if _f]) + def __init__(self, initlist=None, allowedElems=None): + if initlist is None: + initlist = [] + if allowedElems is None: + allowedElems = [] + super().__init__([_f for _f in initlist if _f]) self.allowedElems = sorted(allowedElems) def __cmp__(self, other): raise NotImplementedError + def __eq__(self, other): raise NotImplementedError + def __ge__(self, other): raise NotImplementedError + def __gt__(self, other): raise NotImplementedError + def __le__(self, other): raise NotImplementedError + def __lt__(self, other): raise NotImplementedError + def __str__(self): - if len(self) == 0: + if not len(self): return 'none' self.data.sort() if self.data == self.allowedElems: return 'all' else: return ','.join(self) + def prepare_to_store(self): return self.__str__() -def _converter(val, allowedElems, mapdict): - """ - """ +def _converter(val, allowedElems, mapdict) -> _ListVariable: + """ """ if val == 'none': val = [] elif val == 'all': @@ -98,35 +110,40 @@ val = [mapdict.get(v, v) for v in val] notAllowed = [v for v in val if v not in allowedElems] if notAllowed: - raise ValueError("Invalid value(s) for option: %s" % - ','.join(notAllowed)) + raise ValueError( + "Invalid value(s) for option: %s" % ','.join(notAllowed) + ) return _ListVariable(val, allowedElems) -## def _validator(key, val, env): -## """ -## """ -## # todo: write validator for pgk list -## return 1 +# def _validator(key, val, env) -> None: +# """ """ +# # TODO: write validator for pgk list +# pass -def ListVariable(key, help, default, names, map={}): - """ - The input parameters describe a 'package list' option, thus they - are returned with the correct converter and validator appended. The - result is usable for input to opts.Add() . +def ListVariable(key, help, default, names, map={}) -> Tuple[str, str, str, None, Callable]: + """Return a tuple describing a list SCons Variable. + + The input parameters describe a 'list' option. Returns + a tuple including the correct converter and validator. + The result is usable for input to :meth:`Add`. + + *help* will have text appended indicating the legal values + (not including any extra names from *map*). + + *map* can be used to map alternative names to the ones in *names* - + that is, a form of alias. - A 'package list' option may either be 'all', 'none' or a list of - package names (separated by space). + A 'list' option may either be 'all', 'none' or a list of + names (separated by commas). """ names_str = 'allowed names: %s' % ' '.join(names) if SCons.Util.is_List(default): default = ','.join(default) help = '\n '.join( (help, '(all|none|comma-separated list of names)', names_str)) - return (key, help, default, - None, #_validator, - lambda val: _converter(val, names, map)) + return (key, help, default, None, lambda val: _converter(val, names, map)) # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/SCons/Variables/ListVariableTests.py scons-4.4.0+dfsg/SCons/Variables/ListVariableTests.py --- scons-4.0.1+dfsg/SCons/Variables/ListVariableTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/ListVariableTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Variables/PackageVariable.py scons-4.4.0+dfsg/SCons/Variables/PackageVariable.py --- scons-4.0.1+dfsg/SCons/Variables/PackageVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/PackageVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,34 +1,6 @@ -"""SCons.Variables.PackageVariable - -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. - -Usage example: - - Examples: - x11=no (disables X11 support) - x11=yes (will search for the package installation dir) - x11=/usr/local/X11 (will check this path for existence) - - To replace autoconf's --with-xxx=yyy :: - - opts = Variables() - opts.Add(PackageVariable('x11', - 'use X11 installed here (yes = search some places', - 'yes')) - ... - if env['x11'] == True: - dir = ... search X11 in some standard places ... - env['x11'] = dir - if env['x11']: - ... build with x11 ... -""" - +# 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 @@ -48,33 +20,61 @@ # 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__" +"""Variable type for package Variables. -__all__ = ['PackageVariable',] +To be used whenever a 'package' may be enabled/disabled and the +package path may be specified. + +Given these options :: + + x11=no (disables X11 support) + x11=yes (will search for the package installation dir) + x11=/usr/local/X11 (will check this path for existence) + +Can be used as a replacement for autoconf's ``--with-xxx=yyy`` :: + + opts = Variables() + opts.Add( + PackageVariable( + key='x11', + help='use X11 installed here (yes = search some places)', + default='yes' + ) + ) + ... + if env['x11'] == True: + dir = ... # search X11 in some standard places ... + env['x11'] = dir + if env['x11']: + ... # build with x11 ... +""" + +from typing import Tuple, Callable import SCons.Errors -__enable_strings = ('1', 'yes', 'true', 'on', 'enable', 'search') -__disable_strings = ('0', 'no', 'false', 'off', 'disable') +__all__ = ['PackageVariable',] + +ENABLE_STRINGS = ('1', 'yes', 'true', 'on', 'enable', 'search') +DISABLE_STRINGS = ('0', 'no', 'false', 'off', 'disable') def _converter(val): - """ - """ + """ """ lval = val.lower() - if lval in __enable_strings: return True - if lval in __disable_strings: return False - #raise ValueError("Invalid value for boolean option: %s" % val) + if lval in ENABLE_STRINGS: + return True + if lval in DISABLE_STRINGS: + return False return val -def _validator(key, val, env, searchfunc): +def _validator(key, val, env, searchfunc) -> None: + """ """ # NB: searchfunc is currently undocumented and unsupported - """ - """ # TODO write validator, check for path import os + if env[key] is True: if searchfunc: env[key] = searchfunc(key, val) @@ -83,20 +83,21 @@ 'Path does not exist for option %s: %s' % (key, val)) -def PackageVariable(key, help, default, searchfunc=None): - # NB: searchfunc is currently undocumented and unsupported - """ - The input parameters describe a 'package list' option, thus they - are returned with the correct converter and validator appended. The - result is usable for input to opts.Add() . +def PackageVariable(key, help, default, searchfunc=None) -> Tuple[str, str, str, Callable, Callable]: + """Return a tuple describing a package list SCons Variable. + + The input parameters describe a 'package list' option. Returns + a tuple including the correct converter and validator appended. + The result is usable as input to :meth:`Add` . - A 'package list' option may either be 'all', 'none' or a list of - package names (separated by space). + A 'package list' option may either be 'all', 'none' or a pathname + string. This information is appended to *help*. """ + # NB: searchfunc is currently undocumented and unsupported help = '\n '.join( (help, '( yes | no | /path/to/%s )' % key)) return (key, help, default, - lambda k, v, e: _validator(k,v,e,searchfunc), + lambda k, v, e: _validator(k, v, e, searchfunc), _converter) # Local Variables: diff -Nru scons-4.0.1+dfsg/SCons/Variables/PackageVariableTests.py scons-4.4.0+dfsg/SCons/Variables/PackageVariableTests.py --- scons-4.0.1+dfsg/SCons/Variables/PackageVariableTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/PackageVariableTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/SCons/Variables/PathVariable.py scons-4.4.0+dfsg/SCons/Variables/PathVariable.py --- scons-4.0.1+dfsg/SCons/Variables/PathVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/PathVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,51 +1,6 @@ -"""SCons.Variables.PathVariable - -This file defines an option type for SCons implementing path settings. - -To be used whenever a user-specified path override should be allowed. - -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. - -Usage example:: - - Examples: - prefix=/usr/local - - opts = Variables() - - opts = Variables() - opts.Add(PathVariable('qtdir', - 'where the root of Qt is installed', - qtdir, PathIsDir)) - opts.Add(PathVariable('qt_includes', - 'where the Qt includes are installed', - '$qtdir/includes', PathIsDirCreate)) - opts.Add(PathVariable('qt_libraries', - 'where the Qt library is installed', - '$qtdir/lib')) - -""" - +# 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 @@ -65,26 +20,75 @@ # 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__" +"""Variable type for path Variables. + +To be used whenever a user-specified path override setting should be allowed. + +Arguments to PathVariable are: + * *key* - name of this option on the command line (e.g. "prefix") + * *help* - help string for option + * *default* - default value for this option + * *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*). *key* is the + name of the option, *val* is the path specified for the option, + and *env* is the environment to which the Options have been added. + +Usage example:: + + opts = Variables() + opts.Add( + PathVariable( + 'qtdir', + help='where the root of Qt is installed', + default=qtdir, + validator=PathIsDir, + ) + ) + opts.Add( + PathVariable( + 'qt_includes', + help='where the Qt includes are installed', + default='$qtdir/includes', + validator=PathIsDirCreate, + ) + ) + opts.Add( + PathVariable( + 'qt_libraries', + help='where the Qt library is installed', + default='$qtdir/lib', + ) + ) +""" -__all__ = ['PathVariable',] import os import os.path +from typing import Tuple, Callable import SCons.Errors +__all__ = ['PathVariable',] + class _PathVariableClass: @staticmethod - def PathAccept(key, val, env): + def PathAccept(key, val, env) -> None: """Accepts any path, no checking done.""" pass - + @staticmethod - def PathIsDir(key, val, env): + def PathIsDir(key, val, env) -> None: """Validator to check if Path is a directory.""" if not os.path.isdir(val): if os.path.isfile(val): @@ -94,17 +98,20 @@ raise SCons.Errors.UserError(m % (key, val)) @staticmethod - def PathIsDirCreate(key, val, env): + def PathIsDirCreate(key, val, env) -> None: """Validator to check if Path is a directory, creating it if it does not exist.""" - if os.path.isfile(val): + try: + os.makedirs(val, exist_ok=True) + except FileExistsError: m = 'Path for option %s is a file, not a directory: %s' raise SCons.Errors.UserError(m % (key, val)) - if not os.path.isdir(val): - os.makedirs(val) + except PermissionError: + m = 'Path for option %s could not be created: %s' + raise SCons.Errors.UserError(m % (key, val)) @staticmethod - def PathIsFile(key, val, env): + def PathIsFile(key, val, env) -> None: """Validator to check if Path is a file""" if not os.path.isfile(val): if os.path.isdir(val): @@ -114,32 +121,33 @@ raise SCons.Errors.UserError(m % (key, val)) @staticmethod - def PathExists(key, val, env): + def PathExists(key, val, env) -> None: """Validator to check if Path exists""" if not os.path.exists(val): m = 'Path for option %s does not exist: %s' raise SCons.Errors.UserError(m % (key, val)) - def __call__(self, key, help, default, validator=None): - """ - The input parameters describe a 'path list' option, thus they - are returned with the correct converter and validator appended. The - result is usable for input to opts.Add() . + def __call__(self, key, help, default, validator=None) -> Tuple[str, str, str, Callable, None]: + """Return a tuple describing a path list SCons Variable. + + The input parameters describe a 'path list' option. Returns + a tuple with the correct converter and validator appended. The + result is usable for input to :meth:`Add`. - The 'default' option specifies the default path to use if the + The *default* option specifies the default path to use if the user does not specify an override with this option. - validator is a validator, see this file for examples + *validator* is a validator, see this file for examples """ if validator is None: validator = self.PathExists if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): - return (key, '%s ( /path/to/%s )' % (help, key[0]), default, - validator, None) + helpmsg = '%s ( /path/to/%s )' % (help, key[0]) else: - return (key, '%s ( /path/to/%s )' % (help, key), default, - validator, None) + helpmsg = '%s ( /path/to/%s )' % (help, key) + return (key, helpmsg, default, validator, None) + PathVariable = _PathVariableClass() diff -Nru scons-4.0.1+dfsg/SCons/Variables/PathVariableTests.py scons-4.4.0+dfsg/SCons/Variables/PathVariableTests.py --- scons-4.0.1+dfsg/SCons/Variables/PathVariableTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/PathVariableTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -99,8 +96,8 @@ o.validator('X', dne, {}) except SCons.Errors.UserError as e: assert str(e) == 'Directory path for option X does not exist: %s' % dne, e - except: - raise Exception("did not catch expected UserError") + except Exception as e: + raise Exception("did not catch expected UserError") from e def test_PathIsDirCreate(self): """Test the PathIsDirCreate validator""" @@ -124,8 +121,16 @@ o.validator('X', f, {}) except SCons.Errors.UserError as e: assert str(e) == 'Path for option X is a file, not a directory: %s' % f, e - except: - raise Exception("did not catch expected UserError") + except Exception as e: + raise Exception("did not catch expected UserError") from e + + f = '/yyy/zzz' # this not exists and should fail to create + try: + o.validator('X', f, {}) + except SCons.Errors.UserError as e: + assert str(e) == 'Path for option X could not be created: %s' % f, e + except Exception as e: + raise Exception("did not catch expected UserError") from e def test_PathIsFile(self): """Test the PathIsFile validator""" diff -Nru scons-4.0.1+dfsg/SCons/Variables/VariablesTests.py scons-4.4.0+dfsg/SCons/Variables/VariablesTests.py --- scons-4.0.1+dfsg/SCons/Variables/VariablesTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Variables/VariablesTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -44,16 +41,12 @@ def __getitem__(self, key): return self.dict[key] def __contains__(self, key): - return self.dict.__contains__(key) - def has_key(self, key): return key in self.dict - - def check(key, value, env): assert int(value) == 6 * 9, "key %s = %s" % (key, repr(value)) - + # Check saved option file by executing and comparing against # the expected dictionary def checkSave(file, expected): @@ -145,7 +138,7 @@ test = TestSCons.TestSCons() file = test.workpath('custom.py') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', 'THE answer to THE question', "42", @@ -166,7 +159,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=54') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', 'THE answer to THE question', "42", @@ -194,7 +187,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=42') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', 'THE answer to THE question', "10", @@ -215,7 +208,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=10') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', 'THE answer to THE question', "12", @@ -236,7 +229,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=10') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', 'THE answer to THE question', "12", @@ -254,7 +247,7 @@ test = TestSCons.TestSCons() file = test.workpath('custom.py') opts = SCons.Variables.Variables(file) - + opts.Add('ANSWER', help='THE answer to THE question', converter=str) @@ -289,9 +282,9 @@ nopts = SCons.Variables.Variables() # Ensure that both attributes are initialized to - # an empty list and dict, respectively. + # an empty list and dict, respectively. assert len(nopts.files) == 0 - assert len(nopts.args) == 0 + assert len(nopts.args) == 0 def test_args(self): """Test updating an Environment with arguments overridden""" @@ -302,7 +295,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=42') opts = SCons.Variables.Variables(file, {'ANSWER':54}) - + opts.Add('ANSWER', 'THE answer to THE question', "42", @@ -322,7 +315,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=54') opts = SCons.Variables.Variables(file, {'ANSWER':42}) - + opts.Add('ANSWER', 'THE answer to THE question', "54", @@ -339,7 +332,7 @@ file = test.workpath('custom.py') test.write('custom.py', 'ANSWER=54') opts = SCons.Variables.Variables(file, {'ANSWER':54}) - + opts.Add('ANSWER', 'THE answer to THE question', "54", @@ -361,7 +354,7 @@ if val in [1, 'y']: val = 1 if val in [0, 'n']: val = 0 return val - + # test saving out empty file opts.Add('OPT_VAL', 'An option to test', @@ -407,11 +400,11 @@ self.x = x def __str__(self): return self.x - + test = TestSCons.TestSCons() cache_file = test.workpath('cached.options') opts = SCons.Variables.Variables() - + opts.Add('THIS_USED_TO_BREAK', 'An option to test', "Default") @@ -419,11 +412,11 @@ opts.Add('THIS_ALSO_BROKE', 'An option to test', "Default2") - + opts.Add('THIS_SHOULD_WORK', 'An option to test', Foo('bar')) - + env = Environment() opts.Update(env, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String", 'THIS_ALSO_BROKE' : "\\Escape\nSequences\t", @@ -509,7 +502,10 @@ assert text == expectAlpha, text textBackwards = opts.GenerateHelpText(env, sort=lambda x, y: cmp(y, x)) - assert textBackwards == expectBackwards, "Expected:\n%s\nGot:\n%s\n"%(textBackwards, expectBackwards) + assert textBackwards == expectBackwards, "Expected:\n%s\nGot:\n%s\n" % ( + textBackwards, + expectBackwards, + ) def test_FormatVariableHelpText(self): """Test generating custom format help text""" @@ -557,7 +553,7 @@ """ text = opts.GenerateHelpText(env, sort=cmp) assert text == expectAlpha, text - + def test_Aliases(self): """Test option aliases""" # test alias as a tuple @@ -567,17 +563,17 @@ 'THE answer to THE question', "42"), ) - + env = Environment() opts.Update(env, {'ANSWER' : 'answer'}) - + assert 'ANSWER' in env - + env = Environment() opts.Update(env, {'ANSWERALIAS' : 'answer'}) - + assert 'ANSWER' in env and 'ANSWERALIAS' not in env - + # test alias as a list opts = SCons.Variables.Variables() opts.AddVariables( @@ -585,17 +581,16 @@ 'THE answer to THE question', "42"), ) - + env = Environment() opts.Update(env, {'ANSWER' : 'answer'}) - + assert 'ANSWER' in env - + env = Environment() opts.Update(env, {'ANSWERALIAS' : 'answer'}) - - assert 'ANSWER' in env and 'ANSWERALIAS' not in env + assert 'ANSWER' in env and 'ANSWERALIAS' not in env class UnknownVariablesTestCase(unittest.TestCase): @@ -603,7 +598,7 @@ def test_unknown(self): """Test the UnknownVariables() method""" opts = SCons.Variables.Variables() - + opts.Add('ANSWER', 'THE answer to THE question', "42") @@ -619,38 +614,38 @@ r = opts.UnknownVariables() assert r == {'UNKNOWN' : 'unknown'}, r assert env['ANSWER'] == 'answer', env['ANSWER'] - + def test_AddOptionUpdatesUnknown(self): """Test updating of the 'unknown' dict""" opts = SCons.Variables.Variables() - + opts.Add('A', 'A test variable', "1") - + args = { 'A' : 'a', 'ADDEDLATER' : 'notaddedyet', } - + env = Environment() opts.Update(env,args) - + r = opts.UnknownVariables() assert r == {'ADDEDLATER' : 'notaddedyet'}, r assert env['A'] == 'a', env['A'] - + opts.Add('ADDEDLATER', 'An option not present initially', "1") - + args = { 'A' : 'a', 'ADDEDLATER' : 'added', } - + opts.Update(env, args) - + r = opts.UnknownVariables() assert len(r) == 0, r assert env['ADDEDLATER'] == 'added', env['ADDEDLATER'] @@ -658,33 +653,33 @@ def test_AddOptionWithAliasUpdatesUnknown(self): """Test updating of the 'unknown' dict (with aliases)""" opts = SCons.Variables.Variables() - + opts.Add('A', 'A test variable', "1") - + args = { 'A' : 'a', 'ADDEDLATERALIAS' : 'notaddedyet', } - + env = Environment() opts.Update(env,args) - + r = opts.UnknownVariables() assert r == {'ADDEDLATERALIAS' : 'notaddedyet'}, r assert env['A'] == 'a', env['A'] - + opts.AddVariables( (('ADDEDLATER', 'ADDEDLATERALIAS'), 'An option not present initially', "1"), ) - + args['ADDEDLATERALIAS'] = 'added' - + opts.Update(env, args) - + r = opts.UnknownVariables() assert len(r) == 0, r assert env['ADDEDLATER'] == 'added', env['ADDEDLATER'] diff -Nru scons-4.0.1+dfsg/SCons/Warnings.py scons-4.4.0+dfsg/SCons/Warnings.py --- scons-4.0.1+dfsg/SCons/Warnings.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/Warnings.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,41 +20,36 @@ # 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 import SCons.Errors -class Warning(SCons.Errors.UserError): +class SConsWarning(SCons.Errors.UserError): pass -class WarningOnByDefault(Warning): +class WarningOnByDefault(SConsWarning): pass # NOTE: If you add a new warning class, add it to the man page, too! -class TargetNotBuiltWarning(Warning): # Should go to OnByDefault +# Not all warnings are defined here, some are defined in the location of use + +class TargetNotBuiltWarning(SConsWarning): # Should go to OnByDefault pass class CacheVersionWarning(WarningOnByDefault): pass -class CacheWriteErrorWarning(Warning): +class CacheWriteErrorWarning(SConsWarning): pass class CorruptSConsignWarning(WarningOnByDefault): pass -class DependencyWarning(Warning): +class DependencyWarning(SConsWarning): pass class DevelopmentVersionWarning(WarningOnByDefault): @@ -94,7 +90,7 @@ class VisualVersionMismatch(WarningOnByDefault): pass -class VisualStudioMissingWarning(Warning): +class VisualStudioMissingWarning(SConsWarning): pass class FortranCxxMixWarning(LinkWarning): @@ -103,10 +99,10 @@ # Deprecation warnings -class FutureDeprecatedWarning(Warning): +class FutureDeprecatedWarning(SConsWarning): pass -class DeprecatedWarning(Warning): +class DeprecatedWarning(SConsWarning): pass class MandatoryDeprecatedWarning(DeprecatedWarning): @@ -132,37 +128,49 @@ class DeprecatedMissingSConscriptWarning(DeprecatedWarning): pass +class ToolQtDeprecatedWarning(FutureDeprecatedWarning): + pass # The below is a list of 2-tuples. The first element is a class object. # The second element is true if that class is enabled, false if it is disabled. _enabled = [] # If set, raise the warning as an exception -_warningAsException = 0 +_warningAsException = False # If not None, a function to call with the warning _warningOut = None def suppressWarningClass(clazz): - """Suppresses all warnings that are of type clazz or - derived from clazz.""" - _enabled.insert(0, (clazz, 0)) + """Suppresses all warnings of type clazz or derived from clazz.""" + _enabled.insert(0, (clazz, False)) def enableWarningClass(clazz): - """Enables all warnings that are of type clazz or - derived from clazz.""" - _enabled.insert(0, (clazz, 1)) + """Enables all warnings of type clazz or derived from clazz.""" + _enabled.insert(0, (clazz, True)) + +def warningAsException(flag=True): + """Set global _warningAsExeption flag. -def warningAsException(flag=1): - """Turn warnings into exceptions. Returns the old value of the flag.""" + Args: + flag: value to set warnings-as-exceptions to [default: True] + + Returns: + The previous value. + """ global _warningAsException old = _warningAsException _warningAsException = flag return old def warn(clazz, *args): - global _enabled, _warningAsException, _warningOut + """Issue a warning, accounting for SCons rules. + Check if warnings for this class are enabled. + If warnings are treated as exceptions, raise exception. + Use the global warning-emitter _warningOut, which allows selecting + different ways of presenting a traceback (see Script/Main.py) + """ warning = clazz(args) for cls, flag in _enabled: if isinstance(warning, cls): @@ -180,39 +188,36 @@ The requests are strings passed to the --warn option or the SetOption('warn') function. - An argument to this option should be of the form - or no-. The warning class is munged in order - to get an actual class name from the classes above, which we - need to pass to the {enable,disable}WarningClass() functions. - The supplied is split on hyphens, each element - is capitalized, then smushed back together. Then the string - "Warning" is appended to get the class name. + An argument to this option should be of the form "warning-class" + or "no-warning-class". The warning class is munged and has + the suffix "Warning" added in order to get an actual class name + from the classes above, which we need to pass to the + {enable,disable}WarningClass() functions. - For example, 'deprecated' will enable the DeprecatedWarning - class. 'no-dependency' will disable the DependencyWarning class. + For example, "deprecated" will enable the DeprecatedWarning class. + "no-dependency" will disable the DependencyWarning class. As a special case, --warn=all and --warn=no-all will enable or - disable (respectively) the base Warning class of all warnings. + disable (respectively) the base class of all SCons warnings. """ - def _capitalize(s): - if s[:5] == "scons": - return "SCons" + s[5:] - else: - return s.capitalize() + def _classmunge(s): + """Convert a warning argument to SConsCase. - for arg in arguments: - - elems = arg.lower().split('-') - enable = 1 - if elems[0] == 'no': - enable = 0 - del elems[0] + The result is CamelCase, except "Scons" is changed to "SCons" + """ + s = s.replace("-", " ").title().replace(" ", "") + return s.replace("Scons", "SCons") - if len(elems) == 1 and elems[0] == 'all': - class_name = "Warning" + for arg in arguments: + enable = True + if arg.startswith("no-"): + enable = False + arg = arg[len("no-") :] + if arg == 'all': + class_name = "SConsWarning" else: - class_name = ''.join(map(_capitalize, elems)) + "Warning" + class_name = _classmunge(arg) + 'Warning' try: clazz = globals()[class_name] except KeyError: diff -Nru scons-4.0.1+dfsg/SCons/WarningsTests.py scons-4.4.0+dfsg/SCons/WarningsTests.py --- scons-4.0.1+dfsg/SCons/WarningsTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SCons/WarningsTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -45,7 +42,7 @@ to = TestOutput() SCons.Warnings._warningOut=to - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, "Foo") assert to.out == "Foo", to.out @@ -60,12 +57,12 @@ SCons.Warnings._enabled = [] SCons.Warnings._warningAsException = 0 - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) old = SCons.Warnings.warningAsException() assert old == 0, old exc_caught = 0 try: - SCons.Warnings.warn(SCons.Warnings.Warning, "Foo") + SCons.Warnings.warn(SCons.Warnings.SConsWarning, "Foo") except: exc_caught = 1 assert exc_caught == 1 @@ -74,7 +71,7 @@ assert old == 1, old exc_caught = 0 try: - SCons.Warnings.warn(SCons.Warnings.Warning, "Foo") + SCons.Warnings.warn(SCons.Warnings.SConsWarning, "Foo") except: exc_caught = 1 assert exc_caught == 0 @@ -95,7 +92,7 @@ "Foo") assert to.out is None, to.out - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, "Foo") assert to.out == "Foo", to.out @@ -111,15 +108,15 @@ assert to.out is None, to.out # Dependency warnings should still be enabled though - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) SCons.Warnings.warn(SCons.Warnings.DependencyWarning, "Foo") assert to.out == "Foo", to.out # Try reenabling all warnings... - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) - SCons.Warnings.enableWarningClass(SCons.Warnings.Warning) + SCons.Warnings.enableWarningClass(SCons.Warnings.SConsWarning) SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, "Foo") assert to.out == "Foo", to.out diff -Nru scons-4.0.1+dfsg/SConstruct scons-4.4.0+dfsg/SConstruct --- scons-4.0.1+dfsg/SConstruct 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -12,7 +12,9 @@ # 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 @@ project = 'scons' -default_version = '4.0.1' +default_version = '4.4.0' copyright = "Copyright (c) %s The SCons Foundation" % copyright_years # @@ -142,6 +144,7 @@ BUILD=command_line.build_id, BUILDDIR=command_line.build_dir, BUILDSYS=command_line.build_system, + COPYRIGHT_YEARS=copyright_years, COPYRIGHT=copyright, DATE=command_line.date, DEB_DATE=deb_date, @@ -193,14 +196,25 @@ SConscript('doc/SConscript') +# Copy manpage's into base dir for inclusion 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]) + +# NOTE: Commenting this out as the manpages are expected to be in the base directory when manually +# running setup.py from the base of the repo. +# NOTE: This used by distro package maintainers. +# env.AddPostAction(tgz_file, Delete(man_pages)) + # TODO add auto copyright date to README.rst, LICENSE # TODO build API DOCS diff -Nru scons-4.0.1+dfsg/scripts/scons.bat scons-4.4.0+dfsg/scripts/scons.bat --- scons-4.0.1+dfsg/scripts/scons.bat 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/scripts/scons.bat 2022-07-30 21:48:28.000000000 +0000 @@ -4,7 +4,7 @@ if "%OS%" == "Windows_NT" goto WinNT @REM for 9x/Me you better not have more than 9 args -python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %1 %2 %3 %4 %5 %6 %7 %8 %9 +python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %* @REM no way to set exit status of this script for 9x/Me goto endscons diff -Nru scons-4.0.1+dfsg/scripts/scons-configure-cache.py scons-4.4.0+dfsg/scripts/scons-configure-cache.py --- scons-4.0.1+dfsg/scripts/scons-configure-cache.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/scripts/scons-configure-cache.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -47,7 +49,7 @@ import sys # python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) @@ -92,4 +94,4 @@ from SCons.Utilities.ConfigureCache import main if __name__ == "__main__": - main() \ No newline at end of file + main() diff -Nru scons-4.0.1+dfsg/scripts/sconsign.py scons-4.4.0+dfsg/scripts/sconsign.py --- scons-4.0.1+dfsg/scripts/sconsign.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/scripts/sconsign.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -39,7 +41,7 @@ import sys # python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) diff -Nru scons-4.0.1+dfsg/scripts/scons.py scons-4.4.0+dfsg/scripts/scons.py --- scons-4.0.1+dfsg/scripts/scons.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/scripts/scons.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -21,7 +23,7 @@ # 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. +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -39,9 +41,8 @@ import os import sys - # Python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) diff -Nru scons-4.0.1+dfsg/setup.cfg scons-4.4.0+dfsg/setup.cfg --- scons-4.0.1+dfsg/setup.cfg 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/setup.cfg 2022-07-30 21:48:28.000000000 +0000 @@ -10,24 +10,27 @@ license_file = LICENSE -url = http://www.scons.org/ -project-urls = +url = https://www.scons.org/ +project_urls = Documentation = https://scons.org/documentation.html Twitter = https://twitter.com/SConsProject GitHub = https://github.com/SCons/scons Bug-Tracker = https://github.com/SCons/scons/issues + Discord = https://discord.gg/pejaFYrD9n + Mailing lists = https://scons.org/lists.html classifiers = Development Status :: 5 - Production/Stable - Topic :: Utilities + Topic :: Software Development :: Build Tools Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Environment :: Console Intended Audience :: Developers License :: OSI Approved :: MIT License @@ -39,10 +42,9 @@ [options] zip_safe = False -python_requires = >=3.5 +python_requires = >=3.6 install_requires = setuptools - pywin32 >= 1.0;platform_system=="Windows" setup_requires = setuptools include_package_data = True @@ -61,13 +63,20 @@ [options.package_data] -* = *.txt, *.rst +* = *.txt, *.rst, *.1 SCons.Tool.docbook = *.* + +[options.data_files] +. = scons.1 + scons-time.1 + sconsign.1 + [sdist] - dist-dir=build/dist + 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 + diff -Nru scons-4.0.1+dfsg/setup.py scons-4.4.0+dfsg/setup.py --- scons-4.0.1+dfsg/setup.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/setup.py 2022-07-30 21:48:28.000000000 +0000 @@ -7,11 +7,13 @@ 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 @@ raise RuntimeError("Unable to find version string.") - exclude = ['*Tests'] diff -Nru scons-4.0.1+dfsg/site_scons/BuildCommandLine.py scons-4.4.0+dfsg/site_scons/BuildCommandLine.py --- scons-4.0.1+dfsg/site_scons/BuildCommandLine.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/site_scons/BuildCommandLine.py 2022-07-30 21:48:28.000000000 +0000 @@ -67,13 +67,26 @@ self.init_command_line_variables() + def set_date(self): + """ + Determine the release date and the pattern to match a date + Mon, 05 Jun 2010 21:17:15 -0700 + NEW DATE WILL BE INSERTED HERE + """ + + min = (time.daylight and time.altzone or time.timezone) // 60 + hr = min // 60 + min = -(min % 60 + hr * 100) + self.date = (time.strftime('%a, %d %b %Y %X', time.localtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))) + + ' %+.4d' % min) + def process_command_line_vars(self): # # Now grab the information that we "build" into the files. # self.date = ARGUMENTS.get('DATE') if not self.date: - self.date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))) + self.set_date() self.developer = ARGUMENTS.get('DEVELOPER') if not self.developer: diff -Nru scons-4.0.1+dfsg/site_scons/scons_local_package.py scons-4.4.0+dfsg/site_scons/scons_local_package.py --- scons-4.0.1+dfsg/site_scons/scons_local_package.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/site_scons/scons_local_package.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ 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 -Nru scons-4.0.1+dfsg/site_scons/site_init.py scons-4.4.0+dfsg/site_scons/site_init.py --- scons-4.0.1+dfsg/site_scons/site_init.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/site_scons/site_init.py 2022-07-30 21:48:28.000000000 +0000 @@ -15,4 +15,4 @@ unzip = whereis('unzip') zip_path = whereis('zip') -BuildCommandLine.git = git \ No newline at end of file +BuildCommandLine.git = git diff -Nru scons-4.0.1+dfsg/site_scons/update_build_info.py scons-4.4.0+dfsg/site_scons/update_build_info.py --- scons-4.0.1+dfsg/site_scons/update_build_info.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/site_scons/update_build_info.py 2022-07-30 21:48:28.000000000 +0000 @@ -14,3 +14,4 @@ 'import SCons.compat # noqa'], ) env.Precious(si) + env.NoClean(si) # Don't clean this file as it breaks the build. diff -Nru scons-4.0.1+dfsg/site_scons/Utilities.py scons-4.4.0+dfsg/site_scons/Utilities.py --- scons-4.0.1+dfsg/site_scons/Utilities.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/site_scons/Utilities.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,10 @@ import os import stat import time -import distutils.util +import sysconfig -platform = distutils.util.get_platform() +platform = sysconfig.get_platform() def is_windows(): """ Check if we're on a Windows platform""" diff -Nru scons-4.0.1+dfsg/src/test_setup.py scons-4.4.0+dfsg/src/test_setup.py --- scons-4.0.1+dfsg/src/test_setup.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/src/test_setup.py 2022-07-30 21:48:28.000000000 +0000 @@ -81,7 +81,7 @@ ] def __init__(self): - TestSCons.TestSCons.__init__(self) + super().__init__() self.root = self.workpath('root') self.prefix = self.root + os.path.splitdrive(sys.prefix)[1] diff -Nru scons-4.0.1+dfsg/template/file.py scons-4.4.0+dfsg/template/file.py --- scons-4.0.1+dfsg/template/file.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/template/file.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,11 +1,6 @@ -"""${subst '/' '.' ${subst '^src/' '' ${subst '\.py$' '' $filename}}} - -XXX - -""" - +# 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,11 +20,11 @@ # 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__" - +""" +Template for an SCons source file. +Replace this with the purpose of the file. +""" import XXX diff -Nru scons-4.0.1+dfsg/template/__init__.py scons-4.4.0+dfsg/template/__init__.py --- scons-4.0.1+dfsg/template/__init__.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/template/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -# -# __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. -# - -"""SCons - -The main package for the SCons software construction utility. - -""" - -# -# __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__ = "__REVISION__" -__version__ = "__VERSION__" -__build__ = "__BUILD__" -__buildsys__ = "__BUILDSYS__" -__date__ = "__DATE__" -__developer__ = "__DEVELOPER__" -__copyright__ = "__COPYRIGHT__" - -# make sure compatibility is always in place -import SCons.compat # noqa - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/template/RELEASE.txt scons-4.4.0+dfsg/template/RELEASE.txt --- scons-4.0.1+dfsg/template/RELEASE.txt 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/template/RELEASE.txt 2022-07-30 21:48:28.000000000 +0000 @@ -1,73 +1,58 @@ - A new SCons checkpoint release, 2.0.0ayyyymmdd, is now available - on the SCons download page: +A new SCons release, 4.1.0, is now available +on the SCons download page: - https://scons.org/pages/download.html + https://scons.org/pages/download.html - XXX The primary purpose of this release ... XXX - A SCons "checkpoint release" is intended to provide early access to - new features so they can be tested in the field before being released - for adoption by other software distributions. +Here is a summary of the changes since 4.1.0: - Note that a checkpoint release is developed using the same test-driven - development methodology as all SCons releases. Existing SCons - functionality should all work as it does in previous releases (except - for any changes identified in the release notes) and early adopters - should be able to use a checkpoint release safely for production work - with existing SConscript files. If not, it represents not only a bug - in SCons but also a hole in the regression test suite, and we want to - hear about it. +NEW FUNCTIONALITY +----------------- - New features may be more lightly tested than in past releases, - especially as concerns their interaction with all of the other - functionality in SCons. We are especially interested in hearing bug - reports about new functionality. +- List new features (presumably why a checkpoint is being released) - We do not recommend that downstream distributions (Debian, Fedora, - etc.) package a checkpoint release, mainly to avoid confusing the - "public" release numbering with the long checkpoint release names. +DEPRECATED FUNCTIONALITY +------------------------ - Here is a summary of the changes since 1.3.0: +- List anything that's been deprecated since the last release - NEW FUNCTIONALITY +CHANGED/ENHANCED EXISTING FUNCTIONALITY +--------------------------------------- - - List new features (presumably why a checkpoint is being released) +- List modifications to existing features, where the previous behavior + wouldn't actually be considered a bug - DEPRECATED FUNCTIONALITY +FIXES +----- - - List anything that's been deprecated since the last release +- List fixes of outright bugs - CHANGED/ENHANCED EXISTING FUNCTIONALITY +IMPROVEMENTS +------------ - - List modifications to existing features, where the previous behavior - wouldn't actually be considered a bug +- List improvements that wouldn't be visible to the user in the + documentation: performance improvements (describe the circumstances + under which they would be observed), or major code cleanups - FIXES +PACKAGING +--------- - - List fixes of outright bugs +- List changes in the way SCons is packaged and/or released - IMPROVEMENTS +DOCUMENTATION +------------- - - List improvements that wouldn't be visible to the user in the - documentation: performance improvements (describe the circumstances - under which they would be observed), or major code cleanups +- List any significant changes to the documentation (not individual + typo fixes, even if they're mentioned in src/CHANGES.txt to give + the contributor credit) - PACKAGING +DEVELOPMENT +----------- - - List changes in the way SCons is packaged and/or released +- List visible changes in the way SCons is developed - DOCUMENTATION +Thanks to the following contributors listed below for their contributions to this release. +========================================================================================== +.. code-block:: text - - List any significant changes to the documentation (not individual - typo fixes, even if they're mentioned in src/CHANGES.txt to give - the contributor credit) - - DEVELOPMENT - - - List visible changes in the way SCons is developed - - Thanks to CURLY, LARRY, and MOE for their contributions to this release. - Contributors are listed alphabetically by their last name. - -__COPYRIGHT__ -__FILE__ __REVISION__ __DATE__ __DEVELOPER__ + git shortlog --no-merges -ns 4.0.1..HEAD diff -Nru scons-4.0.1+dfsg/template/test.py scons-4.4.0+dfsg/template/test.py --- scons-4.0.1+dfsg/template/test.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/template/test.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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__" """ -XXX Put a description of the test here. +Template for end-to-end test file. +Replace this with a description of the test. """ import TestSCons @@ -36,7 +36,7 @@ env = Environment() """) -test.run(arguments = '.') +test.run(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/template/Tests.py scons-4.4.0+dfsg/template/Tests.py --- scons-4.0.1+dfsg/template/Tests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/template/Tests.py 2022-07-30 21:48:28.000000000 +0000 @@ -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,11 @@ # 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__" +""" +Template for unit-test file. +Replace this with a description of the test. +""" import unittest diff -Nru scons-4.0.1+dfsg/test/Actions/append.py scons-4.4.0+dfsg/test/Actions/append.py --- scons-4.0.1+dfsg/test/Actions/append.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Actions/append.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,17 +22,16 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# This test exercises the addition operator of Action objects. -# Using Environment.Prepend() and Environment.Append(), you should be -# able to add new actions to existing ones, effectively adding steps -# to a build process. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +""" +This test exercises the addition operator of Action objects. +Using Environment.Prepend() and Environment.Append(), you should be +able to add new actions to existing ones, effectively adding steps +to a build process. +""" import os import stat -import sys import TestSCons _exe = TestSCons._exe diff -Nru scons-4.0.1+dfsg/test/Actions/function.py scons-4.4.0+dfsg/test/Actions/function.py --- scons-4.0.1+dfsg/test/Actions/function.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Actions/function.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 sys @@ -59,6 +58,7 @@ ('literal_in_listcomp', 'Literal inside list comprehension', '2'), ) +DefaultEnvironment(tools=[]) optEnv = Environment(options=options, tools=[]) r = re.compile(optEnv['regexp']) @@ -67,25 +67,24 @@ r''' def toto(header='%(header)s', trailer='%(trailer)s'): xxx = %(closure_cell_value)s - def writeDeps(target, source, env, b=%(b)s, r=r %(extraarg)s , - header=header, trailer=trailer): + def writeDeps(target, source, env, b=%(b)s, r=r %(extraarg)s , header=header, trailer=trailer): """+'"""%(docstring)s"""'+""" def foo(b=b): return %(nestedfuncexp)s - f = open(str(target[0]),'wb') - f.write(bytearray(header,'utf-8')) - for d in env['ENVDEPS']: - f.write(bytearray(d+'%(separator)s','utf-8')) - f.write(bytearray(trailer+'\\n','utf-8')) - f.write(bytearray(str(foo())+'\\n','utf-8')) - f.write(bytearray(r.match('aaaa').group(1)+'\\n','utf-8')) - f.write(bytearray(str(sum([x*%(literal_in_listcomp)s for x in [1,2]]))+'\\n', 'utf-8')) - %(extracode)s - try: - f.write(bytearray(str(xarg),'utf-8')+b'\\n') - except NameError: - pass - f.close() + + with open(str(target[0]), 'wb') as f: + f.write(bytearray(header, 'utf-8')) + for d in env['ENVDEPS']: + f.write(bytearray(d+'%(separator)s', 'utf-8')) + f.write(bytearray(trailer+'\\n', 'utf-8')) + f.write(bytearray(str(foo())+'\\n', 'utf-8')) + f.write(bytearray(r.match('aaaa').group(1)+'\\n', 'utf-8')) + f.write(bytearray(str(sum([x*%(literal_in_listcomp)s for x in [1, 2]]))+'\\n', 'utf-8')) + %(extracode)s + try: + f.write(bytearray(str(xarg), 'utf-8')+b'\\n') + except NameError: + pass return writeDeps ''' @@ -93,13 +92,9 @@ exec(withClosure % optEnv) genHeaderBld = SCons.Builder.Builder( - action = SCons.Action.Action( - toto(), - 'Generating $TARGET', - varlist=['ENVDEPS'] - ), - suffix = '.gen.h' - ) + action=SCons.Action.Action(toto(), 'Generating $TARGET', varlist=['ENVDEPS']), + suffix='.gen.h', +) DefaultEnvironment(tools=[]) env = Environment(tools=[]) @@ -128,23 +123,22 @@ """ def runtest(arguments, expectedOutFile, expectedRebuild=True, stderr=""): - test.run(arguments=arguments, - stdout=expectedRebuild and rebuildstr or nobuildstr, - stderr="") + test.run( + arguments=arguments, + stdout=expectedRebuild and rebuildstr or nobuildstr, + stderr="", + ) sys.stdout.write('First Build.\n') test.must_match('Out.gen.h', expectedOutFile, message="First Build") - # Should not be rebuild when run a second time with the same - # arguments. - + # Should not be rebuild when run a second time with the same arguments. sys.stdout.write('Rebuild.\n') - test.run(arguments = arguments, stdout=nobuildstr, stderr="") + test.run(arguments=arguments, stdout=nobuildstr, stderr="") test.must_match('Out.gen.h', expectedOutFile, message="Should not rebuild") - # We're making this script chatty to prevent timeouts on really really # slow buildbot slaves (*cough* Solaris *cough*). diff -Nru scons-4.0.1+dfsg/test/Actions/pre-post.py scons-4.4.0+dfsg/test/Actions/pre-post.py --- scons-4.0.1+dfsg/test/Actions/pre-post.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Actions/pre-post.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,15 +22,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. -# -# This test exercises the AddPreAction() and AddPostAction() API -# functions, which add pre-build and post-build actions to nodes. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +""" +This test exercises the AddPreAction() and AddPostAction() API +functions, which add pre-build and post-build actions to nodes. +""" import os -import stat import TestSCons @@ -57,11 +57,8 @@ def after(env, target, source): t = str(target[0]) a = "after_" + t - fin = open(t, "rb") - fout = open(a, "wb") - fout.write(fin.read()) - fout.close() - fin.close() + with open(t, "rb") as fin, open(a, "wb") as fout: + fout.write(fin.read()) os.chmod(a, os.stat(a)[stat.ST_MODE] | stat.S_IXUSR) foo = env.Program(source='foo.c', target='foo') @@ -104,19 +101,22 @@ # work4 start test.write(['work4', 'SConstruct'], """\ - DefaultEnvironment(tools=[]) def pre_action(target, source, env): with open(str(target[0]), 'ab') as f: f.write(('pre %%s\\n' %% source[0]).encode()) + def post_action(target, source, env): with open(str(target[0]), 'ab') as f: f.write(('post %%s\\n' %% source[0]).encode()) + env = Environment(tools=[]) -o = env.Command(['pre-post', 'file.out'], - 'file.in', - r'%(_python_)s build.py ${TARGETS[1]} $SOURCE') +o = env.Command( + ['pre-post', 'file.out'], + 'file.in', + r'%(_python_)s build.py ${TARGETS[1]} $SOURCE' +) env.AddPreAction(o, pre_action) env.AddPostAction(o, post_action) """ % locals()) diff -Nru scons-4.0.1+dfsg/test/Actions/subst_shell_env-fixture/SConstruct scons-4.4.0+dfsg/test/Actions/subst_shell_env-fixture/SConstruct --- scons-4.0.1+dfsg/test/Actions/subst_shell_env-fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Actions/subst_shell_env-fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,38 @@ +import sys + +def custom_environment_expansion1(env, target, source, shell_env): + ENV = shell_env.copy() + ENV['EXPANDED_SHELL_VAR1'] = env.subst(env['ENV']['EXPANDED_SHELL_VAR1'], target=target, source=source) + return ENV + +def custom_environment_expansion2(env, target, source, shell_env): + ENV = shell_env.copy() + ENV['EXPANDED_SHELL_VAR2'] = env.subst(env['ENV']['EXPANDED_SHELL_VAR2'], target=target, source=source) + return ENV + +def expand_this_generator(env, target, source, for_signature): + return "I_got_expanded_to_" + str(target[0]) + +def expand_that_generator(env, target, source, for_signature): + return str(target[0]) + "_is_from_expansion" + +env = Environment(tools=['textfile']) + +env['SHELL_ENV_GENERATORS'] = [custom_environment_expansion1, custom_environment_expansion2] + +env['EXPAND_THIS'] = expand_this_generator +env['EXPAND_THAT'] = expand_that_generator + +env['ENV']['EXPANDED_SHELL_VAR1'] = "$EXPAND_THIS" +env['ENV']['EXPANDED_SHELL_VAR2'] = "$EXPAND_THAT" +env['ENV']['NON_EXPANDED_SHELL_VAR'] = "$EXPAND_THIS" + +env.Textfile('expand_script.py', [ + 'import os', + 'print(os.environ["EXPANDED_SHELL_VAR1"])', + 'print(os.environ["EXPANDED_SHELL_VAR2"])', + 'print(os.environ["NON_EXPANDED_SHELL_VAR"])', +]) +env.Command('out.txt', 'expand_script.py', fr'{sys.executable} $SOURCE > $TARGET') + +env.Depends('out.txt', env.Command('out2.txt', 'expand_script.py', fr'{sys.executable} $SOURCE > $TARGET')) diff -Nru scons-4.0.1+dfsg/test/Actions/subst_shell_env.py scons-4.4.0+dfsg/test/Actions/subst_shell_env.py --- scons-4.0.1+dfsg/test/Actions/subst_shell_env.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Actions/subst_shell_env.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,48 @@ +#!/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 shell environment variables can be expanded per target/source +when executing actions on the command line. +""" +import os + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('subst_shell_env-fixture') + +test.run(arguments = ['-Q']) +test.must_match('out.txt', f"I_got_expanded_to_out.txt{os.linesep}out.txt_is_from_expansion{os.linesep}$EXPAND_THIS{os.linesep}") +test.must_match('out2.txt', f"I_got_expanded_to_out2.txt{os.linesep}out2.txt_is_from_expansion{os.linesep}$EXPAND_THIS{os.linesep}") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/AddOption/args-and-targets.py scons-4.4.0+dfsg/test/AddOption/args-and-targets.py --- scons-4.0.1+dfsg/test/AddOption/args-and-targets.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/AddOption/args-and-targets.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# 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. + +""" +Verify that when an option is specified which takes args, +those do not end up treated as targets. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write( + 'SConstruct', + """\ +env = Environment() +AddOption( + '--extra', + nargs=1, + dest='extra', + action='store', + type='string', + metavar='ARG1', + default=(), + help='An argument to the option', +) +print(str(GetOption('extra'))) +print(COMMAND_LINE_TARGETS) +""", +) + +# arg using = +test.run('-Q -q --extra=A TARG', status=1, stdout="A\n['TARG']\n") +# arg not using = +test.run('-Q -q --extra A TARG', status=1, stdout="A\n['TARG']\n") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/AddOption/.exclude_tests scons-4.4.0+dfsg/test/AddOption/.exclude_tests --- scons-4.0.1+dfsg/test/AddOption/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/AddOption/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,4 @@ +# for now, the tests showing problems with processing space-separated +# arguments are excluded, pending an implementation that doesn't fail. +args-and-targets.py +multi-arg.py diff -Nru scons-4.0.1+dfsg/test/AddOption/longopts.py scons-4.4.0+dfsg/test/AddOption/longopts.py --- scons-4.0.1+dfsg/test/AddOption/longopts.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AddOption/longopts.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verifies that the default name matching of optparse for long options @@ -51,6 +50,16 @@ 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 [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: no such option: '--myargumen'. Did you mean '--myargument'? +""") + + test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/AddOption/multi-arg.py scons-4.4.0+dfsg/test/AddOption/multi-arg.py --- scons-4.0.1+dfsg/test/AddOption/multi-arg.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/AddOption/multi-arg.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# +# 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. + +""" +Verify that when an option is specified with nargs > 1, +SCons consumes those correctly into the args. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +# First, test an option with nargs=2 and no others: +test.write( + 'SConstruct', + """\ +env = Environment() +AddOption('--extras', + nargs=2, + dest='extras', + action='store', + type='string', + metavar='FILE1 FILE2', + default=(), + help='two extra files to install') +print(str(GetOption('extras'))) +""", +) + +# no args +test.run('-Q -q .', stdout="()\n") +# one arg, should fail +test.run( + '-Q -q . --extras A', + status=2, + stderr="""\ +usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: --extras option requires 2 arguments +""", +) +# two args +test.run('-Q -q . --extras A B', status=1, stdout="('A', 'B')\n") +# -- means the rest are not processed as args +test.run('-Q -q . -- --extras A B', status=1, stdout="()\n") + +# Now test what has been a bug: another option is +# also defined, this impacts the collection of args for the nargs>1 opt +test.write( + 'SConstruct', + """\ +env = Environment() +AddOption( + '--prefix', + nargs=1, + dest='prefix', + action='store', + type='string', + metavar='DIR', + help='installation prefix', +) +AddOption( + '--extras', + nargs=2, + dest='extras', + action='store', + type='string', + metavar='FILE1 FILE2', + default=(), + help='two extra files to install', +) +print(str(GetOption('prefix'))) +print(str(GetOption('extras'))) +""", +) + +# no options +test.run('-Q -q .', stdout="None\n()\n") +# one single-arg option +test.run('-Q -q . --prefix=/home/foo', stdout="/home/foo\n()\n") +# one two-arg option +test.run('-Q -q . --extras A B', status=1, stdout="None\n('A', 'B')\n") +# single-arg option followed by two-arg option +test.run( + '-Q -q . --prefix=/home/foo --extras A B', + status=1, + stdout="/home/foo\n('A', 'B')\n", +) +# two-arg option followed by single-arg option +test.run( + '-Q -q . --extras A B --prefix=/home/foo', + status=1, + stdout="/home/foo\n('A', 'B')\n", +) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/AR/ARFLAGS.py scons-4.4.0+dfsg/test/AR/ARFLAGS.py --- scons-4.0.1+dfsg/test/AR/ARFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AR/ARFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/AR/AR.py scons-4.4.0+dfsg/test/AR/AR.py --- scons-4.0.1+dfsg/test/AR/AR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AR/AR.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/AS/ASFLAGS.py scons-4.4.0+dfsg/test/AS/ASFLAGS.py --- scons-4.0.1+dfsg/test/AS/ASFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/ASFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/AS/ASPPFLAGS.py scons-4.4.0+dfsg/test/AS/ASPPFLAGS.py --- scons-4.0.1+dfsg/test/AS/ASPPFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/ASPPFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/AS/ASPP.py scons-4.4.0+dfsg/test/AS/ASPP.py --- scons-4.0.1+dfsg/test/AS/ASPP.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/ASPP.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/AS/AS.py scons-4.4.0+dfsg/test/AS/AS.py --- scons-4.0.1+dfsg/test/AS/AS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/AS.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ assembler (a wrapper we create). """ -import os -import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/AS/fixture/myas_args.py scons-4.4.0+dfsg/test/AS/fixture/myas_args.py --- scons-4.0.1+dfsg/test/AS/fixture/myas_args.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/fixture/myas_args.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,7 @@ import sys -if sys.platform == 'win32': + +def my_win32_as(): args = sys.argv[1:] inf = None optstring = '' @@ -21,25 +22,38 @@ out = a[3:] continue optstring = optstring + ' ' + a + with open(inf, 'rb') as ifp, open(out, 'wb') as ofp: - ofp.write(bytearray(optstring + "\n",'utf-8')) - for l in ifp.readlines(): - if l[:3] != b'#as': - ofp.write(l) - sys.exit(0) -else: + optstring = optstring + "\n" + ofp.write(optstring.encode('utf-8')) + for line in ifp: + if not line.startswith(b'#as'): + ofp.write(line) + + +def my_as(): import getopt + opts, args = getopt.getopt(sys.argv[1:], 'co:x') optstring = '' for opt, arg in opts: - if opt == '-o': out = arg - else: optstring = optstring + ' ' + opt + if opt == '-o': + out = arg + else: + optstring = optstring + ' ' + opt with open(args[0], 'rb') as ifp, open(out, 'wb') as ofp: - ofp.write(bytearray(optstring + "\n",'utf-8')) - for l in ifp.readlines(): - if l[:3] != b'#as': - ofp.write(l) + optstring = optstring + "\n" + ofp.write(optstring.encode('utf-8')) + for line in ifp: + if not line.startswith(b'#as'): + ofp.write(line) + +if __name__ == "__main__": + if sys.platform == 'win32': + my_win32_as() + else: + my_as() sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/AS/fixture/myas.py scons-4.4.0+dfsg/test/AS/fixture/myas.py --- scons-4.0.1+dfsg/test/AS/fixture/myas.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/AS/fixture/myas.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,7 @@ import sys -if sys.platform == 'win32': + +def my_win32_as(): args = sys.argv[1:] inf = None while args: @@ -10,29 +11,41 @@ args = args[2:] continue args = args[1:] - if not a[0] in "/-": + if not a[0] in '/-': if not inf: inf = a continue - if a[:3] == '/Fo': out = a[3:] + if a[:3] == '/Fo': + out = a[3:] + with open(inf, 'rb') as ifp, open(out, 'wb') as ofp: - for l in ifp.readlines(): - if l[:3] != b'#as': - ofp.write(l) - sys.exit(0) + for line in ifp: + if not line.startswith(b'#as'): + ofp.write(line) + -else: +def my_as(): import getopt + try: opts, args = getopt.getopt(sys.argv[1:], 'co:') except getopt.GetoptError: # we may be called with --version, just quit if so sys.exit(0) for opt, arg in opts: - if opt == '-o': out = arg + if opt == '-o': + out = arg + if args: with open(args[0], 'rb') as ifp, open(out, 'wb') as ofp: - for l in ifp.readlines(): - if l[:3] != b'#as': - ofp.write(l) + for line in ifp: + if not line.startswith(b'#as'): + ofp.write(line) + + +if __name__ == "__main__": + if sys.platform == 'win32': + my_win32_as() + else: + my_as() sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Builder/errors.py scons-4.4.0+dfsg/test/Builder/errors.py --- scons-4.0.1+dfsg/test/Builder/errors.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Builder/errors.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test the ability to catch Builder creation with poorly specified Actions. """ -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/file.in scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/file.in --- scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/file.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/file.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +file.in diff -Nru scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/SConstruct scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/SConstruct --- scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,12 @@ +import SCons +class CustomCacheDir(SCons.CacheDir.CacheDir): + + @classmethod + def copy_to_cache(cls, env, src, dst): + print("MY_CUSTOM_CACHEDIR_CLASS") + super().copy_to_cache(env, src, dst) + +env = Environment(tools=[]) +env['CACHEDIR_CLASS'] = CustomCacheDir +env.CacheDir('cache') +env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS.py scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS.py --- scons-4.0.1+dfsg/test/CacheDir/CACHEDIR_CLASS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/CACHEDIR_CLASS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# 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. +# + +""" +Test testing the CACHEDIR_CLASS construction variable. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('CACHEDIR_CLASS_fixture') + +test.run() + +test.must_contain_all_lines(test.stdout(), ["MY_CUSTOM_CACHEDIR_CLASS"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/CacheDir/CacheDir_TryCompile.py scons-4.4.0+dfsg/test/CacheDir/CacheDir_TryCompile.py --- scons-4.0.1+dfsg/test/CacheDir/CacheDir_TryCompile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/CacheDir_TryCompile.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,7 +32,6 @@ which ended up a mixture of bytes and strings. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/custom_cachedir_fixture/file.in scons-4.4.0+dfsg/test/CacheDir/custom_cachedir_fixture/file.in --- scons-4.0.1+dfsg/test/CacheDir/custom_cachedir_fixture/file.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/custom_cachedir_fixture/file.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +file.in diff -Nru scons-4.0.1+dfsg/test/CacheDir/custom_cachedir_fixture/SConstruct scons-4.4.0+dfsg/test/CacheDir/custom_cachedir_fixture/SConstruct --- scons-4.0.1+dfsg/test/CacheDir/custom_cachedir_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/custom_cachedir_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,11 @@ +import SCons +class CustomCacheDir(SCons.CacheDir.CacheDir): + + @classmethod + def copy_to_cache(cls, env, src, dst): + print("MY_CUSTOM_CACHEDIR_CLASS") + super().copy_to_cache(env, src, dst) + +env = Environment(tools=[]) +env.CacheDir('cache', CustomCacheDir) +env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/CacheDir/CustomCacheDir.py scons-4.4.0+dfsg/test/CacheDir/CustomCacheDir.py --- scons-4.0.1+dfsg/test/CacheDir/CustomCacheDir.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/CustomCacheDir.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# 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. +# + +""" +Test that a custom cache dir can be passed to SCons. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('custom_cachedir_fixture') + +test.run() + +test.must_contain_all_lines(test.stdout(), ["MY_CUSTOM_CACHEDIR_CLASS"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/CacheDir/DoubleCachedirClass.py scons-4.4.0+dfsg/test/CacheDir/DoubleCachedirClass.py --- scons-4.0.1+dfsg/test/CacheDir/DoubleCachedirClass.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/DoubleCachedirClass.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# 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. +# + +""" +Test that cache dir is reinitialized correctly when two cachedirs are in use +and also that the cachedirs are isolated to their own environments. + +The core of the test is: +----------------------------------------- +env = Environment(tools=[]) +env.CacheDir('cache1', CustomCacheDir1) +env.CacheDir('cache2', CustomCacheDir2) + +cloned = env.Clone() +cloned.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) + +env.CacheDir('cache1', CustomCacheDir1) +----------------------------------------- + +Where each cachedir is printing its own name in an overridden copy_to_cache function, so +since the only command putting something to cache is in the cloned environment, we should +see only cachedir2 print since that was initialized for that env when the clone happened. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('double_cachedir_fixture') + +test.run() + +test.must_contain_single_instance_of(test.stdout(), ["INSTANCIATED CustomCacheDir2"]) +test.must_contain_single_instance_of(test.stdout(), ["MY_CUSTOM_CACHEDIR_CLASS2"]) +test.must_not_contain_any_line(test.stdout(), ["MY_CUSTOM_CACHEDIR_CLASS1"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/CacheDir/double_cachedir_fixture/file.in scons-4.4.0+dfsg/test/CacheDir/double_cachedir_fixture/file.in --- scons-4.0.1+dfsg/test/CacheDir/double_cachedir_fixture/file.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/double_cachedir_fixture/file.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +file.in diff -Nru scons-4.0.1+dfsg/test/CacheDir/double_cachedir_fixture/SConstruct scons-4.4.0+dfsg/test/CacheDir/double_cachedir_fixture/SConstruct --- scons-4.0.1+dfsg/test/CacheDir/double_cachedir_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/double_cachedir_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,36 @@ +import SCons +class CustomCacheDir1(SCons.CacheDir.CacheDir): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + print("INSTANCIATED %s" % str(type(self).__name__)) + + @classmethod + def copy_to_cache(cls, env, src, dst): + print("MY_CUSTOM_CACHEDIR_CLASS1") + super().copy_to_cache(env, src, dst) + +class CustomCacheDir2(SCons.CacheDir.CacheDir): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + print("INSTANCIATED %s" % str(type(self).__name__)) + + @classmethod + def copy_to_cache(cls, env, src, dst): + print("MY_CUSTOM_CACHEDIR_CLASS2") + super().copy_to_cache(env, src, dst) + +env = Environment(tools=[]) +env.CacheDir('cache1', CustomCacheDir1) +env.CacheDir('cache2', CustomCacheDir2) + +# two cachedirs were initialized, but the second one was the most recent +# and should remain in the cloned environment, even when we switch the +# original environment back. The cachedir2 should be the only copy_to_cache +# function we call. +cloned = env.Clone() +cloned.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) + +env.CacheDir('cache1', CustomCacheDir1) + diff -Nru scons-4.0.1+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/file.in scons-4.4.0+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/file.in --- scons-4.0.1+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/file.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/file.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +file.in diff -Nru scons-4.0.1+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/SConstruct scons-4.4.0+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/SConstruct --- scons-4.0.1+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/invalid_custom_cachedir_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +class CustomCacheDir: + pass + +env = Environment(tools=[]) +env.CacheDir('cache', CustomCacheDir) +env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/CacheDir/InvalidCustomCacheDir.py scons-4.4.0+dfsg/test/CacheDir/InvalidCustomCacheDir.py --- scons-4.0.1+dfsg/test/CacheDir/InvalidCustomCacheDir.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/InvalidCustomCacheDir.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# 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. +# + +""" +Test to make sure invalid custom cachedir cause error. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('invalid_custom_cachedir_fixture') + +test.run(status = 2, stderr = None) + +test.must_contain_all_lines(test.stderr(), ["Custom CACHEDIR_CLASS not derived from CacheDir"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/CacheDir/multiple-targets.py scons-4.4.0+dfsg/test/CacheDir/multiple-targets.py --- scons-4.0.1+dfsg/test/CacheDir/multiple-targets.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/multiple-targets.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,8 +28,6 @@ Test that multiple target files get retrieved from a CacheDir correctly. """ -import os.path -import shutil import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/NoCache.py scons-4.4.0+dfsg/test/CacheDir/NoCache.py --- scons-4.0.1+dfsg/test/CacheDir/NoCache.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/NoCache.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,7 @@ Verify that the NoCache environment method works. """ -import TestSCons, os.path +import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/CacheDir/option--cd.py scons-4.4.0+dfsg/test/CacheDir/option--cd.py --- scons-4.0.1+dfsg/test/CacheDir/option--cd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/option--cd.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ CacheDir. """ -import os.path -import shutil import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/option--cr.py scons-4.4.0+dfsg/test/CacheDir/option--cr.py --- scons-4.0.1+dfsg/test/CacheDir/option--cr.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/option--cr.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ CacheDir. It should retrieve as normal but not update files. """ -import os.path -import shutil import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/option--cs.py scons-4.4.0+dfsg/test/CacheDir/option--cs.py --- scons-4.0.1+dfsg/test/CacheDir/option--cs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/option--cs.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ retrieving derived files from a CacheDir. """ -import os.path -import shutil import TestSCons diff -Nru scons-4.0.1+dfsg/test/CacheDir/readonly-cache.py scons-4.4.0+dfsg/test/CacheDir/readonly-cache.py --- scons-4.0.1+dfsg/test/CacheDir/readonly-cache.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/readonly-cache.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,7 +32,6 @@ import os import TestSCons import time -from stat import * test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/CacheDir/scanner-target.py scons-4.4.0+dfsg/test/CacheDir/scanner-target.py --- scons-4.0.1+dfsg/test/CacheDir/scanner-target.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/scanner-target.py 2022-07-30 21:48:28.000000000 +0000 @@ -31,8 +31,6 @@ been cleared (as a sign that the built file should now be rescanned). """ -import os.path -import shutil import TestSCons @@ -55,11 +53,9 @@ print('This is never called (unless we build file.out)') return [] -SillyScanner = SCons.Scanner.Base(function = sillyScanner, skeys = ['.res']) +SillyScanner = SCons.Scanner.ScannerBase(function=sillyScanner, skeys=['.res']) -env = Environment(tools=[], - SCANNERS = [SillyScanner], - BUILDERS = {}) +env = Environment(tools=[], SCANNERS=[SillyScanner], BUILDERS={}) r = env.Command('file.res', 'file.ma', docopy) diff -Nru scons-4.0.1+dfsg/test/CacheDir/source-scanner.py scons-4.4.0+dfsg/test/CacheDir/source-scanner.py --- scons-4.0.1+dfsg/test/CacheDir/source-scanner.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/source-scanner.py 2022-07-30 21:48:28.000000000 +0000 @@ -57,11 +57,9 @@ print('This is never called (unless we build file.out)') return [] -SillyScanner = SCons.Scanner.Base(function = sillyScanner, skeys = ['.res']) +SillyScanner = SCons.Scanner.ScannerBase(function=sillyScanner, skeys=['.res']) -env = Environment(tools=[], - SCANNERS = [SillyScanner], - BUILDERS = {}) +env = Environment(tools=[], SCANNERS=[SillyScanner], BUILDERS={}) r = env.Command('file.res', 'file.ma', docopy) diff -Nru scons-4.0.1+dfsg/test/CacheDir/timestamp-match.py scons-4.4.0+dfsg/test/CacheDir/timestamp-match.py --- scons-4.0.1+dfsg/test/CacheDir/timestamp-match.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/timestamp-match.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that CAcheDir() works when using 'timestamp-match' decisions. @@ -41,21 +40,15 @@ test.write('file.in', "file.in\n") -test.run(arguments = '--cache-show --debug=explain .') - +test.run(arguments='--cache-show --debug=explain .') test.must_match('file.out', "file.in\n") +test.up_to_date(options='--cache-show --debug=explain', arguments='.') -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.sleep() - +test.sleep() # delay for timestamps test.touch('file.in') - -test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') +test.not_up_to_date(options='--cache-show --debug=explain', arguments='.') +test.up_to_date(options='--cache-show --debug=explain', arguments='.') +test.up_to_date(options='--cache-show --debug=explain', arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/CacheDir/timestamp-newer.py scons-4.4.0+dfsg/test/CacheDir/timestamp-newer.py --- scons-4.0.1+dfsg/test/CacheDir/timestamp-newer.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CacheDir/timestamp-newer.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that CAcheDir() works when using 'timestamp-newer' decisions. @@ -41,21 +40,16 @@ test.write('file.in', "file.in\n") -test.run(arguments = '--cache-show --debug=explain .') - +test.run(arguments='--cache-show --debug=explain .') test.must_match('file.out', "file.in\n") +test.up_to_date(options='--cache-show --debug=explain', arguments='.') -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.sleep() - +test.sleep() # delay for timestamps test.touch('file.in') -test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') - -test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') +test.not_up_to_date(options='--cache-show --debug=explain', arguments='.') +test.up_to_date(options='--cache-show --debug=explain', arguments='.') +test.up_to_date(options='--cache-show --debug=explain', arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/CC/CC-fixture/.exclude_tests scons-4.4.0+dfsg/test/CC/CC-fixture/.exclude_tests --- scons-4.0.1+dfsg/test/CC/CC-fixture/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CC-fixture/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +mycc.py diff -Nru scons-4.0.1+dfsg/test/CC/CC-fixture/mycc.py scons-4.4.0+dfsg/test/CC/CC-fixture/mycc.py --- scons-4.0.1+dfsg/test/CC/CC-fixture/mycc.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CC-fixture/mycc.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,55 @@ +""" +Phony cc command for testing SCons. + +Copies its source file to the target file, dropping lines that match +a pattern, so we can recognize the tool has made a modification. +Intended for use as the $CXX construction variable. + +Note: mycc.py differs from the general fixture file mycompile.py +in arg handling: that one is intended for use as a *COM consvar, +where no compiler consvars will be passed on, this one is intended +for use as $CC, where arguments like -o come into play. +""" +import getopt +import sys + +def fake_win32_cc(): + args = sys.argv[1:] + inf = None + while args: + arg = args[0] + if arg == '-o': + out = args[1] + args = args[2:] + continue + args = args[1:] + if arg[0] not in '/-': + if not inf: + inf = arg + continue + if arg.startswith('/Fo'): + out = arg[3:] + + with open(inf, 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*cc*/'): + outfile.write(line) + +def fake_cc(): + opts, args = getopt.getopt(sys.argv[1:], 'co:') + for opt, arg in opts: + if opt == '-o': + out = arg + + with open(args[0], 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*cc*/'): + outfile.write(line) + +if __name__ == '__main__': + print(f"DEBUG: {sys.argv[0]}: {sys.argv[1:]}") + if sys.platform == 'win32': + fake_win32_cc() + else: + fake_cc() + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/CC/CC-fixture/test1.c scons-4.4.0+dfsg/test/CC/CC-fixture/test1.c --- scons-4.0.1+dfsg/test/CC/CC-fixture/test1.c 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CC-fixture/test1.c 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,3 @@ This is a .c file. /*cc*/ -/*link*/ +#link diff -Nru scons-4.0.1+dfsg/test/CC/CC-fixture/test2.C scons-4.4.0+dfsg/test/CC/CC-fixture/test2.C --- scons-4.0.1+dfsg/test/CC/CC-fixture/test2.C 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CC-fixture/test2.C 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,3 @@ This is a .C file. /*cc*/ -/*link*/ +#link diff -Nru scons-4.0.1+dfsg/test/CC/CC.py scons-4.4.0+dfsg/test/CC/CC.py --- scons-4.0.1+dfsg/test/CC/CC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,106 +22,29 @@ # 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 TestSCons _python_ = TestSCons._python_ -_exe = TestSCons._exe +_exe = TestSCons._exe test = TestSCons.TestSCons() test.dir_fixture('CC-fixture') - -if sys.platform == 'win32': - - test.write('mylink.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-o': - out = args[1] - args = args[2:] - continue - if not a[0] in '/-': - break - args = args[1:] - if a[:5].lower() == '/out:': out = a[5:] -infile = open(args[0], 'rb') -outfile = open(out, 'wb') -for l in infile.readlines(): - if l[:8] != b'/*link*/': - outfile.write(l) -sys.exit(0) -""") - - test.write('mycc.py', r""" -import sys -args = sys.argv[1:] -inf = None -while args: - a = args[0] - if a == '-o': - out = args[1] - args = args[2:] - continue - args = args[1:] - if not a[0] in '-/': - if not inf: - inf = a - continue - if a[:3] == '/Fo': out = a[3:] -infile = open(inf, 'rb') -outfile = open(out, 'wb') -for l in infile.readlines(): - if l[:6] != b'/*cc*/': - outfile.write(l) -sys.exit(0) -""") - -else: - - test.write('mylink.py', r""" -import getopt -import sys -opts, args = getopt.getopt(sys.argv[1:], 'o:') -for opt, arg in opts: - if opt == '-o': out = arg -infile = open(args[0], 'rb') -outfile = open(out, 'wb') -for l in infile.readlines(): - if l[:8] != b'/*link*/': - outfile.write(l) -sys.exit(0) -""") - - test.write('mycc.py', r""" -import getopt -import sys -opts, args = getopt.getopt(sys.argv[1:], 'co:') -for opt, arg in opts: - if opt == '-o': out = arg -infile = open(args[0], 'rb') -outfile = open(out, 'wb') -for l in infile.readlines(): - if l[:6] != b'/*cc*/': - outfile.write(l) -sys.exit(0) -""") +test.file_fixture('mylink.py') test.write('SConstruct', """ cc = Environment().Dictionary('CC') -env = Environment(LINK = r'%(_python_)s mylink.py', - LINKFLAGS = [], - CC = r'%(_python_)s mycc.py', - CXX = cc, - CXXFLAGS = []) -env.Program(target = 'test1', source = 'test1.c') +env = Environment( + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + CC=r'%(_python_)s mycc.py', + CXX=cc, + CXXFLAGS=[], +) +env.Program(target='test1', source='test1.c') """ % locals()) test.run(arguments = '.', stderr = None) @@ -130,10 +55,12 @@ test.write('SConstruct', """ cc = Environment().Dictionary('CC') -env = Environment(LINK = r'%(_python_)s mylink.py', - CC = r'%(_python_)s mycc.py', - CXX = cc) -env.Program(target = 'test2', source = 'test2.C') +env = Environment( + LINK=r'%(_python_)s mylink.py', + CC=r'%(_python_)s mycc.py', + CXX=cc, +) +env.Program(target='test2', source='test2.C') """ % locals()) test.run(arguments = '.', stderr = None) @@ -144,9 +71,9 @@ test.write('SConstruct', """ foo = Environment() cc = foo.Dictionary('CC') -bar = Environment(CC = r'%(_python_)s wrapper.py ' + cc) -foo.Program(target = 'foo', source = 'foo.c') -bar.Program(target = 'bar', source = 'bar.c') +bar = Environment(CC=r'%(_python_)s wrapper.py ' + cc) +foo.Program(target='foo', source='foo.c') +bar.Program(target='bar', source='bar.c') """ % locals()) test.run(arguments = 'foo' + _exe) diff -Nru scons-4.0.1+dfsg/test/CC/CCVERSION.py scons-4.4.0+dfsg/test/CC/CCVERSION.py --- scons-4.0.1+dfsg/test/CC/CCVERSION.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/CCVERSION.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/data scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/data --- scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/data 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/data 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,10 @@ +gcc (tdm-1) 9.2.0 +Copyright (C) 2019 Free Software Foundation, Inc. +Ýòî ñâîáîäíî ðàñïðîñòðàíÿåìîå ïðîãðàììíîå îáåñïå÷åíèå. Óñëîâèÿ êîïèðîâàíèÿ +ïðèâåäåíû â èñõîäíûõ òåêñòàõ. + + Áåç ãàðàíòèè êàêèõ-ëèáî êà÷åñòâ, âêëþ÷àÿ +êîììåð÷åñêóþ öåííîñòü è ïðèìåíèìîñòü äëÿ êàêèõ-ëèáî öåëåé. + + + diff -Nru scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/.exclude_tests scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/.exclude_tests --- scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,2 @@ +data +gcc-non-utf8.py diff -Nru scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/gcc-non-utf8.py scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/gcc-non-utf8.py --- scons-4.0.1+dfsg/test/CC/gcc-non-utf8-fixture/gcc-non-utf8.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/gcc-non-utf8-fixture/gcc-non-utf8.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +import sys + +if __name__ == '__main__': + if '--version' in sys.argv: + with open("data", "rb") as f: + sys.stdout.buffer.write(f.read()) diff -Nru scons-4.0.1+dfsg/test/CC/gcc-version.py scons-4.4.0+dfsg/test/CC/gcc-version.py --- scons-4.0.1+dfsg/test/CC/gcc-version.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/gcc-version.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that if gcc returns non-UTF8 text, the version check doesn't fall over. +""" + +import sys + +import TestSCons + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +test = TestSCons.TestSCons() + +test.dir_fixture('gcc-non-utf8-fixture') + +test.write( + 'SConstruct', + """ +import sys + +DefaultEnvironment(tools=[]) +env = Environment(tools=[], CC=r"%(_python_)s gcc-non-utf8.py") +try: + env.Tool('gcc') +except UnicodeDecodeError: + print("Failed decoding gcc version message.", file=sys.stderr) + Exit(1) +""" + % locals(), +) + +test.run(arguments='.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/CC/SHCCFLAGS.py scons-4.4.0+dfsg/test/CC/SHCCFLAGS.py --- scons-4.0.1+dfsg/test/CC/SHCCFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/SHCCFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -40,6 +40,7 @@ os.environ['LD_LIBRARYN32_PATH'] = '.' test.write('SConstruct', """ +DefaultEnvironment(tools=[]) foo = Environment(SHCCFLAGS = '%s', WINDOWS_INSERT_DEF=1) bar = Environment(SHCCFLAGS = '%s', WINDOWS_INSERT_DEF=1) diff -Nru scons-4.0.1+dfsg/test/CC/SHCC.py scons-4.4.0+dfsg/test/CC/SHCC.py --- scons-4.0.1+dfsg/test/CC/SHCC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CC/SHCC.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/CFILESUFFIX.py scons-4.4.0+dfsg/test/CFILESUFFIX.py --- scons-4.0.1+dfsg/test/CFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,15 +22,11 @@ # 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__" """ Verify that we can set CFILESUFFIX to arbitrary values. """ -import os import TestSCons @@ -36,32 +34,19 @@ test = TestSCons.TestSCons() -test.write('mylex.py', """ -import getopt -import sys -if sys.platform == 'win32': - longopts = ['nounistd'] -else: - longopts = [] -cmd_opts, args = getopt.getopt(sys.argv[1:], 't', longopts) -for a in args: - with open(a, 'rb') as f: - contents = f.read() - sys.stdout.write((contents.replace(b'LEX', b'mylex.py')).decode()) -sys.exit(0) -""") +test.file_fixture('mylex.py') test.write('SConstruct', """ -env = Environment(LEX = r'%(_python_)s mylex.py', tools = ['lex']) -env.CFile(target = 'foo', source = 'foo.l') -env.Clone(CFILESUFFIX = '.xyz').CFile(target = 'bar', source = 'bar.l') +env = Environment(LEX=r'%(_python_)s mylex.py', tools=['lex']) +env.CFile(target='foo', source='foo.l') +env.Clone(CFILESUFFIX='.xyz').CFile(target='bar', source='bar.l') # Make sure that calling a Tool on a construction environment *after* # we've set CFILESUFFIX doesn't overwrite the value. -env2 = Environment(tools = [], CFILESUFFIX = '.env2') +env2 = Environment(tools=[], CFILESUFFIX='.env2') env2.Tool('lex') env2['LEX'] = r'%(_python_)s mylex.py' -env2.CFile(target = 'f3', source = 'f3.l') +env2.CFile(target='f3', source='f3.l') """ % locals()) input = r""" diff -Nru scons-4.0.1+dfsg/test/chained-build.py scons-4.4.0+dfsg/test/chained-build.py --- scons-4.0.1+dfsg/test/chained-build.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/chained-build.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 TestSCons @@ -58,23 +57,20 @@ test.write(['w1', 'SConstruct2'], SConstruct2_contents) test.write(['w1', 'foo.in'], "foo.in 1") -test.run(chdir='w1', - arguments="--max-drift=0 -f SConstruct1 foo.mid", - stdout = test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n')) - -test.run(chdir='w1', - arguments="--max-drift=0 -f SConstruct2 foo.out", - stdout = test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n')) - -test.up_to_date(chdir='w1', - options="--max-drift=0 -f SConstruct1", - arguments="foo.mid") +test.run( + chdir='w1', + arguments="--max-drift=0 -f SConstruct1 foo.mid", + stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'), +) +test.run( + chdir='w1', + arguments="--max-drift=0 -f SConstruct2 foo.out", + stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'), +) +test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct1", arguments="foo.mid") +test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct2", arguments="foo.out") -test.up_to_date(chdir='w1', - options="--max-drift=0 -f SConstruct2", - arguments="foo.out") - -test.sleep() # make sure foo.in rewrite has new mod-time +test.sleep() # delay for timestamps test.write(['w1', 'foo.in'], "foo.in 2") # Because we're using --max-drift=0, we use the cached csig value @@ -86,17 +82,19 @@ # Now try with --max-drift disabled. The build of foo.out should still # be considered up-to-date, but the build of foo.mid now detects the # change and rebuilds, too, which then causes a rebuild of foo.out. -test.up_to_date(chdir='w1', - options="--max-drift=-1 -f SConstruct2", - arguments="foo.out") - -test.run(chdir='w1', - arguments="--max-drift=-1 -f SConstruct1 foo.mid", - stdout = test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n')) - -test.run(chdir='w1', - arguments="--max-drift=-1 -f SConstruct2 foo.out", - stdout = test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n')) +test.up_to_date( + chdir='w1', options="--max-drift=-1 -f SConstruct2", arguments="foo.out" +) +test.run( + chdir='w1', + arguments="--max-drift=-1 -f SConstruct1 foo.mid", + stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'), +) +test.run( + chdir='w1', + arguments="--max-drift=-1 -f SConstruct2 foo.out", + stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'), +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Clang/clang_shared_library.py scons-4.4.0+dfsg/test/Clang/clang_shared_library.py --- scons-4.0.1+dfsg/test/Clang/clang_shared_library.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Clang/clang_shared_library.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -22,8 +24,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons from SCons.Environment import Base diff -Nru scons-4.0.1+dfsg/test/Clean/Option.py scons-4.4.0+dfsg/test/Clean/Option.py --- scons-4.0.1+dfsg/test/Clean/Option.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Clean/Option.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ cleaning behavior. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/CommandGenerator.py scons-4.4.0+dfsg/test/CommandGenerator.py --- scons-4.0.1+dfsg/test/CommandGenerator.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CommandGenerator.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/CompilationDatabase/fixture/SConstruct_variant scons-4.4.0+dfsg/test/CompilationDatabase/fixture/SConstruct_variant --- scons-4.0.1+dfsg/test/CompilationDatabase/fixture/SConstruct_variant 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CompilationDatabase/fixture/SConstruct_variant 2022-07-30 21:48:28.000000000 +0000 @@ -32,6 +32,10 @@ env.CompilationDatabase('compile_commands_over_abs_1.json', COMPILATIONDB_USE_ABSPATH=1) env.CompilationDatabase('compile_commands_over_abs_0.json', COMPILATIONDB_USE_ABSPATH=0) +# Try filter for build and build2 output +env.CompilationDatabase('compile_commands_filter_build.json', COMPILATIONDB_PATH_FILTER='build/*') +env.CompilationDatabase('compile_commands_filter_build2.json', COMPILATIONDB_PATH_FILTER='build2/*') + env.VariantDir('build','src') env.Program('build/main', 'build/test_main.c') diff -Nru scons-4.0.1+dfsg/test/CompilationDatabase/variant_dir.py scons-4.4.0+dfsg/test/CompilationDatabase/variant_dir.py --- scons-4.0.1+dfsg/test/CompilationDatabase/variant_dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CompilationDatabase/variant_dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -56,6 +56,14 @@ 'compile_commands_over_abs_1.json', ] +filter_build_files = [ + 'compile_commands_filter_build.json', +] + +filter_build2_files = [ + 'compile_commands_filter_build2.json', +] + example_rel_file = """[ { "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", @@ -115,4 +123,45 @@ test.must_exist(f) test.must_match(f, example_abs_file, mode='r') +example_filter_build_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output_file': os.path.join('build', 'test_main.o'), + 'variant_src_file': os.path.join('build', 'test_main.c') + } + +if sys.platform == 'win32': + example_filter_build_file = example_filter_build_file.replace('\\', '\\\\') + +for f in filter_build_files: + test.must_exist(f) + test.must_match(f, example_filter_build_file, mode='r') + +example_filter_build2_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output2_file)s -c %(src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output2_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output2_file': os.path.join('build2', 'test_main.o'), + } + +if sys.platform == 'win32': + example_filter_build2_file = example_filter_build2_file.replace('\\', '\\\\') + +for f in filter_build2_files: + test.must_exist(f) + test.must_match(f, example_filter_build2_file, mode='r') + test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Configure/config-h.py scons-4.4.0+dfsg/test/Configure/config-h.py --- scons-4.0.1+dfsg/test/Configure/config-h.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/config-h.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -25,9 +26,7 @@ Verify creation of a config.h file from a Configure context. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import re import TestSCons @@ -47,6 +46,10 @@ r3 = conf.CheckFunc('memmove') r4 = conf.CheckType('int') r5 = conf.CheckType('noType') + +m1 = conf.CheckMember('struct timespec.tv_sec', '#include ') +m2 = conf.CheckMember('struct timespec.tv_nanosec', '#include ') + r6 = conf.CheckCHeader('stdio.h', '<>') r7 = conf.CheckCHeader('hopefullynoc-header.h') r8 = conf.CheckCXXHeader('vector', '<>') @@ -67,6 +70,8 @@ Checking for C function memmove()... yes Checking for C type int... yes Checking for C type noType... no +Checking for C member struct timespec.tv_sec... yes +Checking for C member struct timespec.tv_nanosec... no Checking for C header file stdio.h... yes Checking for C header file hopefullynoc-header.h... no Checking for C++ header file vector... yes @@ -105,6 +110,12 @@ /* Define to 1 if the system has the type `noType'. */ /* #undef HAVE_NOTYPE */ +/* Define to 1 if the system has the member `struct timespec.tv_sec`. */ +#define HAVE_STRUCT_TIMESPEC_TV_SEC 1 + +/* Define to 1 if the system has the member `struct timespec.tv_nanosec`. */ +/* #undef HAVE_STRUCT_TIMESPEC_TV_NANOSEC */ + /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 diff -Nru scons-4.0.1+dfsg/test/Configure/ConfigureDryRunError.py scons-4.4.0+dfsg/test/Configure/ConfigureDryRunError.py --- scons-4.0.1+dfsg/test/Configure/ConfigureDryRunError.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/ConfigureDryRunError.py 2022-07-30 21:48:28.000000000 +0000 @@ -31,6 +31,8 @@ import TestSCons +from SCons.Util import get_current_hash_algorithm_used + _obj = TestSCons._obj test = TestSCons.TestSCons() @@ -65,7 +67,16 @@ test.must_not_exist('config.log') test.subdir('.sconf_temp') -conftest_0_c = os.path.join(".sconf_temp", "conftest_df286a1d2f67e69d030b4eff75ca7e12_0.c") +# depending on which default hash function we're using, we'd expect one of the following filenames. +# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files +possible_filenames = { + 'md5': "conftest_df286a1d2f67e69d030b4eff75ca7e12_0.c", + 'sha1': "conftest_6e784ac3248d146c68396335df2f9428d78c1d24_0.c", + 'sha256': "conftest_be4b3c1d600e20dfc3e8d98748cd8193c850331643466d800ef8a4229a5be410_0.c" +} +test_filename = possible_filenames[get_current_hash_algorithm_used()] + +conftest_0_c = os.path.join(".sconf_temp", test_filename) SConstruct_file_line = test.python_file_line(SConstruct_path, 6)[:-1] expect = """ diff -Nru scons-4.0.1+dfsg/test/Configure/implicit-cache.py scons-4.4.0+dfsg/test/Configure/implicit-cache.py --- scons-4.0.1+dfsg/test/Configure/implicit-cache.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/implicit-cache.py 2022-07-30 21:48:28.000000000 +0000 @@ -55,6 +55,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSConsign +from SCons.Util import get_hash_format, get_current_hash_algorithm_used test = TestSConsign.TestSConsign() @@ -75,7 +76,28 @@ test.run(arguments = '.') -test.run_sconsign('-d .sconf_temp -e conftest_5a3fa36d51dd2a28d521d6cc0e2e1d04_0.c --raw .sconsign.dblite') +# depending on which default hash function we're using, we'd expect one of the following filenames. +# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files +# this test is different than the other tests, as the database name is used here. +# when the database defaults to md5, that's a different name than when the user selects md5 directly. +possible_filenames = { + 'default': "conftest_5a3fa36d51dd2a28d521d6cc0e2e1d04_0.c", + 'md5': "conftest_5a3fa36d51dd2a28d521d6cc0e2e1d04_0.c", + 'sha1': "conftest_80e5b88f2c7427a92f0e6c7184f144f874f10e60_0.c", + 'sha256': "conftest_ba8270c26647ad00993cd7777f4c5d3751018372b97d16eb993563bea051c3df_0.c" +} +# user left algorithm default, it defaulted to md5, with the special database name +if get_hash_format() is None and get_current_hash_algorithm_used() == 'md5': + test_filename = possible_filenames['default'] +# either user selected something (like explicitly setting md5) or algorithm defaulted to something else. +# SCons can default to something else if it detects the hashlib doesn't support it, example md5 in FIPS +# mode prior to Python 3.9 +else: + test_filename = possible_filenames[get_current_hash_algorithm_used()] + +database_name=test.get_sconsignname() + ".dblite" + +test.run_sconsign('-d .sconf_temp -e {} --raw {}'.format(test_filename, database_name)) old_sconsign_dblite = test.stdout() # Second run: Have the configure subsystem also look for foo.h, so @@ -88,11 +110,11 @@ test.run(arguments = '--implicit-cache USE_FOO=1 .') -test.run_sconsign('-d .sconf_temp -e conftest_5a3fa36d51dd2a28d521d6cc0e2e1d04_0.c --raw .sconsign.dblite') +test.run_sconsign('-d .sconf_temp -e {} --raw {}'.format(test_filename, database_name)) new_sconsign_dblite = test.stdout() if old_sconsign_dblite != new_sconsign_dblite: - print(".sconsign.dblite did not match:") + print("{} did not match:".format(database_name)) print("FIRST RUN ==========") print(old_sconsign_dblite) print("SECOND RUN ==========") diff -Nru scons-4.0.1+dfsg/test/Configure/is_conftest/fixture/SConstruct scons-4.4.0+dfsg/test/Configure/is_conftest/fixture/SConstruct --- scons-4.0.1+dfsg/test/Configure/is_conftest/fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/is_conftest/fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,24 @@ +""" +Test the nodes are created as conftest nodes in configure tests. +""" +import sys +DefaultEnvironment(tools=[]) + +env = Environment() + +conf = Configure(env) +if sys.platform == "win32": + conf.env.Append( + CCFLAGS="/DEBUG /Z7 /INCREMENTAL:NO", + LINKFLAGS="/DEBUG /INCREMENTAL:NO", + PDB='${TARGET.base}.pdb') +if not conf.TryRun("int main( int argc, char* argv[] ){return 0;}", '.c'): + print("FAIL") + +env = conf.Finish() + +for node in env.Glob(conf.confdir.path + '/*'): + if not node.is_conftest(): + print("FAIL") + + diff -Nru scons-4.0.1+dfsg/test/Configure/is_conftest/is_conftest.py scons-4.4.0+dfsg/test/Configure/is_conftest/is_conftest.py --- scons-4.0.1+dfsg/test/Configure/is_conftest/is_conftest.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/is_conftest/is_conftest.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# 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. + +""" +Verify is_conftest is marking nodes, even for intermediate files. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.file_fixture('./fixture/SConstruct') + +test.run('-Q --silent') + +if "FAIL" in test.stdout(): + test.fail_test() + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Configure/option--config.py scons-4.4.0+dfsg/test/Configure/option--config.py --- scons-4.0.1+dfsg/test/Configure/option--config.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/option--config.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,6 +32,7 @@ from TestSCons import TestSCons, ConfigCheckInfo, _obj from TestCmd import IS_WINDOWS +from SCons.Util import get_current_hash_algorithm_used test = TestSCons() @@ -42,6 +43,11 @@ NCF = test.NCF # non-cached build failure CF = test.CF # cached build failure +# as this test is somewhat complicated, skip it if the library doesn't support md5 +# as the default hashing algorithm. +if get_current_hash_algorithm_used() != 'md5': + test.skip_test('Skipping test as could not continue without the hash algorithm set to md5!') + SConstruct_path = test.workpath('SConstruct') test.write(SConstruct_path, """ diff -Nru scons-4.0.1+dfsg/test/Configure/VariantDir2.py scons-4.4.0+dfsg/test/Configure/VariantDir2.py --- scons-4.0.1+dfsg/test/Configure/VariantDir2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/VariantDir2.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Verify that Configure contexts work with SConstruct/SConscript structure """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/Configure/VariantDir-SConscript.py scons-4.4.0+dfsg/test/Configure/VariantDir-SConscript.py --- scons-4.0.1+dfsg/test/Configure/VariantDir-SConscript.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Configure/VariantDir-SConscript.py 2022-07-30 21:48:28.000000000 +0000 @@ -128,7 +128,7 @@ import shutil shutil.rmtree(test.workpath(".sconf_temp")) -test.unlink(".sconsign.dblite") +test.unlink(test.get_sconsignname()+".dblite") # now with SConscriptChdir(1) test.run(arguments='chdir=yes') diff -Nru scons-4.0.1+dfsg/test/Copy-Action.py scons-4.4.0+dfsg/test/Copy-Action.py --- scons-4.0.1+dfsg/test/Copy-Action.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Copy-Action.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the Copy() Action works, and preserves file modification @@ -37,29 +36,32 @@ test = TestSCons.TestSCons() -test.write('SConstruct', """ +test.write('SConstruct', """\ Execute(Copy('f1.out', 'f1.in')) Execute(Copy(File('d2.out'), 'd2.in')) Execute(Copy('d3.out', File('f3.in'))) + def cat(env, source, target): target = str(target[0]) with open(target, "w") as f: for src in source: with open(str(src), "r") as ifp: f.write(ifp.read()) + Cat = Action(cat) env = Environment() -env.Command('bar.out', 'bar.in', [Cat, - Copy("f4.out", "f4.in"), - Copy("d5.out", "d5.in"), - Copy("d6.out", "f6.in")]) -env = Environment(OUTPUT = 'f7.out', INPUT = 'f7.in') +env.Command( + 'bar.out', + 'bar.in', + [Cat, Copy("f4.out", "f4.in"), Copy("d5.out", "d5.in"), Copy("d6.out", "f6.in")], +) +env = Environment(OUTPUT='f7.out', INPUT='f7.in') env.Command('f8.out', 'f8.in', [Copy('$OUTPUT', '$INPUT'), Cat]) env.Command('f9.out', 'f9.in', [Cat, Copy('${TARGET}-Copy', '$SOURCE')]) -env.CopyTo( 'd4', 'f10.in' ) -env.CopyAs( 'd4/f11.out', 'f11.in') -env.CopyAs( 'd4/f12.out', 'd5/f12.in') +env.CopyTo('d4', 'f10.in') +env.CopyAs('d4/f11.out', 'f11.in') +env.CopyAs('d4/f12.out', 'd5/f12.in') env.Command('f 13.out', 'f 13.in', Copy('$TARGET', '$SOURCE')) """) @@ -87,19 +89,20 @@ os.chmod('f1.in', 0o646) os.chmod('f4.in', 0o644) -test.sleep() +test.sleep() # delay for timestamps d4_f10_in = os.path.join('d4', 'f10.in') d4_f11_out = os.path.join('d4', 'f11.out') d4_f12_out = os.path.join('d4', 'f12.out') d5_f12_in = os.path.join('d5', 'f12.in') -expect = test.wrap_stdout(read_str = """\ +expect = test.wrap_stdout( + read_str="""\ Copy("f1.out", "f1.in") Copy("d2.out", "d2.in") Copy("d3.out", "f3.in") """, - build_str = """\ + build_str="""\ cat(["bar.out"], ["bar.in"]) Copy("f4.out", "f4.in") Copy("d5.out", "d5.in") @@ -112,9 +115,10 @@ cat(["f8.out"], ["f8.in"]) cat(["f9.out"], ["f9.in"]) Copy("f9.out-Copy", "f9.in") -""" % locals()) +""" % locals(), +) -test.run(options = '-n', arguments = '.', stdout = expect) +test.run(options='-n', arguments='.', stdout=expect) test.must_not_exist('f1.out') test.must_not_exist('d2.out') @@ -162,23 +166,21 @@ for value in ['ST_MODE', 'ST_MTIME']: v = getattr(stat, value) if s1[v] != s2[v]: - msg = '%s[%s] %s != %s[%s] %s\n' % \ - (repr(f1), value, s1[v], - repr(f2), value, s2[v],) + msg = f"{f1!r}[{value}] {s1[v]} != {f2!r}[{value}] {s2[v]}\n" sys.stderr.write(msg) - errors = errors + 1 + errors += 1 -must_be_same('f1.out', 'f1.in') -must_be_same(['d2.out', 'file'], ['d2.in', 'file']) -must_be_same(['d3.out', 'f3.in'], 'f3.in') -must_be_same('f4.out', 'f4.in') -must_be_same(['d5.out', 'file'], ['d5.in', 'file']) -must_be_same(['d6.out', 'f6.in'], 'f6.in') -must_be_same('f7.out', 'f7.in') -must_be_same(['d4', 'f10.in'], 'f10.in') -must_be_same(['d4', 'f11.out'], 'f11.in') -must_be_same(['d4', 'f12.out'], ['d5', 'f12.in']) -must_be_same('f 13.out', 'f 13.in') +must_be_same('f1.out', 'f1.in') +must_be_same(['d2.out', 'file'], ['d2.in', 'file']) +must_be_same(['d3.out', 'f3.in'], 'f3.in') +must_be_same('f4.out', 'f4.in') +must_be_same(['d5.out', 'file'], ['d5.in', 'file']) +must_be_same(['d6.out', 'f6.in'], 'f6.in') +must_be_same('f7.out', 'f7.in') +must_be_same(['d4', 'f10.in'], 'f10.in') +must_be_same(['d4', 'f11.out'], 'f11.in') +must_be_same(['d4', 'f12.out'], ['d5', 'f12.in']) +must_be_same('f 13.out', 'f 13.in') if errors: test.fail_test() diff -Nru scons-4.0.1+dfsg/test/Copy-Symlinks.py scons-4.4.0+dfsg/test/Copy-Symlinks.py --- scons-4.0.1+dfsg/test/Copy-Symlinks.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Copy-Symlinks.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ """ import os -import stat -import sys import TestSCons import SCons.Defaults diff -Nru scons-4.0.1+dfsg/test/CPPDEFINES/basic.py scons-4.4.0+dfsg/test/CPPDEFINES/basic.py --- scons-4.0.1+dfsg/test/CPPDEFINES/basic.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CPPDEFINES/basic.py 2022-07-30 21:48:28.000000000 +0000 @@ -38,13 +38,25 @@ ['x', 'y', 'z'], ['x', ['y', 123], 'z', ('int', '$INTEGER')], { 'c' : 3, 'b': None, 'a' : 1 }, + "${TESTDEFS}", + "${GEN}", ] + +def generator(target, source, env, for_signature): + if target and source: + return '_'.join([str(target[0]), 'GENERATED', str(source[0])]) + return 'TARGET_AND_SOURCE_ARE_MISSING' + for i in test_list: - env = Environment(CPPDEFPREFIX='-D', CPPDEFSUFFIX='', INTEGER=0) - print(env.Clone(CPPDEFINES=i).subst('$_CPPDEFFLAGS')) + env = Environment(CPPDEFPREFIX='-D', CPPDEFSUFFIX='', INTEGER=0, TESTDEFS=["FOO", "BAR=1"], GEN=generator) + ttt = env.Entry('#ttt') + sss = env.Entry('#sss') + print(env.Clone(CPPDEFINES=i).subst('$_CPPDEFFLAGS', target=[ttt], source=[sss])) for i in test_list: - env = Environment(CPPDEFPREFIX='|', CPPDEFSUFFIX='|', INTEGER=1) - print(env.Clone(CPPDEFINES=i).subst('$_CPPDEFFLAGS')) + env = Environment(CPPDEFPREFIX='|', CPPDEFSUFFIX='|', INTEGER=1, TESTDEFS=["FOO", "BAR=1"], GEN=generator) + ttt = env.Entry('#ttt') + sss = env.Entry('#sss') + print(env.Clone(CPPDEFINES=i).subst('$_CPPDEFFLAGS', target=[ttt], source=[sss])) """) expect = test.wrap_stdout(build_str="scons: `.' is up to date.\n", @@ -53,10 +65,14 @@ -Dx -Dy -Dz -Dx -Dy=123 -Dz -Dint=0 -Da=1 -Db -Dc=3 +-DFOO -DBAR=1 +-Dttt_GENERATED_sss |xyz| |x| |y| |z| |x| |y=123| |z| |int=1| |a=1| |b| |c=3| +|FOO| |BAR=1| +|ttt_GENERATED_sss| """) test.run(arguments = '.', stdout=expect) diff -Nru scons-4.0.1+dfsg/test/CPPFLAGS.py scons-4.4.0+dfsg/test/CPPFLAGS.py --- scons-4.0.1+dfsg/test/CPPFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CPPFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 sys @@ -38,25 +37,22 @@ if sys.platform == 'win32': test.skip_test('Skipping on win32.\n') -if sys.platform == 'win32': - test.file_fixture('mylink_win32.py', 'mylink.py') -else: - test.file_fixture('mylink.py') - +test.file_fixture('mylink.py') test.file_fixture('mygcc.py') - test.write('SConstruct', """ -env = Environment(CPPFLAGS = '-x', - LINK = r'%(_python_)s mylink.py', - LINKFLAGS = [], - CC = r'%(_python_)s mygcc.py cc', - CXX = r'%(_python_)s mygcc.py c++', - CXXFLAGS = [], - FORTRAN = r'%(_python_)s mygcc.py g77', - OBJSUFFIX = '.obj', - PROGSUFFIX = '.exe') -env.Program(target = 'foo', source = Split('test1.c test2.cpp test3.F')) +env = Environment( + CPPFLAGS='-x', + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + CC=r'%(_python_)s mygcc.py cc', + CXX=r'%(_python_)s mygcc.py c++', + CXXFLAGS=[], + FORTRAN=r'%(_python_)s mygcc.py g77', + OBJSUFFIX='.obj', + PROGSUFFIX='.exe', +) +env.Program(target='foo', source=Split('test1.c test2.cpp test3.F')) """ % locals()) test.write('test1.c', r"""test1.c @@ -86,19 +82,20 @@ test.must_match('mygcc.out', "cc\nc++\n") test.write('SConstruct', """ -env = Environment(CPPFLAGS = '-x', - SHLINK = r'%(_python_)s mylink.py', - SHLINKFLAGS = [], - CC = r'%(_python_)s mygcc.py cc', - CXX = r'%(_python_)s mygcc.py c++', - CXXFLAGS = [], - FORTRAN = r'%(_python_)s mygcc.py g77', - OBJSUFFIX = '.obj', - SHOBJPREFIX = '', - SHOBJSUFFIX = '.shobj', - PROGSUFFIX = '.exe') -env.SharedLibrary(target = File('foo.bar'), - source = Split('test1.c test2.cpp test3.F')) +env = Environment( + CPPFLAGS='-x', + SHLINK=r'%(_python_)s mylink.py', + SHLINKFLAGS=[], + CC=r'%(_python_)s mygcc.py cc', + CXX=r'%(_python_)s mygcc.py c++', + CXXFLAGS=[], + FORTRAN=r'%(_python_)s mygcc.py g77', + OBJSUFFIX='.obj', + SHOBJPREFIX='', + SHOBJSUFFIX='.shobj', + PROGSUFFIX='.exe', +) +env.SharedLibrary(target=File('foo.bar'), source=Split('test1.c test2.cpp test3.F')) """ % locals()) test.write('test1.c', r"""test1.c diff -Nru scons-4.0.1+dfsg/test/_CPPINCFLAGS.py scons-4.4.0+dfsg/test/_CPPINCFLAGS.py --- scons-4.0.1+dfsg/test/_CPPINCFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/_CPPINCFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -20,9 +21,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__" """ Test that we can expand $_CPPINCFLAGS correctly regardless of whether diff -Nru scons-4.0.1+dfsg/test/CXX/CXXFILESUFFIX.py scons-4.4.0+dfsg/test/CXX/CXXFILESUFFIX.py --- scons-4.0.1+dfsg/test/CXX/CXXFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CXX/CXXFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 import TestSCons @@ -32,32 +29,19 @@ test = TestSCons.TestSCons() -test.write('mylex.py', """ -import getopt -import sys -if sys.platform == 'win32': - longopts = ['nounistd'] -else: - longopts = [] -cmd_opts, args = getopt.getopt(sys.argv[1:], 't', longopts) -for a in args: - with open(a, 'r') as f: - contents = f.read() - sys.stdout.write(contents.replace('LEX', 'mylex.py')) -sys.exit(0) -""") +test.file_fixture('mylex.py') test.write('SConstruct', """ -env = Environment(LEX = r'%(_python_)s mylex.py', tools = ['lex']) -env.CXXFile(target = 'foo', source = 'foo.ll') -env.Clone(CXXFILESUFFIX = '.xyz').CXXFile(target = 'bar', source = 'bar.ll') +env = Environment(LEX=r'%(_python_)s mylex.py', tools=['lex']) +env.CXXFile(target='foo', source='foo.ll') +env.Clone(CXXFILESUFFIX='.xyz').CXXFile(target='bar', source='bar.ll') # Make sure that calling a Tool on a construction environment *after* # we've set CXXFILESUFFIX doesn't overwrite the value. -env2 = Environment(tools = [], CXXFILESUFFIX = '.env2') +env2 = Environment(tools=[], CXXFILESUFFIX='.env2') env2.Tool('lex') env2['LEX'] = r'%(_python_)s mylex.py' -env2.CXXFile(target = 'f3', source = 'f3.ll') +env2.CXXFile(target='f3', source='f3.ll') """ % locals()) input = r""" diff -Nru scons-4.0.1+dfsg/test/CXX/CXX-fixture/.exclude_tests scons-4.4.0+dfsg/test/CXX/CXX-fixture/.exclude_tests --- scons-4.0.1+dfsg/test/CXX/CXX-fixture/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CXX/CXX-fixture/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +myc++.py diff -Nru scons-4.0.1+dfsg/test/CXX/CXX-fixture/myc++.py scons-4.4.0+dfsg/test/CXX/CXX-fixture/myc++.py --- scons-4.0.1+dfsg/test/CXX/CXX-fixture/myc++.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/CXX/CXX-fixture/myc++.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,55 @@ +""" +Phony c++ command for testing SCons. + +Copies its source file to the target file, dropping lines that match +a pattern, so we can recognize the tool has made a modification. +Intended for use as the $CXX construction variable. + +Note: mycxx.py differs from the general fixture file mycompile.py +in arg handling: that one is intended for use as a *COM consvar, +where no compiler consvars will be passed on, this one is intended +for use as $CXX, where arguments like -o come into play. +""" +import getopt +import sys + +def fake_win32_cxx(): + args = sys.argv[1:] + inf = None + while args: + arg = args[0] + if arg == '-o': + out = args[1] + args = args[2:] + continue + args = args[1:] + if arg[0] not in '/-': + if not inf: + inf = arg + continue + if arg.startswith('/Fo'): + out = arg[3:] + + with open(inf, 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*c++*/'): + outfile.write(line) + +def fake_cxx(): + opts, args = getopt.getopt(sys.argv[1:], 'co:') + for opt, arg in opts: + if opt == '-o': + out = arg + + with open(args[0], 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*c++*/'): + outfile.write(line) + +if __name__ == '__main__': + print(f"DEBUG: {sys.argv[0]}: {sys.argv[1:]}") + if sys.platform == 'win32': + fake_win32_cxx() + else: + fake_cxx() + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/CXX/CXX.py scons-4.4.0+dfsg/test/CXX/CXX.py --- scons-4.0.1+dfsg/test/CXX/CXX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/CXX/CXX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 os import sys import TestSCons @@ -33,120 +31,46 @@ test = TestSCons.TestSCons() - - -if sys.platform == 'win32': - - test.write('mylink.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-o': - out = args[1] - args = args[2:] - continue - if not a[0] in '/-': - break - args = args[1:] - if a[:5].lower() == '/out:': out = a[5:] -infile = open(args[0], 'r') -outfile = open(out, 'w') -for l in infile.readlines(): - if l[:8] != '/*link*/': - outfile.write(l) -sys.exit(0) -""") - - test.write('myc++.py', r""" -import sys -args = sys.argv[1:] -inf = None -while args: - a = args[0] - if a == '-o': - out = args[1] - args = args[2:] - continue - args = args[1:] - if not a[0] in '/-': - if not inf: - inf = a - continue - if a[:3] == '/Fo': out = a[3:] -infile = open(inf, 'r') -outfile = open(out, 'w') -for l in infile.readlines(): - if l[:7] != '/*c++*/': - outfile.write(l) -sys.exit(0) -""") - -else: - - test.write('mylink.py', r""" -import getopt -import sys -opts, args = getopt.getopt(sys.argv[1:], 'o:') -for opt, arg in opts: - if opt == '-o': out = arg -infile = open(args[0], 'r') -outfile = open(out, 'w') -for l in infile.readlines(): - if l[:8] != '/*link*/': - outfile.write(l) -sys.exit(0) -""") - - test.write('myc++.py', r""" -import getopt -import sys -opts, args = getopt.getopt(sys.argv[1:], 'co:') -for opt, arg in opts: - if opt == '-o': out = arg -infile = open(args[0], 'r') -outfile = open(out, 'w') -for l in infile.readlines(): - if l[:7] != '/*c++*/': - outfile.write(l) -sys.exit(0) -""") +test.file_fixture('mylink.py') +test.dir_fixture('CXX-fixture') test.write('SConstruct', """ -env = Environment(LINK = r'%(_python_)s mylink.py', - LINKFLAGS = [], - CXX = r'%(_python_)s myc++.py', - CXXFLAGS = []) -env.Program(target = 'test1', source = 'test1.cc') -env.Program(target = 'test2', source = 'test2.cpp') -env.Program(target = 'test3', source = 'test3.cxx') -env.Program(target = 'test4', source = 'test4.c++') -env.Program(target = 'test5', source = 'test5.C++') +env = Environment( + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + CXX=r'%(_python_)s myc++.py', + CXXFLAGS=[], +) +env.Program(target='test1', source='test1.cc') +env.Program(target='test2', source='test2.cpp') +env.Program(target='test3', source='test3.cxx') +env.Program(target='test4', source='test4.c++') +env.Program(target='test5', source='test5.C++') """ % locals()) test.write('test1.cc', r"""This is a .cc file. /*c++*/ -/*link*/ +#link """) test.write('test2.cpp', r"""This is a .cpp file. /*c++*/ -/*link*/ +#link """) test.write('test3.cxx', r"""This is a .cxx file. /*c++*/ -/*link*/ +#link """) test.write('test4.c++', r"""This is a .c++ file. /*c++*/ -/*link*/ +#link """) test.write('test5.C++', r"""This is a .C++ file. /*c++*/ -/*link*/ +#link """) test.run(arguments = '.', stderr = None) @@ -162,35 +86,32 @@ test.must_match('test5' + _exe, "This is a .C++ file.\n", mode='r') if TestSCons.case_sensitive_suffixes('.c', '.C'): - test.write('SConstruct', """ -env = Environment(LINK = r'%(_python_)s mylink.py', - LINKFLAGS = [], - CXX = r'%(_python_)s myc++.py', - CXXFLAGS = []) -env.Program(target = 'test6', source = 'test6.C') +env = Environment( + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + CXX=r'%(_python_)s myc++.py', + CXXFLAGS=[], +) +env.Program(target='test6', source='test6.C') """ % locals()) test.write('test6.C', r"""This is a .C file. /*c++*/ -/*link*/ +#link """) test.run(arguments = '.', stderr = None) - test.must_match('test6' + _exe, "This is a .C file.\n", mode='r') - - - test.file_fixture('wrapper.py') test.write('SConstruct', """ foo = Environment() cxx = foo.Dictionary('CXX') -bar = Environment(CXX = r'%(_python_)s wrapper.py ' + cxx) -foo.Program(target = 'foo', source = 'foo.cxx') -bar.Program(target = 'bar', source = 'bar.cxx') +bar = Environment(CXX=r'%(_python_)s wrapper.py ' + cxx) +foo.Program(target='foo', source='foo.cxx') +bar.Program(target='bar', source='bar.cxx') """ % locals()) test.write('foo.cxx', r""" diff -Nru scons-4.0.1+dfsg/test/D/DMD.py scons-4.4.0+dfsg/test/D/DMD.py --- scons-4.0.1+dfsg/test/D/DMD.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/DMD.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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. -# # Amended by Russel Winder 2010-05-05 -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons import sys diff -Nru scons-4.0.1+dfsg/test/D/GDC.py scons-4.4.0+dfsg/test/D/GDC.py --- scons-4.0.1+dfsg/test/D/GDC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/GDC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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. -# # Amended by Russel Winder 2010-05-05 -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons _exe = TestSCons._exe diff -Nru scons-4.0.1+dfsg/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py scons-4.4.0+dfsg/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py --- scons-4.0.1+dfsg/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,6 @@ -""" -These tests verify that SCons fails appropriately where the user has tried to supply multiple command line -options via a single string rather than providing a list of strings, one string per option. -""" - +# 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,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__" +""" +These tests verify that SCons fails appropriately where the user has +tried to supply multiple command line options via a single string rather +than providing a list of strings, one string per option. +""" + import TestSCons @@ -49,19 +49,19 @@ config = f.read().format(tool) test.write('SConstruct', config) - test.run(status=2, stdout=None, stderr=None) result = { 'dmd': ".*unrecognized switch '-m64 -O'.*", - 'gdc': ".*unrecognized command line option.*", + 'gdc': ".*unrecognized command.line option.*", 'ldc': ".*Unknown command line argument '-m64 -O'.*", }[tool] + from SCons.Environment import Base if tool == 'dmd' and Base()['DC'] == 'gdmd': result = ".*unrecognized command line option '-m64 -O'.*" - test.fail_test(not test.match_re_dotall(test.stderr(), result)) + test.run(status=2, stdout=None, stderr=result, match=TestSCons.match_re_dotall) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py scons-4.4.0+dfsg/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py --- scons-4.0.1+dfsg/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,9 +1,6 @@ -""" -Test compiling and executing using the gdc tool. -""" - +# 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 @@ -23,9 +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__" +""" +Test compiling and executing using the gdc tool. +""" from Common.singleStringCannotBeMultipleOptions import testForTool testForTool('gdc') diff -Nru scons-4.0.1+dfsg/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py scons-4.4.0+dfsg/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py --- scons-4.0.1+dfsg/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/Issues/2994/Common/D_changed_DFLAGS_not_rebuilding.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,7 @@ 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 -Nru scons-4.0.1+dfsg/test/D/LDC.py scons-4.4.0+dfsg/test/D/LDC.py --- scons-4.0.1+dfsg/test/D/LDC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/LDC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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. -# # Amended by Russel Winder 2010-05-05 -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons from os.path import abspath, dirname diff -Nru scons-4.0.1+dfsg/test/D/MixedDAndC/Common/common.py scons-4.4.0+dfsg/test/D/MixedDAndC/Common/common.py --- scons-4.0.1+dfsg/test/D/MixedDAndC/Common/common.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/MixedDAndC/Common/common.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ import TestSCons from os.path import abspath, dirname -from platform import architecture import sys sys.path.insert(1, abspath(dirname(__file__) + '/../../Support')) diff -Nru scons-4.0.1+dfsg/test/D/SharedObjects/Common/common.py scons-4.4.0+dfsg/test/D/SharedObjects/Common/common.py --- scons-4.0.1+dfsg/test/D/SharedObjects/Common/common.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/SharedObjects/Common/common.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,9 +1,6 @@ -""" -Support functions for all the tests. -""" - +# 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 @@ -23,16 +20,18 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# +""" +Support functions for all the tests. +""" -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons from SCons.Environment import Base +import re +import subprocess from os.path import abspath, dirname -from subprocess import check_output import sys sys.path.insert(1, abspath(dirname(__file__) + '/../../Support')) @@ -47,9 +46,17 @@ test.skip_test("Required executable for tool '{0}' not found, skipping test.\n".format(tool)) if tool == 'gdc': - result = check_output(('gdc', '--version')) - version = result.decode().splitlines()[0].split()[3] - major, minor, debug = [int(x) for x in version.split('.')] + cp = subprocess.run(('gdc', '--version'), stdout=subprocess.PIPE) + # different version strings possible, i.e.: + # gdc (GCC) 11.1.1 20210531 (Red Hat 11.1.1-3)\nCopyright (C)... + # gdc (Ubuntu 10.2.0-5ubuntu1~20.04) 10.20.0\nCopyright (C)... + vstr = cp.stdout.decode().splitlines()[0] + match = re.search(r'[0-9]+(\.[0-9]+)+', vstr) + if match: + version = match.group(0) + major, minor, debug = [int(x) for x in version.split('.')] + else: + major = 0 if (major < 6) or (major == 6 and minor < 3): test.skip_test('gdc prior to version 6.0.0 does not support shared libraries.\n') @@ -90,6 +97,7 @@ test.must_exist(test.workpath(code_name)) test.must_exist(test.workpath(library_name)) + test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/D/SharedObjects/Image/SConstruct_template scons-4.4.0+dfsg/test/D/SharedObjects/Image/SConstruct_template --- scons-4.0.1+dfsg/test/D/SharedObjects/Image/SConstruct_template 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/SharedObjects/Image/SConstruct_template 2022-07-30 21:48:28.000000000 +0000 @@ -3,8 +3,18 @@ # The core difference between this test and the one of SharedObjectSuffixIssue # is that here we explicitly use the relevant D tool and things work. -environment = Environment( +DefaultEnvironment(tools=[]) +env = Environment( tools=['{0}', 'link'] ) -environment.SharedLibrary('answer', 'code.d') +shobj = env.SharedObject('code.d') +env.SharedLibrary('answer', shobj) +ver_lib = env.SharedLibrary('answer_versioned', shobj, SHLIBVERSION='1.1.1', SOVERSION='4') + +shlibfile = ver_lib[0] +try: + for (f,t) in ver_lib[0].attributes.shliblinks: + print("SYMLINK:%s,%s"%(f,t)) +except AttributeError: + print("NOSYMLINK") diff -Nru scons-4.0.1+dfsg/test/D/SharedObjects/sconstest-dmd.py scons-4.4.0+dfsg/test/D/SharedObjects/sconstest-dmd.py --- scons-4.0.1+dfsg/test/D/SharedObjects/sconstest-dmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/SharedObjects/sconstest-dmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -2,8 +2,9 @@ Test compiling and executing using the dmd tool. """ +# 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 @@ -23,9 +24,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__" from Common.common import testForTool testForTool('dmd') diff -Nru scons-4.0.1+dfsg/test/D/Support/executablesSearch.py scons-4.4.0+dfsg/test/D/Support/executablesSearch.py --- scons-4.0.1+dfsg/test/D/Support/executablesSearch.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/D/Support/executablesSearch.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,11 +1,6 @@ -#! /usr/bin/env python - -""" -Support functions for all the tests. -""" - +# 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,11 @@ # 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. -# +#! /usr/bin/env python -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +""" +Support functions for all the tests. +""" if __name__ == '__main__': import sys diff -Nru scons-4.0.1+dfsg/test/Decider/content-timestamp-symlink.py scons-4.4.0+dfsg/test/Decider/content-timestamp-symlink.py --- scons-4.0.1+dfsg/test/Decider/content-timestamp-symlink.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/content-timestamp-symlink.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,81 @@ +#!/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. + +""" +Test the content-timestamp decider (formerly known as md5-timestamp) +correctly detects modification of a source file which is a symlink. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +if not test.platform_has_symlink(): + test.skip_test('Symbolic links not reliably available on this platform, skipping test.\n') + +# a dummy "compiler" for the builder +test.write('build.py', r""" +import sys + +with open(sys.argv[1], 'wb') as ofp: + for infile in sys.argv[2:]: + with open (infile, 'rb') as ifp: + ofp.write(ifp.read()) +sys.exit(0) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +Build = Builder(action=r'%(_python_)s build.py $TARGET $SOURCES') +env = Environment(tools=[], BUILDERS={'Build': Build}) +env.Decider('content-timestamp') +env.Build(target='match1.out', source='match1.in') +env.Build(target='match2.out', source='match2.in') +""" % locals()) + +test.write('match1.in', 'match1.in\n') +test.symlink('match1.in', 'match2.in') + +test.run(arguments='.') +test.must_match('match1.out', 'match1.in\n') +test.must_match('match2.out', 'match1.in\n') + +# first make sure some time has elapsed, so a low-granularity timestamp +# doesn't fail to trigger +test.sleep() +# Now update the source file contents, both targets should rebuild +test.write('match1.in', 'match2.in\n') + +test.run(arguments='.') +test.must_match('match1.out', 'match2.in\n', message="match1.out not rebuilt\n") +test.must_match('match2.out', 'match2.in\n', message="match2.out not rebuilt\n") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Decider/MD5-timestamp.py scons-4.4.0+dfsg/test/Decider/MD5-timestamp.py --- scons-4.0.1+dfsg/test/Decider/MD5-timestamp.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/MD5-timestamp.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify behavior of the MD5-timestamp Decider() setting. @@ -49,15 +48,10 @@ test.write('content3.in', "content3.in 1\n") test.run(arguments = '.') - test.up_to_date(arguments = '.') - - -test.sleep() - +test.sleep() # delay for timestamps test.write('content1.in', "content1.in 2\n") - test.touch('content2.in') time_content = os.stat('content3.in')[stat.ST_MTIME] @@ -73,11 +67,8 @@ Copy("content1.out", "content1.in") """) -test.run(arguments = '.', stdout=expect) - -test.up_to_date(arguments = '.') - - +test.run(arguments='.', stdout=expect) +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Decider/MD5-timestamp-Repository.py scons-4.4.0+dfsg/test/Decider/MD5-timestamp-Repository.py --- scons-4.0.1+dfsg/test/Decider/MD5-timestamp-Repository.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/MD5-timestamp-Repository.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify behavior of the MD5-timestamp Decider() setting when combined with Repository() usage @@ -38,13 +37,11 @@ test.subdir('Repository', 'work') repository = test.workpath('Repository') - test.write(['Repository','content1.in'], "content1.in 1\n") test.write(['Repository','content2.in'], "content2.in 1\n") test.write(['Repository','content3.in'], "content3.in 1\n") # test.writable('Repository', 0) - test.write(['work','SConstruct'], """\ Repository(r'%s') DefaultEnvironment(tools=[]) @@ -53,18 +50,14 @@ m.Command('content1.out', 'content1.in', Copy('$TARGET', '$SOURCE')) m.Command('content2.out', 'content2.in', Copy('$TARGET', '$SOURCE')) m.Command('content3.out', 'content3.in', Copy('$TARGET', '$SOURCE')) -"""%repository) +""" % repository) test.run(chdir='work',arguments='.') - test.up_to_date(chdir='work',arguments='.') -test.sleep() - +test.sleep() # delay for timestamps test.write(['Repository','content1.in'], "content1.in 2\n") - test.touch(['Repository','content2.in']) - time_content = os.stat(os.path.join(repository,'content3.in'))[stat.ST_MTIME] test.write(['Repository','content3.in'], "content3.in 2\n") test.touch(['Repository','content3.in'], time_content) @@ -76,10 +69,9 @@ expect = test.wrap_stdout("""\ Copy("content1.out", "%s") -"""%os.path.join(repository,'content1.in')) +""" % os.path.join(repository, 'content1.in')) test.run(chdir='work', arguments='.', stdout=expect) - test.up_to_date(chdir='work', arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Decider/MD5-winonly-firstbuild.py scons-4.4.0+dfsg/test/Decider/MD5-winonly-firstbuild.py --- scons-4.0.1+dfsg/test/Decider/MD5-winonly-firstbuild.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/MD5-winonly-firstbuild.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,8 +29,6 @@ In this case flex and yacc are an example. """ -import os -import stat import TestSCons from TestCmd import IS_WINDOWS diff -Nru scons-4.0.1+dfsg/test/Decider/MD5-winonly-fixture/test_parse.y scons-4.4.0+dfsg/test/Decider/MD5-winonly-fixture/test_parse.y --- scons-4.0.1+dfsg/test/Decider/MD5-winonly-fixture/test_parse.y 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/MD5-winonly-fixture/test_parse.y 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,9 @@ %{ #include +int yyerror(char *s); +int yylex(); + int regs[26]; int base; @@ -25,11 +28,13 @@ %% +int main() { return(yyparse()); } +int yyerror(s) char *s; { @@ -37,7 +42,8 @@ return(0); } +int yywrap() { return(1); -} \ No newline at end of file +} diff -Nru scons-4.0.1+dfsg/test/Decider/timestamp.py scons-4.4.0+dfsg/test/Decider/timestamp.py --- scons-4.0.1+dfsg/test/Decider/timestamp.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Decider/timestamp.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify various interactions of the timestamp-match and timestamp-newer @@ -54,27 +53,21 @@ test.write('newer2.in', "newer2.in\n") test.run(arguments = '.') - test.up_to_date(arguments = '.') time_match = os.stat('match2.out')[stat.ST_MTIME] time_newer = os.stat('newer2.out')[stat.ST_MTIME] - - # Now make all the source files newer than (different timestamps from) # the last time the targets were built, and touch the target files # of match1.out and newer1.out to see the different effects. - -test.sleep() - +test.sleep() # delay for timestamps test.touch('match1.in') test.touch('newer1.in') test.touch('match2.in') test.touch('newer2.in') -test.sleep() - +test.sleep() # delay for timestamps test.touch('match1.out') test.touch('newer1.out') @@ -90,7 +83,7 @@ Copy("newer2.out", "newer2.in") """) -test.run(arguments = '.', stdout=expect) +test.run(arguments='.', stdout=expect) # Now, for the somewhat pathological case, reset the match2.out and # newer2.out timestamps to the older timestamp when the targets were @@ -107,9 +100,7 @@ Copy("newer2.out", "newer2.in") """) -test.run(arguments = '.', stdout=expect) - - +test.run(arguments='.', stdout=expect) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Dir/Dir.py scons-4.4.0+dfsg/test/Dir/Dir.py --- scons-4.0.1+dfsg/test/Dir/Dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Dir/Dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the Dir() global function and environment method work diff -Nru scons-4.0.1+dfsg/test/Dir/DriveAbsPath.py scons-4.4.0+dfsg/test/Dir/DriveAbsPath.py --- scons-4.0.1+dfsg/test/Dir/DriveAbsPath.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Dir/DriveAbsPath.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" r""" Test to confirm that Dir(drive_path).abspath works on Windows. This verifies diff -Nru scons-4.0.1+dfsg/test/Dir/mixed-targets.py scons-4.4.0+dfsg/test/Dir/mixed-targets.py --- scons-4.0.1+dfsg/test/Dir/mixed-targets.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Dir/mixed-targets.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Make sure that target lists of intermixed Node.FS.Dir and Node.FS.File diff -Nru scons-4.0.1+dfsg/test/Dir/PyPackageDir/PyPackageDir.py scons-4.4.0+dfsg/test/Dir/PyPackageDir/PyPackageDir.py --- scons-4.0.1+dfsg/test/Dir/PyPackageDir/PyPackageDir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Dir/PyPackageDir/PyPackageDir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 os.path import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Dir/source.py scons-4.4.0+dfsg/test/Dir/source.py --- scons-4.0.1+dfsg/test/Dir/source.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Dir/source.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ This test tests directories as source files. The correct behavior is that @@ -43,15 +42,16 @@ test.write('SConstruct', """\ DefaultEnvironment(tools=[]) + def writeTarget(target, source, env): - f=open(str(target[0]), 'w') + f = open(str(target[0]), 'w') f.write("stuff\\n") f.close() return 0 -test_bld_dir = Builder(action=writeTarget, - source_factory=Dir, - source_scanner=DirScanner) +test_bld_dir = Builder( + action=writeTarget, source_factory=Dir, source_scanner=DirScanner +) test_bld_file = Builder(action=writeTarget) env = Environment(tools=[]) env['BUILDERS']['TestDir'] = test_bld_dir @@ -62,34 +62,36 @@ env_tstamp.TestFile(source='junk.txt', target='tstamp/junk.out') env_tstamp.TestDir(source='tstamp', target='tstamp.out') env_tstamp.Command('cmd-tstamp-noscan.out', 'cmd-tstamp', writeTarget) -env_tstamp.Command('cmd-tstamp.out', 'cmd-tstamp', writeTarget, - source_scanner=DirScanner) +env_tstamp.Command( + 'cmd-tstamp.out', 'cmd-tstamp', writeTarget, source_scanner=DirScanner +) env_content = env.Clone() env_content.Decider('content') env_content.TestFile(source='junk.txt', target='content/junk.out') env_content.TestDir(source='content', target='content.out') env_content.Command('cmd-content-noscan.out', 'cmd-content', writeTarget) -env_content.Command('cmd-content.out', 'cmd-content', writeTarget, - source_scanner=DirScanner) +env_content.Command( + 'cmd-content.out', 'cmd-content', writeTarget, source_scanner=DirScanner +) """) -test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 1\n') -test.write([ 'tstamp', '#hash.txt' ], 'hash.txt 1\n') -test.write([ 'tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n') -test.write([ 'tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n') -test.write([ 'content', 'foo.txt' ], 'foo.txt 1\n') -test.write([ 'content', '#hash.txt' ], 'hash.txt 1\n') -test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 1\n') -test.write([ 'content', 'subdir', '#hash.txt' ], 'hash.txt 1\n') -test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 1\n') -test.write([ 'cmd-tstamp', '#hash.txt' ], 'hash.txt 1\n') -test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 1\n') -test.write([ 'cmd-tstamp', 'subdir', '#hash.txt' ], 'hash.txt 1\n') -test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 1\n') -test.write([ 'cmd-content', '#hash.txt' ], '#hash.txt 1\n') -test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 1\n') -test.write([ 'cmd-content', 'subdir', '#hash.txt' ], 'hash.txt 1\n') +test.write(['tstamp', 'foo.txt'], 'foo.txt 1\n') +test.write(['tstamp', '#hash.txt'], 'hash.txt 1\n') +test.write(['tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n') +test.write(['tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n') +test.write(['content', 'foo.txt'], 'foo.txt 1\n') +test.write(['content', '#hash.txt'], 'hash.txt 1\n') +test.write(['content', 'subdir', 'bar.txt'], 'bar.txt 1\n') +test.write(['content', 'subdir', '#hash.txt'], 'hash.txt 1\n') +test.write(['cmd-tstamp', 'foo.txt'], 'foo.txt 1\n') +test.write(['cmd-tstamp', '#hash.txt'], 'hash.txt 1\n') +test.write(['cmd-tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n') +test.write(['cmd-tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n') +test.write(['cmd-content', 'foo.txt'], 'foo.txt 1\n') +test.write(['cmd-content', '#hash.txt'], '#hash.txt 1\n') +test.write(['cmd-content', 'subdir', 'bar.txt'], 'bar.txt 1\n') +test.write(['cmd-content', 'subdir', '#hash.txt'], 'hash.txt 1\n') test.write('junk.txt', 'junk.txt\n') test.run(arguments=".", stderr=None) @@ -107,59 +109,61 @@ test.up_to_date(arguments='cmd-tstamp-noscan.out') test.up_to_date(arguments='cmd-content-noscan.out') -test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 2\n') +test.sleep() # delay for timestamps + +test.write(['tstamp', 'foo.txt'], 'foo.txt 2\n') test.not_up_to_date(arguments='tstamp.out') -test.write([ 'tstamp', 'new.txt' ], 'new.txt\n') +test.write(['tstamp', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='tstamp.out') -test.write([ 'content', 'foo.txt' ], 'foo.txt 2\n') +test.write(['content', 'foo.txt'], 'foo.txt 2\n') test.not_up_to_date(arguments='content.out') -test.write([ 'content', 'new.txt' ], 'new.txt\n') +test.write(['content', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='content.out') -test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 2\n') +test.write(['cmd-tstamp', 'foo.txt'], 'foo.txt 2\n') test.not_up_to_date(arguments='cmd-tstamp.out') test.up_to_date(arguments='cmd-tstamp-noscan.out') -test.write([ 'cmd-tstamp', 'new.txt' ], 'new.txt\n') +test.write(['cmd-tstamp', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='cmd-tstamp.out') test.up_to_date(arguments='cmd-tstamp-noscan.out') -test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 2\n') +test.write(['cmd-content', 'foo.txt'], 'foo.txt 2\n') test.not_up_to_date(arguments='cmd-content.out') test.up_to_date(arguments='cmd-content-noscan.out') -test.write([ 'cmd-content', 'new.txt' ], 'new.txt\n') +test.write(['cmd-content', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='cmd-content.out') test.up_to_date(arguments='cmd-content-noscan.out') -test.write([ 'tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n') +test.write(['tstamp', 'subdir', 'bar.txt'], 'bar.txt 2\n') test.not_up_to_date(arguments='tstamp.out') -test.write([ 'tstamp', 'subdir', 'new.txt' ], 'new.txt\n') +test.write(['tstamp', 'subdir', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='tstamp.out') -test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 2\n') +test.write(['content', 'subdir', 'bar.txt'], 'bar.txt 2\n') test.not_up_to_date(arguments='content.out') -test.write([ 'content', 'subdir', 'new.txt' ], 'new.txt\n') +test.write(['content', 'subdir', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='content.out') -test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n') +test.write(['cmd-tstamp', 'subdir', 'bar.txt'], 'bar.txt 2\n') test.not_up_to_date(arguments='cmd-tstamp.out') test.up_to_date(arguments='cmd-tstamp-noscan.out') -test.write([ 'cmd-tstamp', 'subdir', 'new.txt' ], 'new.txt\n') +test.write(['cmd-tstamp', 'subdir', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='cmd-tstamp.out') test.up_to_date(arguments='cmd-tstamp-noscan.out') -test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 2\n') +test.write(['cmd-content', 'subdir', 'bar.txt'], 'bar.txt 2\n') test.not_up_to_date(arguments='cmd-content.out') test.up_to_date(arguments='cmd-content-noscan.out') -test.write([ 'cmd-content', 'subdir', 'new.txt' ], 'new.txt\n') +test.write(['cmd-content', 'subdir', 'new.txt'], 'new.txt\n') test.not_up_to_date(arguments='cmd-content.out') test.up_to_date(arguments='cmd-content-noscan.out') diff -Nru scons-4.0.1+dfsg/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py scons-4.4.0+dfsg/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py --- scons-4.0.1+dfsg/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basedir/htmlchunked/htmlchunked_cmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py scons-4.4.0+dfsg/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py --- scons-4.0.1+dfsg/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basedir/htmlhelp/htmlhelp_cmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Docbook/basedir/slideshtml/slideshtml_cmd.py scons-4.4.0+dfsg/test/Docbook/basedir/slideshtml/slideshtml_cmd.py --- scons-4.0.1+dfsg/test/Docbook/basedir/slideshtml/slideshtml_cmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basedir/slideshtml/slideshtml_cmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py scons-4.4.0+dfsg/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py --- scons-4.0.1+dfsg/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -27,7 +27,6 @@ the xsltproc executable, if it exists. """ -import os import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/slideshtml/slideshtml_cmd.py scons-4.4.0+dfsg/test/Docbook/basic/slideshtml/slideshtml_cmd.py --- scons-4.0.1+dfsg/test/Docbook/basic/slideshtml/slideshtml_cmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/slideshtml/slideshtml_cmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ """ import os -import sys import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/SConstruct scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/SConstruct --- scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +env = Environment(tools=['docbook']) + +SConscript('subdir/SConscript', 'env') diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/in.xml scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/in.xml --- scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/in.xml 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/in.xml 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,77 @@ + + + SCons 2.3.5 + User Guide + + + Steven + Knight + + + Steven Knight and the SCons Development Team + + 2004 - 2020 + + + 2004 - 2020 + The SCons Foundation + + + + +
+ + SCons User's Guide Copyright (c) 2004-2019 Steven Knight + +
+ + +
+ + version 2.3.5 + +
+ + + +Builders + +... + +
+Test + +... +
+ +
+ + +Construction Variables + + +In this appendix... + + + + + + ASCOMSTR + + +The string displayed when an object file +is generated from an assembly-language source file. +If this is not set, then $ASCOM (the command line) is displayed. + + + +env = Environment(ASCOMSTR = "Assembling $TARGET") + + + + + + + +
+ diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/SConscript scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/SConscript --- scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/SConscript 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/SConscript 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,7 @@ +Import('env') + +# +# Create document +# +env.DocbookXslt('out.xml', 'in.xml', + xsl='to_docbook.xslt') diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/to_docbook.xslt scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/to_docbook.xslt --- scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/to_docbook.xslt 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/image/subdir/to_docbook.xslt 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/xsltsubdir.py scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/xsltsubdir.py --- scons-4.0.1+dfsg/test/Docbook/basic/xsltsubdir/xsltsubdir.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Docbook/basic/xsltsubdir/xsltsubdir.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001-2010 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. +# + +""" +Test the Xslt builder in a hierarchical build scenario +""" + +import TestSCons + +test = TestSCons.TestSCons() + +try: + import lxml # noqa: F401 +except Exception: + test.skip_test('Cannot find installed Python binding for lxml, skipping test.\n') + +test.dir_fixture('image') + +# Normal invocation +test.run() +test.must_not_be_empty(test.workpath('subdir/out.xml')) +test.must_contain(test.workpath('subdir/out.xml'),'', mode='r') +test.must_not_contain(test.workpath('subdir/out.xml'),'', mode='r') + + +# Cleanup +test.run(arguments='-c') +test.must_not_exist(test.workpath('subdir/out.xml')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/DVIPDF/DVIPDFFLAGS.py scons-4.4.0+dfsg/test/DVIPDF/DVIPDFFLAGS.py --- scons-4.0.1+dfsg/test/DVIPDF/DVIPDFFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/DVIPDF/DVIPDFFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -122,7 +122,7 @@ 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 -Nru scons-4.0.1+dfsg/test/emitter.py scons-4.4.0+dfsg/test/emitter.py --- scons-4.0.1+dfsg/test/emitter.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/emitter.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Errors/Exception.py scons-4.4.0+dfsg/test/Errors/Exception.py --- scons-4.0.1+dfsg/test/Errors/Exception.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Errors/Exception.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 TestSCons @@ -53,7 +52,7 @@ # so make sure the proper variations are supported in the following # regexp. expect = r"""scons: \*\*\* \[exit.out\] Exception : exit -Traceback \((most recent call|innermost) last\): +Traceback \(most recent call last\): ( File ".+", line \d+, in \S+ [^\n]+ )*( File ".+", line \d+, in \S+ diff -Nru scons-4.0.1+dfsg/test/Errors/execute-a-directory.py scons-4.4.0+dfsg/test/Errors/execute-a-directory.py --- scons-4.0.1+dfsg/test/Errors/execute-a-directory.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Errors/execute-a-directory.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import TestSCons @@ -65,7 +64,7 @@ """ cannot_execute = """\ -(sh: )*.+: cannot execute( \\[Is a directory\\])? +(sh: )*.+: cannot execute(( -)? \\[?Is a directory\\]?)? scons: \\*\\*\\* \\[%s\\] Error %s """ diff -Nru scons-4.0.1+dfsg/test/Errors/InternalError.py scons-4.4.0+dfsg/test/Errors/InternalError.py --- scons-4.0.1+dfsg/test/Errors/InternalError.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Errors/InternalError.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify the exit status and error output if an SConstruct file @@ -41,7 +40,7 @@ """) test.run(stdout = "scons: Reading SConscript files ...\ninternal error\n", - stderr = r"""Traceback \((most recent call|innermost) last\): + stderr = r"""Traceback \(most recent call last\): File ".+", line \d+, in .+ File ".+", line \d+, in .+ File ".+", line \d+, in .+ diff -Nru scons-4.0.1+dfsg/test/Errors/non-executable-file.py scons-4.4.0+dfsg/test/Errors/non-executable-file.py --- scons-4.0.1+dfsg/test/Errors/non-executable-file.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Errors/non-executable-file.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import TestSCons @@ -54,7 +53,7 @@ """ cannot_execute = """\ -(sh: )*.+: cannot execute( \\[Permission denied\\])? +(sh: )*.+: cannot execute(( -)? \\[?Permission denied\\]?)? scons: \\*\\*\\* \\[%s\\] Error %s """ diff -Nru scons-4.0.1+dfsg/test/exceptions.py scons-4.4.0+dfsg/test/exceptions.py --- scons-4.0.1+dfsg/test/exceptions.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/exceptions.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 re @@ -37,17 +36,18 @@ test.write(SConstruct_path, """\ def func(source = None, target = None, env = None): raise Exception("func exception") -B = Builder(action = func) -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'foo.out', source = 'foo.in') +B = Builder(action=func) +env = Environment(BUILDERS={'B': B}) +env.B(target='foo.out', source='foo.in') """) test.write('foo.in', "foo.in\n") expected_stderr = r"""scons: \*\*\* \[foo.out\] Exception : func exception -Traceback \((most recent call|innermost) last\): +Traceback \(most recent call last\): ( File ".+", line \d+, in \S+ [^\n]+ + [^\n]+ )*( File ".+", line \d+, in \S+ )*( File ".+", line \d+, in \S+ [^\n]+ @@ -56,10 +56,8 @@ Exception: func exception """ % re.escape(SConstruct_path) -test.run(arguments = "foo.out", stderr = expected_stderr, status = 2) - -test.run(arguments = "-j2 foo.out", stderr = expected_stderr, status = 2) - +test.run(arguments="foo.out", stderr=expected_stderr, status=2) +test.run(arguments="-j2 foo.out", stderr=expected_stderr, status=2) # Verify that exceptions caused by exit values of builder actions are # correctly signalled, for both Serial and Parallel jobs. @@ -70,29 +68,28 @@ """) test.write(SConstruct_path, """ -Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE') -env = Environment(BUILDERS = { 'Fail' : Fail }) -env.Fail(target = 'out.f1', source = 'in.f1') +Fail = Builder(action=r'%(_python_)s myfail.py $TARGETS $SOURCE') +env = Environment(BUILDERS={'Fail': Fail}) +env.Fail(target='out.f1', source='in.f1') """ % locals()) test.write('in.f1', "in.f1\n") expected_stderr = "scons: \\*\\*\\* \\[out.f1\\] Error 1\n" -test.run(arguments = '.', status = 2, stderr = expected_stderr) -test.run(arguments = '-j2 .', status = 2, stderr = expected_stderr) - +test.run(arguments='.', status=2, stderr=expected_stderr) +test.run(arguments='-j2 .', status=2, stderr=expected_stderr) # Verify that all exceptions from simultaneous tasks are reported, # even if the exception is raised during the Task.prepare() # [Node.prepare()] test.write(SConstruct_path, """ -Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE') -env = Environment(BUILDERS = { 'Fail' : Fail }) -env.Fail(target = 'out.f1', source = 'in.f1') -env.Fail(target = 'out.f2', source = 'in.f2') -env.Fail(target = 'out.f3', source = 'in.f3') +Fail = Builder(action=r'%(_python_)s myfail.py $TARGETS $SOURCE') +env = Environment(BUILDERS={'Fail': Fail}) +env.Fail(target='out.f1', source='in.f1') +env.Fail(target='out.f2', source='in.f2') +env.Fail(target='out.f3', source='in.f3') """ % locals()) # in.f2 is not created to cause a Task.prepare exception @@ -100,7 +97,7 @@ test.write('in.f3', 'in.f3\n') # In Serial task mode, get the first exception and stop -test.run(arguments = '.', status = 2, stderr = expected_stderr) +test.run(arguments='.', status=2, stderr=expected_stderr) # In Parallel task mode, we will get all three exceptions. @@ -117,11 +114,9 @@ # walk of '.' and are already considered up-to-date when we kick off the # "simultaneous" builds of the output (target) files. -test.run(arguments = '-j7 -k .', status = 2, stderr = None) - +test.run(arguments='-j7 -k .', status=2, stderr=None) test.must_contain_all_lines(test.stderr(), expected_stderr_list) - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/exitfns.py scons-4.4.0+dfsg/test/exitfns.py --- scons-4.0.1+dfsg/test/exitfns.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/exitfns.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -35,7 +34,7 @@ test.skip_test("This test replaces the exit function which is needed by coverage to write test data; skipping test.") sconstruct = """ -from SCons.exitfuncs import * +from SCons.exitfuncs import register def x1(): print("running x1") diff -Nru scons-4.0.1+dfsg/test/File/File.py scons-4.4.0+dfsg/test/File/File.py --- scons-4.0.1+dfsg/test/File/File.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/File/File.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,82 @@ +#!/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__" + +""" +Verify that: + + -- the File() global function and environment method work correctly; + -- the former does not try to expand construction variables; + -- calling File() as a method of a File() object works correctly. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +env = Environment(FOO='fff', BAR='bbb') +print(File('ddd')) +print(File('$FOO')) +print(File('${BAR}_$BAR')) +rv = File(['mmm', 'nnn']) +rv_msg = [node.path for node in rv] +print(rv_msg) +print(env.File('eee')) +print(env.File('$FOO')) +print(env.File('${BAR}_$BAR')) +rv = env.File(['ooo', 'ppp']) +rv_msg = [node.path for node in rv] +print(rv_msg) +f1 = env.File('f1') +print(f1) +f2 = f1.File('f2') +print(f2) +""") + +expect = test.wrap_stdout(read_str = """\ +ddd +$FOO +${BAR}_$BAR +['mmm', 'nnn'] +eee +fff +bbb_bbb +['ooo', 'ppp'] +f1 +f2 +""", build_str="""\ +scons: `.' is up to date. +""") + +test.run(stdout=expect) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/File/File-relpath.py scons-4.4.0+dfsg/test/File/File-relpath.py --- scons-4.0.1+dfsg/test/File/File-relpath.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/File/File-relpath.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that .relpath works on file nodes. +Specifically ${TARGET.relpath}, ${SOURCE.relpath} match expected path +""" + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +test.subdir("src", ["src", "dir"]) + +test.dir_fixture("fixture/relpath") + +expected = [ + # expanding variable, expected string + ("${TARGETS.relpath}", "../foo/dir build/file1"), + ( + "${TARGETS.abspath}", + "%s %s" + % (os.path.abspath("base/../foo/dir"), os.path.abspath("base/build/file1")), + ), + ("${SOURCES.relpath}", "src/file"), + ("${SOURCES.abspath}", os.path.abspath("base/src/file")), + ("${SOURCE.relpath}", "src/file"), + ("${SOURCE.abspath}", os.path.abspath("base/src/file")), +] + +expected_stdout = "\n".join(["%s=%s" % (s, o) for s, o in expected]) +expected_stdout += "\nscons: `.' is up to date." + +if IS_WINDOWS: + expected_stdout = expected_stdout.replace("/", os.sep) + +test.run("-Q", chdir="base", status=0, stdout=expected_stdout + "\n") diff -Nru scons-4.0.1+dfsg/test/File/fixture/relpath/base/SConstruct scons-4.4.0+dfsg/test/File/fixture/relpath/base/SConstruct --- scons-4.0.1+dfsg/test/File/fixture/relpath/base/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/File/fixture/relpath/base/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,22 @@ +# Testcase to check that .relpath works on SOURCES,TARGETS, and the singular SOURCE +# This is the SConstruct for test/File/File-relpath.py +# +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) + +input_list = [ + "${TARGETS.relpath}", + "${TARGETS.abspath}", + "${SOURCES.relpath}", + "${SOURCES.abspath}", + "${SOURCE.relpath}", + "${SOURCE.abspath}", + ] +outputs = env.subst( + input_list, + target=[File("../foo/dir"), File("build/file1")], + source=[File("src/file")], +) + +for i,s in zip(input_list,outputs): + print("%s=%s"%(i,s)) diff -Nru scons-4.0.1+dfsg/test/File.py scons-4.4.0+dfsg/test/File.py --- scons-4.0.1+dfsg/test/File.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/File.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -#!/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__" - -""" -Verify that: - - -- the File() global function and environment method work correctly; - -- the former does not try to expand construction variables; - -- calling File() as a method of a File() object works correctly. -""" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', """ -env = Environment(FOO='fff', BAR='bbb') -print(File('ddd')) -print(File('$FOO')) -print(File('${BAR}_$BAR')) -rv = File(['mmm', 'nnn']) -rv_msg = [node.path for node in rv] -print(rv_msg) -print(env.File('eee')) -print(env.File('$FOO')) -print(env.File('${BAR}_$BAR')) -rv = env.File(['ooo', 'ppp']) -rv_msg = [node.path for node in rv] -print(rv_msg) -f1 = env.File('f1') -print(f1) -f2 = f1.File('f2') -print(f2) -""") - -expect = test.wrap_stdout(read_str = """\ -ddd -$FOO -${BAR}_$BAR -['mmm', 'nnn'] -eee -fff -bbb_bbb -['ooo', 'ppp'] -f1 -f2 -""", build_str="""\ -scons: `.' is up to date. -""") - -test.run(stdout=expect) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/fixture/mycompile.py scons-4.4.0+dfsg/test/fixture/mycompile.py --- scons-4.0.1+dfsg/test/fixture/mycompile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/mycompile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,19 +1,30 @@ -r""" -Phony "compiler" for testing SCons. +""" +Phony compiler for testing SCons. + +Copies its source files to the target file, dropping lines that match +a pattern, so we can recognize the tool has made a modification. +Intended for use as a *COM construction variable. + +Calling convention is: + argv[1] the function of the script (cc, c++, as, link etc.) + argv[2] the output file to write + argv[3:] one or more input files to "compile" -Copies its source files to the target file, dropping lines -that match a pattern, so we can recognize the tool -has made a modification. +Invocation often looks like: + Environment(CCCOM = r'%(_python_)s mycompile.py cc $TARGET $SOURCE', ... """ +import fileinput import sys +def fake_compile(): + skipline = f"/*{sys.argv[1]}*/\n".encode("utf-8") + with open(sys.argv[2], 'wb') as ofp, fileinput.input(files=sys.argv[3:], mode='rb') as ifp: + for line in ifp: + if line != skipline: + ofp.write(line) + + if __name__ == '__main__': - line = ('/*' + sys.argv[1] + '*/\n').encode() - with open(sys.argv[2], 'wb') as ofp: - for f in sys.argv[3:]: - with open(f, 'rb') as ifp: - lines = [ln for ln in ifp if ln != line] - for ln in lines: - ofp.write(ln) + fake_compile() sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/mygcc.py scons-4.4.0+dfsg/test/fixture/mygcc.py --- scons-4.0.1+dfsg/test/fixture/mygcc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/mygcc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,18 +1,35 @@ +""" +Phony compiler for testing SCons. + +Copies its source file to the target file, dropping lines that match +a pattern, so we can recognize the tool has made a modification. + +The first argument is the language (cc, c__, g77, etc.). + +Recognizes a -x option to append the language to 'mygcc.out' +for tracing purposes. + +Intended for use as $CC, $CXX, etc. +""" + import getopt import sys -compiler = sys.argv[1] -clen = len(compiler) + 1 -opts, args = getopt.getopt(sys.argv[2:], 'co:xf:K:') -for opt, arg in opts: - if opt == '-o': - out = arg - elif opt == '-x': - with open('mygcc.out', 'a') as f: - f.write(compiler + "\n") - -with open(out, 'w') as ofp, open(args[0], 'r') as ifp: - for line in ifp.readlines(): - if line[:clen] != '#' + compiler: - ofp.write(line) -sys.exit(0) +def fake_gcc(): + compiler = sys.argv[1].encode('utf-8') + opts, args = getopt.getopt(sys.argv[2:], 'co:xf:K:') + for opt, arg in opts: + if opt == '-o': + out = arg + elif opt == '-x': + with open('mygcc.out', 'ab') as logfile: + logfile.write(compiler + b"\n") + + with open(out, 'wb') as ofp, open(args[0], 'rb') as ifp: + for line in ifp: + if not line.startswith(b'#' + compiler): + ofp.write(line) + +if __name__ == '__main__': + fake_gcc() + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/mylex.py scons-4.4.0+dfsg/test/fixture/mylex.py --- scons-4.0.1+dfsg/test/fixture/mylex.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/mylex.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,65 @@ +""" +Phony lex for testing SCons. + +Writes the contents of input file to stdout, +after "substituting" $LEXFLAGS and $I_ARGS + +Needs to understand all the lex/flex options the testcases might use. +""" + +import getopt +import sys +from pathlib import Path + + +def make_side_effect(path, text): + p = Path(path) + if str(p.parent) != '.': + p.parent.mkdir(parents=True, exist_ok=True) + with p.open(mode="wb") as f: + f.write(text) + + +def fake_lex(): + make_header = None + make_table = None + + if sys.platform == 'win32': + longopts = ['nounistd'] + else: + longopts = [] + longopts.extend(['header-file=', 'tables-file=']) + cmd_opts, args = getopt.getopt(sys.argv[1:], 'I:tx', longopts) + opt_string = '' + i_arguments = '' + + for opt, arg in cmd_opts: + if opt == '-I': + i_arguments = f'{i_arguments} {arg}' + elif opt == '--header-file': + make_header = arg + opt_string = f'{opt_string} {opt}={arg}' + elif opt == '--tables-file': + make_table = arg + opt_string = f'{opt_string} {opt}={arg}' + else: + opt_string = f'{opt_string} {opt}' + + for arg in args: + with open(arg, 'rb') as ifp: + contents = ifp.read().decode(encoding='utf-8') + contents = contents.replace('LEXFLAGS', opt_string) + contents = contents.replace('LEX', 'mylex.py') + contents = contents.replace('I_ARGS', i_arguments) + sys.stdout.write(contents) + + # Extra bits: + if make_header: + make_side_effect(make_header, b"lex header\n") + if make_table: + make_side_effect(make_table, b"lex table\n") + + +if __name__ == '__main__': + fake_lex() + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/mylink.py scons-4.4.0+dfsg/test/fixture/mylink.py --- scons-4.0.1+dfsg/test/fixture/mylink.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/mylink.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,11 @@ """ -Dummy linker for use by tests" +Phony linker for testing SCons. + +Copies its source files to the target file, dropping lines that match +a pattern, so we can recognize the tool has made a modification. +Intended for use as the $LINK construction variable. """ +import fileinput import getopt import sys @@ -10,34 +15,32 @@ if opt == '-o': out = arg - with open(out, 'w') as ofp: - for f in args: - with open(f, 'r') as ifp: - for line in ifp.readlines(): - if line[:5] != '#link': - ofp.write(line) - sys.exit(0) + with open(out, 'wb') as ofp, fileinput.input(files=args, mode='rb') as ifp: + for line in ifp: + if not line.startswith(b'#link'): + ofp.write(line) def fake_win32_link(): args = sys.argv[1:] while args: - a = args[0] - if a == '-o': + arg = args[0] + if arg == '-o': out = args[1] args = args[2:] continue - if not a[0] in '/-': + if arg[0] not in '/-': break args = args[1:] - if a[:5].lower() == '/out:': out = a[5:] + if arg.lower().startswith('/out:'): + out = arg[5:] with open(args[0], 'rb') as ifp, open(out, 'wb') as ofp: - for line in ifp.readlines(): + for line in ifp: if not line.startswith(b'#link'): ofp.write(line) - sys.exit(0) if __name__ == '__main__': if sys.platform == 'win32': fake_win32_link() else: fake_link() + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/mylink_win32.py scons-4.4.0+dfsg/test/fixture/mylink_win32.py --- scons-4.0.1+dfsg/test/fixture/mylink_win32.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/mylink_win32.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -import sys - -args = sys.argv[1:] -while args: - a = args[0] - if a[0] != '/': - break - args.pop(0) - if a[:5] == '/OUT:': - out = a[5:] - -with open(out, 'w') as ofp, open(args[0], 'r') as ifp: - for line in ifp.readlines(): - if line[:5] != '#link': - ofp.write(line) -sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/myrewrite.py scons-4.4.0+dfsg/test/fixture/myrewrite.py --- scons-4.0.1+dfsg/test/fixture/myrewrite.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/myrewrite.py 2022-07-30 21:48:28.000000000 +0000 @@ -2,16 +2,19 @@ Phony tool to modify a file in place for testing SCons. Drops lines that match a pattern. Currently used to test -ranlib-related behavior without invoking ranlib. +ranlib and ar behavior without actually invoking those tools. """ import sys -if __name__ == '__main__': - line = ('/*' + sys.argv[1] + '*/\n').encode() +def rewrite(): + line = ('/*' + sys.argv[1] + '*/\n').encode('utf-8') with open(sys.argv[2], 'rb') as ifp: lines = [ln for ln in ifp if ln != line] with open(sys.argv[2], 'wb') as ofp: - for ln in lines: - ofp.write(ln) + ofp.writelines(lines) + + +if __name__ == '__main__': + rewrite() sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_query_toolset_version.py scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_query_toolset_version.py --- scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_query_toolset_version.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_query_toolset_version.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,15 @@ +import SCons +import SCons.Tool.MSCommon + +def DummyVsWhere(msvc_version, env): + # not testing versions with vswhere, so return none + return None + +for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR: + SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')] + +SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere + +msvc_version, msvc_toolset_version = SCons.Tool.MSCommon.msvc_query_version_toolset() + +print('msvc_version={}, msvc_toolset_version={}'.format(repr(msvc_version), repr(msvc_toolset_version))) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_sdk_versions.py scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_sdk_versions.py --- scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_sdk_versions.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_sdk_versions.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,15 @@ +import SCons +import SCons.Tool.MSCommon + +def DummyVsWhere(msvc_version, env): + # not testing versions with vswhere, so return none + return None + +for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR: + SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')] + +SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere + +sdk_version_list = SCons.Tool.MSCommon.msvc_sdk_versions() + +print('sdk_version_list='+repr(sdk_version_list)) diff -Nru scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_toolset_versions.py scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_toolset_versions.py --- scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_toolset_versions.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_msvc_toolset_versions.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,15 @@ +import SCons +import SCons.Tool.MSCommon + +def DummyVsWhere(msvc_version, env): + # not testing versions with vswhere, so return none + return None + +for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR: + SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')] + +SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere + +toolset_version_list = SCons.Tool.MSCommon.msvc_toolset_versions() + +print('toolset_version_list='+repr(toolset_version_list)) diff -Nru scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py --- scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,14 @@ +import SCons +import SCons.Tool.MSCommon + +def DummyVsWhere(msvc_version, env): + # not testing versions with vswhere, so return none + return None + +for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR: + SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')] + +SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere + +env = SCons.Environment.Environment(tools=['myignoredefaultmsvctool']) + diff -Nru scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_version.py scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_version.py --- scons-4.0.1+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_version.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/no_msvc/no_msvcs_sconstruct_version.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,19 @@ +import SCons +import SCons.Tool.MSCommon + + +def DummyVsWhere(msvc_version, env): + # not testing versions with vswhere, so return none + return None + + +for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR: + SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')] + +SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere + +SCons.Tool.MSCommon.msvc_set_notfound_policy('error') + +env = SCons.Environment.Environment(MSVC_VERSION='14.3') + + diff -Nru scons-4.0.1+dfsg/test/fixture/python_scanner/from_import_simple_package_module1_func.py scons-4.4.0+dfsg/test/fixture/python_scanner/from_import_simple_package_module1_func.py --- scons-4.0.1+dfsg/test/fixture/python_scanner/from_import_simple_package_module1_func.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/python_scanner/from_import_simple_package_module1_func.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +from simple_package.module1 import somefunc # noqa: F401 \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/fixture/python_scanner/from_nested1_import_multiple.py scons-4.4.0+dfsg/test/fixture/python_scanner/from_nested1_import_multiple.py --- scons-4.0.1+dfsg/test/fixture/python_scanner/from_nested1_import_multiple.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/python_scanner/from_nested1_import_multiple.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +from nested1 import module, nested2 # noqa: F401 \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/fixture/python_scanner/imports_unknown_files.py scons-4.4.0+dfsg/test/fixture/python_scanner/imports_unknown_files.py --- scons-4.0.1+dfsg/test/fixture/python_scanner/imports_unknown_files.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/python_scanner/imports_unknown_files.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +import doesntexist # noqa: F401 +import notthere.something # noqa: F401 +from notthere import a, few, things # noqa: F401 \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/fixture/python_scanner/simple_package/module1.py scons-4.4.0+dfsg/test/fixture/python_scanner/simple_package/module1.py --- scons-4.0.1+dfsg/test/fixture/python_scanner/simple_package/module1.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/python_scanner/simple_package/module1.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,2 @@ +def somefunc(): + return \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/fixture/wrapper.py scons-4.4.0+dfsg/test/fixture/wrapper.py --- scons-4.0.1+dfsg/test/fixture/wrapper.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/wrapper.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,10 @@ +""" +Command wrapper, for testing SCons. + +Writes the command name to file "wrapper.out", +then passes the command line on to subprocess. +No checking is done. +""" import os import sys import subprocess @@ -7,4 +14,4 @@ if '--version' not in sys.argv and '-dumpversion' not in sys.argv: with open(path, 'wb') as f: f.write(b"wrapper.py\n") - subprocess.run(sys.argv[1:]) + subprocess.run(sys.argv[1:], check=False) diff -Nru scons-4.0.1+dfsg/test/fixture/wrapper_with_args.py scons-4.4.0+dfsg/test/fixture/wrapper_with_args.py --- scons-4.0.1+dfsg/test/fixture/wrapper_with_args.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/fixture/wrapper_with_args.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,3 +1,10 @@ +""" +Command wrapper taking arguments, for testing SCons. + +Writes the command name and argument list to file "wrapper.out", +then passes the command line on to subprocess. +No checking is done. +""" import os import sys import subprocess @@ -6,4 +13,4 @@ path = os.path.join(os.path.dirname(os.path.relpath(__file__)), 'wrapper.out') with open(path, 'a') as f: f.write("wrapper_with_args.py %s\n" % " ".join(sys.argv[1:])) - subprocess.run(sys.argv[1:]) + subprocess.run(sys.argv[1:], check=False) diff -Nru scons-4.0.1+dfsg/test/Fortran/F03FILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/F03FILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/F03FILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F03FILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F03FILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/F03FILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/F03FILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F03FILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F03FLAGS.py scons-4.4.0+dfsg/test/Fortran/F03FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/F03FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F03FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F03.py scons-4.4.0+dfsg/test/Fortran/F03.py --- scons-4.0.1+dfsg/test/Fortran/F03.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F03.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F08FILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/F08FILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/F08FILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F08FILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F08FILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/F08FILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/F08FILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F08FILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F08FLAGS.py scons-4.4.0+dfsg/test/Fortran/F08FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/F08FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F08FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F08.py scons-4.4.0+dfsg/test/Fortran/F08.py --- scons-4.0.1+dfsg/test/Fortran/F08.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F08.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F77FILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/F77FILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/F77FILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F77FILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F77FILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/F77FILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/F77FILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F77FILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F77FLAGS.py scons-4.4.0+dfsg/test/Fortran/F77FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/F77FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F77FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F77PATH.py scons-4.4.0+dfsg/test/Fortran/F77PATH.py --- scons-4.0.1+dfsg/test/Fortran/F77PATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F77PATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 @@ -39,30 +38,27 @@ fc = 'f77' if not test.detect_tool(fc): - test.skip_test('Could not find a f77 tool; skipping test.\n') - -test.subdir('include', - 'subdir', - ['subdir', 'include'], - 'foobar', - 'inc2') - - - -test.write('SConstruct', """ -env = Environment(F77 = '%s', - F77PATH = ['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], - FOO='include', - F77FLAGS = '-x f77') + # gfortran names all variants the same, try it too + fc = 'gfortran' + if not test.detect_tool(fc): + test.skip_test('Could not find a f77 tool; skipping test.\n') + +test.subdir('include', 'subdir', ['subdir', 'include'], 'foobar', 'inc2') + +test.write('SConstruct', """\ +env = Environment( + F77='%s', + F77PATH=['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], + FOO='include', + F77FLAGS='-x f77', +) obj = env.Object(target='foobar/prog', source='subdir/prog.f77') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(F77 = '%s', - F77PATH=[include, '#foobar', '#subdir'], - F77FLAGS = '-x f77') +env = Environment(F77='%s', F77PATH=[include, '#foobar', '#subdir'], F77FLAGS='-x f77') SConscript('variant/SConscript', "env") """ % (fc, fc)) @@ -115,8 +111,6 @@ PRINT *, 'subdir/ttt.f77' """) - - test.run(arguments = args) test.run(program = test.workpath(prog), @@ -151,8 +145,6 @@ test.up_to_date(arguments = args) - - test.write(['include', 'foo.f77'], r""" PRINT *, 'include/foo.f77 2' @@ -193,9 +185,6 @@ test.up_to_date(arguments = args) - - -# test.write(['include', 'bar.f77'], r""" PRINT *, 'include/bar.f77 2' @@ -235,22 +224,22 @@ test.up_to_date(arguments = args) - - # Change F77PATH and make sure we don't rebuild because of it. -test.write('SConstruct', """ -env = Environment(F77 = '%s', - F77PATH = Split('inc2 include ${TARGET.dir} ${SOURCE.dir}'), - F77FLAGS = '-x f77') +test.write('SConstruct', """\ +env = Environment( + F77='%s', + F77PATH=Split('inc2 include ${TARGET.dir} ${SOURCE.dir}'), + F77FLAGS='-x f77', +) obj = env.Object(target='foobar/prog', source='subdir/prog.f77') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(F77 = '%s', - F77PATH=['inc2', include, '#foobar', '#subdir'], - F77FLAGS = '-x f77') +env = Environment( + F77='%s', F77PATH=['inc2', include, '#foobar', '#subdir'], F77FLAGS='-x f77' +) SConscript('variant/SConscript', "env") """ % (fc, fc)) @@ -294,20 +283,15 @@ test.up_to_date(arguments = args) - - # Check that a null-string F77PATH doesn't blow up. -test.write('SConstruct', """ -env = Environment(tools = ['f77'], F77PATH = '', F77FLAGS = '-x f77') -env.Object('foo', source = 'empty.f77') -""") +test.write('SConstruct', """\ +env = Environment(tools=['%s'], F77PATH='', F77FLAGS='-x f77') +env.Object('foo', source='empty.f77') +""" % fc) test.write('empty.f77', '') - test.run(arguments = '.') - - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Fortran/F77.py scons-4.4.0+dfsg/test/Fortran/F77.py --- scons-4.0.1+dfsg/test/Fortran/F77.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F77.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F90FILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/F90FILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/F90FILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F90FILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F90FILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/F90FILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/F90FILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F90FILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F90FLAGS.py scons-4.4.0+dfsg/test/Fortran/F90FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/F90FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F90FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F90PATH.py scons-4.4.0+dfsg/test/Fortran/F90PATH.py --- scons-4.0.1+dfsg/test/Fortran/F90PATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F90PATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 @@ -39,32 +38,29 @@ fc = 'f90' if not test.detect_tool(fc): - test.skip_test('Could not find a f90 tool; skipping test.\n') - -test.subdir('include', - 'subdir', - ['subdir', 'include'], - 'foobar', - 'inc2') - + # gfortran names all variants the same, try it too + fc = 'gfortran' + if not test.detect_tool(fc): + test.skip_test('Could not find a f90 tool; skipping test.\n') +test.subdir('include', 'subdir', ['subdir', 'include'], 'foobar', 'inc2') test.write('SConstruct', """ -env = Environment(F90 = r'%s', - F90PATH = ['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], - LINK = '$F90', - FOO='include') +env = Environment( + F90=r'%s', + F90PATH=['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], + LINK='$F90', + FOO='include', +) obj = env.Object(target='foobar/prog', source='subdir/prog.f90') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(F90 = r'%s', - F90PATH=[include, '#foobar', '#subdir'], - LINK = '$F90') +env = Environment(F90=r'%s', F90PATH=[include, '#foobar', '#subdir'], LINK='$F90') SConscript('variant/SConscript', "env") -""" % (fc, fc, )) +""" % (fc, fc)) test.write(['subdir', 'SConscript'], """ @@ -115,8 +111,6 @@ PRINT *, 'subdir/ttt.f90' """) - - test.run(arguments = args) test.run(program = test.workpath(prog), @@ -151,8 +145,6 @@ test.up_to_date(arguments = args) - - test.write(['include', 'foo.f90'], r""" PRINT *, 'include/foo.f90 2' @@ -193,9 +185,6 @@ test.up_to_date(arguments = args) - - -# test.write(['include', 'bar.f90'], r""" PRINT *, 'include/bar.f90 2' @@ -238,27 +227,28 @@ # Change F90PATH and make sure we don't rebuild because of it. -test.write('SConstruct', """ -env = Environment(F90 = r'%s', - F90PATH = Split('inc2 include ${TARGET.dir} ${SOURCE.dir}'), - LINK = '$F90') +test.write('SConstruct', """\ +env = Environment( + F90=r'%s', + F90PATH=Split('inc2 include ${TARGET.dir} ${SOURCE.dir}'), + LINK='$F90' +) obj = env.Object(target='foobar/prog', source='subdir/prog.f90') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(F90 = r'%s', - F90PATH=['inc2', include, '#foobar', '#subdir'], - LINK = '$F90') +env = Environment( + F90=r'%s', + F90PATH=['inc2', include, '#foobar', '#subdir'], + LINK='$F90', +) SConscript('variant/SConscript', "env") """ % (fc, fc)) test.up_to_date(arguments = args) - - -# test.write(['inc2', 'foo.f90'], r""" PRINT *, 'inc2/foo.f90 1' @@ -296,8 +286,6 @@ test.up_to_date(arguments = args) - - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Fortran/F90.py scons-4.4.0+dfsg/test/Fortran/F90.py --- scons-4.0.1+dfsg/test/Fortran/F90.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F90.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F95FILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/F95FILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/F95FILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F95FILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F95FILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/F95FILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/F95FILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F95FILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F95FLAGS.py scons-4.4.0+dfsg/test/Fortran/F95FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/F95FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F95FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/F95.py scons-4.4.0+dfsg/test/Fortran/F95.py --- scons-4.0.1+dfsg/test/Fortran/F95.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/F95.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/fixture/myfortran_flags.py scons-4.4.0+dfsg/test/Fortran/fixture/myfortran_flags.py --- scons-4.0.1+dfsg/test/Fortran/fixture/myfortran_flags.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/fixture/myfortran_flags.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,16 +1,19 @@ import getopt import sys + comment = ('#' + sys.argv[1]).encode() -opts, args = getopt.getopt(sys.argv[2:], 'cf:o:xy') + +opts, args = getopt.getopt(sys.argv[2:], 'cf:o:xyz') optstring = '' length = len(comment) for opt, arg in opts: if opt == '-o': out = arg elif opt not in ('-f', '-K'): optstring = optstring + ' ' + opt -infile = open(args[0], 'rb') -outfile = open(out, 'wb') -outfile.write((optstring + "\n").encode()) -for l in infile.readlines(): - if l[:length] != comment: - outfile.write(l) + +with open(args[0], 'rb') as infile, open(out, 'wb') as outfile: + outfile.write((optstring + "\n").encode()) + for l in infile: + if not l.startswith(comment): + outfile.write(l) + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Fortran/fixture/myfortran.py scons-4.4.0+dfsg/test/Fortran/fixture/myfortran.py --- scons-4.0.1+dfsg/test/Fortran/fixture/myfortran.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/fixture/myfortran.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,14 +1,17 @@ import getopt import sys + print(sys.argv) comment = ('#' + sys.argv[1]).encode() -length = len(comment) + opts, args = getopt.getopt(sys.argv[2:], 'cf:o:K:') for opt, arg in opts: - if opt == '-o': out = arg -infile = open(args[0], 'rb') -outfile = open(out, 'wb') -for l in infile.readlines(): - if l[:length] != comment: - outfile.write(l) + if opt == '-o': + out = arg + +with open(args[0], 'rb') as infile, open(out, 'wb') as outfile: + for l in infile: + if not l.startswith(comment): + outfile.write(l) + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANCOMMONFLAGS.py scons-4.4.0+dfsg/test/Fortran/FORTRANCOMMONFLAGS.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANCOMMONFLAGS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANCOMMONFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that while FORTRANFLAGS is not passed to another dialect, +FORTRANCOMMONFLAGS is passed to both. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() +_exe = TestSCons._exe + +test.file_fixture('mylink.py') +test.file_fixture(['fixture', 'myfortran_flags.py']) + +test.write('SConstruct', """ +env = Environment( + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + F90=r'%(_python_)s myfortran_flags.py g90', + F90FLAGS='-x', + FORTRAN=r'%(_python_)s myfortran_flags.py fortran', + FORTRANFLAGS='-y', + FORTRANCOMMONFLAGS='-z', +) +env.Program(target='test01', source='test01.f') +env.Program(target='test02', source='test02.F') +env.Program(target='test03', source='test03.for') +env.Program(target='test04', source='test04.FOR') +env.Program(target='test05', source='test05.ftn') +env.Program(target='test06', source='test06.FTN') +env.Program(target='test07', source='test07.fpp') +env.Program(target='test08', source='test08.FPP') +env.Program(target='test11', source='test11.f90') +env.Program(target='test12', source='test12.F90') +""" % locals()) + +test.write('test01.f', "This is a .f file.\n#link\n#fortran\n") +test.write('test02.F', "This is a .F file.\n#link\n#fortran\n") +test.write('test03.for', "This is a .for file.\n#link\n#fortran\n") +test.write('test04.FOR', "This is a .FOR file.\n#link\n#fortran\n") +test.write('test05.ftn', "This is a .ftn file.\n#link\n#fortran\n") +test.write('test06.FTN', "This is a .FTN file.\n#link\n#fortran\n") +test.write('test07.fpp', "This is a .fpp file.\n#link\n#fortran\n") +test.write('test08.FPP', "This is a .FPP file.\n#link\n#fortran\n") +test.write('test11.f90', "This is a .f90 file.\n#link\n#g90\n") +test.write('test12.F90', "This is a .F90 file.\n#link\n#g90\n") + +test.run(arguments = '.', stderr = None) + +test.must_match('test01' + _exe, " -c -z -y\nThis is a .f file.\n") +test.must_match('test02' + _exe, " -c -z -y\nThis is a .F file.\n") +test.must_match('test03' + _exe, " -c -z -y\nThis is a .for file.\n") +test.must_match('test04' + _exe, " -c -z -y\nThis is a .FOR file.\n") +test.must_match('test05' + _exe, " -c -z -y\nThis is a .ftn file.\n") +test.must_match('test06' + _exe, " -c -z -y\nThis is a .FTN file.\n") +test.must_match('test07' + _exe, " -c -z -y\nThis is a .fpp file.\n") +test.must_match('test08' + _exe, " -c -z -y\nThis is a .FPP file.\n") +test.must_match('test11' + _exe, " -c -z -x\nThis is a .f90 file.\n") +test.must_match('test12' + _exe, " -c -z -x\nThis is a .F90 file.\n") + + +fc = 'f90' +g90 = test.detect_tool(fc) +if g90: + test.file_fixture('wrapper.py') + + test.write('SConstruct', """ +foo = Environment(F90='%(fc)s') +f90 = foo.Dictionary('F90') +bar = foo.Clone(F90=r'%(_python_)s wrapper.py ' + f90) +foo.Program(target='foo', source='foo.f90') +bar.Program(target='bar', source='bar.f90') +""" % locals()) + + test.write('foo.f90', r""" + PROGRAM FOO + PRINT *,'foo.f90' + END +""") + + test.write('bar.f90', r""" + PROGRAM BAR + PRINT *,'bar.f90' + END +""") + + test.run(arguments='foo' + _exe, stderr=None) + test.run(program=test.workpath('foo'), stdout=" foo.f90\n") + test.must_not_exist('wrapper.out') + + import sys + + if sys.platform[:5] == 'sunos': + test.run(arguments='bar' + _exe, stderr=None) + else: + test.run(arguments='bar' + _exe) + test.run(program=test.workpath('bar'), stdout=" bar.f90\n") + test.must_match('wrapper.out', "wrapper.py\n") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANFILESUFFIXES2.py scons-4.4.0+dfsg/test/Fortran/FORTRANFILESUFFIXES2.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANFILESUFFIXES2.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANFILESUFFIXES2.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,15 +22,11 @@ # 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 TestSCons _python_ = TestSCons._python_ -_exe = TestSCons._exe +_exe = TestSCons._exe test = TestSCons.TestSCons() @@ -36,28 +34,30 @@ test.file_fixture(['fixture', 'myfortran.py']) # Test non default file suffix: .f, .f90 and .f95 for FORTRAN -test.write('SConstruct', """ -env = Environment(LINK = r'%(_python_)s mylink.py', - LINKFLAGS = [], - F77 = r'%(_python_)s myfortran.py g77', - FORTRAN = r'%(_python_)s myfortran.py fortran', - FORTRANFILESUFFIXES = ['.f', '.f95', '.f90', '.ffake'], - tools = ['default', 'fortran']) -#print(env.Dump()) -env.Program(target = 'test01', source = 'test01.f') -env.Program(target = 'test02', source = 'test02.f90') -env.Program(target = 'test03', source = 'test03.f95') -env.Program(target = 'test04', source = 'test04.ffake') -env.Program(target = 'test05', source = 'test05.f77') +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment( + LINK=r'%(_python_)s mylink.py', + LINKFLAGS=[], + F77=r'%(_python_)s myfortran.py g77', + FORTRAN=r'%(_python_)s myfortran.py fortran', + FORTRANFILESUFFIXES=['.f', '.f95', '.f90', '.ffake'], + tools=['default', 'fortran'], +) +env.Program(target='test01', source='test01.f') +env.Program(target='test02', source='test02.f90') +env.Program(target='test03', source='test03.f95') +env.Program(target='test04', source='test04.ffake') +env.Program(target='test05', source='test05.f77') """ % locals()) -test.write('test01.f', "This is a .f file.\n#link\n#fortran\n") -test.write('test02.f90', "This is a .f90 file.\n#link\n#fortran\n") +test.write('test01.f', "This is a .f file.\n#link\n#fortran\n") +test.write('test02.f90', "This is a .f90 file.\n#link\n#fortran\n") test.write('test03.f95', "This is a .f95 file.\n#link\n#fortran\n") test.write('test04.ffake', "This is a .ffake file.\n#link\n#fortran\n") test.write('test05.f77', "This is a .f77 file.\n#link\n#g77\n") -test.run(arguments = '.', stderr = None) +test.run(arguments='.', stderr=None) test.must_match('test01' + _exe, "This is a .f file.\n") test.must_match('test02' + _exe, "This is a .f90 file.\n") diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANFILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/FORTRANFILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANFILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANFILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANFLAGS.py scons-4.4.0+dfsg/test/Fortran/FORTRANFLAGS.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANPATH.py scons-4.4.0+dfsg/test/Fortran/FORTRANPATH.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -20,9 +21,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 @@ -39,28 +37,26 @@ fc = 'f77' if not test.detect_tool(fc): - test.skip_test('Could not find a f77 tool; skipping test.\n') - -test.subdir('include', - 'subdir', - ['subdir', 'include'], - 'foobar', - 'inc2') - - - -test.write('SConstruct', """ -env = Environment(FORTRAN = '%s', - FORTRANPATH = ['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], - FOO='include') + # gfortran names all variants the same, try it too + fc = 'gfortran' + if not test.detect_tool(fc): + test.skip_test('Could not find a f77 tool; skipping test.\n') + +test.subdir('include', 'subdir', ['subdir', 'include'], 'foobar', 'inc2') + +test.write('SConstruct', """\ +env = Environment( + FORTRAN='%s', + FORTRANPATH=['$FOO', '${TARGET.dir}', '${SOURCE.dir}'], + FOO='include' +) obj = env.Object(target='foobar/prog', source='subdir/prog.f') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(FORTRAN = '%s', - FORTRANPATH=[include, '#foobar', '#subdir']) +env = Environment(FORTRAN='%s', FORTRANPATH=[include, '#foobar', '#subdir']) SConscript('variant/SConscript', "env") """ % (fc, fc)) @@ -153,8 +149,6 @@ test.up_to_date(arguments = args) - - test.write(['include', 'foo.f'], r""" PRINT *, 'include/foo.f 2' @@ -199,9 +193,6 @@ test.up_to_date(arguments = args) - - -# test.write(['include', 'bar.f'], r""" PRINT *, 'include/bar.f 2' @@ -249,25 +240,26 @@ # Change FORTRANPATH and make sure we don't rebuild because of it. -test.write('SConstruct', """ -env = Environment(FORTRAN = '%s', - FORTRANPATH = Split('inc2 include ${TARGET.dir} ${SOURCE.dir}')) +test.write('SConstruct', """\ +env = Environment( + FORTRAN='%s', + FORTRANPATH=Split('inc2 include ${TARGET.dir} ${SOURCE.dir}'), +) obj = env.Object(target='foobar/prog', source='subdir/prog.f') env.Program(target='prog', source=obj) SConscript('subdir/SConscript', "env") VariantDir('variant', 'subdir', 0) include = Dir('include') -env = Environment(FORTRAN = '%s', - FORTRANPATH=['inc2', include, '#foobar', '#subdir']) +env = Environment( + FORTRAN='%s', + FORTRANPATH=['inc2', include, '#foobar', '#subdir'], +) SConscript('variant/SConscript', "env") """ % (fc, fc)) test.up_to_date(arguments = args) - - -# test.write(['inc2', 'foo.f'], r""" PRINT *, 'inc2/foo.f 1' @@ -310,8 +302,6 @@ test.up_to_date(arguments = args) - - # Check that a null-string FORTRANPATH doesn't blow up. test.write('SConstruct', """ env = Environment(FORTRANPATH = '') diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRANPPFILESUFFIXES.py scons-4.4.0+dfsg/test/Fortran/FORTRANPPFILESUFFIXES.py --- scons-4.0.1+dfsg/test/Fortran/FORTRANPPFILESUFFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRANPPFILESUFFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,9 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import string -import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/Fortran/FORTRAN.py scons-4.4.0+dfsg/test/Fortran/FORTRAN.py --- scons-4.0.1+dfsg/test/Fortran/FORTRAN.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/FORTRAN.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF03.py scons-4.4.0+dfsg/test/Fortran/SHF03.py --- scons-4.0.1+dfsg/test/Fortran/SHF03.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF03.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF08.py scons-4.4.0+dfsg/test/Fortran/SHF08.py --- scons-4.0.1+dfsg/test/Fortran/SHF08.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF08.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF77FLAGS.py scons-4.4.0+dfsg/test/Fortran/SHF77FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/SHF77FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF77FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF77.py scons-4.4.0+dfsg/test/Fortran/SHF77.py --- scons-4.0.1+dfsg/test/Fortran/SHF77.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF77.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF90FLAGS.py scons-4.4.0+dfsg/test/Fortran/SHF90FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/SHF90FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF90FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF90.py scons-4.4.0+dfsg/test/Fortran/SHF90.py --- scons-4.0.1+dfsg/test/Fortran/SHF90.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF90.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF95FLAGS.py scons-4.4.0+dfsg/test/Fortran/SHF95FLAGS.py --- scons-4.0.1+dfsg/test/Fortran/SHF95FLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF95FLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHF95.py scons-4.4.0+dfsg/test/Fortran/SHF95.py --- scons-4.0.1+dfsg/test/Fortran/SHF95.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHF95.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHFORTRANFLAGS.py scons-4.4.0+dfsg/test/Fortran/SHFORTRANFLAGS.py --- scons-4.0.1+dfsg/test/Fortran/SHFORTRANFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHFORTRANFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Fortran/SHFORTRAN.py scons-4.4.0+dfsg/test/Fortran/SHFORTRAN.py --- scons-4.0.1+dfsg/test/Fortran/SHFORTRAN.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Fortran/SHFORTRAN.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/GetBuildFailures/serial.py scons-4.4.0+dfsg/test/GetBuildFailures/serial.py --- scons-4.0.1+dfsg/test/GetBuildFailures/serial.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/GetBuildFailures/serial.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,7 +22,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. -# """ Verify that the GetBuildFailures() function returns a list of @@ -28,8 +29,6 @@ attributes we expect to be most commonly used. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons import re @@ -196,7 +195,7 @@ scons: *** [f13] f13: My SConsEnvironmentError scons: *** [f14] InternalError : My InternalError """) + \ -r"""Traceback \((most recent call|innermost) last\): +r"""Traceback \(most recent call last\): ( File ".+", line \d+, in \S+ [^\n]+ )*( File ".+", line \d+, in \S+ diff -Nru scons-4.0.1+dfsg/test/GetOption/BadSetOption.py scons-4.4.0+dfsg/test/GetOption/BadSetOption.py --- scons-4.0.1+dfsg/test/GetOption/BadSetOption.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/GetOption/BadSetOption.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that invalid SetOption calls generate expected errors. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +badopts = ( + ("no_such_var", True, "This option is not settable from a SConscript file: no_such_var"), + ("num_jobs", -22, "A positive integer is required: -22"), + ("max_drift", "'Foo'", "An integer is required: 'Foo'"), + ("duplicate", "'cookie'", "Not a valid duplication style: cookie"), + ("diskcheck", "'off'", "Not a valid diskcheck value: off"), + ("md5_chunksize", "'big'", "An integer is required: 'big'"), + ("hash_chunksize", "'small'", "An integer is required: 'small'"), +) + +for opt, value, expect in badopts: + SConstruct = "SC-" + opt + test.write( + SConstruct, + """\ +DefaultEnvironment(tools=[]) +SetOption("%(opt)s", %(value)s) +""" + % locals(), + ) + expect = r"scons: *** %s" % expect + test.run(arguments='-Q -f %s .' % SConstruct, stderr=None, status=2) + test.must_contain_all(test.stderr(), expect) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/GetOption/GetSetOption.py scons-4.4.0+dfsg/test/GetOption/GetSetOption.py --- scons-4.0.1+dfsg/test/GetOption/GetSetOption.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/GetOption/GetSetOption.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test getting and setting options through global functions +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) +option_list = ['clean', 'implicit_cache', 'max_drift', 'num_jobs'] +val = 1 +for option in option_list: + SetOption(option, val) + o = env.GetOption(option) + assert o == val, "%s %s != %s" % (option, o, val) + val = val + 1 +for option in option_list: + env.SetOption(option, val) + o = GetOption(option) + assert o == val, "%s %s != %s" % (option, o, val) + val = val + 1 +""") + +test.run(arguments = '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/GetOption/help.py scons-4.4.0+dfsg/test/GetOption/help.py --- scons-4.0.1+dfsg/test/GetOption/help.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/GetOption/help.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test use of GetOption('help') to short-circuit work. @@ -40,14 +39,14 @@ print("no help for you") """) -test.run(arguments = '-q -Q', stdout = "no help for you\n") +test.run(arguments='-q -Q', stdout="no help for you\n") expect = "GetOption('help') set" -test.run(arguments = '-q -Q -h') +test.run(arguments='-q -Q -h') test.fail_test(test.stdout().split('\n')[0] != expect) -test.run(arguments = '-q -Q --help') +test.run(arguments='-q -Q --help') test.fail_test(test.stdout().split('\n')[0] != expect) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/GetSetOption.py scons-4.4.0+dfsg/test/GetSetOption.py --- scons-4.0.1+dfsg/test/GetSetOption.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/GetSetOption.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -#!/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 getting and setting options through global functions -""" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', """ -env = Environment() -option_list = ['clean', 'implicit_cache', 'max_drift', 'num_jobs'] -val = 1 -for option in option_list: - SetOption(option, val) - o = env.GetOption(option) - assert o == val, "%s %s != %s" % (option, o, val) - val = val + 1 -for option in option_list: - env.SetOption(option, val) - o = GetOption(option) - assert o == val, "%s %s != %s" % (option, o, val) - val = val + 1 -""") - -test.run(arguments = '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/gettext/MOFiles/UserExamples.py scons-4.4.0+dfsg/test/gettext/MOFiles/UserExamples.py --- scons-4.0.1+dfsg/test/gettext/MOFiles/UserExamples.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/gettext/MOFiles/UserExamples.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ """ import TestSCons -import os test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/gettext/POUpdate/UserExamples.py scons-4.4.0+dfsg/test/gettext/POUpdate/UserExamples.py --- scons-4.0.1+dfsg/test/gettext/POUpdate/UserExamples.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/gettext/POUpdate/UserExamples.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ """ import TestSCons -import os test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/gettext/Translate/MultiCatalog.py scons-4.4.0+dfsg/test/gettext/Translate/MultiCatalog.py --- scons-4.0.1+dfsg/test/gettext/Translate/MultiCatalog.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/gettext/Translate/MultiCatalog.py 2022-07-30 21:48:28.000000000 +0000 @@ -42,7 +42,6 @@ # replicate the bug. import TestSCons -from os import path test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/ignore-command.py scons-4.4.0+dfsg/test/ignore-command.py --- scons-4.0.1+dfsg/test/ignore-command.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/ignore-command.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/implicit/changed-node.py scons-4.4.0+dfsg/test/implicit/changed-node.py --- scons-4.0.1+dfsg/test/implicit/changed-node.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/implicit/changed-node.py 2022-07-30 21:48:28.000000000 +0000 @@ -126,8 +126,9 @@ #def clean(full=0): # for f in ('d','b','a','SConstruct'): # rm(f) +# database_name = test.get_sconsignname() # if full: -# for f in ('.sconsign.dblite', 'build.py'): +# for f in (database_name + '.dblite', 'build.py'): # rm(f) # #clean(1) diff -Nru scons-4.0.1+dfsg/test/import.py scons-4.4.0+dfsg/test/import.py --- scons-4.0.1+dfsg/test/import.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/import.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ 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 @@ 'MSCommon', # clang common "clangCommon", + # link common logic + "linkCommon", # Sun pkgchk and pkginfo common stuff 'sun_pkg.py', # RPM utilities diff -Nru scons-4.0.1+dfsg/test/Install/Clone.py scons-4.4.0+dfsg/test/Install/Clone.py --- scons-4.0.1+dfsg/test/Install/Clone.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/Clone.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that we can Install() and InstallAs() from a construction diff -Nru scons-4.0.1+dfsg/test/Install/directories.py scons-4.4.0+dfsg/test/Install/directories.py --- scons-4.0.1+dfsg/test/Install/directories.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/directories.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,30 +22,28 @@ # 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 using Install() on directories. """ -import os.path import TestSCons test = TestSCons.TestSCons() -test.subdir('outside', - 'work', - ['work', 'dir1'], - ['work', 'dir1', 'sub'], - ['work', 'dir2'], - ['work', 'dir2', 'sub'], - ['work', 'dir3'], - ['work', 'dir3', 'sub'], - ['work', 'dir4'], - ['work', 'dir4', 'sub']) +test.subdir( + 'outside', + 'work', + ['work', 'dir1'], + ['work', 'dir1', 'sub'], + ['work', 'dir2'], + ['work', 'dir2', 'sub'], + ['work', 'dir3'], + ['work', 'dir3', 'sub'], + ['work', 'dir4'], + ['work', 'dir4', 'sub'], +) test.write(['work', 'SConstruct'], """\ DefaultEnvironment(tools=[]) @@ -81,7 +81,7 @@ Install directory: "dir4" as "%s" """ % tuple(arguments)) -test.run(chdir = 'work', arguments = arguments, stdout = expect) +test.run(chdir='work', arguments=arguments, stdout=expect) test.must_match(test.workpath('outside', 'dir1', 'f2'), "work/dir1/f2\n") test.must_match(test.workpath('outside', 'dir1', 'sub', 'f3'), "work/dir1/sub/f3\n") diff -Nru scons-4.0.1+dfsg/test/Install/dir-exists.py scons-4.4.0+dfsg/test/Install/dir-exists.py --- scons-4.0.1+dfsg/test/Install/dir-exists.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/dir-exists.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Test using Install() on directories that exist. @@ -49,7 +48,7 @@ echo hi > a%sf Install directory: "a" as "b%sa" """%(os.sep, os.sep) -test.run(arguments = ["-Q"], stdout = expect) +test.run(arguments=["-Q"], stdout=expect) test.must_exist(test.workpath('a', 'f')) test.must_exist(test.workpath('b', 'a', 'f')) diff -Nru scons-4.0.1+dfsg/test/Install/fixture/SConstruct-multi scons-4.4.0+dfsg/test/Install/fixture/SConstruct-multi --- scons-4.0.1+dfsg/test/Install/fixture/SConstruct-multi 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/fixture/SConstruct-multi 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,24 @@ +# first run creates a src file, makes it read-only, and installs. +# second run updates src, Install should successfully replace +# the previous install (read-only attr on Windows might fail it) + +import os +import pathlib +import stat + +destdir = pathlib.Path("bin") +destdir.mkdir(exist_ok=True) + +srcfile = pathlib.Path("hello") +try: + srcfile.chmod(stat.S_IREAD | stat.S_IWRITE) +except OSError: + pass + +with srcfile.open(mode="w") as f: + print("Hello from ", os.getpid(), file=f) +srcfile.chmod(stat.S_IREAD) + +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) +env.Install('bin', 'hello') diff -Nru scons-4.0.1+dfsg/test/Install/InstallAs.py scons-4.4.0+dfsg/test/Install/InstallAs.py --- scons-4.0.1+dfsg/test/Install/InstallAs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/InstallAs.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Test the InstallAs() Environment method. @@ -83,7 +82,6 @@ test.up_to_date(arguments = '.') -# test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Install/Install.py scons-4.4.0+dfsg/test/Install/Install.py --- scons-4.0.1+dfsg/test/Install/Install.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/Install.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that the Install() Builder works diff -Nru scons-4.0.1+dfsg/test/Install/Install-ro.py scons-4.4.0+dfsg/test/Install/Install-ro.py --- scons-4.0.1+dfsg/test/Install/Install-ro.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/Install-ro.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# +# MIT Licenxe +# +# 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. + +""" +Test that SCons allows Install on top of an existing read-only file. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.file_fixture('fixture/SConstruct-multi', 'SConstruct') +test.run(arguments=["-Q"]) +test.run(arguments=["-Q"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: diff -Nru scons-4.0.1+dfsg/test/Install/INSTALLSTR.py scons-4.4.0+dfsg/test/Install/INSTALLSTR.py --- scons-4.0.1+dfsg/test/Install/INSTALLSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/INSTALLSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Test that the $INSTALLSTR variable is displayed when we install a file. @@ -36,16 +35,18 @@ test.subdir('install') +# Check that spaces aren't stripped in INSTALLSTR by using +# extra whitespace in the string (issue 2018) test.write('SConstruct', """\ DefaultEnvironment(tools=[]) -env = Environment(tools=[], INSTALLSTR = 'INSTALL $SOURCE => $TARGET!') +env = Environment(tools=[], INSTALLSTR='INSTALL $SOURCE => $TARGET!') env.Install('install', 'file') """) test.write('file', "file\n") test.run(stdout=test.wrap_stdout("""\ -INSTALL file => %s! +INSTALL file => %s! """) % os.path.join('install', 'file')) test.must_match(['install', 'file'], "file\n") diff -Nru scons-4.0.1+dfsg/test/Install/multi-dir/src/SConstruct scons-4.4.0+dfsg/test/Install/multi-dir/src/SConstruct --- scons-4.0.1+dfsg/test/Install/multi-dir/src/SConstruct 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/multi-dir/src/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -1,7 +1,8 @@ # This tests for a bug where installing a sequence dirs and subdirs # outside the source tree can cause SCons to fail to create the dest # dir. -import os, os.path, shutil +import os + DefaultEnvironment(tools=[]) env=Environment(tools=[]) dst='../build' diff -Nru scons-4.0.1+dfsg/test/Install/multi-dir.py scons-4.4.0+dfsg/test/Install/multi-dir.py --- scons-4.0.1+dfsg/test/Install/multi-dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/multi-dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that using Install to create multiple dir hierarchies outside diff -Nru scons-4.0.1+dfsg/test/Install/multi.py scons-4.4.0+dfsg/test/Install/multi.py --- scons-4.0.1+dfsg/test/Install/multi.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/multi.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that multiple calls to test.Install() with the same file @@ -42,8 +41,7 @@ test.write('file1', "file1\n") -test.run(arguments = '.') - +test.run(arguments='.') test.must_match(['install', 'file1'], "file1\n") test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Install/non-ascii-name.py scons-4.4.0+dfsg/test/Install/non-ascii-name.py --- scons-4.0.1+dfsg/test/Install/non-ascii-name.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/non-ascii-name.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,7 +1,8 @@ -# -*- coding: utf-8 -*- #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,15 +22,11 @@ # 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__" """ Verify that the Install() Builder works """ -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/Install/no-top-relative.py scons-4.4.0+dfsg/test/Install/no-top-relative.py --- scons-4.0.1+dfsg/test/Install/no-top-relative.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/no-top-relative.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that we can install a file if its file name portion begins diff -Nru scons-4.0.1+dfsg/test/Install/option--install-sandbox.py scons-4.4.0+dfsg/test/Install/option--install-sandbox.py --- scons-4.0.1+dfsg/test/Install/option--install-sandbox.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/option--install-sandbox.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Test the --install-sandbox commandline option for Install() and InstallAs(). @@ -43,11 +42,8 @@ target_file2_out = os.path.join(target, 'file2.out') subdir_file3_in = os.path.join('subdir', 'file3.in') target_subdir_file3_out = os.path.join(target, 'subdir', 'file3.out') -file1_out = target+os.path.join( target, - os.path.splitdrive(destdir)[1], - 'file1.out' ) +file1_out = target + os.path.join(target, os.path.splitdrive(destdir)[1], 'file1.out') -# test.write('SConstruct', r""" DefaultEnvironment(tools=[]) env = Environment(tools=[], SUBDIR='subdir') diff -Nru scons-4.0.1+dfsg/test/Install/rec-sub-dir.py scons-4.4.0+dfsg/test/Install/rec-sub-dir.py --- scons-4.0.1+dfsg/test/Install/rec-sub-dir.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/rec-sub-dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# MIT Licenxe +# +# 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. + +""" +Test using Install() on directory that contains existing subdirectories +causing copytree recursion where the directory already exists. +""" + +import os.path + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +Execute(Mkdir('a/b/c')) +Execute(Mkdir('b/c/d')) +Install('z', 'a') +Install('z/a', 'b') +""") + +expect="""\ +Mkdir("a/b/c") +Mkdir("b/c/d") +Install directory: "a" as "z%sa" +Install directory: "b" as "z%sa%sb" +""" % (os.sep, os.sep, os.sep) +test.run(arguments=["-Q"], stdout=expect) + +test.must_exist(test.workpath('a', 'b', 'c')) +test.must_exist(test.workpath('b', 'c', 'd')) +test.must_exist(test.workpath('z', 'a', 'b', 'c', 'd')) + +# this run used to fail on Windows with an OS error before the copytree fix +test.run(arguments=["-Q"]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Install/tool.py scons-4.4.0+dfsg/test/Install/tool.py --- scons-4.0.1+dfsg/test/Install/tool.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/tool.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ Verify that we can still call Install() and InstallAs() even when @@ -37,14 +36,14 @@ test.write('SConstruct', """ DefaultEnvironment(tools=[]) -env = Environment(tools = []) +env = Environment(tools=[]) env.Install('iii', 'foo.in') env.InstallAs('foo.out', 'foo.in') """) test.write('foo.in', "foo.in\n") -test.run(arguments = '.') +test.run(arguments='.') test.must_match(['iii', 'foo.in'], "foo.in\n") test.must_match('foo.out', "foo.in\n") diff -Nru scons-4.0.1+dfsg/test/Install/wrap-by-attribute.py scons-4.4.0+dfsg/test/Install/wrap-by-attribute.py --- scons-4.0.1+dfsg/test/Install/wrap-by-attribute.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Install/wrap-by-attribute.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT Licenxe +# +# 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,9 +22,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__" """ @@ -45,6 +44,7 @@ DefaultEnvironment(tools=[]) import os.path + def cat(env, source, target): target = str(target[0]) with open(target, 'wb') as ofp: @@ -52,18 +52,23 @@ with open(str(src), 'rb') as ifp: ofp.write(ifp.read()) + env = Environment(tools=[], DESTDIR='dest') -env.Append(BUILDERS={'Cat':Builder(action=cat)}) +env.Append(BUILDERS={'Cat': Builder(action=cat)}) env.SconsInternalInstallFunc = env.Install env.SconsInternalInstallAsFunc = env.InstallAs + def InstallWithDestDir(dir, source): abspath = os.path.splitdrive(env.Dir(dir).get_abspath())[1] - return env.SconsInternalInstallFunc('$DESTDIR'+abspath, source) + return env.SconsInternalInstallFunc('$DESTDIR' + abspath, source) + + def InstallAsWithDestDir(target, source): abspath = os.path.splitdrive(env.File(target).get_abspath())[1] - return env.SconsInternalInstallAsFunc('$DESTDIR'+abspath, source) + return env.SconsInternalInstallAsFunc('$DESTDIR' + abspath, source) + # Add the wrappers directly as attributes. env.Install = InstallWithDestDir @@ -82,7 +87,6 @@ e2.Install('export', source=t) t = e2.Cat(target='f4.out', source='f4.in') e2.InstallAs('export/f4-new.out', source=t) - """) test.write('f1.in', "f1.in\n") @@ -90,7 +94,7 @@ test.write('f3.in', "f3.in\n") test.write('f4.in', "f4.in\n") -test.run(arguments = '.') +test.run(arguments='.') export = os.path.splitdrive(test.workpath('export'))[1] @@ -104,7 +108,7 @@ test.must_match(f3_out, "f3.in\n") test.must_match(f4_new_out, "f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Interactive/configure.py scons-4.4.0+dfsg/test/Interactive/configure.py --- scons-4.0.1+dfsg/test/Interactive/configure.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Interactive/configure.py 2022-07-30 21:48:28.000000000 +0000 @@ -53,9 +53,9 @@ # The order of this list is related to the order of the counts below expected_patterns = [ - re.compile("^scons>>> .*foo\.cpp.*$"), - re.compile("^scons>>> scons: `foo.obj' is up to date\.$"), - re.compile("^scons>>>\s*$"), + re.compile(r"^scons>>> .*foo\.cpp.*$"), + re.compile(r"^scons>>> scons: `foo.obj' is up to date\.$"), + re.compile(r"^scons>>>\s*$"), ] # The order of this list is related to the order of the regular expressions above diff -Nru scons-4.0.1+dfsg/test/Interactive/version.py scons-4.4.0+dfsg/test/Interactive/version.py --- scons-4.0.1+dfsg/test/Interactive/version.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Interactive/version.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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. +# """ Verify the behavior of the "version" subcommand. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestCmd import TestSCons @@ -56,7 +58,7 @@ stdin="version\nexit\n") expect2 = r"""scons>>> SCons by Steven Knight et al\.: -\tSCons: v\S+, [^,]*, by \S+ on \S+ +\tSCons: v\S+, [^,]*,[^,]*, by \S+ on \S+ \tSCons path: \[.*\] %(copyright_line)sscons>>> """ % locals() diff -Nru scons-4.0.1+dfsg/test/Java/DerivedSourceTest.py scons-4.4.0+dfsg/test/Java/DerivedSourceTest.py --- scons-4.0.1+dfsg/test/Java/DerivedSourceTest.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/DerivedSourceTest.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test of javac.py when building java code from derived sources. diff -Nru scons-4.0.1+dfsg/test/Java/JARCHDIR.py scons-4.4.0+dfsg/test/Java/JARCHDIR.py --- scons-4.0.1+dfsg/test/Java/JARCHDIR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JARCHDIR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that when JARCHDIR that our command to create .jar files @@ -33,7 +32,6 @@ ${TARGET} or ${SOURCE} work. """ -import os import TestSCons @@ -45,21 +43,20 @@ test.write('SConstruct', """ DefaultEnvironment(tools=[]) dir = 'dist' -env = Environment(tools = ['javac', 'jar'], - JARCHDIR = dir) +env = Environment(tools=['javac', 'jar'], JARCHDIR=dir) bin = env.Java(dir, Dir('./')) jar = env.Jar(File('c.jar', dir), bin) # Make sure we handle class files with $ in them, such as typically # created for inner classes. -env = env.Clone(JARCHDIR = '.') +env = env.Clone(JARCHDIR='.') inner = env.Jar('inner.jar', 'Inner$$Class.class') # Commented out as this logic doesn't work as is. # target_env = env.Clone(JARCHDIR = '${TARGET.dir}') # target_env.Jar('out/t.jar', 'in/t.class') -source_env = env.Clone(JARCHDIR = '${SOURCE.dir}') +source_env = env.Clone(JARCHDIR='${SOURCE.dir}') source_env.Jar('out/s.jar', 'in/s.class') Default(bin, jar, inner) diff -Nru scons-4.0.1+dfsg/test/Java/JARCOM.py scons-4.4.0+dfsg/test/Java/JARCOM.py --- scons-4.0.1+dfsg/test/Java/JARCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JARCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $JARCOM construction variable. @@ -38,9 +37,11 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'jar'], - JARCOM = r'%(_python_)s mycompile.py jar $TARGET $SOURCES') -env.Jar(target = 'test1', source = ['file1.in', 'file2.in', 'file3.in']) +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'jar'], JARCOM=r'%(_python_)s mycompile.py jar $TARGET $SOURCES' +) +env.Jar(target='test1', source=['file1.in', 'file2.in', 'file3.in']) """ % locals()) test.write('file1.in', "file1.in\n/*jar*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JARCOMSTR.py scons-4.4.0+dfsg/test/Java/JARCOMSTR.py --- scons-4.0.1+dfsg/test/Java/JARCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JARCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $JARCOMSTR construction variable allows you to configure @@ -38,10 +37,13 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'jar'], - JARCOM = r'%(_python_)s mycompile.py jar $TARGET $SOURCES', - JARCOMSTR = "Jar'ing up $TARGET from $SOURCES") -env.Jar(target = 'test1', source = ['file1.in', 'file2.in', 'file3.in']) +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'jar'], + JARCOM=r'%(_python_)s mycompile.py jar $TARGET $SOURCES', + JARCOMSTR="Jar'ing up $TARGET from $SOURCES", +) +env.Jar(target='test1', source=['file1.in', 'file2.in', 'file3.in']) """ % locals()) test.write('file1.in', "file1.in\n/*jar*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JARFLAGS.py scons-4.4.0+dfsg/test/Java/JARFLAGS.py --- scons-4.0.1+dfsg/test/Java/JARFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JARFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 import TestSCons @@ -37,11 +34,11 @@ test.subdir('src') test.write('SConstruct', """ -env = Environment(tools = ['javac', 'jar'], - JARFLAGS = 'cvf') +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac', 'jar'], JARFLAGS='cvf') env['JARFLAGS'] = 'cvf' -class_files = env.Java(target = 'classes', source = 'src') -env.Jar(target = 'test.jar', source = class_files) +class_files = env.Java(target='classes', source='src') +env.Jar(target='test.jar', source=class_files) """ % locals()) test.write(['src', 'Example1.java'], """\ diff -Nru scons-4.0.1+dfsg/test/Java/jar_not_in_PATH.py scons-4.4.0+dfsg/test/Java/jar_not_in_PATH.py --- scons-4.0.1+dfsg/test/Java/jar_not_in_PATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/jar_not_in_PATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,16 +22,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__" """ Ensures that the Tool gets initialized, even when jar is not directly found via the PATH variable (issue #2730). """ -import os import TestSCons @@ -37,33 +35,17 @@ test = TestSCons.TestSCons() -test.write('myjar.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == 'cf': - out = args[1] - args = args[1:] - else: - break - args = args[1:] -outfile = open(out, 'wb') -for file in args: - infile = open(file, 'rb') - for l in infile.readlines(): - if l[:7] != '/*jar*/': - outfile.write(l) -sys.exit(0) -""") +test.file_fixture(['Java-fixture', 'myjar.py']) -test.write('SConstruct', """ +test.write('SConstruct', """\ import os -oldpath = os.environ.get('PATH','') -env = Environment(ENV = {'PATH' : ['.']}) + +oldpath = os.environ.get('PATH', '') +DefaultEnvironment(tools=[]) +env = Environment(ENV={'PATH': ['.']}, tools=['javac', 'jar']) env['ENV']['PATH'] = oldpath -env['JAR'] = r'%(_python_)s ./myjar.py' -env.Jar(target = 'test1.jar', source = 'test1.class') +env['JAR'] = r'%(_python_)s myjar.py' +env.Jar(target='test1.jar', source='test1.class') """ % locals()) test.write('test1.class', """\ @@ -72,7 +54,7 @@ line 3 """) -test.run(arguments = '.', stderr = None) +test.run(arguments='.', stderr=None) test.must_exist('test1.jar') diff -Nru scons-4.0.1+dfsg/test/Java/JAR.py scons-4.4.0+dfsg/test/Java/JAR.py --- scons-4.0.1+dfsg/test/Java/JAR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,127 +22,37 @@ # 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 Jar builder. + +These tests require a findable/working Java subsystem. +""" import os import TestSCons -import sys _python_ = TestSCons._python_ test = TestSCons.TestSCons() -# Keep this logic because it skips the test if javac or jar not found. where_javac, java_version = test.java_where_javac() where_jar = test.java_where_jar() -test.write('myjar.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == 'cf': - out = args[1] - args = args[1:] - else: - break - args = args[1:] -outfile = open(out, 'w') -for file in args: - infile = open(file, 'r') - for l in infile.readlines(): - if l[:7] != '/*jar*/': - outfile.write(l) -sys.exit(0) -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -env = Environment(tools = ['jar'], - JAR = r'%(_python_)s myjar.py') -env.Jar(target = 'test1.jar', source = 'test1.class') -""" % locals()) - -test.write('test1.class', """\ -test1.class -/*jar*/ -line 3 -""") - -test.run(arguments='.', stderr=None) - -test.must_match('test1.jar', "test1.class\nline 3\n", mode='r') - -if os.path.normcase('.class') == os.path.normcase('.CLASS'): - - test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -env = Environment(tools = ['jar'], - JAR = r'%(_python_)s myjar.py') -env.Jar(target = 'test2.jar', source = 'test2.CLASS') -""" % locals()) - - test.write('test2.CLASS', """\ -test2.CLASS -/*jar*/ -line 3 -""") - - test.run(arguments='.', stderr=None) - - test.must_match('test2.jar', "test2.CLASS\nline 3\n", mode='r') - -test.write('myjar2.py', r""" -import sys -f=open(sys.argv[2], 'w') -f.write(" ".join(sys.argv[1:])) -f.write("\n") -f.close() -sys.exit(0) -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -env = Environment(tools = ['jar'], - JAR = r'%(_python_)s myjar2.py', - JARFLAGS='cvf') -env.Jar(target = 'classes.jar', source = [ 'testdir/bar.class', - 'foo.mf' ], - TESTDIR='testdir', - JARCHDIR='$TESTDIR') -""" % locals()) - -test.subdir('testdir') -test.write(['testdir', 'bar.class'], 'foo') -test.write('foo.mf', - """Manifest-Version : 1.0 - blah - blah - blah - """) -test.run(arguments='classes.jar') -test.must_match('classes.jar', - 'cvfm classes.jar foo.mf -C testdir bar.class\n', mode='r') - test.file_fixture('wrapper_with_args.py') -test.write('SConstruct', """ +test.write('SConstruct', """\ DefaultEnvironment(tools=[]) -foo = Environment(tools = ['javac', 'jar']) +foo = Environment(tools=['javac', 'jar']) # jar = foo.Dictionary('JAR') -bar = foo.Clone(JAR = r'%(_python_)s wrapper_with_args.py jar') -foo.Java(target = 'classes', source = 'com/sub/foo') -bar.Java(target = 'classes', source = 'com/sub/bar') -foo.Jar(target = 'foo', source = 'classes/com/sub/foo') -bar.Jar(target = 'bar', source = Dir('classes/com/sub/bar')) +bar = foo.Clone(JAR=r'%(_python_)s wrapper_with_args.py jar') +foo.Java(target='classes', source='com/sub/foo') +bar.Java(target='classes', source='com/sub/bar') +foo.Jar(target='foo', source='classes/com/sub/foo') +bar.Jar(target='bar', source=Dir('classes/com/sub/bar')) """ % locals()) -test.subdir('com', - ['com', 'sub'], - ['com', 'sub', 'foo'], - ['com', 'sub', 'bar']) +test.subdir('com', ['com', 'sub'], ['com', 'sub', 'foo'], ['com', 'sub', 'bar']) test.write(['com', 'sub', 'foo', 'Example1.java'], """\ package com.sub.foo; @@ -230,13 +142,12 @@ expected_wrapper_out = "wrapper_with_args.py jar cf bar.jar classes/com/sub/bar\n" expected_wrapper_out = expected_wrapper_out.replace('/', os.sep) -test.must_match('wrapper.out', - expected_wrapper_out % locals(), mode='r') +test.must_match('wrapper.out', expected_wrapper_out % locals(), mode='r') test.must_exist('foo.jar') test.must_exist('bar.jar') -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') ####### # test java source files as source to Jar builder @@ -252,22 +163,43 @@ DefaultEnvironment(tools=[]) foo = Environment() -foo.Jar(target = 'foobar', source = [ - 'com/javasource/JavaFile1.java', - 'com/javasource/JavaFile2.java', - 'com/javasource/JavaFile3.java' -]) -foo.Jar(target = ['foo', 'bar'], source = [ - 'com/javasource/JavaFile1.java', - 'com/javasource/JavaFile2.java', - 'com/javasource/JavaFile3.java' -]) -foo.Command("foobarTest", [], Mkdir("foobarTest") ) -foo.Command('foobarTest/com/javasource/JavaFile3.java', 'foobar.jar', foo['JAR'] + ' xvf ../foobar.jar', chdir='foobarTest') -foo.Command("fooTest", [], Mkdir("fooTest") ) -foo.Command('fooTest/com/javasource/JavaFile3.java', 'foo.jar', foo['JAR'] + ' xvf ../foo.jar', chdir='fooTest') -foo.Command("barTest", [], Mkdir("barTest") ) -foo.Command('barTest/com/javasource/JavaFile3.java', 'bar.jar', foo['JAR'] + ' xvf ../bar.jar', chdir='barTest') +foo.Jar( + target='foobar', + source=[ + 'com/javasource/JavaFile1.java', + 'com/javasource/JavaFile2.java', + 'com/javasource/JavaFile3.java', + ], +) +foo.Jar( + target=['foo', 'bar'], + source=[ + 'com/javasource/JavaFile1.java', + 'com/javasource/JavaFile2.java', + 'com/javasource/JavaFile3.java', + ], +) +foo.Command("foobarTest", [], Mkdir("foobarTest")) +foo.Command( + 'foobarTest/com/javasource/JavaFile3.java', + 'foobar.jar', + foo['JAR'] + ' xvf ../foobar.jar', + chdir='foobarTest', +) +foo.Command("fooTest", [], Mkdir("fooTest")) +foo.Command( + 'fooTest/com/javasource/JavaFile3.java', + 'foo.jar', + foo['JAR'] + ' xvf ../foo.jar', + chdir='fooTest', +) +foo.Command("barTest", [], Mkdir("barTest")) +foo.Command( + 'barTest/com/javasource/JavaFile3.java', + 'bar.jar', + foo['JAR'] + ' xvf ../bar.jar', + chdir='barTest', +) """) test.write(['testdir2', 'com', 'javasource', 'JavaFile1.java'], """\ @@ -311,11 +243,7 @@ # use regex . for dirsep so this will work on both windows and other platforms. expect = ".*jar cf foo.jar -C com.javasource.JavaFile1 com.javasource.JavaFile1.class -C com.javasource.JavaFile2 com.javasource.JavaFile2.class -C com.javasource.JavaFile3 com.javasource.JavaFile3.class.*" -test.run(chdir='testdir2', - match=TestSCons.match_re_dotall, - stdout = expect) - - +test.run(chdir='testdir2', match=TestSCons.match_re_dotall, stdout=expect) #test single target jar test.must_exist(['testdir2','foobar.jar']) @@ -340,12 +268,14 @@ # test list of lists # make some directories to test in -test.subdir('listOfLists', - ['manifest_dir'], - ['listOfLists', 'src'], - ['listOfLists', 'src', 'com'], - ['listOfLists', 'src', 'com', 'javasource'], - ['listOfLists', 'src', 'com', 'resource']) +test.subdir( + 'listOfLists', + ['manifest_dir'], + ['listOfLists', 'src'], + ['listOfLists', 'src', 'com'], + ['listOfLists', 'src', 'com', 'javasource'], + ['listOfLists', 'src', 'com', 'resource'], +) # test varient dir and lists of lists test.write(['listOfLists', 'SConstruct'], """ @@ -354,15 +284,26 @@ foo = Environment() foo.VariantDir('build', 'src', duplicate=0) foo.VariantDir('test', '../manifest_dir', duplicate=0) -sourceFiles = ["src/com/javasource/JavaFile1.java", "src/com/javasource/JavaFile2.java", "src/com/javasource/JavaFile3.java",] +sourceFiles = [ + "src/com/javasource/JavaFile1.java", + "src/com/javasource/JavaFile2.java", + "src/com/javasource/JavaFile3.java", +] list_of_class_files = foo.Java('build', source=sourceFiles) resources = ['build/com/resource/resource1.txt', 'build/com/resource/resource2.txt'] for resource in resources: - foo.Command(resource, list_of_class_files, Copy(resource, resource.replace('build','src'))) + foo.Command( + resource, list_of_class_files, Copy(resource, resource.replace('build', 'src')) + ) contents = [list_of_class_files, resources] -foo.Jar(target = 'lists', source = contents + ['test/MANIFEST.mf'], JARCHDIR='build') -foo.Command("listsTest", [], Mkdir("listsTest") ) -foo.Command('listsTest/src/com/javasource/JavaFile3.java', 'lists.jar', foo['JAR'] + ' xvf ../lists.jar', chdir='listsTest') +foo.Jar(target='lists', source=contents + ['test/MANIFEST.mf'], JARCHDIR='build') +foo.Command("listsTest", [], Mkdir("listsTest")) +foo.Command( + 'listsTest/src/com/javasource/JavaFile3.java', + 'lists.jar', + foo['JAR'] + ' xvf ../lists.jar', + chdir='listsTest', +) """) test.write(['listOfLists', 'src', 'com', 'javasource', 'JavaFile1.java'], """\ @@ -433,25 +374,34 @@ # test different style of passing in dirs # make some directories to test in -test.subdir('testdir3', - ['testdir3', 'com'], - ['testdir3', 'com', 'sub'], - ['testdir3', 'com', 'sub', 'foo'], - ['testdir3', 'com', 'sub', 'bar']) +test.subdir( + 'testdir3', + ['testdir3', 'com'], + ['testdir3', 'com', 'sub'], + ['testdir3', 'com', 'sub', 'foo'], + ['testdir3', 'com', 'sub', 'bar'], +) # Create the jars then extract them back to check contents test.write(['testdir3', 'SConstruct'], """ DefaultEnvironment(tools=[]) foo = Environment() -bar = foo.Clone() -foo.Java(target = 'classes', source = 'com/sub/foo') -bar.Java(target = 'classes', source = 'com/sub/bar') -foo.Jar(target = 'foo', source = 'classes/com/sub/foo', JARCHDIR='classes') -bar.Jar(target = 'bar', source = Dir('classes/com/sub/bar'), JARCHDIR='classes') -foo.Command("fooTest", 'foo.jar', Mkdir("fooTest") ) +foo_cls = foo.Java(target='classes', source='com/sub/foo') +foo_res = 'classes/com/sub/foo/NonJava.txt' +foo_res_src = 'com/sub/foo/NonJava.txt' +foo.Command(foo_res, foo_cls, Copy(foo_res, foo_res_src)) +foo.Jar(target='foo', source='classes/com/sub/foo', JARCHDIR='classes') +foo.Command("fooTest", 'foo.jar', Mkdir("fooTest")) foo.Command('doesnt_exist1', "fooTest", foo['JAR'] + ' xvf ../foo.jar', chdir='fooTest') -bar.Command("barTest", 'bar.jar', Mkdir("barTest") ) + +bar = foo.Clone() +bar_cls = bar.Java(target='classes', source='com/sub/bar') +bar_res = 'classes/com/sub/bar/NonJava.txt' +bar_res_src = 'com/sub/bar/NonJava.txt' +bar.Command(bar_res, bar_cls, Copy(bar_res, bar_res_src)) +bar.Jar(target='bar', source=Dir('classes/com/sub/bar'), JARCHDIR='classes') +bar.Command("barTest", 'bar.jar', Mkdir("barTest")) bar.Command('doesnt_exist2', 'barTest', bar['JAR'] + ' xvf ../bar.jar', chdir='barTest') """) @@ -551,7 +501,6 @@ # check the output and make sure the java files got converted to classes - # make sure there are class in the jar test.must_exist(['testdir3','foo.jar']) test.must_exist(['testdir3', 'fooTest', 'com', 'sub', 'foo', 'Example1.class']) @@ -559,7 +508,7 @@ test.must_exist(['testdir3', 'fooTest', 'com', 'sub', 'foo', 'Example3.class']) # TODO: determine expected behavior with resource files, should they be # automatically copied in or specified in seperate commands -#test.must_exist(['testdir3', 'fooTest', 'com', 'sub', 'foo', 'NonJava.txt']) +test.must_exist(['testdir3', 'fooTest', 'com', 'sub', 'foo', 'NonJava.txt']) # make sure both jars got createds test.must_exist(['testdir3','bar.jar']) @@ -568,11 +517,10 @@ test.must_exist(['testdir3', 'barTest', 'com', 'sub', 'bar', 'Example6.class']) # TODO: determine expected behavior with resource files, should they be # automatically copied in or specified in seperate commands -#test.must_exist(['testdir3', 'fooTest', 'com', 'sub', 'bar', 'NonJava.txt']) +test.must_exist(['testdir3', 'barTest', 'com', 'sub', 'bar', 'NonJava.txt']) test.pass_test() - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff -Nru scons-4.0.1+dfsg/test/Java/Java-1.4.py scons-4.4.0+dfsg/test/Java/Java-1.4.py --- scons-4.0.1+dfsg/test/Java/Java-1.4.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-1.4.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -21,8 +23,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__" - """ Test Java compilation with a live Java 1.4 "javac" compiler. """ diff -Nru scons-4.0.1+dfsg/test/Java/Java-1.5.py scons-4.4.0+dfsg/test/Java/Java-1.5.py --- scons-4.0.1+dfsg/test/Java/Java-1.5.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-1.5.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -21,8 +23,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__" - """ Test Java compilation with a live Java 1.5 "javac" compiler. """ diff -Nru scons-4.0.1+dfsg/test/Java/Java-1.6.py scons-4.4.0+dfsg/test/Java/Java-1.6.py --- scons-4.0.1+dfsg/test/Java/Java-1.6.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-1.6.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -21,8 +19,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__" - """ Test Java compilation with a live Java 1.6 "javac" compiler. """ diff -Nru scons-4.0.1+dfsg/test/Java/Java-1.8.py scons-4.4.0+dfsg/test/Java/Java-1.8.py --- scons-4.0.1+dfsg/test/Java/Java-1.8.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-1.8.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -21,8 +23,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__" - """ Test Java compilation with a live Java 1.8 "javac" compiler. """ diff -Nru scons-4.0.1+dfsg/test/Java/JAVABOOTCLASSPATH.py scons-4.4.0+dfsg/test/Java/JAVABOOTCLASSPATH.py --- scons-4.0.1+dfsg/test/Java/JAVABOOTCLASSPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVABOOTCLASSPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that use of $JAVABOOTCLASSPATH sets the -bootclasspath option @@ -33,19 +32,16 @@ import TestSCons -_python_ = TestSCons._python_ - test = TestSCons.TestSCons() where_javac, java_version = test.java_where_javac() -where_javah = test.java_where_javah() test.write('SConstruct', """ -env = Environment(tools = ['javac', 'javah'], - JAVABOOTCLASSPATH = ['dir1', 'dir2']) -j1 = env.Java(target = 'class', source = 'com/Example1.java') -j2 = env.Java(target = 'class', source = 'com/Example2.java') -""" % locals()) +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac'], JAVABOOTCLASSPATH=['dir1', 'dir2']) +j1 = env.Java(target='class', source='com/Example1.java') +j2 = env.Java(target='class', source='com/Example2.java') +""") test.subdir('com') diff -Nru scons-4.0.1+dfsg/test/Java/JAVACCOM.py scons-4.4.0+dfsg/test/Java/JAVACCOM.py --- scons-4.0.1+dfsg/test/Java/JAVACCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVACCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $JAVACCOM construction variable. @@ -39,9 +38,12 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'javac'], - JAVACCOM = r'%(_python_)s mycompile.py javac $TARGET $SOURCES') -env.Java(target = 'classes', source = 'src') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'javac'], + JAVACCOM=r'%(_python_)s mycompile.py javac $TARGET $SOURCES', +) +env.Java(target='classes', source='src') """ % locals()) test.write(['src', 'file1.java'], "file1.java\n/*javac*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JAVACCOMSTR.py scons-4.4.0+dfsg/test/Java/JAVACCOMSTR.py --- scons-4.0.1+dfsg/test/Java/JAVACCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVACCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $JAVACCOMSTR construction variable allows you to configure @@ -42,10 +41,13 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'javac'], - JAVACCOM = r'%(_python_)s mycompile.py javac $TARGET $SOURCES', - JAVACCOMSTR = "Compiling class(es) $TARGET from $SOURCES") -env.Java(target = 'classes', source = 'src') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'javac'], + JAVACCOM=r'%(_python_)s mycompile.py javac $TARGET $SOURCES', + JAVACCOMSTR="Compiling class(es) $TARGET from $SOURCES", +) +env.Java(target='classes', source='src') """ % locals()) test.write(['src', 'file1.java'], "file1.java\n/*javac*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JAVACFLAGS.py scons-4.4.0+dfsg/test/Java/JAVACFLAGS.py --- scons-4.0.1+dfsg/test/Java/JAVACFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVACFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 @@ -35,9 +34,9 @@ test.subdir('src') test.write('SConstruct', """ -env = Environment(tools = ['javac'], - JAVACFLAGS = '-O') -env.Java(target = 'classes', source = 'src') +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac'], JAVACFLAGS='-O') +env.Java(target='classes', source='src') """ % locals()) test.write(['src', 'Example1.java'], """\ diff -Nru scons-4.0.1+dfsg/test/Java/JAVACLASSPATH.py scons-4.4.0+dfsg/test/Java/JAVACLASSPATH.py --- scons-4.0.1+dfsg/test/Java/JAVACLASSPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVACLASSPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that use of $JAVASOURCEPATH allows finding Java .class @@ -30,6 +29,8 @@ to the javac command line. """ +import pathlib + import TestSCons _python_ = TestSCons._python_ @@ -39,11 +40,25 @@ where_javac, java_version = test.java_where_javac() where_javah = test.java_where_javah() +# TODO rework for 'javac -h', for now skip +# The logical test would be: if java_version > 9: +# but java_where_javah() roots around and will find from an older version +if not test.Environment().WhereIs('javah'): + test.skip_test("No Java javah for version > 9, skipping test.\n") + +# On some systems, the alternatives system does not remove javah even if the +# preferred Java doesn't have it, so try another check +javacdir = pathlib.Path(where_javac).parent +javahdir = pathlib.Path(where_javah).parent +if javacdir != javahdir: + test.skip_test("Cannot find Java javah matching javac, skipping test.\n") + test.write('SConstruct', """ -env = Environment(tools = ['javac', 'javah']) -j1 = env.Java(target = 'class1', source = 'com.1/Example1.java') -j2 = env.Java(target = 'class2', source = 'com.2/Example2.java') -env.JavaH(target = 'outdir', source = [j1, j2], JAVACLASSPATH = 'class2') +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac', 'javah']) +j1 = env.Java(target='class1', source='com.1/Example1.java') +j2 = env.Java(target='class2', source='com.2/Example2.java') +env.JavaH(target='outdir', source=[j1, j2], JAVACLASSPATH='class2') """ % locals()) test.subdir('com.1', 'com.2') diff -Nru scons-4.0.1+dfsg/test/Java/JAVAC.py scons-4.4.0+dfsg/test/Java/JAVAC.py --- scons-4.0.1+dfsg/test/Java/JAVAC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVAC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,11 @@ # 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 setting the JAVAC variable. + +This test does not require a JDK to operate. """ import os @@ -36,33 +37,12 @@ test = TestSCons.TestSCons() +test.file_fixture(['Java-fixture', 'myjavac.py']) - -test.write('myjavac.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-d': - args = args[1:] - elif a == '-sourcepath': - args = args[1:] - else: - break - args = args[1:] -for file in args: - infile = open(file, 'r') - outfile = open(file[:-5] + '.class', 'w') - for l in infile.readlines(): - if l[:9] != '/*javac*/': - outfile.write(l) -sys.exit(0) -""") - -test.write('SConstruct', """ -env = Environment(tools = ['javac'], - JAVAC = r'%(_python_)s myjavac.py') -env.Java(target = '.', source = '.') +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac'], JAVAC=r'%(_python_)s myjavac.py') +env.Java(target='.', source='.') """ % locals()) test.write('test1.java', """\ @@ -72,15 +52,13 @@ """) test.run(arguments='.', stderr=None) - test.must_match('test1.class', "test1.java\nline 3\n", mode='r') if os.path.normcase('.java') == os.path.normcase('.JAVA'): - test.write('SConstruct', """\ -env = Environment(tools = ['javac'], - JAVAC = r'%(_python_)s myjavac.py') -env.Java(target = '.', source = '.') +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac'], JAVAC=r'%(_python_)s myjavac.py') +env.Java(target='.', source='.') """ % locals()) test.write('test2.JAVA', """\ @@ -90,11 +68,8 @@ """) test.run(arguments='.', stderr=None) - test.must_match('test2.class', "test2.JAVA\nline 3\n", mode='r') - - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Java/Java-fixture/.exclude_tests scons-4.4.0+dfsg/test/Java/Java-fixture/.exclude_tests --- scons-4.0.1+dfsg/test/Java/Java-fixture/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-fixture/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +myjar.py +myjavac.py +myrmic.py diff -Nru scons-4.0.1+dfsg/test/Java/Java-fixture/myjar.py scons-4.4.0+dfsg/test/Java/Java-fixture/myjar.py --- scons-4.0.1+dfsg/test/Java/Java-fixture/myjar.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-fixture/myjar.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,19 @@ +import fileinput +import sys + +args = sys.argv[1:] +while args: + arg = args[0] + if arg == 'cf': + out = args[1] + args = args[1:] + else: + break + args = args[1:] + +with open(out, 'wb') as ofp, fileinput.input(files=args, mode='rb') as ifp: + for line in ifp: + if not line.startswith(b'/*jar*/'): + ofp.write(line) + +sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Java/Java-fixture/myjavac.py scons-4.4.0+dfsg/test/Java/Java-fixture/myjavac.py --- scons-4.0.1+dfsg/test/Java/Java-fixture/myjavac.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-fixture/myjavac.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,21 @@ +import sys + +args = sys.argv[1:] +while args: + arg = args[0] + if arg == '-d': + args = args[1:] + elif arg == '-sourcepath': + args = args[1:] + else: + break + args = args[1:] + +for file in args: + out = file.lower().replace('.java', '.class') + with open(file, 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*javac*/'): + outfile.write(line) + +sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Java/Java-fixture/myrmic.py scons-4.4.0+dfsg/test/Java/Java-fixture/myrmic.py --- scons-4.0.1+dfsg/test/Java/Java-fixture/myrmic.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/Java-fixture/myrmic.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,24 @@ +import os +import sys + +args = sys.argv[1:] +while args: + arg = args[0] + if arg == '-d': + outdir = args[1] + args = args[1:] + elif arg == '-classpath': + args = args[1:] + elif arg == '-sourcepath': + args = args[1:] + else: + break + args = args[1:] +for file in args: + out = os.path.join(outdir, file.lower().replace('.java', '.class')) + with open(file, 'rb') as infile, open(out, 'wb') as outfile: + for line in infile: + if not line.startswith(b'/*rmic*/'): + outfile.write(line) + +sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/Java/JAVAHCOM.py scons-4.4.0+dfsg/test/Java/JAVAHCOM.py --- scons-4.0.1+dfsg/test/Java/JAVAHCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVAHCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $JAVAHCOM construction variable. @@ -37,11 +36,14 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'javah'], - JAVAHCOM = r'%(_python_)s mycompile.py javah $TARGET $SOURCES') -env.JavaH(target = 'out', source = 'file1.class') -env.JavaH(target = 'out', source = 'file2.class') -env.JavaH(target = 'out', source = 'file3.class') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'javah'], + JAVAHCOM=r'%(_python_)s mycompile.py javah $TARGET $SOURCES', +) +env.JavaH(target='out', source='file1.class') +env.JavaH(target='out', source='file2.class') +env.JavaH(target='out', source='file3.class') """ % locals()) test.write('file1.class', "file1.class\n/*javah*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JAVAHCOMSTR.py scons-4.4.0+dfsg/test/Java/JAVAHCOMSTR.py --- scons-4.0.1+dfsg/test/Java/JAVAHCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVAHCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $JAVAHCOMSTR construction variable allows you to configure @@ -46,12 +45,15 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'javah'], - JAVAHCOM = r'%(_python_)s mycompile.py javah $TARGET $SOURCES', - JAVAHCOMSTR = 'Building javah $TARGET from $SOURCES') -env.JavaH(target = 'out', source = 'file1.class') -env.JavaH(target = 'out', source = 'file2.class') -env.JavaH(target = 'out', source = 'file3.class') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'javah'], + JAVAHCOM=r'%(_python_)s mycompile.py javah $TARGET $SOURCES', + JAVAHCOMSTR='Building javah $TARGET from $SOURCES', +) +env.JavaH(target='out', source='file1.class') +env.JavaH(target='out', source='file2.class') +env.JavaH(target='out', source='file3.class') """ % locals()) test.write('file1.class', "file1.class\n/*javah*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/JAVAH-mock.py scons-4.4.0+dfsg/test/Java/JAVAH-mock.py --- scons-4.0.1+dfsg/test/Java/JAVAH-mock.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVAH-mock.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test JavaH without calling the tool +Split from rest of test to allow these to run if real javah skipped. +""" + +import os + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('myjavah.py', r""" +import sys +args = sys.argv[1:] +while args: + a = args[0] + if a == '-d': + outdir = args[1] + args = args[1:] + elif a == '-o': + outfile = open(args[1], 'w') + args = args[1:] + elif a == '-classpath': + args = args[1:] + elif a == '-sourcepath': + args = args[1:] + else: + break + args = args[1:] +for file in args: + infile = open(file, 'r') + for l in infile.readlines(): + if l[:9] != '/*javah*/': + outfile.write(l) +sys.exit(0) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +env = Environment(tools=['javah'], JAVAH=r'%(_python_)s myjavah.py') +env.JavaH(target=File('test1.h'), source='test1.java') +""" % locals()) + +test.write('test1.java', """\ +test1.java +/*javah*/ +line 3 +""") + +test.run(arguments='.', stderr=None) +test.must_match('test1.h', "test1.java\nline 3\n", mode='r') + +if os.path.normcase('.java') == os.path.normcase('.JAVA'): + test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(tools=['javah'], JAVAH=r'%(_python_)s myjavah.py') +env.JavaH(target=File('test2.h'), source='test2.JAVA') +""" % locals()) + + test.write('test2.JAVA', """\ +test2.JAVA +/*javah*/ +line 3 +""") + + test.run(arguments='.', stderr=None) + test.must_match('test2.h', "test2.JAVA\nline 3\n", mode='r') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Java/JAVAH.py scons-4.4.0+dfsg/test/Java/JAVAH.py --- scons-4.0.1+dfsg/test/Java/JAVAH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVAH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 os +import pathlib import TestSCons @@ -32,70 +32,8 @@ test = TestSCons.TestSCons() -test.write('myjavah.py', r""" -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-d': - outdir = args[1] - args = args[1:] - elif a == '-o': - outfile = open(args[1], 'w') - args = args[1:] - elif a == '-classpath': - args = args[1:] - elif a == '-sourcepath': - args = args[1:] - else: - break - args = args[1:] -for file in args: - infile = open(file, 'r') - for l in infile.readlines(): - if l[:9] != '/*javah*/': - outfile.write(l) -sys.exit(0) -""") - -test.write('SConstruct', """ -env = Environment(tools = ['javah'], - JAVAH = r'%(_python_)s myjavah.py') -env.JavaH(target = File('test1.h'), source = 'test1.java') -""" % locals()) - -test.write('test1.java', """\ -test1.java -/*javah*/ -line 3 -""") - -test.run(arguments='.', stderr=None) - -test.must_match('test1.h', "test1.java\nline 3\n", mode='r') - -if os.path.normcase('.java') == os.path.normcase('.JAVA'): - - test.write('SConstruct', """\ -env = Environment(tools = ['javah'], - JAVAH = r'%(_python_)s myjavah.py') -env.JavaH(target = File('test2.h'), source = 'test2.JAVA') -""" % locals()) - - test.write('test2.JAVA', """\ -test2.JAVA -/*javah*/ -line 3 -""") - - test.run(arguments='.', stderr=None) - - test.must_match('test2.h', "test2.JAVA\nline 3\n", mode='r') - - where_javac, java_version = test.java_where_javac() where_javah = test.java_where_javah() - if java_version: java_version = repr(java_version) @@ -105,36 +43,58 @@ if test.javac_is_gcj: test.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n') +# TODO rework for 'javac -h', for now skip +# The logical test would be: if java_version > 9: +# but java_where_javah() roots around and will find from an older version +if not test.Environment().WhereIs('javah'): + test.skip_test("No Java javah for version > 9, skipping test.\n") + +# On some systems, the alternatives system does not remove javah even if the +# preferred Java doesn't have it, so try another check +javacdir = pathlib.Path(where_javac).parent +javahdir = pathlib.Path(where_javah).parent +if javacdir != javahdir: + test.skip_test("Cannot find Java javah matching javac, skipping test.\n") + test.file_fixture('wrapper_with_args.py') test.write('SConstruct', """ -foo = Environment(tools = ['javac', 'javah', 'install']) +DefaultEnvironment(tools=[]) +foo = Environment(tools=['javac', 'javah', 'install']) jv = %(java_version)s if jv: foo['JAVAVERSION'] = jv javah = foo.Dictionary('JAVAH') -bar = foo.Clone(JAVAH = r'%(_python_)s wrapper_with_args.py ' + javah) -foo.Java(target = 'class1', source = 'com/sub/foo') -bar_classes = bar.Java(target = 'class2', source = 'com/sub/bar') -foo_classes = foo.Java(target = 'class3', source = 'src') -foo.JavaH(target = 'outdir1', - source = ['class1/com/sub/foo/Example1.class', - 'class1/com/other/Example2', - 'class1/com/sub/foo/Example3'], - JAVACLASSDIR = 'class1') -bar.JavaH(target = 'outdir2', source = bar_classes) -foo.JavaH(target = File('output.h'), source = foo_classes) +bar = foo.Clone(JAVAH=r'%(_python_)s wrapper_with_args.py ' + javah) +foo.Java(target='class1', source='com/sub/foo') +bar_classes = bar.Java(target='class2', source='com/sub/bar') +foo_classes = foo.Java(target='class3', source='src') +foo.JavaH( + target='outdir1', + source=[ + 'class1/com/sub/foo/Example1.class', + 'class1/com/other/Example2', + 'class1/com/sub/foo/Example3', + ], + JAVACLASSDIR='class1', +) +bar.JavaH(target='outdir2', source=bar_classes) +foo.JavaH(target=File('output.h'), source=foo_classes) foo.Install('class4/com/sub/foo', 'class1/com/sub/foo/Example1.class') -foo.JavaH(target = 'outdir4', - source = ['class4/com/sub/foo/Example1.class'], - JAVACLASSDIR = 'class4') +foo.JavaH( + target='outdir4', + source=['class4/com/sub/foo/Example1.class'], + JAVACLASSDIR='class4', +) """ % locals()) -test.subdir('com', - ['com', 'sub'], - ['com', 'sub', 'foo'], - ['com', 'sub', 'bar'], - 'src') +test.subdir( + 'com', + ['com', 'sub'], + ['com', 'sub', 'foo'], + ['com', 'sub', 'bar'], + 'src', +) test.write(['com', 'sub', 'foo', 'Example1.java'], """\ package com.sub.foo; @@ -280,8 +240,12 @@ test.run(arguments = '.') -test.must_match('wrapper.out', "wrapper_with_args.py javah -d outdir2 -classpath class2 com.sub.bar.Example4 com.other.Example5 com.sub.bar.Example6\n" % locals(), - mode='r') +test.must_match( + 'wrapper.out', + "wrapper_with_args.py javah -d outdir2 -classpath class2 com.sub.bar.Example4 com.other.Example5 com.sub.bar.Example6\n" + % locals(), + mode='r', +) test.must_exist(['outdir1', 'com_sub_foo_Example1.h']) test.must_exist(['outdir1', 'com_other_Example2.h']) diff -Nru scons-4.0.1+dfsg/test/Java/JAVASOURCEPATH.py scons-4.4.0+dfsg/test/Java/JAVASOURCEPATH.py --- scons-4.0.1+dfsg/test/Java/JAVASOURCEPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/JAVASOURCEPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that use of $JAVASOURCEPATH allows finding source .java @@ -32,18 +31,17 @@ import TestSCons -_python_ = TestSCons._python_ - test = TestSCons.TestSCons() where_javac, java_version = test.java_where_javac() test.write('SConstruct', """ -env = Environment(tools = ['javac', 'javah']) -bar = env.Java(target = 'bar/classes', - source = 'bar/src/TestBar.java', - JAVASOURCEPATH = ['foo/src']) -""" % locals()) +DefaultEnvironment(tools=[]) +env = Environment(tools=['javac']) +bar = env.Java( + target='bar/classes', source='bar/src/TestBar.java', JAVASOURCEPATH=['foo/src'] +) +""") test.subdir('foo', ['foo', 'src'], diff -Nru scons-4.0.1+dfsg/test/Java/multi-step.py scons-4.4.0+dfsg/test/Java/multi-step.py --- scons-4.0.1+dfsg/test/Java/multi-step.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/multi-step.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -24,11 +26,12 @@ """ Real-world test (courtesy Leanid Nazdrynau) of the multi-step capabilities of the various Java Builders. -""" -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +TODO: the whole Applet facility is deprecated, need a new test. +""" import os +import pathlib import TestSCons @@ -50,27 +53,42 @@ if test.javac_is_gcj: test.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n') -test.subdir(['src'], - ['src', 'HelloApplet'], - ['src', 'HelloApplet', 'com'], - ['src', 'javah'], - ['src', 'jni'], - ['src', 'server'], - ['src', 'server', 'JavaSource'], - ['src', 'server', 'JavaSource', 'com'], - ['src', 'server', 'JavaSource', 'com', 'gnu'], - ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons'], - ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web'], - ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools'], - ['src', 'server', 'WebContent'], - ['src', 'server', 'WebContent', 'META-INF'], - ['src', 'server', 'WebContent', 'WEB-INF'], - ['src', 'server', 'WebContent', 'WEB-INF', 'conf'], - ['src', 'server', 'WebContent', 'WEB-INF', 'lib'], - ['src', 'server', 'WebContent', 'theme']) +# TODO rework for 'javac -h', for now skip +# The logical test would be: if java_version > 9: +# but java_where_javah() roots around and will find from an older version +if not test.Environment().WhereIs('javah'): + test.skip_test("No Java javah for version > 9, skipping test.\n") + +# On some systems, the alternatives system does not remove javah even if the +# preferred Java doesn't have it, so try another check +javacdir = pathlib.Path(where_javac).parent +javahdir = pathlib.Path(where_javah).parent +if javacdir != javahdir: + test.skip_test("Cannot find Java javah matching javac, skipping test.\n") + +test.subdir( + ['src'], + ['src', 'HelloApplet'], + ['src', 'HelloApplet', 'com'], + ['src', 'javah'], + ['src', 'jni'], + ['src', 'server'], + ['src', 'server', 'JavaSource'], + ['src', 'server', 'JavaSource', 'com'], + ['src', 'server', 'JavaSource', 'com', 'gnu'], + ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons'], + ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web'], + ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools'], + ['src', 'server', 'WebContent'], + ['src', 'server', 'WebContent', 'META-INF'], + ['src', 'server', 'WebContent', 'WEB-INF'], + ['src', 'server', 'WebContent', 'WEB-INF', 'conf'], + ['src', 'server', 'WebContent', 'WEB-INF', 'lib'], + ['src', 'server', 'WebContent', 'theme'], +) test.write(['SConstruct'], """\ -import os,sys +import os, sys if sys.platform == 'win32': # Ensure tests don't pick up link from mingw or cygwin @@ -78,31 +96,35 @@ else: tools = ['default', 'javac', 'javah', 'swig'] -env=Environment(tools = tools, - CPPPATH=["$JAVAINCLUDES"]) +env = Environment(tools=tools, CPPPATH=["$JAVAINCLUDES"]) Export('env') # env.PrependENVPath('PATH',os.environ.get('PATH',[])) -env['INCPREFIX']='-I' -env.Append(SWIGFLAGS=['-c++','$_CPPINCFLAGS']) +env['INCPREFIX'] = '-I' +env.Append(SWIGFLAGS=['-c++', '$_CPPINCFLAGS']) -#this is for JNI -#env.Append(CCFLAGS=['/IN:/jdk/v1.3.1/include','/IN:/jdk/v1.3.1/include/win32']) +# this is for JNI +# env.Append(CCFLAGS=['/IN:/jdk/v1.3.1/include','/IN:/jdk/v1.3.1/include/win32']) -#this for windows only C++ build -#env.Append(CXXFLAGS='-GX') +# this for windows only C++ build +# env.Append(CXXFLAGS='-GX') env.Append(CPPPATH='.') env.VariantDir('buildout', 'src', duplicate=0) -if sys.platform[:6]=='darwin': - env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers']) +if sys.platform[:6] == 'darwin': + env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers']) -#If you do not have swig on your system please remove 'buildout/jni/SConscript' line from next call -env.SConscript(['buildout/server/JavaSource/SConscript', - 'buildout/HelloApplet/SConscript', - 'buildout/jni/SConscript', - 'buildout/javah/SConscript']) +# If you do not have swig on your system please remove +# 'buildout/jni/SConscript' line from next call +env.SConscript( + [ + 'buildout/server/JavaSource/SConscript', + 'buildout/HelloApplet/SConscript', + 'buildout/jni/SConscript', + 'buildout/javah/SConscript', + ] +) """ % locals()) test.write(['src', 'HelloApplet', 'Hello.html'], """\ @@ -123,21 +145,20 @@ test.write(['src', 'HelloApplet', 'SConscript'], """\ import os -Import ("env") -denv=env.Clone() -classes=denv.Java(target='classes',source=['com']) -#set correct path for jar -denv['JARCHDIR']=os.path.join(denv.Dir('.').get_abspath(),'classes') -denv.Jar('HelloApplet',classes) - - -#To sign applet you have to create keystore before and made a calls like this - -#keystore='/path/to/jarsignkey' -#denv['JARSIGNFLAGS']='-keystore '+keystore+' -storepass pass -keypass passkey' -#denv['JARSIGNALIAS']='ALIAS' -#denv['JARCOM']=[denv['JARCOM'],'$JARSIGNCOM'] +Import("env") +denv = env.Clone() +classes = denv.Java(target='classes', source=['com']) +# set correct path for jar +denv['JARCHDIR'] = os.path.join(denv.Dir('.').get_abspath(), 'classes') +denv.Jar('HelloApplet', classes) + +# To sign applet you have to create keystore before and made a calls like this + +# keystore='/path/to/jarsignkey' +# denv['JARSIGNFLAGS']='-keystore '+keystore+' -storepass pass -keypass passkey' +# denv['JARSIGNALIAS']='ALIAS' +# denv['JARCOM']=[denv['JARCOM'],'$JARSIGNCOM'] """) test.write(['src', 'HelloApplet', 'com', 'Hello.java'], """\ @@ -179,12 +200,11 @@ test.write(['src', 'javah', 'SConscript'], """\ Import('env') -denv=env.Clone() -denv['JARCHDIR']=denv.Dir('.').get_abspath() -denv.Jar('myid','MyID.java') -denv.JavaH(denv.Dir('.').get_abspath(),'MyID.java') -denv.SharedLibrary('myid','MyID.cc') - +denv = env.Clone() +denv['JARCHDIR'] = denv.Dir('.').get_abspath() +denv.Jar('myid', 'MyID.java') +denv.JavaH(denv.Dir('.').get_abspath(), 'MyID.java') +denv.SharedLibrary('myid', 'MyID.cc') """) test.write(['src', 'jni', 'A.java'], """\ @@ -225,8 +245,6 @@ #include "JniWrapper.h" - - JniWrapper::JniWrapper( JNIEnv *pEnv ) : mpEnv( pEnv ) { @@ -239,7 +257,6 @@ JniWrapper::~JniWrapper() { - } JniWrapper& JniWrapper::operator=( const JniWrapper& rJniWrapper ) @@ -373,13 +390,13 @@ """) test.write(['src', 'jni', 'SConscript'], """\ -Import ("env") -denv=env.Clone() +Import("env") +denv = env.Clone() denv.Append(SWIGFLAGS=['-java']) -denv.SharedLibrary('scons',['JniWrapper.cc','Sample.i']) -denv['JARCHDIR']=denv.Dir('.').get_abspath() -denv.Jar(['Sample.i','A.java']) +denv.SharedLibrary('scons', ['JniWrapper.cc', 'Sample.i']) +denv['JARCHDIR'] = denv.Dir('.').get_abspath() +denv.Jar(['Sample.i', 'A.java']) """) test.write(['src', 'jni', 'Sample.h'], """\ diff -Nru scons-4.0.1+dfsg/test/Java/nested-classes.py scons-4.4.0+dfsg/test/Java/nested-classes.py --- scons-4.0.1+dfsg/test/Java/nested-classes.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/nested-classes.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,16 +22,11 @@ # 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 Java compilation with inner and anonymous classes (Issue 2087). """ -import os - import TestSCons _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Java/no-JARCHDIR.py scons-4.4.0+dfsg/test/Java/no-JARCHDIR.py --- scons-4.0.1+dfsg/test/Java/no-JARCHDIR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/no-JARCHDIR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify the Jar() behavior when we have no JARCHDIR set (it should diff -Nru scons-4.0.1+dfsg/test/Java/RMICCOM.py scons-4.4.0+dfsg/test/Java/RMICCOM.py --- scons-4.0.1+dfsg/test/Java/RMICCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/RMICCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $RMICCOM construction variable. @@ -45,11 +44,14 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'rmic'], - RMICCOM = r'%(_python_)s mycompile.py rmic $TARGET $SOURCES') -env.RMIC(target = 'out', source = 'file1.class') -env.RMIC(target = 'out', source = 'file2.class') -env.RMIC(target = 'out', source = 'file3.class') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'rmic'], + RMICCOM=r'%(_python_)s mycompile.py rmic $TARGET $SOURCES', +) +env.RMIC(target='out', source='file1.class') +env.RMIC(target='out', source='file2.class') +env.RMIC(target='out', source='file3.class') """ % locals()) test.write('file1.class', "file1.class\n/*rmic*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/RMICCOMSTR.py scons-4.4.0+dfsg/test/Java/RMICCOMSTR.py --- scons-4.0.1+dfsg/test/Java/RMICCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/RMICCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $RMICCOMSTR construction variable allows you to configure @@ -46,12 +45,15 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(TOOLS = ['default', 'rmic'], - RMICCOM = r'%(_python_)s mycompile.py rmic $TARGET $SOURCES', - RMICCOMSTR = 'Building rmic $TARGET from $SOURCES') -env.RMIC(target = 'out', source = 'file1.class') -env.RMIC(target = 'out', source = 'file2.class') -env.RMIC(target = 'out', source = 'file3.class') +DefaultEnvironment(tools=[]) +env = Environment( + TOOLS=['default', 'rmic'], + RMICCOM=r'%(_python_)s mycompile.py rmic $TARGET $SOURCES', + RMICCOMSTR='Building rmic $TARGET from $SOURCES', +) +env.RMIC(target='out', source='file1.class') +env.RMIC(target='out', source='file2.class') +env.RMIC(target='out', source='file3.class') """ % locals()) test.write('file1.class', "file1.class\n/*rmic*/\n") diff -Nru scons-4.0.1+dfsg/test/Java/rmic_not_in_PATH.py scons-4.4.0+dfsg/test/Java/rmic_not_in_PATH.py --- scons-4.0.1+dfsg/test/Java/rmic_not_in_PATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/rmic_not_in_PATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Ensures that the Tool gets initialized, even when rmic is not directly @@ -37,38 +36,17 @@ test = TestSCons.TestSCons() -test.write('myrmic.py', r""" -import os -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-d': - outdir = args[1] - args = args[1:] - elif a == '-classpath': - args = args[1:] - elif a == '-sourcepath': - args = args[1:] - else: - break - args = args[1:] -for file in args: - infile = open(file, 'rb') - outfile = open(os.path.join(outdir, file[:-5] + '.class'), 'wb') - for l in infile.readlines(): - if l[:8] != '/*rmic*/': - outfile.write(l) -sys.exit(0) -""") +test.file_fixture(['Java-fixture', 'myrmic.py']) test.write('SConstruct', """ import os -oldpath = os.environ.get('PATH','') -env = Environment(ENV = {'PATH' : ['.']}) + +oldpath = os.environ.get('PATH', '') +DefaultEnvironment(tools=[]) +env = Environment(ENV={'PATH': ['.']}, tools=['javac', 'rmic']) env['ENV']['PATH'] = oldpath env['RMIC'] = r'%(_python_)s myrmic.py' -env.RMIC(target = 'outdir', source = 'test1.java') +env.RMIC(target='outdir', source='test1.java') """ % locals()) test.write('test1.java', """\ diff -Nru scons-4.0.1+dfsg/test/Java/RMIC.py scons-4.4.0+dfsg/test/Java/RMIC.py --- scons-4.0.1+dfsg/test/Java/RMIC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/RMIC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 @@ -32,35 +31,12 @@ test = TestSCons.TestSCons() -test.write('myrmic.py', r""" -import os -import sys -args = sys.argv[1:] -while args: - a = args[0] - if a == '-d': - outdir = args[1] - args = args[1:] - elif a == '-classpath': - args = args[1:] - elif a == '-sourcepath': - args = args[1:] - else: - break - args = args[1:] -for file in args: - infile = open(file, 'r') - outfile = open(os.path.join(outdir, file[:-5] + '.class'), 'w') - for l in infile.readlines(): - if l[:8] != '/*rmic*/': - outfile.write(l) -sys.exit(0) -""") +test.file_fixture(['Java-fixture', 'myrmic.py']) test.write('SConstruct', """ -env = Environment(tools = ['rmic'], - RMIC = r'%(_python_)s myrmic.py') -env.RMIC(target = 'outdir', source = 'test1.java') +DefaultEnvironment(tools=[]) +env = Environment(tools=['rmic'], RMIC=r'%(_python_)s myrmic.py') +env.RMIC(target='outdir', source='test1.java') """ % locals()) test.write('test1.java', """\ @@ -75,9 +51,9 @@ if os.path.normcase('.java') == os.path.normcase('.JAVA'): test.write('SConstruct', """\ -env = Environment(tools = ['rmic'], - RMIC = r'%(_python_)s myrmic.py') -env.RMIC(target = 'outdir', source = 'test2.JAVA') +DefaultEnvironment(tools=[]) +env = Environment(tools=['rmic'], RMIC=r'%(_python_)s myrmic.py') +env.RMIC(target='outdir', source='test2.JAVA') """ % locals()) test.write('test2.JAVA', """\ @@ -123,30 +99,34 @@ test.file_fixture('wrapper_with_args.py') test.write('SConstruct', """ -foo = Environment(tools = ['javac', 'rmic']) -foo.Java(target = 'class1', source = 'com/sub/foo') -foo.RMIC(target = 'outdir1', - source = ['class1/com/sub/foo/Example1.class', - 'class1/com/sub/foo/Example2'], - JAVACLASSDIR = 'class1') +DefaultEnvironment(tools=[]) +foo = Environment(tools=['javac', 'rmic']) +foo.Java(target='class1', source='com/sub/foo') +foo.RMIC( + target='outdir1', + source=['class1/com/sub/foo/Example1.class', 'class1/com/sub/foo/Example2'], + JAVACLASSDIR='class1', +) rmic = foo.Dictionary('RMIC') -bar = foo.Clone(RMIC = r'%(_python_)s wrapper_with_args.py ' + rmic) -bar_classes = bar.Java(target = 'class2', source = 'com/sub/bar') +bar = foo.Clone(RMIC=r'%(_python_)s wrapper_with_args.py ' + rmic) +bar_classes = bar.Java(target='class2', source='com/sub/bar') # XXX This is kind of a Python brute-force way to do what Ant # does with its "excludes" attribute. We should probably find # a similar friendlier way to do this. bar_classes = [c for c in bar_classes if 'Hello' not in str(c)] -bar.RMIC(target = Dir('outdir2'), source = bar_classes) +bar.RMIC(target=Dir('outdir2'), source=bar_classes) """ % locals() ) - test.subdir('com', - ['com', 'other'], - ['com', 'sub'], - ['com', 'sub', 'foo'], - ['com', 'sub', 'bar'], - 'src3a', - 'src3b') + test.subdir( + 'com', + ['com', 'other'], + ['com', 'sub'], + ['com', 'sub', 'foo'], + ['com', 'sub', 'bar'], + 'src3a', + 'src3b', + ) test.write(['com', 'sub', 'foo', 'Hello.java'], """\ package com.sub.foo; diff -Nru scons-4.0.1+dfsg/test/Java/source-files.py scons-4.4.0+dfsg/test/Java/source-files.py --- scons-4.0.1+dfsg/test/Java/source-files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/source-files.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that we can pass the Java() builder explicit lists of .java @@ -31,8 +30,6 @@ import TestSCons -_python_ = TestSCons._python_ - test = TestSCons.TestSCons() # Keep this logic because it skips the test if javac or jar not found. @@ -40,10 +37,10 @@ where_jar = test.java_where_jar() test.write('SConstruct', """ -env = Environment(tools = ['javac', 'javah']) -env.Java(target = 'class1', source = 'com/Example1.java') -env.Java(target = 'class2', source = ['com/Example2.java', 'com/Example3.java']) -""" % locals()) +env = Environment(tools=['javac']) +env.Java(target='class1', source='com/Example1.java') +env.Java(target='class2', source=['com/Example2.java', 'com/Example3.java']) +""") test.subdir('com', 'src') diff -Nru scons-4.0.1+dfsg/test/Java/swig-dependencies.py scons-4.4.0+dfsg/test/Java/swig-dependencies.py --- scons-4.0.1+dfsg/test/Java/swig-dependencies.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Java/swig-dependencies.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that dependencies on SWIG-generated .java files work correctly. @@ -39,8 +38,6 @@ test.skip_test('Can not find installed "swig", skipping test.\n') where_javac, java_version = test.java_where_javac() -where_javah = test.java_where_javah() - where_java_include=test.java_where_includes() test.subdir(['foo'], @@ -50,11 +47,11 @@ test.write(['SConstruct'], """\ import os -env = Environment(ENV = os.environ) +env = Environment(ENV=os.environ) if env['PLATFORM'] != 'win32': - env.Append(CPPFLAGS = ' -g -Wall') -env['CPPPATH'] ='$JAVAINCLUDES' - + env.Append(CPPFLAGS=' -g -Wall') +env['CPPPATH'] = '$JAVAINCLUDES' + Export('env') SConscript('#foo/SConscript') @@ -143,7 +140,6 @@ # 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 -Nru scons-4.0.1+dfsg/test/leaky-handles.py scons-4.4.0+dfsg/test/leaky-handles.py --- scons-4.0.1+dfsg/test/leaky-handles.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/leaky-handles.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,15 +28,14 @@ Verify that file handles aren't leaked to child processes """ -import os import sys import TestSCons test = TestSCons.TestSCons() -if os.name != 'posix' or sys.platform == 'darwin': - msg = "Skipping fork leak test on non-posix platform '%s'\n" % os.name +if sys.platform != 'linux': + msg = "Skipping fork leak test on non-linux platforms\n" test.skip_test(msg) test.write('SConstruct', """ diff -Nru scons-4.0.1+dfsg/test/LEX/FLEXFLAGS.py scons-4.4.0+dfsg/test/LEX/FLEXFLAGS.py --- scons-4.0.1+dfsg/test/LEX/FLEXFLAGS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/FLEXFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that detection of file-writing options in LEXFLAGS works. +Also test that construction vars for the same purpose work. +""" + +import sysconfig +from pathlib import Path + +import TestSCons +from TestCmd import IS_WINDOWS + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +test = TestSCons.TestSCons() + +test.subdir('sub1') +test.subdir('sub2') + +test.file_fixture('mylex.py') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +SConscript(dirs=['sub1', 'sub2']) +""") + +# this SConscript is for the options-in-flags version +test.write(['sub1', 'SConscript'], f"""\ +import sys + +env = Environment( + LEX=r'{_python_} mylex.py', + LEXFLAGS='-x --header-file=header.h --tables-file=tables.t', + tools=['default', 'lex'], +) +targs = env.CFile(target='aaa', source='aaa.l') +t = [str(target) for target in targs] +# fail ourselves if the two extra files were not detected +if not all((len(t) == 3, "header.h" in t, "tables.t" in t)): + sys.exit(1) +""") +test.write(['sub1', 'aaa.l'], "aaa.l\nLEXFLAGS\n") + +# this SConscript is for the construction var version +test.write(['sub2', 'SConscript'], f"""\ +import sys + +env = Environment( + LEX=r'{_python_} mylex.py', + LEXFLAGS='-x', + tools=['default', 'lex'], +) +env.CFile( + target='aaa', + source='aaa.l', + LEX_HEADER_FILE='header.h', + LEX_TABLES_FILE='tables.t', +) +""") +test.write(['sub2', 'aaa.l'], "aaa.l\nLEXFLAGS\n") + +test.run('.', stderr=None) + +lexflags = ' -x --header-file=header.h --tables-file=tables.t -t' +if IS_WINDOWS and not sysconfig.get_platform() in ("mingw",): + lexflags = ' --nounistd' + lexflags +# Read in with mode='r' because mylex.py implicitly wrote to stdout +# with mode='w'. +test.must_match(['sub1', 'aaa.c'], "aaa.l\n%s\n" % lexflags, mode='r') + +# NOTE: this behavior is "wrong" but we're keeping it for compat. +# the generated files should go into 'sub1', not the topdir. +test.must_match(['header.h'], 'lex header\n') +test.must_match(['tables.t'], 'lex table\n') + +# To confirm the files from the file-output options were tracked, +# we should do a clean and make sure they got removed. +# As noted, they currently don't go into the tracked location, +# so using the check in the SConscript instead. +#test.run(arguments='-c .') +#test.must_not_exist(test.workpath(['sub1', 'header.h'])) +#test.must_not_exist(test.workpath(['sub1', 'tables.t'])) + +sub2 = Path('sub2') +headerfile = sub2 / 'header.h' +tablefile = sub2 / 'tables.t' +lexflags = f' -x --header-file={headerfile} --tables-file={tablefile} -t' +if IS_WINDOWS and not sysconfig.get_platform() in ("mingw",): + lexflags = ' --nounistd' + lexflags +# Read in with mode='r' because mylex.py implicitly wrote to stdout +# with mode='w'. +test.must_match(['sub2', 'aaa.c'], "aaa.l\n%s\n" % lexflags, mode='r') +test.must_match(['sub2', 'header.h'], 'lex header\n') +test.must_match(['sub2', 'tables.t'], 'lex table\n') + +# To confirm the files from the file-output options were tracked, +# do a clean and make sure they got removed. +test.run(arguments='-c .', stderr=None) +test.must_not_exist(test.workpath('sub2', 'header.h')) +test.must_not_exist(test.workpath('sub2', 'tables.t')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/LEX/LEXCOM.py scons-4.4.0+dfsg/test/LEX/LEXCOM.py --- scons-4.0.1+dfsg/test/LEX/LEXCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/LEXCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $LEXCOM construction variable. @@ -37,16 +36,19 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'lex'], - LEXCOM = r'%(_python_)s mycompile.py lex $TARGET $SOURCES') -env.CFile(target = 'aaa', source = 'aaa.l') -env.CFile(target = 'bbb', source = 'bbb.lex') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'lex'], + LEXCOM=r'%(_python_)s mycompile.py lex $TARGET $SOURCES', +) +env.CFile(target='aaa', source='aaa.l') +env.CFile(target='bbb', source='bbb.lex') """ % locals()) test.write('aaa.l', "aaa.l\n/*lex*/\n") test.write('bbb.lex', "bbb.lex\n/*lex*/\n") -test.run(arguments = '.') +test.run(arguments='.') test.must_match('aaa.c', "aaa.l\n") test.must_match('bbb.c', "bbb.lex\n") diff -Nru scons-4.0.1+dfsg/test/LEX/LEXCOMSTR.py scons-4.4.0+dfsg/test/LEX/LEXCOMSTR.py --- scons-4.0.1+dfsg/test/LEX/LEXCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/LEXCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $LEXCOMSTR construction variable allows you to customize @@ -38,17 +37,20 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'lex'], - LEXCOM = r'%(_python_)s mycompile.py lex $TARGET $SOURCES', - LEXCOMSTR = 'Lexing $TARGET from $SOURCE') -env.CFile(target = 'aaa', source = 'aaa.l') -env.CFile(target = 'bbb', source = 'bbb.lex') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'lex'], + LEXCOM=r'%(_python_)s mycompile.py lex $TARGET $SOURCES', + LEXCOMSTR='Lexing $TARGET from $SOURCE', +) +env.CFile(target='aaa', source='aaa.l') +env.CFile(target='bbb', source='bbb.lex') """ % locals()) test.write('aaa.l', "aaa.l\n/*lex*/\n") test.write('bbb.lex', "bbb.lex\n/*lex*/\n") -test.run(stdout = test.wrap_stdout("""\ +test.run(stdout=test.wrap_stdout("""\ Lexing aaa.c from aaa.l Lexing bbb.c from bbb.lex """)) diff -Nru scons-4.0.1+dfsg/test/LEX/LEXFLAGS.py scons-4.4.0+dfsg/test/LEX/LEXFLAGS.py --- scons-4.0.1+dfsg/test/LEX/LEXFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/LEXFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,14 +22,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 os import sys +import sysconfig import TestSCons +from TestCmd import IS_WINDOWS _python_ = TestSCons._python_ _exe = TestSCons._exe @@ -36,48 +36,28 @@ test.subdir('in') -test.write('mylex.py', """ -import getopt -import sys -import os -if sys.platform == 'win32': - longopts = ['nounistd'] -else: - longopts = [] -cmd_opts, args = getopt.getopt(sys.argv[1:], 'I:tx', longopts) -opt_string = '' -i_arguments = '' -for opt, arg in cmd_opts: - if opt == '-I': i_arguments = i_arguments + ' ' + arg - else: opt_string = opt_string + ' ' + opt -for a in args: - with open(a, 'r') as f: - contents = f.read() - contents = contents.replace('LEXFLAGS', opt_string) - contents = contents.replace('I_ARGS', i_arguments) - sys.stdout.write(contents) -sys.exit(0) -""") - -test.write('SConstruct', """ -env = Environment(LEX = r'%(_python_)s mylex.py', - LEXFLAGS = '-x -I${TARGET.dir} -I${SOURCE.dir}', - tools=['default', 'lex']) -env.CFile(target = 'out/aaa', source = 'in/aaa.l') +test.file_fixture('mylex.py') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment( + LEX=r'%(_python_)s mylex.py', + LEXFLAGS='-x -I${TARGET.dir} -I${SOURCE.dir}', + tools=['default', 'lex'], +) +env.CFile(target='out/aaa', source='in/aaa.l') """ % locals()) test.write(['in', 'aaa.l'], "aaa.l\nLEXFLAGS\nI_ARGS\n") -test.run('.', stderr = None) +test.run('.', stderr=None) lexflags = ' -x -t' -if sys.platform == 'win32': +if IS_WINDOWS and not sysconfig.get_platform() in ("mingw",): lexflags = ' --nounistd' + lexflags -# Read in with mode='r' because mylex.py implicitley wrote to stdout +# Read in with mode='r' because mylex.py implicitly wrote to stdout # with mode='w'. -test.must_match(['out', 'aaa.c'], "aaa.l\n%s\n out in\n" % lexflags, mode='r') - - +test.must_match(['out', 'aaa.c'], "aaa.l\n%s\n out in\n" % lexflags, mode='r') test.pass_test() diff -Nru "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/SConstruct" "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/SConstruct" --- "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/SConstruct" 1970-01-01 00:00:00.000000000 +0000 +++ "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/SConstruct" 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,2 @@ +DefaultEnvironment(tools=[]) +SConscript("src/SConscript") \ No newline at end of file diff -Nru "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer2.l" "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer2.l" --- "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer2.l" 1970-01-01 00:00:00.000000000 +0000 +++ "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer2.l" 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +%% \ No newline at end of file diff -Nru "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer.l" "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer.l" --- "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer.l" 1970-01-01 00:00:00.000000000 +0000 +++ "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/lexer.l" 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +%% \ No newline at end of file diff -Nru "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/SConscript" "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/SConscript" --- "/tmp/tmp8jgoepld/OomgcaYXO5/scons-4.0.1+dfsg/test/LEX/lex_headerfile/spaced path/src/SConscript" 1970-01-01 00:00:00.000000000 +0000 +++ "/tmp/tmp8jgoepld/QobYWril2J/scons-4.4.0+dfsg/test/LEX/lex_headerfile/spaced path/src/SConscript" 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,10 @@ +env = Environment(tools=['lex']) + +def make_header_path(env, target, source, for_signature): + return target[1] + +env.Replace(LEX_HEADER_FILE_GEN=make_header_path) +env.Append(LEXFLAGS=['--header-file=$LEX_HEADER_FILE_GEN']) + +env.CFile(target=['#gen_src/lexer.c', '#gen_src/lexer.l.h'], source='lexer.l') +env.CFile(target=['#gen_src/lexer2.c', '#gen_src/lexer2.l.h'], source='lexer2.l') \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/LEX/lex_headerfile.py scons-4.4.0+dfsg/test/LEX/lex_headerfile.py --- scons-4.0.1+dfsg/test/LEX/lex_headerfile.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/lex_headerfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test the headerfile option for lex tool. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +lex = test.where_is('win_flex') or test.where_is('lex') or test.where_is('flex') +if not lex: + test.skip_test('No lex or flex found; skipping test.\n') + +test.dir_fixture('lex_headerfile') + +test.run(chdir='spaced path', arguments='.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/LEX/LEX.py scons-4.4.0+dfsg/test/LEX/LEX.py --- scons-4.0.1+dfsg/test/LEX/LEX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/LEX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,11 +22,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 import TestSCons @@ -33,46 +30,30 @@ test = TestSCons.TestSCons() - - -test.write('mylex.py', """ -import getopt -import sys -if sys.platform == 'win32': - longopts = ['nounistd'] -else: - longopts = [] -cmd_opts, args = getopt.getopt(sys.argv[1:], 't', longopts) -for a in args: - with open(a, 'rb') as f: - contents = f.read() - sys.stdout.write(contents.replace(b'LEX', b'mylex.py').decode()) -sys.exit(0) -""") +test.file_fixture('mylex.py') test.write('SConstruct', """ -env = Environment(LEX = r'%(_python_)s mylex.py', tools=['default', 'lex']) -env.CFile(target = 'aaa', source = 'aaa.l') -env.CFile(target = 'bbb', source = 'bbb.lex') -env.CXXFile(target = 'ccc', source = 'ccc.ll') -env.CXXFile(target = 'ddd', source = 'ddd.lm') +DefaultEnvironment(tools=[]) +env = Environment(LEX=r'%(_python_)s mylex.py', tools=['default', 'lex']) +env.CFile(target='aaa', source='aaa.l') +env.CFile(target='bbb', source='bbb.lex') +env.CXXFile(target='ccc', source='ccc.ll') +env.CXXFile(target='ddd', source='ddd.lm') """ % locals()) -test.write('aaa.l', "aaa.l\nLEX\n") -test.write('bbb.lex', "bbb.lex\nLEX\n") -test.write('ccc.ll', "ccc.ll\nLEX\n") -test.write('ddd.lm', "ddd.lm\nLEX\n") +test.write('aaa.l', "aaa.l\nLEX\n") +test.write('bbb.lex', "bbb.lex\nLEX\n") +test.write('ccc.ll', "ccc.ll\nLEX\n") +test.write('ddd.lm', "ddd.lm\nLEX\n") -test.run(arguments = '.', stderr = None) +test.run(arguments='.', stderr=None) # Read in with mode='r' because mylex.py implicitley wrote to stdout # with mode='w'. -test.must_match('aaa.c', "aaa.l\nmylex.py\n", mode='r') -test.must_match('bbb.c', "bbb.lex\nmylex.py\n", mode='r') -test.must_match('ccc.cc', "ccc.ll\nmylex.py\n", mode='r') -test.must_match('ddd.m', "ddd.lm\nmylex.py\n", mode='r') - - +test.must_match('aaa.c', "aaa.l\nmylex.py\n", mode='r') +test.must_match('bbb.c', "bbb.lex\nmylex.py\n", mode='r') +test.must_match('ccc.cc', "ccc.ll\nmylex.py\n", mode='r') +test.must_match('ddd.m', "ddd.lm\nmylex.py\n", mode='r') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/LEX/live_mingw.py scons-4.4.0+dfsg/test/LEX/live_mingw.py --- scons-4.0.1+dfsg/test/LEX/live_mingw.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/live_mingw.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test LEX and LEXFLAGS and unistd.h with a live lex in mingw environment. @@ -31,17 +30,18 @@ import sys import TestSCons +from TestCmd import IS_WINDOWS _exe = TestSCons._exe _python_ = TestSCons._python_ test = TestSCons.TestSCons() -if sys.platform != 'win32': +if not IS_WINDOWS: test.skip_test('Not windows environment; skipping test.\n') if not test.where_is('gcc'): - test.skip_test('No mingw or cygwin build environment found; skipping test.\n') + test.skip_test('No mingw or cygwin build environment found; skipping test.\n') lex = test.where_is('lex') or test.where_is('flex') @@ -51,14 +51,17 @@ test.file_fixture('wrapper.py') test.write('SConstruct', """ +DefaultEnvironment(tools=[]) foo = Environment(tools=['default', 'mingw', 'lex'], LEXUNISTD="") lex = foo.Dictionary('LEX') -bar = Environment(LEX = r'%(_python_)s wrapper.py ' + lex, - LEXFLAGS = '-b', - LEXUNISTD="", - tools=['default', 'mingw', 'lex']) -foo.Program(target = 'foo', source = 'foo.l') -bar.Program(target = 'bar', source = 'bar.l') +bar = Environment( + LEX=r'%(_python_)s wrapper.py ' + lex, + LEXFLAGS='-b', + LEXUNISTD="", + tools=['default', 'mingw', 'lex'], +) +foo.Program(target='foo', source='foo.l') +bar.Program(target='bar', source='bar.l') """ % locals()) lex = r""" diff -Nru scons-4.0.1+dfsg/test/LEX/live.py scons-4.4.0+dfsg/test/LEX/live.py --- scons-4.0.1+dfsg/test/LEX/live.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/live.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test LEX and LEXFLAGS with a live lex. @@ -36,19 +35,18 @@ test = TestSCons.TestSCons() lex = test.where_is('win_flex') or test.where_is('lex') or test.where_is('flex') - if not lex: test.skip_test('No lex or flex found; skipping test.\n') test.file_fixture('wrapper.py') test.write('SConstruct', """ +DefaultEnvironment(tools=[]) foo = Environment() lex = foo.Dictionary('LEX') -bar = Environment(LEX = r'%(_python_)s wrapper.py ' + lex, - LEXFLAGS = '-b') -foo.Program(target = 'foo', source = 'foo.l') -bar.Program(target = 'bar', source = 'bar.l') +bar = Environment(LEX=r'%(_python_)s wrapper.py ' + lex, LEXFLAGS='-b') +foo.Program(target='foo', source='foo.l') +bar.Program(target='bar', source='bar.l') """ % locals()) lex = r""" @@ -70,22 +68,18 @@ """ test.write('foo.l', lex % ('foo.l', 'foo.l')) - test.write('bar.l', lex % ('bar.l', 'bar.l')) -test.run(arguments = 'foo' + _exe, stderr = None) - +test.run(arguments='foo' + _exe, stderr=None) test.must_not_exist(test.workpath('wrapper.out')) test.must_not_exist(test.workpath('lex.backup')) -test.run(program = test.workpath('foo'), stdin = "a\n", stdout = "Afoo.lA\n") - -test.run(arguments = 'bar' + _exe) - +test.run(program=test.workpath('foo'), stdin="a\n", stdout="Afoo.lA\n") +test.run(arguments='bar' + _exe) test.must_match(test.workpath('wrapper.out'), "wrapper.py\n") test.must_exist(test.workpath('lex.backup')) -test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "Bbar.lB\n") +test.run(program=test.workpath('bar'), stdin="b\n", stdout="Bbar.lB\n") test.pass_test() diff -Nru scons-4.0.1+dfsg/test/LEX/no_lex.py scons-4.4.0+dfsg/test/LEX/no_lex.py --- scons-4.0.1+dfsg/test/LEX/no_lex.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LEX/no_lex.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test Environments are functional and return None when no lex tool is found. @@ -35,7 +34,7 @@ test.write('SConstruct', """ import SCons -def no_lex(env, key_program, default_paths=[]): +def no_lex(env, key_program, default_paths=[], add_path=False): return None class TestEnvironment(SCons.Environment.Environment): @@ -44,11 +43,12 @@ SCons.Tool.find_program_path = no_lex +DefaultEnvironment(tools=[]) foo = TestEnvironment(tools=['default', 'lex']) print(foo.Dictionary('LEX')) """ % locals()) -test.run(arguments = '-Q -s', stdout = 'None\n' ) +test.run(arguments='-Q -s', stdout='None\n') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Libs/LIBPATH.py scons-4.4.0+dfsg/test/Libs/LIBPATH.py --- scons-4.0.1+dfsg/test/Libs/LIBPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Libs/LIBPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 os.path import time @@ -40,20 +40,17 @@ prog1 = test.workpath('prog') + _exe prog2 = test.workpath(dll_ + 'shlib') + _dll -test.write('SConstruct', """ -env1 = Environment(LIBS = [ 'foo1' ], - LIBPATH = [ '$FOO' ], - FOO='./lib1') +test.write('SConstruct', """\ +env1 = Environment(LIBS=['foo1'], LIBPATH=['$FOO'], FOO='./lib1') f1 = env1.SharedObject('f1', 'f1.c') -env1.Program(target = 'prog', source = 'prog.c') -env1.Library(target = './lib1/foo1', source = f1) +env1.Program(target='prog', source='prog.c') +env1.Library(target='./lib1/foo1', source=f1) -env2 = Environment(LIBS = 'foo2', - LIBPATH = '.') -env2.SharedLibrary(target = 'shlib', source = 'shlib.c', no_import_lib = 1) -env2.Library(target = 'foo2', source = f1) +env2 = Environment(LIBS='foo2', LIBPATH='.') +env2.SharedLibrary(target='shlib', source='shlib.c', no_import_lib=1) +env2.Library(target='foo2', source=f1) """) test.write('f1.c', r""" @@ -99,8 +96,8 @@ oldtime1 = os.path.getmtime(prog1) oldtime2 = os.path.getmtime(prog2) -time.sleep(2) -test.run(arguments = '.') +test.sleep() # delay for timestamps +test.run(arguments='.') test.fail_test(oldtime1 != os.path.getmtime(prog1)) test.fail_test(oldtime2 != os.path.getmtime(prog2)) @@ -115,30 +112,25 @@ } """) -test.run(arguments = '.', - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) -test.run(program = prog1, - stdout = "f1.c 1\nprog.c\n") +test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall) +test.run(program=prog1, stdout="f1.c 1\nprog.c\n") test.fail_test(oldtime2 == os.path.getmtime(prog2)) #test.up_to_date(arguments = '.') # Change LIBPATH and make sure we don't rebuild because of it. -test.write('SConstruct', """ -env1 = Environment(LIBS = [ 'foo1' ], - LIBPATH = [ './lib1', './lib2' ]) +test.write('SConstruct', """\ +env1 = Environment(LIBS=['foo1'], LIBPATH=['./lib1', './lib2']) f1 = env1.SharedObject('f1', 'f1.c') -env1.Program(target = 'prog', source = 'prog.c') -env1.Library(target = './lib1/foo1', source = f1) +env1.Program(target='prog', source='prog.c') +env1.Library(target='./lib1/foo1', source=f1) -env2 = Environment(LIBS = 'foo2', - LIBPATH = Split('. ./lib2')) -env2.SharedLibrary(target = 'shlib', source = 'shlib.c', no_import_lib = 1) -env2.Library(target = 'foo2', source = f1) +env2 = Environment(LIBS='foo2', LIBPATH=Split('. ./lib2')) +env2.SharedLibrary(target='shlib', source='shlib.c', no_import_lib=1) +env2.Library(target='foo2', source=f1) """) -test.up_to_date(arguments = '.', stderr=None) +test.up_to_date(arguments='.', stderr=None) test.write('f1.c', r""" #include @@ -150,27 +142,22 @@ } """) -test.run(arguments = '.', - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) -test.run(program = prog1, - stdout = "f1.c 2\nprog.c\n") +test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall) +test.run(program=prog1, stdout="f1.c 2\nprog.c\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') # We need at least one file for some implementations of the Library # builder, notably the SGI one. test.write('empty.c', 'int a=0;\n') # Check that a null-string LIBPATH doesn't blow up. -test.write('SConstruct', """ -env = Environment(LIBPATH = '') -env.Library('foo', source = 'empty.c') +test.write('SConstruct', """\ +env = Environment(LIBPATH='') +env.Library('foo', source='empty.c') """) -test.run(arguments = '.', - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) +test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Libs/LIBPREFIXES.py scons-4.4.0+dfsg/test/Libs/LIBPREFIXES.py --- scons-4.0.1+dfsg/test/Libs/LIBPREFIXES.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Libs/LIBPREFIXES.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,21 +22,17 @@ # 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 TestSCons +from TestSCons import _lib if sys.platform == 'win32': - _lib = '.lib' import SCons.Tool.MSCommon as msc if not msc.msvc_exists(): _lib = '.a' -else: - _lib = '.a' test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Libs/LIBS.py scons-4.4.0+dfsg/test/Libs/LIBS.py --- scons-4.0.1+dfsg/test/Libs/LIBS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Libs/LIBS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,22 +22,22 @@ # 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 TestSCons -import sys + +# Leave below to resolve sider complaints +_exe = TestSCons._exe +lib_ = TestSCons.lib_ +_lib = TestSCons._lib if sys.platform == 'win32': - _exe = '.exe' - bar_lib = 'bar.lib' import SCons.Tool.MSCommon as msc if not msc.msvc_exists(): - bar_lib = 'libbar.a' -else: - _exe = '' - bar_lib = 'libbar.a' + _lib = '.a' + lib_ = 'lib' +bar_lib = lib_ + 'bar' + _lib test = TestSCons.TestSCons() @@ -97,6 +99,7 @@ test.write('sl.c', """\ #include + void sl(void) { @@ -105,7 +108,11 @@ """) test.write('slprog.c', """\ +#include #include + +void sl(void); + int main(int argc, char *argv[]) { diff -Nru scons-4.0.1+dfsg/test/Libs/SharedLibrary.py scons-4.4.0+dfsg/test/Libs/SharedLibrary.py --- scons-4.0.1+dfsg/test/Libs/SharedLibrary.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Libs/SharedLibrary.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 import sys @@ -33,38 +32,29 @@ test.write('SConstruct', """ import sys -env=Environment(WINDOWS_INSERT_DEF=1) -env2 = Environment(LIBS = [ 'foo1', 'foo2', 'foo3' ], - LIBPATH = [ '.' ]) -env.SharedLibrary(target = 'foo1', source = 'f1.c') + +env = Environment(WINDOWS_INSERT_DEF=1) +env2 = Environment(LIBS=['foo1', 'foo2', 'foo3'], LIBPATH=['.']) +env.SharedLibrary(target='foo1', source='f1.c') if sys.platform == 'win32': - env.StaticLibrary(target = 'foo1-static', source = 'f1.c') + env.StaticLibrary(target='foo1-static', source='f1.c') else: - env.StaticLibrary(target = 'foo1', source = 'f1.c') -SharedLibrary(target = 'foo2', - source = Split('f2a.c f2b.c f2c.c'), - WINDOWS_INSERT_DEF = 1) -env.SharedLibrary(target = 'foo3', source = ['f3a.c', 'f3b.c', 'f3c.c'], no_import_lib = 1) -env2.Program(target = 'prog', source = 'prog.c') + env.StaticLibrary(target='foo1', source='f1.c') +SharedLibrary(target='foo2', source=Split('f2a.c f2b.c f2c.c'), WINDOWS_INSERT_DEF=1) +env.SharedLibrary(target='foo3', source=['f3a.c', 'f3b.c', 'f3c.c'], no_import_lib=1) +env2.Program(target='prog', source='prog.c') """) test.write('SConstructFoo', """ -env=Environment() +env = Environment() obj = env.Object('foo', 'foo.c') -Default(env.SharedLibrary(target = 'foo', source = obj)) +Default(env.SharedLibrary(target='foo', source=obj)) """) test.write('SConstructFoo2', """ -env=Environment() +env = Environment() obj = env.SharedObject('bar', 'foo.c') -Default(env.Library(target = 'foo', source = obj)) -""") - -test.write('SConstructBaz', """ -env=Environment() -env['SHLIBVERSION'] = '1.0.0' -obj = env.SharedObject('baz', 'foo.c') -Default(env.SharedLibrary(target = 'baz', source = obj)) +Default(env.Library(target='foo', source=obj)) """) test.write('foo.c', r""" @@ -252,7 +242,7 @@ test.write('f4.c', r""" #include -f4(void) +void f4(void) { printf("f4.c\n"); fflush(stdout); @@ -291,12 +281,6 @@ test.run(program = test.workpath('progbar'), stdout = "f4.c\nprogbar.c\n") -if sys.platform.startswith('openbsd'): - # Make sure we don't link libraries with -Wl,-soname on OpenBSD. - test.run(arguments = '-f SConstructBaz') - for line in test.stdout().split('\n'): - test.fail_test(line.find('-Wl,-soname=libbaz.so') != -1) - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Libs/SharedLibrary-update-deps.py scons-4.4.0+dfsg/test/Libs/SharedLibrary-update-deps.py --- scons-4.0.1+dfsg/test/Libs/SharedLibrary-update-deps.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Libs/SharedLibrary-update-deps.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,17 +22,16 @@ # 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 that SharedLibrary() updates when a different lib is linked, even if it has the same md5. +Test that SharedLibrary() updates when a different lib is linked, +even if it has the same md5. This is https://github.com/SCons/scons/issues/2903 """ import sys -import os.path +import sysconfig + import TestSCons test = TestSCons.TestSCons() @@ -51,7 +52,7 @@ test.must_not_contain_any_line(test.stdout(), ["is up to date"]) # Now try changing the link command line (in an innocuous way); should rebuild. -if sys.platform == 'win32': +if sys.platform == 'win32' and not sysconfig.get_platform() in ("mingw",): extraflags='shlinkflags=/DEBUG' else: extraflags='shlinkflags=-g' diff -Nru scons-4.0.1+dfsg/test/LINK/LDMODULEVERSIONFLAGS.py scons-4.4.0+dfsg/test/LINK/LDMODULEVERSIONFLAGS.py --- scons-4.0.1+dfsg/test/LINK/LDMODULEVERSIONFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/LDMODULEVERSIONFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,8 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os -import re import TestSCons import SCons.Platform diff -Nru scons-4.0.1+dfsg/test/LINK/LINKFLAGS.py scons-4.4.0+dfsg/test/LINK/LINKFLAGS.py --- scons-4.0.1+dfsg/test/LINK/LINKFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/LINKFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/LINK/LINK.py scons-4.4.0+dfsg/test/LINK/LINK.py --- scons-4.0.1+dfsg/test/LINK/LINK.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/LINK.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/LINK/SHLIBVERSIONFLAGS.py scons-4.4.0+dfsg/test/LINK/SHLIBVERSIONFLAGS.py --- scons-4.0.1+dfsg/test/LINK/SHLIBVERSIONFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/SHLIBVERSIONFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -22,14 +24,11 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import re import TestSCons -import SCons.Platform + import SCons.Defaults +import SCons.Platform foo_c_src = "void foo() {}\n" @@ -40,43 +39,62 @@ test = TestSCons.TestSCons() if 'gnulink' in tool_list: versionflags = r".+ -Wl,-soname=libfoo.so.1( .+)+" - soname='libfoo.so.4' - sonameVersionFlags=r".+ -Wl,-soname=%s( .+)+" % soname + soname = 'libfoo.so.4' + sonameVersionFlags = r".+ -Wl,-soname=%s( .+)+" % soname elif 'sunlink' in tool_list: versionflags = r".+ -h libfoo.so.1( .+)+" - soname='libfoo.so.4' - sonameVersionFlags=r".+ -h %s( .+)+" % soname + soname = 'libfoo.so.4' + sonameVersionFlags = r".+ -h %s( .+)+" % soname elif 'applelink' in tool_list: - versionflags = r".+ 'libfoo.1.dylib'->'libfoo.1.2.3.dylib'(.+)+" - soname='libfoo.4.dylib' - sonameVersionFlags=r".+ '%s'->'libfoo.1.2.3.dylib'(.+)+" % soname + versionflags = r".+ -Wl,-current_version,1.2.3( .+)+" + soname = 'libfoo.4.dylib' + sonameVersionFlags = r".+ -Wl,-compatibility_version,1.2.0(.+)+" else: test.skip_test('No testable linkers found, skipping the test\n') - # stdout must not contain SHLIBVERSIONFLAGS if there is no SHLIBVERSION provided test.write('foo.c', foo_c_src) test.write('SConstruct', "SharedLibrary('foo','foo.c')\n") test.run() test.fail_test(test.match_re_dotall(test.stdout(), versionflags)) -test.run(arguments = ['-c']) +test.run(arguments=['-c']) # stdout must contain SHLIBVERSIONFLAGS if there is SHLIBVERSION provided test = TestSCons.TestSCons() test.write('foo.c', foo_c_src) test.write('SConstruct', "SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3')\n") -test.run(stdout = versionflags, match = TestSCons.match_re_dotall) -test.run(arguments = ['-c']) +test.run(stdout=versionflags, match=TestSCons.match_re_dotall) +test.run(arguments=['-c']) -# stdout must contain SHLIBVERSIONFLAGS if there is SHLIBVERSION provided +# stdout must contain SONAME if there is SONAME provided test = TestSCons.TestSCons() test.write('foo.c', foo_c_src) test.write('SConstruct', """ SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SONAME='%s') """ % soname) -test.run(stdout = sonameVersionFlags, match = TestSCons.match_re_dotall) -test.run(arguments = ['-c']) +test.run(stdout=sonameVersionFlags, match=TestSCons.match_re_dotall) +test.must_exist(test.workpath(soname)) +test.run(arguments=['-c']) + +# stdout must contain SOVERSION if there is SOVERSION provided +test = TestSCons.TestSCons() +test.write('foo.c', foo_c_src) +test.write('SConstruct', """ +SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SOVERSION='4') +""") +test.run(stdout=sonameVersionFlags, match=TestSCons.match_re_dotall) +test.must_exist(test.workpath(soname)) +test.run(arguments=['-c']) + +# test if both SONAME and SOVERSION are used +test = TestSCons.TestSCons() +test.write('foo.c', foo_c_src) +test.write('SConstruct', """ +SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SONAME='%s',SOVERSION='4') +""" % soname) +test.run(status=2, stderr=None) +test.must_contain_all_lines(test.stderr(), ['Ambiguous library .so naming']) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/LINK/SHLINKFLAGS.py scons-4.4.0+dfsg/test/LINK/SHLINKFLAGS.py --- scons-4.0.1+dfsg/test/LINK/SHLINKFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/SHLINKFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/LINK/SHLINK.py scons-4.4.0+dfsg/test/LINK/SHLINK.py --- scons-4.0.1+dfsg/test/LINK/SHLINK.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/SHLINK.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/LINK/VersionedLib.py scons-4.4.0+dfsg/test/LINK/VersionedLib.py --- scons-4.0.1+dfsg/test/LINK/VersionedLib.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/LINK/VersionedLib.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -21,10 +23,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os -import sys import TestSCons import SCons.Platform @@ -219,7 +218,7 @@ instfiles = t['instfiles'] test.write('SConstruct', """\ -import os +DefaultEnvironment(tools=[]) env = Environment() objs = env.SharedObject('test.c') mylib = env.SharedLibrary('test', objs, SHLIBVERSION = '%s') diff -Nru scons-4.0.1+dfsg/test/long-lines/signature.py scons-4.4.0+dfsg/test/long-lines/signature.py --- scons-4.0.1+dfsg/test/long-lines/signature.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/long-lines/signature.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that use of long command lines correctly excludes arguments @@ -38,18 +37,22 @@ build_py = test.workpath('build.py') +# create a dummy command which understands a tempfile syntax +# so it doesn't have to be that platform/compiler's specific syntax. test.write(build_py, """\ #!%(_python_)s import sys -if sys.argv[1][0] == '@': - with open(sys.argv[1][1:], 'r') as f: - args = f.read().split() +if sys.argv[1].startswith('@'): + tempfile = sys.argv[1][1:] + with open(tempfile, 'r') as tmp: + args = tmp.read().split() else: args = sys.argv[1:] -with open(args[0], 'w') as fp, open(args[1], 'r') as ifp: - fp.write(ifp.read()) - fp.write('FILEFLAG=%%s\\n' %% args[2]) - fp.write('TIMESTAMP=%%s\\n' %% args[3]) + +with open(args[0], 'w') as ofp, open(args[1], 'r') as ifp: + ofp.write(ifp.read()) + ofp.write('FILEFLAG=%%s\\n' %% args[2]) + ofp.write('TIMESTAMP=%%s\\n' %% args[3]) """ % locals()) os.chmod(build_py, 0o755) @@ -58,21 +61,29 @@ DefaultEnvironment(tools=[]) arg = 'a_long_ignored_argument' extra_arguments = arg -while len(extra_arguments) <= 1024: +MAXLINE=1024 +while len(extra_arguments) <= MAXLINE: extra_arguments = extra_arguments + ' ' + arg -env = Environment(tools=[], - FILECOM=[r'%(build_py)s', - '$TARGET', '$SOURCE', - '$FILEFLAG', - '$(', '$TIMESTAMP', '$)', - '$EXTRA_ARGUMENTS'], - FILEFLAG=ARGUMENTS.get('FILEFLAG'), - TIMESTAMP=ARGUMENTS.get('TIMESTAMP'), - EXTRA_ARGUMENTS=extra_arguments, - MAXLINELENGTH=1024) +env = Environment( + tools=[], + FILECOM=[ + r'%(build_py)s', + '$TARGET', + '$SOURCE', + '$FILEFLAG', + '$(', + '$TIMESTAMP', + '$)', + '$EXTRA_ARGUMENTS', + ], + FILEFLAG=ARGUMENTS.get('FILEFLAG'), + TIMESTAMP=ARGUMENTS.get('TIMESTAMP'), + EXTRA_ARGUMENTS=extra_arguments, + MAXLINELENGTH=MAXLINE, + TEMPFILEPREFIX='@', +) env.PrependENVPath('PATHEXT', '.PY') -env.Command('file.out', 'file.in', - '${TEMPFILE(FILECOM)}') +env.Command('file.out', 'file.in', r'%(_python_)s ${TEMPFILE(FILECOM)}') """ % locals()) test.write('file.in', "file.in\n", mode='w') diff -Nru scons-4.0.1+dfsg/test/MinGW/bug_2799/SConstruct scons-4.4.0+dfsg/test/MinGW/bug_2799/SConstruct --- scons-4.0.1+dfsg/test/MinGW/bug_2799/SConstruct 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/bug_2799/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -1,12 +1,12 @@ env = Environment( - tools = ['mingw'], - SHCCCOMSTR = 'SHCC $TARGET', - SHLINKCOMSTR = 'SHLINK $TARGET', - LDMODULECOMSTR = 'LDMODULE $TARGET', - SHOBSUFFIX='.o', - SHLIBSUFFIX='.so', - SHLIBPREFIX='lib', - LDMODULESUFFIX='.so', + tools=['mingw'], + SHCCCOMSTR='SHCC $TARGET', + SHLINKCOMSTR='SHLINK $TARGET', + LDMODULECOMSTR='LDMODULE $TARGET', + SHOBSUFFIX='.o', + SHLIBSUFFIX='.so', + SHLIBPREFIX='lib', + LDMODULESUFFIX='.so', ) env.SharedLibrary('testlib', 'shlib.c') diff -Nru scons-4.0.1+dfsg/test/MinGW/MinGWSharedLibrary.py scons-4.4.0+dfsg/test/MinGW/MinGWSharedLibrary.py --- scons-4.0.1+dfsg/test/MinGW/MinGWSharedLibrary.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/MinGWSharedLibrary.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $RCCOM construction variable @@ -42,23 +41,28 @@ test = TestSCons.TestSCons() -if sys.platform not in ('cygwin','win32',): - test.skip_test("Skipping mingw test on non-Windows %s platform."%sys.platform) +if sys.platform not in ('cygwin', 'win32',): + test.skip_test("Skipping mingw test on non-Windows platform %s." % sys.platform) -gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) +dp = MINGW_DEFAULT_PATHS +gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=dp) if not gcc: test.skip_test("Skipping mingw test, no MinGW found.\n") test.write('foobar.cc', """ int abc(int a) { return (a+1); - } - """) +} +""") test.write('SConstruct', """ -env = Environment(tools=['mingw','link','g++']) -#env.Tool('mingw') -env.SharedLibrary('foobar', 'foobar.cc') +DefaultEnvironment(tools=[]) +env = Environment(tools=['mingw', 'link', 'g++']) +foobar_obj = env.SharedObject('foobar.cc') +env.SharedLibrary('foobar', foobar_obj) + +# Now verify versioned shared library doesn't fail +env.SharedLibrary('foobar_ver', foobar_obj, SHLIBVERSION='2.4') """ % locals()) test.run(arguments = ".") diff -Nru scons-4.0.1+dfsg/test/MinGW/mingw_uses_comstr_issue_2799.py scons-4.4.0+dfsg/test/MinGW/mingw_uses_comstr_issue_2799.py --- scons-4.0.1+dfsg/test/MinGW/mingw_uses_comstr_issue_2799.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/mingw_uses_comstr_issue_2799.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -28,7 +30,6 @@ Test that mingw respects SHLINKCOMSTR, SHCCCOMSTR, and LDMODULECOMSTR """ -import sys import TestSCons _python_ = TestSCons._python_ @@ -38,13 +39,16 @@ test.dir_fixture('bug_2799') test.run('-n -Q') -test.must_contain_all_lines(test.stdout(), - [ - 'SHCC shlib.o', - 'SHLINK libtestlib.so', - 'SHCC module.o', - 'LDMODULE libtestmodule.so',''], - ) +test.must_contain_all_lines( + test.stdout(), + [ + 'SHCC shlib.o', + 'SHLINK libtestlib.so', + 'SHCC module.o', + 'LDMODULE libtestmodule.so', + '', + ], +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/MinGW/RCCOM.py scons-4.4.0+dfsg/test/MinGW/RCCOM.py --- scons-4.0.1+dfsg/test/MinGW/RCCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/RCCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,13 +22,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__" """ Test the ability to configure the $RCCOM construction variable -when using MinGW. +when using MinGW. This test does not use a compiler. """ import sys @@ -37,14 +36,17 @@ test = TestSCons.TestSCons() if sys.platform in ('irix6',): - test.skip_test("Skipping mingw test on non-Windows %s platform."%sys.platform) + test.skip_test("Skipping mingw test on non-Windows platform %s." % sys.platform) test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'mingw'], - RCCOM = r'%(_python_)s mycompile.py rc $TARGET $SOURCES') -env.RES(target = 'aaa', source = 'aaa.rc') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'mingw'], + RCCOM=r'%(_python_)s mycompile.py rc $TARGET $SOURCES', +) +env.RES(target='aaa', source='aaa.rc') """ % locals()) test.write('aaa.rc', "aaa.rc\n/*rc*/\n") diff -Nru scons-4.0.1+dfsg/test/MinGW/RCCOMSTR.py scons-4.4.0+dfsg/test/MinGW/RCCOMSTR.py --- scons-4.0.1+dfsg/test/MinGW/RCCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/RCCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,13 +22,11 @@ # 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 that the $RCCOMSTR construction variable allows you to customize -the displayed string when rc is called. +the displayed string when rc is called when using MinGW. +This test does not use a compiler. """ import sys @@ -42,10 +42,13 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'mingw'], - RCCOM = r'%(_python_)s mycompile.py rc $TARGET $SOURCES', - RCCOMSTR = 'RCing $TARGET from $SOURCE') -env.RES(target = 'aaa', source = 'aaa.rc') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'mingw'], + RCCOM=r'%(_python_)s mycompile.py rc $TARGET $SOURCES', + RCCOMSTR='RCing $TARGET from $SOURCE', +) +env.RES(target='aaa', source='aaa.rc') """ % locals()) test.write('aaa.rc', "aaa.rc\n/*rc*/\n") diff -Nru scons-4.0.1+dfsg/test/MinGW/WINDOWS_INSERT_DEF.py scons-4.4.0+dfsg/test/MinGW/WINDOWS_INSERT_DEF.py --- scons-4.0.1+dfsg/test/MinGW/WINDOWS_INSERT_DEF.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MinGW/WINDOWS_INSERT_DEF.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Make sure that WINDOWS_INSERT_DEF isn't ignored when using MinGW. @@ -39,11 +38,11 @@ test = TestSCons.TestSCons() -if sys.platform not in ('cygwin', 'win32'): - test.skip_test( - "Skipping mingw test on non-Windows platform: %s" % sys.platform) +if sys.platform not in ('cygwin', 'win32',): + test.skip_test("Skipping mingw test on non-Windows platform %s\n" % sys.platform) -gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) +dp = MINGW_DEFAULT_PATHS +gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=dp) if not gcc: test.skip_test("Skipping mingw test, no MinGW found.\n") @@ -53,9 +52,9 @@ """) test.write('SConstruct', """ -env = Environment(TOOLS = ['mingw']) -hello_dll = env.SharedLibrary(WINDOWS_INSERT_DEF = 0, - target = 'hello', source = 'hello.c') +DefaultEnvironment(tools=[]) +env = Environment(TOOLS=['mingw']) +hello_dll = env.SharedLibrary(WINDOWS_INSERT_DEF=0, target='hello', source='hello.c') """ % locals()) test.run(arguments = ".") diff -Nru scons-4.0.1+dfsg/test/MSVC/hierarchical.py scons-4.4.0+dfsg/test/MSVC/hierarchical.py --- scons-4.0.1+dfsg/test/MSVC/hierarchical.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/hierarchical.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify use of Visual Studio with a hierarchical build. @@ -37,18 +36,16 @@ test.subdir('src', 'build', 'out') test.write('SConstruct', """ +DefaultEnvironment(tools=[]) VariantDir('build', 'src', duplicate=0) SConscript('build/SConscript') """) test.write('src/SConscript',""" -import os # TODO: this is order-dependent (putting 'mssdk' second or third breaks), # and ideally we shouldn't need to specify the tools= list anyway. env = Environment(tools=['mssdk', 'msvc', 'mslink']) -env.Append(CPPPATH=os.environ.get('INCLUDE', ''), - LIBPATH=os.environ.get('LIB', '')) -env['PCH'] = 'StdAfx.pch' +env['PCH'] = File('StdAfx.pch') env['PDB'] = '#out/test.pdb' env['PCHSTOP'] = 'StdAfx.h' env.PCH('StdAfx.cpp') diff -Nru scons-4.0.1+dfsg/test/MSVC/mssdk.py scons-4.4.0+dfsg/test/MSVC/mssdk.py --- scons-4.0.1+dfsg/test/MSVC/mssdk.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/mssdk.py 2022-07-30 21:48:28.000000000 +0000 @@ -27,7 +27,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import time import TestSCons diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_badversion.py scons-4.4.0+dfsg/test/MSVC/msvc_badversion.py --- scons-4.0.1+dfsg/test/MSVC/msvc_badversion.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_badversion.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test scons with an invalid MSVC version when at least one MSVC is present. +""" + +import sys + +import TestSCons +import SCons.Tool.MSCommon.vc as msvc + +test = TestSCons.TestSCons() + +if sys.platform != 'win32': + test.skip_test("Not win32 platform. Skipping test\n") + +test.skip_if_not_msvc() + +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 + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(MSVC_VERSION='12.9') +""") +test.run(arguments='-Q -s', stdout='') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='ignore') +""") +test.run(arguments='-Q -s', stdout='') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='warning') +""") +test.run(arguments='-Q -s', stdout='') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='error') +""") +test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall) + +test.write('SConstruct', """\ +env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='bad_value') +""") +test.run(arguments='-Q -s', status=2, stderr=r"^.* Value specified for MSVC_NOTFOUND_POLICY.+", match=TestSCons.match_re_dotall) + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_cache_force_defaults.py scons-4.4.0+dfsg/test/MSVC/msvc_cache_force_defaults.py --- scons-4.0.1+dfsg/test/MSVC/msvc_cache_force_defaults.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_cache_force_defaults.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,80 @@ +# 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. + +""" +Test SCONS_CACHE_MSVC_FORCE_DEFAULTS system environment variable. +""" + +import textwrap + +from SCons.Tool.MSCommon.vc import get_installed_vcs_components +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +installed_versions = get_installed_vcs_components() + +default_version = installed_versions[0] + +if default_version.msvc_vernum >= 14.0: + # VS2015 and later + + # force SDK version and toolset version as msvc batch file arguments + test.write('SConstruct', textwrap.dedent( + """ + import os + import json + + cache_file = 'MSCACHE.json' + + os.environ['SCONS_CACHE_MSVC_CONFIG']=cache_file + os.environ['SCONS_CACHE_MSVC_FORCE_DEFAULTS']='1' + + DefaultEnvironment(tools=[]) + env = Environment(tools=['msvc']) + + envcache_keys = [] + with open(cache_file, 'r') as file: + envcache_list = json.load(file) + envcache_keys = [tuple(d['key']) for d in envcache_list] + + if envcache_keys: + # key = (script, arguments) + print("SCRIPT_ARGS: {}".format(envcache_keys[0][-1])) + """ + )) + test.run(arguments = "-Q -s", status=0, stdout=None) + + cache_arg = test.stdout().strip() + + if default_version.msvc_verstr == '14.0': + # VS2015: target_arch msvc_sdk_version + expect = r'^SCRIPT_ARGS: .* [0-9.]+$' + else: + # VS2017+ msvc_sdk_version msvc_toolset_version + expect = r'^SCRIPT_ARGS: [0-9.]+ -vcvars_ver=[0-9.]+$' + + test.must_contain_all(cache_arg, expect, find=TestSCons.match_re) + diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/foo.cpp scons-4.4.0+dfsg/test/MSVC/msvc_fixture/foo.cpp --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/foo.cpp 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/foo.cpp 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +#include "StdAfx.h" \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/resource.h scons-4.4.0+dfsg/test/MSVC/msvc_fixture/resource.h --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/resource.h 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/resource.h 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +#define IDS_TEST 2001 diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/SConstruct scons-4.4.0+dfsg/test/MSVC/msvc_fixture/SConstruct --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,14 @@ +# msvc_fixture's SConstruct + +DefaultEnvironment(tools=[]) +# TODO: this is order-dependent (putting 'mssdk' second or third breaks), +# and ideally we shouldn't need to specify the tools= list anyway. +env = Environment(tools=['mssdk', 'msvc', 'mslink']) +env.Append(CCFLAGS='/DPCHDEF') +env['PDB'] = File('test.pdb') +env['PCHSTOP'] = 'StdAfx.h' +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env.Program('test', ['test.cpp', env.RES('test.rc')], LIBS=['user32']) + +env.Object('fast', 'foo.cpp') +env.Object('slow', 'foo.cpp', PCH=0) diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/StdAfx.cpp scons-4.4.0+dfsg/test/MSVC/msvc_fixture/StdAfx.cpp --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/StdAfx.cpp 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/StdAfx.cpp 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,4 @@ +#include "StdAfx.h" +#ifndef PCHDEF +this line generates an error if PCHDEF is not defined! +#endif \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/StdAfx.h scons-4.4.0+dfsg/test/MSVC/msvc_fixture/StdAfx.h --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/StdAfx.h 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/StdAfx.h 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +#include +#include +#include "resource.h" \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/test.cpp scons-4.4.0+dfsg/test/MSVC/msvc_fixture/test.cpp --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/test.cpp 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,10 @@ +#include "StdAfx.h" +#include "resource.h" + +int main(void) +{ + char test[1024]; + LoadString(GetModuleHandle(NULL), IDS_TEST, test, sizeof(test)); + printf("%d %s\n", IDS_TEST, test); + return 0; +} \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc_fixture/test.rc scons-4.4.0+dfsg/test/MSVC/msvc_fixture/test.rc --- scons-4.0.1+dfsg/test/MSVC/msvc_fixture/test.rc 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc_fixture/test.rc 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +#include "resource.h" + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TEST "test 1" +END diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_NOTFOUND_POLICY.py scons-4.4.0+dfsg/test/MSVC/MSVC_NOTFOUND_POLICY.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_NOTFOUND_POLICY.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_NOTFOUND_POLICY.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,126 @@ +# 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. + +""" +Test the MSVC_NOTFOUND_POLICY construction variable and functions. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +import textwrap + +# Test construction variable with valid symbols +test.write('SConstruct', textwrap.dedent( + """ + env_list = [] + DefaultEnvironment(tools=[]) + for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']: + for policy in [symbol, symbol.upper(), symbol.lower()]: + env = Environment(MSVC_NOTFOUND_POLICY=policy, tools=['msvc']) + env_list.append(env) + """ +)) +test.run(arguments='-Q -s', stdout='') + +# Test construction variable with invalid symbol +test.write('SConstruct', textwrap.dedent( + """ + env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Undefined', tools=['msvc']) + """ +)) +test.run(arguments='-Q -s', status=2, stderr=None) +expect = "MSVCArgumentError: Value specified for MSVC_NOTFOUND_POLICY is not supported: 'Undefined'." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with global policy +test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_notfound_policy + msvc_set_notfound_policy('Exception') + env = Environment(MSVC_VERSION='12.9', tools=['msvc']) + """ +)) +test.run(arguments='-Q -s', status=2, stderr=None) +expect = "MSVCVersionNotFound: MSVC version '12.9' was not found." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with global policy and construction variable ignored +test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_notfound_policy + msvc_set_notfound_policy('Exception') + env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY=None, tools=['msvc']) + """ +)) +test.run(arguments='-Q -s', status=2, stderr=None) +expect = "MSVCVersionNotFound: MSVC version '12.9' was not found." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with construction variable +test.write('SConstruct', textwrap.dedent( + """ + env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Error', tools=['msvc']) + """ +)) +test.run(arguments='-Q -s', status=2, stderr=None) +expect = "MSVCVersionNotFound: MSVC version '12.9' was not found." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with global policy +test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_notfound_policy + msvc_set_notfound_policy('Warning') + env = Environment(MSVC_VERSION='12.9', tools=['msvc']) + """ +)) +test.run(arguments="-Q -s --warn=visual-c-missing .", status=0, stderr=None) +expect = "scons: warning: MSVC version '12.9' was not found." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with construction variable +test.write('SConstruct', textwrap.dedent( + """ + env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Warning', tools=['msvc']) + """ +)) +test.run(arguments="-Q -s --warn=visual-c-missing .", status=0, stderr=None) +expect = "scons: warning: MSVC version '12.9' was not found." +test.must_contain_all(test.stderr(), expect) + +# Test environment construction with construction variable (override global) +test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_notfound_policy + msvc_set_notfound_policy('Exception') + env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Ignore', tools=['msvc']) + """ +)) +test.run(arguments='-Q -s', stdout='') + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/msvc.py scons-4.4.0+dfsg/test/MSVC/msvc.py --- scons-4.0.1+dfsg/test/MSVC/msvc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/msvc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -26,7 +28,6 @@ of a precompiled header with the $CCFLAGS variable. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import time @@ -36,71 +37,11 @@ test.skip_if_not_msvc() +test.dir_fixture('msvc_fixture') + ##### # Test the basics -test.write('SConstruct',""" -import os -DefaultEnvironment(tools=[]) -# TODO: this is order-dependent (putting 'mssdk' second or third breaks), -# and ideally we shouldn't need to specify the tools= list anyway. -env = Environment(tools=['mssdk', 'msvc', 'mslink']) -env.Append(CPPPATH=os.environ.get('INCLUDE', ''), - LIBPATH=os.environ.get('LIB', ''), - CCFLAGS='/DPCHDEF') -env['PDB'] = File('test.pdb') -env['PCHSTOP'] = 'StdAfx.h' -env['PCH'] = env.PCH('StdAfx.cpp')[0] -env.Program('test', ['test.cpp', env.RES('test.rc')], LIBS=['user32']) - -env.Object('fast', 'foo.cpp') -env.Object('slow', 'foo.cpp', PCH=0) -""") - -test.write('test.cpp', ''' -#include "StdAfx.h" -#include "resource.h" - -int main(void) -{ - char test[1024]; - LoadString(GetModuleHandle(NULL), IDS_TEST, test, sizeof(test)); - printf("%d %s\\n", IDS_TEST, test); - return 0; -} -''') - -test.write('test.rc', ''' -#include "resource.h" - -STRINGTABLE DISCARDABLE -BEGIN - IDS_TEST "test 1" -END -''') - -test.write('resource.h', ''' -#define IDS_TEST 2001 -''') - - -test.write('foo.cpp', ''' -#include "StdAfx.h" -''') - -test.write('StdAfx.h', ''' -#include -#include -#include "resource.h" -''') - -test.write('StdAfx.cpp', ''' -#include "StdAfx.h" -#ifndef PCHDEF -this line generates an error if PCHDEF is not defined! -#endif -''') - # Visual Studio 8 has deprecated the /Yd option and prints warnings # about it, so ignore stderr when running SCons. @@ -170,13 +111,13 @@ test.must_exist(test.workpath('test.obj')) -start = time.time() +start = time.perf_counter() test.run(arguments='fast.obj', stderr=None) -fast = time.time() - start +fast = time.perf_counter() - start -start = time.time() +start = time.perf_counter() test.run(arguments='slow.obj', stderr=None) -slow = time.time() - start +slow = time.perf_counter() - start # TODO: Reevaluate if having this part of the test makes sense any longer diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_SCRIPTERROR_POLICY.py scons-4.4.0+dfsg/test/MSVC/MSVC_SCRIPTERROR_POLICY.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_SCRIPTERROR_POLICY.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_SCRIPTERROR_POLICY.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,141 @@ +# 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. + +""" +Test the MSVC_SCRIPTERROR_POLICY construction variable and functions. +""" + +import TestSCons +import textwrap + +from SCons.Tool.MSCommon.vc import get_installed_vcs_components + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +installed_versions = get_installed_vcs_components() + +default_version = installed_versions[0] + +# Test construction variable with valid symbols +test.write('SConstruct', textwrap.dedent( + """ + env_list = [] + DefaultEnvironment(tools=[]) + for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']: + for policy in [symbol, symbol.upper(), symbol.lower()]: + env = Environment(MSVC_SCRIPTERROR_POLICY=policy, tools=['msvc']) + env_list.append(env) + """ +)) +test.run(arguments='-Q -s', stdout='') + +if default_version.msvc_vernum >= 14.1: + # Need VS2017 or later for MSVC_SCRIPT_ARGS + + # Test environment construction with construction variable (invalid) + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Undefined', tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: Value specified for MSVC_SCRIPTERROR_POLICY is not supported: 'Undefined'." + test.must_contain_all(test.stderr(), expect) + + # Test environment construction with construction variable (override global) + test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_scripterror_policy + DefaultEnvironment(tools=[]) + msvc_set_scripterror_policy('Exception') + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Ignore', tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', stdout='') + + # Test environment construction with global policy + test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_scripterror_policy + DefaultEnvironment(tools=[]) + msvc_set_scripterror_policy('Exception') + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCScriptExecutionError: vc script errors detected:" + test.must_contain_all(test.stderr(), expect) + + # Test environment construction with global policy and construction variable ignored + test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_scripterror_policy + DefaultEnvironment(tools=[]) + msvc_set_scripterror_policy('Exception') + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY=None, tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCScriptExecutionError: vc script errors detected:" + test.must_contain_all(test.stderr(), expect) + + # Test environment construction with construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Error', tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCScriptExecutionError: vc script errors detected:" + test.must_contain_all(test.stderr(), expect) + + # Test environment construction with global policy + test.write('SConstruct', textwrap.dedent( + """ + from SCons.Tool.MSCommon import msvc_set_scripterror_policy + DefaultEnvironment(tools=[]) + msvc_set_scripterror_policy('Warning') + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=0, stderr=None) + expect = "scons: warning: vc script errors detected:" + test.must_contain_all(test.stderr(), expect) + + # Test environment construction with construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Warning', tools=['msvc']) + """ + )) + test.run(arguments='-Q -s', status=0, stderr=None) + expect = "scons: warning: vc script errors detected:" + test.must_contain_all(test.stderr(), expect) + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_SDK_VERSION.py scons-4.4.0+dfsg/test/MSVC/MSVC_SDK_VERSION.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_SDK_VERSION.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_SDK_VERSION.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,241 @@ +# 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. + +""" +Test the MSVC_SDK_VERSION construction variable. +""" +import textwrap + +from SCons.Tool.MSCommon.vc import get_installed_vcs_components +from SCons.Tool.MSCommon import msvc_sdk_versions +from SCons.Tool.MSCommon import msvc_toolset_versions +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + + +installed_versions = get_installed_vcs_components() + +default_version = installed_versions[0] + +GE_VS2015_versions = [v for v in installed_versions if v.msvc_vernum >= 14.0] +LT_VS2015_versions = [v for v in installed_versions if v.msvc_vernum < 14.0] + +default_sdk_versions_uwp = msvc_sdk_versions(version=None, msvc_uwp_app=True) +default_sdk_versions_def = msvc_sdk_versions(version=None, msvc_uwp_app=False) + +have_140 = any([v.msvc_verstr == '14.0' for v in GE_VS2015_versions]) + +def version_major(version): + components = version.split('.') + if len(components) >= 2: + return components[0] + '.' + components[1][0] + if len(components) == 1: + return components[0] + '.0' + return version + +def version_major_list(version_list): + versions = [] + seen_major = set() + for version in version_list: + major = version_major(version) + if major in seen_major: + continue + versions.append(version) + seen_major.add(major) + return versions + +if GE_VS2015_versions: + + for supported in GE_VS2015_versions: + + sdk_versions_uwp = msvc_sdk_versions(version=supported.msvc_version, msvc_uwp_app=True) + sdk_versions_def = msvc_sdk_versions(version=supported.msvc_version, msvc_uwp_app=False) + + # find sdk version for each major SDK + sdk_versions = version_major_list(sdk_versions_def) + + for sdk_version in sdk_versions: + + # sdk version construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={0}, MSVC_SDK_VERSION={1}, tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\{2}\\\\' not in lib_path: + raise RuntimeError("{1} not found in lib path " + lib_path) + """.format(repr(supported.msvc_version), repr(sdk_version), sdk_version) + )) + test.run(arguments='-Q -s', stdout='') + + # sdk version script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={0}, MSVC_SCRIPT_ARGS={1}, tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\{2}\\\\' not in lib_path: + raise RuntimeError("{1} not found in lib path " + lib_path) + """.format(repr(supported.msvc_version), repr(sdk_version), sdk_version) + )) + test.run(arguments='-Q -s', stdout='') + + # sdk version construction variable and script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, MSVC_SCRIPT_ARGS={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(sdk_version), repr(sdk_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}:".format( + repr(sdk_version), repr(sdk_version) + ) + test.must_contain_all(test.stderr(), expect) + + # sdk version is not supported + invalid_sdk_version = '9.1' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(invalid_sdk_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SDK_VERSION ({}) is not supported:".format( + repr(invalid_sdk_version) + ) + test.must_contain_all(test.stderr(), expect) + + # sdk version not found + missing_sdk_version = '10.0.12345.6' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(missing_sdk_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCSDKVersionNotFound: MSVC_SDK_VERSION {} not found for platform type 'Desktop':".format( + repr(missing_sdk_version) + ) + test.must_contain_all(test.stderr(), expect) + + # platform contraints: 8.1 and UWP + if '8.1' in sdk_versions: + + if supported.msvc_vernum > 14.0: + + toolset_full_versions = msvc_toolset_versions(supported.msvc_version, full=True, sxs=False) + toolset_versions = version_major_list(toolset_full_versions) + + # toolset msvc_version != current msvc_version and toolset msvc_version != 14.0 + toolset_candidates = [v for v in toolset_versions if version_major(v) not in (supported.msvc_verstr, '14.0')] + toolset_version = toolset_candidates[0] if toolset_candidates else None + + # sdk version 8.1, UWP, and msvc_verson > VS2015 + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SDK_VERSION ('8.1') and platform type ('UWP') constraint violation: MSVC_VERSION {} > '14.0' VS2015:".format( + repr(supported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + + if toolset_version: + + # sdk version 8.1, UWP, and msvc_toolset_verson > VS2015 + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SDK_VERSION ('8.1') and platform type ('UWP') constraint violation: toolset version {} > '14.0' VS2015:".format( + repr(toolset_version) + ) + test.must_contain_all(test.stderr(), expect) + + if have_140: + + # sdk version 8.1, UWP, and msvc_toolset_version > VS2015 + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_TOOLSET_VERSION='14.0', MSVC_UWP_APP=True, tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout='') + + elif supported.msvc_vernum == 14.0: + + # sdk version 8.1, UWP, and msvc_verson == VS2015 + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout='') + +if LT_VS2015_versions: + + for unsupported in LT_VS2015_versions: + # must be VS2015 or later + + sdk_version = default_sdk_versions_def[0] if default_sdk_versions_def else '8.1' + + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc']) + """.format(repr(unsupported.msvc_version), repr(sdk_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format( + repr(sdk_version), repr(unsupported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS={}, tools=['msvc']) + """.format(repr(unsupported.msvc_version), repr(sdk_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format( + repr(sdk_version), repr(unsupported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_SPECTRE_LIBS.py scons-4.4.0+dfsg/test/MSVC/MSVC_SPECTRE_LIBS.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_SPECTRE_LIBS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_SPECTRE_LIBS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,152 @@ +# 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. + +""" +Test the MSVC_SPECTRE_LIBS construction variable. +""" + +import TestSCons +import textwrap + +from SCons.Tool.MSCommon.vc import get_installed_vcs_components +from SCons.Tool.MSCommon import msvc_toolset_versions_spectre + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +installed_versions = get_installed_vcs_components() + +GE_VS2017_versions = [v for v in installed_versions if v.msvc_vernum >= 14.1] +LT_VS2017_versions = [v for v in installed_versions if v.msvc_vernum < 14.1] + +if GE_VS2017_versions: + # VS2017 and later for toolset argument + + for supported in GE_VS2017_versions: + + spectre_toolset_versions = msvc_toolset_versions_spectre(supported.msvc_version) + spectre_toolset_version = spectre_toolset_versions[0] if spectre_toolset_versions else None + + if spectre_toolset_version: + + # spectre libs using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS=True, tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\lib\\\\spectre\\\\' not in lib_path.lower(): + raise RuntimeError("'spectre' not found in lib path " + lib_path) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout='') + + # spectre libs using script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_spectre_libs=spectre', tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\lib\\\\spectre\\\\' not in lib_path.lower(): + raise RuntimeError("'spectre' not found in lib path " + lib_path) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout='') + + # error construction variable and script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS=True, MSVC_SCRIPT_ARGS='-vcvars_spectre_libs=spectre', tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: multiple spectre declarations: MSVC_SPECTRE_LIBS=True and MSVC_SCRIPT_ARGS='-vcvars_spectre_libs=spectre':" + test.must_contain_all(test.stderr(), expect) + + else: + + # spectre libs using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS=True, tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + if not test.stderr().strip().startswith('MSVCSpectreLibsNotFound: Spectre libraries not found'): + test.fail_test() + + # spectre libs using script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_spectre_libs=spectre', MSVC_SCRIPTERROR_POLICY='error', tools=['msvc']) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + if not test.stderr().strip().startswith('MSVCScriptExecutionError: vc script errors detected:'): + test.fail_test() + + # spectre libs using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS=False, tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\lib\\\\spectre\\\\' in lib_path.lower(): + raise RuntimeError("'spectre' found in lib path " + lib_path) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout='') + +if LT_VS2017_versions: + # VS2015 and earlier for toolset argument error + + for unsupported in LT_VS2017_versions: + + # must be VS2017 or later + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS=True, tools=['msvc']) + """.format(repr(unsupported.msvc_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + if not test.stderr().strip().startswith('MSVCArgumentError: MSVC_SPECTRE_LIBS (True) constraint violation:'): + test.fail_test() + + for disabled in (False, None): + + # ignore + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SPECTRE_LIBS={}, tools=['msvc']) + """.format(repr(unsupported.msvc_version), disabled) + )) + test.run(arguments='-Q -s', stdout='') + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_TOOLSET_VERSION.py scons-4.4.0+dfsg/test/MSVC/MSVC_TOOLSET_VERSION.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_TOOLSET_VERSION.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_TOOLSET_VERSION.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,233 @@ +# 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. + +""" +Test the MSVC_TOOLSET_VERSION construction variable. +""" +import textwrap + +from SCons.Tool.MSCommon.vc import get_installed_vcs_components +from SCons.Tool.MSCommon import msvc_toolset_versions + +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +installed_versions = get_installed_vcs_components() + +default_version = installed_versions[0] + +GE_VS2017_versions = [v for v in installed_versions if v.msvc_vernum >= 14.1] +LT_VS2017_versions = [v for v in installed_versions if v.msvc_vernum < 14.1] +LT_VS2015_versions = [v for v in LT_VS2017_versions if v.msvc_vernum < 14.0] + +if GE_VS2017_versions: + # VS2017 and later for toolset argument + + for supported in GE_VS2017_versions: + + toolset_full_versions = msvc_toolset_versions(supported.msvc_version, full=True, sxs=False) + toolset_full_version = toolset_full_versions[0] if toolset_full_versions else None + + toolset_sxs_versions = msvc_toolset_versions(supported.msvc_version, full=False, sxs=True) + toolset_sxs_version = toolset_sxs_versions[0] if toolset_sxs_versions else None + + if toolset_full_version: + + # toolset version using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={0}, MSVC_TOOLSET_VERSION={1}, tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\{2}\\\\' not in lib_path: + raise RuntimeError("{1} not found in lib path " + lib_path) + """.format(repr(supported.msvc_version), repr(toolset_full_version), toolset_full_version) + )) + test.run(arguments='-Q -s', stdout='') + + # toolset version using script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={0}, MSVC_SCRIPT_ARGS='-vcvars_ver={1}', tools=['msvc']) + lib_path = env['ENV']['LIB'] + if '\\\\{1}\\\\' not in lib_path: + raise RuntimeError("'{1}' not found in lib path " + lib_path) + """.format(repr(supported.msvc_version), toolset_full_version) + )) + test.run(arguments='-Q -s', stdout='') + + if toolset_sxs_version: + + # sxs toolset version using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(toolset_sxs_version)) + )) + test.run(arguments='-Q -s', stdout='') + + # msvc_version as toolset version + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(supported.msvc_verstr)) + )) + test.run(arguments='-Q -s', stdout='') + + # msvc_version as toolset version using script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc']) + """.format(repr(supported.msvc_version), supported.msvc_verstr) + )) + test.run(arguments='-Q -s', stdout='') + + # error toolset version and script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc']) + """.format(repr(supported.msvc_version), repr(supported.msvc_verstr), supported.msvc_verstr) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS='-vcvars_ver={}':".format( + repr(supported.msvc_verstr), supported.msvc_verstr + ) + test.must_contain_all(test.stderr(), expect) + + # msvc_toolset_version does not exist (hopefully) + missing_toolset_version = supported.msvc_verstr + '9.99999' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(missing_toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCToolsetVersionNotFound: MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}:".format( + repr(missing_toolset_version), repr(supported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + + # msvc_toolset_version is invalid (format) + invalid_toolset_version = supported.msvc_verstr + '9.99999.99999' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(invalid_toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) format is not supported:".format( + repr(invalid_toolset_version) + ) + test.must_contain_all(test.stderr(), expect) + + # msvc_toolset_version is invalid (version greater than msvc version) + invalid_toolset_vernum = round(supported.msvc_vernum + 0.1, 1) + invalid_toolset_version = str(invalid_toolset_vernum) + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(invalid_toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION:".format( + repr(invalid_toolset_version), repr(invalid_toolset_version), repr(supported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + + # msvc_toolset_version is invalid (version less than 14.0) + invalid_toolset_version = '12.0' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(invalid_toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < '14.0' VS2015:".format( + repr(invalid_toolset_version), repr(invalid_toolset_version) + ) + test.must_contain_all(test.stderr(), expect) + + # 14.0 toolset is invalid (toolset version != 14.0) + invalid_toolset_version = '14.00.00001' + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(supported.msvc_version), repr(invalid_toolset_version)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0':".format( + repr(invalid_toolset_version), repr(invalid_toolset_version) + ) + test.must_contain_all(test.stderr(), expect) + +if LT_VS2017_versions: + # VS2015 and earlier for toolset argument error + + for unsupported in LT_VS2017_versions: + + # must be VS2017 or later + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc']) + """.format(repr(unsupported.msvc_version), repr(unsupported.msvc_verstr)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < '14.1' VS2017:".format( + repr(unsupported.msvc_verstr), repr(unsupported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + +if LT_VS2015_versions: + # VS2013 and earlier for script argument error + + for unsupported in LT_VS2015_versions: + + # must be VS2015 or later for MSVC_SCRIPT_ARGS + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc']) + """.format(repr(unsupported.msvc_version), unsupported.msvc_verstr) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + expect = "MSVCArgumentError: MSVC_SCRIPT_ARGS ('-vcvars_ver={}') constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format( + unsupported.msvc_verstr, repr(unsupported.msvc_version) + ) + test.must_contain_all(test.stderr(), expect) + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/fake_script.bat scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/fake_script.bat --- scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/fake_script.bat 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/fake_script.bat 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +@echo off +REM Fake msvc batch script for use in testing MSVC_USE_SCRIPT_ARGS +echo ARG1: %1 ARG2: %2 diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/SConstruct scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/SConstruct --- scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS-fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,9 @@ +import os + +if 'SCONS_CACHE_MSVC_CONFIG' in os.environ: + del os.environ['SCONS_CACHE_MSVC_CONFIG'] + +os.environ['SCONS_MSCOMMON_DEBUG']='MSDEBUG_OUTPUT.log' + +DefaultEnvironment(tools=[]) +env = Environment(tools=['msvc'], MSVC_USE_SCRIPT='fake_script.bat', MSVC_USE_SCRIPT_ARGS=['one','two']) diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS.py scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT_ARGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +# 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. + +""" +Test the $MSVC_USE_SCRIPT construction variable. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() +test.dir_fixture('MSVC_USE_SCRIPT_ARGS-fixture') + +test.run(arguments = ".", status=0, stderr=None) + +test.must_contain('MSDEBUG_OUTPUT.log', "Calling 'fake_script.bat one two'") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT.py scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SCRIPT.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SCRIPT.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,50 @@ +# 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. + +""" +Test the $MSVC_USE_SCRIPT construction variable. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +test.write('SConstruct', """ +env = Environment(tools=['msvc'], MSVC_USE_SCRIPT='nosuchscriptexists') +""" % locals()) + +test.run(arguments = ".", status=2, stderr=None) + +test.must_contain_all(test.stderr(), "Script specified by MSVC_USE_SCRIPT not found") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SETTINGS.py scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SETTINGS.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_USE_SETTINGS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_USE_SETTINGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,76 @@ +# 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. + +""" +Test the $MSVC_USE_SETTINGS construction variable. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +test.write('SConstruct', """ +e1 = Environment() +cl1 = e1.WhereIs('cl.exe') + +e2 = Environment(tools=[]) + +d = {key: e1['ENV'][key] for key in e1['ENV'].keys() if key not in e2['ENV'] or e1['ENV'][key] != e2['ENV'][key]} +e3 = Environment(MSVC_USE_SETTINGS=d) +cl3 = e3.WhereIs('cl.exe') + +if cl1 == cl3: + print("CL.EXE PATHS MATCH") +""" % locals()) + +test.run(arguments = ".", status=0, stderr=None) + +test.must_contain_all(test.stdout(), "CL.EXE PATHS MATCH") + +test.write('SConstruct', """ +env = Environment(MSVC_USE_SETTINGS={}) +""" % locals()) + +test.run(arguments = "--warn=visual-c-missing .", status=0, stderr=None) + +test.must_contain_all(test.stderr(), "Could not find MSVC compiler 'cl'") + +test.write('SConstruct', """ +env = Environment(MSVC_USE_SETTINGS='dict or None') +""" % locals()) + +test.run(arguments = ".", status=2, stderr=None) + +test.must_contain_all(test.stderr(), "MSVCUseSettingsError: MSVC_USE_SETTINGS type error") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/MSVC_UWP_APP.py scons-4.4.0+dfsg/test/MSVC/MSVC_UWP_APP.py --- scons-4.0.1+dfsg/test/MSVC/MSVC_UWP_APP.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/MSVC_UWP_APP.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,6 @@ -#!/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 @@ -20,172 +20,148 @@ # 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 the ability to configure the $MSVC_UWP_APP construction variable with -the desired effect. +Test the MSVC_UWP_APP construction variable. """ +import textwrap +import re +from SCons.Tool.MSCommon.vc import get_installed_vcs_components import TestSCons -import SCons.Tool.MSCommon.vc as msvc -from SCons.Tool.MSCommon.vc import get_msvc_version_numeric -def AreVCStoreLibPathsInLIBPATH(output): - libpath = None - msvc_version = None - UWP_APP = None - lines = output.splitlines() - for line in lines: - if 'env[ENV][LIBPATH]=' in line: - libpath = line.split('=')[1] - elif 'env[MSVC_VERSION]=' in line: - msvc_version = line.split('=')[1] - elif 'env[ENV][VSCMD_ARG_app_plat]=' in line: - UWP_APP = line.split('=')[1] - - if not libpath or not msvc_version: - # Couldn't find the libpath or msvc version in the output - return (False, False, None) - - libpaths = libpath.lower().split(';') - msvc_num = float(get_msvc_version_numeric(msvc_version)) - - (vclibstore_path_present, vclibstorerefs_path_present) = (False, False) - for path in libpaths: - # Look for the Store VC Lib paths in the LIBPATH: - # [VS install path]\VC\LIB\store[\arch] and - # [VS install path]\VC\LIB\store\references - # For example, - # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\amd64 - # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\references - - if msvc_num <= 14: - if r'vc\lib\store\references' in path: - vclibstorerefs_path_present = True - elif r'vc\lib\store' in path: - vclibstore_path_present = True - elif msvc_num > 14: - if UWP_APP == "UWP": - if(r'\lib\x86\store\references' in path - or r'\lib\x64\store' in path): - vclibstorerefs_path_present = True - vclibstore_path_present = True +test = TestSCons.TestSCons() - return (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) +test.skip_if_not_msvc() -_python_ = TestSCons._python_ -test = TestSCons.TestSCons() +installed_versions = get_installed_vcs_components() -test.skip_if_not_msvc() +GE_VS2015_versions = [v for v in installed_versions if v.msvc_vernum >= 14.0] +LT_VS2015_versions = [v for v in installed_versions if v.msvc_vernum < 14.0] -installed_msvc_versions = msvc.cached_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 - -msvc_140 = '14.0' in installed_msvc_versions -msvc_141 = '14.1' in installed_msvc_versions -msvc_142 = '14.2' in installed_msvc_versions - -if not any((msvc_140, msvc_141, msvc_142)): - test.skip_test("Available MSVC doesn't support App store\n") - -if msvc_140: - test.write('SConstruct', """\ -if ARGUMENTS.get('MSVC_UWP_APP'): - help_vars = Variables() - help_vars.Add(EnumVariable( - 'MSVC_UWP_APP', - 'Build a Universal Windows Platform (UWP) Application', - '0', - allowed_values=('0', '1'))) -else: - help_vars = None -env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.0') -# Print the ENV LIBPATH to stdout -print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH')) -print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION')) -""") - - # Test setting MSVC_UWP_APP is '1' (True) - test.run(arguments = "MSVC_UWP_APP=1") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is False) or (vclibstorerefs_path_present is False), - message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version) - - # Test setting MSVC_UWP_APP is '0' (False) - test.run(arguments = "MSVC_UWP_APP=0") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True), - message='VC Store LIBPATHs present when MSVC_UWP_APP=0 (msvc_version=%s)' % msvc_version) - - # Test not setting MSVC_UWP_APP - test.run(arguments = "") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True), - message='VC Store LIBPATHs present when MSVC_UWP_APP not set (msvc_version=%s)' % msvc_version) - -if msvc_141 or msvc_142: - if msvc_142: - test.write('SConstruct', """\ -if ARGUMENTS.get('MSVC_UWP_APP'): - help_vars = Variables() - help_vars.Add(EnumVariable( - 'MSVC_UWP_APP', - 'Build a Universal Windows Platform (UWP) Application', - '0', - allowed_values=('0', '1'))) -else: - help_vars = None -env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.2') -# Print the ENV LIBPATH to stdout -print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH')) -print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION')) -print('env[ENV][VSCMD_ARG_app_plat]=%s' % env.get('ENV').get('VSCMD_ARG_app_plat')) -""") - elif msvc_141: - test.write('SConstruct', """\ -if ARGUMENTS.get('MSVC_UWP_APP'): - help_vars = Variables() - help_vars.Add(EnumVariable( - 'MSVC_UWP_APP', - 'Build a Universal Windows Platform (UWP) Application', - '0', - allowed_values=('0', '1'))) -else: - help_vars = None -env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.1') -# Print the ENV LIBPATH to stdout -print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH')) -print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION')) -print('env[ENV][VSCMD_ARG_app_plat]=%s' % env.get('ENV').get('VSCMD_ARG_app_plat')) -""") - - # Test setting MSVC_UWP_APP is '1' (True) - test.run(arguments = "MSVC_UWP_APP=1") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is False) or (vclibstorerefs_path_present is False), - message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version) - - # Test setting MSVC_UWP_APP is '0' (False) - test.run(arguments = "MSVC_UWP_APP=0") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True), - message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version) - - # Test not setting MSVC_UWP_APP - test.run(arguments = "") - (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout()) - test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True), - message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version) +# Look for the Store VC Lib paths in the LIBPATH: +# [VS install path]\VC\LIB\store[\arch] and +# [VS install path]\VC\LIB\store\references +# For example, +# C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\amd64 +# C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\references + +re_lib_eq2015_1 = re.compile(r'\\vc\\lib\\store\\references', re.IGNORECASE) +re_lib_eq2015_2 = re.compile(r'\\vc\\lib\\store', re.IGNORECASE) + +re_lib_ge2017_1 = re.compile(r'\\lib\\x86\\store\\references', re.IGNORECASE) +re_lib_ge2017_2 = re.compile(r'\\lib\\x64\\store', re.IGNORECASE) + + +def check_libpath(msvc, active, output): + + def _check_libpath(msvc, output): + outdict = {key.strip(): val.strip() for key, val in [line.split('|') for line in output.splitlines()]} + platform = outdict.get('PLATFORM', '') + libpath = outdict.get('LIBPATH', '') + n_matches = 0 + if msvc.msvc_verstr == '14.0': + for regex in (re_lib_eq2015_1, re_lib_eq2015_2): + if regex.search(libpath): + n_matches += 1 + return n_matches >= 2, 'store', libpath + elif platform == 'UWP': + for regex in (re_lib_ge2017_1, re_lib_ge2017_2): + if regex.search(libpath): + n_matches += 1 + return n_matches > 0, 'uwp', libpath + return False, 'uwp', libpath + + found, kind, libpath = _check_libpath(msvc, output) + + failmsg = None + + if active and not found: + failmsg = 'msvc version {} {} paths not found in lib path {}'.format( + repr(msvc.msvc_version), repr(kind), repr(libpath) + ) + elif not active and found: + failmsg = 'msvc version {} {} paths found in lib path {}'.format( + repr(msvc.msvc_version), repr(kind), repr(libpath) + ) + + return failmsg + +if GE_VS2015_versions: + # VS2015 and later for uwp/store argument + + for supported in GE_VS2015_versions: + + for msvc_uwp_app in (True, '1', False, '0', None): + + active = msvc_uwp_app in (True, '1') + + # uwp using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_UWP_APP={}, tools=['msvc']) + print('LIBPATH|' + env['ENV'].get('LIBPATH', '')) + print('PLATFORM|' + env['ENV'].get('VSCMD_ARG_app_plat','')) + """.format(repr(supported.msvc_version), repr(msvc_uwp_app)) + )) + test.run(arguments='-Q -s', stdout=None) + failmsg = check_libpath(supported, active, test.stdout()) + if failmsg: + test.fail_test(message=failmsg) + + if not active: + continue + + # error construction variable and script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_UWP_APP={}, MSVC_SCRIPT_ARGS='store', tools=['msvc']) + """.format(repr(supported.msvc_version), repr(msvc_uwp_app)) + )) + test.run(arguments='-Q -s', status=2, stderr=None) + if not test.stderr().strip().startswith("MSVCArgumentError: multiple uwp declarations:"): + test.fail_test(message='Expected MSVCArgumentError') + + # uwp using script argument + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='store', tools=['msvc']) + print('LIBPATH|' + env['ENV'].get('LIBPATH', '')) + print('PLATFORM|' + env['ENV'].get('VSCMD_ARG_app_plat','')) + """.format(repr(supported.msvc_version)) + )) + test.run(arguments='-Q -s', stdout=None) + failmsg = check_libpath(supported, True, test.stdout()) + if failmsg: + test.fail_test(message=failmsg) + +if LT_VS2015_versions: + # VS2013 and earlier for uwp/store error + + for unsupported in LT_VS2015_versions: + + for msvc_uwp_app in (True, '1', False, '0', None): + + active = msvc_uwp_app in (True, '1') + + # uwp using construction variable + test.write('SConstruct', textwrap.dedent( + """ + DefaultEnvironment(tools=[]) + env = Environment(MSVC_VERSION={0}, MSVC_UWP_APP={1}, tools=['msvc']) + """.format(repr(unsupported.msvc_version), repr(msvc_uwp_app)) + )) + if not active: + test.run(arguments='-Q -s', stdout=None) + else: + test.run(arguments='-Q -s', status=2, stderr=None) + expect = 'MSVCArgumentError: MSVC_UWP_APP ({}) constraint violation:'.format(repr(msvc_uwp_app)) + if not test.stderr().strip().startswith(expect): + test.fail_test(message='Expected MSVCArgumentError') test.pass_test() -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/no_msvc.py scons-4.4.0+dfsg/test/MSVC/no_msvc.py --- scons-4.0.1+dfsg/test/MSVC/no_msvc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/no_msvc.py 2022-07-30 21:48:28.000000000 +0000 @@ -48,4 +48,39 @@ if 'MSVC_VERSION=None' not in test.stdout(): test.fail_test() -test.pass_test() \ No newline at end of file +# test msvc version number request with no msvc's +test.file_fixture('no_msvc/no_msvcs_sconstruct_version.py', 'SConstruct') +test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall) + +# test that MSVCVersionNotFound is not raised for default msvc tools +# when a non-msvc tool list is used +test.subdir('site_scons', ['site_scons', 'site_tools']) + +test.write(['site_scons', 'site_tools', 'myignoredefaultmsvctool.py'], """ +import SCons.Tool +def generate(env): + env['MYIGNOREDEFAULTMSVCTOOL']='myignoredefaultmsvctool' +def exists(env): + return 1 +""") + +test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct') +test.run(arguments='-Q -s') + +# test no msvc's and msvc_sdk_version() call +test.file_fixture('no_msvc/no_msvcs_sconstruct_msvc_sdk_versions.py', 'SConstruct') +test.run(arguments='-Q -s') +test.must_contain_all(test.stdout(), 'sdk_version_list=[]') + +# test no msvc's and msvc_sdk_version() call +test.file_fixture('no_msvc/no_msvcs_sconstruct_msvc_toolset_versions.py', 'SConstruct') +test.run(arguments='-Q -s') +test.must_contain_all(test.stdout(), 'toolset_version_list=[]') + +# test no msvc's and msvc_query_version_toolset() call +test.file_fixture('no_msvc/no_msvcs_sconstruct_msvc_query_toolset_version.py', 'SConstruct') +test.run(arguments='-Q -s') +test.must_contain_all(test.stdout(), 'msvc_version=None, msvc_toolset_version=None') + +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/MSVC/pch-basics.py scons-4.4.0+dfsg/test/MSVC/pch-basics.py --- scons-4.0.1+dfsg/test/MSVC/pch-basics.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/pch-basics.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Verify PCH works to build a simple exe and a simple dll. """ -import time import TestSCons diff -Nru scons-4.0.1+dfsg/test/MSVC/pch_gen/fixture/SConstruct scons-4.4.0+dfsg/test/MSVC/pch_gen/fixture/SConstruct --- scons-4.0.1+dfsg/test/MSVC/pch_gen/fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/pch_gen/fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,53 @@ +# pch_gen fixture's SConstruct + +DefaultEnvironment(tools=[]) +# TODO: this is order-dependent (putting 'mssdk' second or third breaks), +# and ideally we shouldn't need to specify the tools= list anyway. + + +VariantDir('output1','src') +VariantDir('output2','src') + + +# Add flag to cause pch_gen to return empty string +# This will enable testing that PCH if subst'd yields empty string will stop +# PCH from being enabled. +vars = Variables(None, ARGUMENTS) +vars.AddVariables(BoolVariable("DISABLE_PCH", help="Disable PCH functionality", default=False)) + + +env = Environment(variables=vars, tools=["mssdk", "msvc", "mslink"]) +env.Append(CCFLAGS="/DPCHDEF") +env["PDB"] = File("output1/test.pdb") +env["PCHSTOP"] = "StdAfx.h" + + +def pch_gen(env, target, source, for_signature): + if env['DISABLE_PCH']: + return "" + else: + return "StdAfx-1.pch" + + +env["PCH"] = pch_gen +env.PCH("output1/StdAfx-1.pch", "output1/StdAfx.cpp") +env.Program("output1/test", ["output1/test.cpp", env.RES("output1/test.rc")], LIBS=["user32"]) + +env.Object("output1/fast", "output1/foo.cpp") +env.Object("output1/slow", "output1/foo.cpp", PCH=0) + + + +env2 = env.Clone() + +def pch_gen2(env, target, source, for_signature): + if env['DISABLE_PCH']: + return "" + else: + return env.get('PCH_NODE') +env2["PDB"] = File("output2/test.pdb") +env2["PCHSTOP"] = "StdAfx.h" +env2["PCH"] = pch_gen2 +env2['PCH_NODE'] = env2.PCH("output2/StdAfx-1.pch", "output2/StdAfx.cpp")[0] +env2.Program("output2/test", ["output2/test.cpp", env.RES("output2/test.rc")], LIBS=["user32"]) + diff -Nru scons-4.0.1+dfsg/test/MSVC/pch_gen/pch_gen.py scons-4.4.0+dfsg/test/MSVC/pch_gen/pch_gen.py --- scons-4.0.1+dfsg/test/MSVC/pch_gen/pch_gen.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/pch_gen/pch_gen.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# 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. + +""" +Template for end-to-end test file. +Replace this with a description of the test. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +# include all of msvc_fixture's files +test.dir_fixture('../msvc_fixture','src') + +# Then we'll replace the SConstruct with one specific to this test. +test.file_fixture('fixture/SConstruct', + 'SConstruct') + +test.run(arguments='.') + +test.must_exist(test.workpath('output1/test.exe')) +test.must_exist(test.workpath('output1/test.res')) +test.must_exist(test.workpath('output1/test.pdb')) +test.must_exist(test.workpath('output1/StdAfx-1.pch')) +test.must_exist(test.workpath('output1/StdAfx-1.obj')) + +test.run(arguments="-c .") +test.run(arguments="DISABLE_PCH=1 .") + +test.must_exist(test.workpath('output1/test.exe')) +test.must_exist(test.workpath('output1/test.res')) +test.must_exist(test.workpath('output1/test.pdb')) +test.fail_test(condition = ('/Yuoutput1/StdAfx.h' in test.stdout()), message="Shouldn't have output1/YuStdAfx.h in compile line when PCH is disabled") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVC/pch-spaces-subdir.py scons-4.4.0+dfsg/test/MSVC/pch-spaces-subdir.py --- scons-4.0.1+dfsg/test/MSVC/pch-spaces-subdir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/pch-spaces-subdir.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Verify PCH works if variant dir has spaces in its name """ -import time import TestSCons @@ -63,6 +62,7 @@ """) test.write('SConscript', """\ +DefaultEnvironment(tools=[]) env = Environment() env['PCHSTOP'] = 'Precompiled.h' diff -Nru scons-4.0.1+dfsg/test/MSVC/PCHSTOP-errors.py scons-4.4.0+dfsg/test/MSVC/PCHSTOP-errors.py --- scons-4.0.1+dfsg/test/MSVC/PCHSTOP-errors.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVC/PCHSTOP-errors.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ # Test error reporting """ -import re import TestSCons diff -Nru scons-4.0.1+dfsg/test/MSVS/common-prefix.py scons-4.4.0+dfsg/test/MSVS/common-prefix.py --- scons-4.0.1+dfsg/test/MSVS/common-prefix.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/common-prefix.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ solution (.sln) files that look correct. """ -import os import sys import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/MSVS/runfile.py scons-4.4.0+dfsg/test/MSVS/runfile.py --- scons-4.0.1+dfsg/test/MSVS/runfile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/runfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ solution (.sln) files that look correct. """ -import os import sys import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/MSVS/vs-14.3-exec.py scons-4.4.0+dfsg/test/MSVS/vs-14.3-exec.py --- scons-4.0.1+dfsg/test/MSVS/vs-14.3-exec.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/vs-14.3-exec.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,115 @@ +#!/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 that we can actually build a simple program using our generated +Visual Studio 14.0 project (.vcxproj) and solution (.sln) files +using Visual Studio 14.3 +""" + +import os +import sys + +import TestSConsMSVS + +test = TestSConsMSVS.TestSConsMSVS() + +if sys.platform != 'win32': + msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform + test.skip_test(msg) + +msvs_version = '14.3' + +if msvs_version not in test.msvs_versions(): + msg = "Visual Studio %s not installed; skipping test.\n" % msvs_version + test.skip_test(msg) + + + +# Let SCons figure out the Visual Studio environment variables for us and +# print out a statement that we can exec to suck them into our external +# environment so we can execute devenv and really try to build something. + +test.run(arguments = '-n -q -Q -f -', stdin = """\ +env = Environment(tools = ['msvc'], MSVS_VERSION='%(msvs_version)s') +if env.WhereIs('cl'): + print("os.environ.update(%%s)" %% repr(env['ENV'])) +""" % locals()) + +if(test.stdout() == ""): + msg = "Visual Studio %s missing cl.exe; skipping test.\n" % msvs_version + test.skip_test(msg) + +exec(test.stdout()) + + + +test.subdir('sub dir') + +test.write(['sub dir', 'SConstruct'], """\ +env=Environment(MSVS_VERSION = '%(msvs_version)s') + +env.MSVSProject(target = 'foo.vcxproj', + srcs = ['foo.c'], + buildtarget = 'foo.exe', + variant = 'Release', + DebugSettings = {'LocalDebuggerCommandArguments':'echo "" > output.txt'}) +env.Program('foo.c') +""" % locals()) + +test.write(['sub dir', 'foo.c'], r""" +#include +int +main(int argc, char *argv) +{ + printf("foo.c\n"); + exit (0); +} +""") + +test.run(chdir='sub dir', arguments='.') + +test.vcproj_sys_path(test.workpath('sub dir', 'foo.vcxproj')) + +import SCons.Platform.win32 +system_dll_path = os.path.join(SCons.Platform.win32.get_system_root(), 'System32') +os.environ['PATH'] = os.environ['PATH'] + os.pathsep + system_dll_path + +test.run(chdir='sub dir', + program=[test.get_msvs_executable(msvs_version)], + arguments=['foo.sln', '/build', 'Release']) + +test.run(program=test.workpath('sub dir', 'foo'), stdout="foo.c\n") +test.validate_msvs_file(test.workpath('sub dir', 'foo.vcxproj.user')) + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/MSVS/vs-7.0-scc-files.py scons-4.4.0+dfsg/test/MSVS/vs-7.0-scc-files.py --- scons-4.0.1+dfsg/test/MSVS/vs-7.0-scc-files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/vs-7.0-scc-files.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/MSVS/vs-7.0-scc-legacy-files.py scons-4.4.0+dfsg/test/MSVS/vs-7.0-scc-legacy-files.py --- scons-4.0.1+dfsg/test/MSVS/vs-7.0-scc-legacy-files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/vs-7.0-scc-legacy-files.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/MSVS/vs-7.1-scc-files.py scons-4.4.0+dfsg/test/MSVS/vs-7.1-scc-files.py --- scons-4.0.1+dfsg/test/MSVS/vs-7.1-scc-files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/vs-7.1-scc-files.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/MSVS/vs-7.1-scc-legacy-files.py scons-4.4.0+dfsg/test/MSVS/vs-7.1-scc-legacy-files.py --- scons-4.0.1+dfsg/test/MSVS/vs-7.1-scc-legacy-files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/MSVS/vs-7.1-scc-legacy-files.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ solution (.sln) files that contain SCC information and look correct. """ -import os import TestSConsMSVS diff -Nru scons-4.0.1+dfsg/test/multiline.py scons-4.4.0+dfsg/test/multiline.py --- scons-4.0.1+dfsg/test/multiline.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/multiline.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/ninja/build_libraries.py scons-4.4.0+dfsg/test/ninja/build_libraries.py --- scons-4.0.1+dfsg/test/ninja/build_libraries.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/build_libraries.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,106 @@ +#!/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. + +import os + +import TestSCons +from TestCmd import IS_WINDOWS, IS_MACOS +from TestSCons import _exe, _lib, lib_, _dll, dll_ + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find ninja module. Skipping test.\n") + +ninja_binary = test.where_is('ninja') +if not ninja_binary: + test.skip_test("Could not find ninja executable. Skipping test.\n") + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +win32 = ", 'WIN32'" if IS_WINDOWS else "" + +test.write('SConstruct', """ +SetOption('experimental', 'ninja') +DefaultEnvironment(tools=[]) +env = Environment() +env.Tool('ninja') +env['NINJA'] = r"%(ninja_bin)s" + +shared_lib = env.SharedLibrary(target='test_impl', source='test_impl.c', CPPDEFINES=['LIBRARY_BUILD'%(win32)s]) +env.Program(target='test', source='test1.c', LIBS=['test_impl'], LIBPATH=['.'], RPATH='.') +static_obj = env.Object(target='test_impl_static', source='test_impl.c') +static_lib = env.StaticLibrary(target='test_impl_static', source=static_obj) +static_obj = env.Object(target='test_static', source='test1.c') +env.Program(target='test_static', source=static_obj, LIBS=[static_lib], LIBPATH=['.']) +""" % locals()) + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('test'), stdout="library_function") +test.run(program=test.workpath('test_static'), stdout="library_function") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines( + test.stdout(), + [ + ('Removed %stest_impl' % dll_) + _dll, + 'Removed test' + _exe, + ('Removed %stest_impl_static' % lib_) + _lib, + 'Removed test_static' + _exe, + 'Removed build.ninja', + ], +) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('test')) +test.must_not_exist(test.workpath('test_static')) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('test'), stdout="library_function") +test.run(program=test.workpath('test_static'), stdout="library_function") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/command_line_targets.py scons-4.4.0+dfsg/test/ninja/command_line_targets.py --- scons-4.0.1+dfsg/test/ninja/command_line_targets.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/command_line_targets.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,94 @@ +#!/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. +# + +import os + +import TestSCons + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct') + +# generate simple build +test.run(arguments=['out1.txt'], stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt') +test.must_exist([test.workpath('out1.txt')]) +test.must_not_exist([test.workpath('out2.txt')]) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed out1.txt', + 'Removed build.ninja']) + +# generate simple build +test.run(arguments=['out2.txt'], stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain_all(test.stdout(), 'build.ninja -j1 out2.txt') +test.must_not_exist([test.workpath('out1.txt')]) +test.must_exist([test.workpath('out2.txt')]) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed out2.txt', + 'Removed build.ninja']) + +test.run(arguments=['out1.txt', 'out2.txt'], stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt out2.txt') +test.must_exist([test.workpath('out1.txt')]) +test.must_exist([test.workpath('out2.txt')]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/copy_function_command.py scons-4.4.0+dfsg/test/ninja/copy_function_command.py --- scons-4.0.1+dfsg/test/ninja/copy_function_command.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/copy_function_command.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,89 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) +env = Environment() +env.Tool('ninja') +env.Command('foo2.c', ['foo.c'], Copy('$TARGET','$SOURCE')) +env.Program(target = 'foo', source = 'foo2.c') +""") + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('foo'), stdout="foo.c") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed foo2.o', + 'Removed foo2.c', + 'Removed foo' + _exe, + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo')) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('foo'), stdout="foo.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/default_targets.py scons-4.4.0+dfsg/test/ninja/default_targets.py --- scons-4.0.1+dfsg/test/ninja/default_targets.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/default_targets.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,83 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_not_exist([test.workpath('out1.txt')]) +test.must_exist([test.workpath('out2.txt')]) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed out2.txt', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('out1.txt')) +test.must_not_exist(test.workpath('out2.txt')) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_not_exist([test.workpath('out1.txt')]) +test.must_exist(test.workpath('out2.txt')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/force_scons_callback.py scons-4.4.0+dfsg/test/ninja/force_scons_callback.py --- scons-4.0.1+dfsg/test/ninja/force_scons_callback.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/force_scons_callback.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,91 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath( + os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe) +) + +test.dir_fixture("ninja-fixture") + +test.file_fixture( + "ninja_test_sconscripts/sconstruct_force_scons_callback", "SConstruct" +) + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"]) +test.must_contain_all(test.stdout(), "Executing:") +test.must_contain_all(test.stdout(), "ninja%(_exe)s -f" % locals()) +if test.stdout().count("Defer to SCons to build") != 1: + test.fail_test() +test.must_match("out.txt", "foo.c" + os.linesep) +test.must_match("out2.txt", "test2.cpp" + os.linesep) + +# clean build and ninja files +test.run(arguments="-c", stdout=None) +test.must_contain_all_lines( + test.stdout(), ["Removed out.txt", "Removed out2.txt", "Removed build.ninja"] +) + +# only generate the ninja file +test.run(arguments="--disable-execute-ninja", stdout=None) +test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"]) +test.must_not_exist(test.workpath("out.txt")) +test.must_not_exist(test.workpath("out2.txt")) + +# run ninja independently +program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +if test.stdout().count("Defer to SCons to build") != 1: + test.fail_test() +test.must_match("out.txt", "foo.c" + os.linesep) +test.must_match("out2.txt", "test2.cpp" + os.linesep) + +# only generate the ninja file with specific NINJA_SCONS_DAEMON_PORT +test.run(arguments="PORT=9999 --disable-execute-ninja", stdout=None) +# Verify that port # propagates to call to ninja_run_daemon.py +test.must_contain(test.workpath("build.ninja"), "PORT = 9999") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/generate_and_build_cxx.py scons-4.4.0+dfsg/test/ninja/generate_and_build_cxx.py --- scons-4.0.1+dfsg/test/ninja/generate_and_build_cxx.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/generate_and_build_cxx.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,101 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build_cxx', + 'SConstruct') + +# generate simple build +test.run() +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('test2' + _exe), stdout="print_function") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed test2.o', + 'Removed test2', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('test2' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('test2' + _exe), stdout="print_function") + +test.write('test2.hpp', """ +#include +#include + +class Foo +{ +public: + int print_function(); + int print_function2(){ + std::cout << "2"; + return 0; + }; +}; +""") + +# generate simple build +test.run(program=program, stdout=None) +test.run(program=test.workpath('test2' + _exe), stdout="print_function2") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/generate_and_build.py scons-4.4.0+dfsg/test/ninja/generate_and_build.py --- scons-4.0.1+dfsg/test/ninja/generate_and_build.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/generate_and_build.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,86 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build', 'SConstruct') + +# generate simple build +test.run(stdout=None, arguments='NINJA_CMD_ARGS=-v') +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain_all(test.stdout(), ' -j1 -v') +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +# Test multiple args for NINJA_CMD_ARGS +test.run(stdout=None, arguments={'NINJA_CMD_ARGS':"-v -j3"}) +test.must_contain_all(test.stdout(), ' -v -j3') + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed foo.o', + 'Removed foo', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/generated_sources_alias.py scons-4.4.0+dfsg/test/ninja/generated_sources_alias.py --- scons-4.0.1+dfsg/test/ninja/generated_sources_alias.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/generated_sources_alias.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,82 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.BIN_DIR, + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_generated_sources_alias', 'SConstruct') + +for alias_value in [0, 1]: + + # Gen with source alias + test.run(arguments=['--disable-execute-ninja', f'USE_GEN_SOURCE_ALIAS={alias_value}'], stdout=None) + test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) + test.must_not_exist(test.workpath('gen_source' + _exe)) + + # run ninja independently + program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin + test.run(program=program, stdout=None) + test.run(program=test.workpath('gen_source' + _exe), stdout="4") + + # generate simple build + test.run(arguments=[f'USE_GEN_SOURCE_ALIAS={alias_value}'], stdout=None) + test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) + test.must_contain_all(test.stdout(), 'Executing:') + test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) + test.run(program=test.workpath('gen_source' + _exe), stdout="4") + + # clean build and ninja files + test.run(arguments=[f'USE_GEN_SOURCE_ALIAS={alias_value}', '-c'], stdout=None) + test.must_contain_all_lines(test.stdout(), [ + 'Removed generated_header1.htest', + 'Removed generated_header2.htest', + 'Removed generated_header2.c', + 'Removed build.ninja']) + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/generate_source.py scons-4.4.0+dfsg/test/ninja/generate_source.py --- scons-4.0.1+dfsg/test/ninja/generate_source.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/generate_source.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,115 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +shell = '' if IS_WINDOWS else './' + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +prog = env.Program(target = 'generate_source', source = 'generate_source.c') +env.Command('generated_source.c', prog, '%(shell)sgenerate_source%(_exe)s') +env.Program(target = 'generated_source', source = 'generated_source.c') +""" % locals()) + +test.write('generate_source.c', """ +#include + +int main(int argc, char *argv[]) { + FILE *fp; + + fp = fopen("generated_source.c", "w"); + fprintf(fp, "#include \\n"); + fprintf(fp, "#include \\n"); + fprintf(fp, "\\n"); + fprintf(fp, "int\\n"); + fprintf(fp, "main(int argc, char *argv[])\\n"); + fprintf(fp, "{\\n"); + fprintf(fp, " printf(\\"generated_source.c\\");\\n"); + fprintf(fp, " exit (0);\\n"); + fprintf(fp, "}\\n"); + fclose(fp); +} +""") + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('generated_source' + _exe), stdout="generated_source.c") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed generate_source.o', + 'Removed generate_source' + _exe, + 'Removed generated_source.c', + 'Removed generated_source.o', + 'Removed generated_source' + _exe, + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('generated_source' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('generated_source' + _exe), stdout="generated_source.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/iterative_speedup.py scons-4.4.0+dfsg/test/ninja/iterative_speedup.py --- scons-4.0.1+dfsg/test/ninja/iterative_speedup.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/iterative_speedup.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,246 @@ +#!/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. +# + +import os +import random +import time + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.write('source_0.c', """ +#include +#include +#include "source_0.h" + +int +print_function0() +{ + printf("main print"); + return 0; +} +""") + +test.write('source_0.h', """ +#include +#include + +int +print_function0(); +""") + + +def get_num_cpus(): + """ + Function to get the number of CPUs the system has. + """ + # Linux, Unix and MacOS: + if hasattr(os, "sysconf"): + if 'SC_NPROCESSORS_ONLN' in os.sysconf_names: + # Linux & Unix: + ncpus = os.sysconf("SC_NPROCESSORS_ONLN") + if isinstance(ncpus, int) and ncpus > 0: + return ncpus + # OSX: + return int(os.popen("sysctl -n hw.ncpu")[1].read()) + # Windows: + if 'NUMBER_OF_PROCESSORS' in os.environ: + ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) + if ncpus > 0: + return ncpus + # Default + return 1 + + +def generate_source(parent_source, current_source): + test.write('source_{}.c'.format(current_source), """ + #include + #include + #include "source_%(parent_source)s.h" + #include "source_%(current_source)s.h" + + int + print_function%(current_source)s() + { + return print_function%(parent_source)s(); + } + """ % locals()) + + test.write('source_{}.h'.format(current_source), """ + #include + #include + + int + print_function%(current_source)s(); + """ % locals()) + + +def mod_source_return(test_num): + parent_source = test_num - 1 + test.write('source_{}.c'.format(test_num), """ + #include + #include + #include "source_%(parent_source)s.h" + #include "source_%(test_num)s.h" + + int + print_function%(test_num)s() + { + int test = 5 + 5; + print_function%(parent_source)s(); + return test; + } + """ % locals()) + + +def mod_source_orig(test_num): + parent_source = test_num - 1 + test.write('source_{}.c'.format(test_num), """ + #include + #include + #include "source_%(parent_source)s.h" + #include "source_%(test_num)s.h" + + int + print_function%(test_num)s() + { + return print_function%(parent_source)s(); + } + """ % locals()) + + +num_source = 200 +for i in range(1, num_source + 1): + generate_source(i - 1, i) + +test.write('main.c', """ +#include +#include +#include "source_%(num_source)s.h" +int +main() +{ + print_function%(num_source)s(); + exit(0); +} +""" % locals()) + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +sources = ['main.c'] + env.Glob('source*.c') +env.Program(target = 'print_bin', source = sources) +""") + +test.write('SConstruct_no_ninja', """ +env = Environment() +sources = ['main.c'] + env.Glob('source*.c') +env.Program(target = 'print_bin', source = sources) +""") + +tests_mods = [] +ninja_times = [] +scons_times = [] +for _ in range(10): + tests_mods += [random.randrange(1, num_source, 1)] +jobs = '-j' + str(get_num_cpus()) + +ninja_program = [test.workpath('run_ninja_env.bat'), jobs] if IS_WINDOWS else [ninja_bin, jobs] + +test.run(arguments='--disable-execute-ninja', stdout=None) +test.run(program=ninja_program, arguments='run-ninja-scons-daemon', stdout=None) +start = time.perf_counter() +test.run(program=ninja_program, stdout=None) +stop = time.perf_counter() +ninja_times += [stop - start] +test.run(program=test.workpath('print_bin'), stdout="main print") + + +for test_mod in tests_mods: + mod_source_return(test_mod) + start = time.perf_counter() + test.run(program=ninja_program, stdout=None) + stop = time.perf_counter() + ninja_times += [stop - start] + +for test_mod in tests_mods: + mod_source_orig(test_mod) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed build.ninja']) + +start = time.perf_counter() +test.run(arguments=["-f", "SConstruct_no_ninja", jobs], stdout=None) +stop = time.perf_counter() +scons_times += [stop - start] +test.run(program=test.workpath('print_bin'), stdout="main print") + +for test_mod in tests_mods: + mod_source_return(test_mod) + start = time.perf_counter() + test.run(arguments=["-f", "SConstruct_no_ninja", jobs], stdout=None) + stop = time.perf_counter() + scons_times += [stop - start] + +full_build_print = True +for ninja_time, scons_time in zip(ninja_times, scons_times): + if ninja_time > scons_time: + test.fail_test(message="Ninja was slower than SCons: SCons: {:.3f}s Ninja: {:.3f}s".format(scons_time, ninja_time)) + if full_build_print: + full_build_print = False + print("Clean build {} files - SCons: {:.3f}s Ninja: {:.3f}s".format(num_source, scons_time, ninja_time)) + else: + print("Single File Rebuild - SCons: {:.3f}s Ninja: {:.3f}s".format(scons_time, ninja_time)) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/mingw_command_generator_action.py scons-4.4.0+dfsg/test/ninja/mingw_command_generator_action.py --- scons-4.0.1+dfsg/test/ninja/mingw_command_generator_action.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/mingw_command_generator_action.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,89 @@ +#!/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. +# + +import os +import sys + +import TestSCons +from TestCmd import IS_WINDOWS +import SCons +from SCons.Platform.mingw import MINGW_DEFAULT_PATHS +from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + +test = TestSCons.TestSCons() + +if sys.platform not in ('cygwin', 'win32',): + test.skip_test("Skipping mingw test on non-Windows platform %s." % sys.platform) + +dp = MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS +gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=dp) +if not gcc: + test.skip_test("Skipping mingw test, no MinGW found.\n") + +# ninja must have the os environment setup to work properly +os.environ["PATH"] += os.pathsep + os.path.dirname(gcc) + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.BIN_DIR, + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_mingw_command_generator_action', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('test' + _exe), stdout="library_function") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('test' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('test' + _exe), stdout="library_function") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/mingw_depfile_format.py scons-4.4.0+dfsg/test/ninja/mingw_depfile_format.py --- scons-4.0.1+dfsg/test/ninja/mingw_depfile_format.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/mingw_depfile_format.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,60 @@ +#!/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. +# + +import os + +import TestSCons + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.BIN_DIR, + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_mingw_depfile_format', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain(test.workpath('build.ninja'), 'deps = msvc') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/mkdir_function_command.py scons-4.4.0+dfsg/test/ninja/mkdir_function_command.py --- scons-4.0.1+dfsg/test/ninja/mkdir_function_command.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/mkdir_function_command.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,123 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) +env = Environment() +env.Tool('ninja') +env.Dir('test0') +env.Dir('test1/test2') +env.Dir('test3/test4') +env.Command('test5', 'test3/test4', Mkdir('$TARGET')) +env.Command('test6/test7', ['test1/test2', 'test0'], Mkdir('$TARGET')) +""") + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_single_instance_of(test.stdout(), ["scons: Building targets ..."]) +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_exist([ + test.workpath('test0'), + test.workpath('test1/test2'), + test.workpath('test3/test4'), + test.workpath('test5'), + test.workpath('test6/test7') +]) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed build.ninja']) +os.rmdir('test0') +os.rmdir('test1/test2') +os.rmdir('test1') +os.rmdir('test3/test4') +os.rmdir('test3') +os.rmdir('test5') +os.rmdir('test6/test7') +os.rmdir('test6') + +test.must_not_exist([ + test.workpath('test0'), + test.workpath('test1/test2'), + test.workpath('test3/test4'), + test.workpath('test5'), + test.workpath('test6/test7') +]) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist([ + test.workpath('test0'), + test.workpath('test1/test2'), + test.workpath('test3/test4'), + test.workpath('test5'), + test.workpath('test6/test7') +]) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_not_contain_any_line(test.stdout(), ["scons: Building targets ..."]) +test.must_exist([ + test.workpath('test0'), + test.workpath('test1/test2'), + test.workpath('test3/test4'), + test.workpath('test5'), + test.workpath('test6/test7') +]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/multi_env.py scons-4.4.0+dfsg/test/ninja/multi_env.py --- scons-4.0.1+dfsg/test/ninja/multi_env.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/multi_env.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,98 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test = TestSCons.TestSCons() + +test.dir_fixture('ninja-fixture') + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +env.Program(target = 'foo', source = 'foo.c') + +env2 = Environment() +env2.Program(target = 'bar', source = 'bar.c') +""") + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") +test.run(program=test.workpath('bar' + _exe), stdout="bar.c") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed foo.o', + 'Removed foo' + _exe, + 'Removed bar.o', + 'Removed bar' + _exe, + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo' + _exe)) +test.must_not_exist(test.workpath('bar' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") +test.run(program=test.workpath('bar' + _exe), stdout="bar.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_command_line.py scons-4.4.0+dfsg/test/ninja/ninja_command_line.py --- scons-4.0.1+dfsg/test/ninja/ninja_command_line.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_command_line.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,82 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture', 'src') + +test.file_fixture('ninja_test_sconscripts/sconstruct_ninja_command_line', 'SConstruct') + +# generate simple build +test.run(arguments=['BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +# clean build and ninja files +test.run(arguments=['-c', 'BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed build%sbar2.c' % os.sep, + 'Removed build%sbar2.o' % os.sep, + 'Removed foo', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments=['--disable-execute-ninja', 'BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_conftest.py scons-4.4.0+dfsg/test/ninja/ninja_conftest.py --- scons-4.0.1+dfsg/test/ninja/ninja_conftest.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_conftest.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,81 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/ninja_conftest', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed foo.o', + 'Removed foo', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_file_deterministic.py scons-4.4.0+dfsg/test/ninja/ninja_file_deterministic.py --- scons-4.0.1+dfsg/test/ninja/ninja_file_deterministic.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_file_deterministic.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,110 @@ +#!/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. +# + +import os +import shutil +import filecmp + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.BIN_DIR, + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_ninja_determinism', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) +shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig')) + +ninja_file_mtime = os.path.getmtime(test.workpath('build.ninja')) + +# generate same build again +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja', 'ninja: no work to do.']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) + +if os.path.getmtime(test.workpath('build.ninja')) != ninja_file_mtime: + test.fail_test(message="build.ninja file has been updated (mtime changed) and should not have been") + +# make sure the ninja file was deterministic +if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')): + test.fail_test() + +# clean build and ninja files +os.unlink(test.workpath('build.ninja.orig')) +test.run(arguments='-c', stdout=None) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) +shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig')) + +# only generate the ninja file again +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) + +# run ninja independently again +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_contain_all_lines(test.stdout(), ['ninja: no work to do.']) +test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')]) + +# make sure the ninja file was deterministic +if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')): + test.fail_test() + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/bar.c scons-4.4.0+dfsg/test/ninja/ninja-fixture/bar.c --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/bar.c 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/bar.c 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,10 @@ +#include +#include + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("bar.c"); + exit (0); +} diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/foo.c scons-4.4.0+dfsg/test/ninja/ninja-fixture/foo.c --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/foo.c 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/foo.c 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,10 @@ +#include +#include + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("foo.c"); + exit (0); +} diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/gen_source.c scons-4.4.0+dfsg/test/ninja/ninja-fixture/gen_source.c --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/gen_source.c 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/gen_source.c 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,9 @@ +#include +#include + +#include "generated_header2.htest" + +int main(int argc, char *argv[]) +{ + printf("%d", func2()); +} diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/test1.c scons-4.4.0+dfsg/test/ninja/ninja-fixture/test1.c --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/test1.c 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/test1.c 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,21 @@ +#include +#include + +#ifdef WIN32 +#ifdef LIBRARY_BUILD +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif +#else +#define DLLEXPORT +#endif + +DLLEXPORT extern int library_function(void); + +int +main(int argc, char *argv[]) +{ + library_function(); + exit(0); +} diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/test2.cpp scons-4.4.0+dfsg/test/ninja/ninja-fixture/test2.cpp --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/test2.cpp 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/test2.cpp 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,16 @@ +#include "test2.hpp" + +int +main(int argc, char *argv[]) +{ + Foo* test = new Foo(); + test->print_function(); + test->print_function2(); + return 0; +} + +int Foo::print_function() +{ + std::cout << "print_function"; + return 0; +} \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/test2.hpp scons-4.4.0+dfsg/test/ninja/ninja-fixture/test2.hpp --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/test2.hpp 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/test2.hpp 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,9 @@ +#include +#include + +class Foo +{ +public: + int print_function(); + int print_function2(){return 0;}; +}; diff -Nru scons-4.0.1+dfsg/test/ninja/ninja-fixture/test_impl.c scons-4.4.0+dfsg/test/ninja/ninja-fixture/test_impl.c --- scons-4.0.1+dfsg/test/ninja/ninja-fixture/test_impl.c 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja-fixture/test_impl.c 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,20 @@ +#include +#include + +#ifdef WIN32 +#ifdef LIBRARY_BUILD +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif +#else +#define DLLEXPORT +#endif + + +DLLEXPORT int +library_function(void) +{ + printf("library_function"); + return 0; +} diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_handle_control_c_rebuild.py scons-4.4.0+dfsg/test/ninja/ninja_handle_control_c_rebuild.py --- scons-4.0.1+dfsg/test/ninja/ninja_handle_control_c_rebuild.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_handle_control_c_rebuild.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,89 @@ +#!/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. +# +""" +This test ensures if ninja gets a control-c (or other interrupting signal) while +regenerating the build.ninja, it doesn't remove the build.ninja leaving it +in an unworkable state. +""" +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath( + os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe) +) + +test.dir_fixture("ninja-fixture") + +test.file_fixture("ninja_test_sconscripts/sconstruct_generate_and_build", "SConstruct") + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"]) +test.must_contain_all(test.stdout(), "Executing:") +test.must_contain_all(test.stdout(), "ninja%(_exe)s -f" % locals()) +test.run(program=test.workpath("foo" + _exe), stdout="foo.c") + +# Change the SConstruct +test.file_fixture("ninja_test_sconscripts/sconstruct_control_c_ninja", "SConstruct") + +# run ninja independently +program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin +if IS_WINDOWS: + test.fail_test( + condition=(test.status in [1, 2]), + message="Expected exit status to be 1 or 2 was actually:%d" % test.status, + ) +else: + test.fail_test( + condition=(test.status == 1), + message="Expected exit status to be 1 was actually:%d" % test.status, + ) + +test.run(program=program, stdout=None, stderr=None, status=None) + +if not IS_WINDOWS: + error_msg = "ninja: error: rebuilding 'build.ninja': interrupted by user" + test.must_contain_all(test.stderr(), error_msg) + +# Verify that Rebuilding build.ninja and sending control-c to ninja doesn't remove build.ninja +test.must_exist("build.ninja") +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/ninja_conftest scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/ninja_conftest --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/ninja_conftest 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/ninja_conftest 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,21 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +import sys + +env = Environment() + +conf = Configure(env) +env.Tool('ninja') + +# create a conf test that will fail. A failing conftest +# should not affect ninja generation and build from taking place. +if sys.platform == "win32": + conf.env.Append( + CCFLAGS="/DEBUG /Z7 /INCREMENTAL:NO", + LINKFLAGS="/DEBUG /INCREMENTAL:NO", + PDB='${TARGET.base}.pdb') +conf.TryRun("int main( int argc, char* argv[] ){return fail;}", '.c') +env = conf.Finish() + +env.Program(target='foo', source='foo.c') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_control_c_ninja scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_control_c_ninja --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_control_c_ninja 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_control_c_ninja 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,12 @@ +import os +import signal + +SetOption('experimental', 'ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +env.Program(target='foo', source='foo.c') + +if ARGUMENTS.get('NINJA_DISABLE_AUTO_RUN', 0): + os.kill(os.getppid(), signal.SIGINT) diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_default_targets scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_default_targets --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_default_targets 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_default_targets 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,14 @@ +import SCons + +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment(tools=[]) + +env.Tool('ninja') + +env.Command('out1.txt', 'foo.c', 'echo test > $TARGET' ) +out2_node = env.Command('out2.txt', 'foo.c', 'echo test > $TARGET', NINJA_FORCE_SCONS_BUILD=True) +alias = env.Alias('def', out2_node) + +env.Default(alias) diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_force_scons_callback scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_force_scons_callback --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_force_scons_callback 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_force_scons_callback 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,11 @@ +SetOption("experimental", "ninja") +DefaultEnvironment(tools=[]) + +env = Environment(tools=[]) +daemon_port = ARGUMENTS.get("PORT", False) +if daemon_port: + env["NINJA_SCONS_DAEMON_PORT"] = int(daemon_port) +env.Tool("ninja") + +env.Command("out.txt", "foo.c", "echo $SOURCE> $TARGET", NINJA_FORCE_SCONS_BUILD=True) +env.Command("out2.txt", "test2.cpp", "echo $SOURCE> $TARGET") diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +env.Program(target='foo', source='foo.c') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build_cxx scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build_cxx --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build_cxx 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generate_and_build_cxx 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,5 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) +env = Environment() +env.Tool('ninja') +env.Program(target = 'test2', source = 'test2.cpp') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generated_sources_alias scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generated_sources_alias --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generated_sources_alias 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_generated_sources_alias 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +import SCons + +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +vars = Variables() +vars.Add("USE_GEN_SOURCE_ALIAS") + +env = Environment(variables=vars) +my_gen_alias = 'my_ninja_gen_sources' + + +env['SCANNERS'][0].add_scanner('.htest', SCons.Tool.CScanner) +env.Command('out.txt', [], f'echo USE_GEN_SOURCE_ALIAS={env["USE_GEN_SOURCE_ALIAS"]}') + +if env['USE_GEN_SOURCE_ALIAS'] == "1": + env['NINJA_GENERATED_SOURCE_ALIAS_NAME'] = my_gen_alias +else: + env['NINJA_GENERATED_SOURCE_SUFFIXES'] = ['.htest'] + +env.Tool('ninja') + +env.Alias(my_gen_alias, env.Textfile('generated_header1.htest', [ + '#pragma once', + 'int func1(){return 4;};' +])) +alias = env.Alias(my_gen_alias, env.Textfile('generated_header2.htest', [ + '#pragma once', + '', + 'int func2();' +])) +env.Depends(alias, 'out.txt') + +my_gen_alias, env.Textfile('generated_header2.c', [ + '#include "generated_header1.htest"', + '#include "generated_header2.htest"', + '', + 'int func2(){return func1();}' +]) + +env.Program(target='gen_source', source=['gen_source.c', 'generated_header2.c']) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_command_generator_action scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_command_generator_action --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_command_generator_action 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_command_generator_action 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,7 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment(tools=['mingw']) +env.Tool('ninja') +dll = env.SharedLibrary(target='test_impl', source='test_impl.c') +env.Program(target='test', source='test1.c', LIBS=[dll]) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_depfile_format scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_depfile_format --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_depfile_format 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_mingw_depfile_format 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,7 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment(tools=['mingw']) +env.Tool('ninja') +env['NINJA_DEPFILE_PARSE_FORMAT'] = 'msvc' + diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_command_line scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_command_line --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_command_line 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_command_line 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,14 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env_vars=Variables(args=ARGUMENTS) +env_vars.Add('BUILD') +env_vars.Add('OTHER_VAR') +env = Environment(variables=env_vars) + +env.VariantDir(env['OTHER_VAR'], 'src') +env.Tool('ninja') +with open('src/foo.c') as foo: + env.Textfile('$BUILD/bar2.c', foo.read()) + +env.Program(target = 'foo', source = '$BUILD/bar2.c', CPPPATH='src') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,19 @@ +import random + +SetOption('experimental', 'ninja') +SetOption('skip_ninja_regen', True) +DefaultEnvironment(tools=[]) + +env = Environment(tools=[]) + +env.Tool('ninja') + +# make the dependency list vary in order. Ninja tool should sort them to be deterministic. +for i in range(1, 10): + node = env.Command(f'out{i}.txt', 'foo.c', 'echo test > $TARGET') + deps = list(range(1, i)) + random.shuffle(deps) + for j in deps: + if j == i: + continue + env.Depends(node, f'out{j}.txt') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_no_for_sig_subst scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_no_for_sig_subst --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_no_for_sig_subst 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_no_for_sig_subst 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,24 @@ +import SCons + +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment(tools=[]) +env.Tool('ninja') + + +def test_subst_func(env, target, source, for_signature): + cmd = 'echo test > ' + if not for_signature: + cmd += 'out.txt' + return cmd + +bld = SCons.Builder.Builder( + action=SCons.Action.CommandGeneratorAction( + test_subst_func, + {} + ) + ) + +env['BUILDERS']['TestBld'] = bld +env.TestBld(target='out.txt', source='foo.c') diff -Nru scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_response_file scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_response_file --- scons-4.0.1+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_response_file 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/ninja_test_sconscripts/sconstruct_response_file 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,15 @@ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +vars = Variables() +vars.Add('MLL', default='2048') + +env = Environment(variables=vars) +env['MAXLINELENGTH'] = int(env['MLL']) +env.Tool('ninja') + +env.Program(target='foo', source='foo.c', OBJSUFFIX=env['OBJSUFFIX'] + "1") + +env2 = env.Clone() +env2.Append(CPPPATH='very/long/and/very/fake/path/for/testing') +env2.Program(target='foo2', source='foo.c', OBJSUFFIX=env['OBJSUFFIX'] + "2") \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/ninja/no_for_sig_subst.py scons-4.4.0+dfsg/test/ninja/no_for_sig_subst.py --- scons-4.0.1+dfsg/test/ninja/no_for_sig_subst.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/no_for_sig_subst.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,80 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_no_for_sig_subst', 'SConstruct') + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_exist([test.workpath('out.txt')]) + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed out.txt', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('out.txt')) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_exist([test.workpath('out.txt')]) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/response_file.py scons-4.4.0+dfsg/test/ninja/response_file.py --- scons-4.0.1+dfsg/test/ninja/response_file.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/response_file.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,97 @@ +#!/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. +# + +import os +import sys +import json +from io import StringIO + + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe +_obj = TestSCons._obj + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +test.file_fixture('ninja_test_sconscripts/sconstruct_response_file', 'SConstruct') + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo' + _exe)) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin + +# now we must extract the line length for a given command by print the command +# to a StringIO internal buffer and calculating the length of the resulting command. +test.run(program=[program, 'compiledb'], stdout=None) +command_length = None +with open('compile_commands.json') as f: + comp_commands = json.loads(f.read()) + for cmd in comp_commands: + if cmd['output'].endswith('1'): + result = StringIO() + old_stdout = sys.stdout + sys.stdout = result + print(cmd['command']) + result_string = result.getvalue() + sys.stdout = old_stdout + if sys.platform == 'win32': + command_length = len(result_string) + else: + command_length = len(result_string.split(';')[-1]) + +# now regen the ninja file with the MAXLINELENGTH so we can force the response file in one case. +test.run(arguments=['--disable-execute-ninja', 'MLL='+str(command_length)], stdout=None) +test.run(program=[program, '-v', '-d', 'keeprsp'], stdout=None) +test.must_not_exist(test.workpath('foo' + _obj + '1.rsp')) +test.must_exist(test.workpath('foo' + _obj + '2.rsp')) + +test.run(program=test.workpath('foo' + _exe), stdout="foo.c") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/shell_command.py scons-4.4.0+dfsg/test/ninja/shell_command.py --- scons-4.0.1+dfsg/test/ninja/shell_command.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/shell_command.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,92 @@ +#!/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. +# + +import os + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find module in python") + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath(os.path.join( + ninja.__file__, + os.pardir, + 'data', + 'bin', + 'ninja' + _exe)) + +test.dir_fixture('ninja-fixture') + +shell = '' if IS_WINDOWS else './' + +test.write('SConstruct', """ +SetOption('experimental','ninja') +DefaultEnvironment(tools=[]) + +env = Environment() +env.Tool('ninja') +prog = env.Program(target = 'foo', source = 'foo.c') +env.Command('foo.out', prog, '%(shell)sfoo%(_exe)s > foo.out') +""" % locals()) + +# generate simple build +test.run(stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_contain_all(test.stdout(), 'Executing:') +test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_match('foo.out', 'foo.c') + +# clean build and ninja files +test.run(arguments='-c', stdout=None) +test.must_contain_all_lines(test.stdout(), [ + 'Removed foo.o', + 'Removed foo%(_exe)s' % locals(), + 'Removed foo.out', + 'Removed build.ninja']) + +# only generate the ninja file +test.run(arguments='--disable-execute-ninja', stdout=None) +test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) +test.must_not_exist(test.workpath('foo.out')) + +# run ninja independently +program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin +test.run(program=program, stdout=None) +test.must_match('foo.out', 'foo.c') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/ninja/shutdown_scons_daemon.py scons-4.4.0+dfsg/test/ninja/shutdown_scons_daemon.py --- scons-4.0.1+dfsg/test/ninja/shutdown_scons_daemon.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ninja/shutdown_scons_daemon.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,84 @@ +#!/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. +# + +import os +from timeit import default_timer as timer + +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons() + +try: + import ninja +except ImportError: + test.skip_test("Could not find ninja module in python") + +try: + import psutil +except ImportError: + test.skip_test("Could not find psutil module in python") + + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +ninja_bin = os.path.abspath( + os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe) +) + +test.dir_fixture("ninja-fixture") + +test.file_fixture( + "ninja_test_sconscripts/sconstruct_force_scons_callback", "SConstruct" +) + +test.run(stdout=None) +pid = None +test.must_exist(test.workpath('.ninja/scons_daemon_dirty')) +with open(test.workpath('.ninja/scons_daemon_dirty')) as f: + pid = int(f.read()) + if pid not in [proc.pid for proc in psutil.process_iter()]: + test.fail_test(message="daemon not running!") + +program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin +test.run(program=program, arguments='shutdown-ninja-scons-daemon', stdout=None) + +wait_time = 10 +start_time = timer() +while True: + if wait_time > (timer() - start_time): + if pid not in [proc.pid for proc in psutil.process_iter()]: + break + else: + test.fail_test(message=f"daemon still not shutdown after {wait_time} seconds.") + +test.must_not_exist(test.workpath('.ninja/scons_daemon_dirty')) +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/no-arguments.py scons-4.4.0+dfsg/test/no-arguments.py --- scons-4.0.1+dfsg/test/no-arguments.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/no-arguments.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ arguments, or a null command-line argument. """ -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/NodeOps.py scons-4.4.0+dfsg/test/NodeOps.py --- scons-4.0.1+dfsg/test/NodeOps.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/NodeOps.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,29 +22,23 @@ # 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__" +""" +This test is used to verify that the Buildability of a set of nodes +is unaffected by various querying operations on those nodes: -# This test is used to verify that the Buildability of a set of nodes -# is unaffected by various querying operations on those nodes: -# -# 1) Calling exists() on a Node (e.g. from find_file) in a VariantDir -# will cause that node to be duplicated into the builddir. -# However, this should *not* occur during a dryrun (-n). When not -# performed during a dryrun, this should not affect buildability. -# 2) Calling is_derived() should not affect buildability. +1) Calling exists() on a Node (e.g. from find_file) in a VariantDir + will cause that node to be duplicated into the builddir. + However, this should *not* occur during a dryrun (-n). When not + performed during a dryrun, this should not affect buildability. +2) Calling is_derived() should not affect buildability. +""" import sys -import TestSCons import os -_exe = TestSCons._exe -lib_ = TestSCons.lib_ -_lib = TestSCons._lib -_obj = TestSCons._obj -dll_ = TestSCons.dll_ -_dll = TestSCons._dll +import TestSCons +from TestSCons import _exe, lib_, _lib, _obj, dll_, _dll if os.name == 'posix': os.environ['LD_LIBRARY_PATH'] = '.' diff -Nru scons-4.0.1+dfsg/test/option/debug-count.py scons-4.4.0+dfsg/test/option/debug-count.py --- scons-4.0.1+dfsg/test/option/debug-count.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/debug-count.py 2022-07-30 21:48:28.000000000 +0000 @@ -34,13 +34,6 @@ 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 -Nru scons-4.0.1+dfsg/test/option/debug-memory.py scons-4.4.0+dfsg/test/option/debug-memory.py --- scons-4.0.1+dfsg/test/option/debug-memory.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/debug-memory.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ 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 -Nru scons-4.0.1+dfsg/test/option/debug-objects.py scons-4.4.0+dfsg/test/option/debug-objects.py --- scons-4.0.1+dfsg/test/option/debug-objects.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/debug-objects.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,13 +32,6 @@ 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 -Nru scons-4.0.1+dfsg/test/option/debug-stacktrace.py scons-4.4.0+dfsg/test/option/debug-stacktrace.py --- scons-4.0.1+dfsg/test/option/debug-stacktrace.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/debug-stacktrace.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the --debug=stacktrace option. @@ -34,37 +33,27 @@ test.write('SConstruct', """\ DefaultEnvironment(tools=[]) + def kfile_scan(node, env, target): raise Exception("kfile_scan error") -kscan = Scanner(name = 'kfile', - function = kfile_scan, - skeys = ['.k']) - +kscan = Scanner(name='kfile', function=kfile_scan, skeys=['.k']) env = Environment(tools=[]) env.Append(SCANNERS = [kscan]) env.Command('foo', 'foo.k', Copy('$TARGET', '$SOURCE')) """) - test.write('foo.k', "foo.k\n") test.run(status = 2, stderr = "scons: *** [foo] Exception : kfile_scan error\n") - -test.run(arguments = "--debug=stacktrace", - status = 2, - stderr = None) - +test.run(arguments="--debug=stacktrace", status=2, stderr=None) lines = [ "scons: *** [foo] Exception : kfile_scan error", "scons: internal stack trace:", 'raise Exception("kfile_scan error")', ] - test.must_contain_all_lines(test.stderr(), lines) - - # Test that --debug=stacktrace works for UserError exceptions, # which are handled by different code than other exceptions. @@ -73,25 +62,14 @@ raise SCons.Errors.UserError("explicit UserError!") """) -test.run(arguments = '--debug=stacktrace', - status = 2, - stderr = None) - +test.run(arguments='--debug=stacktrace', status=2, stderr=None) user_error_lines = [ 'UserError: explicit UserError!', 'scons: *** explicit UserError!', ] - -# The "(most recent call last)" message is used by more recent Python -# versions than the "(innermost last)" message, so that's the one -# we report if neither matches. -traceback_lines = [ - "Traceback (most recent call last)", - "Traceback (innermost last)", -] - +traceback_lines = ["Traceback (most recent call last)",] test.must_contain_all_lines(test.stderr(), user_error_lines) -test.must_contain_any_line(test.stderr(), traceback_lines) +test.must_contain_all_lines(test.stderr(), traceback_lines) # Test that full path names to SConscript files show up in stack traces. @@ -99,18 +77,10 @@ 1/0 """) -test.run(arguments = '--debug=stacktrace', - status = 2, - stderr = None) - -lines = [ - ' File "%s", line 1:' % test.workpath('SConstruct'), -] - +test.run(arguments='--debug=stacktrace', status=2, stderr=None) +lines = [' File "%s", line 1:' % test.workpath('SConstruct'),] test.must_contain_all_lines(test.stderr(), lines) - - test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/option/debug-time.py scons-4.4.0+dfsg/test/option/debug-time.py --- scons-4.0.1+dfsg/test/option/debug-time.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/debug-time.py 2022-07-30 21:48:28.000000000 +0000 @@ -95,15 +95,15 @@ test.write('pass.py', "pass\n") test.read(test.program) -start_time = time.time() +start_time = time.perf_counter() test.run(program=TestSCons.python, arguments=test.workpath('pass.py')) -overhead = time.time() - start_time +overhead = time.perf_counter() - start_time -start_time = time.time() +start_time = time.perf_counter() test.run(arguments = "-j1 --debug=time . SLEEP=0") -complete_time = time.time() - start_time +complete_time = time.perf_counter() - start_time @@ -132,7 +132,7 @@ if targets != expected_targets: failures.append("""\ -Scons reported the targets of timing information as %(targets)s, +Scons reported the targets of timing information as %(targets)s, but the actual targets should have been %(expected_targets)s. """ %locals()) diff -Nru scons-4.0.1+dfsg/test/option/fixture/SConstruct__experimental scons-4.4.0+dfsg/test/option/fixture/SConstruct__experimental --- scons-4.0.1+dfsg/test/option/fixture/SConstruct__experimental 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/fixture/SConstruct__experimental 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,9 @@ +from SCons.Script.SConsOptions import experimental_features + +print("All Features=%s" % ','.join(sorted(experimental_features))) + +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) + +exp = GetOption('experimental') +print("Experimental=%s" % sorted(exp)) diff -Nru scons-4.0.1+dfsg/test/option/hash-format/build.py scons-4.4.0+dfsg/test/option/hash-format/build.py --- scons-4.0.1+dfsg/test/option/hash-format/build.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/hash-format/build.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,3 @@ +import sys +with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as infp: + f.write(infp.read()) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/option/hash-format/.exclude_tests scons-4.4.0+dfsg/test/option/hash-format/.exclude_tests --- scons-4.0.1+dfsg/test/option/hash-format/.exclude_tests 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/hash-format/.exclude_tests 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +build.py diff -Nru scons-4.0.1+dfsg/test/option/hash-format/f1.in scons-4.4.0+dfsg/test/option/hash-format/f1.in --- scons-4.0.1+dfsg/test/option/hash-format/f1.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/hash-format/f1.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/option/hash-format/SConstruct scons-4.4.0+dfsg/test/option/hash-format/SConstruct --- scons-4.0.1+dfsg/test/option/hash-format/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/hash-format/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,27 @@ +import atexit +import sys + +hash_format = GetOption('hash_format') +if not hash_format: + # Override to SHA-256 to validate that override is effective + hash_format = 'sha256' + SetOption('hash_format', hash_format) + +DefaultEnvironment(tools=[]) +B = Builder(action = r'$PYTHON build.py $TARGETS $SOURCES') +env = Environment(tools=[], BUILDERS = { 'B' : B }) +env['PYTHON'] = sys.executable +f1 = env.B(target = 'f1.out', source = 'f1.in') + +def VerifyCsig(): + csig = f1[0].get_csig() + if hash_format == 'md5': + assert csig == 'fe06ae4170d4fead2c958439c738859e', csig + elif hash_format == 'sha1': + assert csig == 'efe5c6daa743540e9561934e3e18628b336013f7', csig + elif hash_format == 'sha256': + assert csig == 'a28bb79aa5ca8a5eb2dc5910a103d1a6312e79d73ed8054787cee78cc532a6aa', csig + elif hash_format != 'testfailure': + raise Exception('Hash format %s is not supported in ' + 'test/option/hash-format/SConstruct' % hash_format) +atexit.register(VerifyCsig) diff -Nru scons-4.0.1+dfsg/test/option/hash-format.py scons-4.4.0+dfsg/test/option/hash-format.py --- scons-4.0.1+dfsg/test/option/hash-format.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/hash-format.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,103 @@ +#!/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__" + +import hashlib +import os +import TestSCons +from SCons.Util import ALLOWED_HASH_FORMATS, DEFAULT_HASH_FORMATS + +# Test passing the hash format by command-line. +INVALID_ALGORITHM = 'testfailure' + +for algorithm in [*DEFAULT_HASH_FORMATS, INVALID_ALGORITHM, None]: + test = TestSCons.TestSCons() + test.dir_fixture('hash-format') + + # Expect failure due to an unsupported/invalid algorithm. + # The error message however changes if SCons detects that the host system doesn't support one or more algorithms + # Primary reason the message changes is so user doesn't have to start with unsupported algorithm A and then attempt + # to switch to unsupported algorithm B. + # On normal systems (allowed=default) this will output a fixed message, but on FIPS-enabled or other weird systems + # that don't have default allowed algorithms, it informs the user of the mismatch _and_ the currently supported + # algorithms on the system they're using. + # In Python 3.9 this becomes somewhat obselete as the hashlib is informed we don't use hashing for security but + # for loose integrity. + if algorithm == INVALID_ALGORITHM: + if ALLOWED_HASH_FORMATS == DEFAULT_HASH_FORMATS: + test.run('--hash-format=%s .' % algorithm, stderr=r""" +scons: \*\*\* Hash format "{}" is not supported by SCons. Only the following hash formats are supported: {} +File "[^"]+", line \d+, in \S+ +""".format(algorithm, ', '.join(DEFAULT_HASH_FORMATS)), status=2, match=TestSCons.match_re) + else: + test.run('--hash-format=%s .' % algorithm, stderr=r""" +scons: \*\*\* Hash format "{}" is not supported by SCons. SCons supports more hash formats than your local system is reporting; SCons supports: {}. Your local system only supports: {} +File "[^"]+", line \d+, in \S+ +""".format(algorithm, ', '.join(DEFAULT_HASH_FORMATS), ', '.join(ALLOWED_HASH_FORMATS)), status=2, match=TestSCons.match_re) + continue + elif algorithm is not None: + if algorithm in ALLOWED_HASH_FORMATS: + expected_dblite = test.workpath('.sconsign_%s.dblite' % algorithm) + test.run('--hash-format=%s .' % algorithm) + else: + test.run('--hash-format=%s' % algorithm, stderr=r""" +scons: \*\*\* While hash format "{}" is supported by SCons, the local system indicates only the following hash formats are supported by the hashlib library: {} +File "[^"]+", line \d+, in \S+ +Error in atexit._run_exitfuncs: +Traceback \(most recent call last\): + File "[^"]+", line \d+, in \S+ + assert csig == '[a-z0-9]+', csig +AssertionError: [a-z0-9]+ +""".format(algorithm, ', '.join(ALLOWED_HASH_FORMATS)), status=2, match=TestSCons.match_re) + continue + else: + # The SConsign file in the hash-format folder has logic to call + # SCons.Util.set_hash_format('sha256') if the default algorithm is + # being used. So this test of algorithm==None effectively validates + # that the sconsign db includes the algorithm name if that function is + # used instead of --hash-format. This is useful because consumers are + # expected to call that function if they want to opt into stronger + # hashes. + expected_dblite = test.workpath('.sconsign_sha256.dblite') + test.run('.') + + assert os.path.isfile(expected_dblite), \ + "%s does not exist when running algorithm %s" % (expected_dblite, + algorithm) + + test.run('-C .') + os.unlink(expected_dblite) + +# In this case, the SConstruct file will use SetOption to override the hash +# format. +test.run() + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/help-options.py scons-4.4.0+dfsg/test/option/help-options.py --- scons-4.0.1+dfsg/test/option/help-options.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/help-options.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -25,7 +26,6 @@ Verify behavior of the -H and --help-options options. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import re diff -Nru scons-4.0.1+dfsg/test/option/md5-chunksize.py scons-4.4.0+dfsg/test/option/md5-chunksize.py --- scons-4.0.1+dfsg/test/option/md5-chunksize.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/md5-chunksize.py 2022-07-30 21:48:28.000000000 +0000 @@ -68,17 +68,18 @@ test.must_not_exist('f2.out') # -# Test with --md5-chunksize +# Test with both synonyms: --hash-chunksize and --md5-chunksize # -test.run(arguments = '--md5-chunksize=128 .', - stdout=expected_stdout, - stderr='') -test.must_exist('f1.out') -test.must_exist('f2.out') +for name in ['--md5-chunksize', '--hash-chunksize']: + test.run(arguments = '%s=128 .' % name, + stdout=expected_stdout, + stderr='') + test.must_exist('f1.out') + test.must_exist('f2.out') -test.run(arguments = '--md5-chunksize=128 -c .') -test.must_not_exist('f1.out') -test.must_not_exist('f2.out') + test.run(arguments = '%s=128 -c .' % name) + test.must_not_exist('f1.out') + test.must_not_exist('f2.out') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/option/option-b.py scons-4.4.0+dfsg/test/option/option-b.py --- scons-4.0.1+dfsg/test/option/option-b.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-b.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,43 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments = '-b .', + stderr = "Warning: ignoring -b option\n") + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--C.py scons-4.4.0+dfsg/test/option/option--C.py --- scons-4.0.1+dfsg/test/option/option--C.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--C.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,111 @@ +#!/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. +# + +""" +Test that the -C option changes directory as expected and that +multiple -C options are additive, except if a full path is given +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os + +import TestSCons + +def match_normcase(lines, matches): + if not isinstance(lines, list): + lines = lines.split("\n") + if not isinstance(matches, list): + matches = matches.split("\n") + if len(lines) != len(matches): + return None + for line, match in zip(lines, matches): + if os.path.normcase(line) != os.path.normcase(match): + return None + return 1 + +test = TestSCons.TestSCons(match=match_normcase) + +wpath = test.workpath() +wpath_sub = test.workpath('sub') +wpath_sub_dir = test.workpath('sub', 'dir') +wpath_sub_foo_bar = test.workpath('sub', 'foo', 'bar') + +test.subdir('sub', ['sub', 'dir']) + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +import os +print("SConstruct " + os.getcwd()) +""") + +test.write(['sub', 'SConstruct'], """ +DefaultEnvironment(tools=[]) +import os +print(GetBuildPath('..')) +""") + +test.write(['sub', 'dir', 'SConstruct'], """ +DefaultEnvironment(tools=[]) +import os +env = Environment(FOO='foo', BAR='bar', tools=[]) +print(env.GetBuildPath('../$FOO/$BAR')) +""") + +# single -C +test.run(arguments='-C sub .', + stdout="scons: Entering directory `%s'\n" % wpath_sub \ + + test.wrap_stdout(read_str='%s\n' % wpath, + build_str="scons: `.' is up to date.\n")) + +# multiple -C +test.run(arguments='-C sub -C dir .', + stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \ + + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar, + build_str="scons: `.' is up to date.\n")) + +test.run(arguments=".", + stdout=test.wrap_stdout(read_str='SConstruct %s\n' % wpath, + build_str="scons: `.' is up to date.\n")) + +# alternate form +test.run(arguments='--directory=sub/dir .', + stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \ + + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar, + build_str="scons: `.' is up to date.\n")) + +# checks that using full paths is not additive +test.run(arguments='-C %s -C %s .' % (wpath_sub_dir, wpath_sub), + stdout="scons: Entering directory `%s'\n" % wpath_sub \ + + test.wrap_stdout(read_str='%s\n' % wpath, + build_str="scons: `.' is up to date.\n")) + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--duplicate.py scons-4.4.0+dfsg/test/option/option--duplicate.py --- scons-4.0.1+dfsg/test/option/option--duplicate.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--duplicate.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" +This tests the --duplicate command line option, and the duplicate +SConscript settable option. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os +import sys +import stat +import TestSCons + +python = TestSCons.python + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +try: + duplicate = ARGUMENTS['duplicate'] + SetOption('duplicate', duplicate) +except KeyError: + pass +VariantDir('build', '.', duplicate=1) +SConscript('build/SConscript') +""") + +test.write('SConscript', '') + +# we don't use links on windows currently as they +# require permissions not usually set +hard = hasattr(os, 'link') and sys.platform != 'win32' +soft = hasattr(os, 'symlink') and sys.platform != 'win32' +copy = 1 # should always work + +bss = test.workpath('build/SConscript') + +criterion_hardlinks = { + 'hard' : lambda nl, islink: nl == 2 and not islink, + 'soft' : lambda nl, islink: nl == 1 and islink, + 'copy' : lambda nl, islink: nl == 1 and not islink, +} + +criterion_no_hardlinks = { + 'hard' : lambda nl, islink: not islink, + 'soft' : lambda nl, islink: islink, + 'copy' : lambda nl, islink: not islink, +} + +# On systems without hard linking, it doesn't make sense to check ST_NLINK +if hard: + criterion = criterion_hardlinks +else: + criterion = criterion_no_hardlinks + +description = { + 'hard' : 'a hard link', + 'soft' : 'a soft link', + 'copy' : 'copied', +} + +def testLink(file, type): + nl = os.stat(file)[stat.ST_NLINK] + islink = os.path.islink(file) + assert criterion[type](nl, islink), \ + "Expected %s to be %s (nl %d, islink %d)" \ + % (file, description[type], nl, islink) + +def RunTest(order, type, bss): + # Test the command-line --duplicate option. + test.run(arguments='--duplicate='+order) + testLink(bss, type) + + # Test setting the option in the SConstruct file. + test.run(arguments='duplicate='+order) + testLink(bss, type) + + # Clean up for next run. + os.unlink(bss) + +# test the default (hard-soft-copy) +if hard: type='hard' +elif soft: type='soft' +else: type='copy' +RunTest('hard-soft-copy', type, bss) + +if soft: type='soft' +elif hard: type='hard' +else: type='copy' +RunTest('soft-hard-copy', type, bss) + +if soft: type='soft' +else: type='copy' +RunTest('soft-copy', type, bss) + +if hard: type='hard' +else: type='copy' +RunTest('hard-copy', type, bss) + +type='copy' +RunTest('copy', type, bss) + +test.run(arguments='--duplicate=nonsense', status=2, stderr="""\ +usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: `nonsense' is not a valid duplication option type, try: + hard-soft-copy, soft-hard-copy, hard-copy, soft-copy, copy +""") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--experimental.py scons-4.4.0+dfsg/test/option/option--experimental.py --- scons-4.0.1+dfsg/test/option/option--experimental.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--experimental.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test the --experimental option. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.file_fixture('fixture/SConstruct__experimental', 'SConstruct') + +tests = [ + ('.', []), + ('--experimental=ninja', ['ninja']), + ('--experimental=all', ['ninja', 'transporter', 'warp_speed']), + ('--experimental=none', []), +] + +for args, exper in tests: + read_string = """All Features=ninja,transporter,warp_speed +Experimental=%s +""" % (exper) + test.run(arguments=args, + stdout=test.wrap_stdout(read_str=read_string, build_str="scons: `.' is up to date.\n")) + +test.run(arguments='--experimental=warp_drive', + stderr="""usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: option --experimental: invalid choice: 'warp_drive' (choose from 'all','none','ninja','transporter','warp_speed') +""", + status=2) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-f.py scons-4.4.0+dfsg/test/option/option-f.py --- scons-4.0.1+dfsg/test/option/option-f.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-f.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# +# 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 os + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('subdir') + +subdir_BuildThis = os.path.join('subdir', 'Buildthis') + +test.write('SConscript', """ +DefaultEnvironment(tools=[]) +import os +print("SConscript " + os.getcwd()) +""") + +test.write(subdir_BuildThis, """ +DefaultEnvironment(tools=[]) +import os +print("subdir/BuildThis "+ os.getcwd()) +""") + +test.write('Build2', """ +DefaultEnvironment(tools=[]) +import os +print("Build2 "+ os.getcwd()) +""") + +wpath = test.workpath() + +test.run( + arguments='-f SConscript .', + stdout=test.wrap_stdout( + read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + ), +) + +test.run( + arguments='-f %s .' % subdir_BuildThis, + stdout=test.wrap_stdout( + read_str='subdir/BuildThis %s\n' % wpath, + build_str="scons: `.' is up to date.\n", + ), +) + +test.run( + arguments='--file=SConscript .', + stdout=test.wrap_stdout( + read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + ), +) + +test.run( + arguments='--file=%s .' % subdir_BuildThis, + stdout=test.wrap_stdout( + read_str='subdir/BuildThis %s\n' % wpath, + build_str="scons: `.' is up to date.\n", + ), +) + +test.run( + arguments='--makefile=SConscript .', + stdout=test.wrap_stdout( + read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + ), +) + +test.run( + arguments='--makefile=%s .' % subdir_BuildThis, + stdout=test.wrap_stdout( + read_str='subdir/BuildThis %s\n' % wpath, + build_str="scons: `.' is up to date.\n", + ), +) + +test.run( + arguments='--sconstruct=SConscript .', + stdout=test.wrap_stdout( + read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + ), +) + +test.run( + arguments='--sconstruct=%s .' % subdir_BuildThis, + stdout=test.wrap_stdout( + read_str='subdir/BuildThis %s\n' % wpath, + build_str="scons: `.' is up to date.\n", + ), +) + +test.run( + arguments='-f - .', + stdin=""" +DefaultEnvironment(tools=[]) +import os +print("STDIN " + os.getcwd()) +""", + stdout=test.wrap_stdout( + read_str='STDIN %s\n' % wpath, build_str="scons: `.' is up to date.\n" + ), +) + +expect = test.wrap_stdout( + read_str='Build2 %s\nSConscript %s\n' % (wpath, wpath), + build_str="scons: `.' is up to date.\n", +) +test.run(arguments='-f Build2 -f SConscript .', stdout=expect) + +test.run( + arguments='-f no_such_file .', + stdout=test.wrap_stdout("scons: `.' is up to date.\n"), + stderr=None, +) + +expect = """ +scons: warning: Calling missing SConscript without error is deprecated. +Transition by adding must_exist=False to SConscript calls. +Missing SConscript 'no_such_file'""" +stderr = test.stderr() +test.must_contain_all(test.stderr(), expect) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-i.py scons-4.4.0+dfsg/test/option/option-i.py --- scons-4.0.1+dfsg/test/option/option-i.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-i.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# 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 os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('succeed.py', r""" +import sys + +with open(sys.argv[1], 'w') as file: + file.write("succeed.py: %s\n" % sys.argv[1]) +sys.exit(0) +""") + +test.write('fail.py', r""" +import sys + +sys.exit(1) +""") + +test.write('SConstruct', """ +Succeed = Builder(action=r'%(_python_)s succeed.py $TARGETS') +Fail = Builder(action=r'%(_python_)s fail.py $TARGETS') +env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}) +env.Fail(target='aaa.1', source='aaa.in') +env.Succeed(target='aaa.out', source='aaa.1') +env.Fail(target='bbb.1', source='bbb.in') +env.Succeed(target='bbb.out', source='bbb.1') +""" % locals()) + +test.write('aaa.in', "aaa.in\n") +test.write('bbb.in', "bbb.in\n") + +test.run( + arguments='aaa.1 aaa.out bbb.1 bbb.out', + stderr='scons: *** [aaa.1] Error 1\n', + status=2, +) + +test.fail_test(os.path.exists(test.workpath('aaa.1'))) +test.fail_test(os.path.exists(test.workpath('aaa.out'))) +test.fail_test(os.path.exists(test.workpath('bbb.1'))) +test.fail_test(os.path.exists(test.workpath('bbb.out'))) + +test.run( + arguments='-i aaa.1 aaa.out bbb.1 bbb.out', + stderr='scons: *** [aaa.1] Error 1\nscons: *** [bbb.1] Error 1\n', +) + +test.fail_test(os.path.exists(test.workpath('aaa.1'))) +test.fail_test(test.read('aaa.out',mode='r') != "succeed.py: aaa.out\n") +test.fail_test(os.path.exists(test.workpath('bbb.1'))) +test.fail_test(test.read('bbb.out',mode='r') != "succeed.py: bbb.out\n") + +test.unlink("aaa.out") +test.unlink("bbb.out") + +test.run( + arguments='--ignore-errors aaa.1 aaa.out bbb.1 bbb.out', + stderr='scons: *** [aaa.1] Error 1\nscons: *** [bbb.1] Error 1\n', +) + +test.fail_test(os.path.exists(test.workpath('aaa.1'))) +test.fail_test(test.read('aaa.out', mode='r') != "succeed.py: aaa.out\n") +test.fail_test(os.path.exists(test.workpath('bbb.1'))) +test.fail_test(test.read('bbb.out', mode='r') != "succeed.py: bbb.out\n") + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--I.py scons-4.4.0+dfsg/test/option/option--I.py --- scons-4.0.1+dfsg/test/option/option--I.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--I.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,67 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('sub1', 'sub2') + +test.write(['sub1', 'foo.py'], """ +variable = "sub1/foo" +""") + +test.write(['sub2', 'foo.py'], """ +variable = "sub2/foo" +""") + +test.write(['sub2', 'bar.py'], """ +variable = "sub2/bar" +""") + +test.write('SConstruct', """ +import foo +print(foo.variable) +import bar +print(bar.variable) +""") + +test.run(arguments = '-I sub1 -I sub2 .', + stdout = test.wrap_stdout(read_str = 'sub1/foo\nsub2/bar\n', + build_str = "scons: `.' is up to date.\n")) + +test.run(arguments = '--include-dir=sub2 --include-dir=sub1 .', + stdout = test.wrap_stdout(read_str = 'sub2/foo\nsub2/bar\n', + build_str = "scons: `.' is up to date.\n")) + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-j.py scons-4.4.0+dfsg/test/option/option-j.py --- scons-4.0.1+dfsg/test/option/option-j.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-j.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,230 @@ +#!/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. +# + +""" +This tests the -j command line option, and the num_jobs +SConscript settable option. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path +import sys + +import TestSCons + + +_python_ = TestSCons._python_ + +try: + import threading +except ImportError: + # if threads are not supported, then + # there is nothing to test + TestCmd.no_result() + sys.exit() + + +test = TestSCons.TestSCons() + +test.write('build.py', r""" +import time +import sys +with open(sys.argv[1], 'w') as f: + f.write(str(time.time()) + '\n') + time.sleep(1) + f.write(str(time.time())) +""") + +test.subdir('foo') + +test.write(['foo','foo.in'], r""" +foo you +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS') +env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) +env.Tool('install') +env.MyBuild(target='f1', source='f1.in') +env.MyBuild(target='f2', source='f2.in') + +def copyn(env, target, source): + import shutil + import time + time.sleep(1) + for t in target: + shutil.copy(str(source[0]), str(t)) + +t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], + source='foo/foo.in', + action=copyn) +env.Install('out', t) +""" % locals()) + +def RunTest(args, extra): + """extra is used to make scons rebuild the output file""" + test.write('f1.in', 'f1.in'+extra) + test.write('f2.in', 'f2.in'+extra) + + test.run(arguments = args) + + str = test.read("f1", mode='r') + start1,finish1 = list(map(float, str.split("\n"))) + + str = test.read("f2", mode='r') + start2,finish2 = list(map(float, str.split("\n"))) + + return start2, finish1 + +# Test 2 parallel jobs. +# fail if the second file was not started +# before the first one was finished. +start2, finish1 = RunTest('-j 2 f1 f2', "first") +test.fail_test(not (start2 < finish1)) + +# re-run the test with the same input, fail if we don't +# get back the same times, which would indicate that +# SCons rebuilt the files even though nothing changed +s2, f1 = RunTest('-j 2 f1 f2', "first") +test.fail_test(start2 != s2) +test.fail_test(finish1 != f1) + +# Test a single serial job. +# fail if the second file was started +# before the first one was finished +start2, finish1 = RunTest('f1 f2', "second") +test.fail_test(start2 < finish1) + +# Make sure that a parallel build using a list builder +# succeeds. +test.run(arguments='-j 2 out') + +if sys.platform != 'win32' and sys.version_info[0] == 2: + # Test breaks on win32 when using real subprocess is not the only + # package to import threading + # + # Test that we fall back and warn properly if there's no threading.py + # module (simulated), which is the case if this version of Python wasn't + # built with threading support. + + test.subdir('pythonlib') + + test.write(['pythonlib', 'threading.py'], "raise ImportError\n") + + save_pythonpath = os.environ.get('PYTHONPATH', '') + os.environ['PYTHONPATH'] = test.workpath('pythonlib') + + #start2, finish1 = RunTest('-j 2 f1, f2', "fifth") + + test.write('f1.in', 'f1.in pythonlib\n') + test.write('f2.in', 'f2.in pythonlib\n') + + test.run(arguments = "-j 2 f1 f2", stderr=None) + + warn = """scons: warning: parallel builds are unsupported by this version of Python; +\tignoring -j or num_jobs option.""" + test.must_contain_all_lines(test.stderr(), [warn]) + + str = test.read("f1", mode='r') + start1,finish1 = list(map(float, str.split("\n"))) + + str = test.read("f2", mode='r') + start2,finish2 = list(map(float, str.split("\n"))) + + test.fail_test(start2 < finish1) + + os.environ['PYTHONPATH'] = save_pythonpath + + +# Test SetJobs() with no -j: +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS') +env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) +env.Tool('install') +env.MyBuild(target = 'f1', source = 'f1.in') +env.MyBuild(target = 'f2', source = 'f2.in') + +def copyn(env, target, source): + import shutil + import time + time.sleep(1) + for t in target: + shutil.copy(str(source[0]), str(t)) + +t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn) +env.Install('out', t) + +assert GetOption('num_jobs') == 1 +SetOption('num_jobs', 2) +assert GetOption('num_jobs') == 2 +""" % locals()) + +# This should be a parallel build because the SConscript sets jobs to 2. +# fail if the second file was not started +# before the first one was finished +start2, finish1 = RunTest('f1 f2', "third") +test.fail_test(not (start2 < finish1)) + +# Test SetJobs() with -j: +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS') +env = Environment(BUILDERS = {'MyBuild': MyBuild}, tools=[]) +env.Tool('install') +env.MyBuild(target='f1', source='f1.in') +env.MyBuild(target='f2', source='f2.in') + +def copyn(env, target, source): + import shutil + import time + time.sleep(1) + for t in target: + shutil.copy(str(source[0]), str(t)) + +t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn) +env.Install('out', t) + +assert GetOption('num_jobs') == 1 +SetOption('num_jobs', 2) +assert GetOption('num_jobs') == 1 +""" % locals()) + +# This should be a serial build since -j 1 overrides the call to SetJobs(). +# fail if the second file was started +# before the first one was finished +start2, finish1 = RunTest('-j 1 f1 f2', "fourth") +test.fail_test(start2 < finish1) + + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-k.py scons-4.4.0+dfsg/test/option/option-k.py --- scons-4.0.1+dfsg/test/option/option-k.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-k.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,313 @@ +#!/usr/bin/env python +# +# 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 TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.subdir('work1', 'work2', 'work3') + +test.write('succeed.py', r""" +import sys + +with open(sys.argv[1], 'w') as file: + file.write("succeed.py: %s\n" % sys.argv[1]) +sys.exit(0) +""") + +test.write('fail.py', r""" +import sys + +sys.exit(1) +""") + + +# +# Test: work1 +# + +test.write(['work1', 'SConstruct'], """\ +DefaultEnvironment(tools=[]) +Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS') +Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS') +env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[]) +env.Fail(target='aaa.1', source='aaa.in') +env.Succeed(target='aaa.out', source='aaa.1') +env.Succeed(target='bbb.out', source='bbb.in') +""" % locals()) + +test.write(['work1', 'aaa.in'], "aaa.in\n") +test.write(['work1', 'bbb.in'], "bbb.in\n") + +test.run( + chdir='work1', + arguments='aaa.out bbb.out', + stderr='scons: *** [aaa.1] Error 1\n', + status=2, +) + +test.must_not_exist(test.workpath('work1', 'aaa.1')) +test.must_not_exist(test.workpath('work1', 'aaa.out')) +test.must_not_exist(test.workpath('work1', 'bbb.out')) + +test.run( + chdir='work1', + arguments='-k aaa.out bbb.out', + stderr='scons: *** [aaa.1] Error 1\n', + status=2, +) + +test.must_not_exist(test.workpath('work1', 'aaa.1')) +test.must_not_exist(test.workpath('work1', 'aaa.out')) +test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r') + +test.unlink(['work1', 'bbb.out']) + +test.run( + chdir='work1', + arguments='--keep-going aaa.out bbb.out', + stderr='scons: *** [aaa.1] Error 1\n', + status=2, +) + +test.must_not_exist(test.workpath('work1', 'aaa.1')) +test.must_not_exist(test.workpath('work1', 'aaa.out')) +test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r') + +expect = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Cleaning targets ... +Removed bbb.out +scons: done cleaning targets. +""" + +test.run(chdir='work1', + arguments='--clean --keep-going aaa.out bbb.out', + stdout=expect) + +test.must_not_exist(test.workpath('work1', 'aaa.1')) +test.must_not_exist(test.workpath('work1', 'aaa.out')) +test.must_not_exist(test.workpath('work1', 'bbb.out')) + + + +# +# Test: work2 +# + +test.write(['work2', 'SConstruct'], """\ +DefaultEnvironment(tools=[]) +Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS') +Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS') +env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[]) +env.Fail('aaa.out', 'aaa.in') +env.Succeed('bbb.out', 'aaa.out') +env.Succeed('ccc.out', 'ccc.in') +env.Succeed('ddd.out', 'ccc.in') +""" % locals()) + +test.write(['work2', 'aaa.in'], "aaa.in\n") +test.write(['work2', 'ccc.in'], "ccc.in\n") + +test.run( + chdir='work2', + arguments='-k .', + status=2, + stderr=None, + stdout="""\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +%(_python_)s ../fail.py aaa.out +%(_python_)s ../succeed.py ccc.out +%(_python_)s ../succeed.py ddd.out +scons: done building targets (errors occurred during build). +""" + % locals(), +) + +test.must_not_exist(['work2', 'aaa.out']) +test.must_not_exist(['work2', 'bbb.out']) +test.must_match(['work2', 'ccc.out'], "succeed.py: ccc.out\n", mode='r') +test.must_match(['work2', 'ddd.out'], "succeed.py: ddd.out\n", mode='r') + + + +# +# Test: work3 +# +# Check that the -k (keep-going) switch works correctly when the Nodes +# forms a DAG. The test case is the following +# +# all +# | +# +-----+-----+-------------+ +# | | | +# a1 a2 a3 +# | | | +# + +---+---+ +---+---+ +# \ | / | | +# \ bbb.out / a4 ccc.out +# \ / / +# \ / / +# \ / / +# aaa.out (fails) +# + +test.write(['work3', 'SConstruct'], """\ +DefaultEnvironment(tools=[]) +Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS') +Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS') +env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[]) +a = env.Fail('aaa.out', 'aaa.in') +b = env.Succeed('bbb.out', 'bbb.in') +c = env.Succeed('ccc.out', 'ccc.in') + +a1 = Alias('a1', a) +a2 = Alias('a2', a + b) +a4 = Alias('a4', c) +a3 = Alias('a3', a4 + c) + +Alias('all', a1 + a2 + a3) +""" % locals()) + +test.write(['work3', 'aaa.in'], "aaa.in\n") +test.write(['work3', 'bbb.in'], "bbb.in\n") +test.write(['work3', 'ccc.in'], "ccc.in\n") + + +# Test tegular build (i.e. without -k) +test.run( + chdir='work3', + arguments='.', + status=2, + stderr=None, + stdout="""\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +%(_python_)s ../fail.py aaa.out +scons: building terminated because of errors. +""" + % locals(), +) + +test.must_not_exist(['work3', 'aaa.out']) +test.must_not_exist(['work3', 'bbb.out']) +test.must_not_exist(['work3', 'ccc.out']) + +test.run(chdir='work3', arguments='-c .') +test.must_not_exist(['work3', 'aaa.out']) +test.must_not_exist(['work3', 'bbb.out']) +test.must_not_exist(['work3', 'ccc.out']) + +# Current directory +test.run( + chdir='work3', + arguments='-k .', + status=2, + stderr=None, + stdout="""\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +%(_python_)s ../fail.py aaa.out +%(_python_)s ../succeed.py bbb.out +%(_python_)s ../succeed.py ccc.out +scons: done building targets (errors occurred during build). +""" + % locals(), +) + +test.must_not_exist(['work3', 'aaa.out']) +test.must_exist(['work3', 'bbb.out']) +test.must_exist(['work3', 'ccc.out']) + +test.run(chdir='work3', arguments='-c .') +test.must_not_exist(['work3', 'aaa.out']) +test.must_not_exist(['work3', 'bbb.out']) +test.must_not_exist(['work3', 'ccc.out']) + + +# Single target +test.run( + chdir='work3', + arguments='--keep-going all', + status=2, + stderr=None, + stdout="""\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +%(_python_)s ../fail.py aaa.out +%(_python_)s ../succeed.py bbb.out +%(_python_)s ../succeed.py ccc.out +scons: done building targets (errors occurred during build). +""" + % locals(), +) + +test.must_not_exist(['work3', 'aaa.out']) +test.must_exist(['work3', 'bbb.out']) +test.must_exist(['work3', 'ccc.out']) + +test.run(chdir='work3', arguments='-c .') +test.must_not_exist(['work3', 'aaa.out']) +test.must_not_exist(['work3', 'bbb.out']) +test.must_not_exist(['work3', 'ccc.out']) + +# Separate top-level targets +test.run( + chdir='work3', + arguments='-k a1 a2 a3', + status=2, + stderr=None, + stdout="""\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +%(_python_)s ../fail.py aaa.out +%(_python_)s ../succeed.py bbb.out +%(_python_)s ../succeed.py ccc.out +scons: done building targets (errors occurred during build). +""" + % locals(), +) + +test.must_not_exist(['work3', 'aaa.out']) +test.must_exist(['work3', 'bbb.out']) +test.must_exist(['work3', 'ccc.out']) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--la.py scons-4.4.0+dfsg/test/option/option--la.py --- scons-4.0.1+dfsg/test/option/option--la.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--la.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--list-actions', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--ld.py scons-4.4.0+dfsg/test/option/option--ld.py --- scons-4.0.1+dfsg/test/option/option--ld.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--ld.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--list-derived', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-l.py scons-4.4.0+dfsg/test/option/option-l.py --- scons-4.0.1+dfsg/test/option/option-l.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-l.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,45 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('-l', '1 .') + +test.option_not_yet_implemented('--load-average', '=1 .') + +test.option_not_yet_implemented('--max-load', '=1 .') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--lw.py scons-4.4.0+dfsg/test/option/option--lw.py --- scons-4.0.1+dfsg/test/option/option--lw.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--lw.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--list-where', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--max-drift.py scons-4.4.0+dfsg/test/option/option--max-drift.py --- scons-4.0.1+dfsg/test/option/option--max-drift.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--max-drift.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,129 @@ +#!/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__" + +import os + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('build.py', r""" +import sys +with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp: + f.write(ifp.read()) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS = { 'B' : B }, tools=[]) +env.B(target = 'f1.out', source = 'f1.in') +env.B(target = 'f2.out', source = 'f2.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") + + + +test.run(arguments = 'f1.out') + +test.run(arguments = 'f1.out f2.out', + stdout = test.wrap_stdout( +"""scons: `f1.out' is up to date. +%(_python_)s build.py f2.out f2.in +""" % locals())) + +atime = os.path.getatime(test.workpath('f1.in')) +mtime = os.path.getmtime(test.workpath('f1.in')) + +test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out') + +test.write('f1.in', "f1.in delta\n") +os.utime(test.workpath('f1.in'), (atime,mtime)) + +test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out') + +expect = test.wrap_stdout( +"""%(_python_)s build.py f1.out f1.in +scons: `f2.out' is up to date. +""" % locals()) + +test.run(arguments = '--max-drift=-1 f1.out f2.out', stdout = expect) + +# Test that Set/GetOption('max_drift') works: +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +assert GetOption('max_drift') == 2*24*60*60 +SetOption('max_drift', 1) +assert GetOption('max_drift') == 1 +""") + +test.run() + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +assert GetOption('max_drift') == 1 +SetOption('max_drift', 10) +assert GetOption('max_drift') == 1 +""") + +test.run(arguments='--max-drift=1') + +# Test that SetOption('max_drift') actually sets max_drift +# by mucking with the file timestamps to make SCons not realize the source has changed +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +SetOption('max_drift', 0) +B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS = { 'B' : B }, tools=[]) +env.B(target = 'foo.out', source = 'foo.in') +""" % locals()) + +test.write('foo.in', 'foo.in\n') + +atime = os.path.getatime(test.workpath('foo.in')) +mtime = os.path.getmtime(test.workpath('foo.in')) + +test.run() +test.must_match('foo.out', 'foo.in\n', mode='r') + +test.write('foo.in', 'foo.in delta\n') +os.utime(test.workpath('foo.in'), (atime,mtime)) + +test.run() + +test.must_match('foo.out', 'foo.in\n', mode='r') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-m.py scons-4.4.0+dfsg/test/option/option-m.py --- scons-4.0.1+dfsg/test/option/option-m.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-m.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,43 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments = '-m .', + stderr = "Warning: ignoring -m option\n") + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-n.py scons-4.4.0+dfsg/test/option/option-n.py --- scons-4.0.1+dfsg/test/option/option-n.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-n.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,254 @@ +#!/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. +# + +""" +This test verifies: + 1) that we don't build files when we use the -n, --no-exec, + --just-print, --dry-run, and --recon options; + 2) that we don't remove built files when -n is used in + conjunction with -c; + 3) that files installed by the Install() method don't get + installed when -n is used; + 4) that source files don't get duplicated in a VariantDir + when -n is used. + 5) that Configure calls don't build any files. If a file + needs to be built (i.e. is not up-to-date), a ConfigureError + is raised. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os +import re + +import TestSCons +from SCons.Util import get_current_hash_algorithm_used + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.subdir('build', 'src') + +test.write('build.py', r""" +import sys +with open(sys.argv[1], 'w') as ofp: + ofp.write("build.py: %s\n" % sys.argv[1]) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS') +env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) +env.Tool('install') +env.MyBuild(target='f1.out', source='f1.in') +env.MyBuild(target='f2.out', source='f2.in') +env.Install('install', 'f3.in') +VariantDir('build', 'src', duplicate=1) +SConscript('build/SConscript', "env") +""" % locals()) + +test.write(['src', 'SConscript'], """ +Import("env") +env.MyBuild(target='f4.out', source='f4.in') +""") + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write('f3.in', "f3.in\n") +test.write(['src', 'f4.in'], "src/f4.in\n") + +args = 'f1.out f2.out' +expect = test.wrap_stdout("""\ +%(_python_)s build.py f1.out +%(_python_)s build.py f2.out +""" % locals()) + +test.run(arguments=args, stdout=expect) +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +test.unlink('f1.out') +test.unlink('f2.out') + +test.run(arguments='-n ' + args, stdout=expect) +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + +test.run(arguments='--no-exec ' + args, stdout=expect) +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + +test.run(arguments='--just-print ' + args, stdout=expect) +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + +test.run(arguments='--dry-run ' + args, stdout=expect) +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + +test.run(arguments='--recon ' + args, stdout=expect) +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + +test.run(arguments=args) +test.fail_test(not os.path.exists(test.workpath('f1.out'))) + +# Test that SCons does not write a modified .sconsign when -n is used. +expect = test.wrap_stdout("""\ +%(_python_)s build.py f1.out +""" % locals()) +test.unlink(test.get_sconsignname()+'.dblite') +test.write('f1.out', "X1.out\n") +test.run(arguments='-n f1.out', stdout=expect) +test.run(arguments='-n f1.out', stdout=expect) + +expect = test.wrap_stdout("Removed f1.out\nRemoved f2.out\n", cleaning=1) + +test.run(arguments='-n -c ' + args, stdout=expect) + +test.run(arguments='-c -n ' + args, stdout=expect) + +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +# +install_f3_in = os.path.join('install', 'f3.in') +expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in) + +test.run(arguments='-n install', stdout=expect) +test.fail_test(os.path.exists(test.workpath('install', 'f3.in'))) + +test.run(arguments='install', stdout=expect) +test.fail_test(not os.path.exists(test.workpath('install', 'f3.in'))) + +test.write('f3.in', "f3.in again\n") + +test.run(arguments='-n install', stdout=expect) +test.fail_test(not os.path.exists(test.workpath('install', 'f3.in'))) + +# Make sure duplicate source files in a VariantDir aren't created +# when the -n option is used. + +# First, make sure none of the previous non-dryrun invocations caused +# the build directory to be populated. Processing of the +# src/SConscript (actually build/SConscript) will reference f4.in as a +# source, causing a Node object to be built for "build/f4.in". +# Creating the node won't cause "build/f4.in" to be created from +# "src/f4.in", but that *is* a side-effect of calling the exists() +# method on that node, which may happen via other processing. +# Therefore add this conditional removal to ensure a clean setting +# before running this test. + +if os.path.exists(test.workpath('build', 'f4.in')): + test.unlink(test.workpath('build', 'f4.in')) + +test.run(arguments='-n build') +test.fail_test(os.path.exists(test.workpath('build', 'f4.in'))) + +# test Configure-calls in conjunction with -n +test.subdir('configure') +test.set_match_function(TestSCons.match_re_dotall) +test.set_diff_function(TestSCons.diff_re) +test.write('configure/SConstruct', """\ +DefaultEnvironment(tools=[]) +def CustomTest(context): + def userAction(target,source,env): + import shutil + shutil.copyfile( str(source[0]), str(target[0])) + def strAction(target,source,env): + return "cp " + str(source[0]) + " " + str(target[0]) + context.Message("Executing Custom Test ... " ) + (ok, msg) = context.TryAction(Action(userAction,strAction), + "Hello World", ".in") + context.Result(ok) + return ok + +env = Environment(tools=[]) +conf = Configure(env, + custom_tests={'CustomTest':CustomTest}, + conf_dir="config.test", + log_file="config.log") +if not conf.CustomTest(): + Exit(1) +else: + env = conf.Finish() +""") +# test that conf_dir isn't created and an error is raised +stderr = r""" +scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\. +File \S+, line \S+, in \S+ +""" +test.run(arguments="-n", stderr=stderr, status=2, + chdir=test.workpath("configure")) +test.fail_test(os.path.exists(test.workpath("configure", "config.test"))) +test.fail_test(os.path.exists(test.workpath("configure", "config.log"))) + + +# depending on which default hash function we're using, we'd expect one of the following filenames. +# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files +possible_filenames = { + 'md5': "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in", + 'sha1': "conftest_0a4d55a8d778e5022fab701977c5d840bbc486d0_0.in", + 'sha256': "conftest_a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e_0.in" +} +test_filename = possible_filenames[get_current_hash_algorithm_used()] + +# test that targets are not built, if conf_dir exists. +# verify that .cache and config.log are not created. +# an error should be raised +stderr = r""" +scons: \*\*\* Cannot update configure test "%s" within a dry-run\. +File \S+, line \S+, in \S+ +""" % re.escape(os.path.join("config.test", test_filename)) +test.subdir(['configure', 'config.test']) +test.run(arguments="-n", stderr=stderr, status=2, + chdir=test.workpath("configure")) +test.fail_test(os.path.exists(test.workpath("configure", "config.test", + ".cache"))) +test.fail_test(os.path.exists(test.workpath("configure", "config.test", + "conftest_0"))) +test.fail_test(os.path.exists(test.workpath("configure", "config.test", + "conftest_0.in"))) +test.fail_test(os.path.exists(test.workpath("configure", "config.log"))) + +# test that no error is raised, if all targets are up-to-date. In this +# case .cache and config.log shouldn't be created +stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", + read_str=r"""Executing Custom Test ... \(cached\) yes +""") +test.run(status=0, chdir=test.workpath("configure")) +log1_mtime = os.path.getmtime(test.workpath("configure", "config.log")) +test.run(stdout=stdout, arguments="-n", status=0, + chdir=test.workpath("configure")) +log2_mtime = os.path.getmtime(test.workpath("configure", "config.log")) +test.fail_test(log1_mtime != log2_mtime) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-o.py scons-4.4.0+dfsg/test/option/option-o.py --- scons-4.0.1+dfsg/test/option/option-o.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-o.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,45 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('-o', 'foo .') + +test.option_not_yet_implemented('--old-file', '=foo .') + +test.option_not_yet_implemented('--assume-old', '=foo .') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--override.py scons-4.4.0+dfsg/test/option/option--override.py --- scons-4.0.1+dfsg/test/option/option--override.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--override.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--override', '=foo .') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-p.py scons-4.4.0+dfsg/test/option/option-p.py --- scons-4.0.1+dfsg/test/option/option-p.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-p.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('-p', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option_profile.py scons-4.4.0+dfsg/test/option/option_profile.py --- scons-4.0.1+dfsg/test/option/option_profile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option_profile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -21,9 +23,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 contextlib import sys from io import StringIO @@ -47,7 +46,7 @@ scons_prof = test.workpath('scons.prof') test.run(arguments = "--profile=%s -h" % scons_prof) -test.must_contain_all_lines(test.stdout(), ['usage: scons [OPTION]']) +test.must_contain_all_lines(test.stdout(), ['usage: scons [OPTIONS] [VARIABLES] [TARGETS]']) try: save_stdout = sys.stdout @@ -89,7 +88,7 @@ test.run(arguments = "--profile %s --debug=memory -h" % scons_prof) expect = [ - 'usage: scons [OPTION]', + 'usage: scons [OPTIONS] [VARIABLES] [TARGETS]', 'Options:' ] test.must_contain_all_lines(test.stdout(), expect) diff -Nru scons-4.0.1+dfsg/test/option/option--.py scons-4.4.0+dfsg/test/option/option--.py --- scons-4.0.1+dfsg/test/option/option--.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# 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 os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('build.py', r""" +import sys + +with open(sys.argv[1], 'w') as file: + file.write("build.py: %s\n" % sys.argv[1]) +sys.exit(0) +""") + +test.write('SConstruct', """ +MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS') +env = Environment(BUILDERS={'MyBuild': MyBuild}) +env.MyBuild(target='-f1.out', source='f1.in') +env.MyBuild(target='-f2.out', source='f2.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") + +expect = test.wrap_stdout('%(_python_)s build.py -f1.out\n%(_python_)s build.py -f2.out\n' % locals()) + +test.run(arguments='-- -f1.out -f2.out', stdout=expect) + +test.fail_test(not os.path.exists(test.workpath('-f1.out'))) +test.fail_test(not os.path.exists(test.workpath('-f2.out'))) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--Q.py scons-4.4.0+dfsg/test/option/option--Q.py --- scons-4.0.1+dfsg/test/option/option--Q.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--Q.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# +# 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 os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + + +test.write('build.py', r""" +import sys + +with open(sys.argv[1], 'w') as file: + file.write("build.py: %s\n" % sys.argv[1]) +sys.exit(0) +""") + +test.write('SConstruct', """ +AddOption('--use_SetOption', action='store_true', dest='setoption', default=False) + +use_setoption = GetOption('setoption') + +if use_setoption: + SetOption('no_progress', True) + +MyBuild = Builder(action=r'%(_python_)s build.py $TARGET') +env = Environment(BUILDERS={'MyBuild': MyBuild}) +env.MyBuild(target='f1.out', source='f1.in') +env.MyBuild(target='f2.out', source='f2.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") + +test.run(arguments = '-Q f1.out f2.out', stdout = """\ +%(_python_)s build.py f1.out +%(_python_)s build.py f2.out +""" % locals()) +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +# Make sure -q doesn't suppress other messages, too. +test.run(arguments = '-Q -c f1.out f2.out', stdout = """\ +Removed f1.out +Removed f2.out +""") +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(os.path.exists(test.workpath('f2.out'))) + + +# When set via a SetOption, it will happen after the initial output of +# scons: Reading SConscript files ... +# but remaining status/progress output will not be output +test.run(arguments = '--use_SetOption f1.out f2.out', stdout = """\ +scons: Reading SConscript files ... +%(_python_)s build.py f1.out +%(_python_)s build.py f2.out +""" % locals()) +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--random.py scons-4.4.0+dfsg/test/option/option--random.py --- scons-4.0.1+dfsg/test/option/option--random.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--random.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,121 @@ +#!/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. + +""" +Verify that we build correctly using the --random option. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConscript', """\ +def cat(env, source, target): + target = str(target[0]) + with open(target, "wb") as f: + for src in source: + with open(str(src), "rb") as ifp: + f.write(ifp.read()) +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +""") + +test.write('aaa.in', "aaa.in\n") +test.write('bbb.in', "bbb.in\n") +test.write('ccc.in', "ccc.in\n") + + + +test.write('SConstruct', """\ +SetOption('random', 1) +SConscript('SConscript') +""") + +test.run(arguments = '-n -Q') +non_random_output = test.stdout() + +tries = 0 +max_tries = 10 +while test.stdout() == non_random_output: + if tries >= max_tries: + print("--random generated the non-random output %s times!" % max_tries) + test.fail_test() + tries = tries + 1 + test.run(arguments = '-n -Q --random') + + + +test.write('SConstruct', """\ +SConscript('SConscript') +""") + +test.run(arguments = '-n -Q') +non_random_output = test.stdout() + +tries = 0 +max_tries = 10 +while test.stdout() == non_random_output: + if tries >= max_tries: + print("--random generated the non-random output %s times!" % max_tries) + test.fail_test() + tries = tries + 1 + test.run(arguments = '-n -Q --random') + + + +test.run(arguments = '-Q --random') + +test.must_match('all', "aaa.in\nbbb.in\nccc.in\n") + +test.run(arguments = '-q --random .') + +test.run(arguments = '-c --random .') + +test.must_not_exist(test.workpath('aaa.out')) +test.must_not_exist(test.workpath('bbb.out')) +test.must_not_exist(test.workpath('ccc.out')) +test.must_not_exist(test.workpath('all')) + +test.run(arguments = '-q --random .', status = 1) + +test.run(arguments = '--random .') + +test.must_match('all', "aaa.in\nbbb.in\nccc.in\n") + +test.run(arguments = '-c --random .') + + + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-r.py scons-4.4.0+dfsg/test/option/option-r.py --- scons-4.0.1+dfsg/test/option/option-r.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-r.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,43 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('-r', '.') + +test.option_not_yet_implemented('--no-builtin-rules', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--R.py scons-4.4.0+dfsg/test/option/option--R.py --- scons-4.0.1+dfsg/test/option/option--R.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--R.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,43 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('-R', '.') + +test.option_not_yet_implemented('--no-builtin-variables', '.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-s.py scons-4.4.0+dfsg/test/option/option-s.py --- scons-4.0.1+dfsg/test/option/option-s.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-s.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# 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 os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('build.py', r""" +import sys + +with open(sys.argv[1], 'w') as file: + file.write("build.py: %s\n" % sys.argv[1]) +sys.exit(0) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +MyBuild = Builder(action=r'%(_python_)s build.py $TARGET') + +silent = ARGUMENTS.get('QUIET', 0) +if silent: + SetOption('silent', True) + +env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) +env.MyBuild(target='f1.out', source='f1.in') +env.MyBuild(target='f2.out', source='f2.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") + +test.run(arguments='-s f1.out f2.out', stdout="") +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +test.unlink('f1.out') +test.unlink('f2.out') + +test.run(arguments='--silent f1.out f2.out', stdout="") +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +test.unlink('f1.out') +test.unlink('f2.out') + +test.run(arguments='--quiet f1.out f2.out', stdout="") +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +# -C should also be quiet Issue#2796 +test.subdir( 'sub' ) +test.write(['sub','SConstruct'],"") +test.run(arguments='-s -C sub', stdout="" ) + +test.unlink('f1.out') +test.unlink('f2.out') + +test.run(arguments='QUIET=1 f1.out f2.out', + stdout="scons: Reading SConscript files ...\nscons: done reading SConscript files.\n") +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--S.py scons-4.4.0+dfsg/test/option/option--S.py --- scons-4.0.1+dfsg/test/option/option--S.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--S.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments = '-S .', stderr = "Warning: ignoring -S option\n") + +test.run(arguments = '--no-keep-going .', + stderr = "Warning: ignoring --no-keep-going option\n") + +test.run(arguments = '--stop .', stderr = "Warning: ignoring --stop option\n") + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-t.py scons-4.4.0+dfsg/test/option/option-t.py --- scons-4.0.1+dfsg/test/option/option-t.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-t.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,46 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments = '-t .', + stderr = "Warning: ignoring -t option\n") + +test.run(arguments = '--touch .', + stderr = "Warning: ignoring --touch option\n") + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--tree.py scons-4.4.0+dfsg/test/option/option--tree.py --- scons-4.0.1+dfsg/test/option/option--tree.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--tree.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# 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 TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments='-Q --tree=prune', + stdout="""scons: `.' is up to date. ++-. + +-SConstruct +""") + +test.run(arguments='-Q --tree=foofoo', + stderr="""usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: `foofoo' is not a valid --tree option type, try: + all, derived, prune, status, linedraw +""", + status=2) + + +# Test that unicode characters can be printed (escaped) with the --tree option +test.write('SConstruct', """\ +env = Environment() +env.Tool("textfile") +name = "français" +env.Textfile("Foo", name) +""") + +uchar = chr(0xe7) + +expected = """Creating 'Foo.txt' ++-. + +-Foo.txt + | +-fran%sais + +-SConstruct +""" % uchar + +test.run(arguments='-Q --tree=all', stdout=expected, status=0) + +# Test the "linedraw" option: same basic test as previous. +# With "--tree=linedraw" must default to "all", and use line-drawing chars. +test.write('SConstruct', """\ +env = Environment() +env.Tool("textfile") +name = "français" +env.Textfile("LineDraw", name) +""") + +expected = """Creating 'LineDraw.txt' +└─┬. + ├─┬LineDraw.txt + │ └─fran%sais + └─SConstruct +""" % uchar + + +test.run(arguments='-Q --tree=linedraw', stdout=expected, status=0) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-unknown.py scons-4.4.0+dfsg/test/option/option-unknown.py --- scons-4.0.1+dfsg/test/option/option-unknown.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-unknown.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# 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 TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.run(arguments = '-Z', + stderr = """usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: no such option: -Z +""", + status = 2) + +test.run(arguments = '--ZizzerZazzerZuzz', + stderr = """usage: scons [OPTIONS] [VARIABLES] [TARGETS] + +SCons Error: no such option: --ZizzerZazzerZuzz +""", + status = 2) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option-v.py scons-4.4.0+dfsg/test/option/option-v.py --- scons-4.0.1+dfsg/test/option/option-v.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option-v.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,64 @@ +#!/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__" + +import TestCmd +import TestSCons + +test = TestSCons.TestSCons(match = TestCmd.match_re) + +test.write('SConstruct', "") + +# Standard copyright marker is mangled so it doesn't get replaced +# by the packaging build. +copyright_line = """\ +(_{2}COPYRIGHT__|Copyright \\(c\\) 2001[-\\d, ]+ The SCons Foundation) +""" + + +expect2 = r"""SCons by Steven Knight et al.: +\tSCons: v\S+, [^,]*,[^,]*, by \S+ on \S+ +\tSCons path: \[.*\] +""" + copyright_line + +test.run(arguments = '-v') +stdout = test.stdout() +if not test.match_re(stdout, expect2): + print(stdout) + test.fail_test() + +test.run(arguments = '--version') +stdout = test.stdout() +if not test.match_re(stdout, expect2): + print(stdout) + test.fail_test() + +test.pass_test() + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--wf.py scons-4.4.0+dfsg/test/option/option--wf.py --- scons-4.0.1+dfsg/test/option/option--wf.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--wf.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,41 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--write-filenames', '=FILE .') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--W.py scons-4.4.0+dfsg/test/option/option--W.py --- scons-4.0.1+dfsg/test/option/option--W.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--W.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,49 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +""") + +test.option_not_yet_implemented('-W', 'foo .') + +test.option_not_yet_implemented('--what-if', '=foo .') + +test.option_not_yet_implemented('--new-file', '=foo .') + +test.option_not_yet_implemented('--assume-new', '=foo .') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--wuv.py scons-4.4.0+dfsg/test/option/option--wuv.py --- scons-4.0.1+dfsg/test/option/option--wuv.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--wuv.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,49 @@ +#!/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__" + +import TestSCons + +test = TestSCons.TestSCons() + +# We want to preserve the --warn-undefined-variables option for +# compatibility with GNU Make. Unfortunately, this conflicts with +# the --warn=type option that we're using for our own warning +# control. The getopt module reports "--warn not a unique prefix" +# when both are defined. We may be able to support both in the +# future with a more robust getopt solution. +test.pass_test() #XXX Short-circuit until then. + +test.write('SConstruct', "") + +test.option_not_yet_implemented('--warn-undefined-variables') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/option--Y.py scons-4.4.0+dfsg/test/option/option--Y.py --- scons-4.0.1+dfsg/test/option/option--Y.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/option--Y.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# 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 sys + +from TestSCons import TestSCons, _exe + +test = TestSCons() + +test.subdir('repository', 'work1') + +repository = test.workpath('repository') +repository_foo_c = test.workpath('repository', 'foo.c') +work1_foo = test.workpath('work1', 'foo' + _exe) +work1_foo_c = test.workpath('work1', 'foo.c') + +test.write(['repository', 'SConstruct'], r""" +env = Environment() +env.Program(target= 'foo', source = Split('aaa.c bbb.c foo.c')) +""") + +test.write(['repository', 'aaa.c'], r""" +#include +void +aaa(void) +{ + printf("repository/aaa.c\n"); +} +""") + +test.write(['repository', 'bbb.c'], r""" +#include +void +bbb(void) +{ + printf("repository/bbb.c\n"); +} +""") + +test.write(['repository', 'foo.c'], r""" +#include +#include +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("repository/foo.c\n"); + exit (0); +} +""") + +opts = '-Y ' + repository + +# Make the entire repository non-writable, so we'll detect +# if we try to write into it accidentally. +test.writable('repository', 0) + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """repository/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.write(['work1', 'bbb.c'], r""" +#include +#include +void +bbb(void) +{ + printf("work1/bbb.c\n"); +} +""") + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """repository/aaa.c +work1/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.write(['work1', 'aaa.c'], r""" +#include +#include +void +aaa(void) +{ + printf("work1/aaa.c\n"); +} +""") + +test.write(['work1', 'foo.c'], r""" +#include +#include +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("work1/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """work1/aaa.c +work1/bbb.c +work1/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.unlink(['work1', 'bbb.c']) +test.unlink(['work1', 'foo.c']) + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """work1/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + + + +# +test.subdir('r.NEW', 'r.OLD', 'work2') + +workpath_r_NEW = test.workpath('r.NEW') +workpath_r_OLD = test.workpath('r.OLD') +work2_foo = test.workpath('work2', 'foo' + _exe) + +SConstruct = """ +env = Environment() +env.Program(target = 'foo', source = 'foo.c') +""" + +test.write(['r.OLD', 'SConstruct'], SConstruct) + +test.write(['r.NEW', 'SConstruct'], SConstruct) + +test.write(['r.OLD', 'foo.c'], r""" +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.OLD/foo.c\n"); + exit (0); +} +""") + +opts = '-Y %s -Y %s' % (workpath_r_NEW, workpath_r_OLD) + +# Make the repositories non-writable, so we'll detect +# if we try to write into them accidentally. +test.writable('r.OLD', 0) +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.OLD/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.NEW', 1) + +test.write(['r.NEW', 'foo.c'], r""" +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.NEW/foo.c\n"); + exit (0); +} +""") + +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.NEW/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.write(['work2', 'foo.c'], r""" +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("work2/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "work2/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.OLD', 1) +test.writable('r.NEW', 1) + +test.write(['r.OLD', 'foo.c'], r""" +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.OLD/foo.c 2\n"); + exit (0); +} +""") + +test.write(['r.NEW', 'foo.c'], r""" +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.NEW/foo.c 2\n"); + exit (0); +} +""") + +test.writable('r.OLD', 0) +test.writable('r.NEW', 0) + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.unlink(['work2', 'foo.c']) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.NEW/foo.c 2\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.NEW', 1) + +test.unlink(['r.NEW', 'foo.c']) + +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.OLD/foo.c 2\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + + + +# +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option/warn-missing-sconscript.py scons-4.4.0+dfsg/test/option/warn-missing-sconscript.py --- scons-4.0.1+dfsg/test/option/warn-missing-sconscript.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option/warn-missing-sconscript.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify use of the --warn=missing-sconscript option. @@ -53,7 +52,7 @@ expect = r""" scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=0 to SConscript calls. +Transition by adding must_exist=False to SConscript calls. Missing SConscript 'no_such_file' """ + TestSCons.file_expr diff -Nru scons-4.0.1+dfsg/test/option-b.py scons-4.4.0+dfsg/test/option-b.py --- scons-4.0.1+dfsg/test/option-b.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-b.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments = '-b .', - stderr = "Warning: ignoring -b option\n") - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--C.py scons-4.4.0+dfsg/test/option--C.py --- scons-4.0.1+dfsg/test/option--C.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--C.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -#!/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. -# - -""" -Test that the -C option changes directory as expected and that -multiple -C options are additive, except if a full path is given -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os - -import TestSCons - -def match_normcase(lines, matches): - if not isinstance(lines, list): - lines = lines.split("\n") - if not isinstance(matches, list): - matches = matches.split("\n") - if len(lines) != len(matches): - return None - for line, match in zip(lines, matches): - if os.path.normcase(line) != os.path.normcase(match): - return None - return 1 - -test = TestSCons.TestSCons(match=match_normcase) - -wpath = test.workpath() -wpath_sub = test.workpath('sub') -wpath_sub_dir = test.workpath('sub', 'dir') -wpath_sub_foo_bar = test.workpath('sub', 'foo', 'bar') - -test.subdir('sub', ['sub', 'dir']) - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -import os -print("SConstruct " + os.getcwd()) -""") - -test.write(['sub', 'SConstruct'], """ -DefaultEnvironment(tools=[]) -import os -print(GetBuildPath('..')) -""") - -test.write(['sub', 'dir', 'SConstruct'], """ -DefaultEnvironment(tools=[]) -import os -env = Environment(FOO='foo', BAR='bar', tools=[]) -print(env.GetBuildPath('../$FOO/$BAR')) -""") - -# single -C -test.run(arguments='-C sub .', - stdout="scons: Entering directory `%s'\n" % wpath_sub \ - + test.wrap_stdout(read_str='%s\n' % wpath, - build_str="scons: `.' is up to date.\n")) - -# multiple -C -test.run(arguments='-C sub -C dir .', - stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \ - + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar, - build_str="scons: `.' is up to date.\n")) - -test.run(arguments=".", - stdout=test.wrap_stdout(read_str='SConstruct %s\n' % wpath, - build_str="scons: `.' is up to date.\n")) - -# alternate form -test.run(arguments='--directory=sub/dir .', - stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \ - + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar, - build_str="scons: `.' is up to date.\n")) - -# checks that using full paths is not additive -test.run(arguments='-C %s -C %s .' % (wpath_sub_dir, wpath_sub), - stdout="scons: Entering directory `%s'\n" % wpath_sub \ - + test.wrap_stdout(read_str='%s\n' % wpath, - build_str="scons: `.' is up to date.\n")) - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--duplicate.py scons-4.4.0+dfsg/test/option--duplicate.py --- scons-4.0.1+dfsg/test/option--duplicate.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--duplicate.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -#!/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. -# - -""" -This tests the --duplicate command line option, and the duplicate -SConscript settable option. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import sys -import stat -import TestSCons - -python = TestSCons.python - -test = TestSCons.TestSCons() - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -try: - duplicate = ARGUMENTS['duplicate'] - SetOption('duplicate', duplicate) -except KeyError: - pass -VariantDir('build', '.', duplicate=1) -SConscript('build/SConscript') -""") - -test.write('SConscript', '') - -# we don't use links on windows currently as they -# require permissions not usually set -hard = hasattr(os, 'link') and sys.platform != 'win32' -soft = hasattr(os, 'symlink') and sys.platform != 'win32' -copy = 1 # should always work - -bss = test.workpath('build/SConscript') - -criterion_hardlinks = { - 'hard' : lambda nl, islink: nl == 2 and not islink, - 'soft' : lambda nl, islink: nl == 1 and islink, - 'copy' : lambda nl, islink: nl == 1 and not islink, -} - -criterion_no_hardlinks = { - 'hard' : lambda nl, islink: not islink, - 'soft' : lambda nl, islink: islink, - 'copy' : lambda nl, islink: not islink, -} - -# On systems without hard linking, it doesn't make sense to check ST_NLINK -if hard: - criterion = criterion_hardlinks -else: - criterion = criterion_no_hardlinks - -description = { - 'hard' : 'a hard link', - 'soft' : 'a soft link', - 'copy' : 'copied', -} - -def testLink(file, type): - nl = os.stat(file)[stat.ST_NLINK] - islink = os.path.islink(file) - assert criterion[type](nl, islink), \ - "Expected %s to be %s (nl %d, islink %d)" \ - % (file, description[type], nl, islink) - -def RunTest(order, type, bss): - # Test the command-line --duplicate option. - test.run(arguments='--duplicate='+order) - testLink(bss, type) - - # Test setting the option in the SConstruct file. - test.run(arguments='duplicate='+order) - testLink(bss, type) - - # Clean up for next run. - os.unlink(bss) - -# test the default (hard-soft-copy) -if hard: type='hard' -elif soft: type='soft' -else: type='copy' -RunTest('hard-soft-copy', type, bss) - -if soft: type='soft' -elif hard: type='hard' -else: type='copy' -RunTest('soft-hard-copy', type, bss) - -if soft: type='soft' -else: type='copy' -RunTest('soft-copy', type, bss) - -if hard: type='hard' -else: type='copy' -RunTest('hard-copy', type, bss) - -type='copy' -RunTest('copy', type, bss) - -test.run(arguments='--duplicate=nonsense', status=2, stderr="""\ -usage: scons [OPTION] [TARGET] ... - -SCons Error: `nonsense' is not a valid duplication option type, try: - hard-soft-copy, soft-hard-copy, hard-copy, soft-copy, copy -""") - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-f.py scons-4.4.0+dfsg/test/option-f.py --- scons-4.0.1+dfsg/test/option-f.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-f.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -#!/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__" - -import os - -import TestSCons - -test = TestSCons.TestSCons() - -test.subdir('subdir') - -subdir_BuildThis = os.path.join('subdir', 'Buildthis') - -test.write('SConscript', """ -DefaultEnvironment(tools=[]) -import os -print("SConscript " + os.getcwd()) -""") - -test.write(subdir_BuildThis, """ -DefaultEnvironment(tools=[]) -import os -print("subdir/BuildThis "+ os.getcwd()) -""") - -test.write('Build2', """ -DefaultEnvironment(tools=[]) -import os -print("Build2 "+ os.getcwd()) -""") - -wpath = test.workpath() - -test.run(arguments = '-f SConscript .', - stdout = test.wrap_stdout(read_str = 'SConscript %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '-f %s .' % subdir_BuildThis, - stdout = test.wrap_stdout(read_str = 'subdir/BuildThis %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--file=SConscript .', - stdout = test.wrap_stdout(read_str = 'SConscript %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--file=%s .' % subdir_BuildThis, - stdout = test.wrap_stdout(read_str = 'subdir/BuildThis %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--makefile=SConscript .', - stdout = test.wrap_stdout(read_str = 'SConscript %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--makefile=%s .' % subdir_BuildThis, - stdout = test.wrap_stdout(read_str = 'subdir/BuildThis %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--sconstruct=SConscript .', - stdout = test.wrap_stdout(read_str = 'SConscript %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--sconstruct=%s .' % subdir_BuildThis, - stdout = test.wrap_stdout(read_str = 'subdir/BuildThis %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '-f - .', stdin = """ -DefaultEnvironment(tools=[]) -import os -print("STDIN " + os.getcwd()) -""", - stdout = test.wrap_stdout(read_str = 'STDIN %s\n' % wpath, - build_str = "scons: `.' is up to date.\n")) - -expect = test.wrap_stdout(read_str = 'Build2 %s\nSConscript %s\n' % (wpath, wpath), - build_str = "scons: `.' is up to date.\n") -test.run(arguments = '-f Build2 -f SConscript .', stdout=expect) - -test.run(arguments = '-f no_such_file .', - stdout = test.wrap_stdout("scons: `.' is up to date.\n"), - stderr = None) -expect = """ -scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=0 to SConscript calls. -Missing SConscript 'no_such_file'""" -stderr = test.stderr() -test.must_contain_all(test.stderr(), expect) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-i.py scons-4.4.0+dfsg/test/option-i.py --- scons-4.0.1+dfsg/test/option-i.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-i.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -#!/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__" - -import os.path - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.write('succeed.py', r""" -import sys -file = open(sys.argv[1], 'w') -file.write("succeed.py: %s\n" % sys.argv[1]) -file.close() -sys.exit(0) -""") - -test.write('fail.py', r""" -import sys -sys.exit(1) -""") - -test.write('SConstruct', """ -Succeed = Builder(action = r'%(_python_)s succeed.py $TARGETS') -Fail = Builder(action = r'%(_python_)s fail.py $TARGETS') -env = Environment(BUILDERS = { 'Succeed' : Succeed, 'Fail' : Fail }) -env.Fail(target = 'aaa.1', source = 'aaa.in') -env.Succeed(target = 'aaa.out', source = 'aaa.1') -env.Fail(target = 'bbb.1', source = 'bbb.in') -env.Succeed(target = 'bbb.out', source = 'bbb.1') -""" % locals()) - -test.write('aaa.in', "aaa.in\n") -test.write('bbb.in', "bbb.in\n") - -test.run(arguments = 'aaa.1 aaa.out bbb.1 bbb.out', - stderr = 'scons: *** [aaa.1] Error 1\n', - status = 2) - -test.fail_test(os.path.exists(test.workpath('aaa.1'))) -test.fail_test(os.path.exists(test.workpath('aaa.out'))) -test.fail_test(os.path.exists(test.workpath('bbb.1'))) -test.fail_test(os.path.exists(test.workpath('bbb.out'))) - -test.run(arguments = '-i aaa.1 aaa.out bbb.1 bbb.out', - stderr = - 'scons: *** [aaa.1] Error 1\n' - 'scons: *** [bbb.1] Error 1\n') - -test.fail_test(os.path.exists(test.workpath('aaa.1'))) -test.fail_test(test.read('aaa.out',mode='r') != "succeed.py: aaa.out\n") -test.fail_test(os.path.exists(test.workpath('bbb.1'))) -test.fail_test(test.read('bbb.out',mode='r') != "succeed.py: bbb.out\n") - -test.unlink("aaa.out") -test.unlink("bbb.out") - -test.run(arguments='--ignore-errors aaa.1 aaa.out bbb.1 bbb.out', - stderr='scons: *** [aaa.1] Error 1\n' - 'scons: *** [bbb.1] Error 1\n') - -test.fail_test(os.path.exists(test.workpath('aaa.1'))) -test.fail_test(test.read('aaa.out', mode='r') != "succeed.py: aaa.out\n") -test.fail_test(os.path.exists(test.workpath('bbb.1'))) -test.fail_test(test.read('bbb.out', mode='r') != "succeed.py: bbb.out\n") - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--I.py scons-4.4.0+dfsg/test/option--I.py --- scons-4.0.1+dfsg/test/option--I.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--I.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.subdir('sub1', 'sub2') - -test.write(['sub1', 'foo.py'], """ -variable = "sub1/foo" -""") - -test.write(['sub2', 'foo.py'], """ -variable = "sub2/foo" -""") - -test.write(['sub2', 'bar.py'], """ -variable = "sub2/bar" -""") - -test.write('SConstruct', """ -import foo -print(foo.variable) -import bar -print(bar.variable) -""") - -test.run(arguments = '-I sub1 -I sub2 .', - stdout = test.wrap_stdout(read_str = 'sub1/foo\nsub2/bar\n', - build_str = "scons: `.' is up to date.\n")) - -test.run(arguments = '--include-dir=sub2 --include-dir=sub1 .', - stdout = test.wrap_stdout(read_str = 'sub2/foo\nsub2/bar\n', - build_str = "scons: `.' is up to date.\n")) - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-j.py scons-4.4.0+dfsg/test/option-j.py --- scons-4.0.1+dfsg/test/option-j.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-j.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,230 +0,0 @@ -#!/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. -# - -""" -This tests the -j command line option, and the num_jobs -SConscript settable option. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os.path -import sys - -import TestSCons - - -_python_ = TestSCons._python_ - -try: - import threading -except ImportError: - # if threads are not supported, then - # there is nothing to test - TestCmd.no_result() - sys.exit() - - -test = TestSCons.TestSCons() - -test.write('build.py', r""" -import time -import sys -with open(sys.argv[1], 'w') as f: - f.write(str(time.time()) + '\n') - time.sleep(1) - f.write(str(time.time())) -""") - -test.subdir('foo') - -test.write(['foo','foo.in'], r""" -foo you -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS') -env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) -env.Tool('install') -env.MyBuild(target='f1', source='f1.in') -env.MyBuild(target='f2', source='f2.in') - -def copyn(env, target, source): - import shutil - import time - time.sleep(1) - for t in target: - shutil.copy(str(source[0]), str(t)) - -t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], - source='foo/foo.in', - action=copyn) -env.Install('out', t) -""" % locals()) - -def RunTest(args, extra): - """extra is used to make scons rebuild the output file""" - test.write('f1.in', 'f1.in'+extra) - test.write('f2.in', 'f2.in'+extra) - - test.run(arguments = args) - - str = test.read("f1", mode='r') - start1,finish1 = list(map(float, str.split("\n"))) - - str = test.read("f2", mode='r') - start2,finish2 = list(map(float, str.split("\n"))) - - return start2, finish1 - -# Test 2 parallel jobs. -# fail if the second file was not started -# before the first one was finished. -start2, finish1 = RunTest('-j 2 f1 f2', "first") -test.fail_test(not (start2 < finish1)) - -# re-run the test with the same input, fail if we don't -# get back the same times, which would indicate that -# SCons rebuilt the files even though nothing changed -s2, f1 = RunTest('-j 2 f1 f2', "first") -test.fail_test(start2 != s2) -test.fail_test(finish1 != f1) - -# Test a single serial job. -# fail if the second file was started -# before the first one was finished -start2, finish1 = RunTest('f1 f2', "second") -test.fail_test(start2 < finish1) - -# Make sure that a parallel build using a list builder -# succeeds. -test.run(arguments='-j 2 out') - -if sys.platform != 'win32' and sys.version_info[0] == 2: - # Test breaks on win32 when using real subprocess is not the only - # package to import threading - # - # Test that we fall back and warn properly if there's no threading.py - # module (simulated), which is the case if this version of Python wasn't - # built with threading support. - - test.subdir('pythonlib') - - test.write(['pythonlib', 'threading.py'], "raise ImportError\n") - - save_pythonpath = os.environ.get('PYTHONPATH', '') - os.environ['PYTHONPATH'] = test.workpath('pythonlib') - - #start2, finish1 = RunTest('-j 2 f1, f2', "fifth") - - test.write('f1.in', 'f1.in pythonlib\n') - test.write('f2.in', 'f2.in pythonlib\n') - - test.run(arguments = "-j 2 f1 f2", stderr=None) - - warn = """scons: warning: parallel builds are unsupported by this version of Python; -\tignoring -j or num_jobs option.""" - test.must_contain_all_lines(test.stderr(), [warn]) - - str = test.read("f1", mode='r') - start1,finish1 = list(map(float, str.split("\n"))) - - str = test.read("f2", mode='r') - start2,finish2 = list(map(float, str.split("\n"))) - - test.fail_test(start2 < finish1) - - os.environ['PYTHONPATH'] = save_pythonpath - - -# Test SetJobs() with no -j: -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS') -env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) -env.Tool('install') -env.MyBuild(target = 'f1', source = 'f1.in') -env.MyBuild(target = 'f2', source = 'f2.in') - -def copyn(env, target, source): - import shutil - import time - time.sleep(1) - for t in target: - shutil.copy(str(source[0]), str(t)) - -t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn) -env.Install('out', t) - -assert GetOption('num_jobs') == 1 -SetOption('num_jobs', 2) -assert GetOption('num_jobs') == 2 -""" % locals()) - -# This should be a parallel build because the SConscript sets jobs to 2. -# fail if the second file was not started -# before the first one was finished -start2, finish1 = RunTest('f1 f2', "third") -test.fail_test(not (start2 < finish1)) - -# Test SetJobs() with -j: -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS') -env = Environment(BUILDERS = {'MyBuild': MyBuild}, tools=[]) -env.Tool('install') -env.MyBuild(target='f1', source='f1.in') -env.MyBuild(target='f2', source='f2.in') - -def copyn(env, target, source): - import shutil - import time - time.sleep(1) - for t in target: - shutil.copy(str(source[0]), str(t)) - -t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn) -env.Install('out', t) - -assert GetOption('num_jobs') == 1 -SetOption('num_jobs', 2) -assert GetOption('num_jobs') == 1 -""" % locals()) - -# This should be a serial build since -j 1 overrides the call to SetJobs(). -# fail if the second file was started -# before the first one was finished -start2, finish1 = RunTest('-j 1 f1 f2', "fourth") -test.fail_test(start2 < finish1) - - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-k.py scons-4.4.0+dfsg/test/option-k.py --- scons-4.0.1+dfsg/test/option-k.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-k.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,304 +0,0 @@ -#!/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__" - -import os.path - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.subdir('work1', 'work2', 'work3') - - - -test.write('succeed.py', r""" -import sys -file = open(sys.argv[1], 'w') -file.write("succeed.py: %s\n" % sys.argv[1]) -file.close() -sys.exit(0) -""") - -test.write('fail.py', r""" -import sys -sys.exit(1) -""") - - -# -# Test: work1 -# - -test.write(['work1', 'SConstruct'], """\ -DefaultEnvironment(tools=[]) -Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS') -Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS') -env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[]) -env.Fail(target='aaa.1', source='aaa.in') -env.Succeed(target='aaa.out', source='aaa.1') -env.Succeed(target='bbb.out', source='bbb.in') -""" % locals()) - -test.write(['work1', 'aaa.in'], "aaa.in\n") -test.write(['work1', 'bbb.in'], "bbb.in\n") - -test.run(chdir='work1', - arguments='aaa.out bbb.out', - stderr='scons: *** [aaa.1] Error 1\n', - status=2) - -test.must_not_exist(test.workpath('work1', 'aaa.1')) -test.must_not_exist(test.workpath('work1', 'aaa.out')) -test.must_not_exist(test.workpath('work1', 'bbb.out')) - -test.run(chdir='work1', - arguments='-k aaa.out bbb.out', - stderr='scons: *** [aaa.1] Error 1\n', - status=2) - -test.must_not_exist(test.workpath('work1', 'aaa.1')) -test.must_not_exist(test.workpath('work1', 'aaa.out')) -test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r') - -test.unlink(['work1', 'bbb.out']) - -test.run(chdir = 'work1', - arguments='--keep-going aaa.out bbb.out', - stderr='scons: *** [aaa.1] Error 1\n', - status=2) - -test.must_not_exist(test.workpath('work1', 'aaa.1')) -test.must_not_exist(test.workpath('work1', 'aaa.out')) -test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r') - -expect = """\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Cleaning targets ... -Removed bbb.out -scons: done cleaning targets. -""" - -test.run(chdir='work1', - arguments='--clean --keep-going aaa.out bbb.out', - stdout=expect) - -test.must_not_exist(test.workpath('work1', 'aaa.1')) -test.must_not_exist(test.workpath('work1', 'aaa.out')) -test.must_not_exist(test.workpath('work1', 'bbb.out')) - - - -# -# Test: work2 -# - -test.write(['work2', 'SConstruct'], """\ -DefaultEnvironment(tools=[]) -Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS') -Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS') -env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[]) -env.Fail('aaa.out', 'aaa.in') -env.Succeed('bbb.out', 'aaa.out') -env.Succeed('ccc.out', 'ccc.in') -env.Succeed('ddd.out', 'ccc.in') -""" % locals()) - -test.write(['work2', 'aaa.in'], "aaa.in\n") -test.write(['work2', 'ccc.in'], "ccc.in\n") - -test.run(chdir='work2', - arguments='-k .', - status=2, - stderr=None, - stdout="""\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Building targets ... -%(_python_)s ../fail.py aaa.out -%(_python_)s ../succeed.py ccc.out -%(_python_)s ../succeed.py ddd.out -scons: done building targets (errors occurred during build). -""" % locals()) - -test.must_not_exist(['work2', 'aaa.out']) -test.must_not_exist(['work2', 'bbb.out']) -test.must_match(['work2', 'ccc.out'], "succeed.py: ccc.out\n", mode='r') -test.must_match(['work2', 'ddd.out'], "succeed.py: ddd.out\n", mode='r') - - - -# -# Test: work3 -# -# Check that the -k (keep-going) switch works correctly when the Nodes -# forms a DAG. The test case is the following -# -# all -# | -# +-----+-----+-------------+ -# | | | -# a1 a2 a3 -# | | | -# + +---+---+ +---+---+ -# \ | / | | -# \ bbb.out / a4 ccc.out -# \ / / -# \ / / -# \ / / -# aaa.out (fails) -# - -test.write(['work3', 'SConstruct'], """\ -DefaultEnvironment(tools=[]) -Succeed = Builder(action = r'%(_python_)s ../succeed.py $TARGETS') -Fail = Builder(action = r'%(_python_)s ../fail.py $TARGETS') -env = Environment(BUILDERS = {'Succeed': Succeed, 'Fail': Fail}, tools=[]) -a = env.Fail('aaa.out', 'aaa.in') -b = env.Succeed('bbb.out', 'bbb.in') -c = env.Succeed('ccc.out', 'ccc.in') - -a1 = Alias( 'a1', a ) -a2 = Alias( 'a2', a+b) -a4 = Alias( 'a4', c) -a3 = Alias( 'a3', a4+c) - -Alias('all', a1+a2+a3) -""" % locals()) - -test.write(['work3', 'aaa.in'], "aaa.in\n") -test.write(['work3', 'bbb.in'], "bbb.in\n") -test.write(['work3', 'ccc.in'], "ccc.in\n") - - -# Test tegular build (i.e. without -k) -test.run(chdir = 'work3', - arguments = '.', - status = 2, - stderr = None, - stdout = """\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Building targets ... -%(_python_)s ../fail.py aaa.out -scons: building terminated because of errors. -""" % locals()) - -test.must_not_exist(['work3', 'aaa.out']) -test.must_not_exist(['work3', 'bbb.out']) -test.must_not_exist(['work3', 'ccc.out']) - - -test.run(chdir = 'work3', - arguments = '-c .') -test.must_not_exist(['work3', 'aaa.out']) -test.must_not_exist(['work3', 'bbb.out']) -test.must_not_exist(['work3', 'ccc.out']) - - -# Current directory -test.run(chdir = 'work3', - arguments = '-k .', - status = 2, - stderr = None, - stdout = """\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Building targets ... -%(_python_)s ../fail.py aaa.out -%(_python_)s ../succeed.py bbb.out -%(_python_)s ../succeed.py ccc.out -scons: done building targets (errors occurred during build). -""" % locals()) - -test.must_not_exist(['work3', 'aaa.out']) -test.must_exist(['work3', 'bbb.out']) -test.must_exist(['work3', 'ccc.out']) - - -test.run(chdir = 'work3', - arguments = '-c .') -test.must_not_exist(['work3', 'aaa.out']) -test.must_not_exist(['work3', 'bbb.out']) -test.must_not_exist(['work3', 'ccc.out']) - - -# Single target -test.run(chdir = 'work3', - arguments = '--keep-going all', - status = 2, - stderr = None, - stdout = """\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Building targets ... -%(_python_)s ../fail.py aaa.out -%(_python_)s ../succeed.py bbb.out -%(_python_)s ../succeed.py ccc.out -scons: done building targets (errors occurred during build). -""" % locals()) - -test.must_not_exist(['work3', 'aaa.out']) -test.must_exist(['work3', 'bbb.out']) -test.must_exist(['work3', 'ccc.out']) - - -test.run(chdir = 'work3', - arguments = '-c .') -test.must_not_exist(['work3', 'aaa.out']) -test.must_not_exist(['work3', 'bbb.out']) -test.must_not_exist(['work3', 'ccc.out']) - - -# Separate top-level targets -test.run(chdir = 'work3', - arguments = '-k a1 a2 a3', - status = 2, - stderr = None, - stdout = """\ -scons: Reading SConscript files ... -scons: done reading SConscript files. -scons: Building targets ... -%(_python_)s ../fail.py aaa.out -%(_python_)s ../succeed.py bbb.out -%(_python_)s ../succeed.py ccc.out -scons: done building targets (errors occurred during build). -""" % locals()) - -test.must_not_exist(['work3', 'aaa.out']) -test.must_exist(['work3', 'bbb.out']) -test.must_exist(['work3', 'ccc.out']) - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--la.py scons-4.4.0+dfsg/test/option--la.py --- scons-4.0.1+dfsg/test/option--la.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--la.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--list-actions', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--ld.py scons-4.4.0+dfsg/test/option--ld.py --- scons-4.0.1+dfsg/test/option--ld.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--ld.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--list-derived', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-l.py scons-4.4.0+dfsg/test/option-l.py --- scons-4.0.1+dfsg/test/option-l.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-l.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('-l', '1 .') - -test.option_not_yet_implemented('--load-average', '=1 .') - -test.option_not_yet_implemented('--max-load', '=1 .') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--lw.py scons-4.4.0+dfsg/test/option--lw.py --- scons-4.0.1+dfsg/test/option--lw.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--lw.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--list-where', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--max-drift.py scons-4.4.0+dfsg/test/option--max-drift.py --- scons-4.0.1+dfsg/test/option--max-drift.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--max-drift.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -#!/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__" - -import os - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.write('build.py', r""" -import sys -with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp: - f.write(ifp.read()) -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }, tools=[]) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -""" % locals()) - -test.write('f1.in', "f1.in\n") -test.write('f2.in', "f2.in\n") - - - -test.run(arguments = 'f1.out') - -test.run(arguments = 'f1.out f2.out', - stdout = test.wrap_stdout( -"""scons: `f1.out' is up to date. -%(_python_)s build.py f2.out f2.in -""" % locals())) - -atime = os.path.getatime(test.workpath('f1.in')) -mtime = os.path.getmtime(test.workpath('f1.in')) - -test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out') - -test.write('f1.in', "f1.in delta\n") -os.utime(test.workpath('f1.in'), (atime,mtime)) - -test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out') - -expect = test.wrap_stdout( -"""%(_python_)s build.py f1.out f1.in -scons: `f2.out' is up to date. -""" % locals()) - -test.run(arguments = '--max-drift=-1 f1.out f2.out', stdout = expect) - -# Test that Set/GetOption('max_drift') works: -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -assert GetOption('max_drift') == 2*24*60*60 -SetOption('max_drift', 1) -assert GetOption('max_drift') == 1 -""") - -test.run() - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -assert GetOption('max_drift') == 1 -SetOption('max_drift', 10) -assert GetOption('max_drift') == 1 -""") - -test.run(arguments='--max-drift=1') - -# Test that SetOption('max_drift') actually sets max_drift -# by mucking with the file timestamps to make SCons not realize the source has changed -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -SetOption('max_drift', 0) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }, tools=[]) -env.B(target = 'foo.out', source = 'foo.in') -""" % locals()) - -test.write('foo.in', 'foo.in\n') - -atime = os.path.getatime(test.workpath('foo.in')) -mtime = os.path.getmtime(test.workpath('foo.in')) - -test.run() -test.must_match('foo.out', 'foo.in\n', mode='r') - -test.write('foo.in', 'foo.in delta\n') -os.utime(test.workpath('foo.in'), (atime,mtime)) - -test.run() - -test.must_match('foo.out', 'foo.in\n', mode='r') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-m.py scons-4.4.0+dfsg/test/option-m.py --- scons-4.0.1+dfsg/test/option-m.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-m.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments = '-m .', - stderr = "Warning: ignoring -m option\n") - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-n.py scons-4.4.0+dfsg/test/option-n.py --- scons-4.0.1+dfsg/test/option-n.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-n.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -#!/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. -# - -""" -This test verifies: - 1) that we don't build files when we use the -n, --no-exec, - --just-print, --dry-run, and --recon options; - 2) that we don't remove built files when -n is used in - conjunction with -c; - 3) that files installed by the Install() method don't get - installed when -n is used; - 4) that source files don't get duplicated in a VariantDir - when -n is used. - 5) that Configure calls don't build any files. If a file - needs to be built (i.e. is not up-to-date), a ConfigureError - is raised. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import re - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.subdir('build', 'src') - -test.write('build.py', r""" -import sys -with open(sys.argv[1], 'w') as ofp: - ofp.write("build.py: %s\n" % sys.argv[1]) -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS') -env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) -env.Tool('install') -env.MyBuild(target='f1.out', source='f1.in') -env.MyBuild(target='f2.out', source='f2.in') -env.Install('install', 'f3.in') -VariantDir('build', 'src', duplicate=1) -SConscript('build/SConscript', "env") -""" % locals()) - -test.write(['src', 'SConscript'], """ -Import("env") -env.MyBuild(target='f4.out', source='f4.in') -""") - -test.write('f1.in', "f1.in\n") -test.write('f2.in', "f2.in\n") -test.write('f3.in', "f3.in\n") -test.write(['src', 'f4.in'], "src/f4.in\n") - -args = 'f1.out f2.out' -expect = test.wrap_stdout("""\ -%(_python_)s build.py f1.out -%(_python_)s build.py f2.out -""" % locals()) - -test.run(arguments=args, stdout=expect) -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -test.unlink('f1.out') -test.unlink('f2.out') - -test.run(arguments='-n ' + args, stdout=expect) -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - -test.run(arguments='--no-exec ' + args, stdout=expect) -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - -test.run(arguments='--just-print ' + args, stdout=expect) -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - -test.run(arguments='--dry-run ' + args, stdout=expect) -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - -test.run(arguments='--recon ' + args, stdout=expect) -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - -test.run(arguments=args) -test.fail_test(not os.path.exists(test.workpath('f1.out'))) - -# Test that SCons does not write a modified .sconsign when -n is used. -expect = test.wrap_stdout("""\ -%(_python_)s build.py f1.out -""" % locals()) -test.unlink('.sconsign.dblite') -test.write('f1.out', "X1.out\n") -test.run(arguments='-n f1.out', stdout=expect) -test.run(arguments='-n f1.out', stdout=expect) - -expect = test.wrap_stdout("Removed f1.out\nRemoved f2.out\n", cleaning=1) - -test.run(arguments='-n -c ' + args, stdout=expect) - -test.run(arguments='-c -n ' + args, stdout=expect) - -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -# -install_f3_in = os.path.join('install', 'f3.in') -expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in) - -test.run(arguments='-n install', stdout=expect) -test.fail_test(os.path.exists(test.workpath('install', 'f3.in'))) - -test.run(arguments='install', stdout=expect) -test.fail_test(not os.path.exists(test.workpath('install', 'f3.in'))) - -test.write('f3.in', "f3.in again\n") - -test.run(arguments='-n install', stdout=expect) -test.fail_test(not os.path.exists(test.workpath('install', 'f3.in'))) - -# Make sure duplicate source files in a VariantDir aren't created -# when the -n option is used. - -# First, make sure none of the previous non-dryrun invocations caused -# the build directory to be populated. Processing of the -# src/SConscript (actually build/SConscript) will reference f4.in as a -# source, causing a Node object to be built for "build/f4.in". -# Creating the node won't cause "build/f4.in" to be created from -# "src/f4.in", but that *is* a side-effect of calling the exists() -# method on that node, which may happen via other processing. -# Therefore add this conditional removal to ensure a clean setting -# before running this test. - -if os.path.exists(test.workpath('build', 'f4.in')): - test.unlink(test.workpath('build', 'f4.in')) - -test.run(arguments='-n build') -test.fail_test(os.path.exists(test.workpath('build', 'f4.in'))) - -# test Configure-calls in conjunction with -n -test.subdir('configure') -test.set_match_function(TestSCons.match_re_dotall) -test.set_diff_function(TestSCons.diff_re) -test.write('configure/SConstruct', """\ -DefaultEnvironment(tools=[]) -def CustomTest(context): - def userAction(target,source,env): - import shutil - shutil.copyfile( str(source[0]), str(target[0])) - def strAction(target,source,env): - return "cp " + str(source[0]) + " " + str(target[0]) - context.Message("Executing Custom Test ... " ) - (ok, msg) = context.TryAction(Action(userAction,strAction), - "Hello World", ".in") - context.Result(ok) - return ok - -env = Environment(tools=[]) -conf = Configure(env, - custom_tests={'CustomTest':CustomTest}, - conf_dir="config.test", - log_file="config.log") -if not conf.CustomTest(): - Exit(1) -else: - env = conf.Finish() -""") -# test that conf_dir isn't created and an error is raised -stderr = r""" -scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\. -File \S+, line \S+, in \S+ -""" -test.run(arguments="-n", stderr=stderr, status=2, - chdir=test.workpath("configure")) -test.fail_test(os.path.exists(test.workpath("configure", "config.test"))) -test.fail_test(os.path.exists(test.workpath("configure", "config.log"))) - -# test that targets are not built, if conf_dir exists. -# verify that .cache and config.log are not created. -# an error should be raised -stderr = r""" -scons: \*\*\* Cannot update configure test "%s" within a dry-run\. -File \S+, line \S+, in \S+ -""" % re.escape(os.path.join("config.test", "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in")) -test.subdir(['configure', 'config.test']) -test.run(arguments="-n", stderr=stderr, status=2, - chdir=test.workpath("configure")) -test.fail_test(os.path.exists(test.workpath("configure", "config.test", - ".cache"))) -test.fail_test(os.path.exists(test.workpath("configure", "config.test", - "conftest_0"))) -test.fail_test(os.path.exists(test.workpath("configure", "config.test", - "conftest_0.in"))) -test.fail_test(os.path.exists(test.workpath("configure", "config.log"))) - -# test that no error is raised, if all targets are up-to-date. In this -# case .cache and config.log shouldn't be created -stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", - read_str=r"""Executing Custom Test ... \(cached\) yes -""") -test.run(status=0, chdir=test.workpath("configure")) -log1_mtime = os.path.getmtime(test.workpath("configure", "config.log")) -test.run(stdout=stdout, arguments="-n", status=0, - chdir=test.workpath("configure")) -log2_mtime = os.path.getmtime(test.workpath("configure", "config.log")) -test.fail_test(log1_mtime != log2_mtime) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-o.py scons-4.4.0+dfsg/test/option-o.py --- scons-4.0.1+dfsg/test/option-o.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-o.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('-o', 'foo .') - -test.option_not_yet_implemented('--old-file', '=foo .') - -test.option_not_yet_implemented('--assume-old', '=foo .') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--override.py scons-4.4.0+dfsg/test/option--override.py --- scons-4.0.1+dfsg/test/option--override.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--override.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--override', '=foo .') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-p.py scons-4.4.0+dfsg/test/option-p.py --- scons-4.0.1+dfsg/test/option-p.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-p.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('-p', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--.py scons-4.4.0+dfsg/test/option--.py --- scons-4.0.1+dfsg/test/option--.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -#!/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__" - -import os.path - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.write('build.py', r""" -import sys -file = open(sys.argv[1], 'w') -file.write("build.py: %s\n" % sys.argv[1]) -file.close() -""") - -test.write('SConstruct', """ -MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS') -env = Environment(BUILDERS = { 'MyBuild' : MyBuild }) -env.MyBuild(target = '-f1.out', source = 'f1.in') -env.MyBuild(target = '-f2.out', source = 'f2.in') -""" % locals()) - -test.write('f1.in', "f1.in\n") -test.write('f2.in', "f2.in\n") - -expect = test.wrap_stdout('%(_python_)s build.py -f1.out\n%(_python_)s build.py -f2.out\n' % locals()) - -test.run(arguments = '-- -f1.out -f2.out', stdout = expect) - -test.fail_test(not os.path.exists(test.workpath('-f1.out'))) -test.fail_test(not os.path.exists(test.workpath('-f2.out'))) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--Q.py scons-4.4.0+dfsg/test/option--Q.py --- scons-4.0.1+dfsg/test/option--Q.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--Q.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -#!/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__" - -import os.path - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - - -test.write('build.py', r""" -import sys -file = open(sys.argv[1], 'w') -file.write("build.py: %s\n" % sys.argv[1]) -file.close() -""") - -test.write('SConstruct', """ - -AddOption('--use_SetOption', action='store_true', dest='setoption', default=False) - -use_setoption=GetOption('setoption') - -if use_setoption: - SetOption('no_progress', True) - -MyBuild = Builder(action = r'%(_python_)s build.py $TARGET') -env = Environment(BUILDERS = { 'MyBuild' : MyBuild }) -env.MyBuild(target = 'f1.out', source = 'f1.in') -env.MyBuild(target = 'f2.out', source = 'f2.in') -""" % locals()) - -test.write('f1.in', "f1.in\n") -test.write('f2.in', "f2.in\n") - -test.run(arguments = '-Q f1.out f2.out', stdout = """\ -%(_python_)s build.py f1.out -%(_python_)s build.py f2.out -""" % locals()) -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -# Make sure -q doesn't suppress other messages, too. -test.run(arguments = '-Q -c f1.out f2.out', stdout = """\ -Removed f1.out -Removed f2.out -""") -test.fail_test(os.path.exists(test.workpath('f1.out'))) -test.fail_test(os.path.exists(test.workpath('f2.out'))) - - -# When set via a SetOption, it will happen after the initial output of -# scons: Reading SConscript files ... -# but remaining status/progress output will not be output -test.run(arguments = '--use_SetOption f1.out f2.out', stdout = """\ -scons: Reading SConscript files ... -%(_python_)s build.py f1.out -%(_python_)s build.py f2.out -""" % locals()) -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--random.py scons-4.4.0+dfsg/test/option--random.py --- scons-4.0.1+dfsg/test/option--random.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--random.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -#!/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. - -""" -Verify that we build correctly using the --random option. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os.path - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConscript', """\ -def cat(env, source, target): - target = str(target[0]) - with open(target, "wb") as f: - for src in source: - with open(str(src), "rb") as ifp: - f.write(ifp.read()) -env = Environment(BUILDERS={'Cat':Builder(action=cat)}) -env.Cat('aaa.out', 'aaa.in') -env.Cat('bbb.out', 'bbb.in') -env.Cat('ccc.out', 'ccc.in') -env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) -""") - -test.write('aaa.in', "aaa.in\n") -test.write('bbb.in', "bbb.in\n") -test.write('ccc.in', "ccc.in\n") - - - -test.write('SConstruct', """\ -SetOption('random', 1) -SConscript('SConscript') -""") - -test.run(arguments = '-n -Q') -non_random_output = test.stdout() - -tries = 0 -max_tries = 10 -while test.stdout() == non_random_output: - if tries >= max_tries: - print("--random generated the non-random output %s times!" % max_tries) - test.fail_test() - tries = tries + 1 - test.run(arguments = '-n -Q --random') - - - -test.write('SConstruct', """\ -SConscript('SConscript') -""") - -test.run(arguments = '-n -Q') -non_random_output = test.stdout() - -tries = 0 -max_tries = 10 -while test.stdout() == non_random_output: - if tries >= max_tries: - print("--random generated the non-random output %s times!" % max_tries) - test.fail_test() - tries = tries + 1 - test.run(arguments = '-n -Q --random') - - - -test.run(arguments = '-Q --random') - -test.must_match('all', "aaa.in\nbbb.in\nccc.in\n") - -test.run(arguments = '-q --random .') - -test.run(arguments = '-c --random .') - -test.must_not_exist(test.workpath('aaa.out')) -test.must_not_exist(test.workpath('bbb.out')) -test.must_not_exist(test.workpath('ccc.out')) -test.must_not_exist(test.workpath('all')) - -test.run(arguments = '-q --random .', status = 1) - -test.run(arguments = '--random .') - -test.must_match('all', "aaa.in\nbbb.in\nccc.in\n") - -test.run(arguments = '-c --random .') - - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-r.py scons-4.4.0+dfsg/test/option-r.py --- scons-4.0.1+dfsg/test/option-r.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-r.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('-r', '.') - -test.option_not_yet_implemented('--no-builtin-rules', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--R.py scons-4.4.0+dfsg/test/option--R.py --- scons-4.0.1+dfsg/test/option--R.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--R.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('-R', '.') - -test.option_not_yet_implemented('--no-builtin-variables', '.') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-s.py scons-4.4.0+dfsg/test/option-s.py --- scons-4.0.1+dfsg/test/option-s.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-s.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -#!/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__" - -import os.path - -import TestSCons - -_python_ = TestSCons._python_ - -test = TestSCons.TestSCons() - -test.write('build.py', r""" -import sys -file = open(sys.argv[1], 'w') -file.write("build.py: %s\n" % sys.argv[1]) -file.close() -""") - -test.write('SConstruct', """ -DefaultEnvironment(tools=[]) -MyBuild = Builder(action = r'%(_python_)s build.py $TARGET') - -silent = ARGUMENTS.get('QUIET',0) -if silent: - SetOption('silent',True) - -env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[]) -env.MyBuild(target='f1.out', source='f1.in') -env.MyBuild(target='f2.out', source='f2.in') -""" % locals()) - -test.write('f1.in', "f1.in\n") -test.write('f2.in', "f2.in\n") - -test.run(arguments='-s f1.out f2.out', stdout="") -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -test.unlink('f1.out') -test.unlink('f2.out') - -test.run(arguments='--silent f1.out f2.out', stdout="") -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -test.unlink('f1.out') -test.unlink('f2.out') - -test.run(arguments='--quiet f1.out f2.out', stdout="") -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - -# -C should also be quiet Issue#2796 -test.subdir( 'sub' ) -test.write(['sub','SConstruct'],"") -test.run(arguments='-s -C sub', stdout="" ) - -test.unlink('f1.out') -test.unlink('f2.out') - -test.run(arguments='QUIET=1 f1.out f2.out', - stdout="scons: Reading SConscript files ...\nscons: done reading SConscript files.\n") -test.fail_test(not os.path.exists(test.workpath('f1.out'))) -test.fail_test(not os.path.exists(test.workpath('f2.out'))) - - - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--S.py scons-4.4.0+dfsg/test/option--S.py --- scons-4.0.1+dfsg/test/option--S.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--S.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments = '-S .', stderr = "Warning: ignoring -S option\n") - -test.run(arguments = '--no-keep-going .', - stderr = "Warning: ignoring --no-keep-going option\n") - -test.run(arguments = '--stop .', stderr = "Warning: ignoring --stop option\n") - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-t.py scons-4.4.0+dfsg/test/option-t.py --- scons-4.0.1+dfsg/test/option-t.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-t.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments = '-t .', - stderr = "Warning: ignoring -t option\n") - -test.run(arguments = '--touch .', - stderr = "Warning: ignoring --touch option\n") - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--tree.py scons-4.4.0+dfsg/test/option--tree.py --- scons-4.0.1+dfsg/test/option--tree.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--tree.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -#!/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__" - -import sys -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments='-Q --tree=prune', - stdout="""scons: `.' is up to date. -+-. - +-SConstruct -""") - -test.run(arguments='-Q --tree=foofoo', - stderr="""usage: scons [OPTION] [TARGET] ... - -SCons Error: `foofoo' is not a valid --tree option type, try: - all, derived, prune, status, linedraw -""", - status=2) - - -# Test that unicode characters can be printed (escaped) with the --tree option -test.write('SConstruct', """\ -env = Environment() -env.Tool("textfile") -name = "français" -env.Textfile("Foo", name) -""") - -uchar = chr(0xe7) - -expected = """Creating 'Foo.txt' -+-. - +-Foo.txt - | +-fran%sais - +-SConstruct -""" % uchar - -test.run(arguments='-Q --tree=all', stdout=expected, status=0) - -# Test the "linedraw" option: same basic test as previous. -# With "--tree=linedraw" must default to "all", and use line-drawing chars. -test.write('SConstruct', """\ -env = Environment() -env.Tool("textfile") -name = "français" -env.Textfile("LineDraw", name) -""") - -expected = """Creating 'LineDraw.txt' -└─┬. - ├─┬LineDraw.txt - │ └─fran%sais - └─SConstruct -""" % uchar - - -test.run(arguments='-Q --tree=linedraw', stdout=expected, status=0) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-unknown.py scons-4.4.0+dfsg/test/option-unknown.py --- scons-4.0.1+dfsg/test/option-unknown.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-unknown.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.run(arguments = '-Z', - stderr = """usage: scons [OPTION] [TARGET] ... - -SCons Error: no such option: -Z -""", - status = 2) - -test.run(arguments = '--ZizzerZazzerZuzz', - stderr = """usage: scons [OPTION] [TARGET] ... - -SCons Error: no such option: --ZizzerZazzerZuzz -""", - status = 2) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option-v.py scons-4.4.0+dfsg/test/option-v.py --- scons-4.0.1+dfsg/test/option-v.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option-v.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -#!/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__" - -import TestCmd -import TestSCons - -test = TestSCons.TestSCons(match = TestCmd.match_re) - -test.write('SConstruct', "") - -# Standard copyright marker is mangled so it doesn't get replaced -# by the packaging build. -copyright_line = """\ -(_{2}COPYRIGHT__|Copyright \\(c\\) 2001[-\\d, ]+ The SCons Foundation) -""" - - -expect2 = r"""SCons by Steven Knight et al.: -\tSCons: v\S+, [^,]*, by \S+ on \S+ -\tSCons path: \[.*\] -""" + copyright_line - -test.run(arguments = '-v') -stdout = test.stdout() -if not test.match_re(stdout, expect2): - print(stdout) - test.fail_test() - -test.run(arguments = '--version') -stdout = test.stdout() -if not test.match_re(stdout, expect2): - print(stdout) - test.fail_test() - -test.pass_test() - - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--wf.py scons-4.4.0+dfsg/test/option--wf.py --- scons-4.0.1+dfsg/test/option--wf.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--wf.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--write-filenames', '=FILE .') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--W.py scons-4.4.0+dfsg/test/option--W.py --- scons-4.0.1+dfsg/test/option--W.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--W.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -test.write('SConstruct', """\ -DefaultEnvironment(tools=[]) -""") - -test.option_not_yet_implemented('-W', 'foo .') - -test.option_not_yet_implemented('--what-if', '=foo .') - -test.option_not_yet_implemented('--new-file', '=foo .') - -test.option_not_yet_implemented('--assume-new', '=foo .') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--wuv.py scons-4.4.0+dfsg/test/option--wuv.py --- scons-4.0.1+dfsg/test/option--wuv.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--wuv.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -#!/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__" - -import TestSCons - -test = TestSCons.TestSCons() - -# We want to preserve the --warn-undefined-variables option for -# compatibility with GNU Make. Unfortunately, this conflicts with -# the --warn=type option that we're using for our own warning -# control. The getopt module reports "--warn not a unique prefix" -# when both are defined. We may be able to support both in the -# future with a more robust getopt solution. -test.pass_test() #XXX Short-circuit until then. - -test.write('SConstruct', "") - -test.option_not_yet_implemented('--warn-undefined-variables') - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/option--Y.py scons-4.4.0+dfsg/test/option--Y.py --- scons-4.0.1+dfsg/test/option--Y.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/option--Y.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,318 +0,0 @@ -#!/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__" - -import sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' - - - -test = TestSCons.TestSCons() - -test.subdir('repository', 'work1') - -repository = test.workpath('repository') -repository_foo_c = test.workpath('repository', 'foo.c') -work1_foo = test.workpath('work1', 'foo' + _exe) -work1_foo_c = test.workpath('work1', 'foo.c') - -test.write(['repository', 'SConstruct'], r""" -env = Environment() -env.Program(target= 'foo', source = Split('aaa.c bbb.c foo.c')) -""") - -test.write(['repository', 'aaa.c'], r""" -#include -void -aaa(void) -{ - printf("repository/aaa.c\n"); -} -""") - -test.write(['repository', 'bbb.c'], r""" -#include -void -bbb(void) -{ - printf("repository/bbb.c\n"); -} -""") - -test.write(['repository', 'foo.c'], r""" -#include -#include -extern void aaa(void); -extern void bbb(void); -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - aaa(); - bbb(); - printf("repository/foo.c\n"); - exit (0); -} -""") - -opts = '-Y ' + repository - -# Make the entire repository non-writable, so we'll detect -# if we try to write into it accidentally. -test.writable('repository', 0) - -test.run(chdir = 'work1', options = opts, arguments = '.') - -test.run(program = work1_foo, stdout = """repository/aaa.c -repository/bbb.c -repository/foo.c -""") - -test.up_to_date(chdir = 'work1', options = opts, arguments = '.') - -# -test.write(['work1', 'bbb.c'], r""" -#include -#include -void -bbb(void) -{ - printf("work1/bbb.c\n"); -} -""") - -test.run(chdir = 'work1', options = opts, arguments = '.') - -test.run(program = work1_foo, stdout = """repository/aaa.c -work1/bbb.c -repository/foo.c -""") - -test.up_to_date(chdir = 'work1', options = opts, arguments = '.') - -# -test.write(['work1', 'aaa.c'], r""" -#include -#include -void -aaa(void) -{ - printf("work1/aaa.c\n"); -} -""") - -test.write(['work1', 'foo.c'], r""" -#include -#include -extern void aaa(void); -extern void bbb(void); -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - aaa(); - bbb(); - printf("work1/foo.c\n"); - exit (0); -} -""") - -test.run(chdir = 'work1', options = opts, arguments = '.') - -test.run(program = work1_foo, stdout = """work1/aaa.c -work1/bbb.c -work1/foo.c -""") - -test.up_to_date(chdir = 'work1', options = opts, arguments = '.') - -# -test.unlink(['work1', 'bbb.c']) -test.unlink(['work1', 'foo.c']) - -test.run(chdir = 'work1', options = opts, arguments = '.') - -test.run(program = work1_foo, stdout = """work1/aaa.c -repository/bbb.c -repository/foo.c -""") - -test.up_to_date(chdir = 'work1', options = opts, arguments = '.') - - - -# -test.subdir('r.NEW', 'r.OLD', 'work2') - -workpath_r_NEW = test.workpath('r.NEW') -workpath_r_OLD = test.workpath('r.OLD') -work2_foo = test.workpath('work2', 'foo' + _exe) - -SConstruct = """ -env = Environment() -env.Program(target = 'foo', source = 'foo.c') -""" - -test.write(['r.OLD', 'SConstruct'], SConstruct) - -test.write(['r.NEW', 'SConstruct'], SConstruct) - -test.write(['r.OLD', 'foo.c'], r""" -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("r.OLD/foo.c\n"); - exit (0); -} -""") - -opts = '-Y %s -Y %s' % (workpath_r_NEW, workpath_r_OLD) - -# Make the repositories non-writable, so we'll detect -# if we try to write into them accidentally. -test.writable('r.OLD', 0) -test.writable('r.NEW', 0) - -test.run(chdir = 'work2', options = opts, arguments = '.') - -test.run(program = work2_foo, stdout = "r.OLD/foo.c\n") - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - -# -test.writable('r.NEW', 1) - -test.write(['r.NEW', 'foo.c'], r""" -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("r.NEW/foo.c\n"); - exit (0); -} -""") - -test.writable('r.NEW', 0) - -test.run(chdir = 'work2', options = opts, arguments = '.') - -test.run(program = work2_foo, stdout = "r.NEW/foo.c\n") - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - -# -test.write(['work2', 'foo.c'], r""" -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("work2/foo.c\n"); - exit (0); -} -""") - -test.run(chdir = 'work2', options = opts, arguments = '.') - -test.run(program = work2_foo, stdout = "work2/foo.c\n") - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - -# -test.writable('r.OLD', 1) -test.writable('r.NEW', 1) - -test.write(['r.OLD', 'foo.c'], r""" -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("r.OLD/foo.c 2\n"); - exit (0); -} -""") - -test.write(['r.NEW', 'foo.c'], r""" -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("r.NEW/foo.c 2\n"); - exit (0); -} -""") - -test.writable('r.OLD', 0) -test.writable('r.NEW', 0) - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - -# -test.unlink(['work2', 'foo.c']) - -test.run(chdir = 'work2', options = opts, arguments = '.') - -test.run(program = work2_foo, stdout = "r.NEW/foo.c 2\n") - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - -# -test.writable('r.NEW', 1) - -test.unlink(['r.NEW', 'foo.c']) - -test.writable('r.NEW', 0) - -test.run(chdir = 'work2', options = opts, arguments = '.') - -test.run(program = work2_foo, stdout = "r.OLD/foo.c 2\n") - -test.up_to_date(chdir = 'work2', options = opts, arguments = '.') - - - -# -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/packaging/msi/explicit-target.py scons-4.4.0+dfsg/test/packaging/msi/explicit-target.py --- scons-4.0.1+dfsg/test/packaging/msi/explicit-target.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/packaging/msi/explicit-target.py 2022-07-30 21:48:28.000000000 +0000 @@ -36,7 +36,7 @@ test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Canoot import xml.dom.minidom skipping test\n') diff -Nru scons-4.0.1+dfsg/test/packaging/msi/file-placement.py scons-4.4.0+dfsg/test/packaging/msi/file-placement.py --- scons-4.0.1+dfsg/test/packaging/msi/file-placement.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/packaging/msi/file-placement.py 2022-07-30 21:48:28.000000000 +0000 @@ -35,7 +35,7 @@ test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Cannot import xml.dom.minidom; skipping test\n') diff -Nru scons-4.0.1+dfsg/test/packaging/msi/package.py scons-4.4.0+dfsg/test/packaging/msi/package.py --- scons-4.0.1+dfsg/test/packaging/msi/package.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/packaging/msi/package.py 2022-07-30 21:48:28.000000000 +0000 @@ -35,7 +35,7 @@ test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Canoot import xml.dom.minidom skipping test\n') diff -Nru scons-4.0.1+dfsg/test/packaging/place-files-in-subdirectory.py scons-4.4.0+dfsg/test/packaging/place-files-in-subdirectory.py --- scons-4.0.1+dfsg/test/packaging/place-files-in-subdirectory.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/packaging/place-files-in-subdirectory.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test the requirement to place files in a given subdirectory before archiving. """ -import os import subprocess import TestSCons diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/failed-build.py scons-4.4.0+dfsg/test/Parallel/failed-build/failed-build.py --- scons-4.0.1+dfsg/test/Parallel/failed-build/failed-build.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/failed-build.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,79 @@ +#!/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 a failed build action with -j works as expected. +""" + +import TestSCons + +python = TestSCons.python +test = TestSCons.TestSCons() + +try: + import psutil # noqa: F401 +except ImportError: + test.skip_test("Failed to import psutil required for test, skipping.") + +test.dir_fixture('fixture') + +# We want to verify that -j 2 starts precisely two jobs, the first of +# which fails and the second of which succeeds, and then stops processing +# due to the first build failure - the second build job does not just +# continue processing tasks. To try to control the timing, the two +# task scripts will be managed by a server script which regulates the +# state of the test. +# +# The failure script waits until the server responds that the +# copy script has, in fact, gotten started. If we don't wait, then SCons +# could detect our script failure early (typically if a high system load +# happens to delay SCons' ability to start the next script) and then not +# start the successful script at all. +# +# The successful script waits until the server responds that the +# failure script has finished (the server checks that the task pid does not +# exist). If we don't wait for that, then SCons could detect our successful +# exit first (typically if a high system load happens to delay the failure +# script) and start another job before it sees the failure from the first +# script. +# +# Both scripts are set to bail if they had to wait too long for what +# they expected to see. + +test.run(arguments='-j 2 .', + status=2, + stderr="scons: *** [f3] Error 1\n") + +test.must_not_exist(test.workpath('f3')) +test.must_match(test.workpath('f4'), 'f4.in') +test.must_not_exist(test.workpath('f5')) +test.must_not_exist(test.workpath('f6')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f3.in scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f3.in --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f3.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f3.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +f3.in \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f4.in scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f4.in --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f4.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f4.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +f4.in \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f5.in scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f5.in --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f5.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f5.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +f4.in \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f6.in scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f6.in --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/f6.in 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/f6.in 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +f6.in \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/mycopy.py scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/mycopy.py --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/mycopy.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/mycopy.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,35 @@ +import os +import sys +import time +import http.client + +sys.path.append(os.getcwd()) +from teststate import Response + +conn = http.client.HTTPConnection("127.0.0.1", port=int(sys.argv[3])) +conn.request("GET", "/?set_mycopy_started=1") +conn.getresponse().read() + +with open(sys.argv[1], 'wb') as ofp, open(sys.argv[2], 'rb') as ifp: + ofp.write(ifp.read()) + +WAIT = 10 +count = 0 + +def check_test_state(): + + conn.request("GET", "/?get_myfail_done=1") + response = conn.getresponse() + response.read() + status = response.status + return status == Response.OK.value + +while not check_test_state() and count < WAIT: + time.sleep(0.1) + count += 0.1 + +if count >= WAIT: + sys.exit(99) + +conn.close() +sys.exit(0) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/myfail.py scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/myfail.py --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/myfail.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/myfail.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,31 @@ +import os +import sys +import time +import http.client + +sys.path.append(os.getcwd()) +from teststate import Response + +WAIT = 10 +count = 0 + +conn = http.client.HTTPConnection("127.0.0.1", port=int(sys.argv[3])) + +def check_test_state(): + conn.request("GET", "/?get_mycopy_started=1") + response = conn.getresponse() + response.read() + status = response.status + return status == Response.OK.value + +while not check_test_state() and count < WAIT: + time.sleep(0.1) + count += 0.1 + +if count >= WAIT: + sys.exit(99) + +conn.request("GET", "/?set_myfail_done=1&pid=" + str(os.getpid())) +conn.close() + +sys.exit(1) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/SConstruct scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/SConstruct --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,24 @@ +import sys +import os +import threading + +import random +PORT = random.randint(10000, 60000) + +sys.path.append(os.getcwd()) +from teststate import server_thread + +# this thread will setup a sever for the different tasks to talk to +# and act as a manager of IPC and the different tasks progressing +# the test through different states +x = threading.Thread(target=server_thread, args=(PORT,)) +x.daemon = True +x.start() + +MyCopy = Builder(action=[[sys.executable, 'mycopy.py', '$TARGET', '$SOURCE', str(PORT)]]) +Fail = Builder(action=[[sys.executable, 'myfail.py', '$TARGETS', '$SOURCE', str(PORT)]]) +env = Environment(BUILDERS={'MyCopy' : MyCopy, 'Fail' : Fail}) +env.Fail(target='f3', source='f3.in') +env.MyCopy(target='f4', source='f4.in') +env.MyCopy(target='f5', source='f5.in') +env.MyCopy(target='f6', source='f6.in') \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/teststate.py scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/teststate.py --- scons-4.0.1+dfsg/test/Parallel/failed-build/fixture/teststate.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build/fixture/teststate.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,90 @@ +import http.server +import socketserver +import time +from urllib.parse import urlparse, parse_qs +from threading import Lock +from enum import Enum +import psutil + +class TestState(Enum): + start_state = 0 + mycopy_started = 1 + myfail_done = 2 + +class Response(Enum): + OK = 200 + WAIT = 201 + DONE = 202 + +def server_thread(PORT): + + class S(http.server.BaseHTTPRequestHandler): + + current_state = TestState.start_state + mutex = Lock() + pid_killed_tries = 20 + + def do_GET(self): + gets = parse_qs(urlparse(self.path).query) + + # the two tasks will communicate with the server with basic get + # requests, either updating or getting the state of the test to + # know if they continue. The server is regluating the state and making + # the right criteria is in place from both tasks before moving the + # test state forward. + + if gets.get('set_mycopy_started'): + S.mutex.acquire() + if S.current_state == TestState.start_state: + S.current_state = TestState.mycopy_started + response = Response.OK + else: + response = Response.WAIT + S.mutex.release() + + elif gets.get('get_mycopy_started'): + S.mutex.acquire() + if S.current_state == TestState.mycopy_started: + response = Response.OK + else: + response = Response.WAIT + S.mutex.release() + + elif gets.get('set_myfail_done'): + S.mutex.acquire() + if S.current_state == TestState.mycopy_started: + count = 0 + pid = int(gets.get('pid')[0]) + while psutil.pid_exists(pid) and count < self.pid_killed_tries: + time.sleep(0.5) + count += 1 + if not psutil.pid_exists(pid): + S.current_state = TestState.myfail_done + response = Response.DONE + else: + response = Response.WAIT + else: + response = Response.WAIT + S.mutex.release() + + elif gets.get('get_myfail_done'): + S.mutex.acquire() + if S.current_state == TestState.myfail_done: + response = Response.OK + else: + response = Response.WAIT + S.mutex.release() + + else: + response = Response.WAIT + self.send_response(response.value) + self.send_header('Content-type', 'text/html') + self.end_headers() + if response != Response.DONE: + self.wfile.write("".encode('utf-8')) + + def log_message(self, format, *args): + return + + httpd = socketserver.TCPServer(("127.0.0.1", PORT), S) + httpd.serve_forever() \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Parallel/failed-build.py scons-4.4.0+dfsg/test/Parallel/failed-build.py --- scons-4.0.1+dfsg/test/Parallel/failed-build.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Parallel/failed-build.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -#!/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. -# - -""" -Verify that a failed build action with -j works as expected. -""" - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import TestSCons - -python = TestSCons.python - -try: - import threading -except ImportError: - # if threads are not supported, then - # there is nothing to test - TestCmd.no_result() - sys.exit() - - -test = TestSCons.TestSCons() - -# We want to verify that -j 2 starts precisely two jobs, the first of -# which fails and the second of which succeeds, and then stops processing -# due to the first build failure - the second build job does not just -# continue processing tasks. To try to control the timing, the two -# created build scripts use a pair of marker directories. -# -# The failure script waits until it sees the 'mycopy.started' directory -# that indicates the successful script has, in fact, gotten started. -# If we don't wait, then SCons could detect our script failure early -# (typically if a high system load happens to delay SCons' ability to -# start the next script) and then not start the successful script at all. -# -# The successful script waits until it sees the 'myfail.exiting' directory -# that indicates the failure script has finished (with everything except -# the final sys.exit(), that is). If we don't wait for that, then SCons -# could detect our successful exit first (typically if a high system -# load happens to delay the failure script) and start another job before -# it sees the failure from the first script. -# -# Both scripts are set to bail if they had to wait too long for what -# they expected to see. - -test.write('myfail.py', """\ -import os -import sys -import time -WAIT = 10 -count = 0 -while not os.path.exists('mycopy.started') and count < WAIT: - time.sleep(1) - count += 1 -if count >= WAIT: - sys.exit(99) -os.mkdir('myfail.exiting') -sys.exit(1) -""") - -test.write('mycopy.py', """\ -import os -import sys -import time -os.mkdir('mycopy.started') -with open(sys.argv[1], 'wb') as ofp, open(sys.argv[2], 'rb') as ifp: - ofp.write(ifp.read()) -WAIT = 10 -count = 0 -while not os.path.exists('myfail.exiting') and count < WAIT: - time.sleep(1) - count += 1 -if count >= WAIT: - sys.exit(99) -os.rmdir('mycopy.started') -sys.exit(0) -""") - -test.write('SConstruct', """ -MyCopy = Builder(action=[[r'%(python)s', 'mycopy.py', '$TARGET', '$SOURCE']]) -Fail = Builder(action=[[r'%(python)s', 'myfail.py', '$TARGETS', '$SOURCE']]) -env = Environment(BUILDERS={'MyCopy' : MyCopy, 'Fail' : Fail}) -env.Fail(target='f3', source='f3.in') -env.MyCopy(target='f4', source='f4.in') -env.MyCopy(target='f5', source='f5.in') -env.MyCopy(target='f6', source='f6.in') -""" % locals()) - -test.write('f3.in', "f3.in\n") -test.write('f4.in', "f4.in\n") -test.write('f5.in', "f5.in\n") -test.write('f6.in', "f6.in\n") - -test.run(arguments='-j 2 .', - status=2, - stderr="scons: *** [f3] Error 1\n") - -test.must_not_exist(test.workpath('f3')) -test.must_match(test.workpath('f4'), 'f4.in\n') -test.must_not_exist(test.workpath('f5')) -test.must_not_exist(test.workpath('f6')) - - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/PharLap.py scons-4.4.0+dfsg/test/PharLap.py --- scons-4.0.1+dfsg/test/PharLap.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/PharLap.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 import sys @@ -284,10 +283,10 @@ @asm.emb """) -test.write("SConstruct", """ -env=Environment(tools = [ 'linkloc', '386asm' ], - ASFLAGS='-twocase -cvsym', - LINKFLAGS='@foo.lnk') +test.write("SConstruct", """\ +env = Environment( + tools=['linkloc', '386asm'], ASFLAGS='-twocase -cvsym', LINKFLAGS='@foo.lnk' +) env.Program(target='minasm', source='minasm.asm') """) @@ -304,8 +303,8 @@ """) oldtime = os.path.getmtime(test.workpath('minasm.exe')) -time.sleep(2) # Give the time stamp time to change -test.run(arguments = '.') +test.sleep() # delay for timestamps +test.run(arguments='.') test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe'))) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Program.py scons-4.4.0+dfsg/test/Program.py --- scons-4.0.1+dfsg/test/Program.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Program.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 time @@ -40,13 +39,13 @@ foo5 = test.workpath('foo5' + _exe) foo_args = 'foo1%s foo2%s foo3%s foo4%s foo5%s' % (_exe, _exe, _exe, _exe, _exe) -test.write('SConstruct', """ +test.write('SConstruct', """\ env = Environment() -env.Program(target = 'foo1', source = 'f1.c') -env.Program(target = 'foo2', source = Split('f2a.c f2b.c f2c.c')) +env.Program(target='foo1', source='f1.c') +env.Program(target='foo2', source=Split('f2a.c f2b.c f2c.c')) f3a = File('f3a.c') f3b = File('f3b.c') -Program(target = 'foo3', source = [f3a, [f3b, 'f3c.c']]) +Program(target='foo3', source=[f3a, [f3b, 'f3c.c']]) env.Program('foo4', 'f4.c') env.Program('foo5.c') """) @@ -156,15 +155,14 @@ } """) -test.run(arguments = '.') +test.run(arguments='.') -test.run(program = foo1, stdout = "f1.c\n") -test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n") -test.run(program = foo3, stdout = "f3a.c\nf3b.c\nf3c.c\n") -test.run(program = foo4, stdout = "f4.c\n") -test.run(program = foo5, stdout = "foo5.c\n") - -test.up_to_date(arguments = '.') +test.run(program=foo1, stdout="f1.c\n") +test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n") +test.run(program=foo3, stdout="f3a.c\nf3b.c\nf3c.c\n") +test.run(program=foo4, stdout="f4.c\n") +test.run(program=foo5, stdout="foo5.c\n") +test.up_to_date(arguments='.') test.write('f1.c', r""" #include @@ -211,15 +209,14 @@ } """) -test.run(arguments = '.') - -test.run(program = foo1, stdout = "f1.c X\n") -test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n") -test.run(program = foo3, stdout = "f3a.c\nf3b.c X\nf3c.c\n") -test.run(program = foo4, stdout = "f4.c X\n") -test.run(program = foo5, stdout = "foo5.c X\n") +test.run(arguments='.') -test.up_to_date(arguments = '.') +test.run(program=foo1, stdout="f1.c X\n") +test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n") +test.run(program=foo3, stdout="f3a.c\nf3b.c X\nf3c.c\n") +test.run(program=foo4, stdout="f4.c X\n") +test.run(program=foo5, stdout="foo5.c X\n") +test.up_to_date(arguments='.') # make sure the programs didn't get rebuilt, because nothing changed: oldtime1 = os.path.getmtime(foo1) @@ -228,10 +225,8 @@ oldtime4 = os.path.getmtime(foo4) oldtime5 = os.path.getmtime(foo5) -time.sleep(2) # introduce a small delay, to make the test valid - -test.run(arguments = foo_args) - +test.sleep() # delay for timestamps +test.run(arguments=foo_args) test.fail_test(oldtime1 != os.path.getmtime(foo1)) test.fail_test(oldtime2 != os.path.getmtime(foo2)) test.fail_test(oldtime3 != os.path.getmtime(foo3)) @@ -284,15 +279,14 @@ } """) -test.run(arguments = foo_args) - -test.run(program = foo1, stdout = "f1.c Y\n") -test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n") -test.run(program = foo3, stdout = "f3a.c\nf3b.c Y\nf3c.c\n") -test.run(program = foo4, stdout = "f4.c Y\n") -test.run(program = foo5, stdout = "foo5.c Y\n") +test.run(arguments=foo_args) -test.up_to_date(arguments = foo_args) +test.run(program=foo1, stdout="f1.c Y\n") +test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n") +test.run(program=foo3, stdout="f3a.c\nf3b.c Y\nf3c.c\n") +test.run(program=foo4, stdout="f4.c Y\n") +test.run(program=foo5, stdout="foo5.c Y\n") +test.up_to_date(arguments=foo_args) test.write('f1.c', r""" #include @@ -340,15 +334,14 @@ } """) -test.run(arguments = foo_args) - -test.run(program = foo1, stdout = "f1.c Z\n") -test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n") -test.run(program = foo3, stdout = "f3a.c\nf3b.c Z\nf3c.c\n") -test.run(program = foo4, stdout = "f4.c Z\n") -test.run(program = foo5, stdout = "foo5.c Z\n") +test.run(arguments=foo_args) -test.up_to_date(arguments = foo_args) +test.run(program=foo1, stdout="f1.c Z\n") +test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n") +test.run(program=foo3, stdout="f3a.c\nf3b.c Z\nf3c.c\n") +test.run(program=foo4, stdout="f4.c Z\n") +test.run(program=foo5, stdout="foo5.c Z\n") +test.up_to_date(arguments=foo_args) # make sure the programs didn't get rebuilt, because nothing changed: oldtime1 = os.path.getmtime(foo1) @@ -357,10 +350,8 @@ oldtime4 = os.path.getmtime(foo4) oldtime5 = os.path.getmtime(foo5) -time.sleep(2) # introduce a small delay, to make the test valid - -test.run(arguments = foo_args) - +test.sleep() # delay for timestamps +test.run(arguments=foo_args) test.fail_test(not (oldtime1 == os.path.getmtime(foo1))) test.fail_test(not (oldtime2 == os.path.getmtime(foo2))) test.fail_test(not (oldtime3 == os.path.getmtime(foo3))) diff -Nru scons-4.0.1+dfsg/test/Progress/file.py scons-4.4.0+dfsg/test/Progress/file.py --- scons-4.0.1+dfsg/test/Progress/file.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Progress/file.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -20,9 +21,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__" """ Verify that the file= argument to Progress() allows us to redirect the @@ -36,9 +34,18 @@ test = TestSCons.TestSCons() test.write('SConstruct', """\ +import atexit env = Environment() env['BUILDERS']['C'] = Builder(action=Copy('$TARGET', '$SOURCE')) -Progress('stderr: $TARGET\\n', file=open('progress.out', 'w')) +fo = open('progress.out', 'w') +Progress('stderr: $TARGET\\n', file=fo) + +# close file at exit +def close_it(): + fo.close() + +atexit.register(close_it) + env.C('S1.out', 'S1.in') env.C('S2.out', 'S2.in') env.C('S3.out', 'S3.in') diff -Nru scons-4.0.1+dfsg/test/Progress/multi_target_fixture/SConstruct scons-4.4.0+dfsg/test/Progress/multi_target_fixture/SConstruct --- scons-4.0.1+dfsg/test/Progress/multi_target_fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Progress/multi_target_fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,15 @@ +import SCons + + +class ProgressTest: + + def __call__(self, node): + if node.get_state() == SCons.Node.executing: + print(node) + + +env = Environment(tools=[]) +env.Command(target=['out1.txt', 'out2.txt'], source=['in.txt'], action=Action( + 'echo $SOURCE > ${TARGETS[0]};echo $SOURCE > ${TARGETS[1]}', None)) +Progress(ProgressTest()) + diff -Nru scons-4.0.1+dfsg/test/Progress/multi-target.py scons-4.4.0+dfsg/test/Progress/multi-target.py --- scons-4.0.1+dfsg/test/Progress/multi-target.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Progress/multi-target.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# 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. +# + +""" +Test to make sure multitarget progress receives status on all target nodes. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.dir_fixture('multi_target_fixture') + +test.run(arguments='out2.txt -Q') + +test.must_contain_exactly_lines(test.stdout(), ['out1.txt', 'out2.txt']) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Progress/spinner.py scons-4.4.0+dfsg/test/Progress/spinner.py --- scons-4.0.1+dfsg/test/Progress/spinner.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Progress/spinner.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ that represents a canonical "spinner" on the output. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/Progress/TARGET.py scons-4.4.0+dfsg/test/Progress/TARGET.py --- scons-4.0.1+dfsg/test/Progress/TARGET.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Progress/TARGET.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ overwriting it by setting the overwrite= keyword argument. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/python-version.py scons-4.4.0+dfsg/test/python-version.py --- scons-4.0.1+dfsg/test/python-version.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/python-version.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ of Python. """ -import os import re import TestCmd diff -Nru scons-4.0.1+dfsg/test/QT/copied-env.py scons-4.4.0+dfsg/test/QT/copied-env.py --- scons-4.0.1+dfsg/test/QT/copied-env.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/copied-env.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -25,8 +27,6 @@ Test Qt with a copied construction environment. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons test = TestSCons.TestSCons() @@ -63,7 +63,7 @@ void aaa(void) """) -test.run() +test.run(arguments="--warn=no-tool-qt-deprecated") moc_MyForm = [x for x in test.stdout().split('\n') if x.find('moc_MyForm') != -1] diff -Nru scons-4.0.1+dfsg/test/QT/CPPPATH-appended.py scons-4.4.0+dfsg/test/QT/CPPPATH-appended.py --- scons-4.0.1+dfsg/test/QT/CPPPATH-appended.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/CPPPATH-appended.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that an appended relative CPPPATH works with generated files. @@ -70,7 +69,7 @@ /* empty; just needs to be found */ """) -test.run(arguments = aaa_exe) +test.run(arguments='--warn=no-tool-qt-deprecated ' + aaa_exe) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/CPPPATH.py scons-4.4.0+dfsg/test/QT/CPPPATH.py --- scons-4.0.1+dfsg/test/QT/CPPPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/CPPPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that an overwritten CPPPATH works with generated files. @@ -60,7 +59,7 @@ /* empty; just needs to be found */ """) -test.run(arguments = aaa_exe) +test.run(arguments='--warn=no-tool-qt-deprecated ' + aaa_exe) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/empty-env.py scons-4.4.0+dfsg/test/QT/empty-env.py --- scons-4.0.1+dfsg/test/QT/empty-env.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/empty-env.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test Qt creation from a copied empty environment. @@ -62,11 +61,14 @@ # we can receive warnings about a non detected qt (empty QTDIR) # these are not critical, but may be annoying. -test.run(stderr=None) +test.run(stderr=None, arguments='--warn=no-tool-qt-deprecated') -test.run(program = test.workpath('main' + TestSCons._exe), - stderr = None, - stdout = 'qt/include/foo6.h\n') +test.run( + program=test.workpath('main' + TestSCons._exe), + arguments='--warn=no-tool-qt-deprecated', + stderr=None, + stdout='qt/include/foo6.h\n', +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/generated-ui.py scons-4.4.0+dfsg/test/QT/generated-ui.py --- scons-4.0.1+dfsg/test/QT/generated-ui.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/generated-ui.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the UI scanning logic correctly picks up scansG @@ -120,11 +119,13 @@ """) -test.run(arguments = '.', - stderr = TestSCons.noisy_ar, - match = TestSCons.match_re_dotall) +test.run( + arguments='--warn=no-tool-qt-deprecated', + stderr=TestSCons.noisy_ar, + match=TestSCons.match_re_dotall, +) -test.up_to_date(arguments = '.') +test.up_to_date(options="--warn=no-tool-qt-deprecated", arguments=".") test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/installed.py scons-4.4.0+dfsg/test/QT/installed.py --- scons-4.0.1+dfsg/test/QT/installed.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/installed.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Look if qt is installed, and try out all builders. @@ -173,13 +172,15 @@ } """) -test.run(arguments="bld/test_realqt" + TestSCons._exe) +test.run(arguments="--warn=no-tool-qt-deprecated bld/test_realqt" + TestSCons._exe) - -test.run(program=test.workpath("bld", "test_realqt"), - stdout=None, - status=None, - stderr=None) +test.run( + program=test.workpath("bld", "test_realqt"), + arguments="--warn=no-tool-qt-deprecated", + stdout=None, + status=None, + stderr=None, +) if test.stdout() != "Hello World\n" or test.stderr() != '' or test.status: sys.stdout.write(test.stdout()) @@ -191,23 +192,24 @@ expect = 'cannot connect to X server' test.fail_test(test.stdout()) test.fail_test(expect not in test.stderr()) - if test.status != 1 and (test.status>>8) != 1: + if test.status != 1 and (test.status >> 8) != 1: sys.stdout.write('test_realqt returned status %s\n' % test.status) test.fail_test() QTDIR = os.environ['QTDIR'] PATH = os.environ['PATH'] -os.environ['QTDIR']='' -os.environ['PATH']='.' +os.environ['QTDIR'] = '' +os.environ['PATH'] = '.' -test.run(stderr=None, arguments="-c bld/test_realqt" + TestSCons._exe) +test.run( + stderr=None, + arguments="--warn=no-tool-qt-deprecated -c bld/test_realqt" + TestSCons._exe, +) expect1 = "scons: warning: Could not detect qt, using empty QTDIR" expect2 = "scons: warning: Could not detect qt, using moc executable as a hint" -test.fail_test(expect1 not in test.stderr() and - expect2 not in test.stderr()) - +test.fail_test(expect1 not in test.stderr() and expect2 not in test.stderr()) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/manual.py scons-4.4.0+dfsg/test/QT/manual.py --- scons-4.0.1+dfsg/test/QT/manual.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/manual.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the manual QT builder calls. @@ -124,7 +123,7 @@ } """) -test.run(arguments = aaa_exe) +test.run(arguments="--warn=no-tool-qt-deprecated " + aaa_exe) # normal invocation test.must_exist(test.workpath('include', 'moc_aaa.cc')) diff -Nru scons-4.0.1+dfsg/test/QT/moc-from-cpp.py scons-4.4.0+dfsg/test/QT/moc-from-cpp.py --- scons-4.0.1+dfsg/test/QT/moc-from-cpp.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/moc-from-cpp.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Create a moc file from a cpp file. @@ -64,11 +63,13 @@ } """) -test.run(arguments=lib_aaa, - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) +test.run( + arguments="--warn=no-tool-qt-deprecated " + lib_aaa, + stderr=TestSCons.noisy_ar, + match=TestSCons.match_re_dotall, +) -test.up_to_date(options = '-n', arguments = lib_aaa) +test.up_to_date(options='-n --warn=no-tool-qt-deprecated', arguments=lib_aaa) test.write('aaa.cpp', r""" #include "my_qobject.h" @@ -77,22 +78,30 @@ #include "%s" """ % moc) -test.not_up_to_date(options = '-n', arguments = moc) - -test.run(options = '-c', arguments = lib_aaa) +test.not_up_to_date(options='-n --warn=no-tool-qt-deprecated', arguments=moc) -test.run(arguments = "variant_dir=1 " + test.workpath('build', lib_aaa), - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) +test.run(options="--warn=no-tool-qt-deprecated -c", arguments=lib_aaa) -test.run(arguments = "variant_dir=1 chdir=1 " + test.workpath('build', lib_aaa)) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 " + + test.workpath('build', lib_aaa), + stderr=TestSCons.noisy_ar, + match=TestSCons.match_re_dotall, +) + +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 chdir=1 " + + test.workpath('build', lib_aaa) +) test.must_exist(test.workpath('build', moc)) -test.run(arguments = "variant_dir=1 dup=0 " + - test.workpath('build_dup0', lib_aaa), - stderr=TestSCons.noisy_ar, - match=TestSCons.match_re_dotall) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 dup=0 " + + test.workpath('build_dup0', lib_aaa), + stderr=TestSCons.noisy_ar, + match=TestSCons.match_re_dotall, +) test.must_exist(test.workpath('build_dup0', moc)) diff -Nru scons-4.0.1+dfsg/test/QT/moc-from-header.py scons-4.4.0+dfsg/test/QT/moc-from-header.py --- scons-4.0.1+dfsg/test/QT/moc-from-header.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/moc-from-header.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Create a moc file from a header file. @@ -69,11 +68,8 @@ void aaa(void) Q_OBJECT; """) -test.run() - -test.up_to_date(options = '-n', arguments=aaa_exe) - -test.up_to_date(options = '-n', arguments = aaa_exe) +test.run(arguments="--warn=no-tool-qt-deprecated") +test.up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=aaa_exe) test.write('aaa.h', r""" /* a change */ @@ -81,18 +77,26 @@ void aaa(void) Q_OBJECT; """) -test.not_up_to_date(options='-n', arguments = moc) - -test.run(program = test.workpath(aaa_exe), stdout = 'aaa.h\n') - -test.run(arguments = "variant_dir=1 " + build_aaa_exe) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=moc) -test.run(arguments = "variant_dir=1 chdir=1 " + build_aaa_exe) +test.run( + arguments="--warn=no-tool-qt-deprecated", + program=test.workpath(aaa_exe), + stdout='aaa.h\n', +) + +test.run(arguments="--warn=no-tool-qt-deprecated variant_dir=1 " + build_aaa_exe) + +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 chdir=1 " + build_aaa_exe +) test.must_exist(test.workpath('build', moc)) -test.run(arguments = "variant_dir=1 chdir=1 dup=0 " + - test.workpath('build_dup0', aaa_exe) ) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 chdir=1 dup=0 " + + test.workpath('build_dup0', aaa_exe) +) test.must_exist(['build_dup0', moc]) diff -Nru scons-4.0.1+dfsg/test/QT/QTFLAGS.py scons-4.4.0+dfsg/test/QT/QTFLAGS.py --- scons-4.0.1+dfsg/test/QT/QTFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/QTFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Testing the configuration mechanisms of the 'qt' tool. @@ -40,7 +39,7 @@ test.run( chdir=test.workpath('qt', 'lib'), - arguments='.', + arguments="--warn=no-tool-qt-deprecated .", stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall, ) @@ -138,16 +137,18 @@ } """) -test.run(chdir = 'work1', arguments = "mytest" + _exe) +test.run(chdir='work1', arguments="--warn=no-tool-qt-deprecated mytest" + _exe) -test.must_exist(['work1', 'mmmmocFromH.cxx'], - ['work1', 'mocmocFromCpp.inl'], - ['work1', 'an_ui_file.cxx'], - ['work1', 'uic-an_ui_file.hpp'], - ['work1', 'mmman_ui_file.cxx'], - ['work1', 'another_ui_file.cxx'], - ['work1', 'uic-another_ui_file.hpp'], - ['work1', 'mmmanother_ui_file.cxx']) +test.must_exist( + ['work1', 'mmmmocFromH.cxx'], + ['work1', 'mocmocFromCpp.inl'], + ['work1', 'an_ui_file.cxx'], + ['work1', 'uic-an_ui_file.hpp'], + ['work1', 'mmman_ui_file.cxx'], + ['work1', 'another_ui_file.cxx'], + ['work1', 'uic-another_ui_file.hpp'], + ['work1', 'mmmanother_ui_file.cxx'], +) def _flagTest(test,fileToContentsStart): for f,c in fileToContentsStart.items(): @@ -155,19 +156,29 @@ return 1 return 0 -test.fail_test(_flagTest(test, {'mmmmocFromH.cxx':'/* mymoc.py -z */', - 'mocmocFromCpp.inl':'/* mymoc.py -w */', - 'an_ui_file.cxx':'/* myuic.py -x */', - 'uic-an_ui_file.hpp':'/* myuic.py -y */', - 'mmman_ui_file.cxx':'/* mymoc.py -z */'})) +test.fail_test( + _flagTest( + test, + { + 'mmmmocFromH.cxx': '/* mymoc.py -z */', + 'mocmocFromCpp.inl': '/* mymoc.py -w */', + 'an_ui_file.cxx': '/* myuic.py -x */', + 'uic-an_ui_file.hpp': '/* myuic.py -y */', + 'mmman_ui_file.cxx': '/* mymoc.py -z */', + }, + ) +) test.write(['work2', 'SConstruct'], """ import os.path -env1 = Environment(tools=['qt'], - QTDIR = r'%(QTDIR)s', - QT_BINPATH='$QTDIR/bin64', - QT_LIBPATH='$QTDIR/lib64', - QT_CPPPATH='$QTDIR/h64') + +env1 = Environment( + tools=['qt'], + QTDIR=r'%(QTDIR)s', + QT_BINPATH='$QTDIR/bin64', + QT_LIBPATH='$QTDIR/lib64', + QT_CPPPATH='$QTDIR/h64', +) cpppath = env1.subst('$CPPPATH') if os.path.normpath(cpppath) != os.path.join(r'%(QTDIR)s', 'h64'): @@ -182,11 +193,9 @@ print(qt_moc) Exit(3) -env2 = Environment(tools=['default', 'qt'], - QTDIR = None, - QT_LIB = None, - QT_CPPPATH = None, - QT_LIBPATH = None) +env2 = Environment( + tools=['default', 'qt'], QTDIR=None, QT_LIB=None, QT_CPPPATH=None, QT_LIBPATH=None +) env2.Program('main.cpp') """ % {'QTDIR':QT}) @@ -197,7 +206,7 @@ # Ignore stderr, because if Qt is not installed, # there may be a warning about an empty QTDIR on stderr. -test.run(chdir='work2', stderr=None) +test.run(arguments="--warn=no-tool-qt-deprecated", chdir='work2', stderr=None) test.must_exist(['work2', 'main' + _exe]) diff -Nru scons-4.0.1+dfsg/test/QT/qt_warnings.py scons-4.4.0+dfsg/test/QT/qt_warnings.py --- scons-4.0.1+dfsg/test/QT/qt_warnings.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/qt_warnings.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -25,8 +27,6 @@ Test the Qt tool warnings. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import re @@ -51,7 +51,7 @@ env.StaticLibrary('aaa.cpp') """) -test.run(stderr=None) +test.run(arguments="--warn=no-tool-qt-deprecated", stderr=None) match12 = r""" scons: warning: Generated moc file 'aaa.moc' is not included by 'aaa.cpp' @@ -64,7 +64,7 @@ os.environ['QTDIR'] = test.QT -test.run(arguments='-n noqtdir=1') +test.run(arguments='--warn=no-tool-qt-deprecated -n noqtdir=1') # We'd like to eliminate $QTDIR from the environment as follows: # del os.environ['QTDIR'] @@ -74,7 +74,7 @@ # environment, so it only gets removed from the Python dictionary. # Consequently, we need to just wipe out its value as follows> os.environ['QTDIR'] = '' -test.run(stderr=None, arguments='-n noqtdir=1') +test.run(stderr=None, arguments='--warn=no-tool-qt-deprecated -n noqtdir=1') moc = test.where_is('moc') if moc: diff -Nru scons-4.0.1+dfsg/test/QT/reentrant.py scons-4.4.0+dfsg/test/QT/reentrant.py --- scons-4.0.1+dfsg/test/QT/reentrant.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/reentrant.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test creation from a copied environment that already has QT variables. @@ -59,11 +58,13 @@ int main(void) { foo5(); return 0; } """) -test.run() - -test.run(program = test.workpath('main' + TestSCons._exe), - stdout = 'qt/include/foo5.h\n') +test.run(arguments="--warn=no-tool-qt-deprecated") +test.run( + arguments='--warn=no-tool-qt-deprecated', + program=test.workpath('main' + TestSCons._exe), + stdout='qt/include/foo5.h\n', +) test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/QT/source-from-ui.py scons-4.4.0+dfsg/test/QT/source-from-ui.py --- scons-4.0.1+dfsg/test/QT/source-from-ui.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/source-from-ui.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Create .cpp, .h, moc_....cpp from a .ui file. @@ -68,9 +67,9 @@ } """) -test.run(arguments = aaa_dll) +test.run(arguments="--warn=no-tool-qt-deprecated " + aaa_dll) -test.up_to_date(options='-n', arguments = aaa_dll) +test.up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=aaa_dll) test.write('aaa.ui', r""" /* a change */ @@ -82,11 +81,11 @@ DLLEXPORT void aaa(void) """) -test.not_up_to_date(options = '-n', arguments = moc) -test.not_up_to_date(options = '-n', arguments = cpp) -test.not_up_to_date(options = '-n', arguments = h) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=moc) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=cpp) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=h) -test.run(arguments = aaa_dll) +test.run(arguments="--warn=no-tool-qt-deprecated " + aaa_dll) test.write('aaa.ui', r""" void aaa(void) @@ -94,28 +93,30 @@ """) # test that non-existant ui.h files are ignored (as uic does) -test.run(arguments = aaa_dll) +test.run(arguments="--warn=no-tool-qt-deprecated " + aaa_dll) test.write('aaa.ui.h', r""" /* test dependency to .ui.h */ """) -test.run(arguments = aaa_dll) +test.run(arguments="--warn=no-tool-qt-deprecated " + aaa_dll) test.write('aaa.ui.h', r""" /* changed */ """) -test.not_up_to_date(options = '-n', arguments = obj) -test.not_up_to_date(options = '-n', arguments = cpp) -test.not_up_to_date(options = '-n', arguments = h) -test.not_up_to_date(options = '-n', arguments = moc) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=obj) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=cpp) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=h) +test.not_up_to_date(options='--warn=no-tool-qt-deprecated -n', arguments=moc) # clean up -test.run(arguments = '-c ' + aaa_dll) +test.run(arguments="--warn=no-tool-qt-deprecated -c " + aaa_dll) -test.run(arguments = "variant_dir=1 " + - test.workpath('build', aaa_dll) ) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 " + + test.workpath('build', aaa_dll) +) test.must_exist(test.workpath('build', moc)) test.must_exist(test.workpath('build', cpp)) @@ -127,8 +128,10 @@ cppContents = test.read(test.workpath('build', cpp), mode='r') test.fail_test(cppContents.find('#include "aaa.ui.h"') == -1) -test.run(arguments = "variant_dir=1 chdir=1 " + - test.workpath('build', aaa_dll) ) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 chdir=1 " + + test.workpath('build', aaa_dll) +) test.must_exist(test.workpath('build', moc)) test.must_exist(test.workpath('build', cpp)) @@ -137,12 +140,14 @@ test.must_not_exist(test.workpath(cpp)) test.must_not_exist(test.workpath(h)) -test.run(arguments = "variant_dir=1 chdir=1 dup=0 " + - test.workpath('build_dup0', aaa_dll) ) - -test.must_exist(test.workpath('build_dup0',moc)) -test.must_exist(test.workpath('build_dup0',cpp)) -test.must_exist(test.workpath('build_dup0',h)) +test.run( + arguments="--warn=no-tool-qt-deprecated variant_dir=1 chdir=1 dup=0 " + + test.workpath('build_dup0', aaa_dll) +) + +test.must_exist(test.workpath('build_dup0', moc)) +test.must_exist(test.workpath('build_dup0', cpp)) +test.must_exist(test.workpath('build_dup0', h)) test.must_not_exist(test.workpath(moc)) test.must_not_exist(test.workpath(cpp)) test.must_not_exist(test.workpath(h)) diff -Nru scons-4.0.1+dfsg/test/QT/Tool.py scons-4.4.0+dfsg/test/QT/Tool.py --- scons-4.0.1+dfsg/test/QT/Tool.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/Tool.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -31,8 +33,6 @@ good real-world sanity check on the interaction of some key subsystems. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import TestSCons @@ -145,7 +145,7 @@ env.Tool('qt', ['$TOOL_PATH']) """) -test.run(arguments = '.') +test.run(arguments='--warn=no-tool-qt-deprecated .') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/QT/up-to-date.py scons-4.4.0+dfsg/test/QT/up-to-date.py --- scons-4.0.1+dfsg/test/QT/up-to-date.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/QT/up-to-date.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -22,8 +24,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - """ Validate that a stripped-down real-world Qt configuation (thanks to Leanid Nazdrynau) with a generated .h file is correctly @@ -128,14 +128,12 @@ #include """) -my_obj = 'layer/aclock/qt_bug/my'+_obj +my_obj = 'layer/aclock/qt_bug/my' + _obj -test.run(arguments = my_obj, stderr=None) +test.run(arguments='--warn=no-tool-qt-deprecated ' + my_obj, stderr=None) -expect = my_obj.replace( '/', os.sep ) -test.up_to_date(options = '--debug=explain', - arguments =expect, - stderr=None) +expect = my_obj.replace('/', os.sep) +test.up_to_date(options='--debug=explain', arguments=expect, stderr=None) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/question/Configure.py scons-4.4.0+dfsg/test/question/Configure.py --- scons-4.0.1+dfsg/test/question/Configure.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/question/Configure.py 2022-07-30 21:48:28.000000000 +0000 @@ -36,6 +36,7 @@ import TestCmd import TestSCons +from SCons.Util import get_current_hash_algorithm_used test = TestSCons.TestSCons(match = TestCmd.match_re_dotall) @@ -80,13 +81,22 @@ test.must_not_exist(test.workpath("config.test")) test.must_not_exist(test.workpath("config.log")) +# depending on which default hash function we're using, we'd expect one of the following filenames. +# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files +possible_filenames = { + 'md5': "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in", + 'sha1': "conftest_0a4d55a8d778e5022fab701977c5d840bbc486d0_0.in", + 'sha256': "conftest_a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e_0.in" +} +test_filename = possible_filenames[get_current_hash_algorithm_used()] + # test that targets are not built, if conf_dir exists. # verify that .cache and config.log are not created. # an error should be raised stderr=r""" scons: \*\*\* Cannot update configure test "%s" within a dry-run\. File \S+, line \S+, in \S+ -""" % re.escape(os.path.join("config.test", "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in")) +""" % re.escape(os.path.join("config.test", test_filename)) test.subdir('config.test') @@ -94,7 +104,7 @@ test.must_not_exist(test.workpath("config.test", ".cache")) test.must_not_exist(test.workpath("config.test", "conftest_0")) -test.must_not_exist(test.workpath("config.test", "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in")) +test.must_not_exist(test.workpath("config.test", test_filename)) test.must_not_exist(test.workpath("config.log")) # test that no error is raised, if all targets are up-to-date. In this diff -Nru scons-4.0.1+dfsg/test/rebuild-generated.py scons-4.4.0+dfsg/test/rebuild-generated.py --- scons-4.0.1+dfsg/test/rebuild-generated.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/rebuild-generated.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test case for the bug report: @@ -52,13 +51,16 @@ import os import sys +import sysconfig + import TestSCons test = TestSCons.TestSCons() _obj = TestSCons._obj -if sys.platform == 'win32': +if sys.platform == 'win32' and not sysconfig.get_platform() in ("mingw",): + generator_name = 'generator.bat' test.write(generator_name, '@echo #include "header.hh"') kernel_action = "$SOURCES > $TARGET" @@ -67,28 +69,23 @@ test.write(generator_name, 'echo \'#include "header.hh"\'') kernel_action = "sh $SOURCES > $TARGET" -test.write('SConstruct', """\ +if sysconfig.get_platform() in ("mingw",): + # mingw Python uses a sep of '/', when Command fires, that will not work. + # use its altsep instead, that is the standard Windows separator. + sep = os.altsep +else: + sep = os.sep + +test.write('SConstruct', """\ env = Environment() -kernelDefines = env.Command("header.hh", - "header.hh.in", - Copy('$TARGET', '$SOURCE')) - -kernelImporterSource = env.Command( - "generated.cc", ["%s"], - "%s") - -kernelImporter = env.Program( - kernelImporterSource + ["main.cc"]) - -kernelImports = env.Command( - "KernelImport.hh", kernelImporter, - ".%s$SOURCE > $TARGET") - -osLinuxModule = env.StaticObject( - ["target.cc"]) -""" % (generator_name, kernel_action, os.sep)) +kernelDefines = env.Command("header.hh", "header.hh.in", Copy('$TARGET', '$SOURCE')) +kernelImporterSource = env.Command("generated.cc", ["%s"], "%s") +kernelImporter = env.Program(kernelImporterSource + ["main.cc"]) +kernelImports = env.Command("KernelImport.hh", kernelImporter, ".%s$SOURCE > $TARGET") +osLinuxModule = env.StaticObject(["target.cc"]) +""" % (generator_name, kernel_action, sep)) test.write('main.cc', """\ int diff -Nru scons-4.0.1+dfsg/test/Removed/debug-dtree.py scons-4.4.0+dfsg/test/Removed/debug-dtree.py --- scons-4.0.1+dfsg/test/Removed/debug-dtree.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Removed/debug-dtree.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the --debug=dtree option fails with expected exception @@ -37,7 +36,7 @@ test.write('SConstruct', "") -expect = r"""usage: scons [OPTION] [TARGET] ... +expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS] SCons Error: `dtree' is not a valid debug option type ; please use --tree=derived instead """ diff -Nru scons-4.0.1+dfsg/test/Removed/debug-nomemoizer.py scons-4.4.0+dfsg/test/Removed/debug-nomemoizer.py --- scons-4.0.1+dfsg/test/Removed/debug-nomemoizer.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Removed/debug-nomemoizer.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the --debug=nomemoizer option fails with expected exception @@ -37,7 +36,7 @@ test.write('SConstruct', "") -expect=r"""usage: scons [OPTION] [TARGET] ... +expect=r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS] SCons Error: `nomemoizer' is not a valid debug option type ; there is no replacement """ diff -Nru scons-4.0.1+dfsg/test/Removed/debug-stree.py scons-4.4.0+dfsg/test/Removed/debug-stree.py --- scons-4.0.1+dfsg/test/Removed/debug-stree.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Removed/debug-stree.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the --debug=stree option fails with expected exception @@ -37,7 +36,7 @@ test.write('SConstruct', "") -expect = r"""usage: scons [OPTION] [TARGET] ... +expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS] SCons Error: `stree' is not a valid debug option type ; please use --tree=all,status instead """ diff -Nru scons-4.0.1+dfsg/test/Removed/debug-tree.py scons-4.4.0+dfsg/test/Removed/debug-tree.py --- scons-4.0.1+dfsg/test/Removed/debug-tree.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Removed/debug-tree.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the --debug=tree option fails with expected exception @@ -38,7 +37,7 @@ test.write('SConstruct', "") -expect = r"""usage: scons [OPTION] [TARGET] ... +expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS] SCons Error: `tree' is not a valid debug option type ; please use --tree=all instead """ diff -Nru scons-4.0.1+dfsg/test/Removed/SourceSignatures/Old/no-csigs.py scons-4.4.0+dfsg/test/Removed/SourceSignatures/Old/no-csigs.py --- scons-4.0.1+dfsg/test/Removed/SourceSignatures/Old/no-csigs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Removed/SourceSignatures/Old/no-csigs.py 2022-07-30 21:48:28.000000000 +0000 @@ -66,7 +66,7 @@ \S+ \[build\(target, source, env\)\] """ -test.run_sconsign(arguments = test.workpath('.sconsign'), +test.run_sconsign(arguments = test.workpath(test.get_sconsignname()), stdout = expect) diff -Nru scons-4.0.1+dfsg/test/Repository/absolute-path.py scons-4.4.0+dfsg/test/Repository/absolute-path.py --- scons-4.0.1+dfsg/test/Repository/absolute-path.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/absolute-path.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,20 +22,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 os.path import sys -import TestSCons -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe -test = TestSCons.TestSCons() +test = TestSCons() test.subdir('repository', ['repository', 'src'], @@ -46,7 +41,6 @@ opts = "-Y " + test.workpath('repository') -# test.write(['repository', 'SConstruct'], r""" SConscript(r'%s') """ % src_SConscript) diff -Nru scons-4.0.1+dfsg/test/Repository/CPPPATH.py scons-4.4.0+dfsg/test/Repository/CPPPATH.py --- scons-4.0.1+dfsg/test/Repository/CPPPATH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/CPPPATH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,19 +22,11 @@ # 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 TestSCons +from TestSCons import TestSCons -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' - -test = TestSCons.TestSCons() +test = TestSCons() test.subdir('repository', ['repository', 'include1'], @@ -43,7 +37,6 @@ opts = '-Y ' + test.workpath('repository') -# test.write(['repository', 'include1', 'foo.h'], r""" #define STRING "repository/include1/foo.h" """) diff -Nru scons-4.0.1+dfsg/test/Repository/include.py scons-4.4.0+dfsg/test/Repository/include.py --- scons-4.0.1+dfsg/test/Repository/include.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/include.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,19 +22,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 sys -import TestSCons -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe -test = TestSCons.TestSCons() +test = TestSCons() test.subdir('repository', 'work') diff -Nru scons-4.0.1+dfsg/test/Repository/InstallAs.py scons-4.4.0+dfsg/test/Repository/InstallAs.py --- scons-4.0.1+dfsg/test/Repository/InstallAs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/InstallAs.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/Repository/Install.py scons-4.4.0+dfsg/test/Repository/Install.py --- scons-4.0.1+dfsg/test/Repository/Install.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/Install.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/Repository/JavaH.py scons-4.4.0+dfsg/test/Repository/JavaH.py --- scons-4.0.1+dfsg/test/Repository/JavaH.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/JavaH.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,15 +22,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__" """ Test building Java applications when using Repositories. """ import os +import pathlib import TestSCons @@ -40,17 +40,34 @@ where_java = test.java_where_java() where_javah = test.java_where_javah() +# On some systems, the alternatives system does not remove javah even if the +# preferred Java doesn't have it, check the paths just in case. +javacdir = pathlib.Path(where_javac).parent +javahdir = pathlib.Path(where_javah).parent +if javacdir != javahdir: + test.skip_test("Cannot find Java javah matching javac, skipping test.\n") + java = where_java javac = where_javac javah = where_javah +# TODO: javah no longer exists for Java > 9. Other tests fail +# on certain systems because the java_where_* routines are very greedy +# and may indicate it's found even if the working java is > 9 if there +# was a 1.8 insallation present - and then at runtime it's not found. +# In this case we actually pass the javac/javah that's found by those, +# which means the test will seem to work. We still need to rework this. + ############################################################################### # -test.subdir('rep1', ['rep1', 'src'], - 'work1', - 'work2', - 'work3') +test.subdir( + 'rep1', + ['rep1', 'src'], + 'work1', + 'work2', + 'work3', +) # rep1_classes = test.workpath('rep1', 'classes') @@ -62,11 +79,9 @@ # test.write(['rep1', 'SConstruct'], """ -env = Environment(tools = ['javac', 'javah'], - JAVAC = r'"%s"', - JAVAH = r'"%s"') -classes = env.Java(target = 'classes', source = 'src') -env.JavaH(target = 'outdir', source = classes) +env = Environment(tools=['javac', 'javah'], JAVAC=r'"%s"', JAVAH=r'"%s"') +classes = env.Java(target='classes', source='src') +env.JavaH(target='outdir', source=classes) """ % (javac, javah)) test.write(['rep1', 'src', 'Foo1.java'], """\ @@ -206,11 +221,9 @@ # test.write(['work3', 'SConstruct'], """ -env = Environment(tools = ['javac', 'javah'], - JAVAC = r'"%s"', - JAVAH = r'"%s"') -classes = env.Java(target = 'classes', source = 'src') -hfiles = env.JavaH(target = 'outdir', source = classes) +env = Environment(tools=['javac', 'javah'], JAVAC=r'"%s"', JAVAH=r'"%s"') +classes = env.Java(target='classes', source='src') +hfiles = env.JavaH(target='outdir', source=classes) Local(hfiles) """ % (javac, javah)) diff -Nru scons-4.0.1+dfsg/test/Repository/link-object.py scons-4.4.0+dfsg/test/Repository/link-object.py --- scons-4.0.1+dfsg/test/Repository/link-object.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/link-object.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,31 +22,19 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe +test = TestSCons() -test = TestSCons.TestSCons() - -# test.subdir('repository', 'work') -# workpath_repository = test.workpath('repository') repository_foo = test.workpath('repository', 'foo' + _exe) work_foo = test.workpath('work', 'foo' + _exe) -# test.write(['repository', 'SConstruct'], """ Repository(r'%s') env = Environment() diff -Nru scons-4.0.1+dfsg/test/Repository/M4.py scons-4.4.0+dfsg/test/Repository/M4.py --- scons-4.0.1+dfsg/test/Repository/M4.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/M4.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test that $M4 and $M4FLAGS work with repositories. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/Repository/multi-dir.py scons-4.4.0+dfsg/test/Repository/multi-dir.py --- scons-4.0.1+dfsg/test/Repository/multi-dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/multi-dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,23 +22,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 sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons +test = TestSCons() -test = TestSCons.TestSCons() - -# test.subdir('work', ['work', 'src'], ['work', 'include'], @@ -44,7 +36,6 @@ ['repository', 'src'], ['repository', 'include']) -# workpath_repository = test.workpath('repository') work_include_my_string_h = test.workpath('work', 'include', 'my_string.h') work_src_xxx = test.workpath('work', 'src', 'xxx') @@ -52,7 +43,6 @@ opts = "-Y " + workpath_repository -# test.write(['repository', 'SConstruct'], """ env = Environment(CPPPATH = ['#src', '#include']) SConscript('src/SConscript', "env") diff -Nru scons-4.0.1+dfsg/test/Repository/no-repository.py scons-4.4.0+dfsg/test/Repository/no-repository.py --- scons-4.0.1+dfsg/test/Repository/no-repository.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/no-repository.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,22 +22,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 sys -import TestSCons - -python = TestSCons.python - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe -test = TestSCons.TestSCons() +test = TestSCons() test.subdir('work') diff -Nru scons-4.0.1+dfsg/test/Repository/no-SConsignFile.py scons-4.4.0+dfsg/test/Repository/no-SConsignFile.py --- scons-4.0.1+dfsg/test/Repository/no-SConsignFile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/no-SConsignFile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that using Repository() works even when the Repository has no @@ -63,13 +62,10 @@ # Make sure it's past the max_drift time, # so the source file signatures get saved. -test.sleep(2) +test.sleep() # delay for timestamps test.run(chdir='build', arguments='.') - -test.run(program=test.workpath('build', 'foo'), - stdout="src/foo.h\nsrc/foo.c\n") - +test.run(program=test.workpath('build', 'foo'), stdout="src/foo.h\nsrc/foo.c\n") test.up_to_date(chdir='build', arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/Repository/Program.py scons-4.4.0+dfsg/test/Repository/Program.py --- scons-4.0.1+dfsg/test/Repository/Program.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/Program.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,21 +22,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 sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe for implicit_deps in ['0', '1', '2', '\"all\"']: # First, test a single repository. - test = TestSCons.TestSCons() + test = TestSCons() test.subdir('repository', 'work1') repository = test.workpath('repository') repository_foo_c = test.workpath('repository', 'foo.c') diff -Nru scons-4.0.1+dfsg/test/Repository/SConscript.py scons-4.4.0+dfsg/test/Repository/SConscript.py --- scons-4.0.1+dfsg/test/Repository/SConscript.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/SConscript.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,25 +22,16 @@ # 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 how we handle SConscript calls when using a Repository. """ import sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons -test = TestSCons.TestSCons() +test = TestSCons() -# test.subdir('work', ['work', 'src'], 'rep1', @@ -48,11 +41,9 @@ ['rep2', 'src'], ['rep2', 'src', 'sub']) -# workpath_rep1 = test.workpath('rep1') workpath_rep2 = test.workpath('rep2') -# test.write(['work', 'SConstruct'], """ Repository(r'%s') SConscript('src/SConscript') diff -Nru scons-4.0.1+dfsg/test/Repository/top-level-path.py scons-4.4.0+dfsg/test/Repository/top-level-path.py --- scons-4.0.1+dfsg/test/Repository/top-level-path.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/top-level-path.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,20 +22,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 os.path import sys -import TestSCons -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe -test = TestSCons.TestSCons() +test = TestSCons() test.subdir('repository', ['repository', 'src'], @@ -45,7 +40,6 @@ opts = "-Y " + test.workpath('repository') -# test.write(['repository', 'SConstruct'], r""" SConscript(r'%s') """ % src_SConscript) diff -Nru scons-4.0.1+dfsg/test/Repository/variants.py scons-4.4.0+dfsg/test/Repository/variants.py --- scons-4.0.1+dfsg/test/Repository/variants.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/variants.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,38 +22,31 @@ # 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 time -import TestSCons -if sys.platform == 'win32': - _obj = '.obj' - _exe = '.exe' -else: - _obj = '.o' - _exe = '' - -test = TestSCons.TestSCons() - -test.subdir('repository', - ['repository', 'src1'], - ['repository', 'src2'], - ['repository', 'src2', 'include'], - ['repository', 'src2', 'xxx'], - ['repository', 'build2'], - ['repository', 'build2', 'foo'], - ['repository', 'build2', 'bar'], - 'work1', - ['work1', 'src1'], - 'work2', - ['work2', 'src2'], - ['work2', 'src2', 'include'], - ['work2', 'src2', 'xxx']) +from TestSCons import TestSCons, _exe, _obj + +test = TestSCons() + +test.subdir( + 'repository', + ['repository', 'src1'], + ['repository', 'src2'], + ['repository', 'src2', 'include'], + ['repository', 'src2', 'xxx'], + ['repository', 'build2'], + ['repository', 'build2', 'foo'], + ['repository', 'build2', 'bar'], + 'work1', + ['work1', 'src1'], + 'work2', + ['work2', 'src2'], + ['work2', 'src2', 'include'], + ['work2', 'src2', 'xxx'], +) aaa_obj = 'aaa' + _obj bbb_obj = 'bbb' + _obj @@ -63,14 +58,18 @@ work1_build1_foo_xxx = test.workpath('work1', 'build1', 'foo', 'xxx') work1_build1_bar_xxx = test.workpath('work1', 'build1', 'bar', 'xxx') -repository_build2_foo_src2_xxx_xxx = test.workpath('repository', 'build2', - 'foo', 'src2', 'xxx', 'xxx') -repository_build2_bar_src2_xxx_xxx = test.workpath('repository', 'build2', - 'bar', 'src2', 'xxx', 'xxx') -work2_build2_foo_src2_xxx_xxx = test.workpath('work2', 'build2', - 'foo', 'src2', 'xxx', 'xxx') -work2_build2_bar_src2_xxx_xxx = test.workpath('work2', 'build2', - 'bar', 'src2', 'xxx', 'xxx') +repository_build2_foo_src2_xxx_xxx = test.workpath( + 'repository', 'build2', 'foo', 'src2', 'xxx', 'xxx' +) +repository_build2_bar_src2_xxx_xxx = test.workpath( + 'repository', 'build2', 'bar', 'src2', 'xxx', 'xxx' +) +work2_build2_foo_src2_xxx_xxx = test.workpath( + 'work2', 'build2', 'foo', 'src2', 'xxx', 'xxx' +) +work2_build2_bar_src2_xxx_xxx = test.workpath( + 'work2', 'build2', 'bar', 'src2', 'xxx', 'xxx' +) opts = "-Y " + test.workpath('repository') @@ -80,12 +79,13 @@ build1_os = "#build1/" + OS default = Environment() ccflags = { - '' : '', - 'foo' : '-DFOO', - 'bar' : '-DBAR', + '': '', + 'foo': '-DFOO', + 'bar': '-DBAR', } -env1 = Environment(CCFLAGS = default.subst('$CCFLAGS %s' % ccflags[OS]), - CPPPATH = build1_os) +env1 = Environment( + CCFLAGS=default.subst('$CCFLAGS %s' % ccflags[OS]), CPPPATH=build1_os +) VariantDir(build1_os, 'src1') SConscript(build1_os + '/SConscript', "env1") @@ -102,8 +102,9 @@ VariantDir('src2', '#src2') default = Environment() -env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DFOO'), - CPPPATH = ['#src2/xxx', '#src2/include']) +env2 = Environment( + CCFLAGS=default.subst('$CCFLAGS -DFOO'), CPPPATH=['#src2/xxx', '#src2/include'] +) SConscript('src2/xxx/SConscript', "env2") """) @@ -112,8 +113,9 @@ VariantDir('src2', '#src2') default = Environment() -env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DBAR'), - CPPPATH = ['#src2/xxx', '#src2/include']) +env2 = Environment( + CCFLAGS=default.subst('$CCFLAGS -DBAR'), CPPPATH=['#src2/xxx', '#src2/include'] +) SConscript('src2/xxx/SConscript', "env2") """) @@ -223,12 +225,11 @@ repository/src1/main.c: REPOSITORY_FOO """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) +database_name = test.get_sconsignname() +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) test.run(program=repository_build2_foo_src2_xxx_xxx, stdout="""\ repository/src2/include/my_string.h: FOO @@ -242,12 +243,10 @@ repository/src2/xxx/main.c: BAR """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) # Make the entire repository non-writable, so we'll detect # if we try to write into it accidentally. @@ -256,15 +255,10 @@ # test.up_to_date(chdir='work1', options=opts + " OS=foo", arguments='build1') -test.fail_test(os.path.exists( - test.workpath('work1', 'build1', 'foo', aaa_obj))) -test.fail_test(os.path.exists( - test.workpath('work1', 'build1', 'foo', bbb_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work1', 'build1', 'foo', main_obj))) - -test.fail_test(os.path.exists( - test.workpath('work1', 'build1', 'foo', xxx_exe))) +test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', aaa_obj))) +test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', bbb_obj))) +test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', main_obj))) +test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', xxx_exe))) # test.run(chdir='work1', options=opts, arguments='OS=bar .') @@ -276,18 +270,13 @@ repository/src1/main.c: REPOSITORY_BAR """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) - +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) test.up_to_date(chdir='work1', options=opts + " OS=bar", arguments='build1') -# Ensure file time stamps will be newer. -time.sleep(2) - +test.sleep() # delay for timestamps test.write(['work1', 'src1', 'iii.h'], r""" #ifdef FOO #define STRING "WORK_FOO" @@ -307,13 +296,10 @@ repository/src1/main.c: WORK_BAR """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) - +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) test.up_to_date(chdir='work1', options=opts + " OS=bar", arguments='build1') # @@ -325,38 +311,39 @@ repository/src1/main.c: WORK_FOO """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) - +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) test.up_to_date(chdir='work1', options=opts + " OS=foo", arguments='build1') - -# test.up_to_date(chdir='work2', options=opts, arguments='build2') -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'foo', 'src2', 'xxx', aaa_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'foo', 'src2', 'xxx', bbb_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'foo', 'src2', 'xxx', main_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'foo', 'src2', 'xxx', xxx_exe))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'bar', 'src2', 'xxx', aaa_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'bar', 'src2', 'xxx', bbb_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'bar', 'src2', 'xxx', main_obj))) -test.fail_test(os.path.exists(test.workpath( - 'work2', 'build2', 'bar', 'src2', 'xxx', xxx_exe))) - -# Ensure file time stamps will be newer. -time.sleep(2) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', aaa_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', bbb_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', main_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', xxx_exe)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', aaa_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', bbb_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', main_obj)) +) +test.fail_test( + os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', xxx_exe)) +) +test.sleep() # delay for timestamps test.write(['work2', 'src2', 'include', 'my_string.h'], r""" #ifdef FOO #define INCLUDE_OS "FOO" @@ -367,7 +354,6 @@ #define INCLUDE_STRING "work2/src2/include/my_string.h: %s\n" """) -# test.run(chdir='work2', options=opts, arguments='build2') test.run(program=work2_build2_foo_src2_xxx_xxx, stdout="""\ @@ -382,16 +368,12 @@ repository/src2/xxx/main.c: BAR """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) - -# Ensure file time stamps will be newer. -time.sleep(2) +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) +test.sleep() # delay for timestamps test.write(['work2', 'src2', 'xxx', 'include.h'], r""" #include #ifdef FOO @@ -417,38 +399,37 @@ repository/src2/xxx/main.c: BAR """) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) -# test.unlink(['work2', 'src2', 'include', 'my_string.h']) - test.run(chdir='work2', options=opts, arguments='build2') -test.run(program=work2_build2_foo_src2_xxx_xxx, stdout="""\ +test.run( + program=work2_build2_foo_src2_xxx_xxx, + stdout="""\ repository/src2/include/my_string.h: FOO work2/src2/xxx/include.h: FOO repository/src2/xxx/main.c: FOO -""") +""", +) -test.run(program=work2_build2_bar_src2_xxx_xxx, stdout="""\ +test.run( + program=work2_build2_bar_src2_xxx_xxx, + stdout="""\ repository/src2/include/my_string.h: BAR work2/src2/xxx/include.h: BAR repository/src2/xxx/main.c: BAR -""") +""", +) -test.fail_test(os.path.exists( - test.workpath('repository', 'src1', '.sconsign'))) -test.fail_test(os.path.exists( - test.workpath('repository', 'src2', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work1', 'src1', '.sconsign'))) -test.fail_test(os.path.exists(test.workpath('work2', 'src2', '.sconsign'))) +test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name))) +test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name))) +test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name))) -# test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/Repository/within-repository.py scons-4.4.0+dfsg/test/Repository/within-repository.py --- scons-4.0.1+dfsg/test/Repository/within-repository.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Repository/within-repository.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,31 +22,19 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys -import TestSCons - -if sys.platform == 'win32': - _exe = '.exe' -else: - _exe = '' +from TestSCons import TestSCons, _exe +test = TestSCons() -test = TestSCons.TestSCons() - -# test.subdir('repository', ['repository', 'src']) -# workpath_repository = test.workpath('repository') repository_foo = test.workpath('repository', 'foo' + _exe) repository_src_bar = test.workpath('repository', 'src', 'bar' + _exe) -# test.write(['repository', 'SConstruct'], """ Repository(r'%s') SConscript('src/SConscript') diff -Nru scons-4.0.1+dfsg/test/runtest/baseline/no_result.py scons-4.4.0+dfsg/test/runtest/baseline/no_result.py --- scons-4.0.1+dfsg/test/runtest/baseline/no_result.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/baseline/no_result.py 2022-07-30 21:48:28.000000000 +0000 @@ -48,11 +48,17 @@ NO RESULT TEST STDERR """ -test.run(arguments='-k -b . test/no_result.py', +test.run(arguments='--no-ignore-skips -k -b . test/no_result.py', status=2, stdout=expect_stdout, stderr=expect_stderr) +test.run(arguments='-k -b . test/no_result.py', + status=0, + stdout=expect_stdout, + stderr=expect_stderr) + + test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/runtest/faillog.py scons-4.4.0+dfsg/test/runtest/faillog.py --- scons-4.0.1+dfsg/test/runtest/faillog.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/faillog.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,81 @@ +#!/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 a list of tests in failed_tests.log to run with the --retry option +""" + +import os.path + +import TestRuntest + +pythonstring = TestRuntest.pythonstring +pythonflags = TestRuntest.pythonflags +test_fail_py = os.path.join('test', 'fail.py') +test_pass_py = os.path.join('test', 'pass.py') + +test = TestRuntest.TestRuntest() +test.subdir('test') +test.write_failing_test(test_fail_py) +test.write_passing_test(test_pass_py) + +expect_stdout = """\ +%(pythonstring)s%(pythonflags)s %(test_fail_py)s +FAILING TEST STDOUT +%(pythonstring)s%(pythonflags)s %(test_pass_py)s +PASSING TEST STDOUT + +Failed the following test: +\t%(test_fail_py)s +""" % locals() + +expect_stderr = """\ +FAILING TEST STDERR +PASSING TEST STDERR +""" + +testlist = [ + test_fail_py, + test_pass_py, +] + +test.run( + arguments='-k --faillog=fail.log %s' % ' '.join(testlist), + status=1, + stdout=expect_stdout, + stderr=expect_stderr, +) +test.must_exist('fail.log') +test.must_contain('fail.log', test_fail_py) +test.must_not_exist('failed_tests.log') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/runtest/fallback.py scons-4.4.0+dfsg/test/runtest/fallback.py --- scons-4.0.1+dfsg/test/runtest/fallback.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/fallback.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -#!/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 that runtest.py falls back (with a warning) using --noqmtest -if it can't find qmtest on the $PATH. -""" - -import os - -import TestRuntest - -pythonstring = TestRuntest.pythonstring -pythonflags = TestRuntest.pythonflags - -test = TestRuntest.TestRuntest() - -# qmtest may be in more than one location in your path -while test.where_is('qmtest'): - qmtest=test.where_is('qmtest') - dir = os.path.split(qmtest)[0] - path = os.environ['PATH'].split(os.pathsep) - path.remove(dir) - os.environ['PATH'] = os.pathsep.join(path) - -test.subdir('test') - -test_fail_py = os.path.join('test', 'fail.py') -test_no_result_py = os.path.join('test', 'no_result.py') -test_pass_py = os.path.join('test', 'pass.py') - -test.write_failing_test(test_fail_py) -test.write_no_result_test(test_no_result_py) -test.write_passing_test(test_pass_py) - -expect_stdout = """\ -%(pythonstring)s%(pythonflags)s %(test_fail_py)s -FAILING TEST STDOUT -%(pythonstring)s%(pythonflags)s %(test_no_result_py)s -NO RESULT TEST STDOUT -%(pythonstring)s%(pythonflags)s %(test_pass_py)s -PASSING TEST STDOUT - -Failed the following test: -\t%(test_fail_py)s - -NO RESULT from the following test: -\t%(test_no_result_py)s -""" % locals() - -expect_stderr = """\ -FAILING TEST STDERR -NO RESULT TEST STDERR -PASSING TEST STDERR -""" - -testlist = [ - test_fail_py, - test_no_result_py, - test_pass_py, -] - -test.run(arguments = '-k '+' '.join(testlist), - status = 1, - stdout = expect_stdout, - stderr = expect_stderr) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/runtest/no_faillog.py scons-4.4.0+dfsg/test/runtest/no_faillog.py --- scons-4.0.1+dfsg/test/runtest/no_faillog.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/no_faillog.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,83 @@ +#!/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 a list of tests in failed_tests.log to run with the --retry option +""" + +import os.path + +import TestRuntest + +pythonstring = TestRuntest.pythonstring +pythonflags = TestRuntest.pythonflags +test_fail_py = os.path.join('test', 'fail.py') +test_pass_py = os.path.join('test', 'pass.py') + +test = TestRuntest.TestRuntest() +test.subdir('test') +test.write_failing_test(test_fail_py) +test.write_passing_test(test_pass_py) + +test.write('failed_tests.log', """\ +%(test_fail_py)s +""" % locals()) + +expect_stdout = """\ +%(pythonstring)s%(pythonflags)s %(test_fail_py)s +FAILING TEST STDOUT +%(pythonstring)s%(pythonflags)s %(test_pass_py)s +PASSING TEST STDOUT + +Failed the following test: +\t%(test_fail_py)s +""" % locals() + +expect_stderr = """\ +FAILING TEST STDERR +PASSING TEST STDERR +""" + +testlist = [ + test_fail_py, + test_pass_py, +] + +test.run( + arguments='-k --no-faillog %s' % ' '.join(testlist), + status=1, + stdout=expect_stdout, + stderr=expect_stderr, +) +test.must_not_exist('failing_tests.log') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/runtest/noqmtest.py scons-4.4.0+dfsg/test/runtest/noqmtest.py --- scons-4.0.1+dfsg/test/runtest/noqmtest.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/noqmtest.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -#!/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 that by default tests are invoked directly via Python, not -using qmtest. -""" - -import os - -import TestRuntest - -pythonstring = TestRuntest.pythonstring -pythonflags = TestRuntest.pythonflags - -test = TestRuntest.TestRuntest() - -test.subdir('test') - -test_fail_py = os.path.join('test', 'fail.py') -test_no_result_py = os.path.join('test', 'no_result.py') -test_pass_py = os.path.join('test', 'pass.py') - -test.write_failing_test(test_fail_py) -test.write_no_result_test(test_no_result_py) -test.write_passing_test(test_pass_py) - -expect_stdout = """\ -%(pythonstring)s%(pythonflags)s %(test_fail_py)s -FAILING TEST STDOUT -%(pythonstring)s%(pythonflags)s %(test_no_result_py)s -NO RESULT TEST STDOUT -%(pythonstring)s%(pythonflags)s %(test_pass_py)s -PASSING TEST STDOUT - -Failed the following test: -\t%(test_fail_py)s - -NO RESULT from the following test: -\t%(test_no_result_py)s -""" % locals() - -expect_stderr = """\ -FAILING TEST STDERR -NO RESULT TEST STDERR -PASSING TEST STDERR -""" - -testlist = [ - test_fail_py, - test_no_result_py, - test_pass_py, -] - -test.run(arguments = '-k %s' % ' '.join(testlist), - status = 1, - stdout = expect_stdout, - stderr = expect_stderr) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/runtest/print_time.py scons-4.4.0+dfsg/test/runtest/print_time.py --- scons-4.0.1+dfsg/test/runtest/print_time.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/print_time.py 2022-07-30 21:48:28.000000000 +0000 @@ -42,13 +42,9 @@ test_pass_py = re.escape(os.path.join('test', 'pass.py')) test = TestRuntest.TestRuntest(match = TestCmd.match_re) - test.subdir('test') - test.write_failing_test(['test', 'fail.py']) - test.write_no_result_test(['test', 'no_result.py']) - test.write_passing_test(['test', 'pass.py']) expect_stdout = """\ diff -Nru scons-4.0.1+dfsg/test/runtest/python.py scons-4.4.0+dfsg/test/runtest/python.py --- scons-4.0.1+dfsg/test/runtest/python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/python.py 2022-07-30 21:48:28.000000000 +0000 @@ -37,9 +37,7 @@ import TestRuntest test = TestRuntest.TestRuntest() - test_pass_py = os.path.join('test', 'pass.py') - head, python = os.path.split(TestRuntest.python) head, dir = os.path.split(head) diff -Nru scons-4.0.1+dfsg/test/runtest/retry.py scons-4.4.0+dfsg/test/runtest/retry.py --- scons-4.0.1+dfsg/test/runtest/retry.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/retry.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,69 @@ +#!/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 a list of tests in failed_tests.log to run with the --retry option +""" + +import os.path + +import TestRuntest + +pythonstring = TestRuntest.pythonstring +pythonflags = TestRuntest.pythonflags +test_fail_py = os.path.join('test', 'fail.py') +test_no_result_py = os.path.join('test', 'no_result.py') +test_pass_py = os.path.join('test', 'pass.py') + +test = TestRuntest.TestRuntest() + +test.subdir('test') +test.write_failing_test(['test', 'fail.py']) +test.write_no_result_test(['test', 'no_result.py']) +test.write_passing_test(['test', 'pass.py']) + +test.write('failed_tests.log', """\ +%(test_fail_py)s +""" % locals()) + +expect_stdout = """\ +%(pythonstring)s%(pythonflags)s %(test_fail_py)s +FAILING TEST STDOUT +""" % locals() + +expect_stderr = """\ +FAILING TEST STDERR +""" + +test.run(arguments='-k --retry', status=1, stdout=expect_stdout, stderr=expect_stderr) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/runtest/SCons.py scons-4.4.0+dfsg/test/runtest/SCons.py --- scons-4.0.1+dfsg/test/runtest/SCons.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/SCons.py 2022-07-30 21:48:28.000000000 +0000 @@ -34,9 +34,7 @@ import TestRuntest test = TestRuntest.TestRuntest() - -test.subdir(['SCons'], - ['SCons', 'suite']) +test.subdir(['SCons'], ['SCons', 'suite']) pythonstring = TestRuntest.pythonstring pythonflags = TestRuntest.pythonflags @@ -44,11 +42,8 @@ src_suite_passTests_py = os.path.join('SCons', 'suite', 'passTests.py') test.write_passing_test(['SCons', 'pass.py']) - test.write_passing_test(['SCons', 'passTests.py']) - test.write_passing_test(['SCons', 'suite', 'pass.py']) - test.write_passing_test(['SCons', 'suite', 'passTests.py']) expect_stdout = """\ diff -Nru scons-4.0.1+dfsg/test/runtest/simple/combined.py scons-4.4.0+dfsg/test/runtest/simple/combined.py --- scons-4.0.1+dfsg/test/runtest/simple/combined.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/simple/combined.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,4 +1,3 @@ - #!/usr/bin/env python # # __COPYRIGHT__ @@ -34,21 +33,17 @@ import TestRuntest -test = TestRuntest.TestRuntest() - pythonstring = TestRuntest.pythonstring pythonflags = TestRuntest.pythonflags test_fail_py = os.path.join('test', 'fail.py') test_no_result_py = os.path.join('test', 'no_result.py') test_pass_py = os.path.join('test', 'pass.py') +test = TestRuntest.TestRuntest() test.subdir('test') - -test.write_failing_test(['test', 'fail.py']) - -test.write_no_result_test(['test', 'no_result.py']) - -test.write_passing_test(['test', 'pass.py']) +test.write_failing_test(test_fail_py) +test.write_no_result_test(test_no_result_py) +test.write_passing_test(test_pass_py) expect_stdout = """\ %(pythonstring)s%(pythonflags)s %(test_fail_py)s @@ -71,10 +66,14 @@ PASSING TEST STDERR """ -test.run(arguments='-k test', - status=1, - stdout=expect_stdout, - stderr=expect_stderr) +test.run( + arguments='-k test', + status=1, + stdout=expect_stdout, + stderr=expect_stderr +) +test.must_exist('failed_tests.log') +test.must_contain('failed_tests.log', test_fail_py) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/runtest/simple/no_result.py scons-4.4.0+dfsg/test/runtest/simple/no_result.py --- scons-4.0.1+dfsg/test/runtest/simple/no_result.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/simple/no_result.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test how we handle a no-results test specified on the command line. @@ -48,11 +47,17 @@ NO RESULT TEST STDERR """ -test.run(arguments='-k test/no_result.py', +test.run(arguments='--no-ignore-skips -k test/no_result.py', status=2, stdout=expect_stdout, stderr=expect_stderr) +test.run(arguments='-k test/no_result.py', + status=0, + stdout=expect_stdout, + stderr=expect_stderr) + + test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/runtest/testlistfile.py scons-4.4.0+dfsg/test/runtest/testlistfile.py --- scons-4.0.1+dfsg/test/runtest/testlistfile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/runtest/testlistfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -26,10 +26,10 @@ """ Test a list of tests to run in a file specified with the -f option. +The commented-out test should not run. """ import os.path -import re import TestRuntest @@ -42,11 +42,8 @@ test = TestRuntest.TestRuntest() test.subdir('test') - test.write_failing_test(['test', 'fail.py']) - test.write_no_result_test(['test', 'no_result.py']) - test.write_passing_test(['test', 'pass.py']) test.write('t.txt', """\ diff -Nru scons-4.0.1+dfsg/test/Scanner/Python/SConstruct scons-4.4.0+dfsg/test/Scanner/Python/SConstruct --- scons-4.0.1+dfsg/test/Scanner/Python/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Scanner/Python/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,16 @@ +import sys + +env = Environment(tools=['python']) + +# Copy each file individually instead of copying the dir. This has the benefit +# of establishing nodes in-memory for each of the resulting files, which helps +# the scanner work correctly. +srcDir = env.Dir('to_be_copied') +for srcNode in srcDir.glob('*'): + for destDir in [env.Dir('package1'), env.Dir('package2')]: + env.Command(destDir.File(srcNode.name), srcNode, + Copy('$TARGET', '$SOURCE')) + +# Don't set a dependency on the copy actions on purpose. Scanner should find +# the dependencies automatically. +env.Command('a.out', 'script.py', '$PYTHON $SOURCE $TARGET', PYTHON=sys.executable) \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Scanner/Python/script.py scons-4.4.0+dfsg/test/Scanner/Python/script.py --- scons-4.0.1+dfsg/test/Scanner/Python/script.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Scanner/Python/script.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,6 @@ +import package1 # noqa: F401 +import package2 # noqa: F401 +import sys + +with open(sys.argv[1], 'w') as f: + f.write('test') diff -Nru scons-4.0.1+dfsg/test/Scanner/Python/to_be_copied/__init__.py scons-4.4.0+dfsg/test/Scanner/Python/to_be_copied/__init__.py --- scons-4.0.1+dfsg/test/Scanner/Python/to_be_copied/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Scanner/Python/to_be_copied/__init__.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1 @@ +from . import helper # noqa: F401 \ No newline at end of file diff -Nru scons-4.0.1+dfsg/test/Scanner/Python.py scons-4.4.0+dfsg/test/Scanner/Python.py --- scons-4.0.1+dfsg/test/Scanner/Python.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Scanner/Python.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# +# 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. + +""" +Functional test for the Python scanner. Validates that the scanner is able to +find dynamically generated dependencies. The SConstruct copies in the +dependencies and runs a script. The expected behavior is that the scanner +picks up these dependencies, so SCons understands that the script shouldn't +be run until the files are copied. +""" + +import TestSCons + +test = TestSCons.TestSCons() +test.dir_fixture('Python') +test.run(arguments = '.') +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/Scanner/Scanner.py scons-4.4.0+dfsg/test/Scanner/Scanner.py --- scons-4.0.1+dfsg/test/Scanner/Scanner.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Scanner/Scanner.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/SConscript/fixture/SConstruct scons-4.4.0+dfsg/test/SConscript/fixture/SConstruct --- scons-4.0.1+dfsg/test/SConscript/fixture/SConstruct 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConscript/fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/test/SConscript/must_exist_deprecation.py scons-4.4.0+dfsg/test/SConscript/must_exist_deprecation.py --- scons-4.0.1+dfsg/test/SConscript/must_exist_deprecation.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConscript/must_exist_deprecation.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test deprecation warning if must_exist flag is used in an 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') +warnmsg = """ +scons: warning: Calling missing SConscript without error is deprecated. +Transition by adding must_exist=False to SConscript calls. +Missing SConscript '{}' +""".format(missing) + test.python_file_line(SConstruct_path, 14) + +expect_stderr = warnmsg +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 -Nru scons-4.0.1+dfsg/test/SConscript/must_exist.py scons-4.4.0+dfsg/test/SConscript/must_exist.py --- scons-4.0.1+dfsg/test/SConscript/must_exist.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConscript/must_exist.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,14 +22,11 @@ # 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 handling of must_exist flag and global setting requiring the file to exist in an SConscript call -''' +""" import os import TestSCons @@ -43,32 +42,32 @@ import sys DefaultEnvironment(tools=[]) -# 1. call should succeed with deprecation warning +# 1. 1st default call should succeed with deprecation warning try: SConscript('missing/SConscript') except SCons.Errors.UserError as e: if _warningOut: _warningOut(e) -# 2. call should succeed with warning +# 2. 2nd default call should succeed with warning (no depr) try: SConscript('missing/SConscript') except SCons.Errors.UserError as e: if _warningOut: _warningOut(e) -# 3. call should raise exception +# 3. must_exist True call should raise exception try: SConscript('missing/SConscript', must_exist=True) except SCons.Errors.UserError as e: if _warningOut: _warningOut(e) -# 4. call should succeed with warning +# 4. must_exist False call should succeed silently try: SConscript('missing/SConscript', must_exist=False) except SCons.Errors.UserError as e: if _warningOut: _warningOut(e) -SCons.Script.set_missing_sconscript_error() # 5. with system setting changed, should raise exception +SCons.Script.set_missing_sconscript_error() try: SConscript('missing/SConscript') except SCons.Errors.UserError as e: @@ -88,7 +87,7 @@ missing = os.path.normpath('missing/SConscript') warn1 = """ scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=0 to SConscript calls. +Transition by adding must_exist=False to SConscript calls. Missing SConscript '{}' """.format(missing) + test.python_file_line(SConstruct_path, 8) @@ -100,19 +99,13 @@ scons: warning: Fatal: missing SConscript '{}' """.format(missing) + test.python_file_line(SConstruct_path, 23) -warn3 = """ -scons: warning: Ignoring missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 26) - err2 = """ scons: warning: Fatal: missing SConscript '{}' """.format(missing) + test.python_file_line(SConstruct_path, 36) -warn4 = """ -scons: warning: Ignoring missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 39) +nowarn = "" -expect_stderr = warn1 + warn2 + err1 + warn3 + err2 + warn4 +expect_stderr = warn1 + warn2 + err1 + nowarn + err2 + nowarn test.run(arguments = ".", stderr = expect_stderr) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SCONSFLAGS.py scons-4.4.0+dfsg/test/SCONSFLAGS.py --- scons-4.0.1+dfsg/test/SCONSFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SCONSFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 @@ -65,7 +64,7 @@ os.environ['SCONSFLAGS'] = '-Z' -expect = r"""usage: scons [OPTION] [TARGET] ... +expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS] SCons Error: no such option: -Z """ diff -Nru scons-4.0.1+dfsg/test/sconsign/corrupt.py scons-4.4.0+dfsg/test/sconsign/corrupt.py --- scons-4.0.1+dfsg/test/sconsign/corrupt.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/corrupt.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,14 +30,20 @@ import TestSCons import TestCmd +import re test = TestSCons.TestSCons(match = TestCmd.match_re) test.subdir('work1', ['work1', 'sub'], 'work2', ['work2', 'sub']) -work1__sconsign_dblite = test.workpath('work1', '.sconsign.dblite') -work2_sub__sconsign = test.workpath('work2', 'sub', '.sconsign') +database_name = test.get_sconsignname() +database_filename = database_name + ".dblite" + +# for test1 we're using the default database filename +work1__sconsign_dblite = test.workpath('work1', database_filename) +# for test 2 we have an explicit hardcode to .sconsign +work2_sub__sconsign = test.workpath('work2', 'sub', database_name) SConstruct_contents = """\ def build1(target, source, env): @@ -57,9 +63,9 @@ test.write(['work1', 'foo.in'], "work1/foo.in\n") stderr = r''' -scons: warning: Ignoring corrupt .sconsign file: \.sconsign\.dblite +scons: warning: Ignoring corrupt .sconsign file: {} .* -''' +'''.format(re.escape(database_filename)) stdout = test.wrap_stdout(r'build1\(\["sub.foo\.out"\], \["foo\.in"\]\)' + '\n') @@ -82,9 +88,9 @@ test.write(['work2', 'foo.in'], "work2/foo.in\n") stderr = r''' -scons: warning: Ignoring corrupt .sconsign file: sub.\.sconsign +scons: warning: Ignoring corrupt .sconsign file: sub.{} .* -''' +'''.format(database_name) stdout = test.wrap_stdout(r'build1\(\["sub.foo\.out"\], \["foo\.in"\]\)' + '\n') diff -Nru scons-4.0.1+dfsg/test/sconsign/nonwritable.py scons-4.4.0+dfsg/test/sconsign/nonwritable.py --- scons-4.0.1+dfsg/test/sconsign/nonwritable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/nonwritable.py 2022-07-30 21:48:28.000000000 +0000 @@ -44,10 +44,11 @@ ['work2', 'sub2'], ['work2', 'sub3']) -work1__sconsign_dblite = test.workpath('work1', '.sconsign.dblite') -work2_sub1__sconsign = test.workpath('work2', 'sub1', '.sconsign') -work2_sub2__sconsign = test.workpath('work2', 'sub2', '.sconsign') -work2_sub3__sconsign = test.workpath('work2', 'sub3', '.sconsign') +database_name = test.get_sconsignname() +work1__sconsign_dblite = test.workpath('work1', database_name + '.dblite') +work2_sub1__sconsign = test.workpath('work2', 'sub1', database_name) +work2_sub2__sconsign = test.workpath('work2', 'sub2', database_name) +work2_sub3__sconsign = test.workpath('work2', 'sub3', database_name) SConstruct_contents = """\ def build1(target, source, env): diff -Nru scons-4.0.1+dfsg/test/sconsign/script/Configure.py scons-4.4.0+dfsg/test/sconsign/script/Configure.py --- scons-4.0.1+dfsg/test/sconsign/script/Configure.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/script/Configure.py 2022-07-30 21:48:28.000000000 +0000 @@ -66,7 +66,7 @@ test.run(arguments = '.') -sig_re = r'[0-9a-fA-F]{32}' +sig_re = r'[0-9a-fA-F]{32,64}' date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d' _sconf_temp_conftest_0_c = '.sconf_temp/conftest_%(sig_re)s_0.c'%locals() @@ -90,7 +90,9 @@ %(CC_file)s: %(sig_re)s \d+ \d+ """ % locals() -test.run_sconsign(arguments = ".sconsign", +# grab .sconsign or .sconsign_ +database_name=test.get_sconsignname() +test.run_sconsign(arguments = database_name, stdout = expect) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/sconsign/script/dblite.py scons-4.4.0+dfsg/test/sconsign/script/dblite.py --- scons-4.0.1+dfsg/test/sconsign/script/dblite.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/script/dblite.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that various ways of getting at a an sconsign file written with @@ -97,19 +96,13 @@ } """) -test.write(['sub2', 'inc1.h'], r"""\ -#define STRING1 "inc1.h" -""") - -test.write(['sub2', 'inc2.h'], r"""\ -#define STRING2 "inc2.h" -""") - -test.sleep() +test.write(['sub2', 'inc1.h'], r'#define STRING1 "inc1.h"') +test.write(['sub2', 'inc2.h'], r'#define STRING2 "inc2.h"') -test.run(arguments = '. --max-drift=1') +test.sleep() # delay for timestamps +test.run(arguments='. --max-drift=1') -sig_re = r'[0-9a-fA-F]{32}' +sig_re = r'[0-9a-fA-F]{32,64}' date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d' if sys.platform == 'win32': @@ -146,23 +139,23 @@ common_flags = '-e hello%(_exe)s -e hello%(_obj)s -d sub1' % locals() -test.run_sconsign(arguments = "%s my_sconsign" % common_flags, - stdout = expect) +test.run_sconsign(arguments="%s my_sconsign" % common_flags, stdout=expect) -test.run_sconsign(arguments = "%s my_sconsign.dblite" % common_flags, - stdout = expect) +test.run_sconsign(arguments="%s my_sconsign.dblite" % common_flags, stdout=expect) -test.run_sconsign(arguments = "%s -f dblite my_sconsign" % common_flags, - stdout = expect) +test.run_sconsign(arguments="%s -f dblite my_sconsign" % common_flags, stdout=expect) -test.run_sconsign(arguments = "%s -f dblite my_sconsign.dblite" % common_flags, - stdout = expect) +test.run_sconsign( + arguments="%s -f dblite my_sconsign.dblite" % common_flags, stdout=expect +) -test.run_sconsign(arguments = "%s -r -f dblite my_sconsign" % common_flags, - stdout = expect_r) +test.run_sconsign( + arguments="%s -r -f dblite my_sconsign" % common_flags, stdout=expect_r +) -test.run_sconsign(arguments = "%s -r -f dblite my_sconsign.dblite" % common_flags, - stdout = expect_r) +test.run_sconsign( + arguments="%s -r -f dblite my_sconsign.dblite" % common_flags, stdout=expect_r +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/sconsign/script/no-SConsignFile.py scons-4.4.0+dfsg/test/sconsign/script/no-SConsignFile.py --- scons-4.0.1+dfsg/test/sconsign/script/no-SConsignFile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/script/no-SConsignFile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the sconsign script works when using an individual @@ -32,12 +31,18 @@ import TestSCons import TestSConsign -_python_ = TestSCons._python_ +from TestSCons import _python_ +from TestCmd import NEED_HELPER test = TestSConsign.TestSConsign(match = TestSConsign.match_re) +if NEED_HELPER: + test.skip_test("Test host cannot directly execute scripts, skipping test\n") + test.subdir('sub1', 'sub2') +database_name = test.get_sconsignname() + # Because this test sets SConsignFile(None), we execute our fake # scripts directly, not by feeding them to the Python executable. # That is, we chmod 0o755 and use a "#!/usr/bin/env python" first @@ -51,7 +56,9 @@ fake_cc_py = test.workpath('fake_cc.py') fake_link_py = test.workpath('fake_link.py') -test.write(fake_cc_py, r"""#!%(_python_)s +test.write( + fake_cc_py, + fr"""#!{_python_} import os import re import sys @@ -78,21 +85,25 @@ outfp.write(line) with open(sys.argv[2], 'w') as outf, open(sys.argv[3], 'r') as ifp: - outf.write('fake_cc.py: %%s\n' %% sys.argv) + outf.write('fake_cc.py: %s\n' % sys.argv) process(ifp, outf) sys.exit(0) -""" % locals()) +""", +) -test.write(fake_link_py, r"""#!%(_python_)s +test.write( + fake_link_py, + fr"""#!{_python_} import sys with open(sys.argv[1], 'w') as outf, open(sys.argv[2], 'r') as ifp: - outf.write('fake_link.py: %%s\n' %% sys.argv) + outf.write('fake_link.py: %s\n' % sys.argv) outf.write(ifp.read()) sys.exit(0) -""" % locals()) +""", +) test.chmod(fake_cc_py, 0o755) test.chmod(fake_link_py, 0o755) @@ -108,42 +119,54 @@ sub2_inc1_h = 'sub2/inc1.h' sub2_inc2_h = 'sub2/inc2.h' -test.write(['SConstruct'], """ +test.write( + ['SConstruct'], + f""" SConsignFile(None) -env1 = Environment(PROGSUFFIX = '.exe', - OBJSUFFIX = '.obj', - # Specify the command lines with lists-of-lists so - # finding the implicit dependencies works even with - # spaces in the fake_*_py path names. - CCCOM = [[r'%(fake_cc_py)s', 'sub2', '$TARGET', '$SOURCE']], - LINKCOM = [[r'%(fake_link_py)s', '$TARGET', '$SOURCE']]) +env1 = Environment( + PROGSUFFIX='.exe', + OBJSUFFIX='.obj', + # Specify the command lines with lists-of-lists so + # finding the implicit dependencies works even with + # spaces in the fake_*_py path names. + CCCOM=[[r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], + LINKCOM=[[r'{fake_link_py}', '$TARGET', '$SOURCE']], +) env1.PrependENVPath('PATHEXT', '.PY') env1.Program('sub1/hello.c') -env2 = env1.Clone(CPPPATH = ['sub2']) +env2 = env1.Clone(CPPPATH=['sub2']) env2.Program('sub2/hello.c') -""" % locals()) +""", +) +# TODO in the above, we would normally want to run a python program +# using "our python" like this: +# CCCOM=[[r'{_python_}', r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], +# LINKCOM=[[r'{_python_}', r'{fake_link_py}', '$TARGET', '$SOURCE']], +# however we're looking at dependencies with sconsign, so that breaks things. +# It still breaks things on Windows if something else is registered as the +# handler for .py files, as Visual Studio Code installs itself. -test.write(['sub1', 'hello.c'], r"""\ +test.write(['sub1', 'hello.c'], r""" sub1/hello.c """) -test.write(['sub2', 'hello.c'], r"""\ +test.write(['sub2', 'hello.c'], r""" #include #include sub2/hello.c """) -test.write(['sub2', 'inc1.h'], r"""\ +test.write(['sub2', 'inc1.h'], r""" #define STRING1 "inc1.h" """) -test.write(['sub2', 'inc2.h'], r"""\ +test.write(['sub2', 'inc2.h'], r""" #define STRING2 "inc2.h" """) test.run(arguments = '--implicit-cache --tree=prune .') -sig_re = r'[0-9a-fA-F]{32}' +sig_re = r'[0-9a-fA-F]{32,64}' expect = r"""hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ @@ -156,9 +179,9 @@ %(sig_re)s \[.*\] """ % locals() -test.run_sconsign(arguments = "sub1/.sconsign", stdout=expect) +test.run_sconsign(arguments = f"sub1/{database_name}", stdout=expect) -test.run_sconsign(arguments = "--raw sub1/.sconsign", +test.run_sconsign(arguments = f"--raw sub1/{database_name}", stdout = r"""hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+L?, 'size': \d+L?, '_version_id': 2} hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+L?, 'size': \d+L?, '_version_id': 2} %(sub1_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+L?, 'size': \d+L?, '_version_id': 2} @@ -170,7 +193,7 @@ %(sig_re)s \[.*\] """ % locals()) -test.run_sconsign(arguments = "-v sub1/.sconsign", +test.run_sconsign(arguments = f"-v sub1/{database_name}", stdout = r"""hello.c: csig: %(sig_re)s timestamp: \d+ @@ -205,7 +228,7 @@ action: %(sig_re)s \[.*\] """ % locals()) -test.run_sconsign(arguments = "-c -v sub1/.sconsign", +test.run_sconsign(arguments = f"-c -v sub1/{database_name}", stdout = r"""hello.c: csig: %(sig_re)s hello.exe: @@ -214,7 +237,7 @@ csig: %(sig_re)s """ % locals()) -test.run_sconsign(arguments = "-s -v sub1/.sconsign", +test.run_sconsign(arguments = f"-s -v sub1/{database_name}", stdout = r"""hello.c: size: \d+ hello.exe: @@ -223,7 +246,7 @@ size: \d+ """ % locals()) -test.run_sconsign(arguments = "-t -v sub1/.sconsign", +test.run_sconsign(arguments = f"-t -v sub1/{database_name}", stdout = r"""hello.c: timestamp: \d+ hello.exe: @@ -232,14 +255,14 @@ timestamp: \d+ """ % locals()) -test.run_sconsign(arguments = "-e hello.obj sub1/.sconsign", +test.run_sconsign(arguments = f"-e hello.obj sub1/{database_name}", stdout = r"""hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ fake_cc\.py: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals()) -test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj sub1/.sconsign", +test.run_sconsign(arguments = f"-e hello.obj -e hello.exe -e hello.obj sub1/{database_name}", stdout = r"""hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ fake_cc\.py: %(sig_re)s \d+ \d+ @@ -254,7 +277,7 @@ %(sig_re)s \[.*\] """ % locals()) -test.run_sconsign(arguments = "sub2/.sconsign", +test.run_sconsign(arguments = f"sub2/{database_name}", stdout = r"""hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ %(sub2_hello_obj)s: %(sig_re)s \d+ \d+ @@ -270,7 +293,7 @@ inc2.h: %(sig_re)s \d+ \d+ """ % locals()) -#test.run_sconsign(arguments = "-i -v sub2/.sconsign", +#test.run_sconsign(arguments = "-i -v sub2/{}".format(database_name), # stdout = r"""hello.c: %(sig_re)s \d+ \d+ #hello.exe: %(sig_re)s \d+ \d+ # implicit: @@ -282,7 +305,7 @@ # inc2.h: %(sig_re)s \d+ \d+ #""" % locals()) -test.run_sconsign(arguments = "-e hello.obj sub2/.sconsign sub1/.sconsign", +test.run_sconsign(arguments = f"-e hello.obj sub2/{database_name} sub1/{database_name}", stdout = r"""hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ diff -Nru scons-4.0.1+dfsg/test/sconsign/script/SConsignFile.py scons-4.4.0+dfsg/test/sconsign/script/SConsignFile.py --- scons-4.0.1+dfsg/test/sconsign/script/SConsignFile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/script/SConsignFile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,28 +22,31 @@ # 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__" """ Verify that the sconsign script works with files generated when using the signatures in an SConsignFile(). """ -import re import TestSCons import TestSConsign -_python_ = TestSCons._python_ +from TestSCons import _python_ +from TestCmd import NEED_HELPER test = TestSConsign.TestSConsign(match = TestSConsign.match_re) + +if NEED_HELPER: + test.skip_test("Test host cannot directly execute scripts, skipping test\n") + test.subdir('sub1', 'sub2') fake_cc_py = test.workpath('fake_cc.py') fake_link_py = test.workpath('fake_link.py') -test.write(fake_cc_py, r"""#!%(_python_)s +test.write( + fake_cc_py, + fr"""#!{_python_} import os import re import sys @@ -68,21 +73,25 @@ outfp.write(line) with open(sys.argv[2], 'w') as outf, open(sys.argv[3], 'r') as ifp: - outf.write('fake_cc.py: %%s\n' %% sys.argv) + outf.write('fake_cc.py: %s\n' % sys.argv) process(ifp, outf) sys.exit(0) -""" % locals()) +""", +) -test.write(fake_link_py, r"""#!%(_python_)s +test.write( + fake_link_py, + fr"""#!{_python_} import sys with open(sys.argv[1], 'w') as outf, open(sys.argv[2], 'r') as ifp: - outf.write('fake_link.py: %%s\n' %% sys.argv) + outf.write('fake_link.py: %s\n' % sys.argv) outf.write(ifp.read()) sys.exit(0) -""" % locals()) +""", +) test.chmod(fake_cc_py, 0o755) test.chmod(fake_link_py, 0o755) @@ -98,17 +107,29 @@ sub2_inc1_h = 'sub2/inc1.h' sub2_inc2_h = 'sub2/inc2.h' -test.write(['SConstruct'], """\ +test.write( + ['SConstruct'], + f"""\ SConsignFile() -env1 = Environment(PROGSUFFIX = '.exe', - OBJSUFFIX = '.obj', - CCCOM = [[r'%(fake_cc_py)s', 'sub2', '$TARGET', '$SOURCE']], - LINKCOM = [[r'%(fake_link_py)s', '$TARGET', '$SOURCE']]) +env1 = Environment( + PROGSUFFIX='.exe', + OBJSUFFIX='.obj', + CCCOM=[[r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], + LINKCOM=[[r'{fake_link_py}', '$TARGET', '$SOURCE']], +) env1.PrependENVPath('PATHEXT', '.PY') env1.Program('sub1/hello.c') -env2 = env1.Clone(CPPPATH = ['sub2']) +env2 = env1.Clone(CPPPATH=['sub2']) env2.Program('sub2/hello.c') -""" % locals()) +""", +) +# TODO in the above, we would normally want to run a python program +# using "our python" like this: +# CCCOM=[[r'{_python_}', r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], +# LINKCOM=[[r'{_python_}', r'{fake_link_py}', '$TARGET', '$SOURCE']], +# however we're looking at dependencies with sconsign, so that breaks things. +# It still breaks things on Windows if something else is registered as the +# handler for .py files, as Visual Studio Code installs itself. test.write(['sub1', 'hello.c'], r""" sub1/hello.c @@ -126,19 +147,21 @@ } """) -test.write(['sub2', 'inc1.h'], r"""\ +test.write(['sub2', 'inc1.h'], r""" #define STRING1 "inc1.h" """) -test.write(['sub2', 'inc2.h'], r"""\ +test.write(['sub2', 'inc2.h'], r""" #define STRING2 "inc2.h" """) test.run(arguments = '--implicit-cache .') -sig_re = r'[0-9a-fA-F]{32}' +sig_re = r'[0-9a-fA-F]{32,64}' + +database_name = test.get_sconsignname() -test.run_sconsign(arguments = ".sconsign", +test.run_sconsign(arguments = database_name, stdout = r"""=== .: SConstruct: None \d+ \d+ fake_cc\.py: %(sig_re)s \d+ \d+ @@ -169,7 +192,7 @@ inc2.h: %(sig_re)s \d+ \d+ """ % locals()) -test.run_sconsign(arguments = "--raw .sconsign", +test.run_sconsign(arguments = "--raw " + database_name, stdout = r"""=== .: SConstruct: {'csig': None, 'timestamp': \d+L?, 'size': \d+L?, '_version_id': 2} fake_cc\.py: {'csig': '%(sig_re)s', 'timestamp': \d+L?, 'size': \d+L?, '_version_id': 2} @@ -297,9 +320,9 @@ size: \d+ """ % locals() -test.run_sconsign(arguments = "-v .sconsign", stdout=expect) +test.run_sconsign(arguments = "-v " + database_name, stdout=expect) -test.run_sconsign(arguments = "-c -v .sconsign", +test.run_sconsign(arguments = "-c -v " + database_name, stdout = r"""=== .: SConstruct: csig: None @@ -327,7 +350,7 @@ csig: %(sig_re)s """ % locals()) -test.run_sconsign(arguments = "-s -v .sconsign", +test.run_sconsign(arguments = "-s -v " + database_name, stdout = r"""=== .: SConstruct: size: \d+ @@ -355,7 +378,7 @@ size: \d+ """ % locals()) -test.run_sconsign(arguments = "-t -v .sconsign", +test.run_sconsign(arguments = "-t -v " + database_name, stdout = r"""=== .: SConstruct: timestamp: \d+ @@ -383,7 +406,7 @@ timestamp: \d+ """ % locals()) -test.run_sconsign(arguments = "-e hello.obj .sconsign", +test.run_sconsign(arguments = "-e hello.obj " + database_name, stdout = r"""=== .: === sub1: hello.obj: %(sig_re)s \d+ \d+ @@ -401,7 +424,7 @@ stderr = r"""sconsign: no entry `hello\.obj' in `\.' """ % locals()) -test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj .sconsign", +test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj " + database_name, stdout = r"""=== .: === sub1: hello.obj: %(sig_re)s \d+ \d+ @@ -439,7 +462,7 @@ sconsign: no entry `hello\.obj' in `\.' """ % locals()) -#test.run_sconsign(arguments = "-i -v .sconsign", +#test.run_sconsign(arguments = "-i -v " + database_name, # stdout = r"""=== sub1: #hello.exe: # implicit: diff -Nru scons-4.0.1+dfsg/test/sconsign/script/Signatures.py scons-4.4.0+dfsg/test/sconsign/script/Signatures.py --- scons-4.0.1+dfsg/test/sconsign/script/Signatures.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/sconsign/script/Signatures.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the sconsign script works when using a .sconsign file in @@ -33,16 +32,20 @@ import TestSCons import TestSConsign -_python_ = TestSCons._python_ +from TestSCons import _python_ +from TestCmd import NEED_HELPER test = TestSConsign.TestSConsign(match = TestSConsign.match_re) +if NEED_HELPER: + test.skip_test("Test host cannot directly execute scripts, skipping test\n") + # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are # canonicalized to use / as the separator. -sub1_hello_c = 'sub1/hello.c' -sub1_hello_obj = 'sub1/hello.obj' +sub1_hello_c = 'sub1/hello.c' +sub1_hello_obj = 'sub1/hello.obj' test.subdir('sub1', 'sub2') @@ -59,7 +62,9 @@ fake_cc_py = test.workpath('fake_cc.py') fake_link_py = test.workpath('fake_link.py') -test.write(fake_cc_py, r"""#!%(_python_)s +test.write( + fake_cc_py, + fr"""#!{_python_} import os import re import sys @@ -86,40 +91,56 @@ outfp.write(line) with open(sys.argv[2], 'w') as outf, open(sys.argv[3], 'r') as ifp: - outf.write('fake_cc.py: %%s\n' %% sys.argv) + outf.write('fake_cc.py: %s\n' % sys.argv) process(ifp, outf) sys.exit(0) -""" % locals()) +""", +) -test.write(fake_link_py, r"""#!%(_python_)s +test.write( + fake_link_py, + fr"""#!{_python_} import sys with open(sys.argv[1], 'w') as outf, open(sys.argv[2], 'r') as ifp: - outf.write('fake_link.py: %%s\n' %% sys.argv) + outf.write('fake_link.py: %s\n' % sys.argv) outf.write(ifp.read()) sys.exit(0) -""" % locals()) +""", +) test.chmod(fake_cc_py, 0o755) test.chmod(fake_link_py, 0o755) -test.write('SConstruct', """ +test.write( + 'SConstruct', + f""" SConsignFile(None) Decider('timestamp-newer') -env1 = Environment(PROGSUFFIX = '.exe', - OBJSUFFIX = '.obj', - # Specify the command lines with lists-of-lists so - # finding the implicit dependencies works even with - # spaces in the fake_*_py path names. - CCCOM = [[r'%(fake_cc_py)s', 'sub2', '$TARGET', '$SOURCE']], - LINKCOM = [[r'%(fake_link_py)s', '$TARGET', '$SOURCE']]) +env1 = Environment( + PROGSUFFIX='.exe', + OBJSUFFIX='.obj', + # Specify the command lines with lists-of-lists so + # finding the implicit dependencies works even with + # spaces in the fake_*_py path names. + CCCOM=[[r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], + LINKCOM=[[r'{fake_link_py}', '$TARGET', '$SOURCE']], +) env1.PrependENVPath('PATHEXT', '.PY') env1.Program('sub1/hello.c') -env2 = env1.Clone(CPPPATH = ['sub2']) +env2 = env1.Clone(CPPPATH=['sub2']) env2.Program('sub2/hello.c') -""" % locals()) +""", +) +# TODO in the above, we would normally want to run a python program +# using "our Python" like this: +# CCCOM=[[r'{_python_}', r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']], +# LINKCOM=[[r'{_python_}', r'{fake_link_py}', '$TARGET', '$SOURCE']], +# however we're looking at dependencies with sconsign, so that breaks things. +# It still breaks things on Windows if something else is registered as the +# handler for .py files, as Visual Studio Code installs itself. test.write(['sub1', 'hello.c'], r"""\ sub1/hello.c @@ -139,15 +160,16 @@ #define STRING2 "inc2.h" """) -test.sleep() - +test.sleep() # delay for timestamps test.run(arguments = '. --max-drift=1') -sig_re = r'[0-9a-fA-F]{32}' +sig_re = r'[0-9a-fA-F]{32,64}' date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d' +database_name = test.get_sconsignname() -test.run_sconsign(arguments = "-e hello.exe -e hello.obj sub1/.sconsign", - stdout = r"""hello.exe: %(sig_re)s \d+ \d+ +test.run_sconsign( + arguments=f"-e hello.exe -e hello.obj sub1/{database_name}", + stdout=r"""hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ fake_link\.py: None \d+ \d+ %(sig_re)s \[.*\] @@ -155,10 +177,12 @@ %(sub1_hello_c)s: None \d+ \d+ fake_cc\.py: None \d+ \d+ %(sig_re)s \[.*\] -""" % locals()) +""" % locals(), +) -test.run_sconsign(arguments = "-e hello.exe -e hello.obj -r sub1/.sconsign", - stdout = r"""hello.exe: %(sig_re)s '%(date_re)s' \d+ +test.run_sconsign( + arguments=f"-e hello.exe -e hello.obj -r sub1/{database_name}", + stdout=r"""hello.exe: %(sig_re)s '%(date_re)s' \d+ %(sub1_hello_obj)s: %(sig_re)s '%(date_re)s' \d+ fake_link\.py: None '%(date_re)s' \d+ %(sig_re)s \[.*\] @@ -166,7 +190,8 @@ %(sub1_hello_c)s: None '%(date_re)s' \d+ fake_cc\.py: None '%(date_re)s' \d+ %(sig_re)s \[.*\] -""" % locals()) +""" % locals(), +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/default.py scons-4.4.0+dfsg/test/SConsignFile/default.py --- scons-4.0.1+dfsg/test/SConsignFile/default.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/default.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,16 +22,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__" - -""" -Verify the default behavior of SConsignFile(), called with no arguments. -""" +"""Verify the default behavior of SConsignFile() called with no arguments.""" import TestSCons -import os.path _python_ = TestSCons._python_ @@ -47,12 +43,13 @@ # test.write('SConstruct', """ SConsignFile() -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -62,20 +59,23 @@ test.run() -test.must_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) +database_name = test.get_sconsignname() +database_filename = database_name + ".dblite" + +test.must_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) test.must_match('f1.out', "f1.in\n") test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') -test.must_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) +test.must_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/explicit-dbm-module.py scons-4.4.0+dfsg/test/SConsignFile/explicit-dbm-module.py --- scons-4.0.1+dfsg/test/SConsignFile/explicit-dbm-module.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/explicit-dbm-module.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# 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. + +"""Verify SConsignFile() when used with explicit SCons.dblite.""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +use_db = 'SCons.dblite' + +test.subdir('subdir') + +test.write('build.py', r""" +import sys +with open(sys.argv[1], 'wb') as ofp, open(sys.argv[2], 'rb') as ifp: + ofp.write(ifp.read()) +sys.exit(0) +""") + +test.write('SConstruct', """ +import %(use_db)s +SConsignFile(dbm_module=%(use_db)s) +DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write(['subdir', 'f3.in'], "subdir/f3.in\n") +test.write(['subdir', 'f4.in'], "subdir/f4.in\n") + +test.run() + +database_name = test.get_sconsignname() +database_filename = database_name + ".dblite" + +test.must_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) + +test.must_match('f1.out', "f1.in\n") +test.must_match('f2.out', "f2.in\n") +test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") +test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") + +test.up_to_date(arguments='.') + +test.must_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/SConsignFile/explicit-file.py scons-4.4.0+dfsg/test/SConsignFile/explicit-file.py --- scons-4.0.1+dfsg/test/SConsignFile/explicit-file.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/explicit-file.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,16 +22,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__" -""" -Verify the default behavior of SConsignFile(), called with no arguments. -""" +"""Verify the behavior of env.SConsignFile() called with a subst-able path.""" import TestSCons -import os.path _python_ = TestSCons._python_ @@ -45,14 +41,15 @@ # test.write('SConstruct', """ -e = Environment(XXX = 'scons') +DefaultEnvironment(tools=[]) +e = Environment(XXX='scons', tools=[]) e.SConsignFile('my_${XXX}ign') -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f5.out', source = 'f5.in') -env.B(target = 'f6.out', source = 'f6.in') -env.B(target = 'subdir/f7.out', source = 'subdir/f7.in') -env.B(target = 'subdir/f8.out', source = 'subdir/f8.in') +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f5.out', source='f5.in') +env.B(target='f6.out', source='f6.in') +env.B(target='subdir/f7.out', source='subdir/f7.in') +env.B(target='subdir/f8.out', source='subdir/f8.in') """ % locals()) test.write('f5.in', "f5.in\n") @@ -62,20 +59,21 @@ test.run() +database_name = test.get_sconsignname() test.must_exist(test.workpath('my_sconsign.dblite')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) test.must_match('f5.out', "f5.in\n") test.must_match('f6.out', "f6.in\n") test.must_match(['subdir', 'f7.out'], "subdir/f7.in\n") test.must_match(['subdir', 'f8.out'], "subdir/f8.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.must_exist(test.workpath('my_sconsign.dblite')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) +test.must_not_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath('subdir', database_name)) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/make-directory.py scons-4.4.0+dfsg/test/SConsignFile/make-directory.py --- scons-4.0.1+dfsg/test/SConsignFile/make-directory.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/make-directory.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify the ability to make a SConsignFile() in a non-existent @@ -40,15 +39,17 @@ test.write('SConstruct', """ import SCons.dblite -env = Environment() +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) env.SConsignFile("sub/dir/sconsign", SCons.dblite) env.Install('bar', 'foo.txt') """) test.write('foo.txt', "Foo\n") - -expect = test.wrap_stdout(read_str = 'Mkdir("%s")\n' % sub_dir, - build_str = 'Install file: "foo.txt" as "%s"\n' % bar_foo_txt) +expect = test.wrap_stdout( + read_str='Mkdir("%s")\n' % sub_dir, + build_str='Install file: "foo.txt" as "%s"\n' % bar_foo_txt, +) test.run(options='-n', stdout=expect) @@ -56,7 +57,8 @@ test.must_not_exist('sub') test.must_not_exist(['sub', 'dir']) -test.must_not_exist(['sub', 'dir', '.sconsign.dblite']) +database_name = test.get_sconsignname() +test.must_not_exist(['sub', 'dir', database_name + '.dblite']) test.run(stdout=expect) diff -Nru scons-4.0.1+dfsg/test/SConsignFile/use-dbhash.py scons-4.4.0+dfsg/test/SConsignFile/use-dbhash.py --- scons-4.0.1+dfsg/test/SConsignFile/use-dbhash.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/use-dbhash.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify SConsignFile() when used with dbhash. @@ -36,8 +35,9 @@ try: import dbm.bsd + use_dbm = 'dbm.bsd' except ImportError: - test.skip_test('No dbhash in this version of Python; skipping test.\n') + test.skip_test('No dbm.bsd in this version of Python; skipping test.\n') test.subdir('subdir') @@ -48,13 +48,15 @@ sys.exit(0) """) +database_name = test.get_sconsignname() + # test.write('SConstruct', """ -import sys -import dbhash -SConsignFile('.sconsign', dbhash) +import %(use_dbm)s +SConsignFile('%(database_name)s', %(use_dbm)s) +DefaultEnvironment(tools=[]) B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) +env = Environment(BUILDERS={'B': B}, tools=[]) env.B(target = 'f1.out', source = 'f1.in') env.B(target = 'f2.out', source = 'f2.in') env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') @@ -68,10 +70,12 @@ test.run() -test.must_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +database_name = test.get_sconsignname() +database_filename = database_name + ".dblite" +test.must_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.must_match('f1.out', "f1.in\n") test.must_match('f2.out', "f2.in\n") @@ -80,10 +84,10 @@ test.up_to_date(arguments = '.') -test.must_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +test.must_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/use-dbm.py scons-4.4.0+dfsg/test/SConsignFile/use-dbm.py --- scons-4.0.1+dfsg/test/SConsignFile/use-dbm.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/use-dbm.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify SConsignFile() when used with dbm. @@ -37,15 +36,9 @@ try: import dbm.ndbm - - use_db = 'dbm.ndbm' + use_dbm = 'dbm.ndbm' except ImportError: - try: - import dbm - - use_db = 'dbm' - except ImportError: - test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n') + test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n') test.subdir('subdir') @@ -56,18 +49,18 @@ sys.exit(0) """) +database_name = test.get_sconsignname() # test.write('SConstruct', """ -import sys -import %(use_db)s -SConsignFile('.sconsign', %(use_db)s) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') +import %(use_dbm)s +SConsignFile('%(database_name)s', %(use_dbm)s) DefaultEnvironment(tools=[]) -env = Environment(BUILDERS = { 'B' : B }, tools=[]) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -80,11 +73,15 @@ # We don't check for explicit .db or other file, because base "dbm" # can use different file extensions on different implementations. -test.fail_test(os.path.exists('.sconsign') and 'dbm' not in dbm.whichdb('.sconsign'), - message=".sconsign existed and wasn't any type of dbm file") -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +database_name = test.get_sconsignname() +database_filename = database_name + '.dblite' +test.fail_test( + os.path.exists(database_name) and 'dbm' not in dbm.whichdb(database_name), + message="{} existed and wasn't any type of dbm file".format(database_name), +) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.must_match('f1.out', "f1.in\n") test.must_match('f2.out', "f2.in\n") @@ -93,11 +90,11 @@ test.up_to_date(arguments='.') -test.fail_test(os.path.exists('.sconsign') and 'dbm' not in dbm.whichdb('.sconsign'), - message=".sconsign existed and wasn't any type of dbm file") -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +test.fail_test(os.path.exists(database_name) and 'dbm' not in dbm.whichdb(database_name), + message="{} existed and wasn't any type of dbm file".format(database_name)) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/use-dumbdbm.py scons-4.4.0+dfsg/test/SConsignFile/use-dumbdbm.py --- scons-4.0.1+dfsg/test/SConsignFile/use-dumbdbm.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/use-dumbdbm.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify SConsignFile() when used with dumbdbm. @@ -35,14 +34,10 @@ 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') @@ -53,17 +48,18 @@ sys.exit(0) """) +database_name = test.get_sconsignname() # test.write('SConstruct', """ -import sys import %(use_dbm)s -SConsignFile('.sconsign', %(use_dbm)s) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +SConsignFile('%(database_name)s', %(use_dbm)s) +DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -73,30 +69,30 @@ test.run() -test.must_exist(test.workpath('.sconsign.dat')) -test.must_exist(test.workpath('.sconsign.dir')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dat')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dir')) +test.must_exist(test.workpath('{}.dat'.format(database_name))) +test.must_exist(test.workpath('{}.dir'.format(database_name))) +test.must_not_exist(test.workpath('{}'.format(database_name))) +test.must_not_exist(test.workpath('{}.dblite'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dblite'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dat'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dir'.format(database_name))) test.must_match('f1.out', "f1.in\n") test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') -test.must_exist(test.workpath('.sconsign.dat')) -test.must_exist(test.workpath('.sconsign.dir')) -test.must_not_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dat')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dir')) +test.must_exist(test.workpath('{}.dat'.format(database_name))) +test.must_exist(test.workpath('{}.dir'.format(database_name))) +test.must_not_exist(test.workpath('{}'.format(database_name))) +test.must_not_exist(test.workpath('{}.dblite'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dblite'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dat'.format(database_name))) +test.must_not_exist(test.workpath('subdir', '{}.dir'.format(database_name))) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SConsignFile/use-gdbm.py scons-4.4.0+dfsg/test/SConsignFile/use-gdbm.py --- scons-4.0.1+dfsg/test/SConsignFile/use-gdbm.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SConsignFile/use-gdbm.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify SConsignFile() when used with gdbm. @@ -35,14 +34,10 @@ 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') @@ -53,17 +48,19 @@ sys.exit(0) """) +database_name = test.get_sconsignname() +database_filename = database_name + '.dblite' # test.write('SConstruct', """ -import sys import %(use_dbm)s -SConsignFile('.sconsign', %(use_dbm)s) -B = Builder(action = '%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +SConsignFile('%(database_name)s', %(use_dbm)s) +DefaultEnvironment(tools=[]) +B = Builder(action='%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -73,22 +70,22 @@ test.run() -test.must_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +test.must_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.must_match('f1.out', "f1.in\n") test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') -test.must_exist(test.workpath('.sconsign')) -test.must_not_exist(test.workpath('.sconsign.dblite')) -test.must_not_exist(test.workpath('subdir', '.sconsign')) -test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) +test.must_exist(test.workpath(database_name)) +test.must_not_exist(test.workpath(database_filename)) +test.must_not_exist(test.workpath('subdir', database_name)) +test.must_not_exist(test.workpath('subdir', database_filename)) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/scons-time/func/chdir.py scons-4.4.0+dfsg/test/scons-time/func/chdir.py --- scons-4.0.1+dfsg/test/scons-time/func/chdir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/func/chdir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the func -C and --chdir options change directory before @@ -52,7 +51,7 @@ i = str(i) test.subdir(i) test.profile_data('profs/foo-%s.prof' % i, '%s/prof.py' % i, '_main', input) - s = r'\d.\d\d\d %s/prof\.py:1\(_main\)' % re.escape(test.workpath(i)) + s = r'\d.\d\d\d %s.prof\.py:1\(_main\)' % re.escape(test.workpath(i)) expect.append(s + '\n') expect = ''.join(expect) diff -Nru scons-4.0.1+dfsg/test/scons-time/func/funcglob.py scons-4.4.0+dfsg/test/scons-time/func/funcglob.py --- scons-4.0.1+dfsg/test/scons-time/func/funcglob.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/func/funcglob.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the func subcommands globs for files. @@ -46,7 +45,7 @@ for i in range(9): test.subdir(str(i)) test.profile_data('foo-%s.prof' % i, '%s/prof.py' % i, '_main', input) - expect.append((r'\d.\d\d\d %s/prof\.py:1\(_main\)' + '\n') % i) + expect.append((r'\d.\d\d\d %s.prof\.py:1\(_main\)' + '\n') % i) expect = ''.join(expect) diff -Nru scons-4.0.1+dfsg/test/scons-time/func/prefix.py scons-4.4.0+dfsg/test/scons-time/func/prefix.py --- scons-4.0.1+dfsg/test/scons-time/func/prefix.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/func/prefix.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Verify that the func -p and --prefix options specify what log files to use. """ -import os.path import TestSCons_time diff -Nru scons-4.0.1+dfsg/test/scons-time/func/tail.py scons-4.4.0+dfsg/test/scons-time/func/tail.py --- scons-4.0.1+dfsg/test/scons-time/func/tail.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/func/tail.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the func subcommand only prints results for the last number @@ -47,7 +46,7 @@ for i in range(9): test.subdir(str(i)) test.profile_data('foo-%s.prof' % i, '%s/prof.py' % i, '_main', input) - expect.append((r'\d.\d\d\d %s/prof\.py:1\(_main\)' + '\n') % i) + expect.append((r'\d.\d\d\d %s.prof\.py:1\(_main\)' + '\n') % i) test.run(arguments = 'func -t 3 foo-*.prof', stdout = ''.join(expect[-3:])) diff -Nru scons-4.0.1+dfsg/test/scons-time/run/archive/zip.py scons-4.4.0+dfsg/test/scons-time/run/archive/zip.py --- scons-4.0.1+dfsg/test/scons-time/run/archive/zip.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/run/archive/zip.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ .zip file. """ -import sys import TestSCons_time diff -Nru scons-4.0.1+dfsg/test/scons-time/run/config/python.py scons-4.4.0+dfsg/test/scons-time/run/config/python.py --- scons-4.0.1+dfsg/test/scons-time/run/config/python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/run/config/python.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -25,38 +27,45 @@ Verify specifying an alternate Python executable in a config file. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import TestSCons_time -_python_ = TestSCons_time._python_ +from TestCmd import NEED_HELPER +from TestSCons_time import _python_ test = TestSCons_time.TestSCons_time() +if NEED_HELPER: + test.skip_test("Test host cannot directly execute scripts, skipping test\n") + test.write_sample_project('foo.tar.gz') my_python_py = test.workpath('my_python.py') -test.write('config', """\ -python = r'%(my_python_py)s' -""" % locals()) - -test.write(my_python_py, """\ -#!%(_python_)s +test.write( + 'config', + f"""\ +python = r'{my_python_py}' +""", +) + +test.write( + my_python_py, + fr"""#!{_python_} import sys profile = '' for arg in sys.argv[1:]: if arg.startswith('--profile='): profile = arg[10:] break -print('my_python.py: %%s' %% profile) -""" % locals()) +print('my_python.py: %s' % profile) +""", +) os.chmod(my_python_py, 0o755) -test.run(arguments = 'run -f config foo.tar.gz') +test.run(arguments='run -f config foo.tar.gz') prof0 = test.workpath('foo-000-0.prof') prof1 = test.workpath('foo-000-1.prof') diff -Nru scons-4.0.1+dfsg/test/scons-time/run/option/python.py scons-4.4.0+dfsg/test/scons-time/run/option/python.py --- scons-4.0.1+dfsg/test/scons-time/run/option/python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/scons-time/run/option/python.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify the run --python option to specify an alternatie Python executable. @@ -32,28 +31,34 @@ import TestSCons_time -_python_ = TestSCons_time._python_ +from TestCmd import NEED_HELPER +from TestSCons_time import _python_ test = TestSCons_time.TestSCons_time() +if NEED_HELPER: + test.skip_test("Test host cannot directly execute scripts, skipping test\n") + test.write_sample_project('foo.tar.gz') my_python_py = test.workpath('my_python.py') -test.write(my_python_py, """\ -#!%(_python_)s +test.write( + my_python_py, + fr"""#!{_python_} import sys profile = '' for arg in sys.argv[1:]: if arg.startswith('--profile='): profile = arg[10:] break -sys.stdout.write('my_python.py: %%s\\n' %% profile) -""" % locals()) +print('my_python.py: %s' % profile) +""", +) os.chmod(my_python_py, 0o755) -test.run(arguments = 'run --python %s foo.tar.gz' % my_python_py) +test.run(arguments='run --python %s foo.tar.gz' % my_python_py) prof0 = test.workpath('foo-000-0.prof') prof1 = test.workpath('foo-000-1.prof') diff -Nru scons-4.0.1+dfsg/test/SideEffect/parallel.py scons-4.4.0+dfsg/test/SideEffect/parallel.py --- scons-4.0.1+dfsg/test/SideEffect/parallel.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SideEffect/parallel.py 2022-07-30 21:48:28.000000000 +0000 @@ -54,6 +54,8 @@ with open(logfile, 'ab') as f: f.write(('%s -> %s\\n' % (src, target)).encode()) +with open(target, 'wb') as ofp, open(src, 'rb') as ifp: + ofp.write(ifp.read()) # Give the other threads a chance to start. time.sleep(1) @@ -79,6 +81,14 @@ test.run(arguments = "-j 4 .") +test.must_match('h1.out', 'h1.in\n') +test.must_match('g2.out', 'g2.in\n') +test.must_match('f3.out', 'f3.in\n') +test.must_exist('log.txt') +test.must_exist('log.out') + +stdout = test.stdout() + build_lines = [ 'build.py h1.in h1.out', @@ -86,7 +96,20 @@ 'build.py f3.in f3.out', ] -test.must_contain_all_lines(test.stdout(), build_lines) +missing = [] +for line in build_lines: + if stdout.find(line) == -1: + missing.append(line) + +if missing: + print("===== standard output is missing the following lines:") + print('\n'.join(missing)) + print("===== STDOUT ========================================") + print(stdout) + test.fail_test() + + +log = test.read('log.txt', mode='r') log_lines = [ 'f3.in -> f3.out', @@ -94,8 +117,17 @@ 'g2.in -> g2.out', ] -test.must_contain_all_lines(test.read('log.txt', mode='r'), log_lines) - +missing = [] +for line in log_lines: + if log.find(line) == -1: + missing.append(line) + +if missing: + print("===== log file 'log.txt' is missing the following lines:") + print('\n'.join(missing)) + print("===== STDOUT ===========================================") + print(log) + test.fail_test() test.pass_test() diff -Nru scons-4.0.1+dfsg/test/silent-command.py scons-4.4.0+dfsg/test/silent-command.py --- scons-4.0.1+dfsg/test/silent-command.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/silent-command.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/site_scons/basic.py scons-4.4.0+dfsg/test/site_scons/basic.py --- scons-4.0.1+dfsg/test/site_scons/basic.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/basic.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 TestSCons diff -Nru scons-4.0.1+dfsg/test/site_scons/nonexistent.py scons-4.4.0+dfsg/test/site_scons/nonexistent.py --- scons-4.0.1+dfsg/test/site_scons/nonexistent.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/nonexistent.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that specifying --site-dir= with a nonexistent directory diff -Nru scons-4.0.1+dfsg/test/site_scons/no-site-dir.py scons-4.4.0+dfsg/test/site_scons/no-site-dir.py --- scons-4.0.1+dfsg/test/site_scons/no-site-dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/no-site-dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify use of the --no-site-dir option: diff -Nru scons-4.0.1+dfsg/test/site_scons/override.py scons-4.4.0+dfsg/test/site_scons/override.py --- scons-4.0.1+dfsg/test/site_scons/override.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/override.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ diff -Nru scons-4.0.1+dfsg/test/site_scons/site-dir.py scons-4.4.0+dfsg/test/site_scons/site-dir.py --- scons-4.0.1+dfsg/test/site_scons/site-dir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/site-dir.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,52 +22,78 @@ # 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__" """ -Verify that --site-dir=otherdir loads the site_init.py script -from the other dir; +Verify that --site-dir=otherdir loads the site_init.py script from otherdir; the usual site_scons/site_init.py should NOT be loaded. +Check that a later --no-site-dir turns off site-dir processing +even if a --site-dir option was seen earlier. """ +import os + import TestSCons test = TestSCons.TestSCons() test.subdir('site_scons', ['site_scons', 'site_tools']) -test.write(['site_scons', 'site_init.py'], """ +test.write( + ['site_scons', 'site_init.py'], + """ from SCons.Script import * print("Hi there, I am in site_scons/site_init.py!") -""") +""", +) -test.write(['site_scons', 'site_tools', 'mytool.py'], """ +test.write( + ['site_scons', 'site_tools', 'mytool.py'], + """ import SCons.Tool def generate(env): env['MYTOOL']='mytool' def exists(env): return 1 -""") - - +""", +) test.subdir('alt_site', ['alt_site', 'site_tools']) -test.write(['alt_site', 'site_init.py'], """ +test.write( + ['alt_site', 'site_init.py'], + """ from SCons.Script import * print("Hi there, I am in alt_site/site_init.py!") -""") +""", +) -test.write('SConstruct', """ +test.write( + 'SConstruct', + """ e=Environment() -""") - -test.run(arguments = '-Q --site-dir=alt_site .', - stdout = """Hi there, I am in alt_site/site_init.py! -scons: `.' is up to date.\n""") +""", +) +test.run( + arguments='-Q --site-dir=alt_site .', + stdout="""Hi there, I am in alt_site/site_init.py! +scons: `.' is up to date.\n""", +) + + +# --site-dir followed by --no-site-dir turns processing off: +test.run( + arguments="-Q --site-dir=alt_site --no-site-dir .", + stdout="""scons: `.' is up to date.\n""", +) + + +# same test, but using SCONSFLAGS +os.environ["SCONSFLAGS"] = "-Q --site-dir=alt_site" +test.run( + arguments="--no-site-dir .", + stdout="""scons: `.' is up to date.\n""", +) test.pass_test() diff -Nru scons-4.0.1+dfsg/test/site_scons/site_init.py scons-4.4.0+dfsg/test/site_scons/site_init.py --- scons-4.0.1+dfsg/test/site_scons/site_init.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/site_init.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify various aspects of the handling of site_init.py. @@ -41,7 +40,7 @@ def _test_metadata(): """Test site_init's module metadata. - + The following special variables should be predefined: __doc__, __file__ and __name__. No special variables should be transferred from SCons.Script. diff -Nru scons-4.0.1+dfsg/test/site_scons/sysdirs.py scons-4.4.0+dfsg/test/site_scons/sysdirs.py --- scons-4.0.1+dfsg/test/site_scons/sysdirs.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/sysdirs.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 diff -Nru scons-4.0.1+dfsg/test/site_scons/sys-path.py scons-4.4.0+dfsg/test/site_scons/sys-path.py --- scons-4.0.1+dfsg/test/site_scons/sys-path.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/site_scons/sys-path.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the site_scons dir is added to sys.path as an diff -Nru scons-4.0.1+dfsg/test/srcchange.py scons-4.4.0+dfsg/test/srcchange.py --- scons-4.0.1+dfsg/test/srcchange.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/srcchange.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,7 +32,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/subdir.py scons-4.4.0+dfsg/test/subdir.py --- scons-4.0.1+dfsg/test/subdir.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/subdir.py 2022-07-30 21:48:28.000000000 +0000 @@ -25,7 +25,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons -import os.path _python_ = TestSCons._python_ diff -Nru scons-4.0.1+dfsg/test/Subst/SyntaxError.py scons-4.4.0+dfsg/test/Subst/SyntaxError.py --- scons-4.0.1+dfsg/test/Subst/SyntaxError.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Subst/SyntaxError.py 2022-07-30 21:48:28.000000000 +0000 @@ -34,7 +34,7 @@ test = TestSCons.TestSCons(match = TestSCons.match_re_dotall) -expect_build = r"""scons: \*\*\*%s SyntaxError `(invalid syntax|Unknown character)( \((, )?line 1\))?' trying to evaluate `%s' +expect_build = r"""scons: \*\*\*%s SyntaxError `invalid syntax( |\. Perhaps you forgot a comma\? )\(, line 1\)?' trying to evaluate `%s' """ expect_read = "\n" + expect_build + TestSCons.file_expr diff -Nru scons-4.0.1+dfsg/test/SWIG/generated_swigfile.py scons-4.4.0+dfsg/test/SWIG/generated_swigfile.py --- scons-4.0.1+dfsg/test/SWIG/generated_swigfile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SWIG/generated_swigfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -20,9 +21,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__" """ Verify that SCons realizes the -noproxy option means no .py file will @@ -38,14 +36,8 @@ if sys.platform == 'win32': _dll = '.dll' else: - _dll = '.so' + _dll = '.so' -# swig-python expects specific filenames. -# the platform specific suffix won't necessarily work. -if sys.platform == 'win32': - _dll = '.dll' -else: - _dll = '.so' test = TestSCons.TestSCons() @@ -54,12 +46,11 @@ test.skip_test('Can not find installed "swig", skipping test.\n') python, python_include, python_libpath, python_lib = \ - test.get_platform_python_info(python_h_required=True) + test.get_platform_python_info(python_h_required=True) # handle testing on other platforms: ldmodule_prefix = '_' - test.write('SConstruct', """ foo = Environment(CPPPATH=[r'%(python_include)s'], SWIG=[r'%(swig)s'], @@ -69,7 +60,6 @@ python_c_file = foo.CFile( target='python_swig_test',source=python_interface, SWIGFLAGS = '-python -c++' ) java_interface = foo.Command( 'test_java_swig.i', Value(1),'echo %%module test_java_swig > test_java_swig.i' ) java_c_file = foo.CFile( target='java_swig_test' ,source=java_interface, SWIGFLAGS = '-java -c++' ) - """ % locals()) expected_stdout = """\ @@ -78,12 +68,11 @@ echo %%module test_py_swig > test_py_swig.i %(swig)s -o python_swig_test_wrap.cc -python -c++ test_py_swig.i """ % locals() -test.run(arguments = '.',stdout=test.wrap_stdout(expected_stdout)) - +test.run(arguments='.', stdout=test.wrap_stdout(expected_stdout)) # If we mistakenly depend on the .py file that SWIG didn't create # (suppressed by the -noproxy option) then the build won't be up-to-date. -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/SWIG/live.py scons-4.4.0+dfsg/test/SWIG/live.py --- scons-4.0.1+dfsg/test/SWIG/live.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SWIG/live.py 2022-07-30 21:48:28.000000000 +0000 @@ -27,7 +27,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import sys import TestSCons diff -Nru scons-4.0.1+dfsg/test/SWIG/recursive-includes-cpp.py scons-4.4.0+dfsg/test/SWIG/recursive-includes-cpp.py --- scons-4.0.1+dfsg/test/SWIG/recursive-includes-cpp.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SWIG/recursive-includes-cpp.py 2022-07-30 21:48:28.000000000 +0000 @@ -40,9 +40,8 @@ test = TestSCons.TestSCons() # Check for prerequisites of this test. -for pre_req in ['swig', 'python']: - if not test.where_is(pre_req): - test.skip_test('Can not find installed "' + pre_req + '", skipping test.%s' % os.linesep) +if not test.where_is('swig'): + test.skip_test('Can not find installed "swig", skipping test.%s' % os.linesep) python, python_include, python_libpath, python_lib = \ test.get_platform_python_info(python_h_required=True) diff -Nru scons-4.0.1+dfsg/test/SWIG/SWIGFLAGS.py scons-4.4.0+dfsg/test/SWIG/SWIGFLAGS.py --- scons-4.0.1+dfsg/test/SWIG/SWIGFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SWIG/SWIGFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Verify that we can use ${SOURCE} expansions in $SWIGFLAGS. """ -import sys import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/SWIG/SWIGOUTDIR.py scons-4.4.0+dfsg/test/SWIG/SWIGOUTDIR.py --- scons-4.0.1+dfsg/test/SWIG/SWIGOUTDIR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/SWIG/SWIGOUTDIR.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 @@ -20,9 +21,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__" """ Verify that use of the $SWIGOUTDIR variable causes SCons to recognize diff -Nru scons-4.0.1+dfsg/test/symlink/dangling-include.py scons-4.4.0+dfsg/test/symlink/dangling-include.py --- scons-4.0.1+dfsg/test/symlink/dangling-include.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/symlink/dangling-include.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test how we handle #includes of dangling symlinks. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/symlink/dangling-source.py scons-4.4.0+dfsg/test/symlink/dangling-source.py --- scons-4.0.1+dfsg/test/symlink/dangling-source.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/symlink/dangling-source.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test how we handle dangling symlinks as source files. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/TARGETS.py scons-4.4.0+dfsg/test/TARGETS.py --- scons-4.0.1+dfsg/test/TARGETS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TARGETS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test use of the COMMAND_LINE_TARGETS and DEFAULT_TARGETS variables. @@ -137,6 +136,21 @@ +# blanks in cmdline should not be treated as targets (issue 2986) +test.write( + file='SConstruct', + content="""\ +tgt_foo = Textfile(target="foo", source="foostuff") +tgt_bar = Textfile(target="bar", source="bartuff") +Default(tgt_foo) +""", +) +test.run(arguments=["-Q", "-n", "''"], stdout="Creating 'foo.txt'\n") +test.run(arguments=["-Q", "-n", ""], stdout="Creating 'foo.txt'\n") +test.run(arguments=["-Q", "-n", '""'], stdout="Creating 'foo.txt'\n") + + + test.pass_test() # Local Variables: diff -Nru scons-4.0.1+dfsg/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist scons-4.4.0+dfsg/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist --- scons-4.0.1+dfsg/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/fixture/SConstruct-tempfile-actionlist 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/test/TEMPFILE/fixture/SConstruct.tempfiledir scons-4.4.0+dfsg/test/TEMPFILE/fixture/SConstruct.tempfiledir --- scons-4.0.1+dfsg/test/TEMPFILE/fixture/SConstruct.tempfiledir 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/fixture/SConstruct.tempfiledir 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,17 @@ +import os + +my_temp_dir = os.path.join(os.getcwd(), 'my_temp_files') + +env = Environment( + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILEDIR=my_temp_dir, +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') + +plain_env = Environment( + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, +) +plain_env.Command('global_foo.out', 'foo.in', '$BUILDCOM') diff -Nru scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILE-actionlist.py scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILE-actionlist.py --- scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILE-actionlist.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILE-actionlist.py 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILEDIR.py scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILEDIR.py --- scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILEDIR.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILEDIR.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# 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 setting the $TEMPFILEDIR variable will cause +the generated tempfile used for long command lines to be created in specified directory. +And if not specified in one of TMPDIR, TEMP or TMP (based on os' normal usage of such) +""" +from re import escape +import tempfile +import TestSCons +from TestCmd import IS_WINDOWS + +test = TestSCons.TestSCons(match=TestSCons.match_re) + +test.file_fixture('fixture/SConstruct.tempfiledir', 'SConstruct') + +expected_output = r"""Using tempfile __WORKDIR__/my_temp_files/\S+ for command line: +xxx.py foo.out foo.in +xxx.py @__WORKDIR__/my_temp_files/\S+ +Using tempfile __TEMPDIR__/\S+ for command line: +xxx.py global_foo.out foo.in +xxx.py @__TEMPDIR__/\S+ +""" + +if IS_WINDOWS: + expected_output = expected_output.replace('/','\\\\') +wd_escaped = escape(test.workdir) +td_escaped = escape(tempfile.gettempdir()) +expected_output =expected_output.replace("__WORKDIR__", wd_escaped) +expected_output = expected_output.replace("__TEMPDIR__", td_escaped) + +test.write('foo.in', "foo.in\n") + +test.run(arguments='-n -Q .', + stdout=expected_output) +# """\ +# Using tempfile \\S+ for command line: +# xxx.py foo.out foo.in +# xxx.py \\S+ +# """) +# +# try: +# tempfile = test.stdout().splitlines()[0].split()[2] +# except IndexError: +# test.fail_test("Unexpected output couldn't find tempfile") +# +# dirname = os.path.basename(os.path.dirname(tempfile)) +# test.fail_test('my_temp_files' != dirname, message="Temp file not created in \"my_temp_files\" directory") +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILEPREFIX.py scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILEPREFIX.py --- scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILEPREFIX.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILEPREFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# 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. + +""" +Verify that setting the $TEMPFILEPREFIX variable will cause +it to appear at the front of name of the generated tempfile +used for long command lines. +""" + +import TestSCons + +test = TestSCons.TestSCons(match=TestSCons.match_re) + +test.write('SConstruct', """ +import os + +env = Environment( + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILEPREFIX='-via', +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.write('foo.in', "foo.in\n") + +test.run( + arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py foo.out foo.in +xxx.py -via\\S+ +""") + +test.write('SConstruct', """ +import os + +def print_cmd_line(s, targets, sources, env): + pass + +env = Environment( + BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH = 16, + TEMPFILEPREFIX = '-via', + PRINT_CMD_LINE_FUNC=print_cmd_line +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.run(arguments='-n -Q .', stdout="") + +test.write('SConstruct', """ +import os +from SCons.Platform import TempFileMunge + +class TestTempFileMunge(TempFileMunge): + def __init__(self, cmd, cmdstr=None): + super().__init__(cmd, cmdstr) + + def _print_cmd_str(self, target, source, env, cmdstr): + super()._print_cmd_str(target, source, None, cmdstr) + +env = Environment( + TEMPFILE=TestTempFileMunge, + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILEPREFIX='-via', +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.run( + arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py foo.out foo.in +xxx.py -via\\S+ +""") + +# make sure an empty prefix works too +test.write('SConstruct', """ +import os +from SCons.Platform import TempFileMunge + +class TestTempFileMunge(TempFileMunge): + def __init__(self, cmd, cmdstr=None): + super().__init__(cmd, cmdstr) + + def _print_cmd_str(self, target, source, env, cmdstr): + super()._print_cmd_str(target, source, None, cmdstr) + +env = Environment( + TEMPFILE=TestTempFileMunge, + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILEPREFIX='', +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.run( + arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py foo.out foo.in +xxx.py [^@]\\S+ +""") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILESUFFIX.py scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILESUFFIX.py --- scons-4.0.1+dfsg/test/TEMPFILE/TEMPFILESUFFIX.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEMPFILE/TEMPFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# +# 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. + +""" +Verify that setting the $TEMPFILESUFFIX variable will cause +it to appear at the end of name of the generated tempfile +used for long command lines. +""" + + +import TestSCons + +test = TestSCons.TestSCons(match=TestSCons.match_re) + +test.write('SConstruct', """ +import os + +env = Environment( + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILESUFFIX='.foo', +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.write('foo.in', "foo.in\n") +test.run( + arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py foo.out foo.in +xxx.py \\S+ +""") + +test.write('SConstruct', """ +import os + +def print_cmd_line(s, targets, sources, env): + pass + +env = Environment( + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILESUFFIX='.foo', + PRINT_CMD_LINE_FUNC=print_cmd_line, +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.run(arguments = '-n -Q .', + stdout = """""") + +test.write('SConstruct', """ +import os +from SCons.Platform import TempFileMunge + +class TestTempFileMunge(TempFileMunge): + def __init__(self, cmd, cmdstr=None): + super().__init__(cmd, cmdstr) + + def _print_cmd_str(self, target, source, env, cmdstr): + super()._print_cmd_str(target, source, None, cmdstr) + +env = Environment( + TEMPFILE=TestTempFileMunge, + BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', + MAXLINELENGTH=16, + TEMPFILESUFFIX='.foo', +) +env.AppendENVPath('PATH', os.curdir) +env.Command('foo.out', 'foo.in', '$BUILDCOM') +""") + +test.run( + arguments='-n -Q .', + stdout="""\ +Using tempfile \\S+ for command line: +xxx.py foo.out foo.in +xxx.py \\S+ +""") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TempFileMunge/fixture/SConstruct.tempfiledir scons-4.4.0+dfsg/test/TempFileMunge/fixture/SConstruct.tempfiledir --- scons-4.0.1+dfsg/test/TempFileMunge/fixture/SConstruct.tempfiledir 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TempFileMunge/fixture/SConstruct.tempfiledir 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -import os - -my_temp_dir = os.path.join(os.getcwd(), 'my_temp_files') - -env = Environment( - BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH=16, - TEMPFILEDIR=my_temp_dir, -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') - -plain_env = Environment( - BUILDCOM='${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH=16, -) -plain_env.Command('global_foo.out', 'foo.in', '$BUILDCOM') diff -Nru scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILEDIR.py scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILEDIR.py --- scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILEDIR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILEDIR.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# -# 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 setting the $TEMPFILEDIR variable will cause -the generated tempfile used for long command lines to be created in specified directory. -And if not specified in one of TMPDIR, TEMP or TMP (based on os' normal usage of such) -""" -from re import escape -import tempfile -import TestSCons -from TestCmd import IS_WINDOWS - -test = TestSCons.TestSCons(match=TestSCons.match_re) - -test.file_fixture('fixture/SConstruct.tempfiledir', 'SConstruct') - -expected_output = r"""Using tempfile __WORKDIR__/my_temp_files/\S+ for command line: -xxx.py foo.out foo.in -xxx.py @__WORKDIR__/my_temp_files/\S+ -Using tempfile __TEMPDIR__/\S+ for command line: -xxx.py global_foo.out foo.in -xxx.py @__TEMPDIR__/\S+ -""" - -if IS_WINDOWS: - expected_output = expected_output.replace('/','\\\\') -wd_escaped = escape(test.workdir) -td_escaped = escape(tempfile.gettempdir()) -expected_output =expected_output.replace("__WORKDIR__", wd_escaped) -expected_output = expected_output.replace("__TEMPDIR__", td_escaped) - -test.write('foo.in', "foo.in\n") - -test.run(arguments='-n -Q .', - stdout=expected_output) -# """\ -# Using tempfile \\S+ for command line: -# xxx.py foo.out foo.in -# xxx.py \\S+ -# """) -# -# try: -# tempfile = test.stdout().splitlines()[0].split()[2] -# except IndexError: -# test.fail_test("Unexpected output couldn't find tempfile") -# -# dirname = os.path.basename(os.path.dirname(tempfile)) -# test.fail_test('my_temp_files' != dirname, message="Temp file not created in \"my_temp_files\" directory") -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILEPREFIX.py scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILEPREFIX.py --- scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILEPREFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILEPREFIX.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# 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 setting the $TEMPFILEPREFIX variable will cause -it to appear at the front of name of the generated tempfile -used for long command lines. -""" - -import os -import stat - -import TestSCons - -test = TestSCons.TestSCons(match = TestSCons.match_re) - -test.write('SConstruct', """ -import os -env = Environment( - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILEPREFIX = '-via', -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.write('foo.in', "foo.in\n") - -test.run(arguments = '-n -Q .', - stdout = """\ -Using tempfile \\S+ for command line: -xxx.py foo.out foo.in -xxx.py -via\\S+ -""") - -test.write('SConstruct', """ -import os - -def print_cmd_line(s, targets, sources, env): - pass - -env = Environment( - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILEPREFIX = '-via', - PRINT_CMD_LINE_FUNC=print_cmd_line -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.run(arguments = '-n -Q .', - stdout = """""") - -test.write('SConstruct', """ -import os -from SCons.Platform import TempFileMunge - -class TestTempFileMunge(TempFileMunge): - - def __init__(self, cmd, cmdstr = None): - super(TestTempFileMunge, self).__init__(cmd, cmdstr) - - def _print_cmd_str(self, target, source, env, cmdstr): - super(TestTempFileMunge, self)._print_cmd_str(target, source, None, cmdstr) - -env = Environment( - TEMPFILE = TestTempFileMunge, - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILEPREFIX = '-via', - -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.run(arguments = '-n -Q .', - stdout = """\ -Using tempfile \\S+ for command line: -xxx.py foo.out foo.in -xxx.py -via\\S+ -""") - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILESUFFIX.py scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILESUFFIX.py --- scons-4.0.1+dfsg/test/TempFileMunge/TEMPFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TempFileMunge/TEMPFILESUFFIX.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# 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 setting the $TEMPFILESUFFIX variable will cause -it to appear at the end of name of the generated tempfile -used for long command lines. -""" - -import os -import stat - -import TestSCons - -test = TestSCons.TestSCons(match=TestSCons.match_re) - -test.write('SConstruct', """ -import os -env = Environment( - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILESUFFIX = '.foo', -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.write('foo.in', "foo.in\n") - -test.run(arguments = '-n -Q .', - stdout = """\ -Using tempfile \\S+ for command line: -xxx.py foo.out foo.in -xxx.py \\S+ -""") - -test.write('SConstruct', """ -import os - -def print_cmd_line(s, targets, sources, env): - pass - -env = Environment( - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILESUFFIX = '.foo', - PRINT_CMD_LINE_FUNC=print_cmd_line -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.run(arguments = '-n -Q .', - stdout = """""") - -test.write('SConstruct', """ -import os -from SCons.Platform import TempFileMunge - -class TestTempFileMunge(TempFileMunge): - - def __init__(self, cmd, cmdstr = None): - super(TestTempFileMunge, self).__init__(cmd, cmdstr) - - def _print_cmd_str(self, target, source, env, cmdstr): - super(TestTempFileMunge, self)._print_cmd_str(target, source, None, cmdstr) - -env = Environment( - TEMPFILE = TestTempFileMunge, - BUILDCOM = '${TEMPFILE("xxx.py $TARGET $SOURCES")}', - MAXLINELENGTH = 16, - TEMPFILESUFFIX = '.foo', - -) -env.AppendENVPath('PATH', os.curdir) -env.Command('foo.out', 'foo.in', '$BUILDCOM') -""") - -test.run(arguments = '-n -Q .', - stdout = """\ -Using tempfile \\S+ for command line: -xxx.py foo.out foo.in -xxx.py \\S+ -""") - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/TEX/generated_files.py scons-4.4.0+dfsg/test/TEX/generated_files.py --- scons-4.0.1+dfsg/test/TEX/generated_files.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEX/generated_files.py 2022-07-30 21:48:28.000000000 +0000 @@ -33,7 +33,6 @@ """ import TestSCons -import os test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/TEX/synctex.py scons-4.4.0+dfsg/test/TEX/synctex.py --- scons-4.0.1+dfsg/test/TEX/synctex.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/TEX/synctex.py 2022-07-30 21:48:28.000000000 +0000 @@ -31,7 +31,6 @@ Test configuration contributed by Robert Managan. """ -import os import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/textfile/fixture/SConstruct scons-4.4.0+dfsg/test/textfile/fixture/SConstruct --- scons-4.0.1+dfsg/test/textfile/fixture/SConstruct 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/fixture/SConstruct 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,5 @@ DefaultEnvironment(tools=[]) - env = Environment(tools=['textfile']) data0 = ['Goethe', 'Schiller'] data = ['lalala', 42, data0, 'tanteratei'] @@ -10,6 +9,10 @@ env.Textfile('foo1a.txt', data + ['']) env.Textfile('foo2a.txt', data + [''], LINESEPARATOR='|*') +issue_4021_textfile = r'..\..\..\@HINT_PATH@\Datalogics.PDFL.dll' +env.Textfile('issue-4021.txt', issue_4021_textfile, + SUBST_DICT={'@HINT_PATH@': r'NETCore\bin\$$(Platform)\$$(Configuration)'}) + # recreate the list with the data wrapped in Value() data0 = list(map(Value, data0)) data = list(map(Value, data)) diff -Nru scons-4.0.1+dfsg/test/textfile/fixture/SConstruct.issue-4037 scons-4.4.0+dfsg/test/textfile/fixture/SConstruct.issue-4037 --- scons-4.0.1+dfsg/test/textfile/fixture/SConstruct.issue-4037 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/fixture/SConstruct.issue-4037 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,18 @@ +env = Environment() + +def generator(source, target, env, for_signature): + if for_signature: + return "sig" + return "val" + +env['GENERATOR'] = generator + +env.Textfile( + target="target", + source=[ + "@generated@", + ], + SUBST_DICT={ + '@generated@' : '$GENERATOR', + }, +) diff -Nru scons-4.0.1+dfsg/test/textfile/issue-3540.py scons-4.4.0+dfsg/test/textfile/issue-3540.py --- scons-4.0.1+dfsg/test/textfile/issue-3540.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/issue-3540.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test for GH Issue 3540 diff -Nru scons-4.0.1+dfsg/test/textfile/issue-3550.py scons-4.4.0+dfsg/test/textfile/issue-3550.py --- scons-4.0.1+dfsg/test/textfile/issue-3550.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/issue-3550.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,14 +22,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__" """ Test for GH Issue 3550 - You can't pass a Windows path in a value to be interpolated, - because SCons will try to pass it through re.sub which rejects certain character sequences. +You can't pass a Windows path in a value to be interpolated, +because SCons will try to pass it through re.sub which rejects +certain character sequences. """ import TestSCons diff -Nru scons-4.0.1+dfsg/test/textfile/issue-4037.py scons-4.4.0+dfsg/test/textfile/issue-4037.py --- scons-4.0.1+dfsg/test/textfile/issue-4037.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/issue-4037.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test for GH Issue 4037 + +The fix for #4031 created a code path where the subst function +used by textfile was called with SUBST_RAW, which, if the items to +subst was a callable, caused it to be called with for_signature=True. +This did not happen previously as the test was "!= SUBST_CMD", +and the mode coming in was indeed SUBST_CMD. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +match_mode = 'r' + +test.file_fixture('fixture/SConstruct.issue-4037', 'SConstruct') + +test.run(arguments='.') + +test.must_match( + 'target.txt', + "val", + mode=match_mode, +) + +test.pass_test() diff -Nru scons-4.0.1+dfsg/test/textfile/textfile.py scons-4.4.0+dfsg/test/textfile/textfile.py --- scons-4.0.1+dfsg/test/textfile/textfile.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/textfile/textfile.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 TestSCons @@ -30,7 +29,7 @@ test = TestSCons.TestSCons() -foo1 = test.workpath('foo1.txt') +# foo1 = test.workpath('foo1.txt') # foo2 = test.workpath('foo2.txt') # foo1a = test.workpath('foo1a.txt') # foo2a = test.workpath('foo2a.txt') @@ -51,6 +50,8 @@ foo1aText = foo1Text + linesep foo2aText = foo2Text + '|*' +issue_4021_text = r'..\..\..\NETCore\bin\$(Platform)\$(Configuration)\Datalogics.PDFL.dll' + test.up_to_date(arguments='.') files = list(map(test.workpath, ( @@ -81,6 +82,7 @@ test.must_match('bar1a.txt', foo1aText, mode=match_mode) test.must_match('foo2a.txt', foo2aText, mode=match_mode) test.must_match('bar2a.txt', foo2aText, mode=match_mode) +test.must_match('issue-4021.txt', issue_4021_text, mode=match_mode) check_times() # write the contents and make sure the files diff -Nru scons-4.0.1+dfsg/test/timestamp-fallback.py scons-4.4.0+dfsg/test/timestamp-fallback.py --- scons-4.0.1+dfsg/test/timestamp-fallback.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/timestamp-fallback.py 2022-07-30 21:48:28.000000000 +0000 @@ -32,7 +32,6 @@ of md5 as unsafe, although SCons does not use it in a security context. """ -import sys import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/tool_args.py scons-4.4.0+dfsg/test/tool_args.py --- scons-4.0.1+dfsg/test/tool_args.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/tool_args.py 2022-07-30 21:48:28.000000000 +0000 @@ -29,7 +29,6 @@ a Tool specification's generate() method. """ -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/toolpath/basic.py scons-4.4.0+dfsg/test/toolpath/basic.py --- scons-4.0.1+dfsg/test/toolpath/basic.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/toolpath/basic.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/toolpath/nested/nested.py scons-4.4.0+dfsg/test/toolpath/nested/nested.py --- scons-4.0.1+dfsg/test/toolpath/nested/nested.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/toolpath/nested/nested.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/toolpath/relative_import/relative_import.py scons-4.4.0+dfsg/test/toolpath/relative_import/relative_import.py --- scons-4.0.1+dfsg/test/toolpath/relative_import/relative_import.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/toolpath/relative_import/relative_import.py 2022-07-30 21:48:28.000000000 +0000 @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import TestSCons test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/Touch.py scons-4.4.0+dfsg/test/Touch.py --- scons-4.0.1+dfsg/test/Touch.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Touch.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Verify that the Touch() Action works. @@ -34,30 +33,29 @@ test = TestSCons.TestSCons() -test.write('SConstruct', """ +test.write('SConstruct', """\ Execute(Touch('f1')) Execute(Touch(File('f1-File'))) + def cat(env, source, target): target = str(target[0]) with open(target, "wb") as f: for src in source: with open(str(src), "rb") as ifp: f.write(ifp.read()) + Cat = Action(cat) env = Environment() env.Command('f2.out', 'f2.in', [Cat, Touch("f3")]) env = Environment(FILE='f4') env.Command('f5.out', 'f5.in', [Touch("$FILE"), Cat]) -env.Command('f6.out', 'f6.in', [Cat, - Touch("Touch-$SOURCE"), - Touch("$TARGET-Touch")]) +env.Command('f6.out', 'f6.in', [Cat, Touch("Touch-$SOURCE"), Touch("$TARGET-Touch")]) # Make sure Touch works with a list of arguments env = Environment() -env.Command('f7.out', 'f7.in', [Cat, - Touch(["Touch-$SOURCE", - "$TARGET-Touch", - File("f8")])]) +env.Command( + 'f7.out', 'f7.in', [Cat, Touch(["Touch-$SOURCE", "$TARGET-Touch", File("f8")])] +) """) test.write('f1', "f1\n") @@ -70,11 +68,12 @@ old_f1_time = os.path.getmtime(test.workpath('f1')) old_f1_File_time = os.path.getmtime(test.workpath('f1-File')) -expect = test.wrap_stdout(read_str = """\ +expect = test.wrap_stdout( + read_str="""\ Touch("f1") Touch("f1-File") """, - build_str = """\ + build_str="""\ cat(["f2.out"], ["f2.in"]) Touch("f3") Touch("f4") @@ -84,11 +83,11 @@ Touch("f6.out-Touch") cat(["f7.out"], ["f7.in"]) Touch(["Touch-f7.in", "f7.out-Touch", "f8"]) -""") -test.run(options = '-n', arguments = '.', stdout = expect) - -test.sleep(2) +""", +) +test.run(options='-n', arguments='.', stdout=expect) +test.sleep() # delay for timestamps new_f1_time = os.path.getmtime(test.workpath('f1')) test.fail_test(old_f1_time != new_f1_time) new_f1_File_time = os.path.getmtime(test.workpath('f1-File')) diff -Nru scons-4.0.1+dfsg/test/update-release-info/update-release-info.py scons-4.4.0+dfsg/test/update-release-info/update-release-info.py --- scons-4.0.1+dfsg/test/update-release-info/update-release-info.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/update-release-info/update-release-info.py 2022-07-30 21:48:28.000000000 +0000 @@ -27,7 +27,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os, sys, time +import os +import time import TestRuntest diff -Nru scons-4.0.1+dfsg/test/Value/GetContent.py scons-4.4.0+dfsg/test/Value/GetContent.py --- scons-4.0.1+dfsg/test/Value/GetContent.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/Value/GetContent.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,50 @@ +#!/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 the Value node as a build target +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +import SCons.Script +def null_build(target, source, env): + pass +env = DefaultEnvironment() +env['BUILDERS']['ValueBuilder'] = SCons.Builder.Builder( + action=SCons.Action.Action(null_build), + target_factory=SCons.Node.Python.Value, +) +v = env.ValueBuilder("myvalue",env.Dir("#")) +v[0].get_text_contents() +""") + +test.run() +test.pass_test() + diff -Nru scons-4.0.1+dfsg/test/Variables/BoolVariable.py scons-4.4.0+dfsg/test/Variables/BoolVariable.py --- scons-4.0.1+dfsg/test/Variables/BoolVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Variables/BoolVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test the BoolVariable canned Variable type. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/Variables/EnumVariable.py scons-4.4.0+dfsg/test/Variables/EnumVariable.py --- scons-4.0.1+dfsg/test/Variables/EnumVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Variables/EnumVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test the EnumVariable canned Variable type. """ -import os.path import TestSCons diff -Nru scons-4.0.1+dfsg/test/Variables/PackageVariable.py scons-4.4.0+dfsg/test/Variables/PackageVariable.py --- scons-4.0.1+dfsg/test/Variables/PackageVariable.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Variables/PackageVariable.py 2022-07-30 21:48:28.000000000 +0000 @@ -28,7 +28,6 @@ Test the PackageVariable canned Variable type. """ -import os import TestSCons diff -Nru scons-4.0.1+dfsg/test/Variables/Variables.py scons-4.4.0+dfsg/test/Variables/Variables.py --- scons-4.0.1+dfsg/test/Variables/Variables.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Variables/Variables.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 TestSCons diff -Nru scons-4.0.1+dfsg/test/virtualenv/activated/option/enable-virtualenv.py scons-4.4.0+dfsg/test/virtualenv/activated/option/enable-virtualenv.py --- scons-4.0.1+dfsg/test/virtualenv/activated/option/enable-virtualenv.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/activated/option/enable-virtualenv.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff -Nru scons-4.0.1+dfsg/test/virtualenv/activated/option/ignore-virtualenv.py scons-4.4.0+dfsg/test/virtualenv/activated/option/ignore-virtualenv.py --- scons-4.0.1+dfsg/test/virtualenv/activated/option/ignore-virtualenv.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/activated/option/ignore-virtualenv.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff -Nru scons-4.0.1+dfsg/test/virtualenv/activated/virtualenv_activated_python.py scons-4.4.0+dfsg/test/virtualenv/activated/virtualenv_activated_python.py --- scons-4.0.1+dfsg/test/virtualenv/activated/virtualenv_activated_python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/activated/virtualenv_activated_python.py 2022-07-30 21:48:28.000000000 +0000 @@ -33,7 +33,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff -Nru scons-4.0.1+dfsg/test/virtualenv/activated/virtualenv_detect_virtualenv.py scons-4.4.0+dfsg/test/virtualenv/activated/virtualenv_detect_virtualenv.py --- scons-4.0.1+dfsg/test/virtualenv/activated/virtualenv_detect_virtualenv.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/activated/virtualenv_detect_virtualenv.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/virtualenv/regularenv/virtualenv_detect_regularenv.py scons-4.4.0+dfsg/test/virtualenv/regularenv/virtualenv_detect_regularenv.py --- scons-4.0.1+dfsg/test/virtualenv/regularenv/virtualenv_detect_regularenv.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/regularenv/virtualenv_detect_regularenv.py 2022-07-30 21:48:28.000000000 +0000 @@ -30,7 +30,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys test = TestSCons.TestSCons() diff -Nru scons-4.0.1+dfsg/test/virtualenv/unactivated/virtualenv_unactivated_python.py scons-4.4.0+dfsg/test/virtualenv/unactivated/virtualenv_unactivated_python.py --- scons-4.0.1+dfsg/test/virtualenv/unactivated/virtualenv_unactivated_python.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/virtualenv/unactivated/virtualenv_unactivated_python.py 2022-07-30 21:48:28.000000000 +0000 @@ -33,7 +33,6 @@ import TestSCons import SCons.Platform.virtualenv -import sys import os import re diff -Nru scons-4.0.1+dfsg/test/Win32/mingw.py scons-4.4.0+dfsg/test/Win32/mingw.py --- scons-4.0.1+dfsg/test/Win32/mingw.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Win32/mingw.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,8 @@ -""" -This tests the MinGW C/C++ compiler support. -""" - #!/usr/bin/env python # -# __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 @@ -24,9 +22,11 @@ # 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__" +""" +This tests the MinGW C/C++ compiler support. +This test requires MinGW to be installed. +""" import os import sys @@ -41,10 +41,11 @@ msg = "Skipping mingw test on non-Windows platform '%s'\n" % sys.platform test.skip_test(msg) -# This test requires MinGW to be installed: test.write('SConstruct',""" -from SCons.Tool.mingw import exists import sys +from SCons.Tool.mingw import exists + +DefaultEnvironment(tools=[]) env = Environment() if exists(env): print('mingw exists') @@ -59,12 +60,18 @@ # Do the actual testing: test.write('SConstruct',""" -env=Environment(tools=['mingw']) +DefaultEnvironment(tools=[]) +env = Environment(tools=['mingw']) assert env['CC'] == 'gcc' env.StaticLibrary('static', 'static.cpp') env.SharedLibrary('shared', 'shared.cpp') env.SharedLibrary('cshared', ['cshared.c', 'cshared.def'], WINDOWS_INSERT_DEF=1) -env.Program('test', ['test.cpp', env.RES('resource.rc', CPPPATH=['header'])], LIBS=['static', 'shared', 'cshared'], LIBPATH=['.']) +env.Program( + 'test', + ['test.cpp', env.RES('resource.rc', CPPPATH=['header'])], + LIBS=['static', 'shared', 'cshared'], + LIBPATH=['.'], +) """) test.write('test.cpp', ''' diff -Nru scons-4.0.1+dfsg/test/Win32/msvc_mingw_env.py scons-4.4.0+dfsg/test/Win32/msvc_mingw_env.py --- scons-4.0.1+dfsg/test/Win32/msvc_mingw_env.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/Win32/msvc_mingw_env.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,8 @@ -""" -This tests the MinGW with MSVC tool. -""" - #!/usr/bin/env python # -# __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 @@ -24,9 +22,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__" +""" +This tests the MinGW with MSVC tool. +""" import sys @@ -43,21 +42,22 @@ # control test: check for nologo and cl in env test.write('SConstruct',""" -env=Environment(tools=['default']) +DefaultEnvironment(tools=[]) +env = Environment(tools=['default']) print('CCFLAGS=' + str(env['CCFLAGS']).strip()) print('CC=' + str(env['CC']).strip()) """) test.run(arguments='-Q -s') -if('CCFLAGS=/nologo' not in test.stdout() - or 'CC=cl' not in test.stdout()): +if 'CCFLAGS=/nologo' not in test.stdout() or 'CC=cl' not in test.stdout(): test.fail_test() # make sure windows msvc doesnt add bad mingw flags # and that gcc is selected test.write('SConstruct',""" -env=Environment(tools=['default', 'mingw']) -print('CCFLAGS="' + str(env['CCFLAGS']).strip() + '"') -print('CC=' + str(env['CC']).strip()) +DefaultEnvironment(tools=[]) +env = Environment(tools=['default', 'mingw']) +print('CCFLAGS="' + str(env['CCFLAGS']).strip() + '"') +print('CC=' + str(env['CC']).strip()) """) test.run(arguments='-Q -s') if('CCFLAGS=""' not in test.stdout() @@ -66,18 +66,19 @@ # msvc should overwrite the flags and use cl test.write('SConstruct',""" -env=Environment(tools=['mingw', 'default']) +DefaultEnvironment(tools=[]) +env = Environment(tools=['mingw', 'default']) print('CCFLAGS=' + str(env['CCFLAGS']).strip()) print('CC=' + str(env['CC']).strip()) """) test.run(arguments='-Q -s') -if('CCFLAGS=/nologo' not in test.stdout() - or 'CC=cl' not in test.stdout()): +if 'CCFLAGS=/nologo' not in test.stdout() or 'CC=cl' not in test.stdout(): test.fail_test() # test that CCFLAGS are preserved test.write('SConstruct',""" -env=Environment(tools=['mingw'], CCFLAGS='-myflag') +DefaultEnvironment(tools=[]) +env = Environment(tools=['mingw'], CCFLAGS='-myflag') print(env['CCFLAGS']) """) test.run(arguments='-Q -s') @@ -86,7 +87,8 @@ # test that it handles a list test.write('SConstruct',""" -env=Environment(tools=['mingw'], CCFLAGS=['-myflag', '-myflag2']) +DefaultEnvironment(tools=[]) +env = Environment(tools=['mingw'], CCFLAGS=['-myflag', '-myflag2']) print(str(env['CCFLAGS'])) """) test.run(arguments='-Q -s') diff -Nru scons-4.0.1+dfsg/test/YACC/BISONFLAGS.py scons-4.4.0+dfsg/test/YACC/BISONFLAGS.py --- scons-4.0.1+dfsg/test/YACC/BISONFLAGS.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/BISONFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# +# 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. + +""" +Test that detection of file-writing options in YACCFLAGS works. +Also test that the construction vars for the same purpose work. +""" + +from pathlib import Path + +import TestSCons +from TestCmd import IS_WINDOWS + +_python_ = TestSCons._python_ +_exe = TestSCons._exe + +if IS_WINDOWS: + compiler = 'msvc' + linker = 'mslink' +else: + compiler = 'gcc' + linker = 'gnulink' + +test = TestSCons.TestSCons() + +test.subdir('sub1') +test.subdir('sub2') + +test.dir_fixture('YACCFLAGS-fixture') + +test.write('SConstruct', """\ +DefaultEnvironment(tools=[]) +SConscript(dirs=['sub1', 'sub2']) +""") + +# this SConscript is for the options-in-flags version +test.write(['sub1', 'SConscript'], """\ +import sys + +env = Environment( + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-x --header=header.h --graph=graph.g', + tools=['yacc', '%(linker)s', '%(compiler)s'], +) +targs = env.CFile(target='aaa', source='aaa.y') +t = [str(target) for target in targs] +# fail ourselves if the two extra files were not detected +if not all((len(t) == 3, "header.h" in t, "graph.g" in t)): + sys.exit(1) +""" % locals()) +test.write(['sub1', 'aaa.y'], "aaa.y\nYACCFLAGS\n") + +# this SConscript is for the construction var version +test.write(['sub2', 'SConscript'], """\ +import sys + +env = Environment( + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-x', + tools=['yacc', '%(linker)s', '%(compiler)s'], +) +env.CFile( + target='aaa', + source='aaa.y', + YACC_HEADER_FILE='header.h', + YACC_GRAPH_FILE='graph.g', +) +""" % locals()) +test.write(['sub2', 'aaa.y'], "aaa.y\nYACCFLAGS\n") + +test.run('.', stderr=None) +test.must_match(['sub1', 'aaa.c'], "aaa.y\n -x --header=header.h --graph=graph.g\n") + +# NOTE: this behavior is "wrong" but we're keeping it for compat: +# the generated files should go into 'sub1', not the topdir. +test.must_match(['header.h'], 'yacc header\n') +test.must_match(['graph.g'], 'yacc graph\n') + +# To confirm the files from the file-output options were tracked, +# we should do a clean and make sure they got removed. +# As noted, they currently don't go into the tracked location, +# so using the check in the SConscript instead. +#test.run(arguments='-c .') +#test.must_not_exist(test.workpath(['sub1', 'header.h'])) +#test.must_not_exist(test.workpath(['sub1', 'graph.g'])) + +sub2 = Path('sub2') +headerfile = sub2 / 'header.h' +graphfile = sub2 / 'graph.g' +yaccflags = f"aaa.y\n -x --header={headerfile} --graph={graphfile}\n" +test.must_match(['sub2', 'aaa.c'], yaccflags) +test.must_match(['sub2', 'header.h'], 'yacc header\n') +test.must_match(['sub2', 'graph.g'], 'yacc graph\n') + +# To confirm the files from the file-output options were tracked, +# do a clean and make sure they got removed. As noted, they currently +# don't go into the tracked location, so using the the SConscript check instead. +test.run(arguments='-c .') +test.must_not_exist(test.workpath('sub2', 'header.h')) +test.must_not_exist(test.workpath('sub2', 'graph.g')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff -Nru scons-4.0.1+dfsg/test/YACC/live-check-output-cleaned.py scons-4.4.0+dfsg/test/YACC/live-check-output-cleaned.py --- scons-4.0.1+dfsg/test/YACC/live-check-output-cleaned.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/live-check-output-cleaned.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that .output file is cleaned @@ -77,14 +76,14 @@ test.write('foo.y', yacc % 'foo.y') -test.run('.', stderr = None) +test.run('.', stderr=None) -test.up_to_date(arguments = 'foo.c') +test.up_to_date(arguments='foo.c') test.must_exist(test.workpath('foo.output')) test.must_exist(test.workpath('foo.c')) -test.run(arguments = '-c .') +test.run(arguments='-c .') test.must_not_exist(test.workpath('foo.output')) test.must_not_exist(test.workpath('foo.c')) diff -Nru scons-4.0.1+dfsg/test/YACC/live.py scons-4.4.0+dfsg/test/YACC/live.py --- scons-4.0.1+dfsg/test/YACC/live.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/live.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,17 +22,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__" """ Test YACC and YACCFLAGS with a live yacc compiler. """ import TestSCons -import sys -import os _exe = TestSCons._exe _python_ = TestSCons._python_ @@ -46,14 +43,14 @@ test.write('SConstruct', """ DefaultEnvironment(tools=[]) -foo = Environment(YACCFLAGS='-d', tools = ['default', 'yacc']) +foo = Environment(YACCFLAGS='-d', tools=['default', 'yacc']) yacc = foo.Dictionary('YACC') -bar = Environment(YACC = r'%(_python_)s wrapper.py ' + yacc, tools = ['default', 'yacc']) -foo.Program(target = 'foo', source = 'foo.y') -bar.Program(target = 'bar', source = 'bar.y') -foo.Program(target = 'hello', source = ['hello.cpp']) -foo.CXXFile(target = 'file.cpp', source = ['file.yy'], YACCFLAGS='-d') -foo.CFile(target = 'not_foo', source = 'foo.y') +bar = Environment(YACC=r'%(_python_)s wrapper.py ' + yacc, tools=['default', 'yacc']) +foo.Program(target='foo', source='foo.y') +bar.Program(target='bar', source='bar.y') +foo.Program(target='hello', source=['hello.cpp']) +foo.CXXFile(target='file.cpp', source=['file.yy'], YACCFLAGS='-d') +foo.CFile(target='not_foo', source='foo.y') """ % locals()) yacc = r""" diff -Nru scons-4.0.1+dfsg/test/YACC/YACCCOM.py scons-4.4.0+dfsg/test/YACC/YACCCOM.py --- scons-4.0.1+dfsg/test/YACC/YACCCOM.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCCOM.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test the ability to configure the $YACCCOM construction variable. @@ -37,16 +36,19 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'yacc'], - YACCCOM = r'%(_python_)s mycompile.py yacc $TARGET $SOURCES') -env.CFile(target = 'aaa', source = 'aaa.y') -env.CFile(target = 'bbb', source = 'bbb.yacc') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACCCOM=r'%(_python_)s mycompile.py yacc $TARGET $SOURCES', +) +env.CFile(target='aaa', source='aaa.y') +env.CFile(target='bbb', source='bbb.yacc') """ % locals()) test.write('aaa.y', 'aaa.y\n/*yacc*/\n') test.write('bbb.yacc', 'bbb.yacc\n/*yacc*/\n') -test.run(arguments = '.') +test.run(arguments='.') test.must_match('aaa.c', "aaa.y\n") test.must_match('bbb.c', "bbb.yacc\n") diff -Nru scons-4.0.1+dfsg/test/YACC/YACCCOMSTR.py scons-4.4.0+dfsg/test/YACC/YACCCOMSTR.py --- scons-4.0.1+dfsg/test/YACC/YACCCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that the $YACCCOMSTR construction variable allows you to customize @@ -38,17 +37,20 @@ test.file_fixture('mycompile.py') test.write('SConstruct', """ -env = Environment(tools=['default', 'yacc'], - YACCCOM = r'%(_python_)s mycompile.py yacc $TARGET $SOURCES', - YACCCOMSTR = 'Yaccing $TARGET from $SOURCE') -env.CFile(target = 'aaa', source = 'aaa.y') -env.CFile(target = 'bbb', source = 'bbb.yacc') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACCCOM=r'%(_python_)s mycompile.py yacc $TARGET $SOURCES', + YACCCOMSTR='Yaccing $TARGET from $SOURCE', +) +env.CFile(target='aaa', source='aaa.y') +env.CFile(target='bbb', source='bbb.yacc') """ % locals()) test.write('aaa.y', 'aaa.y\n/*yacc*/\n') test.write('bbb.yacc', 'bbb.yacc\n/*yacc*/\n') -test.run(stdout = test.wrap_stdout("""\ +test.run(stdout=test.wrap_stdout("""\ Yaccing aaa.c from aaa.y Yaccing bbb.c from bbb.yacc """)) diff -Nru scons-4.0.1+dfsg/test/YACC/YACC-fixture/myyacc.py scons-4.4.0+dfsg/test/YACC/YACC-fixture/myyacc.py --- scons-4.0.1+dfsg/test/YACC/YACC-fixture/myyacc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACC-fixture/myyacc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,13 +1,19 @@ import getopt import sys + cmd_opts, args = getopt.getopt(sys.argv[1:], 'o:', []) opt_string = '' for opt, arg in cmd_opts: - if opt == '-o': out = arg - else: opt_string = opt_string + ' ' + opt + if opt == '-o': + out = arg + else: + opt_string = opt_string + ' ' + opt + with open(out, 'w') as ofp: for a in args: with open(a, 'r') as ifp: contents = ifp.read() - ofp.write(contents.replace('YACC', 'myyacc.py')) + contents = contents.replace('YACC', 'myyacc.py') + ofp.write(contents) + sys.exit(0) diff -Nru scons-4.0.1+dfsg/test/YACC/YACC-fixture/SConstruct_YACC_before scons-4.4.0+dfsg/test/YACC/YACC-fixture/SConstruct_YACC_before --- scons-4.0.1+dfsg/test/YACC/YACC-fixture/SConstruct_YACC_before 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACC-fixture/SConstruct_YACC_before 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,4 @@ +env=Environment(tools=[]) +env2=env.Clone(YACC="SOMETHING_DUMB") +env2.Tool('yacc') +env2.CFile('aaa.y') diff -Nru scons-4.0.1+dfsg/test/YACC/YACCFLAGS-fixture/myyacc.py scons-4.4.0+dfsg/test/YACC/YACCFLAGS-fixture/myyacc.py --- scons-4.0.1+dfsg/test/YACC/YACCFLAGS-fixture/myyacc.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCFLAGS-fixture/myyacc.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,17 +1,65 @@ import getopt import sys -cmd_opts, args = getopt.getopt(sys.argv[1:], 'o:I:x', []) -opt_string = '' -i_arguments = '' -for opt, arg in cmd_opts: - if opt == '-o': out = arg - elif opt == '-I': i_arguments = i_arguments + ' ' + arg - else: opt_string = opt_string + ' ' + opt -with open(out, 'wb') as ofp: - for a in args: - with open(a, 'rb') as ifp: - contents = ifp.read() - contents = contents.replace(b'YACCFLAGS', opt_string.encode()) - contents = contents.replace(b'I_ARGS', i_arguments.encode()) - ofp.write(contents) -sys.exit(0) +from pathlib import Path + + +def make_side_effect(path, text): + p = Path(path) + if str(p.parent) != '.': + p.parent.mkdir(parents=True, exist_ok=True) + with p.open(mode="wb") as f: + f.write(text) + + +def fake_yacc(): + make_header = None + make_graph = None + + longopts = ["defines=", "header=", "graph="] + cmd_opts, args = getopt.getopt(sys.argv[1:], 'o:I:x', longopts) + opt_string = '' + i_arguments = '' + + for opt, arg in cmd_opts: + if opt == '-o': + out = arg + elif opt == '-I': + i_arguments = f'{i_arguments} {arg}' + elif opt in ('--defines', '--header'): + make_header = arg + opt_string = f'{opt_string} {opt}={arg}' + elif opt == '--graph': + make_graph = arg + opt_string = f'{opt_string} {opt}={arg}' + else: + opt_string = f'{opt_string} {opt}' + + with open(out, 'wb') as ofp: + for a in args: + with open(a, 'rb') as ifp: + contents = ifp.read() + contents = contents.replace(b'YACCFLAGS', opt_string.encode()) + contents = contents.replace(b'YACC', b'myyacc.py') + contents = contents.replace(b'I_ARGS', i_arguments.encode()) + ofp.write(contents) + + # Extra bits: + if make_header: + make_side_effect(make_header, b"yacc header\n") + if make_graph: + make_side_effect(make_graph, b"yacc graph\n") + + +if __name__ == '__main__': + fake_yacc() + sys.exit(0) + +# 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. + +# If -g is specified on the command line, yacc will emit a .vcg +# file with the same base name as the .y, .yacc, .ym or .yy file. + +# If -v is specified yacc will create the output debug file +# which is not really source for any process, but should +# be noted and also be cleaned (issue #2558) diff -Nru scons-4.0.1+dfsg/test/YACC/YACCFLAGS.py scons-4.4.0+dfsg/test/YACC/YACCFLAGS.py --- scons-4.0.1+dfsg/test/YACC/YACCFLAGS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCFLAGS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,19 +22,16 @@ # 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 TestSCons +from TestCmd import IS_WINDOWS _python_ = TestSCons._python_ _exe = TestSCons._exe -if sys.platform == 'win32': +if IS_WINDOWS: compiler = 'msvc' linker = 'mslink' else: @@ -46,19 +45,18 @@ test.dir_fixture('YACCFLAGS-fixture') test.write('SConstruct', """ -env = Environment(YACC = r'%(_python_)s myyacc.py', - YACCFLAGS = '-x -I${TARGET.dir} -I${SOURCE.dir}', - tools=['yacc', '%(linker)s', '%(compiler)s']) -env.CFile(target = 'out/aaa', source = 'in/aaa.y') +DefaultEnvironment(tools=[]) +env = Environment( + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-x -I${TARGET.dir} -I${SOURCE.dir}', + tools=['yacc', '%(linker)s', '%(compiler)s'], +) +env.CFile(target='out/aaa', source='in/aaa.y') """ % locals()) -test.write(['in', 'aaa.y'], "aaa.y\nYACCFLAGS\nI_ARGS\n") - -test.run('.', stderr = None) - -test.must_match(['out', 'aaa.c'], "aaa.y\n -x\n out in\n") - - +test.write(['in', 'aaa.y'], "aaa.y\nYACCFLAGS\nI_ARGS\n") +test.run('.', stderr=None) +test.must_match(['out', 'aaa.c'], "aaa.y\n -x\n out in\n") test.pass_test() diff -Nru scons-4.0.1+dfsg/test/YACC/YACCHFILESUFFIX.py scons-4.4.0+dfsg/test/YACC/YACCHFILESUFFIX.py --- scons-4.0.1+dfsg/test/YACC/YACCHFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCHFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that setting the YACCHFILESUFFIX variable can reflect a yacc @@ -35,12 +34,11 @@ test = TestSCons.TestSCons() - - test.write('myyacc.py', """\ import getopt import os.path import sys + opts, args = getopt.getopt(sys.argv[1:], 'do:') for o, a in opts: if o == '-o': @@ -51,33 +49,34 @@ outfile.write(l) outfile.close() base, ext = os.path.splitext(args[0]) -with open(base+'.hsuffix', 'wb') as outfile: +with open(base + '.hsuffix', 'wb') as outfile: outfile.write((" ".join(sys.argv) + '\\n').encode()) sys.exit(0) """) test.write('SConstruct', """ -env = Environment(tools=['default', 'yacc'], - YACC = r'%(_python_)s myyacc.py', - YACCFLAGS = '-d', - YACCHFILESUFFIX = '.hsuffix') -env.CFile(target = 'aaa', source = 'aaa.y') -env.CFile(target = 'bbb', source = 'bbb.yacc') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-d', + YACCHFILESUFFIX='.hsuffix', +) +env.CFile(target='aaa', source='aaa.y') +env.CFile(target='bbb', source='bbb.yacc') """ % locals()) test.write('aaa.y', "aaa.y\n/*yacc*/\n") test.write('bbb.yacc', "bbb.yacc\n/*yacc*/\n") -test.run(arguments = '.') +test.run(arguments='.') test.must_match('aaa.c', "aaa.y\n") test.must_contain('aaa.hsuffix', "myyacc.py -d -o aaa.c aaa.y\n") test.must_match('bbb.c', "bbb.yacc\n") test.must_contain('bbb.hsuffix', "myyacc.py -d -o bbb.c bbb.yacc\n") -test.up_to_date(arguments = '.') - - +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/YACC/YACCHXXFILESUFFIX.py scons-4.4.0+dfsg/test/YACC/YACCHXXFILESUFFIX.py --- scons-4.0.1+dfsg/test/YACC/YACCHXXFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCHXXFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test that setting the YACCHXXFILESUFFIX variable can reflect a yacc @@ -35,12 +34,11 @@ test = TestSCons.TestSCons() - - test.write('myyacc.py', """\ import getopt import os.path import sys + opts, args = getopt.getopt(sys.argv[1:], 'do:') for o, a in opts: if o == '-o': @@ -51,29 +49,30 @@ outfile.write(l) outfile.close() base, ext = os.path.splitext(args[0]) -with open(base+'.hxxsuffix', 'wb') as outfile: - outfile.write((" ".join(sys.argv)+'\\n').encode()) +with open(base + '.hxxsuffix', 'wb') as outfile: + outfile.write((" ".join(sys.argv) + '\\n').encode()) sys.exit(0) """) test.write('SConstruct', """ -env = Environment(tools=['default', 'yacc'], - YACC = r'%(_python_)s myyacc.py', - YACCFLAGS = '-d', - YACCHXXFILESUFFIX = '.hxxsuffix') -env.CXXFile(target = 'aaa', source = 'aaa.yy') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-d', + YACCHXXFILESUFFIX='.hxxsuffix', +) +env.CXXFile(target='aaa', source='aaa.yy') """ % locals()) test.write('aaa.yy', "aaa.yy\n/*yacc*/\n") -test.run(arguments = '.') +test.run(arguments='.') test.must_match('aaa.cc', "aaa.yy\n") test.must_contain('aaa.hxxsuffix', "myyacc.py -d -o aaa.cc aaa.yy\n") -test.up_to_date(arguments = '.') - - +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/YACC/YACC.py scons-4.4.0+dfsg/test/YACC/YACC.py --- scons-4.0.1+dfsg/test/YACC/YACC.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACC.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,19 +22,17 @@ # 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 +from TestCmd import IS_WINDOWS import TestSCons _python_ = TestSCons._python_ _exe = TestSCons._exe -if sys.platform == 'win32': +if IS_WINDOWS: compiler = 'msvc' linker = 'mslink' else: @@ -44,22 +44,26 @@ test.dir_fixture('YACC-fixture') test.write('SConstruct', """ -env = Environment(YACC = r'%(_python_)s myyacc.py', tools=['default', 'yacc']) -env.CFile(target = 'aaa', source = 'aaa.y') -env.CFile(target = 'bbb', source = 'bbb.yacc') -env.CXXFile(target = 'ccc', source = 'ccc.yy') -env.CFile(target = 'ddd', source = 'ddd.ym') +DefaultEnvironment(tools=[]) +env = Environment(YACC=r'%(_python_)s myyacc.py', tools=['default', 'yacc']) +env.CFile(target='aaa', source='aaa.y') +env.CFile(target='bbb', source='bbb.yacc') +env.CXXFile(target='ccc', source='ccc.yy') +env.CFile(target='ddd', source='ddd.ym') """ % locals()) -test.run(arguments = '.', stderr = None) - -test.must_match('aaa.c', "aaa.y" + os.linesep + "myyacc.py" + os.linesep) -test.must_match('bbb.c', "bbb.yacc" + os.linesep + "myyacc.py" + os.linesep) -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='.', stderr=None) +test.must_match('aaa.c', "aaa.y" + os.linesep + "myyacc.py" + os.linesep) +test.must_match('bbb.c', "bbb.yacc" + os.linesep + "myyacc.py" + os.linesep) +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 -Nru scons-4.0.1+dfsg/test/YACC/YACCVCGFILESUFFIX.py scons-4.4.0+dfsg/test/YACC/YACCVCGFILESUFFIX.py --- scons-4.0.1+dfsg/test/YACC/YACCVCGFILESUFFIX.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/YACC/YACCVCGFILESUFFIX.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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__" """ Test setting the YACCVCGFILESUFFIX variable. @@ -34,12 +33,11 @@ test = TestSCons.TestSCons() - - test.write('myyacc.py', """\ import getopt import os.path import sys + vcg = None opts, args = getopt.getopt(sys.argv[1:], 'go:') for o, a in opts: @@ -54,23 +52,26 @@ outfile.close() if vcg: base, ext = os.path.splitext(args[0]) - with open(base+'.vcgsuffix', 'wb') as outfile: - outfile.write((" ".join(sys.argv)+'\\n').encode()) + with open(base + '.vcgsuffix', 'wb') as outfile: + outfile.write((" ".join(sys.argv) + '\\n').encode()) sys.exit(0) """) test.write('SConstruct', """ -env = Environment(tools=['default', 'yacc'], - YACC = r'%(_python_)s myyacc.py', - YACCVCGFILESUFFIX = '.vcgsuffix') -env.CXXFile(target = 'aaa', source = 'aaa.yy') -env.CXXFile(target = 'bbb', source = 'bbb.yy', YACCFLAGS = '-g') +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACC=r'%(_python_)s myyacc.py', + YACCVCGFILESUFFIX='.vcgsuffix', +) +env.CXXFile(target='aaa', source='aaa.yy') +env.CXXFile(target='bbb', source='bbb.yy', YACCFLAGS='-g') """ % locals()) test.write('aaa.yy', "aaa.yy\n/*yacc*/\n") test.write('bbb.yy', "bbb.yy\n/*yacc*/\n") -test.run(arguments = '.') +test.run(arguments='.') test.must_match('aaa.cc', "aaa.yy\n") test.must_not_exist('aaa.vcg') @@ -80,9 +81,7 @@ test.must_not_exist('bbb.vcg') test.must_contain('bbb.vcgsuffix', "myyacc.py -g -o bbb.cc bbb.yy\n") -test.up_to_date(arguments = '.') - - +test.up_to_date(arguments='.') test.pass_test() diff -Nru scons-4.0.1+dfsg/test/ZIP/ZIPCOMSTR.py scons-4.4.0+dfsg/test/ZIP/ZIPCOMSTR.py --- scons-4.0.1+dfsg/test/ZIP/ZIPCOMSTR.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/ZIP/ZIPCOMSTR.py 2022-07-30 21:48:28.000000000 +0000 @@ -42,12 +42,21 @@ 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 -Nru scons-4.0.1+dfsg/test/ZIP/ZIP_OVERRIDE_TIMESTAMP.py scons-4.4.0+dfsg/test/ZIP/ZIP_OVERRIDE_TIMESTAMP.py --- scons-4.0.1+dfsg/test/ZIP/ZIP_OVERRIDE_TIMESTAMP.py 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/test/ZIP/ZIP_OVERRIDE_TIMESTAMP.py 2022-07-30 21:48:28.000000000 +0000 @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# +# 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 TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +import zipfile + + +def zipfile_get_file_datetime(zipfilename, fname): + """Returns the date_time of the given file with the archive.""" + with zipfile.ZipFile(zipfilename, 'r') as zf: + for info in zf.infolist(): + if info.filename == fname: + return info.date_time + + raise Exception("Unable to find %s" % fname) + + +test.write('SConstruct', """ +env = Environment(tools = ['zip']) +env.Zip(target = 'aaa.zip', source = ['file1'], ZIP_OVERRIDE_TIMESTAMP=(1983,3,11,1,2,2)) +""" % locals()) + +test.write(['file1'], "file1\n") + +test.run(arguments = 'aaa.zip', stderr = None) + +test.must_exist('aaa.zip') + +with zipfile.ZipFile('aaa.zip', 'r') as zf: + test.fail_test(zf.testzip() is not None) + +files = test.zipfile_files('aaa.zip') +test.fail_test(files != ['file1'], + message='Zip file aaa.zip has wrong files: %s' % repr(files)) + +date_time = zipfile_get_file_datetime('aaa.zip', 'file1') +test.fail_test(date_time != (1983, 3, 11, 1, 2, 2), + message="Zip file aaa.zip#file1 has wrong date_time: %s" % repr(date_time)) + +test.pass_test() diff -Nru scons-4.0.1+dfsg/test/ZIP/ZIP.py scons-4.4.0+dfsg/test/ZIP/ZIP.py --- scons-4.0.1+dfsg/test/ZIP/ZIP.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/ZIP/ZIP.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,9 +22,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 import stat @@ -33,30 +32,6 @@ test = TestSCons.TestSCons() -try: - import zipfile -except ImportError: - x = "Python version has no 'ziplib' module; skipping tests.\n" - test.skip_test(x) - -def zipfile_contains(zipfilename, names): - """Returns True if zipfilename contains all the names, False otherwise.""" - zf=zipfile.ZipFile(zipfilename, 'r') - if type(names)==type(''): - names=[names] - for name in names: - try: - info=zf.getinfo(name) - except KeyError as e: # name not found - zf.close() - return False - return True - -def zipfile_files(fname): - """Returns all the filenames in zip file fname.""" - zf = zipfile.ZipFile(fname, 'r') - return [x.filename for x in zf.infolist()] - test.subdir('sub1') test.write('SConstruct', """ @@ -78,12 +53,12 @@ test.run(arguments = 'aaa.zip', stderr = None) test.must_exist('aaa.zip') -test.fail_test(not zipfile_contains('aaa.zip', ['file1', 'file2', 'file3'])) +test.fail_test(not test.zipfile_contains('aaa.zip', ['file1', 'file2', 'file3'])) test.run(arguments = 'bbb.zip', stderr = None) test.must_exist('bbb.zip') -test.fail_test(not zipfile_contains('bbb.zip', ['sub1/file5', 'sub1/file6', 'file4'])) +test.fail_test(not test.zipfile_contains('bbb.zip', ['sub1/file5', 'sub1/file6', 'file4'])) ###### @@ -136,11 +111,11 @@ test.must_not_exist(test.workpath('f3.zip')) test.must_exist(test.workpath('f3.xyzzy')) -test.fail_test(zipfile_files("f1.zip") != ['file10', 'file11', 'file12']) +test.fail_test(test.zipfile_files("f1.zip") != ['file10', 'file11', 'file12']) -test.fail_test(zipfile_files("f2.zip") != ['file13', 'file14', 'file15']) +test.fail_test(test.zipfile_files("f2.zip") != ['file13', 'file14', 'file15']) -test.fail_test(zipfile_files("f3.xyzzy") != ['file16', 'file17', 'file18']) +test.fail_test(test.zipfile_files("f3.xyzzy") != ['file16', 'file17', 'file18']) f4_size = os.stat('f4.zip')[stat.ST_SIZE] f4stored_size = os.stat('f4stored.zip')[stat.ST_SIZE] diff -Nru scons-4.0.1+dfsg/test/ZIP/ZIPROOT.py scons-4.4.0+dfsg/test/ZIP/ZIPROOT.py --- scons-4.0.1+dfsg/test/ZIP/ZIPROOT.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/test/ZIP/ZIPROOT.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __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 @@ -20,12 +22,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 os -import stat import TestSCons @@ -35,23 +32,6 @@ import zipfile -def zipfile_contains(zipfilename, names): - """Returns True if zipfilename contains all the names, False otherwise.""" - zf=zipfile.ZipFile(zipfilename, 'r') - if type(names)==type(''): - names=[names] - for name in names: - try: - info=zf.getinfo(name) - except KeyError as e: # name not found - zf.close() - return False - return True - -def zipfile_files(fname): - """Returns all the filenames in zip file fname.""" - zf = zipfile.ZipFile(fname, 'r') - return [x.filename for x in zf.infolist()] test.subdir('sub1') test.subdir(['sub1', 'sub2']) @@ -71,13 +51,12 @@ test.must_exist('aaa.zip') # TEST: Zip file should contain 'file1', not 'sub1/file1', because of ZIPROOT. -zf=zipfile.ZipFile('aaa.zip', 'r') -test.fail_test(zf.testzip() is not None) -zf.close() - -files=zipfile_files('aaa.zip') -test.fail_test(zipfile_files('aaa.zip') != ['file1'], - message='Zip file aaa.zip has wrong files: %s'%repr(files)) +with zipfile.ZipFile('aaa.zip', 'r') as zf: + test.fail_test(zf.testzip() is not None) + +files = test.zipfile_files('aaa.zip') +test.fail_test(test.zipfile_files('aaa.zip') != ['file1'], + message='Zip file aaa.zip has wrong files: %s' % repr(files)) ### @@ -86,13 +65,12 @@ test.must_exist('bbb.zip') # TEST: Zip file should contain 'sub2/file2', not 'sub1/sub2/file2', because of ZIPROOT. -zf=zipfile.ZipFile('bbb.zip', 'r') -test.fail_test(zf.testzip() is not None) -zf.close() - -files=zipfile_files('bbb.zip') -test.fail_test(zipfile_files('bbb.zip') != ['file2', 'sub2/file2'], - message='Zip file bbb.zip has wrong files: %s'%repr(files)) +with zipfile.ZipFile('bbb.zip', 'r') as zf: + test.fail_test(zf.testzip() is not None) + +files = test.zipfile_files('bbb.zip') +test.fail_test(test.zipfile_files('bbb.zip') != ['file2', 'sub2/file2'], + message='Zip file bbb.zip has wrong files: %s' % repr(files)) test.pass_test() diff -Nru scons-4.0.1+dfsg/testing/framework/TestCmd.py scons-4.4.0+dfsg/testing/framework/TestCmd.py --- scons-4.0.1+dfsg/testing/framework/TestCmd.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestCmd.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,5 @@ """ -TestCmd.py: a testing framework for commands and scripts. +A testing framework for commands and scripts. The TestCmd module provides a framework for portable automated testing of executable commands and scripts (in any language, not just Python), @@ -299,9 +299,12 @@ import atexit import difflib import errno +import hashlib import os import re +import psutil import shutil +import signal import stat import subprocess import sys @@ -309,20 +312,20 @@ import threading import time import traceback -import types from collections import UserList, UserString +from pathlib import Path from subprocess import PIPE, STDOUT - +from typing import Optional IS_WINDOWS = sys.platform == 'win32' +IS_MACOS = sys.platform == 'darwin' IS_64_BIT = sys.maxsize > 2**32 IS_PYPY = hasattr(sys, 'pypy_translation_info') - +NEED_HELPER = os.environ.get('SCONS_NO_DIRECT_SCRIPT') # sentinel for cases where None won't do _Null = object() - __all__ = [ 'diff_re', 'fail_test', @@ -345,13 +348,13 @@ 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') @@ -384,17 +387,57 @@ return string +def clean_up_ninja_daemon(self, result_type): + """ + Kill any running scons daemon started by ninja and clean up it's working dir and + temp files. + """ + if self: + for path in Path(self.workdir).rglob('.ninja'): + daemon_dir = Path(tempfile.gettempdir()) / ( + "scons_daemon_" + str(hashlib.md5(str(path.resolve()).encode()).hexdigest()) + ) + pidfiles = [daemon_dir / 'pidfile', path / 'scons_daemon_dirty'] + for pidfile in pidfiles: + if pidfile.exists(): + with open(pidfile) as f: + try: + pid = int(f.read()) + os.kill(pid, signal.SIGINT) + except OSError: + pass + + while True: + if pid not in [proc.pid for proc in psutil.process_iter()]: + break + else: + time.sleep(0.1) + + if not self._preserve[result_type]: + if daemon_dir.exists(): + shutil.rmtree(daemon_dir) + + def fail_test(self=None, condition=True, function=None, skip=0, message=None): - """Cause the test to fail. + """Causes a test to exit with a fail. - By default, the fail_test() method reports that the test FAILED - and exits with a status of 1. If a condition argument is supplied, - the test fails only if the condition is true. + Reports that the test FAILED and exits with a status of 1, unless + a condition argument is supplied; if so the completion processing + takes place only if the condition is true. + + Args: + self: a test class instance. Must be passed in explicitly + by the caller since this is an unbound method. + condition (optional): if false, return to let test continue. + function (optional): function to call before completion processing. + skip (optional): how many lines at the top of the traceback to skip. + message (optional): additional text to include in the fail message. """ if not condition: return if function is not None: function() + clean_up_ninja_daemon(self, 'fail_test') of = "" desc = "" sep = " " @@ -417,16 +460,30 @@ def no_result(self=None, condition=True, function=None, skip=0): - """Causes a test to exit with no valid result. + """Causes a test to exit with a no result. - By default, the no_result() method reports NO RESULT for the test - and exits with a status of 2. If a condition argument is supplied, - the test fails only if the condition is true. + In testing parlance NO RESULT means the test could not be completed + for reasons that imply neither success nor failure - for example a + component needed to run the test could be found. However, at this + point we still have an "outcome", so record the information and exit + with a status code of 2, unless a condition argument is supplied; + if so the completion processing takes place only if the condition is true. + + The different exit code and message allows other logic to distinguish + from a fail and decide how to treat NO RESULT tests. + + Args: + self: a test class instance. Must be passed in explicitly + by the caller since this is an unbound method. + condition (optional): if false, return to let test continue. + function (optional): function to call before completion processing. + skip (optional): how many lines at the top of the traceback to skip. """ if not condition: return if function is not None: function() + clean_up_ninja_daemon(self, 'no_result') of = "" desc = "" sep = " " @@ -445,16 +502,25 @@ def pass_test(self=None, condition=True, function=None): - """Causes a test to pass. + """Causes a test to exit with a pass. + + Reports that the test PASSED and exits with a status of 0, unless + a condition argument is supplied; if so the completion processing + takes place only if the condition is true. - By default, the pass_test() method reports PASSED for the test - and exits with a status of 0. If a condition argument is supplied, the test passes only if the condition is true. + + Args: + self: a test class instance. Must be passed in explicitly + by the caller since this is an unbound method. + condition (optional): if false, return to let test continue. + function (optional): function to call before completion processing. """ if not condition: return if function is not None: function() + clean_up_ninja_daemon(self, 'pass_test') sys.stderr.write("PASSED\n") sys.exit(0) @@ -467,10 +533,10 @@ :param matches: expected lines to match :type matches: str or list[str] :param newline: line separator - :returns: an object (1) on match, else None, like re.match + :returns: None on failure, 1 on success. """ - if isinstance(lines, bytes) or bytes is str: + if isinstance(lines, bytes): newline = to_bytes(newline) if not is_List(lines): @@ -496,8 +562,7 @@ :type lines: str or list[str] :param matches: expected lines to match :type matches: str or list[str] - :returns: True or False - :returns: an object (1) on match, else None, like re.match + :returns: None on failure, 1 on success. """ if not is_List(lines): @@ -519,7 +584,7 @@ :type lines: str or list[str] :param res: regular expression(s) for matching :type res: str or list[str] - :returns: an object (1) on match, else None, like re.match + :returns: None on failure, 1 on success. """ if not is_List(lines): @@ -554,7 +619,7 @@ :type lines: str or list[str] :param res: regular expression(s) for matching :type res: str or list[str] - :returns: a match object, or None as for re.match + :returns: a match object on match, else None, like re.match """ if not isinstance(lines, str): @@ -575,15 +640,13 @@ r"""Compare two sequences of lines; generate the delta as a simple diff. Similar to difflib.context_diff and difflib.unified_diff but - output is like from the 'diff" command without arguments. The function + output is like from the "diff" command without arguments. The function keeps the same signature as the difflib ones so they will be interchangeable, but except for lineterm, the arguments beyond the two sequences are ignored in this version. By default, the diff is not created with trailing newlines, set the lineterm argument to '\n' to do so. - :raises re.error: if a regex fails to compile - Example: >>> print(''.join(simple_diff('one\ntwo\nthree\nfour\n'.splitlines(True), @@ -624,13 +687,16 @@ def diff_re(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): - """Compare a and b (lists of strings) where a are regexes. + """Compare a and b (lists of strings) where a are regular expressions. A simple "diff" of two sets of lines when the expected lines are regular expressions. This is a really dumb thing that just compares each line in turn, so it doesn't look for chunks of matching lines and the like--but at least it lets you know exactly which line first didn't compare correctl... + + Raises: + re.error: if a regex fails to compile """ result = [] diff = len(a) - len(b) @@ -1097,6 +1163,9 @@ interpreter = [interpreter] cmd = list(interpreter) + cmd if arguments: + if isinstance(arguments, dict): + cmd.extend(["%s=%s" % (k, v) for k, v in arguments.items()]) + return cmd if isinstance(arguments, str): arguments = arguments.split() cmd.extend(arguments) @@ -1208,8 +1277,7 @@ return match_stderr_function(lines, matches) def match_stdout(self, lines, matches): - """Compare actual and expected file contents. - """ + """Compare actual and expected file contents.""" try: match_stdout_function = getattr(self, self._match_stdout_function) except TypeError: @@ -1238,8 +1306,7 @@ skip=skip) def pass_test(self, condition=True, function=None): - """Cause the test to pass. - """ + """Cause the test to pass.""" if not condition: return self.condition = 'pass_test' @@ -1543,6 +1610,9 @@ The specified program will have the original directory prepended unless it is enclosed in a [list]. + + argument: If this is a dict() then will create arguments with KEY+VALUE for + each entry in the dict. """ if self.external: if not program: @@ -1616,7 +1686,7 @@ """ time.sleep(seconds) - def stderr(self, run=None): + def stderr(self, run=None) -> Optional[str]: """Returns the error output from the specified run number. If there is no specified run number, then returns the error @@ -1628,10 +1698,13 @@ run = len(self._stderr) elif run < 0: run = len(self._stderr) + run - run = run - 1 - return self._stderr[run] + run -= 1 + try: + return self._stderr[run] + except IndexError: + return None - def stdout(self, run=None): + def stdout(self, run=None) -> Optional[str]: """Returns the stored standard output from a given run. Args: @@ -1648,7 +1721,7 @@ run = len(self._stdout) elif run < 0: run = len(self._stdout) + run - run = run - 1 + run -= 1 try: return self._stdout[run] except IndexError: diff -Nru scons-4.0.1+dfsg/testing/framework/TestCmdTests.py scons-4.4.0+dfsg/testing/framework/TestCmdTests.py --- scons-4.0.1+dfsg/testing/framework/TestCmdTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestCmdTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,36 +1,34 @@ #!/usr/bin/env python """ -TestCmdTests.py: Unit tests for the TestCmd.py module. - -Copyright 2000-2010 Steven Knight -This module is free software, and you may redistribute it and/or modify -it under the same terms as Python itself, so long as this copyright message -and disclaimer are retained in their original form. - -IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, -SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF -THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, -AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, -SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +Unit tests for the TestCmd.py module. """ +# Copyright 2000-2010 Steven Knight +# This module is free software, and you may redistribute it and/or modify +# it under the same terms as Python itself, so long as this copyright message +# and disclaimer are retained in their original form. +# +# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. +# +# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + __author__ = "Steven Knight " __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 @@ -245,7 +243,7 @@ import sys import TestCmd -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path @atexit.register def cleanup(): @@ -417,7 +415,7 @@ def test_diff_custom_function(self): """Test diff() using a custom function""" self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def my_diff(a, b): return [ @@ -442,7 +440,7 @@ def test_diff_string(self): self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff = 'diff_re') test.diff("a\\nb1\\nc\\n", "a\\nb2\\nc\\n", 'STDOUT') @@ -459,7 +457,7 @@ def test_error(self): """Test handling a compilation error in TestCmd.diff_re()""" script_input = """import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd assert TestCmd.diff_re([r"a.*(e"], ["abcde"]) sys.exit(0) @@ -474,7 +472,7 @@ def test_simple_diff_static_method(self): """Test calling the TestCmd.TestCmd.simple_diff() static method""" self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd result = TestCmd.TestCmd.simple_diff(['a', 'b', 'c', 'e', 'f1'], ['a', 'c', 'd', 'e', 'f2']) @@ -487,7 +485,7 @@ def test_context_diff_static_method(self): """Test calling the TestCmd.TestCmd.context_diff() static method""" self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd result = TestCmd.TestCmd.context_diff(['a\\n', 'b\\n', 'c\\n', 'e\\n', 'f1\\n'], ['a\\n', 'c\\n', 'd\\n', 'e\\n', 'f2\\n']) @@ -516,7 +514,7 @@ def test_unified_diff_static_method(self): """Test calling the TestCmd.TestCmd.unified_diff() static method""" self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd result = TestCmd.TestCmd.unified_diff(['a\\n', 'b\\n', 'c\\n', 'e\\n', 'f1\\n'], ['a\\n', 'c\\n', 'd\\n', 'e\\n', 'f2\\n']) @@ -540,7 +538,7 @@ def test_diff_re_static_method(self): """Test calling the TestCmd.TestCmd.diff_re() static method""" self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd result = TestCmd.TestCmd.diff_re(['a', 'b', 'c', '.', 'f1'], ['a', 'c', 'd', 'e', 'f2']) @@ -569,7 +567,7 @@ def test_diff_stderr_default(self): """Test diff_stderr() default behavior""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd() test.diff_stderr('a\nb1\nc\n', 'a\nb2\nc\n') @@ -586,7 +584,7 @@ """Test diff_stderr() not affecting diff_stdout() behavior""" self.popen_python(r""" import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stderr='diff_re') print("diff_stderr:") @@ -607,7 +605,7 @@ def test_diff_stderr_custom_function(self): """Test diff_stderr() using a custom function""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def my_diff(a, b): return ["a:"] + a + ["b:"] + b @@ -625,7 +623,7 @@ def test_diff_stderr_TestCmd_function(self): """Test diff_stderr() using a TestCmd function""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stderr = TestCmd.diff_re) test.diff_stderr('a\n.\n', 'b\nc\n') @@ -641,7 +639,7 @@ def test_diff_stderr_static_method(self): """Test diff_stderr() using a static method""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stderr=TestCmd.TestCmd.diff_re) test.diff_stderr('a\n.\n', 'b\nc\n') @@ -657,7 +655,7 @@ def test_diff_stderr_string(self): """Test diff_stderr() using a string to fetch the diff method""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stderr='diff_re') test.diff_stderr('a\n.\n', 'b\nc\n') @@ -676,7 +674,7 @@ def test_diff_stdout_default(self): """Test diff_stdout() default behavior""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd() test.diff_stdout('a\nb1\nc\n', 'a\nb2\nc\n') @@ -693,7 +691,7 @@ """Test diff_stdout() not affecting diff_stderr() behavior""" self.popen_python(r""" import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stdout='diff_re') print("diff_stdout:") @@ -714,7 +712,7 @@ def test_diff_stdout_custom_function(self): """Test diff_stdout() using a custom function""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def my_diff(a, b): return ["a:"] + a + ["b:"] + b @@ -732,7 +730,7 @@ def test_diff_stdout_TestCmd_function(self): """Test diff_stdout() using a TestCmd function""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stdout = TestCmd.diff_re) test.diff_stdout('a\n.\n', 'b\nc\n') @@ -748,7 +746,7 @@ def test_diff_stdout_static_method(self): """Test diff_stdout() using a static method""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stdout=TestCmd.TestCmd.diff_re) test.diff_stdout('a\n.\n', 'b\nc\n') @@ -764,7 +762,7 @@ def test_diff_stdout_string(self): """Test diff_stdout() using a string to fetch the diff method""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stdout='diff_re') test.diff_stdout('a\n.\n', 'b\nc\n') @@ -790,7 +788,7 @@ 'no_result': "NO RESULT for test at line 5 of \n"} global ExitError input = """import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(workdir = '%s') test.%s() @@ -865,13 +863,13 @@ # Everything before this prepared our "source directory." # Now do the real test. self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd TestCmd.fail_test(condition = 1) """ % self.orig_cwd, status = 1, stderr = "FAILED test at line 4 of \n") self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -879,7 +877,7 @@ """ % self.orig_cwd, status = 1, stderr = "FAILED test of %s\n\tat line 6 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', description = 'xyzzy', workdir = '') test.run() @@ -887,7 +885,7 @@ """ % self.orig_cwd, status = 1, stderr = "FAILED test of %s [xyzzy]\n\tat line 6 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -897,7 +895,7 @@ """ % self.orig_cwd, status = 1, stderr = "printed on failure\nFAILED test of %s\n\tat line 8 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def test1(self): self.run() @@ -908,7 +906,7 @@ """ % self.orig_cwd, status = 1, stderr = "FAILED test of %s\n\tat line 6 of (test1)\n\tfrom line 8 of (test2)\n\tfrom line 9 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def test1(self): self.run() @@ -1065,7 +1063,7 @@ # Now do the real test. try: script_input = """import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd assert TestCmd.match_re_dotall("abcde", r"a.*(e") sys.exit(0) @@ -1138,7 +1136,7 @@ # Now do the real test. try: script_input = """import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd assert TestCmd.match_re("abcde\\n", "a.*(e\\n") sys.exit(0) @@ -1348,13 +1346,13 @@ # Everything before this prepared our "source directory." # Now do the real test. self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd TestCmd.no_result(condition = 1) """ % self.orig_cwd, status = 2, stderr = "NO RESULT for test at line 4 of \n") self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -1362,7 +1360,7 @@ """ % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s\n\tat line 6 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', description = 'xyzzy', workdir = '') test.run() @@ -1370,7 +1368,7 @@ """ % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s [xyzzy]\n\tat line 6 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -1380,7 +1378,7 @@ """ % self.orig_cwd, status = 2, stderr = "printed on no result\nNO RESULT for test of %s\n\tat line 8 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def test1(self): self.run() @@ -1391,7 +1389,7 @@ """ % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s\n\tat line 6 of (test1)\n\tfrom line 8 of (test2)\n\tfrom line 9 of \n" % run_env.workpath('run')) self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd def test1(self): self.run() @@ -1415,13 +1413,13 @@ # Everything before this prepared our "source directory." # Now do the real test. self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd TestCmd.pass_test(condition = 1) """ % self.orig_cwd, stderr = "PASSED\n") self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -1429,7 +1427,7 @@ """ % self.orig_cwd, stderr = "PASSED\n") self.popen_python("""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '') test.run() @@ -2053,7 +2051,7 @@ def test_set_diff_function(self): """Test set_diff_function()""" self.popen_python(r"""import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd() test.diff("a\n", "a\n") @@ -2066,7 +2064,7 @@ """Test set_diff_function(): stdout""" self.popen_python("""\ import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd() print("diff:") @@ -2095,7 +2093,7 @@ """Test set_diff_function(): stderr """ self.popen_python("""\ import sys -sys.path = ['%s'] + sys.path +sys.path = [r'%s'] + sys.path import TestCmd test = TestCmd.TestCmd() print("diff:") @@ -2171,15 +2169,15 @@ """Test sleep()""" test = TestCmd.TestCmd() - start = time.time() + start = time.perf_counter() test.sleep() - end = time.time() + end = time.perf_counter() diff = end - start assert diff > 0.9, "only slept %f seconds (start %f, end %f), not default" % (diff, start, end) - start = time.time() + start = time.perf_counter() test.sleep(3) - end = time.time() + end = time.perf_counter() diff = end - start assert diff > 2.9, "only slept %f seconds (start %f, end %f), not 3" % (diff, start, end) @@ -2263,6 +2261,12 @@ expect = ['PYTHON', default_prog, 'arg3', 'arg4'] assert r == expect, (expect, r) + # Test arguments = dict + r = test.command_args(interpreter='PYTHON', arguments={'VAR1':'1'}) + expect = ['PYTHON', default_prog, 'VAR1=1'] + assert r == expect, (expect, r) + + test.interpreter_set('default_python') r = test.command_args() @@ -2587,7 +2591,7 @@ with open(t.recv_out_path, 'rb') as f: result = to_str(f.read()) expect = 'script_recv: ' + input - assert result == expect, repr(result) + assert result == expect, "Result:[%s] should match\nExpected:[%s]" % (result, expect) p = test.start(stdin=1) input = 'send() input to the receive script\n' @@ -3105,7 +3109,7 @@ assert wpath == os.path.join(test.workdir, 'foo', 'bar') - +@unittest.skipIf(sys.platform == 'win32', "Don't run on win32") class readable_TestCase(TestCmdTestCase): def test_readable(self): """Test readable()""" @@ -3185,7 +3189,7 @@ assert not _is_writable(test.workpath('file1')) - +@unittest.skipIf(sys.platform == 'win32', "Don't run on win32") class executable_TestCase(TestCmdTestCase): def test_executable(self): """Test executable()""" @@ -3333,68 +3337,8 @@ assert stderr == "", stderr - if __name__ == "__main__": - tclasses = [ - __init__TestCase, - basename_TestCase, - cleanup_TestCase, - chmod_TestCase, - combine_TestCase, - command_args_TestCase, - description_TestCase, - diff_TestCase, - diff_stderr_TestCase, - diff_stdout_TestCase, - exit_TestCase, - fail_test_TestCase, - interpreter_TestCase, - match_TestCase, - match_exact_TestCase, - match_re_dotall_TestCase, - match_re_TestCase, - match_stderr_TestCase, - match_stdout_TestCase, - no_result_TestCase, - pass_test_TestCase, - preserve_TestCase, - program_TestCase, - read_TestCase, - rmdir_TestCase, - run_TestCase, - run_verbose_TestCase, - set_diff_function_TestCase, - set_match_function_TestCase, - sleep_TestCase, - start_TestCase, - stderr_TestCase, - stdin_TestCase, - stdout_TestCase, - subdir_TestCase, - symlink_TestCase, - tempdir_TestCase, - timeout_TestCase, - unlink_TestCase, - touch_TestCase, - verbose_TestCase, - workdir_TestCase, - workdirs_TestCase, - workpath_TestCase, - writable_TestCase, - write_TestCase, - variables_TestCase, - ] - if sys.platform != 'win32': - tclasses.extend([ - executable_TestCase, - readable_TestCase, - ]) - suite = unittest.TestSuite() - for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests([ tclass(n) for n in names ]) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + unittest.main() # Local Variables: # tab-width:4 diff -Nru scons-4.0.1+dfsg/testing/framework/TestCommon.py scons-4.4.0+dfsg/testing/framework/TestCommon.py --- scons-4.0.1+dfsg/testing/framework/TestCommon.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestCommon.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,5 @@ """ -TestCommon.py: a testing framework for commands and scripts - with commonly useful error handling +A testing framework for commands and scripts with commonly useful error handling The TestCommon module provides a simple, high-level interface for writing tests of executable commands and scripts, especially commands and scripts @@ -57,12 +56,14 @@ test.must_not_exist('file1', ['file2', ...]) test.must_not_be_empty('file') - - test.run(options = "options to be prepended to arguments", - stdout = "expected standard output from the program", - stderr = "expected error output from the program", - status = expected_status, - match = match_function) + + test.run( + options="options to be prepended to arguments", + stdout="expected standard output from the program", + stderr="expected error output from the program", + status=expected_status, + match=match_function, + ) The TestCommon module also provides the following variables @@ -99,35 +100,43 @@ __revision__ = "TestCommon.py 1.3.D001 2010/06/03 12:58:27 knight" __version__ = "1.3" -import copy import glob import os import stat import sys +import sysconfig from collections import UserList from TestCmd import * from TestCmd import __all__ -__all__.extend([ 'TestCommon', - 'exe_suffix', - 'obj_suffix', - 'shobj_prefix', - 'shobj_suffix', - 'lib_prefix', - 'lib_suffix', - 'dll_prefix', - 'dll_suffix', - ]) +__all__.extend( + [ + 'TestCommon', + 'exe_suffix', + 'obj_suffix', + 'shobj_prefix', + 'shobj_suffix', + 'lib_prefix', + 'lib_suffix', + 'dll_prefix', + 'dll_suffix', + ] +) # Variables that describe the prefixes and suffixes on this system. if sys.platform == 'win32': + if sysconfig.get_platform() == "mingw": + obj_suffix = '.o' + shobj_suffix = '.o' + else: + obj_suffix = '.obj' + shobj_suffix = '.obj' exe_suffix = '.exe' - obj_suffix = '.obj' - shobj_suffix = '.obj' shobj_prefix = '' lib_prefix = '' + # TODO: for mingw, is this .lib or .a? lib_suffix = '.lib' dll_prefix = '' dll_suffix = '.dll' @@ -252,7 +261,7 @@ calling the base class initialization, and then changing directory to the workdir. """ - TestCmd.__init__(self, **kw) + super().__init__(**kw) os.chdir(self.workdir) def options_arguments(self, options, arguments): @@ -304,9 +313,8 @@ Calling test exits FAILED if search result is false """ if 'b' in mode: - # Python 3: reading a file in binary mode returns a - # bytes object. We cannot find the index of a different - # (str) type in that, so convert. + # Reading a file in binary mode returns a bytes object. + # We cannot search for a string in a bytes obj so convert. required = to_bytes(required) file_contents = self.read(file, mode) @@ -352,14 +360,10 @@ function, of the form "find(output, line)", to use when searching for lines in the output. """ - missing = [] if is_List(output): output = '\n'.join(output) - for line in lines: - if not contains(output, line, find): - missing.append(line) - + missing = [line for line in lines if not contains(output, line, find)] if missing: if title is None: title = 'output' @@ -370,6 +374,33 @@ sys.stdout.write(output) self.fail_test() + def must_contain_single_instance_of(self, output, lines, title=None): + """Ensures that the specified output string (first argument) + contains one instance of the specified lines (second argument). + + An optional third argument can be used to describe the type + of output being searched, and only shows up in failure output. + + """ + if is_List(output): + output = '\n'.join(output) + + counts = {} + for line in lines: + count = output.count(line) + if count != 1: + counts[line] = count + + if counts: + if title is None: + title = 'output' + sys.stdout.write("Unexpected number of lines from %s:\n" % title) + for line in counts: + sys.stdout.write(' ' + repr(line) + ": found " + str(counts[line]) + '\n') + sys.stdout.write(self.banner(title + ' ') + '\n') + sys.stdout.write(output) + self.fail_test() + def must_contain_any_line(self, output, lines, title=None, find=None): """Ensures that the specified output string (first argument) contains at least one of the specified lines (second argument). @@ -582,7 +613,7 @@ fsize = os.path.getsize(file) except OSError: fsize = 0 - + if fsize == 0: print("File is empty: `%s'" % file) self.fail_test(file) @@ -723,7 +754,7 @@ self._complete(self.stdout(), stdout, self.stderr(), stderr, status, match) - def skip_test(self, message="Skipping test.\n"): + def skip_test(self, message="Skipping test.\n", from_fw=False): """Skips a test. Proper test-skipping behavior is dependent on the external @@ -732,24 +763,34 @@ In either case, we print the specified message as an indication that the substance of the test was skipped. - (This was originally added to support development under Aegis. - Technically, skipping a test is a NO RESULT, but Aegis would - treat that as a test failure and prevent the change from going to - the next step. Since we ddn't want to force anyone using Aegis - to have to install absolutely every tool used by the tests, we - would actually report to Aegis that a skipped test has PASSED - so that the workflow isn't held up.) + The use case for treating the skip as a PASS was an old system + that the SCons project has not used for a long time, and that + code path could eventually be dropped. + + When reporting a NO RESULT, we normally skip the top line of the + traceback, as from no_result()'s point of view, that is this + function, and the user is likely to only be interested in the + test that called us. If from_fw is True, the skip was initiated + indirectly, coming from some function in the framework + (test_for_tool, skip_if_msvc, etc.), in this case we want to + skip an additional line to eliminate that function as well. + + Args: + message: text to include in the skip message. Callers + should normally provide a reason, to improve on the default. + from_fw: if true, skip an extra line of traceback. """ if message: sys.stdout.write(message) + if not message.endswith('\n'): + sys.stdout.write('\n') sys.stdout.flush() pass_skips = os.environ.get('TESTCOMMON_PASS_SKIPS') if pass_skips in [None, 0, '0']: - # skip=1 means skip this function when showing where this - # result came from. They only care about the line where the - # script called test.skip_test(), not the line number where - # we call test.no_result(). - self.no_result(skip=1) + if from_fw: + self.no_result(skip=2) + else: + self.no_result(skip=1) else: # We're under the development directory for this change, # so this is an Aegis invocation; pass the test (exit 0). diff -Nru scons-4.0.1+dfsg/testing/framework/TestCommonTests.py scons-4.4.0+dfsg/testing/framework/TestCommonTests.py --- scons-4.0.1+dfsg/testing/framework/TestCommonTests.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestCommonTests.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,32 +1,30 @@ #!/usr/bin/env python """ -TestCommonTests.py: Unit tests for the TestCommon.py module. - -Copyright 2000-2010 Steven Knight -This module is free software, and you may redistribute it and/or modify -it under the same terms as Python itself, so long as this copyright message -and disclaimer are retained in their original form. - -IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, -SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF -THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, -AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, -SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +Unit tests for the TestCommon.py module. """ +# Copyright 2000-2010 Steven Knight +# This module is free software, and you may redistribute it and/or modify +# it under the same terms as Python itself, so long as this copyright message +# and disclaimer are retained in their original form. +# +# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. +# +# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + __author__ = "Steven Knight " __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 @@ -1842,7 +1840,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) tc.run(arguments = "arg1 arg2 arg3", @@ -1870,7 +1868,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(fail_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run() """) @@ -1899,7 +1897,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(stderr_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run() """) @@ -1931,8 +1929,8 @@ def raise_exception(*args, **kw): raise TypeError("forced TypeError") TestCmd.TestCmd.start = raise_exception - tc = TestCommon(program='%(pass_script)s', - interpreter='%(python)s', + tc = TestCommon(program=r'%(pass_script)s', + interpreter=r'%(python)s', workdir='') tc.run() """) @@ -1945,7 +1943,7 @@ expect_stderr = lstrip("""\ Exception trying to execute: \\[%s, '[^']*pass'\\] - Traceback \\((innermost|most recent call) last\\): + Traceback \\(most recent call last\\): File "", line \\d+, in (\\?|) File "[^"]+TestCommon.py", line \\d+, in run TestCmd.run\\(self, \\*\\*kw\\) @@ -1968,7 +1966,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(stderr_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(stderr = None) """) @@ -1982,7 +1980,7 @@ def my_match_exact(actual, expect): return actual == expect from TestCommon import TestCommon, match_re_dotall tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_re_dotall) tc.run(arguments = "arg1 arg2 arg3", @@ -1999,7 +1997,7 @@ def my_match_exact(actual, expect): return actual == expect from TestCommon import TestCommon, match_re_dotall tc = TestCommon(program=r'%(stderr_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_re_dotall) tc.run(arguments = "arg1 arg2 arg3", @@ -2015,7 +2013,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(fail_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(status = 1) """) @@ -2028,7 +2026,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) tc.run(stdout = r"%(pass_script)s: STDOUT: []" + "\\n") @@ -2042,7 +2040,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(stderr_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) tc.run(stderr = r"%(stderr_script)s: STDERR: []" + "\\n") @@ -2056,7 +2054,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(status = 1) """) @@ -2086,7 +2084,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(fail_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(status = 2) """) @@ -2116,7 +2114,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(stdout = "Not found\\n") """) @@ -2148,7 +2146,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(stderr_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run(stderr = "Not found\\n") """) @@ -2182,7 +2180,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) tc.run(options = "opt1 opt2 opt3", @@ -2197,7 +2195,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) tc.run(options = "opt1 opt2 opt3", @@ -2219,7 +2217,7 @@ script = lstrip("""\ from TestCommon import TestCommon tc = TestCommon(program=r'%(signal_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='') tc.run() """) @@ -2251,7 +2249,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(stdin_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir='', match=match_exact) expect_stdout = r"%(stdin_script)s: STDOUT: 'input'" + "\\n" @@ -2279,7 +2277,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) p = tc.start(options = "opt1 opt2 opt3") @@ -2295,7 +2293,7 @@ script = lstrip("""\ from TestCommon import TestCommon, match_exact tc = TestCommon(program=r'%(pass_script)s', - interpreter='%(python)s', + interpreter=r'%(python)s', workdir="", match=match_exact) p = tc.start(options = "opt1 opt2 opt3", @@ -2431,8 +2429,10 @@ ] suite = unittest.TestSuite() for tclass in tclasses: - names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests([ tclass(n) for n in names ]) + loader = unittest.TestLoader() + loader.testMethodPrefix = 'test_' + names = loader.getTestCaseNames(tclass) + suite.addTests([tclass(n) for n in names]) if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1) diff -Nru scons-4.0.1+dfsg/testing/framework/TestRuntest.py scons-4.4.0+dfsg/testing/framework/TestRuntest.py --- scons-4.0.1+dfsg/testing/framework/TestRuntest.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestRuntest.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ +# 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. + """ -TestRuntest.py: a testing framework for the runtest.py command used to -invoke SCons tests. +A testing framework for the runtest.py command used to invoke SCons tests. A TestRuntest environment object is created via the usual invocation: @@ -12,10 +34,6 @@ attributes defined in this subclass. """ -# __COPYRIGHT__ - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import os.path import re @@ -25,10 +43,13 @@ from TestCommon import * from TestCommon import __all__ -__all__.extend([ 'TestRuntest', - 'pythonstring', - 'pythonflags', - ]) +__all__.extend( + [ + 'TestRuntest', + 'pythonstring', + 'pythonflags', + ] +) if re.search(r'\s', python): pythonstring = _python_ @@ -36,8 +57,6 @@ pythonstring = python pythonstring = pythonstring.replace('\\', '\\\\') pythonflags = '' -if sys.version_info[0] < 3: - pythonflags = ' -tt' failing_test_template = """\ import sys @@ -127,10 +146,10 @@ del kw['things_to_copy'] orig_cwd = os.getcwd() - TestCommon.__init__(self, **kw) + super().__init__(**kw) dirs = [os.environ.get('SCONS_RUNTEST_DIR', orig_cwd)] - + for thing in things_to_copy: for dir in dirs: t = os.path.join(dir, thing) diff -Nru scons-4.0.1+dfsg/testing/framework/TestSConsign.py scons-4.4.0+dfsg/testing/framework/TestSConsign.py --- scons-4.0.1+dfsg/testing/framework/TestSConsign.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestSConsign.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,10 +1,28 @@ -# __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 +# "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__" - -__doc__ = """ -TestSConsign.py: a testing framework for the "sconsign" script -tool. +""" +A testing framework for the "sconsign" script tool. A TestSConsign environment object is created via the usual invocation: @@ -19,7 +37,6 @@ import os import os.path -import sys from TestSCons import * from TestSCons import __all__ @@ -47,7 +64,7 @@ os.chdir(script_dir) self.script_dir = os.getcwd() - TestSCons.__init__(self, *args, **kw) + super().__init__(*args, **kw) self.my_kw = { 'interpreter' : python, # imported from TestSCons diff -Nru scons-4.0.1+dfsg/testing/framework/TestSConsMSVS.py scons-4.4.0+dfsg/testing/framework/TestSConsMSVS.py --- scons-4.0.1+dfsg/testing/framework/TestSConsMSVS.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestSConsMSVS.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ +# 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. + """ -TestSConsMSVS.py: a testing framework for the SCons software construction -tool. +A testing framework for the SCons software construction tool. A TestSConsMSVS environment object is created via the usual invocation: @@ -13,10 +35,6 @@ in this subclass. """ -# __COPYRIGHT__ - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import sys import platform @@ -28,7 +46,6 @@ from TestSCons import __all__ - expected_dspfile_6_0 = '''\ # Microsoft Developer Studio Project File - Name="Test" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 @@ -638,7 +655,7 @@ """ Returns all MSVC versions that we want to test project file creation for. """ - return ['8.0', '9.0', '10.0', '11.0', '12.0', '14.0', '14.1', '14.2'] + return ['8.0', '9.0', '10.0', '11.0', '12.0', '14.0', '14.1', '14.2', '14.3'] class TestSConsMSVS(TestSCons): @@ -746,8 +763,7 @@ return result def get_vs_host_arch(self): - """ Get an MSVS, SDK , and/or MSVS acceptable platform arch - """ + """ Returns an MSVS, SDK , and/or MSVS acceptable platform arch. """ # Dict to 'canonalize' the arch _ARCH_TO_CANONICAL = { @@ -761,11 +777,6 @@ } host_platform = platform.machine() - # TODO(2.5): the native Python platform.machine() function returns - # '' on all Python versions before 2.6, after which it also uses - # PROCESSOR_ARCHITECTURE. - if not host_platform: - host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') try: host = _ARCH_TO_CANONICAL[host_platform] @@ -862,6 +873,9 @@ elif vc_version == '14.2': # ToolsVersion='16' return '16.0' + elif vc_version == '14.3': + # ToolsVersion='17' + return '17.0' else: raise SCons.Errors.UserError('Received unexpected VC version %s' % vc_version) diff -Nru scons-4.0.1+dfsg/testing/framework/TestSCons.py scons-4.4.0+dfsg/testing/framework/TestSCons.py --- scons-4.0.1+dfsg/testing/framework/TestSCons.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestSCons.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,6 +1,28 @@ +# 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. + """ -TestSCons.py: a testing framework for the SCons software construction -tool. +A testing framework for the SCons software construction tool. A TestSCons environment object is created via the usual invocation: @@ -12,20 +34,18 @@ attributes defined in this subclass. """ -# __COPYRIGHT__ - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import re import shutil import sys import time -import subprocess +import subprocess as sp +import zipfile from collections import namedtuple from TestCommon import * from TestCommon import __all__ +from SCons.Util import get_hash_format, get_current_hash_algorithm_used from TestCmd import Popen from TestCmd import PIPE @@ -35,10 +55,12 @@ # here provides some independent verification that what we packaged # conforms to what we expect. -default_version = '4.1.0.devyyyymmdd' +default_version = '4.3.1ayyyymmdd' -python_version_unsupported = (3, 4, 0) -python_version_deprecated = (3, 4, 0) +# TODO: these need to be hand-edited when there are changes +python_version_unsupported = (3, 6, 0) +python_version_deprecated = (3, 6, 0) +python_version_supported_str = "3.6.0" # str of lowest non-deprecated version # In the checked-in source, the value of SConsVersion in the following # line must remain "__ VERSION __" (without the spaces) so the built @@ -157,11 +179,13 @@ if deprecated_python_version(): msg = r""" -scons: warning: Support for pre-2.7.0 Python version (%s) is deprecated. +scons: warning: Support for pre-%s Python version (%s) is deprecated. If this will cause hardship, contact scons-dev@scons.org """ - - deprecated_python_expr = re_escape(msg % python_version_string()) + file_expr + deprecated_python_expr = ( + re_escape(msg % (python_version_supported_str, python_version_string())) + + file_expr + ) del msg else: deprecated_python_expr = "" @@ -188,7 +212,7 @@ # support the --warn=no-visual-c-missing warning.) visual_c = os.environ.get('TESTSCONS_SCONSFLAGS', '--warn=no-visual-c-missing') - if visual_c: + if visual_c and visual_c not in sconsflags: sconsflags.append(visual_c) os.environ['SCONSFLAGS'] = ' '.join(sconsflags) return save_sconsflags @@ -283,8 +307,6 @@ kw['program'] = os.path.join(self.orig_cwd, kw['program']) if 'interpreter' not in kw and not os.environ.get('SCONS_EXEC'): kw['interpreter'] = [python, ] - if sys.version_info[0] < 3: - kw['interpreter'].append('-tt') if 'match' not in kw: kw['match'] = match_exact if 'workdir' not in kw: @@ -299,7 +321,7 @@ if kw.get('ignore_python_version', -1) != -1: del kw['ignore_python_version'] - TestCommon.__init__(self, **kw) + super().__init__(**kw) if not self.external: import SCons.Node.FS @@ -400,20 +422,35 @@ return None - def wrap_stdout(self, build_str="", read_str="", error=0, cleaning=0): - """Wraps standard output string(s) in the normal - "Reading ... done" and "Building ... done" strings + def wrap_stdout(self, build_str="", read_str="", error=0, cleaning=0) -> str: + """Wraps "expect" strings in SCons boilerplate. + + Given strings of expected output specific to a test, + returns a string which includes the SCons wrapping such as + "Reading ... done", etc.: that is, adds the text that would + be left out by running SCons in quiet mode; + Makes a complete message to match against. + + Args: + read_str: the message for the execution part of the output. + If non-empty, needs to be newline-terminated. + read_str: the message for the reading-sconscript part of + the output. If non-empty, needs to be newline-terminated. + error: if true, expect a fail message rather than a done message. + cleaning (int): index into type messages, if 0 selects + build messages, if 1 selects clean messages. """ cap, lc = [('Build', 'build'), ('Clean', 'clean')][cleaning] if error: - term = "scons: %sing terminated because of errors.\n" % lc + term = f"scons: {lc}ing terminated because of errors.\n" else: - term = "scons: done %sing targets.\n" % lc + term = f"scons: done {lc}ing targets.\n" + return "scons: Reading SConscript files ...\n" + \ read_str + \ "scons: done reading SConscript files.\n" + \ - "scons: %sing targets ...\n" % cap + \ + f"scons: {cap}ing targets ...\n" + \ build_str + \ term @@ -697,29 +734,53 @@ result.extend(sorted(glob.glob(p))) return result + def get_sconsignname(self): + """Get the scons database name used, and return both the prefix and full filename. + if the user left the options defaulted AND the default algorithm set by + SCons is md5, then set the database name to be the special default name + + otherwise, if it defaults to something like 'sha1' or the user explicitly + set 'md5' as the hash format, set the database name to .sconsign_ + eg .sconsign_sha1, etc. + + Returns: + a pair containing: the current dbname, the dbname.dblite filename + """ + hash_format = get_hash_format() + current_hash_algorithm = get_current_hash_algorithm_used() + if hash_format is None and current_hash_algorithm == 'md5': + return ".sconsign" + else: + database_prefix=".sconsign_%s" % current_hash_algorithm + return database_prefix + + def unlink_sconsignfile(self, name='.sconsign.dblite'): - """ - Delete sconsign file. - Note on python it seems to append .p3 to the file name so we take care of that - Parameters - ---------- - name - expected name of sconsign file - - Returns - ------- - None + """Delete the sconsign file. + + Note on python it seems to append .p3 to the file name so we take + care of that. + + TODO the above seems to not be an issue any more. + + Args: + name: expected name of sconsign file """ if sys.version_info[0] == 3: name += '.p3' self.unlink(name) def java_ENV(self, version=None): - """ + """ Initialize JAVA SDK environment. + Initialize with a default external environment that uses a local Java SDK in preference to whatever's found in the default PATH. - :param version: if set, match only that version - :return: the new env. + Args: + version: if set, match only that version + + Returns: + the new env. """ if not self.external: try: @@ -764,11 +825,13 @@ return None def java_where_includes(self, version=None): - """ - Find include path needed for compiling java jni code. + """ Find include path needed for compiling java jni code. - :param version: if set, match only that version - :return: path to java headers + Args: + version: if set, match only that version + + Returns: + path to java headers or None """ import sys @@ -801,66 +864,88 @@ result.append(os.path.join(d, 'linux')) return result - def java_where_java_home(self, version=None): - """ - Find path to what would be JAVA_HOME. + def java_where_java_home(self, version=None) -> str: + """ Find path to what would be JAVA_HOME. SCons does not read JAVA_HOME from the environment, so deduce it. - :param version: if set, match only that version - :return: path where JDK components live + Args: + version: if set, match only that version + + Returns: + path where JDK components live + Bails out of the entire test (skip) if not found. """ if sys.platform[:6] == 'darwin': - # osx 10.11, 10.12 + # osx 10.11+ home_tool = '/usr/libexec/java_home' - java_home = False + java_home = '' if os.path.exists(home_tool): - java_home = subprocess.check_output(home_tool).strip() - java_home = java_home.decode() + cp = sp.run(home_tool, stdout=sp.PIPE, stderr=sp.STDOUT) + if cp.returncode == 0: + java_home = cp.stdout.decode().strip() if version is None: if java_home: return java_home - else: - homes = ['/System/Library/Frameworks/JavaVM.framework/Home', - # osx 10.10 - '/System/Library/Frameworks/JavaVM.framework/Versions/Current/Home'] - for home in homes: - if os.path.exists(home): - return home - + for home in [ + '/System/Library/Frameworks/JavaVM.framework/Home', + # osx 10.10 + '/System/Library/Frameworks/JavaVM.framework/Versions/Current/Home' + ]: + if os.path.exists(home): + return home else: if java_home.find('jdk%s' % version) != -1: return java_home - else: - home = '/System/Library/Frameworks/JavaVM.framework/Versions/%s/Home' % version - if not os.path.exists(home): - # This works on OSX 10.10 - home = '/System/Library/Frameworks/JavaVM.framework/Versions/Current/' + for home in [ + '/System/Library/Frameworks/JavaVM.framework/Versions/%s/Home' % version, + # osx 10.10 + '/System/Library/Frameworks/JavaVM.framework/Versions/Current/' + ]: + if os.path.exists(home): + return home + # if we fell through, make sure flagged as not found + home = '' else: jar = self.java_where_jar(version) home = os.path.normpath('%s/..' % jar) - if os.path.isdir(home): + + if home and os.path.isdir(home): return home - print("Could not determine JAVA_HOME: %s is not a directory" % home) - self.fail_test() - def java_mac_check(self, where_java_bin, java_bin_name): - # on Mac there is a place holder java installed to start the java install process - # so we need to check the output in this case, more info here: - # http://anas.pk/2015/09/02/solution-no-java-runtime-present-mac-yosemite/ - sp = subprocess.Popen([where_java_bin, "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = sp.communicate() - sp.wait() - if "No Java runtime" in str(stderr): - self.skip_test("Could not find Java " + java_bin_name + ", skipping test(s).\n") + self.skip_test( + "Could not run Java: unable to detect valid JAVA_HOME, skipping test.\n", + from_fw=True, + ) + + def java_mac_check(self, where_java_bin, java_bin_name) -> None: + """Extra check for Java on MacOS. + + MacOS has a place holder java/javac, which fails with a detectable + error if Java is not actually installed, and works normally if it is. + Note msg has changed over time. + + Bails out of the entire test (skip) if not found. + """ + cp = sp.run([where_java_bin, "-version"], stdout=sp.PIPE, stderr=sp.STDOUT) + if ( + b"No Java runtime" in cp.stdout + or b"Unable to locate a Java Runtime" in cp.stdout + ): + self.skip_test( + "Could not find Java " + java_bin_name + ", skipping test.\n", + from_fw=True, + ) - def java_where_jar(self, version=None): - """ - Find java archiver jar. + def java_where_jar(self, version=None) -> str: + """ Find java archiver jar. + + Args: + version: if set, match only that version - :param version: if set, match only that version - :return: path to jar + Returns: + path to jar """ ENV = self.java_ENV(version) if self.detect_tool('jar', ENV=ENV): @@ -868,35 +953,39 @@ else: where_jar = self.where_is('jar', ENV['PATH']) if not where_jar: - self.skip_test("Could not find Java jar, skipping test(s).\n") + self.skip_test("Could not find Java jar, skipping test(s).\n", from_fw=True) elif sys.platform == "darwin": self.java_mac_check(where_jar, 'jar') return where_jar - def java_where_java(self, version=None): - """ - Find java executable. + def java_where_java(self, version=None) -> str: + """ Find java executable. + + Args: + version: if set, match only that version - :param version: if set, match only that version - :return: path to the java rutime + Returns: + path to the java rutime """ ENV = self.java_ENV(version) where_java = self.where_is('java', ENV['PATH']) if not where_java: - self.skip_test("Could not find Java java, skipping test(s).\n") + self.skip_test("Could not find Java java, skipping test(s).\n", from_fw=True) elif sys.platform == "darwin": self.java_mac_check(where_java, 'java') return where_java - def java_where_javac(self, version=None): - """ - Find java compiler. + def java_where_javac(self, version=None) -> str: + """ Find java compiler. + + Args: + version: if set, match only that version - :param version: if set, match only that version - :return: path to javac + Returns: + path to javac """ ENV = self.java_ENV(version) if self.detect_tool('javac'): @@ -904,7 +993,7 @@ else: where_javac = self.where_is('javac', ENV['PATH']) if not where_javac: - self.skip_test("Could not find Java javac, skipping test(s).\n") + self.skip_test("Could not find Java javac, skipping test(s).\n", from_fw=True) elif sys.platform == "darwin": self.java_mac_check(where_javac, 'javac') @@ -917,7 +1006,7 @@ verf = 'javac %s' % version if self.stderr().find(verf) == -1 and self.stdout().find(verf) == -1: fmt = "Could not find javac for Java version %s, skipping test(s).\n" - self.skip_test(fmt % version) + self.skip_test(fmt % version, from_fw=True) else: version_re = r'javac (\d*\.*\d)' m = re.search(version_re, self.stderr()) @@ -935,16 +1024,18 @@ self.javac_is_gcj = False return where_javac, version - def java_where_javah(self, version=None): - """ - Find java header generation tool. + def java_where_javah(self, version=None) -> str: + """ Find java header generation tool. TODO issue #3347 since JDK10, there is no separate javah command, 'javac -h' is used. We should not return a javah from a different installed JDK - how to detect and what to return in this case? - :param version: if set, match only that version - :return: path to javah + Args: + version: if set, match only that version + + Returns: + path to javah """ ENV = self.java_ENV(version) if self.detect_tool('javah'): @@ -952,15 +1043,17 @@ else: where_javah = self.where_is('javah', ENV['PATH']) if not where_javah: - self.skip_test("Could not find Java javah, skipping test(s).\n") + self.skip_test("Could not find Java javah, skipping test(s).\n", from_fw=True) return where_javah - def java_where_rmic(self, version=None): - """ - Find java rmic tool. + def java_where_rmic(self, version=None) -> str: + """ Find java rmic tool. + + Args: + version: if set, match only that version - :param version: if set, match only that version - :return: path to rmic + Returns: + path to rmic """ ENV = self.java_ENV(version) if self.detect_tool('rmic'): @@ -968,7 +1061,7 @@ else: where_rmic = self.where_is('rmic', ENV['PATH']) if not where_rmic: - self.skip_test("Could not find Java rmic, skipping non-simulated test(s).\n") + self.skip_test("Could not find Java rmic, skipping non-simulated test(s).\n", from_fw=True) return where_rmic def java_get_class_files(self, dir): @@ -1065,8 +1158,8 @@ """) self.write([dir, 'lib', 'SConstruct'], r""" -env = Environment() import sys +env = Environment() if sys.platform == 'win32': env.StaticLibrary('myqt', 'my_qobject.cpp') else: @@ -1088,20 +1181,20 @@ if isinstance(place, list): place = test.workpath(*place) self.write(place, """\ -if ARGUMENTS.get('noqtdir', 0): QTDIR=None -else: QTDIR=r'%s' -env = Environment(QTDIR = QTDIR, - QT_LIB = r'%s', - QT_MOC = r'%s', - QT_UIC = r'%s', - tools=['default','qt']) +if ARGUMENTS.get('noqtdir', 0): + QTDIR = None +else: + QTDIR = r'%s' +env = Environment( + QTDIR=QTDIR, QT_LIB=r'%s', QT_MOC=r'%s', QT_UIC=r'%s', tools=['default', 'qt'] +) dup = 1 if ARGUMENTS.get('variant_dir', 0): if ARGUMENTS.get('chdir', 0): SConscriptChdir(1) else: SConscriptChdir(0) - dup=int(ARGUMENTS.get('dup', 1)) + dup = int(ARGUMENTS.get('dup', 1)) if dup == 0: builddir = 'build_dup0' env['QT_DEBUG'] = 1 @@ -1135,26 +1228,27 @@ return 'COVERAGE_PROCESS_START' in os.environ or 'COVERAGE_FILE' in os.environ def skip_if_not_msvc(self, check_platform=True): - """ Check whether we are on a Windows platform and skip the - test if not. This check can be omitted by setting - check_platform to False. - Then, for a win32 platform, additionally check - whether we have a MSVC toolchain installed - in the system, and skip the test if none can be - found (=MinGW is the only compiler available). + """ Skip test if MSVC is not available. + + Check whether we are on a Windows platform and skip the test if + not. This check can be omitted by setting check_platform to False. + + Then, for a win32 platform, additionally check whether we have + an MSVC toolchain installed in the system, and skip the test if + none can be found (e.g. MinGW is the only compiler available). """ if check_platform: if sys.platform != 'win32': msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform - self.skip_test(msg) + self.skip_test(msg, from_fw=True) return try: import SCons.Tool.MSCommon as msc if not msc.msvc_exists(): msg = "No MSVC toolchain found...skipping test\n" - self.skip_test(msg) - except: + self.skip_test(msg, from_fw=True) + except Exception: pass def checkConfigureLogAndStdout(self, checks, @@ -1162,29 +1256,24 @@ sconf_dir='.sconf_temp', sconstruct="SConstruct", doCheckLog=True, doCheckStdout=True): - """ + """ Verify expected output from Configure. + Used to verify the expected output from using Configure() via the contents of one or both of stdout or config.log file. - The checks, results, cached parameters all are zipped together - for use in comparing results. + If the algorithm does not succeed, the test is marked a fail + and this function does not return. TODO: Perhaps a better API makes sense? - Parameters - ---------- - checks : list of ConfigCheckInfo tuples which specify - logfile : Name of the config log - sconf_dir : Name of the sconf dir - sconstruct : SConstruct file name - doCheckLog : check specified log file, defaults to true - doCheckStdout : Check stdout, defaults to true - - Returns - ------- - + Args: + checks: list of ConfigCheckInfo tuples which specify + logfile: Name of the config log + sconf_dir: Name of the sconf dir + sconstruct: SConstruct file name + doCheckLog: check specified log file, defaults to true + doCheckStdout: Check stdout, defaults to true """ - try: ls = '\n' nols = '([^\n])' @@ -1299,35 +1388,25 @@ def checkLogAndStdout(self, checks, results, cached, logfile, sconf_dir, sconstruct, doCheckLog=True, doCheckStdout=True): - """ + """ Verify expected output from Configure. + Used to verify the expected output from using Configure() via the contents of one or both of stdout or config.log file. The checks, results, cached parameters all are zipped together - for use in comparing results. + for use in comparing results. If the algorithm does not + succeed, the test is marked a fail and this function does not return. TODO: Perhaps a better API makes sense? - Parameters - ---------- - checks : The Configure checks being run - - results : The expected results for each check - - cached : If the corresponding check is expected to be cached - - logfile : Name of the config log - - sconf_dir : Name of the sconf dir - - sconstruct : SConstruct file name - - doCheckLog : check specified log file, defaults to true - - doCheckStdout : Check stdout, defaults to true - - Returns - ------- - + Args: + checks: The Configure checks being run + results: The expected results for each check + cached: If the corresponding check is expected to be cached + logfile: Name of the config log + sconf_dir: Name of the sconf dir + sconstruct: SConstruct file name + doCheckLog: check specified log file, defaults to true + doCheckStdout: Check stdout, defaults to true """ try: @@ -1371,10 +1450,10 @@ for ext, flag in bld_desc: # each file in TryBuild if ext in ['.c', '.cpp']: conf_filename = re.escape(os.path.join(sconf_dir, "conftest")) +\ - r'_[a-z0-9]{32}_\d+%s' % re.escape(ext) + r'_[a-z0-9]{32,64}_\d+%s' % re.escape(ext) elif ext == '': conf_filename = re.escape(os.path.join(sconf_dir, "conftest")) +\ - r'_[a-z0-9]{32}(_\d+_[a-z0-9]{32})?' + r'_[a-z0-9]{32,64}(_\d+_[a-z0-9]{32,64})?' else: # We allow the second hash group to be optional because @@ -1386,7 +1465,7 @@ # TODO: perhaps revisit and/or fix file naming for intermediate files in # Configure context logic conf_filename = re.escape(os.path.join(sconf_dir, "conftest")) +\ - r'_[a-z0-9]{32}_\d+(_[a-z0-9]{32})?%s' % re.escape(ext) + r'_[a-z0-9]{32,64}_\d+(_[a-z0-9]{32,64})?%s' % re.escape(ext) if flag == self.NCR: # NCR = Non Cached Rebuild @@ -1460,16 +1539,18 @@ print("-----------------------------------------------------") self.fail_test() - def get_python_version(self): - """ - Returns the Python version (just so everyone doesn't have to - hand-code slicing the right number of characters). + def get_python_version(self) -> str: + """ Returns the Python version. + + Convenience function so everyone doesn't have to + hand-code slicing the right number of characters """ # see also sys.prefix documentation return python_minor_version_string() def get_platform_python_info(self, python_h_required=False): - """ + """Return information about Python. + Returns a path to a Python executable suitable for testing on this platform and its associated include path, library path and library name. @@ -1477,12 +1558,12 @@ If the Python executable or Python header (if required) is not found, the test is skipped. - Returns a tuple: - (path to python, include path, library path, library name) + Returns: + tuple: path to python, include path, library path, library name """ python = os.environ.get('python_executable', self.where_is('python')) if not python: - self.skip_test('Can not find installed "python", skipping test.\n') + self.skip_test('Can not find installed "python", skipping test.\n', from_fw=True) # construct a program to run in the intended environment # in order to fetch the characteristics of that Python. @@ -1491,12 +1572,9 @@ 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): @@ -1542,7 +1620,7 @@ """) incpath, libpath, libname, python_h = self.stdout().strip().split('\n') if python_h == "False" and python_h_required: - self.skip_test('Can not find required "Python.h", skipping test.\n') + self.skip_test('Can not find required "Python.h", skipping test.\n', from_fw=True) return (python, incpath, libpath, libname) @@ -1589,7 +1667,8 @@ waited = waited + 1.0 def get_alt_cpp_suffix(self): - """ + """Return alternate C++ file suffix. + Many CXX tests have this same logic. They all needed to determine if the current os supports files with .C and .c as different files or not @@ -1601,12 +1680,27 @@ alt_cpp_suffix = '.C' return alt_cpp_suffix - def platform_has_symlink(self): + def platform_has_symlink(self) -> bool: + """Retun an indication of whether symlink tests should be run. + + Despite the name, we really mean "are they reliably usable" + rather than "do they exist" - basically the Windows case. + """ if not hasattr(os, 'symlink') or sys.platform == 'win32': return False else: return True + def zipfile_contains(self, zipfilename, names): + """Returns True if zipfilename contains all the names, False otherwise.""" + with zipfile.ZipFile(zipfilename, 'r') as zf: + return all(elem in zf.namelist() for elem in names) + + def zipfile_files(self, fname): + """Returns all the filenames in zip file fname.""" + with zipfile.ZipFile(fname, 'r') as zf: + return zf.namelist() + class Stat: def __init__(self, name, units, expression, convert=None): @@ -1681,7 +1775,7 @@ if 'verbose' not in kw and not self.calibrate: kw['verbose'] = True - TestSCons.__init__(self, *args, **kw) + super().__init__(*args, **kw) # TODO(sgk): better way to get the script dir than sys.argv[0] self.test_dir = os.path.dirname(sys.argv[0]) @@ -1826,7 +1920,11 @@ # 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 @@ -1856,11 +1954,11 @@ --debug=memory and --debug=time options to have SCons report its own memory and timing statistics. """ - self.startTime = time.time() + self.startTime = time.perf_counter() try: result = TestSCons.run(self, *args, **kw) finally: - self.endTime = time.time() + self.endTime = time.perf_counter() return result def copy_timing_configuration(self, source_dir, dest_dir): @@ -1888,6 +1986,27 @@ 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 -Nru scons-4.0.1+dfsg/testing/framework/TestSCons_time.py scons-4.4.0+dfsg/testing/framework/TestSCons_time.py --- scons-4.0.1+dfsg/testing/framework/TestSCons_time.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestSCons_time.py 2022-07-30 21:48:28.000000000 +0000 @@ -1,5 +1,28 @@ +# 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. + """ -TestSCons_time.py: a testing framework for the scons-test.py script +A testing framework for the scons-time.py script A TestSCons_time environment object is created via the usual invocation: @@ -11,10 +34,6 @@ attributes defined in this subclass. """ -# __COPYRIGHT__ - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import os import os.path import sys @@ -180,7 +199,7 @@ if 'workdir' not in kw: kw['workdir'] = '' - TestCommon.__init__(self, **kw) + super().__init__(**kw) def archive_split(self, path): if path[-7:] == '.tar.gz': @@ -258,13 +277,9 @@ import shutil try: import tarfile - except ImportError: - - self.skip_test('no tarfile module\n') - + self.skip_test('no tarfile module\n', from_framework=True) else: - base, suffix = self.archive_split(archive) mode = { diff -Nru scons-4.0.1+dfsg/testing/framework/TestUnit/taprunner.py scons-4.4.0+dfsg/testing/framework/TestUnit/taprunner.py --- scons-4.0.1+dfsg/testing/framework/TestUnit/taprunner.py 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/testing/framework/TestUnit/taprunner.py 2022-07-30 21:48:28.000000000 +0000 @@ -43,29 +43,29 @@ self.stream.flush() def addSuccess(self, test): - super(TextTestResult, self).addSuccess(test) + super().addSuccess(test) self._process(test, "ok") def addFailure(self, test, err): - super(TextTestResult, self).addFailure(test, err) + super().addFailure(test, err) self._process(test, "not ok", "FAIL") # [ ] add structured data about assertion def addError(self, test, err): - super(TextTestResult, self).addError(test, err) + super().addError(test, err) self._process(test, "not ok", "ERROR") # [ ] add structured data about exception def addSkip(self, test, reason): - super(TextTestResult, self).addSkip(test, reason) + super().addSkip(test, reason) self._process(test, "ok", directive=(" # SKIP %s" % reason)) def addExpectedFailure(self, test, err): - super(TextTestResult, self).addExpectedFailure(test, err) + super().addExpectedFailure(test, err) self._process(test, "not ok", directive=" # TODO") def addUnexpectedSuccess(self, test): - super(TextTestResult, self).addUnexpectedSuccess(test) + super().addUnexpectedSuccess(test) self._process(test, "not ok", "FAIL (unexpected success)") """ @@ -90,7 +90,7 @@ for case in test: case.suite = test - return super(TAPTestRunner, self).run(test) + return super().run(test) if __name__ == "__main__": diff -Nru scons-4.0.1+dfsg/.travis/install.sh scons-4.4.0+dfsg/.travis/install.sh --- scons-4.0.1+dfsg/.travis/install.sh 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.travis/install.sh 2022-07-30 21:48:28.000000000 +0000 @@ -45,16 +45,31 @@ sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring sudo apt-get update && sudo apt-get install dmd-compiler dub + + if [[ "$BUILD_LXML_FROM_GIT" == "1" ]]; then + pip uninstall -y lxml + pip cache purge + + # for ubuntu 20.04 needed this as well + sudo apt install libxslt1-dev + + # then use git versions of cython and lxml (lxml's cython build uses xslt1-config which is why the above was needed) + pip install git+https://github.com/cython/cython.git@0.29.x + pip install git+https://github.com/lxml/lxml.git + fi + # sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list # wget -qO - https://dlang.org/d-keyring.gpg | sudo apt-key add - # sudo apt-get update && sudo apt-get -y --allow-unauthenticated install dmd-bin # dependencies for ldc tests - export SCONS_LDC_VERSION=1.21.0 - wget https://github.com/ldc-developers/ldc/releases/download/v${SCONS_LDC_VERSION}/ldc2-${SCONS_LDC_VERSION}-linux-x86_64.tar.xz -# wget https://github.com/ldc-developers/ldc/releases/download/v1.15.0/ldc2-1.15.0-linux-x86_64.tar.xz - tar xf ldc2-${SCONS_LDC_VERSION}-linux-x86_64.tar.xz - sudo cp -rf ldc2-${SCONS_LDC_VERSION}-linux-x86_64/* / + # this install method basically worked until 20.04, though a little messy. + # rather than further tweaking, replace it with the recommended snap install + #export SCONS_LDC_VERSION=1.21.0 + #wget https://github.com/ldc-developers/ldc/releases/download/v${SCONS_LDC_VERSION}/ldc2-${SCONS_LDC_VERSION}-linux-x86_64.tar.xz + #tar xf ldc2-${SCONS_LDC_VERSION}-linux-x86_64.tar.xz + #sudo cp -rf ldc2-${SCONS_LDC_VERSION}-linux-x86_64/* / + sudo snap install ldc2 --classic # Failing.. ? # ls -l /usr/lib*/*python*{so,a}* diff -Nru scons-4.0.1+dfsg/.travis/verify_packages.sh scons-4.4.0+dfsg/.travis/verify_packages.sh --- scons-4.0.1+dfsg/.travis/verify_packages.sh 1970-01-01 00:00:00.000000000 +0000 +++ scons-4.4.0+dfsg/.travis/verify_packages.sh 2022-07-30 21:48:28.000000000 +0000 @@ -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 -Nru scons-4.0.1+dfsg/.travis.yml scons-4.4.0+dfsg/.travis.yml --- scons-4.0.1+dfsg/.travis.yml 2020-07-17 03:25:10.000000000 +0000 +++ scons-4.4.0+dfsg/.travis.yml 2022-07-30 21:48:28.000000000 +0000 @@ -1,7 +1,7 @@ dist: xenial language: python -# Used: travis encrypt "chat.freenode.net#scons" --add notifications.irc +# Used: travis encrypt "irc.libera.chat#scons" --add notifications.irc notifications: irc: secure: TTb+41Bj1qIUc6vj+kDqBME8H3lqXdAe1RWAjjz5hL7bzFah6qCBHNJn4DwzqYs6+Pwuwp+6wFy8hgmQttJnXve4h6GtjtvlWprDqxaC7RkFqMWFDBzDalgbB54Bi4+TTZmSJ1K/duI3LrDaN873nyn+2GBnj+3TiNtgURp1fsJMpPxXJzAsoC8UthEsbx0Zkoal/WF+IfsT2q1yQRmAwB9r/drbahx/FfL16r1QjDbI9y1fKvN5J3PirLUvxtHfuH1r8zq1vlLew2fvldgVRtFv7+Lsk2waG/eiRpMf94V5JWP1rNreV/i4AUbZaTLb3bkrhtvTjSKhvx69Ydm+ygXdRgWOD/KRgqpLNAfA+t/a2J1R++89svQI4dPBpQjlfua1elcDCFddeIslgnjDUPO23Y0o7tHAy8sWkwhTcZH1Wm42uJP6Z6tHTH6+dMLvvZpkq4RUKUcrXvoUvCsVlWMGjcsBX+AEQSFGDJnLtLehO9x0QbgVga/IRKjgpDWgQDZgro3AkGg/zzVj5uFRUoU+rbmEXq9feh5i3HfExAvA3UoEtnQ6uadDyWqtQcLRFmPSWDU82CO+sanGdFL0jBjigE8ubPObzxEAz3Fg1xk56OYBkAdEd+2KEzeO1nqJmrhsnc3c/3+b1cBvaL5ozW4XB4XcWsOi268SoiBrcBo= @@ -35,32 +35,23 @@ # pypy is not passing atm, but still report build success for now # allow coverage to fail, so we can still do testing for all platforms allow_failures: - - python: pypy3 - + - python: 3.10-dev + include: - &test_job script: python runtest.py -a -t -j 2 || if [[ $? == 2 ]]; then true; else false; fi before_script: skip after_success: skip - python: pypy3 - - - <<: *test_job python: 3.5 - <<: *test_job - python: 3.6 - - - <<: *test_job - python: 3.7 - dist: xenial # required for Python >= 3.7 - - - <<: *test_job - python: 3.8 - dist: bionic # required for Python >= 3.8 + python: 3.9 + dist: focal - <<: *test_job - python: 3.9-dev - dist: bionic # required for Python >= 3.8 + python: 3.10-dev + dist: focal + env: BUILD_LXML_FROM_GIT=1 - &coverage_jobs dist: bionic @@ -77,18 +68,3 @@ - coverage report - coverage xml -i -o coverage_xml.xml - codecov -X gcov --file coverage_xml.xml - - - &scons_build_job - name: SCons Build - python: 3.7 - install: - - sudo apt-get -y install docbook-xml docbook-xsl xsltproc libxml2-dev libxslt-dev fop docbook-xsl-doc-pdf - - sudo apt-get -y --no-install-recommends install texlive texlive-latex3 biber texmaker ghostscript texlive-bibtex-extra texlive-latex-extra texlive-font-utils latexmk - - pip install -r requirements.txt - script: - - python bin/docs-update-generated.py - - python bin/docs-validate.py - - python bin/docs-create-example-outputs.py - - python scripts/scons.py - - ls -l build/dist - - python build/scons-local/scons.py --version