summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2020-01-30 23:03:35 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2020-01-30 23:03:35 (GMT)
commitff18a25e814dac5e9140c625b84d048962226244 (patch)
treedb78d68aa71babf803ad7e6c70ac4f99f3dfcd41
parent0d4c31c7adc62f215e6a73d2efa7c2787bee6c83 (diff)
parent1e71abf4c79e74adff68eea8eb9b40bfbf1260c3 (diff)
downloadSCons-ff18a25e814dac5e9140c625b84d048962226244.zip
SCons-ff18a25e814dac5e9140c625b84d048962226244.tar.gz
SCons-ff18a25e814dac5e9140c625b84d048962226244.tar.bz2
Merge branch 'issue-3469' of github.com:bdbaddog/scons into issue-3469
-rw-r--r--.travis.yml19
-rw-r--r--doc/design/engine.xml14
-rw-r--r--doc/generated/variables.gen11
-rw-r--r--doc/generated/variables.mod4
-rw-r--r--doc/man/scons.xml463
-rw-r--r--doc/scons.mod45
-rw-r--r--doc/user/depends.xml84
-rw-r--r--doc/user/output.xml13
-rwxr-xr-xsrc/CHANGES.txt18
-rw-r--r--src/engine/MANIFEST.in2
-rw-r--r--src/engine/SCons/Builder.py2
-rw-r--r--src/engine/SCons/BuilderTests.py14
-rw-r--r--src/engine/SCons/CacheDir.py6
-rw-r--r--src/engine/SCons/CacheDirTests.py6
-rw-r--r--src/engine/SCons/Environment.py8
-rw-r--r--src/engine/SCons/Environment.xml110
-rw-r--r--src/engine/SCons/EnvironmentTests.py12
-rw-r--r--src/engine/SCons/Node/AliasTests.py2
-rw-r--r--src/engine/SCons/Node/FS.py4
-rw-r--r--src/engine/SCons/Node/FSTests.py20
-rw-r--r--src/engine/SCons/Node/NodeTests.py2
-rw-r--r--src/engine/SCons/Node/Python.py22
-rw-r--r--src/engine/SCons/Node/PythonTests.py34
-rw-r--r--src/engine/SCons/PathListTests.py2
-rw-r--r--src/engine/SCons/Platform/__init__.py2
-rw-r--r--src/engine/SCons/SConf.py6
-rw-r--r--src/engine/SCons/SConsignTests.py2
-rw-r--r--src/engine/SCons/Scanner/Python.py171
-rw-r--r--src/engine/SCons/Scanner/PythonTests.py269
-rw-r--r--src/engine/SCons/Scanner/RCTests.py2
-rw-r--r--src/engine/SCons/Script/Interactive.py2
-rw-r--r--src/engine/SCons/Script/Main.py4
-rw-r--r--src/engine/SCons/Script/Main.xml88
-rw-r--r--src/engine/SCons/Script/SConscript.xml12
-rw-r--r--src/engine/SCons/Subst.py97
-rw-r--r--src/engine/SCons/Subst.xml2
-rw-r--r--src/engine/SCons/Taskmaster.py2
-rw-r--r--src/engine/SCons/TaskmasterTests.py10
-rw-r--r--src/engine/SCons/Tool/DCommon.xml32
-rw-r--r--src/engine/SCons/Tool/MSCommon/common.py4
-rw-r--r--src/engine/SCons/Tool/__init__.py4
-rw-r--r--src/engine/SCons/Tool/c++.xml17
-rw-r--r--src/engine/SCons/Tool/cc.xml22
-rw-r--r--src/engine/SCons/Tool/f03.xml16
-rw-r--r--src/engine/SCons/Tool/f08.xml16
-rw-r--r--src/engine/SCons/Tool/f77.xml16
-rw-r--r--src/engine/SCons/Tool/f90.xml16
-rw-r--r--src/engine/SCons/Tool/f95.xml16
-rw-r--r--src/engine/SCons/Tool/fortran.xml16
-rw-r--r--src/engine/SCons/Tool/install.xml37
-rw-r--r--src/engine/SCons/Tool/intelc.py8
-rw-r--r--src/engine/SCons/Tool/javac.xml12
-rw-r--r--src/engine/SCons/Tool/link.xml24
-rw-r--r--src/engine/SCons/Tool/msvs.py27
-rw-r--r--src/engine/SCons/Tool/msvsTests.py14
-rw-r--r--src/engine/SCons/Tool/packaging.xml66
-rw-r--r--src/engine/SCons/Tool/packaging/__init__.xml56
-rw-r--r--src/engine/SCons/Tool/packaging/ipk.py2
-rw-r--r--src/engine/SCons/Tool/packaging/rpm.py2
-rw-r--r--src/engine/SCons/Tool/python.py49
-rw-r--r--src/engine/SCons/Tool/python.xml36
-rw-r--r--src/engine/SCons/Tool/suncxx.py18
-rw-r--r--src/engine/SCons/Tool/textfile.py12
-rw-r--r--src/engine/SCons/Tool/textfile.xml10
-rw-r--r--src/engine/SCons/Tool/xgettext.py2
-rw-r--r--src/engine/SCons/Util.py36
-rw-r--r--src/engine/SCons/UtilTests.py36
-rw-r--r--src/engine/SCons/Variables/ListVariableTests.py2
-rw-r--r--src/engine/SCons/Variables/PackageVariableTests.py4
-rw-r--r--src/engine/SCons/cpp.py4
-rw-r--r--src/test_interrupts.py2
-rw-r--r--test/CacheDir/value_dependencies.py52
-rw-r--r--test/CacheDir/value_dependencies/SConstruct32
-rw-r--r--test/CacheDir/value_dependencies/testfile0
-rw-r--r--test/DVIPDF/makeindex.py6
-rw-r--r--test/DVIPS/DVIPS.py40
-rw-r--r--test/Dir/Dir.py18
-rw-r--r--test/File.py14
-rw-r--r--test/TEX/TEX.py2
-rw-r--r--test/TEX/auxiliaries.py4
-rw-r--r--test/TEX/bibliography.py6
-rw-r--r--test/TEX/bibtex-latex-rerun.py2
-rw-r--r--test/TEX/clean.py2
-rw-r--r--test/TEX/configure.py4
-rw-r--r--test/TEX/dryrun.py2
-rw-r--r--test/TEX/glossaries.py2
-rw-r--r--test/TEX/glossary.py2
-rw-r--r--test/TEX/lstinputlisting.py2
-rw-r--r--test/TEX/makeindex.py4
-rw-r--r--test/TEX/multi-line_include_options.py2
-rw-r--r--test/TEX/multi-run.py7
-rw-r--r--test/TEX/newglossary.py2
-rw-r--r--test/TEX/nomencl.py2
-rw-r--r--test/TEX/recursive_scanner_dependencies_import.py2
-rw-r--r--test/TEX/recursive_scanner_dependencies_input.py2
-rw-r--r--test/TEX/rename_result.py2
-rw-r--r--test/TEX/synctex.py2
-rw-r--r--test/TEX/usepackage.py2
-rw-r--r--test/TEX/variant_dir.py5
-rw-r--r--test/TEX/variant_dir_bibunit.py4
-rw-r--r--test/TEX/variant_dir_dup0.py4
-rw-r--r--test/TEX/variant_dir_newglossary.py2
-rw-r--r--test/TEX/variant_dir_style_dup0.py4
-rw-r--r--test/fixture/python_scanner/curdir_reference/helper.py0
-rw-r--r--test/fixture/python_scanner/curdir_reference/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/curdir_reference/script.py1
-rw-r--r--test/fixture/python_scanner/from_import_simple_package_module1.py1
-rw-r--r--test/fixture/python_scanner/from_import_simple_package_module1_as.py1
-rw-r--r--test/fixture/python_scanner/from_import_simple_package_modules_no_space.py1
-rw-r--r--test/fixture/python_scanner/from_import_simple_package_modules_with_space.py1
-rw-r--r--test/fixture/python_scanner/import_simple_package_module1.py1
-rw-r--r--test/fixture/python_scanner/import_simple_package_module1_as.py1
-rw-r--r--test/fixture/python_scanner/imports_nested3.py1
-rw-r--r--test/fixture/python_scanner/imports_simple_package.py1
-rw-r--r--test/fixture/python_scanner/nested1/__init__.py0
-rw-r--r--test/fixture/python_scanner/nested1/module.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/__init__.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/module.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/__init__.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/imports_grandparent_module.py1
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_module.py1
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_then_submodule.py1
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/module.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/nested3/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/nested1/nested2/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/nested1/nested2a/__init__.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2a/module.py0
-rw-r--r--test/fixture/python_scanner/nested1/nested2a/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/nested1/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/sconstest.skip0
-rw-r--r--test/fixture/python_scanner/simple_package/__init__.py0
-rw-r--r--test/fixture/python_scanner/simple_package/module1.py0
-rw-r--r--test/fixture/python_scanner/simple_package/module2.py0
-rw-r--r--test/fixture/python_scanner/simple_package/sconstest.skip0
-rw-r--r--test/srcchange.py2
-rw-r--r--testing/framework/test-framework.rst3
136 files changed, 1585 insertions, 888 deletions
diff --git a/.travis.yml b/.travis.yml
index 985a544..b941f4c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,13 +19,6 @@ install:
# do the rest of the image setup
- ./.travis/install.sh
-# 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
-matrix:
- allow_failures:
- - python: pypy3
- - stage: Coverage
-
# run coverage first as its still useful to collect
stages:
- Coverage
@@ -43,6 +36,12 @@ stages:
# apparently not guaranteed.
jobs:
+
+ # 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
+ - stage: Coverage
include:
- &test_job
stage: Test
@@ -53,29 +52,24 @@ jobs:
env:
- PYVER=pypy3
- PYTHON=pypy3
- sudo: required
-
- <<: *test_job
python: 3.5
env:
- PYVER=35
- PYTHON=3.5
- sudo: required
- <<: *test_job
python: 3.6
env:
- PYVER=36
- PYTHON=3.6
- sudo: required
- <<: *test_job
python: 3.7
env:
- PYVER=37
- PYTHON=3.7
- sudo: required
dist: xenial # required for Python >= 3.7
- <<: *test_job
@@ -83,7 +77,6 @@ jobs:
env:
- PYVER=38
- PYTHON=3.8
- sudo: required
dist: bionic # required for Python >= 3.8
diff --git a/doc/design/engine.xml b/doc/design/engine.xml
index 39289f9..6b8b2a6 100644
--- a/doc/design/engine.xml
+++ b/doc/design/engine.xml
@@ -1104,13 +1104,13 @@ you set it up with another environment...
</para>
<programlisting>
- env.Dependency(target = 'output1', dependency = 'input_1 input_2')
- env.Dependency(target = 'output2', dependency = ['input_1', 'input_2'])
- env.Dependency(target = 'output3', dependency = ['white space input'])
+ env.Depends(target = 'output1', dependency = 'input_1 input_2')
+ env.Depends(target = 'output2', dependency = ['input_1', 'input_2'])
+ env.Depends(target = 'output3', dependency = ['white space input'])
- env.Dependency(target = 'output_a output_b', dependency = 'input_3')
- env.Dependency(target = ['output_c', 'output_d'], dependency = 'input_4')
- env.Dependency(target = ['white space output'], dependency = 'input_5')
+ env.Depends(target = 'output_a output_b', dependency = 'input_3')
+ env.Depends(target = ['output_c', 'output_d'], dependency = 'input_4')
+ env.Depends(target = ['white space output'], dependency = 'input_5')
</programlisting>
<para>
@@ -1129,7 +1129,7 @@ you set it up with another environment...
</para>
<programlisting>
- env.Dependency(target = 'archive.tar.gz', dependency = 'SConstruct')
+ env.Depends(target = 'archive.tar.gz', dependency = 'SConstruct')
</programlisting>
</section>
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 9050832..21e0b1f 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -3448,17 +3448,6 @@ If this is not set, then <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="
</para>
</listitem>
</varlistentry>
- <varlistentry id="cv-LDMODULEEMITTER">
- <term>LDMODULEEMITTER</term>
- <listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Contains the emitter specification for the
-<link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="b-LoadableModule"><function>LoadableModule</function></link> builder.
-The manpage section "Builder Objects" contains
-general information on specifying emitters.
-</para>
-</listitem>
- </varlistentry>
<varlistentry id="cv-LDMODULEFLAGS">
<term>LDMODULEFLAGS</term>
<listitem>
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index ba92aa9..ff44a23 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -65,6 +65,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-CXXVERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$CXXVERSION</envar>">
<!ENTITY cv-DC "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DC</envar>">
<!ENTITY cv-DCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DCOM</envar>">
+<!ENTITY cv-DCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DCOMSTR</envar>">
<!ENTITY cv-DDEBUG "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUG</envar>">
<!ENTITY cv-DDEBUGPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUGPREFIX</envar>">
<!ENTITY cv-DDEBUGSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUGSUFFIX</envar>">
@@ -457,6 +458,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-SHCXXFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHCXXFLAGS</envar>">
<!ENTITY cv-SHDC "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDC</envar>">
<!ENTITY cv-SHDCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDCOM</envar>">
+<!ENTITY cv-SHDCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDCOMSTR</envar>">
<!ENTITY cv-SHDLIBVERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLIBVERSION</envar>">
<!ENTITY cv-SHDLIBVERSIONFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLIBVERSIONFLAGS</envar>">
<!ENTITY cv-SHDLINK "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLINK</envar>">
@@ -706,6 +708,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-CXXVERSION "<link linkend='cv-CXXVERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$CXXVERSION</envar></link>">
<!ENTITY cv-link-DC "<link linkend='cv-DC' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DC</envar></link>">
<!ENTITY cv-link-DCOM "<link linkend='cv-DCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DCOM</envar></link>">
+<!ENTITY cv-link-DCOMSTR "<link linkend='cv-DCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DCOMSTR</envar></link>">
<!ENTITY cv-link-DDEBUG "<link linkend='cv-DDEBUG' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUG</envar></link>">
<!ENTITY cv-link-DDEBUGPREFIX "<link linkend='cv-DDEBUGPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUGPREFIX</envar></link>">
<!ENTITY cv-link-DDEBUGSUFFIX "<link linkend='cv-DDEBUGSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUGSUFFIX</envar></link>">
@@ -1098,6 +1101,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-SHCXXFLAGS "<link linkend='cv-SHCXXFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHCXXFLAGS</envar></link>">
<!ENTITY cv-link-SHDC "<link linkend='cv-SHDC' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDC</envar></link>">
<!ENTITY cv-link-SHDCOM "<link linkend='cv-SHDCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDCOM</envar></link>">
+<!ENTITY cv-link-SHDCOMSTR "<link linkend='cv-SHDCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDCOMSTR</envar></link>">
<!ENTITY cv-link-SHDLIBVERSION "<link linkend='cv-SHDLIBVERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLIBVERSION</envar></link>">
<!ENTITY cv-link-SHDLIBVERSIONFLAGS "<link linkend='cv-SHDLIBVERSIONFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLIBVERSIONFLAGS</envar></link>">
<!ENTITY cv-link-SHDLINK "<link linkend='cv-SHDLINK' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLINK</envar></link>">
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index bd8d5f0..9dccf11 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -93,88 +93,88 @@
</refsynopsisdiv>
-<refsect1 id='description'><title>DESCRIPTION</title>
-<para>The
+<refsect1 id='description'>
+<title>DESCRIPTION</title>
+<para>
<command>scons</command>
-utility builds software (or other files) by determining which
-component pieces must be rebuilt and executing the necessary commands to
-rebuild them.</para>
+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.</para>
+
+<para>You instruct
+<command>scons</command> by writing a configuration file
+which specifies the files to be built (<firstterm>targets</firstterm>),
+and, if necessary, the rules to build those files. Premade
+rules exist for building many common software components
+(such as executable programs, object files, libraries),
+so that for most software projects,
+only the target and input files need be specified.</para>
-<para>By default,
-<command>scons</command>
+<para>
+When invoked, <command>scons</command>
searches for a file named
-<emphasis>SConstruct</emphasis>,
-<emphasis>Sconstruct</emphasis>,
-<emphasis>sconstruct</emphasis>,
-<emphasis>SConstruct.py</emphasis>
-<emphasis>Sconstruct.py</emphasis>
-or
-<emphasis>sconstruct.py</emphasis>
-(in that order) in the current directory and reads its
-configuration from the first file found.
+&SConstruct;
+(going on to check alternative names
+&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>-f</option>
-option.</para>
-
-<para>The
-<emphasis>SConstruct</emphasis>
+option.
+The &SConstruct;
file can specify subsidiary
configuration files using the
-<emphasis role="bold">SConscript</emphasis>()
-function.
+&SConscriptFunc; function.
By convention,
these subsidiary files are named
-<emphasis>SConscript</emphasis>,
+&SConscript;,
although any name may be used.
-(Because of this naming convention,
-the term "SConscript files"
-is sometimes used to refer
-generically to all
-<command>scons</command>
-configuration files,
-regardless of actual file name.)</para>
-
-<para>The configuration files
-specify the target files to be built, and
-(optionally) the rules to build those targets. Reasonable default
-rules exist for building common software components (executable
-programs, object files, libraries), so that for most software
-projects, only the target and input files need be specified.</para>
-
-<para>Before reading the
-<emphasis>SConstruct</emphasis>
-file,
+As a result of this naming convention,
+the term <firstterm>SConscript files</firstterm>
+is often used to refer
+generically to the complete set of
+configuration files for a project,
+including the &SConstruct; file,
+regardless of the actual file names or number of files.</para>
+
+<para>Before reading the SConscript files,
<command>scons</command>
looks for a directory named
-<emphasis>site_scons</emphasis>
-in various system directories (see below) and the directory containing the
-<emphasis>SConstruct</emphasis>
-file; for each of those dirs which exists,
-<emphasis>site_scons</emphasis>
-is prepended to sys.path,
-the file
-<emphasis>site_scons/site_init.py</emphasis>,
-is evaluated if it exists,
-and the directory
-<emphasis>site_scons/site_tools</emphasis>
-is prepended to the default toolpath if it exists.
+<filename>site_scons</filename>
+in various system directories and in the directory containing the
+&SConstruct; file and prepends the ones it
+finds to the Python module search path (<varname>sys.path</varname>),
+thus allowing modules in such directories to be imported in
+the normal Python way in SConscript files.
+For each found site directory,
+if it contains a file <filename>site_init.py</filename>
+it is evaluated, and if it contains a directory
+<filename>site_tools</filename> the path to it
+is prepended to the default toolpath.
See the
-<option>--no-site-dir</option>
-and
<option>--site-dir</option>
-options for more details.</para>
+and
+<option>--no-site-dir</option>
+options for details on default paths and
+controlling the site directories.
+</para>
<para><command>scons</command>
reads and executes the SConscript files as Python scripts,
so you may use normal Python scripting capabilities
(such as flow control, data manipulation, and imported Python libraries)
-to handle complicated build situations.
-<command>scons</command>,
-however, reads and executes all of the SConscript files
+to handle complicated build situations.</para>
+
+<para>
+<command>scons</command>
+reads and executes all of the SConscript files
<emphasis>before</emphasis>
it begins building any targets.
-To make this obvious,
+To make this clear,
<command>scons</command>
prints the following messages about what it is doing:</para>
@@ -189,7 +189,7 @@ $
</literallayout>
<para>The status messages
-(everything except the line that reads "cp foo.in foo.out")
+(lines beginning with the <literal>scons:</literal> tag)
may be suppressed using the
<option>-Q</option>
option.</para>
@@ -209,34 +209,28 @@ that you want to use to build your target files
are not in standard system locations,
<command>scons</command>
will not find them unless
-you explicitly set the <envar>PATH</envar>
+you explicitly set the <command>scons</command>
+<envar>PATH</envar> in the internal environment
to include those locations.
-Whenever you create an
-<command>scons</command>
-construction environment,
+Whenever you create a &consenv;,
you can propagate the value of <envar>PATH</envar>
from your external environment as follows:</para>
<literallayout class="monospaced">
import os
-env = Environment(ENV = {'PATH' : os.environ['PATH']})
+env = Environment(ENV={'PATH': os.environ['PATH']})
</literallayout>
-<para>Similarly, if the commands use external environment variables
-like
-<envar>PATH</envar>,
-<envar>HOME</envar>,
-<envar>JAVA_HOME</envar>,
-<envar>LANG</envar>,
-<envar>SHELL</envar>,
-<envar>TERM</envar>,
-etc.,
-these variables can also be explicitly propagated:</para>
+<para>Similarly, if the commands use specific
+external environment variables that <command>scons</command>
+does not recognize, they can be propagated into
+the internal environment:</para>
<literallayout class="monospaced">
import os
-env = Environment(ENV = {'PATH': os.environ['PATH'],
- 'HOME': os.environ['HOME']})
+env = Environment(ENV={'PATH': os.environ['PATH'],
+ 'ANDROID_HOME': os.environ['ANDROID_HOME'],
+ 'ANDROID_NDK_HOME': os.environ['ANDROID_NDK_HOME']})
</literallayout>
<para>Or you may explicitly propagate the invoking user's
@@ -244,17 +238,23 @@ complete external environment:</para>
<literallayout class="monospaced">
import os
-env = Environment(ENV = os.environ)
+env = Environment(ENV=os.environ)
</literallayout>
<para>This comes at the expense of making your build
dependent on the user's environment being set correctly,
-but it may be more convenient for many configurations.</para>
+but it may be more convenient for many configurations.
+It should not cause problems if done in a build setup which tightly
+controls how the environment is set up before invoking
+<command>scons</command>, as in many continuous
+integration setups.
+</para>
<para><command>scons</command>
can scan known input files automatically for dependency
-information (for example, #include statements
-in C or C++ files) and will rebuild dependent files appropriately
+information (for example, <literal>#include</literal>
+preprocessor directives in C or C++ files)
+and will rebuild dependent files appropriately
whenever any "included" input file changes.
<command>scons</command>
supports the
@@ -266,41 +266,46 @@ SCCS or RCS subdirectories
using SCCS, RCS or BitKeeper.</para>
<para><command>scons</command>
-is normally executed in a top-level directory containing a
-<emphasis>SConstruct</emphasis>
-file, optionally specifying
-as command-line arguments
-the target file or files to be built.</para>
-
-<para>By default, the command</para>
-
-<literallayout class="monospaced">
-scons
-</literallayout>
+is normally executed in a top-level directory containing an
+&SConstruct; file.
+When <command>scons</command> is invoked,
+the command line (including the contents
+of the &SCONSFLAGS; environment variable,
+if set) is processed.
+The options are consumed (see <xref linkend="options"></xref>;
+and also note that SConscript files may define additional options
+for the project using the &AddOption; function).
+Any variable argument assignments (see below) are also consumed.
+Any remaining arguments are taken as the targets to build.
+Targets on the command line may be files, directories,
+or phony targets defined using the &Alias; function.
+The command line targets are available in the
+&COMMAND_LINE_TARGETS; list.
+</para>
-<para>will build all target files in or below the current directory.
-Explicit default targets
-(to be built when no targets are specified on the command line)
-may be defined in the SConscript file(s)
-using the
-<emphasis role="bold">Default()</emphasis>
-function, described below.</para>
+<para>If no targets are specified on the command line,
+<command>scons</command>
+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.
+</para>
-<para>Even when
-<emphasis role="bold">Default()</emphasis>
-targets are specified in the SConscript file(s),
-all target files in or below the current directory
-may be built by explicitly specifying
-the current directory (.)
+<para>To ignore the default targets specified
+through calls to &Default; and instead build all
+target files in or below the current directory
+specify the current directory (<literal>.</literal>)
as a command-line target:</para>
<literallayout class="monospaced">
scons .
</literallayout>
-<para>Building all target files,
+<para>To build all target files,
including any files outside of the current directory,
-may be specified by supplying a command-line target
+supply a command-line target
of the root directory (on POSIX systems):</para>
<literallayout class="monospaced">
@@ -314,15 +319,33 @@ should be built (on Windows systems):</para>
scons C:\ D:\
</literallayout>
-<para>To build only specific targets,
-supply them as command-line arguments:</para>
+<para>A subset of a hierarchical tree may be built by
+remaining at the top-level directory (where the
+&SConstruct;
+file lives) and specifying the subdirectory as the target to
+build:</para>
<literallayout class="monospaced">
-scons foo bar
+scons src/subdir
</literallayout>
-<para>in which case only the specified targets will be built
-(along with any derived files on which they depend).</para>
+<para>or by changing directory and invoking scons with the
+<option>-u</option>
+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 <option>-D</option> and <option>-U</option> options):</para>
+
+<literallayout class="monospaced">
+cd src/subdir
+scons -u .
+</literallayout>
+
+<para>In all cases, more files may be built than are
+requested, as <command>scons</command> needs to make
+sure any dependent files are built.</para>
<para>Specifying "cleanup" targets in SConscript files is not usually necessary.
The
@@ -334,45 +357,22 @@ necessary to build the specified target:</para>
scons -c .
</literallayout>
-<para>to remove all target files, or:</para>
+<para>to remove all target files in or under the current directory, or:</para>
<literallayout class="monospaced">
scons -c build export
</literallayout>
-<para>to remove target files under build and export.
+<para>to remove target files under <filename>build</filename>
+and <filename>export</filename>.</para>
+
+<para>
Additional files or directories to remove can be specified using the
-<emphasis role="bold">Clean()</emphasis>
-function.
+&Clean; function in the SConscript files.
Conversely, targets that would normally be removed by the
<option>-c</option>
-invocation
-can be prevented from being removed by using the
-<emphasis role="bold">NoClean</emphasis>()
-function.</para>
-
-<para>A subset of a hierarchical tree may be built by
-remaining at the top-level directory (where the
-<emphasis>SConstruct</emphasis>
-file lives) and specifying the subdirectory as the target to be
-built:</para>
-
-<literallayout class="monospaced">
-scons src/subdir
-</literallayout>
-
-<para>or by changing directory and invoking scons with the
-<option>-u</option>
-option, which traverses up the directory
-hierarchy until it finds the
-<emphasis>SConstruct</emphasis>
-file, and then builds
-targets relatively to the current subdirectory:</para>
-
-<literallayout class="monospaced">
-cd src/subdir
-scons -u .
-</literallayout>
+invocation can be retained by calling the
+&NoClean; function with those targets.</para>
<para><command>scons</command>
supports building multiple targets in parallel via a
@@ -405,16 +405,16 @@ command-line options. The
option is useful to prevent multiple builds
from trying to update the cache simultaneously.</para>
-<para>Values of variables to be passed to the SConscript file(s)
+<para>Values of variables to be passed to the SConscript files
may be specified on the command line:</para>
<literallayout class="monospaced">
scons debug=1 .
</literallayout>
-<para>These variables are available in SConscript files
-through the ARGUMENTS dictionary,
-and can be used in the SConscript file(s) to modify
+<para>These variables are available
+through the &ARGUMENTS; dictionary,
+and can be used in the SConscript files to modify
the build in any way:</para>
<literallayout class="monospaced">
@@ -425,13 +425,12 @@ else:
</literallayout>
<para>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.
-ARGLIST[0] returns a tuple
-containing (argname, argvalue).
-A Python exception is thrown if you
+if necessary. Each &ARGLIST; entry is a tuple
+containing (<replaceable>argname</replaceable>, <replaceable>argvalue</replaceable>).
+A Python <literal>IndexError</literal> exception is raised if you
try to access a list member that
does not exist.</para>
@@ -443,24 +442,28 @@ There should be no other dependencies or requirements to run
<!-- The following paragraph reflects the default tool search orders -->
<!-- currently in SCons/Tool/__init__.py. If any of those search orders -->
<!-- change, this documentation should change, too. -->
+
<para>By default,
<command>scons</command>
-knows how to search for available programming tools
-on various systems.
-On Windows systems,
+searches for known programming tools
+on various systems and initializes itself based on what is found.
+On Windows systems which identify as <emphasis>win32</emphasis>,
<command>scons</command>
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 <emphasis>cygwin</emphasis>
+(that is, if <command>scons</command> is invoked from a cygwin shell),
+the order changes to prefer the GCC toolchain over the MSVC tools.
On OS/2 systems,
<command>scons</command>
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 Sun Solaris systems,
+On SGI IRIX, IBM AIX, Hewlett Packard HP-UX, and Oracle Solaris systems,
<command>scons</command>
searches for the native compiler tools
(MIPSpro, Visual Age, aCC, and Forte tools respectively)
@@ -470,7 +473,6 @@ including POSIX (Linux and UNIX) platforms,
<command>scons</command>
searches in order
for the GCC tool chain,
-the Microsoft Visual C++ tools,
and the Intel compiler tools.
You may, of course, override these default values
by appropriate configuration of
@@ -4383,20 +4385,17 @@ vars.AddVariables(
</refsect2>
-<refsect2 id='file_and_directory_nodes'><title>File and Directory Nodes</title>
+<refsect2 id='file_and_directory_nodes'>
+<title>File and Directory Nodes</title>
-<para>The
-<emphasis>File</emphasis>()
-and
-<emphasis>Dir</emphasis>()
-functions return
-<emphasis>File</emphasis>
-and
-<emphasis>Dir</emphasis>
-Nodes, respectively.
-Python objects, respectively.
-Those objects have several user-visible attributes
-and methods that are often useful:</para>
+<para>
+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:</para>
<variablelist>
<varlistentry>
@@ -4412,33 +4411,31 @@ file is found).
The build path is the same as the source path if
<emphasis>variant_dir</emphasis>
is not being used.</para>
-
</listitem>
</varlistentry>
+
<varlistentry>
<term>abspath</term>
<listitem>
<para>The absolute build path of the given file or directory.</para>
-
</listitem>
</varlistentry>
+
<varlistentry>
<term>srcnode()</term>
<listitem>
<para>The
<emphasis>srcnode</emphasis>()
method
-returns another
-<emphasis>File</emphasis>
-or
-<emphasis>Dir</emphasis>
-object representing the
-<emphasis>source</emphasis>
-path of the given
-<emphasis>File</emphasis>
-or
-<emphasis>Dir</emphasis>.
-The</para>
+returns another File or Directory Node
+representing the source path of the given
+File or Directory Node.
+</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+
+<para>For example:</para>
<literallayout class="monospaced">
# Get the current build dir's path, relative to top.
@@ -4451,98 +4448,90 @@ File('foo.c').srcnode().path # source path of the given source file.
# Builders also return File objects:
foo = env.Program('foo.c')
-print("foo will be built in %s"%foo.path)
+print("foo will be built in", foo.path)
</literallayout>
-<para>A
-<emphasis>Dir</emphasis>
-Node or
-<emphasis>File</emphasis>
-Node can also be used to create
-file and subdirectory Nodes relative to the generating Node.
-A
-<emphasis>Dir</emphasis>
-Node will place the new Nodes within the directory it represents.
-A
-<emphasis>File</emphasis>
-node will place the new Nodes within its parent directory
-(that is, "beside" the file in question).
-If
-<emphasis>d</emphasis>
-is a
-<emphasis>Dir</emphasis>
-(directory) Node and
-<emphasis>f</emphasis>
-is a
-<emphasis>File</emphasis>
-(file) Node,
-then these methods are available:</para>
+<para>
+File and Directory Node objects have methods to create
+File and Directory Nodes relative to the original Node.
+</para>
+
+<para>
+If the object is a Directory Node,
+these methods will place the the new Node within the directory
+the Node represents:
+</para>
- </listitem>
- </varlistentry>
-</variablelist>
<variablelist>
<varlistentry>
- <term><emphasis>d</emphasis>.Dir(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.Dir(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns a directory Node for a subdirectory of
-<emphasis>d</emphasis>
+<replaceable>d</replaceable>
named
-<emphasis>name</emphasis>.</para>
-
+<replaceable>name</replaceable>.</para>
</listitem>
</varlistentry>
+
<varlistentry>
- <term><emphasis>d</emphasis>.File(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.File(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns a file Node for a file within
-<emphasis>d</emphasis>
+<replaceable>d</replaceable>
named
-<emphasis>name</emphasis>.</para>
-
+<replaceable>name</replaceable>.</para>
</listitem>
</varlistentry>
+
<varlistentry>
- <term><emphasis>d</emphasis>.Entry(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.Entry(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns an unresolved Node within
-<emphasis>d</emphasis>
+<replaceable>d</replaceable>
named
-<emphasis>name</emphasis>.</para>
-
+<replaceable>name</replaceable>.</para>
</listitem>
</varlistentry>
+</variablelist>
+
+<para>
+If the object is a File Node,
+these methods will place the the new Node in the same
+directory as the one the Node represents:
+</para>
+
+<variablelist>
<varlistentry>
- <term><emphasis>f</emphasis>.Dir(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.Dir(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns a directory named
-<emphasis>name</emphasis>
+<replaceable>name</replaceable>
within the parent directory of
-<emphasis>f</emphasis>.</para>
-
+<replaceable>f</replaceable>.</para>
</listitem>
</varlistentry>
+
<varlistentry>
- <term><emphasis>f</emphasis>.File(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.File(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns a file named
-<emphasis>name</emphasis>
+<replaceable>name</replaceable>
within the parent directory of
-<emphasis>f</emphasis>.</para>
-
+<replaceable>f</replaceable>.</para>
</listitem>
</varlistentry>
+
<varlistentry>
- <term><emphasis>f</emphasis>.Entry(<emphasis>name</emphasis>)</term>
+ <term><replaceable>d</replaceable>.Entry(<replaceable>name</replaceable>)</term>
<listitem>
<para>Returns an unresolved Node named
-<emphasis>name</emphasis>
+<replaceable>name</replaceable>
within the parent directory of
-<emphasis>f</emphasis>.</para>
-
+<replaceable>f</replaceable>.</para>
</listitem>
</varlistentry>
</variablelist>
+
<para>For example:</para>
<literallayout class="monospaced">
@@ -5923,7 +5912,7 @@ action='$CC -c -o $TARGET $SOURCES'
cc -c -o foo foo.c bar.c
</literallayout>
-<para>Variable names may be surrounded by curly braces
+<para>Variable names may be surrounded by curly braces
<emphasis role="bold">{ }</emphasis>
to separate the name from surrounding characters which
are not part of the name.
@@ -7200,7 +7189,7 @@ in addition to those passed on the command line.</para>
<listitem>
<para>(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,
+(and/or Build Tools) to a file to give these settings,
which are expensive to generate, persistence
across &scons; invocations.
Use of this option is primarily intended to aid performance
diff --git a/doc/scons.mod b/doc/scons.mod
index 3e843a0..024afab 100644
--- a/doc/scons.mod
+++ b/doc/scons.mod
@@ -225,6 +225,7 @@
<!ENTITY NoCache "<function xmlns='http://www.scons.org/dbxsd/v1.0'>NoCache</function>">
<!ENTITY Objects "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Objects</function>">
<!ENTITY Options "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Options</function>">
+<!ENTITY SConscriptFunc "<function xmlns='http://www.scons.org/dbxsd/v1.0'>SConscript</function>">
<!ENTITY Variables "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Variables</function>">
<!ENTITY PackageOption "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PackageOption</function>">
<!ENTITY PackageVariable "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PackageVariable</function>">
@@ -418,27 +419,27 @@
-->
-<!ENTITY buildfunc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>builder function</literal>">
-<!ENTITY build_action "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>build action</literal>">
-<!ENTITY build_actions "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>build actions</literal>">
-<!ENTITY builder_method "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>builder method</literal>">
+<!ENTITY buildfunc "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>builder function</phrase>">
+<!ENTITY build_action "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>build action</phrase>">
+<!ENTITY build_actions "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>build actions</phrase>">
+<!ENTITY builder_method "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>builder method</phrase>">
-<!ENTITY Configure_Contexts "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Configure Contexts</literal>">
-<!ENTITY configure_context "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>configure context</literal>">
+<!ENTITY Configure_Contexts "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Configure Contexts</phrase>">
+<!ENTITY configure_context "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>configure context</phrase>">
-<!ENTITY ConsEnv "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Environment</literal>">
-<!ENTITY ConsEnvs "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Environments</literal>">
-<!ENTITY Consenv "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction environment</literal>">
-<!ENTITY Consenvs "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction environments</literal>">
-<!ENTITY consenv "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>construction environment</literal>">
-<!ENTITY consenvs "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>construction environments</literal>">
+<!ENTITY ConsEnv "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Environment</phrase>">
+<!ENTITY ConsEnvs "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Environments</phrase>">
+<!ENTITY Consenv "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction environment</phrase>">
+<!ENTITY Consenvs "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction environments</phrase>">
+<!ENTITY consenv "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>construction environment</phrase>">
+<!ENTITY consenvs "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>construction environments</phrase>">
-<!ENTITY ConsVar "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Variable</literal>">
-<!ENTITY ConsVars "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Variables</literal>">
-<!ENTITY Consvar "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction variable</literal>">
-<!ENTITY Consvars "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Construction variables</literal>">
-<!ENTITY consvar "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>construction variable</literal>">
-<!ENTITY consvars "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>construction variables</literal>">
+<!ENTITY ConsVar "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Variable</phrase>">
+<!ENTITY ConsVars "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction Variables</phrase>">
+<!ENTITY Consvar "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction variable</phrase>">
+<!ENTITY Consvars "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>Construction variables</phrase>">
+<!ENTITY consvar "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>construction variable</phrase>">
+<!ENTITY consvars "<phrase xmlns='http://www.scons.org/dbxsd/v1.0'>construction variables</phrase>">
<!ENTITY CPPPATH "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>CPPPATH</literal>">
@@ -529,14 +530,14 @@
-->
-<!ENTITY scons-announce "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>announce@scons.tigris.org</literal>">
-<!ENTITY scons-devel "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>scons-dev@scons.org</literal>">
-<!ENTITY scons-users "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>scons-users@scons.org</literal>">
+<!ENTITY scons-announce "<email xmlns='http://www.scons.org/dbxsd/v1.0'>announce@scons.tigris.org</email>">
+<!ENTITY scons-devel "<email xmlns='http://www.scons.org/dbxsd/v1.0'>scons-dev@scons.org</email>">
+<!ENTITY scons-users "<email xmlns='http://www.scons.org/dbxsd/v1.0'>scons-users@scons.org</email>">
<!--
Character entities
-
+
-->
<!ENTITY lambda "&#923;">
diff --git a/doc/user/depends.xml b/doc/user/depends.xml
index cd5094a..24bede6 100644
--- a/doc/user/depends.xml
+++ b/doc/user/depends.xml
@@ -2,7 +2,7 @@
<!DOCTYPE sconsdoc [
<!ENTITY % scons SYSTEM "../scons.mod">
%scons;
-
+
<!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
%builders-mod;
<!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
@@ -372,7 +372,7 @@ int main() { printf("Hello, world!\n"); }
instead of
<literal>timestamp-match</literal>,
would be if you have some specific reason
- to require this &Make;-like behavior of
+ to require this &Make;-like behavior of
not rebuilding a target when an otherwise-modified
source file is older.
@@ -561,13 +561,6 @@ int main() { printf("Hello, world!\n"); }
</para>
- <para>
- The fourth argument <varname>repo_node</varname>,
- is the &Node; to use if it is not None when comparing &BuildInfo;.
- This is typically only set when the target node only exists in a
- &Repository;
- </para>
-
<variablelist>
<varlistentry>
@@ -612,22 +605,33 @@ int main() { printf("Hello, world!\n"); }
<para>
- Note that ignoring some of the arguments
- in your custom &Decider; function
- is a perfectly normal thing to do,
- if they don't impact the way you want to
- decide if the dependency file has changed.
+ These attributes may not be present at the time of the
+ first run. Without any prior build, no targets have been
+ created and no <filename>.sconsign</filename> DB file exists yet.
+ So you should always check whether the
+ <varname>prev_ni</varname> attribute in question is available
+ (use the Python <function>hasattr</function> method or a
+ <literal>try</literal>-<literal>except</literal> block).
+
+ </para>
+
+
+ <para>
+
+ The fourth argument <varname>repo_node</varname>
+ is the &Node; to use if it is not None when comparing &BuildInfo;.
+ This is typically only set when the target node only exists in a
+ &Repository;
</para>
<para>
- Another thing to look out for is the fact that the three
- attributes above may not be present at the time of the first run.
- Without any prior build, no targets have been created and no
- <filename>.sconsign</filename> DB file exists yet.
- So, you should always check whether the
- <varname>prev_ni</varname> attribute in question is available.
+ Note that ignoring some of the arguments
+ in your custom &Decider; function
+ is a perfectly normal thing to do,
+ if they don't impact the way you want to
+ decide if the dependency file has changed.
</para>
@@ -644,13 +648,14 @@ int main() { printf("Hello, world!\n"); }
<sconstruct>
env = Environment()
+
def config_file_decider(dependency, target, prev_ni, repo_node=None):
import os.path
# We always have to init the .csig value...
dep_csig = dependency.get_csig()
# .csig may not exist, because no target was built yet...
- if 'csig' not in dir(prev_ni):
+ if not prev_ni.hasattr("csig"):
return True
# Target file may not exist yet
if not os.path.exists(str(target.abspath)):
@@ -660,17 +665,18 @@ def config_file_decider(dependency, target, prev_ni, repo_node=None):
return True
return False
+
def update_file():
- f = open("test.txt","a")
- f.write("some line\n")
- f.close()
+ with open("test.txt", "a") as f:
+ f.write("some line\n")
+
update_file()
# Activate our own decider function
env.Decider(config_file_decider)
-env.Install("install","test.txt")
+env.Install("install", "test.txt")
</sconstruct>
</section>
@@ -747,26 +753,6 @@ int main() { printf("Hello, world!\n"); }
</section>
<section>
- <title>Older Functions for Deciding When an Input File Has Changed</title>
-
- <para>
-
- &SCons; still supports two functions that used to be the
- primary methods for configuring the
- decision about whether or not an input file has changed.
- These functions have been officially deprecated
- as &SCons; version 2.0,
- and their use is discouraged,
- mainly because they rely on a somewhat
- confusing distinction between how
- source files and target files are handled.
- These functions are documented here mainly in case you
- encounter them in older &SConscript; files.
-
- </para>
- </section>
-
- <section>
<title>Implicit Dependencies: The &cv-CPPPATH; Construction Variable</title>
<para>
@@ -1426,11 +1412,11 @@ Ignore(hello, '/usr/include/stdio.h')
</programlisting>
<para>
- &Ignore; can also be used to prevent a generated file from being built
- by default. This is due to the fact that directories depend on
- their contents. So to ignore a generated file from the default build,
+ &Ignore; can also be used to prevent a generated file from being built
+ by default. This is due to the fact that directories depend on
+ their contents. So to ignore a generated file from the default build,
you specify that the directory should ignore the generated file.
- Note that the file will still be built if the user specifically
+ Note that the file will still be built if the user specifically
requests the target on scons command line, or if the file is
a dependency of another file which is requested and/or is built
by default.
diff --git a/doc/user/output.xml b/doc/user/output.xml
index f9e1a98..d1082a9 100644
--- a/doc/user/output.xml
+++ b/doc/user/output.xml
@@ -47,7 +47,7 @@
<para>
A key aspect of creating a usable build configuration
- is providing good output from the build
+ is providing useful output from the build
so its users can readily understand
what the build is doing
and get information about how to control the build.
@@ -355,6 +355,17 @@ cc -o foo.o -c foo.c
cc -o foo foo.o
</screen>
+ <para>
+
+ A gentle reminder here: many of the commands for building come in
+ pairs, depending on whether the intent is to build an object for
+ use in a shared library or not. The command strings mirror this,
+ so it may be necessary to set, for example, both
+ <envar>CCCOMSTR</envar> and <envar>SHCCCOMSTR</envar>
+ to get the desired results.
+
+ </para>
+
</section>
<section>
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index ad936e4..3acd034 100755
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -15,6 +15,17 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added C:\msys64\mingw64\bin to default mingw and clang windows PATH's. This
is a reasonable default and also aligns with changes in Appveyor's VS2019 image.
- Drop support for Python 2.7. SCons will be Python 3.5+ going forward.
+ - Change SCons.Node.ValueWithMemo to consider any name passed when memoizing Value() nodes
+
+ From Jeremy Elson:
+ - Updated design doc to use the correct syntax for Depends()
+
+ From Adam Gross:
+ - Added support for taking instances of the Value class as implicit
+ dependencies.
+ - Added new module SCons.Scanner.Python to allow scanning .py files.
+ - Added support for explicitly passing a name when creating Value() nodes. This may be useful
+ when the value can't be converted to a string or if having a name is otherwise desirable.
From Andrew Morrow:
- Fix Issue #3469 - Fixed improper reuse of temporary and compiled files by Configure when changing
@@ -33,12 +44,19 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Improve performance of Subst by preventing unnecessary frame
allocations by no longer defining the *Subber classes inside of their
respective function calls.
+ - Improve performance of Subst in some cases by preventing
+ unnecessary calls to eval when a token is surrounded in braces
+ but is not a function call.
+ - Improve performance of subst by removing unnecessary recursion.
From Mats Wichmann:
- Remove deprecated SourceCode
- str.format syntax errors fixed
- a bunch of linter/checker syntax fixups
- Convert remaining uses of insecure/deprecated mktemp method.
+ - Clean up some duplications in manpage. Clarify portion of manpage on Dir and File nodes.
+ - Reduce needless list conversions.
+ - Fixed regex in Python scanner.
RELEASE 3.1.2 - Mon, 17 Dec 2019 02:06:27 +0000
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 3125824..3c2c0c2 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -40,6 +40,7 @@ SCons/Scanner/Fortran.py
SCons/Scanner/IDL.py
SCons/Scanner/LaTeX.py
SCons/Scanner/Prog.py
+SCons/Scanner/Python.py
SCons/Scanner/RC.py
SCons/Scanner/SWIG.py
SCons/SConf.py
@@ -140,6 +141,7 @@ SCons/Tool/pdf.py
SCons/Tool/pdflatex.py
SCons/Tool/pdftex.py
SCons/Tool/PharLapCommon.py
+SCons/Tool/python.py
SCons/Tool/qt.py
SCons/Tool/rmic.py
SCons/Tool/rpcgen.py
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 69bb19e..13949e5 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -230,7 +230,7 @@ class OverrideWarner(collections.UserDict):
def warn(self):
if self.already_warned:
return
- for k in list(self.keys()):
+ for k in self.keys():
if k in misleading_keywords:
alt = misleading_keywords[k]
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index f28e201..b4286fd 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -173,7 +173,7 @@ class MyNode_without_target_from_source(object):
def builder_set(self, builder):
self.builder = builder
def has_builder(self):
- return not self.builder is None
+ return self.builder is not None
def set_explicit(self, is_explicit):
self.is_explicit = is_explicit
def has_explicit_builder(self):
@@ -205,7 +205,7 @@ class BuilderTestCase(unittest.TestCase):
"""Test simple Builder creation
"""
builder = SCons.Builder.Builder(action="foo")
- assert not builder is None, builder
+ assert builder is not None, builder
builder = SCons.Builder.Builder(action="foo", OVERRIDE='x')
x = builder.overrides['OVERRIDE']
assert x == 'x', x
@@ -429,7 +429,7 @@ class BuilderTestCase(unittest.TestCase):
return Foo(target)
builder = SCons.Builder.Builder(target_factory = FooFactory)
assert builder.target_factory is FooFactory
- assert not builder.source_factory is FooFactory
+ assert builder.source_factory is not FooFactory
def test_source_factory(self):
"""Test a Builder that creates source nodes of a specified class
@@ -440,7 +440,7 @@ class BuilderTestCase(unittest.TestCase):
global Foo
return Foo(source)
builder = SCons.Builder.Builder(source_factory = FooFactory)
- assert not builder.target_factory is FooFactory
+ assert builder.target_factory is not FooFactory
assert builder.source_factory is FooFactory
def test_splitext(self):
@@ -737,7 +737,7 @@ class BuilderTestCase(unittest.TestCase):
with open(str(t), 'w') as f:
f.write("function2\n")
for t in tlist:
- if not t in list(map(str, target)):
+ if t not in list(map(str, target)):
with open(t, 'w') as f:
f.write("function2\n")
return 1
@@ -768,7 +768,7 @@ class BuilderTestCase(unittest.TestCase):
with open(str(t), 'w') as f:
f.write("function3\n")
for t in tlist:
- if not t in list(map(str, target)):
+ if t not in list(map(str, target)):
with open(t, 'w') as f:
f.write("function3\n")
return 1
@@ -821,7 +821,7 @@ class BuilderTestCase(unittest.TestCase):
assert s == ['aaa.bar'], s
builder3 = SCons.Builder.Builder(action='bld3')
- assert not builder3.src_builder is builder1.src_builder
+ assert builder3.src_builder is not builder1.src_builder
builder4 = SCons.Builder.Builder(action='bld4',
src_suffix='.i',
diff --git a/src/engine/SCons/CacheDir.py b/src/engine/SCons/CacheDir.py
index 10c088d..9bb7ef3 100644
--- a/src/engine/SCons/CacheDir.py
+++ b/src/engine/SCons/CacheDir.py
@@ -36,7 +36,6 @@ import sys
import SCons
import SCons.Action
import SCons.Warnings
-from SCons.Util import PY3
cache_enabled = True
cache_debug = False
@@ -160,10 +159,7 @@ class CacheDir(object):
if path is None:
return
- if PY3:
- self._readconfig3(path)
- else:
- self._readconfig2(path)
+ self._readconfig3(path)
def _readconfig3(self, path):
diff --git a/src/engine/SCons/CacheDirTests.py b/src/engine/SCons/CacheDirTests.py
index 0e242c4..ff22d01 100644
--- a/src/engine/SCons/CacheDirTests.py
+++ b/src/engine/SCons/CacheDirTests.py
@@ -33,7 +33,6 @@ import stat
from TestCmd import TestCmd
import SCons.CacheDir
-from SCons.Util import PY3
built_it = None
@@ -169,10 +168,7 @@ class ExceptionTestCase(unittest.TestCase):
os.remove(old_config)
try:
- if PY3:
- self._CacheDir._readconfig3(self._CacheDir.path)
- else:
- self._CacheDir._readconfig2(self._CacheDir.path)
+ self._CacheDir._readconfig3(self._CacheDir.path)
assert False, "Should have raised exception and did not"
except SCons.Errors.SConsEnvironmentError as e:
assert str(e) == "Failed to write cache configuration for {}".format(self._CacheDir.path)
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 3e23196..5e76e35 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -1854,7 +1854,7 @@ class Base(SubstitutionEnvironment):
uniq = {}
for executor in [n.get_executor() for n in nodes]:
uniq[executor] = 1
- for executor in list(uniq.keys()):
+ for executor in uniq.keys():
executor.add_pre_action(action)
return nodes
@@ -1864,7 +1864,7 @@ class Base(SubstitutionEnvironment):
uniq = {}
for executor in [n.get_executor() for n in nodes]:
uniq[executor] = 1
- for executor in list(uniq.keys()):
+ for executor in uniq.keys():
executor.add_post_action(action)
return nodes
@@ -2220,10 +2220,10 @@ class Base(SubstitutionEnvironment):
else:
return [self.subst(arg)]
- def Value(self, value, built_value=None):
+ def Value(self, value, built_value=None, name=None):
"""
"""
- return SCons.Node.Python.ValueWithMemo(value, built_value)
+ return SCons.Node.Python.ValueWithMemo(value, built_value, name)
def VariantDir(self, variant_dir, src_dir, duplicate=1):
variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0]
diff --git a/src/engine/SCons/Environment.xml b/src/engine/SCons/Environment.xml
index b1c2039..e1d5e74 100644
--- a/src/engine/SCons/Environment.xml
+++ b/src/engine/SCons/Environment.xml
@@ -65,15 +65,6 @@ env['BUILDERS']['NewBuilder'] = foo
</summary>
</cvar>
-<cvar name="Dir">
-<summary>
-<para>
-A function that converts a string
-into a Dir instance relative to the target being built.
-</para>
-</summary>
-</cvar>
-
<cvar name="ENV">
<summary>
<para>
@@ -130,15 +121,6 @@ env = Environment(ENV = {'PATH' : os.environ['PATH']})
</summary>
</cvar>
-<cvar name="File">
-<summary>
-<para>
-A function that converts a string into a File instance relative to the
-target being built.
-</para>
-</summary>
-</cvar>
-
<cvar name="SCANNERS">
<summary>
<para>
@@ -460,6 +442,8 @@ including another alias.
can be called multiple times for the same
alias to add additional targets to the alias,
or additional actions to the list for this alias.
+Aliases are global even if set through
+the construction environment method.
</para>
<para>
@@ -1163,17 +1147,16 @@ env.Decider('content')
</example_commands>
<para>
-In addition to the above already-available functions,
-the
+In addition to the above already-available functions, the
<varname>function</varname>
-argument may be an actual Python function
-that takes the following three arguments:
+argument may be a Python function you supply.
+Such a function must accept the following four arguments:
</para>
<para>
<variablelist>
<varlistentry>
-<term><parameter>dependency</parameter></term>
+<term><parameter class="function">dependency</parameter></term>
<listitem>
<para>
The Node (file) which
@@ -1187,7 +1170,7 @@ was built.
</listitem>
</varlistentry>
<varlistentry>
-<term><parameter>target</parameter></term>
+<term><parameter class="function">target</parameter></term>
<listitem>
<para>
The Node (file) being built.
@@ -1200,7 +1183,7 @@ has "changed."
</listitem>
</varlistentry>
<varlistentry>
-<term><parameter>prev_ni</parameter></term>
+<term><parameter class="function">prev_ni</parameter></term>
<listitem>
<para>
Stored information about the state of the
@@ -1216,12 +1199,17 @@ size, or content signature.
</listitem>
</varlistentry>
<varlistentry>
-<term><parameter>repo_node</parameter></term>
+<term><parameter class="function">repo_node</parameter></term>
<listitem>
<para>
-Use this node instead of the one specified by
+If set, use this Node instead of the one specified by
<varname>dependency</varname>
- to determine if the dependency has changed.
+to determine if the dependency has changed.
+This argument is optional so should be written
+as a default argument (typically it would be
+written as <literal>repo_node=None</literal>).
+A caller will normally only set this if the
+target only exists in a Repository.
</para>
</listitem>
</varlistentry>
@@ -1351,11 +1339,10 @@ cc_values = env.Dictionary('CC', 'CCFLAGS', 'CCCOM')
</arguments>
<summary>
<para>
-This returns a Directory Node,
-an object that represents the specified directory
-<varname>name</varname>.
+Returns Directory Node(s).
+A Directory Node is an object that represents a directory.
<varname>name</varname>
-can be a relative or absolute path.
+can be a relative or absolute path or a list of such paths.
<varname>directory</varname>
is an optional directory that will be used as the parent directory.
If no
@@ -1366,7 +1353,10 @@ is specified, the current script's directory is used as the parent.
<para>
If
<varname>name</varname>
-is a list, SCons returns a list of Dir nodes.
+is a single pathname, the corresponding node is returned.
+If
+<varname>name</varname>
+is a list, SCons returns a list of nodes.
Construction variables are expanded in
<varname>name</varname>.
</para>
@@ -1511,20 +1501,24 @@ if Execute("mkdir sub/dir/ectory"):
</arguments>
<summary>
<para>
-This returns a
-File Node,
-an object that represents the specified file
-<varname>name</varname>.
+Returns File Node(s).
+A File Node is an object that represents a file.
<varname>name</varname>
-can be a relative or absolute path.
+can be a relative or absolute path or a list of such paths.
<varname>directory</varname>
is an optional directory that will be used as the parent directory.
+If no
+<varname>directory</varname>
+is specified, the current script's directory is used as the parent.
</para>
<para>
If
<varname>name</varname>
-is a list, SCons returns a list of File nodes.
+is a single pathname, the corresponding node is returned.
+If
+<varname>name</varname>
+is a list, SCons returns a list of nodes.
Construction variables are expanded in
<varname>name</varname>.
</para>
@@ -2879,6 +2873,38 @@ function.
</summary>
</scons_function>
+<scons_function name="Split">
+<arguments>(arg)</arguments>
+<summary>
+<para>
+Returns a list of file names or other objects.
+If <varname>arg</varname> 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 <varname>arg</varname> is already a list,
+the list will be returned untouched.
+If <varname>arg</varname> is any other type of object,
+it will be returned as a list
+containing just the object.
+</para>
+
+<para>
+Example:
+</para>
+
+<example_commands>
+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
+""")
+</example_commands>
+</summary>
+</scons_function>
+
<scons_function name="subst">
<arguments signature="env">
(input, [raw, target, source, conv])
@@ -3055,7 +3081,7 @@ env.Tool('opengl', toolpath = ['build/tools'])
<scons_function name="Value">
<arguments>
-(value, [built_value])
+(value, [built_value], [name])
</arguments>
<summary>
<para>
@@ -3070,6 +3096,10 @@ will be rebuilt.
files are up-to-date.)
When using timestamp source signatures, Value Nodes'
timestamps are equal to the system time when the Node is created.
+<varname>name</varname> can be provided as an alternative name
+for the resulting <literal>Value</literal> node; this is advised
+if the <varname>value</varname> parameter can't be converted to
+a string.
</para>
<para>
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index f3779c7..01baba3 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -236,7 +236,7 @@ class SubstitutionTestCase(unittest.TestCase):
"""
env = SubstitutionEnvironment(XXX = 'x')
assert 'XXX' in env
- assert not 'YYY' in env
+ assert 'YYY' not in env
def test_items(self):
"""Test the SubstitutionEnvironment items() method
@@ -1759,7 +1759,7 @@ def exists(env):
env2.Dictionary('ZZZ')[5] = 6
assert env1.Dictionary('XXX') is env2.Dictionary('XXX')
assert 4 in env2.Dictionary('YYY')
- assert not 4 in env1.Dictionary('YYY')
+ assert 4 not in env1.Dictionary('YYY')
assert 5 in env2.Dictionary('ZZZ')
assert 5 not in env1.Dictionary('ZZZ')
@@ -3289,6 +3289,10 @@ def generate(env):
v3 = env.Value('c', 'build-c')
assert v3.value == 'c', v3.value
+ v4 = env.Value(b'\x00\x0F', name='name')
+ assert v4.value == b'\x00\x0F', v4.value
+ assert v4.name == 'name', v4.name
+
def test_Environment_global_variable(self):
"""Test setting Environment variable to an Environment.Base subclass"""
@@ -3547,8 +3551,8 @@ class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
assert 'YYY' in env
assert 'YYY' in env2
assert 'YYY' in env3
- assert not 'ZZZ' in env
- assert not 'ZZZ' in env2
+ assert 'ZZZ' not in env
+ assert 'ZZZ' not in env2
assert 'ZZZ' in env3
def test_items(self):
diff --git a/src/engine/SCons/Node/AliasTests.py b/src/engine/SCons/Node/AliasTests.py
index 5d9c799..27b75b3 100644
--- a/src/engine/SCons/Node/AliasTests.py
+++ b/src/engine/SCons/Node/AliasTests.py
@@ -93,7 +93,7 @@ class AliasTestCase(unittest.TestCase):
a2 = SCons.Node.Alias.Alias('a')
assert a2.name == 'a', a2.name
- assert not a1 is a2
+ assert a1 is not a2
assert a1.name == a2.name
class AliasNodeInfoTestCase(unittest.TestCase):
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index e1d6f68..6f16256 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -1612,7 +1612,7 @@ class Dir(Base):
This clears any cached information that is invalidated by changing
the repository."""
- for node in list(self.entries.values()):
+ for node in self.entries.values():
if node != self.dir:
if node != self and isinstance(node, Dir):
node.__clearRepositoryCache(duplicate)
@@ -1623,7 +1623,7 @@ class Dir(Base):
except AttributeError:
pass
if duplicate is not None:
- node.duplicate=duplicate
+ node.duplicate = duplicate
def __resetDuplicate(self, node):
if node != self:
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 9c19481..bbfdd1b 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -3066,12 +3066,12 @@ class RepositoryTestCase(_tempdirTestCase):
assert r is d1, r
r = d2.rentry()
- assert not r is d2, r
+ assert r is not d2, r
r = str(r)
assert r == os.path.join(self.rep1, 'd2'), r
r = d3.rentry()
- assert not r is d3, r
+ assert r is not d3, r
r = str(r)
assert r == os.path.join(self.rep2, 'd3'), r
@@ -3079,12 +3079,12 @@ class RepositoryTestCase(_tempdirTestCase):
assert r is e1, r
r = e2.rentry()
- assert not r is e2, r
+ assert r is not e2, r
r = str(r)
assert r == os.path.join(self.rep1, 'e2'), r
r = e3.rentry()
- assert not r is e3, r
+ assert r is not e3, r
r = str(r)
assert r == os.path.join(self.rep2, 'e3'), r
@@ -3092,12 +3092,12 @@ class RepositoryTestCase(_tempdirTestCase):
assert r is f1, r
r = f2.rentry()
- assert not r is f2, r
+ assert r is not f2, r
r = str(r)
assert r == os.path.join(self.rep1, 'f2'), r
r = f3.rentry()
- assert not r is f3, r
+ assert r is not f3, r
r = str(r)
assert r == os.path.join(self.rep2, 'f3'), r
@@ -3127,12 +3127,12 @@ class RepositoryTestCase(_tempdirTestCase):
assert r is d1, r
r = d2.rdir()
- assert not r is d2, r
+ assert r is not d2, r
r = str(r)
assert r == os.path.join(self.rep1, 'd2'), r
r = d3.rdir()
- assert not r is d3, r
+ assert r is not d3, r
r = str(r)
assert r == os.path.join(self.rep3, 'd3'), r
@@ -3183,12 +3183,12 @@ class RepositoryTestCase(_tempdirTestCase):
assert r is f1, r
r = f2.rfile()
- assert not r is f2, r
+ assert r is not f2, r
r = str(r)
assert r == os.path.join(self.rep1, 'f2'), r
r = f3.rfile()
- assert not r is f3, r
+ assert r is not f3, r
r = f3.rstr()
assert r == os.path.join(self.rep3, 'f3'), r
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index d8179ff..8d9d3a9 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -1104,7 +1104,7 @@ class NodeTestCase(unittest.TestCase):
for kid in [n1, n3, n4, n6, n7, n9, n10, n12]:
assert kid in kids, kid
for kid in [n2, n5, n8, n11]:
- assert not kid in kids, kid
+ assert kid not in kids, kid
def test_all_children(self):
"""Test fetching all the "children" of a Node.
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index a5bcd4b..68c6ee8 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -88,7 +88,7 @@ class Value(SCons.Node.Node):
NodeInfo = ValueNodeInfo
BuildInfo = ValueBuildInfo
- def __init__(self, value, built_value=None):
+ def __init__(self, value, built_value=None, name=None):
SCons.Node.Node.__init__(self)
self.value = value
self.changed_since_last_build = 6
@@ -96,6 +96,13 @@ class Value(SCons.Node.Node):
if built_value is not None:
self.built_value = built_value
+ # Set a name so it can be a child of a node and not break
+ # its parent's implementation of Node.get_contents.
+ if name:
+ self.name = name
+ else:
+ self.name = str(value)
+
def str_for_display(self):
return repr(self.value)
@@ -177,23 +184,26 @@ class Value(SCons.Node.Node):
return contents
-def ValueWithMemo(value, built_value=None):
+def ValueWithMemo(value, built_value=None, name=None):
+ """
+ Memoized Value() node factory.
+ """
global _memo_lookup_map
# No current support for memoizing a value that needs to be built.
if built_value:
- return Value(value, built_value)
+ return Value(value, built_value, name=name)
try:
- memo_lookup_key = hash(value)
+ memo_lookup_key = hash((value, name))
except TypeError:
# Non-primitive types will hit this codepath.
- return Value(value)
+ return Value(value, name=name)
try:
return _memo_lookup_map[memo_lookup_key]
except KeyError:
- v = Value(value)
+ v = Value(value, built_value, name)
_memo_lookup_map[memo_lookup_key] = v
return v
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index dbb4ec8..51a49c0 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -64,6 +64,12 @@ class ValueTestCase(unittest.TestCase):
v2.build()
assert v2.built_value == 'faked', v2.built_value
+ v3 = SCons.Node.Python.Value(b'\x00\x0F', name='name')
+ v3.executor = fake_executor()
+ v3.build()
+ assert v3.name == 'name', v3.name
+ assert v3.built_value == 'faked', v3.built_value
+
def test_read(self):
"""Test the Value.read() method
"""
@@ -98,6 +104,9 @@ class ValueTestCase(unittest.TestCase):
assert csig == 'None', csig
+
+
+
class ValueNodeInfoTestCase(unittest.TestCase):
def test___init__(self):
"""Test ValueNodeInfo initialization"""
@@ -112,6 +121,18 @@ class ValueBuildInfoTestCase(unittest.TestCase):
bi = SCons.Node.Python.ValueBuildInfo()
+class ValueChildTestCase(unittest.TestCase):
+ def test___init__(self):
+ """Test support for a Value() being an implicit dependency of a Node"""
+ value = SCons.Node.Python.Value('v')
+ node = SCons.Node.Node()
+ node._func_get_contents = 2 # Pretend to be a Dir.
+ node.add_to_implicit([value])
+ contents = node.get_contents()
+ expected_contents = '%s %s\n' % (value.get_csig(), value.name)
+ assert contents == expected_contents
+
+
class ValueMemoTestCase(unittest.TestCase):
def test_memo(self):
"""Test memoization"""
@@ -144,6 +165,19 @@ class ValueMemoTestCase(unittest.TestCase):
v4 = SCons.Node.Python.ValueWithMemo(a)
assert v3 is not v4
+ def test_value_set_name(self):
+ """ Confirm setting name and caching takes the name into account """
+
+ v1 = SCons.Node.Python.ValueWithMemo(b'\x00\x0F', name='name')
+ v2 = SCons.Node.Python.ValueWithMemo(b'\x00\x0F', name='name2')
+ v3 = SCons.Node.Python.ValueWithMemo('Jibberish')
+
+ self.assertEqual(v1.name,'name', msg=v1.name)
+ self.assertEqual(v2.name,'name2', msg=v2.name)
+ self.assertEqual(v3.name,'Jibberish', msg=v3.name)
+ self.assertTrue(v1 is not v2, msg="v1 and v2 should be different as they have different names but same values")
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/src/engine/SCons/PathListTests.py b/src/engine/SCons/PathListTests.py
index 104be73..09b1132 100644
--- a/src/engine/SCons/PathListTests.py
+++ b/src/engine/SCons/PathListTests.py
@@ -185,7 +185,7 @@ class PathListTestCase(unittest.TestCase):
x3 = SCons.PathList.PathList('x')
- assert not x1 is x3, (x1, x3)
+ assert x1 is not x3, (x1, x3)
if __name__ == "__main__":
diff --git a/src/engine/SCons/Platform/__init__.py b/src/engine/SCons/Platform/__init__.py
index 058241d..5e9a358 100644
--- a/src/engine/SCons/Platform/__init__.py
+++ b/src/engine/SCons/Platform/__init__.py
@@ -195,7 +195,7 @@ class TempFileMunge(object):
# Default to the .lnk suffix for the benefit of the Phar Lap
# linkloc linker, which likes to append an .lnk suffix if
# none is given.
- if env.has_key('TEMPFILESUFFIX'):
+ if 'TEMPFILESUFFIX' in env:
suffix = env.subst('$TEMPFILESUFFIX')
else:
suffix = '.lnk'
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index b2a6357..50a1329 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -133,8 +133,8 @@ def CreateConfigHBuilder(env):
_stringConfigH)
sconfigHBld = SCons.Builder.Builder(action=action)
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
- for k in list(_ac_config_hs.keys()):
- env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
+ for k, v in _ac_config_hs.items():
+ env.SConfigHBuilder(k, env.Value(v))
class SConfWarning(SCons.Warnings.Warning):
@@ -717,7 +717,7 @@ class SConfBase(object):
"""Adds all the tests given in the tests dictionary to this SConf
instance
"""
- for name in list(tests.keys()):
+ for name in tests.keys():
self.AddTest(name, tests[name])
def _createDir( self, node ):
diff --git a/src/engine/SCons/SConsignTests.py b/src/engine/SCons/SConsignTests.py
index d40a7b6..782072d 100644
--- a/src/engine/SCons/SConsignTests.py
+++ b/src/engine/SCons/SConsignTests.py
@@ -337,7 +337,7 @@ class SConsignFileTestCase(SConsignTestCase):
SCons.SConsign.ForDirectory(DummyNode(test.workpath('dir')))
- assert not SCons.SConsign.DataBase is None, SCons.SConsign.DataBase
+ assert SCons.SConsign.DataBase is not None, SCons.SConsign.DataBase
assert fake_dbm.name == file, fake_dbm.name
assert fake_dbm.mode == "c", fake_dbm.mode
diff --git a/src/engine/SCons/Scanner/Python.py b/src/engine/SCons/Scanner/Python.py
new file mode 100644
index 0000000..deb2241
--- /dev/null
+++ b/src/engine/SCons/Scanner/Python.py
@@ -0,0 +1,171 @@
+"""SCons.Scanner.Python
+
+This module implements the dependency scanner for Python code.
+
+One important note about the design is that this does not take any dependencies
+upon packages or binaries in the Python installation unless they are listed in
+PYTHONPATH. To do otherwise would have required code to determine where the
+Python installation is, which is outside of the scope of a scanner like this.
+If consumers want to pick up dependencies upon these packages, they must put
+those directories in PYTHONPATH.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import itertools
+import os
+import re
+import SCons.Scanner
+
+# Capture python "from a import b" and "import a" statements.
+from_cre = re.compile(r'^\s*from\s+([^\s]+)\s+import\s+(.*)', re.M)
+import_cre = re.compile(r'^\s*import\s+([^\s]+)', re.M)
+
+
+def path_function(env, dir=None, target=None, source=None, argument=None):
+ """Retrieves a tuple with all search paths."""
+ paths = env['ENV'].get('PYTHONPATH', '').split(os.pathsep)
+ if source:
+ paths.append(source[0].dir.abspath)
+ return tuple(paths)
+
+
+def find_include_names(node):
+ """
+ Scans the node for all imports.
+
+ Returns a list of tuples. Each tuple has two elements:
+ 1. The main import (e.g. module, module.file, module.module2)
+ 2. Additional optional imports that could be functions or files
+ in the case of a "from X import Y" statement. In the case of a
+ normal "import" statement, this is None.
+ """
+ text = node.get_text_contents()
+ all_matches = []
+ matches = from_cre.findall(text)
+ if matches:
+ for match in matches:
+ imports = [i.strip() for i in match[1].split(',')]
+
+ # Add some custom logic to strip out "as" because the regex
+ # includes it.
+ last_import_split = imports[-1].split()
+ if len(last_import_split) > 1:
+ imports[-1] = last_import_split[0]
+
+ all_matches.append((match[0], imports))
+
+ matches = import_cre.findall(text)
+ if matches:
+ for match in matches:
+ all_matches.append((match, None))
+
+ return all_matches
+
+
+def scan(node, env, path=()):
+ # cache the includes list in node so we only scan it once:
+ if node.includes is not None:
+ includes = node.includes
+ else:
+ includes = find_include_names(node)
+ # Intern the names of the include files. Saves some memory
+ # if the same header is included many times.
+ node.includes = list(map(SCons.Util.silent_intern, includes))
+
+ # XXX TODO: Sort?
+ nodes = []
+ if callable(path):
+ path = path()
+ for module, imports in includes:
+ is_relative = module.startswith('.')
+ if is_relative:
+ # This is a relative include, so we must ignore PYTHONPATH.
+ module_lstripped = module.lstrip('.')
+ # One dot is current directory, two is parent, three is
+ # grandparent, etc.
+ num_parents = len(module) - len(module_lstripped) - 1
+ current_dir = node.get_dir()
+ for i in itertools.repeat(None, num_parents):
+ current_dir = current_dir.up()
+
+ search_paths = [current_dir.abspath]
+ search_string = module_lstripped
+ else:
+ search_paths = path
+ search_string = module
+
+ module_components = search_string.split('.')
+ for search_path in search_paths:
+ candidate_path = os.path.join(search_path, *module_components)
+ # The import stored in "module" could refer to a directory or file.
+ import_dirs = []
+ if os.path.isdir(candidate_path):
+ import_dirs = module_components
+
+ # Because this resolved to a directory, there is a chance that
+ # additional imports (e.g. from module import A, B) could refer
+ # to files to import.
+ if imports:
+ for imp in imports:
+ file = os.path.join(candidate_path, imp + '.py')
+ if os.path.isfile(file):
+ nodes.append(file)
+ elif os.path.isfile(candidate_path + '.py'):
+ nodes.append(candidate_path + '.py')
+ import_dirs = module_components[:-1]
+
+ # We can ignore imports because this resolved to a file. Any
+ # additional imports (e.g. from module.file import A, B) would
+ # only refer to functions in this file.
+
+ # Take a dependency on all __init__.py files from all imported
+ # packages unless it's a relative import. If it's a relative
+ # import, we don't need to take the dependency because Python
+ # requires that all referenced packages have already been imported,
+ # which means that the dependency has already been established.
+ if import_dirs and not is_relative:
+ for i in range(len(import_dirs)):
+ init_components = module_components[:i+1] + ['__init__.py']
+ init_path = os.path.join(search_path, *(init_components))
+ if os.path.isfile(init_path):
+ nodes.append(init_path)
+ break
+
+ return sorted(nodes)
+
+
+PythonSuffixes = ['.py']
+PythonScanner = SCons.Scanner.Base(scan, name='PythonScanner',
+ skeys=PythonSuffixes,
+ path_function=path_function, recursive=1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Scanner/PythonTests.py b/src/engine/SCons/Scanner/PythonTests.py
new file mode 100644
index 0000000..0d4e628
--- /dev/null
+++ b/src/engine/SCons/Scanner/PythonTests.py
@@ -0,0 +1,269 @@
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.compat
+
+import collections
+import os
+import unittest
+
+import TestCmd
+
+import SCons.Node.FS
+import SCons.Scanner.Python
+
+test = TestCmd.TestCmd(workdir='')
+test.dir_fixture('python_scanner')
+
+if os.path.normcase('foo') == os.path.normcase('FOO'):
+ my_normpath = os.path.normcase
+else:
+ my_normpath = os.path.normpath
+
+
+def deps_match(self, deps, headers):
+ global my_normpath
+ scanned = list(map(my_normpath, list(map(str, deps))))
+ expect = list(map(my_normpath, headers))
+ self.assertTrue(scanned == expect,
+ "expect %s != scanned %s" % (expect, scanned))
+
+
+# Copied from LaTeXTests.py.
+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_list(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 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)
+
+
+class PythonScannerTestPythonPath(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ env['ENV']['PYTHONPATH'] = test.workpath('')
+ path = s.path(env)
+ deps = s(env.File('imports_simple_package.py'), env, path)
+ files = ['simple_package/__init__.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestPythonCallablePath(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ env['ENV']['PYTHONPATH'] = test.workpath('')
+ deps = s(env.File('imports_simple_package.py'), env,
+ lambda : s.path(env))
+ files = ['simple_package/__init__.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportSimplePackage(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('imports_simple_package.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py']
+ deps_match(self, deps, files)
+
+ # Repeat the test in case there are any issues caching includes.
+ deps = s(node, env, path)
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportSimplePackageModule1As(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('import_simple_package_module1_as.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportSimplePackageModuleAs(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('import_simple_package_module1.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestFromImportSimplePackageModule1(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('from_import_simple_package_module1.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestFromImportSimplePackageModule1As(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('from_import_simple_package_module1_as.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestFromImportSimplePackageModulesNoSpace(
+ unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('from_import_simple_package_modules_no_space.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py',
+ 'simple_package/module2.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestFromImportSimplePackageModulesWithSpace(
+ unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('from_import_simple_package_modules_with_space.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['simple_package/__init__.py', 'simple_package/module1.py',
+ 'simple_package/module2.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestCurdirReferenceScript(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.Dir('curdir_reference').File('script.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['curdir_reference/helper.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportsNested3(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File('imports_nested3.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['nested1/__init__.py', 'nested1/nested2/__init__.py',
+ 'nested1/nested2/nested3/__init__.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportsGrandparentModule(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File(
+ '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)
+
+
+class PythonScannerTestImportsParentModule(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File(
+ 'nested1/nested2/nested3/imports_parent_module.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['nested1/nested2/module.py']
+ deps_match(self, deps, files)
+
+
+class PythonScannerTestImportsParentThenSubmodule(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment()
+ s = SCons.Scanner.Python.PythonScanner
+ node = env.File(
+ 'nested1/nested2/nested3/imports_parent_then_submodule.py')
+ path = s.path(env, source=[node])
+ deps = s(node, env, path)
+ files = ['nested1/nested2a/module.py']
+ deps_match(self, deps, files)
+
+
+if __name__ == "__main__":
+ unittest.main()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Scanner/RCTests.py b/src/engine/SCons/Scanner/RCTests.py
index 551e613..347149c 100644
--- a/src/engine/SCons/Scanner/RCTests.py
+++ b/src/engine/SCons/Scanner/RCTests.py
@@ -82,7 +82,7 @@ class DummyEnvironment(collections.UserDict):
def Dictionary(self, *args):
return self.data
- def subst(self, arg, target=None, source=None, conv=None):
+ def subst(self, strSubst, target=None, source=None, conv=None):
if strSubst[0] == '$':
return self.data[strSubst[1:]]
return strSubst
diff --git a/src/engine/SCons/Script/Interactive.py b/src/engine/SCons/Script/Interactive.py
index cc4f23c..59299f1 100644
--- a/src/engine/SCons/Script/Interactive.py
+++ b/src/engine/SCons/Script/Interactive.py
@@ -247,7 +247,7 @@ version Prints SCons version information.
while n:
n = walker.get_next()
- for node in list(seen_nodes.keys()):
+ for node in seen_nodes.keys():
# Call node.clear() to clear most of the state
node.clear()
# node.clear() doesn't reset node.state, so call
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index f9c8384..a0d7f4c 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -743,9 +743,9 @@ def _load_site_scons_dir(topdir, site_dir_name=None):
modname = os.path.basename(pathname)[:-len(sfx)]
site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
re_special = re.compile("__[^_]+__")
- for k in list(m.__dict__.keys()):
+ for k, v in m.__dict__.items():
if not re_special.match(k):
- site_m[k] = m.__dict__[k]
+ site_m[k] = v
# This is the magic.
exec(compile(fp.read(), fp.name, 'exec'), site_m)
diff --git a/src/engine/SCons/Script/Main.xml b/src/engine/SCons/Script/Main.xml
index 5c68dee..b54df0e 100644
--- a/src/engine/SCons/Script/Main.xml
+++ b/src/engine/SCons/Script/Main.xml
@@ -312,7 +312,7 @@ The options supported are:
<term><literal>cache_debug</literal></term>
<listitem>
<para>
-which corresponds to --cache-debug;
+which corresponds to <option>--cache-debug</option>;
</para>
</listitem>
</varlistentry>
@@ -320,7 +320,7 @@ which corresponds to --cache-debug;
<term><literal>cache_disable</literal></term>
<listitem>
<para>
-which corresponds to --cache-disable;
+which corresponds to <option>--cache-disable</option>;
</para>
</listitem>
</varlistentry>
@@ -328,7 +328,7 @@ which corresponds to --cache-disable;
<term><literal>cache_force</literal></term>
<listitem>
<para>
-which corresponds to --cache-force;
+which corresponds to <option>--cache-force</option>;
</para>
</listitem>
</varlistentry>
@@ -336,7 +336,7 @@ which corresponds to --cache-force;
<term><literal>cache_show</literal></term>
<listitem>
<para>
-which corresponds to --cache-show;
+which corresponds to <option>--cache-show</option>;
</para>
</listitem>
</varlistentry>
@@ -344,7 +344,8 @@ which corresponds to --cache-show;
<term><literal>clean</literal></term>
<listitem>
<para>
-which corresponds to -c, --clean and --remove;
+which corresponds to <option>-c</option>, <option>--clean</option>
+and <option>--remove</option>;
</para>
</listitem>
</varlistentry>
@@ -352,7 +353,7 @@ which corresponds to -c, --clean and --remove;
<term><literal>config</literal></term>
<listitem>
<para>
-which corresponds to --config;
+which corresponds to <option>--config</option>;
</para>
</listitem>
</varlistentry>
@@ -360,7 +361,7 @@ which corresponds to --config;
<term><literal>directory</literal></term>
<listitem>
<para>
-which corresponds to -C and --directory;
+which corresponds to <option>-C</option> and <option>--directory</option>;
</para>
</listitem>
</varlistentry>
@@ -368,7 +369,7 @@ which corresponds to -C and --directory;
<term><literal>diskcheck</literal></term>
<listitem>
<para>
-which corresponds to --diskcheck
+which corresponds to <option>--diskcheck</option>;
</para>
</listitem>
</varlistentry>
@@ -376,7 +377,7 @@ which corresponds to --diskcheck
<term><literal>duplicate</literal></term>
<listitem>
<para>
-which corresponds to --duplicate;
+which corresponds to <option>--duplicate</option>;
</para>
</listitem>
</varlistentry>
@@ -384,7 +385,7 @@ which corresponds to --duplicate;
<term><literal>file</literal></term>
<listitem>
<para>
-which corresponds to -f, --file, --makefile and --sconstruct;
+which corresponds to <option>-f</option>, <option>--file</option>, <option>--makefile</option> and <option>--sconstruct</option>;
</para>
</listitem>
</varlistentry>
@@ -392,7 +393,7 @@ which corresponds to -f, --file, --makefile and --sconstruct;
<term><literal>help</literal></term>
<listitem>
<para>
-which corresponds to -h and --help;
+which corresponds to <option>-h</option> and <option>--help</option>;
</para>
</listitem>
</varlistentry>
@@ -400,7 +401,7 @@ which corresponds to -h and --help;
<term><literal>ignore_errors</literal></term>
<listitem>
<para>
-which corresponds to --ignore-errors;
+which corresponds to <option>--ignore-errors</option>;
</para>
</listitem>
</varlistentry>
@@ -408,7 +409,7 @@ which corresponds to --ignore-errors;
<term><literal>implicit_cache</literal></term>
<listitem>
<para>
-which corresponds to --implicit-cache;
+which corresponds to <option>--implicit-cache</option>;
</para>
</listitem>
</varlistentry>
@@ -416,7 +417,7 @@ which corresponds to --implicit-cache;
<term><literal>implicit_deps_changed</literal></term>
<listitem>
<para>
-which corresponds to --implicit-deps-changed;
+which corresponds to <option>--implicit-deps-changed</option>;
</para>
</listitem>
</varlistentry>
@@ -424,7 +425,7 @@ which corresponds to --implicit-deps-changed;
<term><literal>implicit_deps_unchanged</literal></term>
<listitem>
<para>
-which corresponds to --implicit-deps-unchanged;
+which corresponds to <option>--implicit-deps-unchanged</option>;
</para>
</listitem>
</varlistentry>
@@ -432,7 +433,7 @@ which corresponds to --implicit-deps-unchanged;
<term><literal>interactive</literal></term>
<listitem>
<para>
-which corresponds to --interact and --interactive;
+which corresponds to <option>--interact</option> and <option>--interactive</option>;
</para>
</listitem>
</varlistentry>
@@ -440,7 +441,7 @@ which corresponds to --interact and --interactive;
<term><literal>keep_going</literal></term>
<listitem>
<para>
-which corresponds to -k and --keep-going;
+which corresponds to <option>-k</option> and <option>--keep-going</option>;
</para>
</listitem>
</varlistentry>
@@ -448,7 +449,7 @@ which corresponds to -k and --keep-going;
<term><literal>max_drift</literal></term>
<listitem>
<para>
-which corresponds to --max-drift;
+which corresponds to <option>--max-drift</option>;
</para>
</listitem>
</varlistentry>
@@ -456,7 +457,9 @@ which corresponds to --max-drift;
<term><literal>no_exec</literal></term>
<listitem>
<para>
-which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
+which corresponds to <option>-n</option>,
+<option>--no-exec</option>, <option>--just-print</option>,
+<option>--dry-run</option> and <option>--recon</option>;
</para>
</listitem>
</varlistentry>
@@ -464,7 +467,7 @@ which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
<term><literal>no_site_dir</literal></term>
<listitem>
<para>
-which corresponds to --no-site-dir;
+which corresponds to <option>--no-site-dir</option>;
</para>
</listitem>
</varlistentry>
@@ -472,7 +475,7 @@ which corresponds to --no-site-dir;
<term><literal>num_jobs</literal></term>
<listitem>
<para>
-which corresponds to -j and --jobs;
+which corresponds to <option>-j</option> and <option>--jobs</option>;
</para>
</listitem>
</varlistentry>
@@ -480,7 +483,7 @@ which corresponds to -j and --jobs;
<term><literal>profile_file</literal></term>
<listitem>
<para>
-which corresponds to --profile;
+which corresponds to <option>--profile</option>;
</para>
</listitem>
</varlistentry>
@@ -488,7 +491,7 @@ which corresponds to --profile;
<term><literal>question</literal></term>
<listitem>
<para>
-which corresponds to -q and --question;
+which corresponds to <option>-q</option> and <option>--question</option>;
</para>
</listitem>
</varlistentry>
@@ -496,7 +499,7 @@ which corresponds to -q and --question;
<term><literal>random</literal></term>
<listitem>
<para>
-which corresponds to --random;
+which corresponds to <option>--random</option>;
</para>
</listitem>
</varlistentry>
@@ -504,7 +507,7 @@ which corresponds to --random;
<term><literal>repository</literal></term>
<listitem>
<para>
-which corresponds to -Y, --repository and --srcdir;
+which corresponds to <option>-Y</option>, <option>--repository</option> and <option>--srcdir</option>;
</para>
</listitem>
</varlistentry>
@@ -512,7 +515,7 @@ which corresponds to -Y, --repository and --srcdir;
<term><literal>silent</literal></term>
<listitem>
<para>
-which corresponds to -s, --silent and --quiet;
+which corresponds to <option>-s</option>, <option>--silent</option> and <option>--quiet</option>;
</para>
</listitem>
</varlistentry>
@@ -520,7 +523,7 @@ which corresponds to -s, --silent and --quiet;
<term><literal>site_dir</literal></term>
<listitem>
<para>
-which corresponds to --site-dir;
+which corresponds to <option>--site-dir</option>;
</para>
</listitem>
</varlistentry>
@@ -528,7 +531,7 @@ which corresponds to --site-dir;
<term><literal>stack_size</literal></term>
<listitem>
<para>
-which corresponds to --stack-size;
+which corresponds to <option>--stack-size</option>;
</para>
</listitem>
</varlistentry>
@@ -536,7 +539,7 @@ which corresponds to --stack-size;
<term><literal>taskmastertrace_file</literal></term>
<listitem>
<para>
-which corresponds to --taskmastertrace; and
+which corresponds to <option>--taskmastertrace</option>; and
</para>
</listitem>
</varlistentry>
@@ -544,7 +547,7 @@ which corresponds to --taskmastertrace; and
<term><literal>warn</literal></term>
<listitem>
<para>
-which corresponds to --warn and --warning.
+which corresponds to <option>--warn</option> and <option>--warning</option>.
</para>
</listitem>
</varlistentry>
@@ -553,7 +556,7 @@ which corresponds to --warn and --warning.
<para>
See the documentation for the
-corresponding command line object for information about each specific
+corresponding command line option for information about each specific
option.
</para>
</summary>
@@ -749,7 +752,8 @@ line options from a SConscript file. The options supported are:
<term><literal>clean</literal></term>
<listitem>
<para>
-which corresponds to -c, --clean and --remove;
+which corresponds to <option>-c</option>, <option>--clean</option>
+and <option>--remove</option>;
</para>
</listitem>
</varlistentry>
@@ -757,7 +761,7 @@ which corresponds to -c, --clean and --remove;
<term><literal>duplicate</literal></term>
<listitem>
<para>
-which corresponds to --duplicate;
+which corresponds to <option>--duplicate</option>;
</para>
</listitem>
</varlistentry>
@@ -765,7 +769,7 @@ which corresponds to --duplicate;
<term><literal>help</literal></term>
<listitem>
<para>
-which corresponds to -h and --help;
+which corresponds to <option>-h</option> and <option>--help</option>;
</para>
</listitem>
</varlistentry>
@@ -773,7 +777,7 @@ which corresponds to -h and --help;
<term><literal>implicit_cache</literal></term>
<listitem>
<para>
-which corresponds to --implicit-cache;
+which corresponds to <option>--implicit-cache</option>;
</para>
</listitem>
</varlistentry>
@@ -781,7 +785,7 @@ which corresponds to --implicit-cache;
<term><literal>max_drift</literal></term>
<listitem>
<para>
-which corresponds to --max-drift;
+which corresponds to <option>--max-drift</option>;
</para>
</listitem>
</varlistentry>
@@ -789,7 +793,9 @@ which corresponds to --max-drift;
<term><literal>no_exec</literal></term>
<listitem>
<para>
-which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
+which corresponds to <option>-n</option>, <option>--no-exec</option>,
+<option>--just-print</option>, <option>--dry-run</option>
+and <option>--recon</option>;
</para>
</listitem>
</varlistentry>
@@ -797,7 +803,7 @@ which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
<term><literal>num_jobs</literal></term>
<listitem>
<para>
-which corresponds to -j and --jobs;
+which corresponds to <option>-j</option> and <option>--jobs</option>;
</para>
</listitem>
</varlistentry>
@@ -805,7 +811,7 @@ which corresponds to -j and --jobs;
<term><literal>random</literal></term>
<listitem>
<para>
-which corresponds to --random; and
+which corresponds to <option>--random</option>; and
</para>
</listitem>
</varlistentry>
@@ -813,7 +819,7 @@ which corresponds to --random; and
<term><literal>silent</literal></term>
<listitem>
<para>
-which corresponds to --silent.
+which corresponds to <option>--silent</option>.
</para>
</listitem>
</varlistentry>
@@ -830,7 +836,7 @@ which corresponds to --stack-size.
<para>
See the documentation for the
-corresponding command line object for information about each specific
+corresponding command line option for information about each specific
option.
</para>
diff --git a/src/engine/SCons/Script/SConscript.xml b/src/engine/SCons/Script/SConscript.xml
index 874c110..a1e0129 100644
--- a/src/engine/SCons/Script/SConscript.xml
+++ b/src/engine/SCons/Script/SConscript.xml
@@ -252,16 +252,16 @@ This specifies help text to be printed if the
<option>-h</option>
argument is given to
&scons;.
-If
+If
&f-Help;
-is called multiple times, the text is appended together in the order that
+is called multiple times, the text is appended together in the order that
&f-Help;
-is called. With append set to False, any
+is called. With append set to False, any
&f-Help;
-text generated with
+text generated with
&f-AddOption;
is clobbered. If append is True, the AddOption help is prepended to the help
-string, thus preserving the
+string, thus preserving the
<option>-h</option>
message.
</para>
@@ -393,7 +393,7 @@ A single script may be specified as a string;
multiple scripts must be specified as a list
(either explicitly or as created by
a function like
-&f-Split;).
+&f-link-Split;).
Examples:
</para>
<example_commands>
diff --git a/src/engine/SCons/Subst.py b/src/engine/SCons/Subst.py
index 664cd6c..a1ef053 100644
--- a/src/engine/SCons/Subst.py
+++ b/src/engine/SCons/Subst.py
@@ -375,23 +375,29 @@ class StringSubber(object):
if key[0] == '{' or '.' in key:
if key[0] == '{':
key = key[1:-1]
- try:
- s = eval(key, self.gvars, lvars)
- except KeyboardInterrupt:
- raise
- except Exception as e:
- if e.__class__ in AllowableExceptions:
- return ''
- raise_exception(e, lvars['TARGETS'], s)
+
+ # Store for error messages if we fail to expand the
+ # value
+ old_s = s
+ s = None
+ if key in lvars:
+ s = lvars[key]
+ elif key in self.gvars:
+ s = self.gvars[key]
else:
- if key in lvars:
- s = lvars[key]
- elif key in self.gvars:
- s = self.gvars[key]
- elif NameError not in AllowableExceptions:
- raise_exception(NameError(key), lvars['TARGETS'], s)
- else:
- return ''
+ try:
+ s = eval(key, self.gvars, lvars)
+ except KeyboardInterrupt:
+ raise
+ except Exception as e:
+ if e.__class__ in AllowableExceptions:
+ return ''
+ raise_exception(e, lvars['TARGETS'], old_s)
+
+ if s is None and NameError not in AllowableExceptions:
+ raise_exception(NameError(key), lvars['TARGETS'], old_s)
+ elif s is None:
+ return ''
# Before re-expanding the result, handle
# recursive expansion by copying the local
@@ -493,6 +499,21 @@ class ListSubber(collections.UserList):
self.in_strip = None
self.next_line()
+ def expanded(self, s):
+ """Determines if the string s requires further expansion.
+
+ Due to the implementation of ListSubber expand will call
+ itself 2 additional times for an already expanded string. This
+ method is used to determine if a string is already fully
+ expanded and if so exit the loop early to prevent these
+ recursive calls.
+ """
+ if not is_String(s) or isinstance(s, CmdStringHolder):
+ return False
+
+ s = str(s) # in case it's a UserString
+ return _separate_args.findall(s) is None
+
def expand(self, s, lvars, within_list):
"""Expand a single "token" as necessary, appending the
expansion to the current result.
@@ -524,23 +545,35 @@ class ListSubber(collections.UserList):
if key[0] == '{' or key.find('.') >= 0:
if key[0] == '{':
key = key[1:-1]
- try:
- s = eval(key, self.gvars, lvars)
- except KeyboardInterrupt:
- raise
- except Exception as e:
- if e.__class__ in AllowableExceptions:
- return
- raise_exception(e, lvars['TARGETS'], s)
+
+ # Store for error messages if we fail to expand the
+ # value
+ old_s = s
+ s = None
+ if key in lvars:
+ s = lvars[key]
+ elif key in self.gvars:
+ s = self.gvars[key]
else:
- if key in lvars:
- s = lvars[key]
- elif key in self.gvars:
- s = self.gvars[key]
- elif NameError not in AllowableExceptions:
- raise_exception(NameError(), lvars['TARGETS'], s)
- else:
- return
+ try:
+ s = eval(key, self.gvars, lvars)
+ except KeyboardInterrupt:
+ raise
+ except Exception as e:
+ if e.__class__ in AllowableExceptions:
+ return
+ raise_exception(e, lvars['TARGETS'], old_s)
+
+ if s is None and NameError not in AllowableExceptions:
+ raise_exception(NameError(), lvars['TARGETS'], old_s)
+ elif s is None:
+ return
+
+ # If the string is already full expanded there's no
+ # need to continue recursion.
+ if self.expanded(s):
+ self.append(s)
+ return
# Before re-expanding the result, handle
# recursive expansion by copying the local
diff --git a/src/engine/SCons/Subst.xml b/src/engine/SCons/Subst.xml
index 980a9ad..77372ce 100644
--- a/src/engine/SCons/Subst.xml
+++ b/src/engine/SCons/Subst.xml
@@ -39,7 +39,7 @@ or
<literal>IndexError</literal>
exception will expand to a
<literal>''</literal>
-(a null string) and not cause scons to fail.
+(an empty string) and not cause scons to fail.
All exceptions not in the specified list
will generate an error message
and terminate processing.
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 06fc94c..1e5776c 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -792,7 +792,7 @@ class Taskmaster(object):
self.ready_exc = None
T = self.trace
- if T: T.write(SCons.Util.UnicodeType('\n') + self.trace_message('Looking for a node to evaluate'))
+ if T: T.write('\n' + self.trace_message('Looking for a node to evaluate'))
while True:
node = self.next_candidate()
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index c0c77b0..1a47230 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -146,7 +146,7 @@ class Node(object):
pass
def has_builder(self):
- return not self.builder is None
+ return self.builder is not None
def is_derived(self):
return self.has_builder or self.side_effect
@@ -935,7 +935,7 @@ class TaskmasterTestCase(unittest.TestCase):
except SCons.Errors.UserError:
pass
else:
- raise TestFailed("did not catch expected UserError")
+ self.fail("did not catch expected UserError")
def raise_BuildError():
raise SCons.Errors.BuildError
@@ -948,7 +948,7 @@ class TaskmasterTestCase(unittest.TestCase):
except SCons.Errors.BuildError:
pass
else:
- raise TestFailed("did not catch expected BuildError")
+ self.fail("did not catch expected BuildError")
# On a generic (non-BuildError) exception from a Builder,
# the target should throw a BuildError exception with the
@@ -968,7 +968,7 @@ class TaskmasterTestCase(unittest.TestCase):
exc_traceback = sys.exc_info()[2]
assert isinstance(e.exc_info[2], type(exc_traceback)), e.exc_info[2]
else:
- raise TestFailed("did not catch expected BuildError")
+ self.fail("did not catch expected BuildError")
built_text = None
cache_text = []
@@ -1049,7 +1049,7 @@ class TaskmasterTestCase(unittest.TestCase):
assert cache_text == ["n1 retrieved"], cache_text
# If no binfo exists anymore, something has gone wrong...
has_binfo = hasattr(n1, 'binfo')
- assert has_binfo == True, has_binfo
+ assert has_binfo, has_binfo
def test_exception(self):
"""Test generic Taskmaster exception handling
diff --git a/src/engine/SCons/Tool/DCommon.xml b/src/engine/SCons/Tool/DCommon.xml
index 7cc47da..6d907c6 100644
--- a/src/engine/SCons/Tool/DCommon.xml
+++ b/src/engine/SCons/Tool/DCommon.xml
@@ -27,6 +27,7 @@ See its __doc__ string for a discussion of the format.
<summary>
<para>
The D compiler to use.
+See also &cv-link-SHDC; for compiling to shared objects.
</para>
</summary>
</cvar>
@@ -37,6 +38,18 @@ The D compiler to use.
The command line used to compile a D file to an object file.
Any options specified in the &cv-link-DFLAGS; construction variable
is included on this command line.
+See also &cv-link-SHDCOM; for compiling to shared objects.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DCOMSTR">
+<summary>
+<para>
+If set, the string displayed when a D source file
+is compiled to a (static) object file.
+If not set, then &cv-link-DCOM; (the command line) is displayed.
+See also &cv-link-SHDCOMSTR; for compiling to shared objects.
</para>
</summary>
</cvar>
@@ -181,6 +194,7 @@ DLIBLINKSUFFIX.
<summary>
<para>
Name of the linker to use for linking systems including D sources.
+See also &cv-link-SHDLINK; for linking shared objects.
</para>
</summary>
</cvar>
@@ -189,6 +203,7 @@ Name of the linker to use for linking systems including D sources.
<summary>
<para>
The command line to use when linking systems including D sources.
+See also &cv-link-SHDLINKCOM; for linking shared objects.
</para>
</summary>
</cvar>
@@ -197,6 +212,7 @@ The command line to use when linking systems including D sources.
<summary>
<para>
List of linker flags.
+See also &cv-link-SHDLINKFLAGS; for linking shared objects.
</para>
</summary>
</cvar>
@@ -278,6 +294,7 @@ DVERSUFFIX.
<para>
The name of the compiler to use when compiling D source
destined to be in a shared objects.
+See also &cv-link-DC; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -286,6 +303,18 @@ destined to be in a shared objects.
<summary>
<para>
The command line to use when compiling code to be part of shared objects.
+See also &cv-link-DCOM; for compiling to static objects.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDCOMSTR">
+<summary>
+<para>
+If set, the string displayed when a D source file
+is compiled to a (shared) object file.
+If not set, then &cv-link-SHDCOM; (the command line) is displayed.
+See also &cv-link-DCOMSTR; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -311,6 +340,7 @@ SHDLIBVERSIONFLAGS.
<para>
The linker to use when creating shared objects for code bases
include D sources.
+See also &cv-link-DLINK; for linking static objects.
</para>
</summary>
</cvar>
@@ -319,6 +349,7 @@ include D sources.
<summary>
<para>
The command line to use when generating shared objects.
+See also &cv-link-DLINKCOM; for linking static objects.
</para>
</summary>
</cvar>
@@ -327,6 +358,7 @@ The command line to use when generating shared objects.
<summary>
<para>
The list of flags to use when generating a shared object.
+See also &cv-link-DLINKFLAGS; for linking static objects.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/MSCommon/common.py b/src/engine/SCons/Tool/MSCommon/common.py
index 386f445..4ce605b 100644
--- a/src/engine/SCons/Tool/MSCommon/common.py
+++ b/src/engine/SCons/Tool/MSCommon/common.py
@@ -152,8 +152,8 @@ def normalize_env(env, keys, force=False):
Note: the environment is copied."""
normenv = {}
if env:
- for k in list(env.keys()):
- normenv[k] = copy.deepcopy(env[k])
+ for k, v in env.items():
+ normenv[k] = copy.deepcopy(v)
for k in keys:
if k in os.environ and (force or k not in normenv):
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 14306ab..76a0913 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -1130,7 +1130,7 @@ class ToolInitializer(object):
so we no longer copy and re-bind them when the construction
environment gets cloned.
"""
- for method in list(self.methods.values()):
+ for method in self.methods.values():
env.RemoveMethod(method)
def apply_tools(self, env):
@@ -1312,6 +1312,8 @@ def tool_list(platform, env):
'tar', 'zip',
# File builders (text)
'textfile',
+ # Python scanner tool
+ 'python',
], env)
tools = ([linker, c_compiler, cxx_compiler,
diff --git a/src/engine/SCons/Tool/c++.xml b/src/engine/SCons/Tool/c++.xml
index b59816b..019821c 100644
--- a/src/engine/SCons/Tool/c++.xml
+++ b/src/engine/SCons/Tool/c++.xml
@@ -47,6 +47,7 @@ Sets construction variables for generic POSIX C++ compilers.
</sets>
<uses>
<item>CXXCOMSTR</item>
+<item>SHCXXCOMSTR</item>
</uses>
</tool>
@@ -54,6 +55,7 @@ Sets construction variables for generic POSIX C++ compilers.
<summary>
<para>
The C++ compiler.
+See also &cv-link-SHCXX; for compiling to shared objects..
</para>
</summary>
</cvar>
@@ -65,6 +67,7 @@ The command line used to compile a C++ source file to an object file.
Any options specified in the &cv-link-CXXFLAGS; and
&cv-link-CPPFLAGS; construction variables
are included on this command line.
+See also &cv-link-SHCXXCOM; for compiling to shared objects..
</para>
</summary>
</cvar>
@@ -72,9 +75,10 @@ are included on this command line.
<cvar name="CXXCOMSTR">
<summary>
<para>
-The string displayed when a C++ source file
+If set, the string displayed when a C++ source file
is compiled to a (static) object file.
-If this is not set, then &cv-link-CXXCOM; (the command line) is displayed.
+If not set, then &cv-link-CXXCOM; (the command line) is displayed.
+See also &cv-link-SHCXXCOMSTR; for compiling to shared objects..
</para>
<example_commands>
@@ -91,6 +95,7 @@ By default, this includes the value of &cv-link-CCFLAGS;,
so that setting &cv-CCFLAGS; affects both C and C++ compilation.
If you want to add C++-specific flags,
you must set or override the value of &cv-link-CXXFLAGS;.
+See also &cv-link-SHCXXFLAGS; for compiling to shared objects..
</para>
</summary>
</cvar>
@@ -99,6 +104,7 @@ you must set or override the value of &cv-link-CXXFLAGS;.
<summary>
<para>
The C++ compiler used for generating shared-library objects.
+See also &cv-link-CXX; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -111,6 +117,7 @@ to a shared-library object file.
Any options specified in the &cv-link-SHCXXFLAGS; and
&cv-link-CPPFLAGS; construction variables
are included on this command line.
+See also &cv-link-CXXCOM; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -118,9 +125,10 @@ are included on this command line.
<cvar name="SHCXXCOMSTR">
<summary>
<para>
-The string displayed when a C++ source file
+If set, the string displayed when a C++ source file
is compiled to a shared object file.
-If this is not set, then &cv-link-SHCXXCOM; (the command line) is displayed.
+If not set, then &cv-link-SHCXXCOM; (the command line) is displayed.
+See also &cv-link-CXXCOMSTR; for compiling to static objects.
</para>
<example_commands>
@@ -134,6 +142,7 @@ env = Environment(SHCXXCOMSTR = "Compiling shared object $TARGET")
<para>
Options that are passed to the C++ compiler
to generate shared-library objects.
+See also &cv-link-CXXFLAGS; for compiling to static objects.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/cc.xml b/src/engine/SCons/Tool/cc.xml
index 06e73ff..e47cf2d 100644
--- a/src/engine/SCons/Tool/cc.xml
+++ b/src/engine/SCons/Tool/cc.xml
@@ -51,6 +51,8 @@ Sets construction variables for generic POSIX C compilers.
</sets>
<uses>
<item>PLATFORM</item>
+<item>CCCOMSTR</item>
+<item>SHCCCOMSTR</item>
</uses>
</tool>
@@ -67,8 +69,8 @@ The C compiler.
<para>
The command line used to compile a C source file to a (static) object
file. Any options specified in the &cv-link-CFLAGS;, &cv-link-CCFLAGS; and
-&cv-link-CPPFLAGS; construction variables are included on this command
-line.
+&cv-link-CPPFLAGS; construction variables are included on this command line.
+See also &cv-link-SHCCCOM; for compiling to shared objects.
</para>
</summary>
</cvar>
@@ -76,9 +78,10 @@ line.
<cvar name="CCCOMSTR">
<summary>
<para>
-The string displayed when a C source file
+If set, the string displayed when a C source file
is compiled to a (static) object file.
-If this is not set, then &cv-link-CCCOM; (the command line) is displayed.
+If not set, then &cv-link-CCCOM; (the command line) is displayed.
+See also &cv-link-SHCCCOMSTR; for compiling to shared objects.
</para>
<example_commands>
@@ -91,6 +94,7 @@ env = Environment(CCCOMSTR = "Compiling static object $TARGET")
<summary>
<para>
General options that are passed to the C and C++ compilers.
+See also &cv-link-SHCCFLAGS; for compiling to shared objects.
</para>
</summary>
</cvar>
@@ -99,6 +103,7 @@ General options that are passed to the C and C++ compilers.
<summary>
<para>
General options that are passed to the C compiler (C only; not C++).
+See also &cv-link-SHCFLAGS; for compiling to shared objects.
</para>
</summary>
</cvar>
@@ -156,6 +161,7 @@ The default list is:
<summary>
<para>
The C compiler used for generating shared-library objects.
+See also &cv-link-CC; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -169,6 +175,7 @@ Any options specified in the &cv-link-SHCFLAGS;,
&cv-link-SHCCFLAGS; and
&cv-link-CPPFLAGS; construction variables
are included on this command line.
+See also &cv-link-CCCOM; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -176,9 +183,10 @@ are included on this command line.
<cvar name="SHCCCOMSTR">
<summary>
<para>
-The string displayed when a C source file
+If set, the string displayed when a C source file
is compiled to a shared object file.
-If this is not set, then &cv-link-SHCCCOM; (the command line) is displayed.
+If not set, then &cv-link-SHCCCOM; (the command line) is displayed.
+See also &cv-link-CCCOMSTR; for compiling to static objects.
</para>
<example_commands>
@@ -192,6 +200,7 @@ env = Environment(SHCCCOMSTR = "Compiling shared object $TARGET")
<para>
Options that are passed to the C and C++ compilers
to generate shared-library objects.
+See also &cv-link-CCFLAGS; for compiling to static objects.
</para>
</summary>
</cvar>
@@ -201,6 +210,7 @@ to generate shared-library objects.
<para>
Options that are passed to the C compiler (only; not C++)
to generate shared-library objects.
+See also &cv-link-CFLAGS; for compiling to static objects.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/f03.xml b/src/engine/SCons/Tool/f03.xml
index c020b81..61c02ef 100644
--- a/src/engine/SCons/Tool/f03.xml
+++ b/src/engine/SCons/Tool/f03.xml
@@ -77,9 +77,9 @@ for all Fortran versions.
<cvar name="F03COMSTR">
<summary>
<para>
-The string displayed when a Fortran 03 source file
+If set, the string displayed when a Fortran 03 source file
is compiled to an object file.
-If this is not set, then &cv-link-F03COM; or &cv-link-FORTRANCOM;
+If not set, then &cv-link-F03COM; or &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -217,10 +217,10 @@ for all Fortran versions.
<cvar name="F03PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 03 source file
+If set, the string displayed when a Fortran 03 source file
is compiled to an object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-F03PPCOM; or &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-F03PPCOM; or &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -256,9 +256,9 @@ for all Fortran versions.
<cvar name="SHF03COMSTR">
<summary>
<para>
-The string displayed when a Fortran 03 source file
+If set, the string displayed when a Fortran 03 source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHF03COM; or &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHF03COM; or &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -299,10 +299,10 @@ for all Fortran versions.
<cvar name="SHF03PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 03 source file
+If set, the string displayed when a Fortran 03 source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHF03PPCOM; or &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHF03PPCOM; or &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/f08.xml b/src/engine/SCons/Tool/f08.xml
index 802e4cc..a56d60b 100644
--- a/src/engine/SCons/Tool/f08.xml
+++ b/src/engine/SCons/Tool/f08.xml
@@ -77,9 +77,9 @@ for all Fortran versions.
<cvar name="F08COMSTR">
<summary>
<para>
-The string displayed when a Fortran 08 source file
+If set, the string displayed when a Fortran 08 source file
is compiled to an object file.
-If this is not set, then &cv-link-F08COM; or &cv-link-FORTRANCOM;
+If not set, then &cv-link-F08COM; or &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -217,10 +217,10 @@ for all Fortran versions.
<cvar name="F08PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 08 source file
+If set, the string displayed when a Fortran 08 source file
is compiled to an object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-F08PPCOM; or &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-F08PPCOM; or &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -256,9 +256,9 @@ for all Fortran versions.
<cvar name="SHF08COMSTR">
<summary>
<para>
-The string displayed when a Fortran 08 source file
+If set, the string displayed when a Fortran 08 source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHF08COM; or &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHF08COM; or &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -299,10 +299,10 @@ for all Fortran versions.
<cvar name="SHF08PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 08 source file
+If set, the string displayed when a Fortran 08 source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHF08PPCOM; or &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHF08PPCOM; or &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/f77.xml b/src/engine/SCons/Tool/f77.xml
index abfc4a2..70ec721 100644
--- a/src/engine/SCons/Tool/f77.xml
+++ b/src/engine/SCons/Tool/f77.xml
@@ -108,9 +108,9 @@ F77 dialect will be used. By default, this is empty
<cvar name="F77COMSTR">
<summary>
<para>
-The string displayed when a Fortran 77 source file
+If set, the string displayed when a Fortran 77 source file
is compiled to an object file.
-If this is not set, then &cv-link-F77COM; or &cv-link-FORTRANCOM;
+If not set, then &cv-link-F77COM; or &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -230,10 +230,10 @@ for all Fortran versions.
<cvar name="F77PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 77 source file
+If set, the string displayed when a Fortran 77 source file
is compiled to an object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-F77PPCOM; or &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-F77PPCOM; or &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -269,9 +269,9 @@ for all Fortran versions.
<cvar name="SHF77COMSTR">
<summary>
<para>
-The string displayed when a Fortran 77 source file
+If set, the string displayed when a Fortran 77 source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHF77COM; or &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHF77COM; or &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -312,10 +312,10 @@ for all Fortran versions.
<cvar name="SHF77PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 77 source file
+If set, the string displayed when a Fortran 77 source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHF77PPCOM; or &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHF77PPCOM; or &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/f90.xml b/src/engine/SCons/Tool/f90.xml
index 94249a3..64dc6e1 100644
--- a/src/engine/SCons/Tool/f90.xml
+++ b/src/engine/SCons/Tool/f90.xml
@@ -77,9 +77,9 @@ for all Fortran versions.
<cvar name="F90COMSTR">
<summary>
<para>
-The string displayed when a Fortran 90 source file
+If set, the string displayed when a Fortran 90 source file
is compiled to an object file.
-If this is not set, then &cv-link-F90COM; or &cv-link-FORTRANCOM;
+If not set, then &cv-link-F90COM; or &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -217,9 +217,9 @@ for all Fortran versions.
<cvar name="F90PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 90 source file
+If set, the string displayed when a Fortran 90 source file
is compiled after first running the file through the C preprocessor.
-If this is not set, then &cv-link-F90PPCOM; or &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-F90PPCOM; or &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -255,9 +255,9 @@ for all Fortran versions.
<cvar name="SHF90COMSTR">
<summary>
<para>
-The string displayed when a Fortran 90 source file
+If set, the string displayed when a Fortran 90 source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHF90COM; or &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHF90COM; or &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -298,10 +298,10 @@ for all Fortran versions.
<cvar name="SHF90PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 90 source file
+If set, the string displayed when a Fortran 90 source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHF90PPCOM; or &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHF90PPCOM; or &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/f95.xml b/src/engine/SCons/Tool/f95.xml
index 4a4db46..4bda653 100644
--- a/src/engine/SCons/Tool/f95.xml
+++ b/src/engine/SCons/Tool/f95.xml
@@ -77,9 +77,9 @@ for all Fortran versions.
<cvar name="F95COMSTR">
<summary>
<para>
-The string displayed when a Fortran 95 source file
+If set, the string displayed when a Fortran 95 source file
is compiled to an object file.
-If this is not set, then &cv-link-F95COM; or &cv-link-FORTRANCOM;
+If not set, then &cv-link-F95COM; or &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -217,10 +217,10 @@ for all Fortran versions.
<cvar name="F95PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 95 source file
+If set, the string displayed when a Fortran 95 source file
is compiled to an object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-F95PPCOM; or &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-F95PPCOM; or &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -256,9 +256,9 @@ for all Fortran versions.
<cvar name="SHF95COMSTR">
<summary>
<para>
-The string displayed when a Fortran 95 source file
+If set, the string displayed when a Fortran 95 source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHF95COM; or &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHF95COM; or &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -299,10 +299,10 @@ for all Fortran versions.
<cvar name="SHF95PPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran 95 source file
+If set, the string displayed when a Fortran 95 source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHF95PPCOM; or &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHF95PPCOM; or &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/fortran.xml b/src/engine/SCons/Tool/fortran.xml
index 53bcfb1..7b3c51f 100644
--- a/src/engine/SCons/Tool/fortran.xml
+++ b/src/engine/SCons/Tool/fortran.xml
@@ -73,9 +73,9 @@ are included on this command line.
<cvar name="FORTRANCOMSTR">
<summary>
<para>
-The string displayed when a Fortran source file
+If set, the string displayed when a Fortran source file
is compiled to an object file.
-If this is not set, then &cv-link-FORTRANCOM;
+If not set, then &cv-link-FORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -285,10 +285,10 @@ construction variables are included on this command line.
<cvar name="FORTRANPPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran source file
+If set, the string displayed when a Fortran source file
is compiled to an object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-FORTRANPPCOM;
+If not set, then &cv-link-FORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
@@ -330,9 +330,9 @@ to a shared-library object file.
<cvar name="SHFORTRANCOMSTR">
<summary>
<para>
-The string displayed when a Fortran source file
+If set, the string displayed when a Fortran source file
is compiled to a shared-library object file.
-If this is not set, then &cv-link-SHFORTRANCOM;
+If not set, then &cv-link-SHFORTRANCOM;
(the command line) is displayed.
</para>
</summary>
@@ -364,10 +364,10 @@ are included on this command line.
<cvar name="SHFORTRANPPCOMSTR">
<summary>
<para>
-The string displayed when a Fortran source file
+If set, the string displayed when a Fortran source file
is compiled to a shared-library object file
after first running the file through the C preprocessor.
-If this is not set, then &cv-link-SHFORTRANPPCOM;
+If not set, then &cv-link-SHFORTRANPPCOM;
(the command line) is displayed.
</para>
</summary>
diff --git a/src/engine/SCons/Tool/install.xml b/src/engine/SCons/Tool/install.xml
index 150308b..ce70d91 100644
--- a/src/engine/SCons/Tool/install.xml
+++ b/src/engine/SCons/Tool/install.xml
@@ -50,10 +50,24 @@ a builder.
</para>
<example_commands>
-env.Install('/usr/local/bin', source = ['foo', 'bar'])
+env.Install(target='/usr/local/bin', source=['foo', 'bar'])
</example_commands>
<para>
+Note that if target paths chosen for the
+&Install; builder (and the related &InstallAs; and
+&InstallVersionedLib; builders) are outside the
+project tree, such as in the example above,
+they may not be selected for "building" by default,
+since in the absence of other instructions
+&scons; builds targets that are underneath the top directory
+(the directory that contains the &SConstruct; file,
+usually the current directory).
+Use command line targets or the &Default; function
+in this case.
+</para>
+
+<para>
If the <option>--install-sandbox</option> command line
option is given, the target directory will be prefixed
by the directory path specified.
@@ -86,12 +100,16 @@ arguments list different numbers of files or directories.
</para>
<example_commands>
-env.InstallAs(target = '/usr/local/bin/foo',
- source = 'foo_debug')
-env.InstallAs(target = ['../lib/libfoo.a', '../lib/libbar.a'],
- source = ['libFOO.a', 'libBAR.a'])
+env.InstallAs(target='/usr/local/bin/foo',
+ source='foo_debug')
+env.InstallAs(target=['../lib/libfoo.a', '../lib/libbar.a'],
+ source=['libFOO.a', 'libBAR.a'])
</example_commands>
+<para>
+See the note under &Install;.
+</para>
+
</summary>
</builder>
@@ -103,9 +121,14 @@ architecture will be generated based on symlinks of the source library.
</para>
<example_commands>
-env.InstallVersionedLib(target = '/usr/local/bin/foo',
- source = 'libxyz.1.5.2.so')
+env.InstallVersionedLib(target='/usr/local/bin/foo',
+ source='libxyz.1.5.2.so')
</example_commands>
+
+<para>
+See the note under &Install;.
+</para>
+
</summary>
</builder>
diff --git a/src/engine/SCons/Tool/intelc.py b/src/engine/SCons/Tool/intelc.py
index 5a101b4..778cba1 100644
--- a/src/engine/SCons/Tool/intelc.py
+++ b/src/engine/SCons/Tool/intelc.py
@@ -495,15 +495,15 @@ def generate(env, version=None, abi=None, topdir=None, verbose=0):
'LIB' : libdir,
'PATH' : bindir,
'LD_LIBRARY_PATH' : libdir}
- for p in list(paths.keys()):
- env.PrependENVPath(p, os.path.join(topdir, paths[p]))
+ for p, v in paths.items():
+ env.PrependENVPath(p, os.path.join(topdir, v))
if is_mac:
paths={'INCLUDE' : 'include',
'LIB' : libdir,
'PATH' : bindir,
'LD_LIBRARY_PATH' : libdir}
- for p in list(paths.keys()):
- env.PrependENVPath(p, os.path.join(topdir, paths[p]))
+ for p, v in paths.items():
+ env.PrependENVPath(p, os.path.join(topdir, v))
if is_windows:
# env key reg valname default subdir of top
paths=(('INCLUDE', 'IncludeDir', 'Include'),
diff --git a/src/engine/SCons/Tool/javac.xml b/src/engine/SCons/Tool/javac.xml
index bc89342..893130b 100644
--- a/src/engine/SCons/Tool/javac.xml
+++ b/src/engine/SCons/Tool/javac.xml
@@ -95,9 +95,9 @@ See its __doc__ string for a discussion of the format.
</para>
<example_commands>
- env.Java(target = 'classes', source = 'src')
- env.Java(target = 'classes', source = ['src1', 'src2'])
- env.Java(target = 'classes', source = ['File1.java', 'File2.java'])
+env.Java(target = 'classes', source = 'src')
+env.Java(target = 'classes', source = ['src1', 'src2'])
+env.Java(target = 'classes', source = ['File1.java', 'File2.java'])
</example_commands>
<para>
@@ -114,8 +114,8 @@ See its __doc__ string for a discussion of the format.
</para>
<example_commands>
- env = Environment()
- env['ENV']['LANG'] = 'en_GB.UTF-8'
+env = Environment()
+env['ENV']['LANG'] = 'en_GB.UTF-8'
</example_commands>
</summary>
</builder>
@@ -174,7 +174,7 @@ See its __doc__ string for a discussion of the format.
</para>
<example_commands>
- env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
+env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
</example_commands>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/link.xml b/src/engine/SCons/Tool/link.xml
index 654dafc..281e147 100644
--- a/src/engine/SCons/Tool/link.xml
+++ b/src/engine/SCons/Tool/link.xml
@@ -32,9 +32,6 @@ based on the types of source files.
</para>
</summary>
<sets>
-<item>SHLINK</item>
-<item>SHLINKFLAGS</item>
-<item>SHLINKCOM</item>
<item>LINK</item>
<item>LINKFLAGS</item>
<item>LINKCOM</item>
@@ -42,6 +39,9 @@ based on the types of source files.
<item>LIBDIRSUFFIX</item>
<item>LIBLINKPREFIX</item>
<item>LIBLINKSUFFIX</item>
+<item>SHLINK</item>
+<item>SHLINKFLAGS</item>
+<item>SHLINKCOM</item>
<item>SHLIBSUFFIX</item>
<item>__SHLIBVERSIONFLAGS</item>
<item>LDMODULE</item>
@@ -55,8 +55,8 @@ based on the types of source files.
<item>__LDMODULEVERSIONFLAGS</item>
</sets>
<uses>
-<item>SHLINKCOMSTR</item>
<item>LINKCOMSTR</item>
+<item>SHLINKCOMSTR</item>
<item>LDMODULECOMSTR</item>
</uses>
</tool>
@@ -184,8 +184,8 @@ On other systems, this is the same as &cv-link-SHLINK;.
<cvar name="LDMODULECOMSTR">
<summary>
<para>
-The string displayed when building loadable modules.
-If this is not set, then &cv-link-LDMODULECOM; (the command line) is displayed.
+If set, the string displayed when building loadable modules.
+If not set, then &cv-link-LDMODULECOM; (the command line) is displayed.
</para>
</summary>
</cvar>
@@ -243,6 +243,7 @@ set.
<summary>
<para>
The linker.
+See also &cv-link-SHLINK; for linking shared objects.
</para>
</summary>
</cvar>
@@ -251,6 +252,7 @@ The linker.
<summary>
<para>
The command line used to link object files into an executable.
+See also &cv-link-SHLINKCOM; for linking shared objects.
</para>
</summary>
</cvar>
@@ -258,9 +260,10 @@ The command line used to link object files into an executable.
<cvar name="LINKCOMSTR">
<summary>
<para>
-The string displayed when object files
+If set, the string displayed when object files
are linked into an executable.
-If this is not set, then &cv-link-LINKCOM; (the command line) is displayed.
+If not set, then &cv-link-LINKCOM; (the command line) is displayed.
+See also &cv-link-SHLINKCOMSTR;. for linking shared objects.
</para>
<example_commands>
@@ -290,6 +293,7 @@ and
&cv-link-_LIBDIRFLAGS;
above,
for the variable that expands to library search path options.
+See also &cv-link-SHLINKFLAGS;. for linking shared objects.
</para>
</summary>
</cvar>
@@ -317,6 +321,7 @@ set.
<summary>
<para>
The linker for programs that use shared libraries.
+See also &cv-link-LINK; for linking static objects.
</para>
</summary>
</cvar>
@@ -325,6 +330,7 @@ The linker for programs that use shared libraries.
<summary>
<para>
The command line used to link programs using shared libraries.
+See also &cv-link-LINKCOM; for linking static objects.
</para>
</summary>
</cvar>
@@ -334,6 +340,7 @@ The command line used to link programs using shared libraries.
<para>
The string displayed when programs using shared libraries are linked.
If this is not set, then &cv-link-SHLINKCOM; (the command line) is displayed.
+See also &cv-link-LINKCOMSTR; for linking static objects.
</para>
<example_commands>
@@ -363,6 +370,7 @@ and
&cv-link-_LIBDIRFLAGS;
above,
for the variable that expands to library search path options.
+See also &cv-link-LINKFLAGS; for linking static objects.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index 929e558..9952ccc 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -220,7 +220,7 @@ class _UserGenerator(object):
for var, src in dbg_settings.items():
# Update only expected keys
trg = {}
- for key in [k for k in list(self.usrdebg.keys()) if k in src]:
+ for key in [k for k in self.usrdebg.keys() if k in src]:
trg[key] = str(src[key])
self.configs[var].debug = trg
@@ -544,7 +544,7 @@ class _DSPGenerator(object):
if t[1] in self.env:
if SCons.Util.is_List(self.env[t[1]]):
for i in self.env[t[1]]:
- if not i in self.sources[t[0]]:
+ if i not in self.sources[t[0]]:
self.sources[t[0]].append(i)
else:
if not self.env[t[1]] in self.sources[t[0]]:
@@ -578,11 +578,10 @@ class _DSPGenerator(object):
for i in range(len(variants)):
AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i], cppdefines[i], cpppaths[i])
- self.platforms = []
- for key in list(self.configs.keys()):
- platform = self.configs[key].platform
- if platform not in self.platforms:
- self.platforms.append(platform)
+ seen = set()
+ self.platforms = [p.platform for p in self.configs.values()
+ if not (p.platform in seen or seen.add(p.platform))]
+
def Build(self):
pass
@@ -702,7 +701,7 @@ class _GenerateV6DSP(_DSPGenerator):
'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe',
'Other Files': ''}
- for kind in sorted(list(categories.keys()), key=lambda a: a.lower()):
+ for kind in sorted(categories.keys(), key=lambda a: a.lower()):
if not self.sources[kind]:
continue # skip empty groups
@@ -1003,7 +1002,7 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
self.file.write('\t<Files>\n')
- cats = sorted([k for k in list(categories.keys()) if self.sources[k]],
+ cats = sorted([k for k in categories.keys() if self.sources[k]],
key=lambda a: a.lower())
for kind in cats:
if len(cats) > 1:
@@ -1348,7 +1347,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe',
'Other Files': ''}
- cats = sorted([k for k in list(categories.keys()) if self.sources[k]],
+ cats = sorted([k for k in categories.keys() if self.sources[k]],
key = lambda a: a.lower())
# print vcxproj.filters file first
@@ -1505,11 +1504,9 @@ class _GenerateV7DSW(_DSWGenerator):
for variant in env['variant']:
AddConfig(self, variant)
- self.platforms = []
- for key in list(self.configs.keys()):
- platform = self.configs[key].platform
- if platform not in self.platforms:
- self.platforms.append(platform)
+ seen = set()
+ self.platforms = [p.platform for p in self.configs.values()
+ if not (p.platform in seen or seen.add(p.platform))]
def GenerateProjectFilesInfo(self):
for dspfile in self.dspfiles:
diff --git a/src/engine/SCons/Tool/msvsTests.py b/src/engine/SCons/Tool/msvsTests.py
index cc4f717..38a100f 100644
--- a/src/engine/SCons/Tool/msvsTests.py
+++ b/src/engine/SCons/Tool/msvsTests.py
@@ -405,20 +405,20 @@ class DummyEnv(object):
return self.dict
return self.dict[key]
- def __setitem__(self,key,value):
+ def __setitem__(self, key, value):
self.dict[key] = value
- def __getitem__(self,key):
+ def __getitem__(self, key):
return self.dict[key]
- def __contains__(self,key):
+ def __contains__(self, key):
return key in self.dict
- def has_key(self,name):
+ def has_key(self, name):
return name in self.dict
def get(self, name, value=None):
- if self.has_key(name):
+ if name in self.dict:
return self.dict[name]
else:
return value
@@ -771,8 +771,8 @@ class msvsTestCase(unittest.TestCase):
# Check expected result
self.assertListEqual(list(genDSP.configs.keys()), list(expected_configs.keys()))
- for key in list(genDSP.configs.keys()):
- self.assertDictEqual(genDSP.configs[key].__dict__, expected_configs[key])
+ for key, v in genDSP.configs.items():
+ self.assertDictEqual(v.__dict__, expected_configs[key])
genDSP.Build()
diff --git a/src/engine/SCons/Tool/packaging.xml b/src/engine/SCons/Tool/packaging.xml
index 8ab4912..55fecec 100644
--- a/src/engine/SCons/Tool/packaging.xml
+++ b/src/engine/SCons/Tool/packaging.xml
@@ -34,7 +34,7 @@ A framework for building binary and source packages.
<builder name="Package">
<summary>
<para>
-Builds a Binary Package of the given source files.
+Builds a Binary Package of the given source files.
</para>
<example_commands>
@@ -43,68 +43,4 @@ env.Package(source = FindInstalledFiles())
</summary>
</builder>
-<cvar name="JAR">
-<summary>
-<para>
-The Java archive tool.
-</para>
-</summary>
-</cvar>
-
-<cvar name="JARCHDIR">
-<summary>
-<para>
-The directory to which the Java archive tool should change
-(using the
-<option>-C</option>
-option).
-</para>
-</summary>
-</cvar>
-
-<cvar name="JARCOM">
-<summary>
-<para>
-The command line used to call the Java archive tool.
-</para>
-</summary>
-</cvar>
-
-<cvar name="JARCOMSTR">
-<summary>
-<para>
-The string displayed when the Java archive tool
-is called
-If this is not set, then &cv-JARCOM; (the command line) is displayed.
-</para>
-
-<example_commands>
-env = Environment(JARCOMSTR = "JARchiving $SOURCES into $TARGET")
-</example_commands>
-</summary>
-</cvar>
-
-<cvar name="JARFLAGS">
-<summary>
-<para>
-General options passed to the Java archive tool.
-By default this is set to
-<option>cf</option>
-to create the necessary
-<command>jar</command>
-file.
-</para>
-</summary>
-</cvar>
-
-<cvar name="JARSUFFIX">
-<summary>
-<para>
-The suffix for Java archives:
-<filename>.jar</filename>
-by default.
-</para>
-</summary>
-</cvar>
-
</sconsdoc>
diff --git a/src/engine/SCons/Tool/packaging/__init__.xml b/src/engine/SCons/Tool/packaging/__init__.xml
index 31c6eed..66a7aa0 100644
--- a/src/engine/SCons/Tool/packaging/__init__.xml
+++ b/src/engine/SCons/Tool/packaging/__init__.xml
@@ -62,24 +62,25 @@ option or with the &cv-PACKAGETYPE; construction variable. Currently
the following packagers available:
</para>
-<para>
- * 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
-</para>
+<para><literal>msi</literal> - Microsoft Installer</para>
+<para><literal>rpm</literal> - RPM Package Manger</para>
+<para><literal>ipkg</literal> - Itsy Package Management System</para>
+<para><literal>tarbz2</literal> - bzip2 compressed tar</para>
+<para><literal>targz</literal> - gzip compressed tar</para>
+<para><literal>tarxz</literal> - xz compressed tar</para>
+<para><literal>zip</literal> - zip file</para>
+<para><literal>src_tarbz2</literal> - bzip2 compressed tar source</para>
+<para><literal>src_targz</literal> - gzip compressed tar source</para>
+<para><literal>src_tarxz</literal> - xz compressed tar source</para>
+<para><literal>src_zip</literal> - zip file source</para>
<para>
-An updated list is always available under the "package_type" option when
-running "scons --help" on a project that has packaging activated.
+An updated list is always available under the
+<replaceable>package_type</replaceable> option when
+running <command>scons --help</command>
+on a project that has packaging activated.
</para>
+
<example_commands>
env = Environment(tools=['default', 'packaging'])
env.Install('/bin/', 'my_program')
@@ -198,20 +199,21 @@ placed if applicable. The default value is "$NAME-$VERSION".
Selects the package type to build. Currently these are available:
</para>
-<para>
- * msi - Microsoft Installer
- * rpm - Redhat Package Manger
- * ipkg - Itsy Package Management System
- * tarbz2 - compressed tar
- * targz - compressed tar
- * zip - zip file
- * src_tarbz2 - compressed tar source
- * src_targz - compressed tar source
- * src_zip - zip file source
-</para>
+<para><literal>msi</literal> - Microsoft Installer</para>
+<para><literal>rpm</literal> - RPM Package Manger</para>
+<para><literal>ipkg</literal> - Itsy Package Management System</para>
+<para><literal>tarbz2</literal> - bzip2 compressed tar</para>
+<para><literal>targz</literal> - gzip compressed tar</para>
+<para><literal>tarxz</literal> - xz compressed tar</para>
+<para><literal>zip</literal> - zip file</para>
+<para><literal>src_tarbz2</literal> - bzip2 compressed tar source</para>
+<para><literal>src_targz</literal> - gzip compressed tar source</para>
+<para><literal>src_tarxz</literal> - xz compressed tar source</para>
+<para><literal>src_zip</literal> - zip file source</para>
<para>
-This may be overridden with the "package_type" command line option.
+This may be overridden with the <option>package_type</option>
+command line option.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/packaging/ipk.py b/src/engine/SCons/Tool/packaging/ipk.py
index fe3f49b..ac8b992 100644
--- a/src/engine/SCons/Tool/packaging/ipk.py
+++ b/src/engine/SCons/Tool/packaging/ipk.py
@@ -173,7 +173,7 @@ Description: $X_IPK_DESCRIPTION
#
# close all opened files
- for f in list(opened_files.values()):
+ for f in opened_files.values():
f.close()
# call a user specified function
diff --git a/src/engine/SCons/Tool/packaging/rpm.py b/src/engine/SCons/Tool/packaging/rpm.py
index ebaa701..db8ae24 100644
--- a/src/engine/SCons/Tool/packaging/rpm.py
+++ b/src/engine/SCons/Tool/packaging/rpm.py
@@ -284,7 +284,7 @@ def build_specfile_filesection(spec, files):
for file in files:
# build the tagset
tags = {}
- for k in list(supported_tags.keys()):
+ for k in supported_tags.keys():
try:
v = file.GetTag(k)
if v:
diff --git a/src/engine/SCons/Tool/python.py b/src/engine/SCons/Tool/python.py
new file mode 100644
index 0000000..c61fc8d
--- /dev/null
+++ b/src/engine/SCons/Tool/python.py
@@ -0,0 +1,49 @@
+"""SCons.Tool.python
+
+Registers the Python scanner for the supported Python source file suffixes.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Tool
+from SCons.Scanner.Python import PythonScanner, PythonSuffixes
+
+
+def generate(env):
+ """Hook the python builder and scanner into the environment."""
+ for suffix in PythonSuffixes:
+ SCons.Tool.SourceFileScanner.add_scanner(suffix, PythonScanner)
+
+
+def exists(env):
+ return True
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/python.xml b/src/engine/SCons/Tool/python.xml
new file mode 100644
index 0000000..e3f7da3
--- /dev/null
+++ b/src/engine/SCons/Tool/python.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+
+<!DOCTYPE sconsdoc [
+<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+%scons;
+<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+%builders-mod;
+<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+%functions-mod;
+<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+%tools-mod;
+<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+%variables-mod;
+]>
+
+<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="python">
+<summary>
+<para>
+Loads the Python scanner scanner into the invoking environment. When loaded, the scanner will
+attempt to find implicit dependencies for any Python source files in the list of sources
+provided to an actual that uses this environment.
+</para>
+</summary>
+</tool>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/suncxx.py b/src/engine/SCons/Tool/suncxx.py
index c155484..1c35612 100644
--- a/src/engine/SCons/Tool/suncxx.py
+++ b/src/engine/SCons/Tool/suncxx.py
@@ -39,7 +39,6 @@ import os
import re
import subprocess
-from SCons.Util import PY3
import SCons.Tool.cxx
cplusplus = SCons.Tool.cxx
# cplusplus = __import__('c++', globals(), locals(), [])
@@ -53,10 +52,7 @@ def get_package_info(package_name, pkginfo, pkgchk):
except KeyError:
version = None
pathname = None
- try:
- from subprocess import DEVNULL # py3k
- except ImportError:
- DEVNULL = open(os.devnull, 'wb')
+ from subprocess import DEVNULL
try:
with open('/var/sadm/install/contents', 'r') as f:
@@ -72,16 +68,14 @@ def get_package_info(package_name, pkginfo, pkgchk):
try:
popen_args = {'stdout': subprocess.PIPE,
'stderr': DEVNULL}
- if PY3:
- popen_args['universal_newlines'] = True
+ popen_args['universal_newlines'] = True
p = subprocess.Popen([pkginfo, '-l', package_name],
**popen_args)
except EnvironmentError:
pass
else:
pkginfo_contents = p.communicate()[0]
- if not PY3:
- pkginfo_contents.decode()
+ pkginfo_contents.decode()
version_re = re.compile(r'^ *VERSION:\s*(.*)$', re.M)
version_match = version_re.search(pkginfo_contents)
if version_match:
@@ -91,16 +85,14 @@ def get_package_info(package_name, pkginfo, pkgchk):
try:
popen_args = {'stdout': subprocess.PIPE,
'stderr': DEVNULL}
- if PY3:
- popen_args['universal_newlines'] = True
+ popen_args['universal_newlines'] = True
p = subprocess.Popen([pkgchk, '-l', package_name],
**popen_args)
except EnvironmentError:
pass
else:
pkgchk_contents = p.communicate()[0]
- if not PY3:
- pkgchk_contents.decode()
+ pkgchk_contents.decode()
pathname_re = re.compile(r'^Pathname:\s*(.*/bin/CC)$', re.M)
pathname_match = pathname_re.search(pkgchk_contents)
if pathname_match:
diff --git a/src/engine/SCons/Tool/textfile.py b/src/engine/SCons/Tool/textfile.py
index 9e2327a..48a2904 100644
--- a/src/engine/SCons/Tool/textfile.py
+++ b/src/engine/SCons/Tool/textfile.py
@@ -53,13 +53,10 @@ import re
from SCons.Node import Node
from SCons.Node.Python import Value
-from SCons.Util import is_String, is_Sequence, is_Dict, to_bytes, PY3
+from SCons.Util import is_String, is_Sequence, is_Dict, to_bytes
-if PY3:
- TEXTFILE_FILE_WRITE_MODE = 'w'
-else:
- TEXTFILE_FILE_WRITE_MODE = 'wb'
+TEXTFILE_FILE_WRITE_MODE = 'w'
LINESEP = '\n'
@@ -126,10 +123,7 @@ def _action(target, source, env):
# write the file
try:
- if SCons.Util.PY3:
- target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE, newline='')
- else:
- target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE)
+ target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE, newline='')
except (OSError, IOError):
raise SCons.Errors.UserError("Can't write target file %s" % target[0])
diff --git a/src/engine/SCons/Tool/textfile.xml b/src/engine/SCons/Tool/textfile.xml
index 957e18c..878eb9f 100644
--- a/src/engine/SCons/Tool/textfile.xml
+++ b/src/engine/SCons/Tool/textfile.xml
@@ -59,7 +59,7 @@ see the &b-Substfile; description for details.
<para>
The prefix and suffix specified by the &cv-TEXTFILEPREFIX;
and &cv-TEXTFILESUFFIX; construction variables
-(the null string and <filename>.txt</filename> by default, respectively)
+(an empty string and <filename>.txt</filename> by default, respectively)
are automatically added to the target if they are not already present.
Examples:
</para>
@@ -124,7 +124,7 @@ the suffix is stripped and the remainder is used as the default target name.
<para>
The prefix and suffix specified by the &cv-SUBSTFILEPREFIX;
and &cv-SUBSTFILESUFFIX; construction variables
-(the null string by default in both cases)
+(an empty string by default in both cases)
are automatically added to the target if they are not already present.
</para>
@@ -218,7 +218,7 @@ lists of tuples are also acceptable.
<summary>
<para>
The prefix used for &b-Substfile; file names,
-the null string by default.
+an empty string by default.
</para>
</summary>
</cvar>
@@ -227,7 +227,7 @@ the null string by default.
<summary>
<para>
The suffix used for &b-Substfile; file names,
-the null string by default.
+an empty string by default.
</para>
</summary>
</cvar>
@@ -236,7 +236,7 @@ the null string by default.
<summary>
<para>
The prefix used for &b-Textfile; file names,
-the null string by default.
+an empty string by default.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py
index 11ca32f..7aba08d 100644
--- a/src/engine/SCons/Tool/xgettext.py
+++ b/src/engine/SCons/Tool/xgettext.py
@@ -70,7 +70,7 @@ class _CmdRunner(object):
self.out, self.err = proc.communicate()
self.status = proc.wait()
if self.err:
- sys.stderr.write(SCons.Util.UnicodeType(self.err))
+ sys.stderr.write(str(self.err))
return self.status
def strfunction(self, target, source, env):
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index d930dde..130cc5e 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -39,18 +39,8 @@ PY3 = sys.version_info[0] == 3
PYPY = hasattr(sys, 'pypy_translation_info')
-try:
- from collections import UserDict, UserList, UserString
-except ImportError:
- from UserDict import UserDict
- from UserList import UserList
- from UserString import UserString
-
-try:
- from collections.abc import Iterable, MappingView
-except ImportError:
- from collections import Iterable
-
+from collections import UserDict, UserList, UserString
+from collections.abc import Iterable, MappingView
from collections import OrderedDict
# Don't "from types import ..." these because we need to get at the
@@ -62,13 +52,6 @@ from collections import OrderedDict
MethodType = types.MethodType
FunctionType = types.FunctionType
-try:
- _ = type(unicode)
-except NameError:
- UnicodeType = str
-else:
- UnicodeType = unicode
-
def dictify(keys, values, result={}):
for k, v in zip(keys, values):
result[k] = v
@@ -210,14 +193,16 @@ def get_environment_var(varstr):
else:
return None
+
class DisplayEngine(object):
print_it = True
+
def __call__(self, text, append_newline=1):
if not self.print_it:
return
if append_newline: text = text + '\n'
try:
- sys.stdout.write(UnicodeType(text))
+ sys.stdout.write(str(text))
except IOError:
# Stdout might be connected to a pipe that has been closed
# by now. The most likely reason for the pipe being closed
@@ -1582,11 +1567,8 @@ del __revision__
def to_bytes(s):
if s is None:
return b'None'
- if not PY3 and isinstance(s, UnicodeType):
- # PY2, must encode unicode
- return bytearray(s, 'utf-8')
- if isinstance (s, (bytes, bytearray)) or bytes is str:
- # Above case not covered here as py2 bytes and strings are the same
+ if isinstance(s, (bytes, bytearray)):
+ # if already bytes return.
return s
return bytes(s, 'utf-8')
@@ -1594,9 +1576,9 @@ def to_bytes(s):
def to_str(s):
if s is None:
return 'None'
- if bytes is str or is_String(s):
+ if is_String(s):
return s
- return str (s, 'utf-8')
+ return str(s, 'utf-8')
def cmp(a, b):
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index e2dd57f..ee07e61 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -37,14 +37,6 @@ import SCons.Errors
from SCons.Util import *
-try:
- eval('unicode')
-except NameError:
- HasUnicode = False
-else:
- HasUnicode = True
-
-
class OutBuffer(object):
def __init__(self):
self.buffer = ""
@@ -274,8 +266,7 @@ class UtilTestCase(unittest.TestCase):
assert not is_Dict([])
assert not is_Dict(())
assert not is_Dict("")
- if HasUnicode:
- exec ("assert not is_Dict(u'')")
+
def test_is_List(self):
assert is_List([])
@@ -290,13 +281,9 @@ class UtilTestCase(unittest.TestCase):
assert not is_List(())
assert not is_List({})
assert not is_List("")
- if HasUnicode:
- exec ("assert not is_List(u'')")
def test_is_String(self):
assert is_String("")
- if HasUnicode:
- exec ("assert is_String(u'')")
assert is_String(UserString(''))
try:
class mystr(str):
@@ -321,15 +308,12 @@ class UtilTestCase(unittest.TestCase):
assert not is_Tuple([])
assert not is_Tuple({})
assert not is_Tuple("")
- if HasUnicode:
- exec ("assert not is_Tuple(u'')")
def test_to_Bytes(self):
""" Test the to_Bytes method"""
- if not PY3:
- self.assertEqual(to_bytes(UnicodeType('Hello')),
- bytearray(u'Hello', 'utf-8'),
- "Check that to_bytes creates byte array when presented with unicode string. PY2 only")
+ self.assertEqual(to_bytes('Hello'),
+ bytearray('Hello', 'utf-8'),
+ "Check that to_bytes creates byte array when presented with unicode string.")
def test_to_String(self):
"""Test the to_String() method."""
@@ -352,18 +336,6 @@ class UtilTestCase(unittest.TestCase):
assert to_String(s2) == s2, s2
assert to_String(s2) == 'foo', s2
- if HasUnicode:
- s3 = UserString(unicode('bar'))
- assert to_String(s3) == s3, s3
- assert to_String(s3) == unicode('bar'), s3
- assert isinstance(to_String(s3), unicode), \
- type(to_String(s3))
-
- if HasUnicode:
- s4 = unicode('baz')
- assert to_String(s4) == unicode('baz'), to_String(s4)
- assert isinstance(to_String(s4), unicode), \
- type(to_String(s4))
def test_WhereIs(self):
test = TestCmd.TestCmd(workdir='')
diff --git a/src/engine/SCons/Variables/ListVariableTests.py b/src/engine/SCons/Variables/ListVariableTests.py
index ef4832c..8f79e07 100644
--- a/src/engine/SCons/Variables/ListVariableTests.py
+++ b/src/engine/SCons/Variables/ListVariableTests.py
@@ -42,7 +42,7 @@ class ListVariableTestCase(unittest.TestCase):
assert o.help == 'test option help\n (all|none|comma-separated list of names)\n allowed names: one two three', repr(o.help)
assert o.default == 'all', o.default
assert o.validator is None, o.validator
- assert not o.converter is None, o.converter
+ assert o.converter is not None, o.converter
opts = SCons.Variables.Variables()
opts.Add(SCons.Variables.ListVariable('test2', 'test2 help',
diff --git a/src/engine/SCons/Variables/PackageVariableTests.py b/src/engine/SCons/Variables/PackageVariableTests.py
index cda3a4a..a7e6b0d 100644
--- a/src/engine/SCons/Variables/PackageVariableTests.py
+++ b/src/engine/SCons/Variables/PackageVariableTests.py
@@ -80,10 +80,10 @@ class PackageVariableTestCase(unittest.TestCase):
# False when we give it str(False). This assures consistent operation
# through a cycle of Variables.Save(<file>) -> Variables(<file>).
x = o.converter(str(True))
- assert x == True, "converter returned a string when given str(True)"
+ assert x, "converter returned a string when given str(True)"
x = o.converter(str(False))
- assert x == False, "converter returned a string when given str(False)"
+ assert not x, "converter returned a string when given str(False)"
def test_validator(self):
"""Test the PackageVariable validator"""
diff --git a/src/engine/SCons/cpp.py b/src/engine/SCons/cpp.py
index 5b35390..0c20c94 100644
--- a/src/engine/SCons/cpp.py
+++ b/src/engine/SCons/cpp.py
@@ -89,7 +89,7 @@ del op_list
override = {
'if' : 'if(?!n?def)',
}
-l = [override.get(x, x) for x in list(Table.keys())]
+l = [override.get(x, x) for x in Table.keys()]
# Turn the list of expressions into one big honkin' regular expression
@@ -268,7 +268,7 @@ class PreProcessor(object):
d = {
'scons_current_file' : self.scons_current_file
}
- for op in list(Table.keys()):
+ for op in Table.keys():
d[op] = getattr(self, 'do_' + op)
self.default_table = d
diff --git a/src/test_interrupts.py b/src/test_interrupts.py
index de18a54..8e1b379 100644
--- a/src/test_interrupts.py
+++ b/src/test_interrupts.py
@@ -105,7 +105,7 @@ for f in files:
indent_list.append( (line_num, match.group('try_or_except') ) )
try_except_lines[match.group('indent')] = indent_list
uncaught_this_file = []
- for indent in list(try_except_lines.keys()):
+ for indent in try_except_lines.keys():
exc_keyboardint_seen = 0
exc_all_seen = 0
for (l,statement) in try_except_lines[indent] + [(-1,indent + 'try')]:
diff --git a/test/CacheDir/value_dependencies.py b/test/CacheDir/value_dependencies.py
new file mode 100644
index 0000000..7992bef
--- /dev/null
+++ b/test/CacheDir/value_dependencies.py
@@ -0,0 +1,52 @@
+#!/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 bwuilds with caching work for an action with a Value as a child
+in a variety of cases. Specifically:
+
+1. A source file that depends on a Value.
+2. A source directory that depends on a Value.
+3. A scanner that returns a Value and a directory that depends on a Value.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.dir_fixture('value_dependencies')
+test.subdir('cache')
+
+# First build, populates the cache
+test.run(arguments='.')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/CacheDir/value_dependencies/SConstruct b/test/CacheDir/value_dependencies/SConstruct
new file mode 100644
index 0000000..7b7e596
--- /dev/null
+++ b/test/CacheDir/value_dependencies/SConstruct
@@ -0,0 +1,32 @@
+import SCons.Node
+
+CacheDir('cache')
+
+def b(target, source, env):
+ with open(target[0].abspath, 'w') as f:
+ pass
+
+def scan(node, env, path):
+ # Have the node depend on a directory, which depends on an instance of
+ # SCons.Node.Python.Value.
+ sample_dir = env.fs.Dir('dir2')
+ env.Depends(sample_dir, env.Value('c'))
+ return [sample_dir, env.Value('d'), env.Value(b'\x03\x0F', name='name3')]
+
+scanner = Scanner(function=scan, node_class=SCons.Node.Node)
+builder = Builder(action=b, source_scanner=scanner)
+
+env = Environment()
+env.Append(BUILDERS={'B': builder})
+
+# Create a node and a directory that each depend on an instance of
+# SCons.Node.Python.Value.
+sample_dir = env.fs.Dir('dir1')
+env.Depends(sample_dir,
+ [env.Value('a'), env.Value(b'\x01\x0F', name='name1')])
+
+sample_file = env.fs.File('testfile')
+env.Depends(sample_file,
+ [env.Value('b'), env.Value(b'\x02\x0F', name='name2')])
+
+env.B(target='File1.out', source=[sample_dir, sample_file])
diff --git a/test/CacheDir/value_dependencies/testfile b/test/CacheDir/value_dependencies/testfile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/CacheDir/value_dependencies/testfile
diff --git a/test/DVIPDF/makeindex.py b/test/DVIPDF/makeindex.py
index b4ac2d0..bb44d27 100644
--- a/test/DVIPDF/makeindex.py
+++ b/test/DVIPDF/makeindex.py
@@ -32,15 +32,15 @@ test = TestSCons.TestSCons()
dvipdf = test.where_is('dvipdf')
if not dvipdf:
- test.skip_test('Could not find dvipdf; skipping test(s).\n')
+ test.skip_test("Could not find 'dvipdf'; skipping test(s).\n")
tex = test.where_is('tex')
if not tex:
- test.skip_test('Could not find tex; skipping test(s).\n')
+ test.skip_test("Could not find 'tex'; skipping test(s).\n")
latex = test.where_is('latex')
if not latex:
- test.skip_test('Could not find latex; skipping test(s).\n')
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
diff --git a/test/DVIPS/DVIPS.py b/test/DVIPS/DVIPS.py
index 27e89ba..df7811a 100644
--- a/test/DVIPS/DVIPS.py
+++ b/test/DVIPS/DVIPS.py
@@ -116,13 +116,13 @@ test.must_match('test4.ps', "This is a .latex test.\n", mode='r')
have_latex = test.where_is('latex')
if not have_latex:
- test.skip_test('Could not find latex; skipping test(s).\n')
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
dvips = test.where_is('dvips')
+if not dvips:
+ test.skip_test("Could not find 'dvips'; skipping test(s).\n")
-if dvips:
-
- test.write("wrapper.py", """
+test.write("wrapper.py", """
import os
import sys
cmd = " ".join(sys.argv[1:])
@@ -130,7 +130,7 @@ open('%s', 'a').write("%%s\\n" %% cmd)
os.system(cmd)
""" % test.workpath('wrapper.out').replace('\\', '\\\\'))
- test.write('SConstruct', """
+test.write('SConstruct', """
import os
ENV = { 'PATH' : os.environ['PATH'] }
foo = Environment(ENV = ENV)
@@ -142,41 +142,41 @@ bar.PostScript(target = 'bar2', source = 'bar2.ltx')
bar.PostScript(target = 'bar3', source = 'bar3.latex')
""" % locals())
- tex = r"""
+tex = r"""
This is the %s TeX file.
\end
"""
- latex = r"""
+latex = r"""
\documentclass{letter}
\begin{document}
This is the %s LaTeX file.
\end{document}
"""
- test.write('foo.tex', tex % 'foo.tex')
- test.write('bar1.tex', tex % 'bar1.tex')
- test.write('bar2.ltx', latex % 'bar2.ltx')
- test.write('bar3.latex', latex % 'bar3.latex')
+test.write('foo.tex', tex % 'foo.tex')
+test.write('bar1.tex', tex % 'bar1.tex')
+test.write('bar2.ltx', latex % 'bar2.ltx')
+test.write('bar3.latex', latex % 'bar3.latex')
- test.run(arguments = 'foo.dvi', stderr = None)
+test.run(arguments = 'foo.dvi', stderr = None)
- test.must_not_exist(test.workpath('wrapper.out'))
+test.must_not_exist(test.workpath('wrapper.out'))
- test.must_exist(test.workpath('foo.dvi'))
+test.must_exist(test.workpath('foo.dvi'))
- test.run(arguments = 'bar1.ps bar2.ps bar3.ps', stderr = None)
+test.run(arguments = 'bar1.ps bar2.ps bar3.ps', stderr = None)
- expect = """dvips -o bar1.ps bar1.dvi
+expect = """dvips -o bar1.ps bar1.dvi
dvips -o bar2.ps bar2.dvi
dvips -o bar3.ps bar3.dvi
"""
- test.must_match('wrapper.out', expect, mode='r')
+test.must_match('wrapper.out', expect, mode='r')
- test.must_exist(test.workpath('bar1.ps'))
- test.must_exist(test.workpath('bar2.ps'))
- test.must_exist(test.workpath('bar3.ps'))
+test.must_exist(test.workpath('bar1.ps'))
+test.must_exist(test.workpath('bar2.ps'))
+test.must_exist(test.workpath('bar3.ps'))
test.pass_test()
diff --git a/test/Dir/Dir.py b/test/Dir/Dir.py
index e726b94..42a48f3 100644
--- a/test/Dir/Dir.py
+++ b/test/Dir/Dir.py
@@ -36,28 +36,34 @@ test = TestSCons.TestSCons()
test.write('SConstruct', """
DefaultEnvironment(tools=[])
-env = Environment(tools=[], FOO = 'fff', BAR = 'bbb')
+env = Environment(tools=[], FOO='fff', BAR='bbb')
print(Dir('ddd'))
print(Dir('$FOO'))
print(Dir('${BAR}_$BAR'))
+rv = Dir(['mmm', 'nnn'])
+rv_msg = [node.path for node in rv]
+print(rv_msg)
print(env.Dir('eee'))
print(env.Dir('$FOO'))
print(env.Dir('${BAR}_$BAR'))
+rv = env.Dir(['ooo', 'ppp'])
+rv_msg = [node.path for node in rv]
+print(rv_msg)
""")
-test.run(stdout = test.wrap_stdout(read_str = """\
+test.run(stdout=test.wrap_stdout(read_str="""\
ddd
$FOO
${BAR}_$BAR
+['mmm', 'nnn']
eee
fff
bbb_bbb
-""", build_str = """\
+['ooo', 'ppp']
+""", build_str="""\
scons: `.' is up to date.
"""))
-
-
test.write('SConstruct', """\
DefaultEnvironment(tools=[])
import os
@@ -66,7 +72,7 @@ def my_mkdir(target=None, source=None, env=None):
MDBuilder = Builder(action=my_mkdir, target_factory=Dir)
env = Environment(tools=[])
-env.Append(BUILDERS = {'MD':MDBuilder})
+env.Append(BUILDERS={'MD': MDBuilder})
env.MD(target='sub1', source=['SConstruct'])
env.MD(target='sub2', source=['SConstruct'], OVERRIDE='foo')
""")
diff --git a/test/File.py b/test/File.py
index ec148b2..bde4449 100644
--- a/test/File.py
+++ b/test/File.py
@@ -37,13 +37,19 @@ import TestSCons
test = TestSCons.TestSCons()
test.write('SConstruct', """
-env = Environment(FOO = 'fff', BAR = 'bbb')
+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')
@@ -54,16 +60,18 @@ expect = test.wrap_stdout(read_str = """\
ddd
$FOO
${BAR}_$BAR
+['mmm', 'nnn']
eee
fff
bbb_bbb
+['ooo', 'ppp']
f1
f2
-""", build_str = """\
+""", build_str="""\
scons: `.' is up to date.
""")
-test.run(stdout = expect)
+test.run(stdout=expect)
test.pass_test()
diff --git a/test/TEX/TEX.py b/test/TEX/TEX.py
index 3964eb8..f0d4043 100644
--- a/test/TEX/TEX.py
+++ b/test/TEX/TEX.py
@@ -38,7 +38,7 @@ test = TestSCons.TestSCons()
have_latex = test.where_is('latex')
if not have_latex:
- test.skip_test('Could not find latex; skipping test(s).\n')
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
test.write('mytex.py', r"""
diff --git a/test/TEX/auxiliaries.py b/test/TEX/auxiliaries.py
index e28c212..1e37e7a 100644
--- a/test/TEX/auxiliaries.py
+++ b/test/TEX/auxiliaries.py
@@ -45,8 +45,8 @@ test = TestSCons.TestSCons()
dvips = test.where_is('dvips')
latex = test.where_is('latex')
-if not dvips or not latex:
- test.skip_test("Could not find dvips or latex; skipping test(s).\n")
+if not all((dvips, latex)):
+ test.skip_test("Could not find 'dvips' and/or 'latex'; skipping test(s).\n")
test.subdir(['docs'])
diff --git a/test/TEX/bibliography.py b/test/TEX/bibliography.py
index a8032db..afccf8f 100644
--- a/test/TEX/bibliography.py
+++ b/test/TEX/bibliography.py
@@ -38,15 +38,15 @@ test = TestSCons.TestSCons()
dvips = test.where_is('dvips')
if not dvips:
- test.skip_test("Could not find dvips; skipping test(s).\n")
+ test.skip_test("Could not find 'dvips'; skipping test(s).\n")
bibtex = test.where_is('bibtex')
if not bibtex:
- test.skip_test("Could not find bibtex; skipping test(s).\n")
+ test.skip_test("Could not find 'bibtex'; skipping test(s).\n")
have_latex = test.where_is('latex')
if not have_latex:
- test.skip_test('Could not find latex; skipping test(s).\n')
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
test.write('SConstruct', """\
diff --git a/test/TEX/bibtex-latex-rerun.py b/test/TEX/bibtex-latex-rerun.py
index 300f03b..f0f8c34 100644
--- a/test/TEX/bibtex-latex-rerun.py
+++ b/test/TEX/bibtex-latex-rerun.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
pdflatex = test.where_is('pdflatex')
if not pdflatex:
- test.skip_test("Could not find pdflatex; skipping test(s).\n")
+ test.skip_test("Could not find 'pdflatex'; skipping test(s).\n")
test.write(['SConstruct'], """\
import os
diff --git a/test/TEX/clean.py b/test/TEX/clean.py
index ad828d2..781caa1 100644
--- a/test/TEX/clean.py
+++ b/test/TEX/clean.py
@@ -36,7 +36,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find tex or latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
comment = os.system('kpsewhich comment.sty')
if not comment==0:
diff --git a/test/TEX/configure.py b/test/TEX/configure.py
index 763f86f..9fb4b3e 100644
--- a/test/TEX/configure.py
+++ b/test/TEX/configure.py
@@ -40,8 +40,8 @@ test = TestSCons.TestSCons()
dvips = test.where_is('dvips')
latex = test.where_is('latex')
-if not dvips or not latex:
- test.skip_test("Could not find dvips or latex; skipping test(s).\n")
+if not all((dvips, latex)):
+ test.skip_test("Could not find 'dvips' and/or 'latex'; skipping test(s).\n")
NCR = test.NCR # non-cached rebuild
diff --git a/test/TEX/dryrun.py b/test/TEX/dryrun.py
index 4265791..90357fc 100644
--- a/test/TEX/dryrun.py
+++ b/test/TEX/dryrun.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test('could not find latex; skipping test\n')
+ test.skip_test("could not find 'latex'; skipping test\n")
test.write('SConstruct', """
import os
diff --git a/test/TEX/glossaries.py b/test/TEX/glossaries.py
index 21180a0..cbb6964 100644
--- a/test/TEX/glossaries.py
+++ b/test/TEX/glossaries.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
gloss = os.system('kpsewhich glossaries.sty')
if not gloss==0:
diff --git a/test/TEX/glossary.py b/test/TEX/glossary.py
index 0becb40..ef13ca1 100644
--- a/test/TEX/glossary.py
+++ b/test/TEX/glossary.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
gloss = os.system('kpsewhich glossary.sty')
if not gloss==0:
diff --git a/test/TEX/lstinputlisting.py b/test/TEX/lstinputlisting.py
index 1d60df7..1f5020b 100644
--- a/test/TEX/lstinputlisting.py
+++ b/test/TEX/lstinputlisting.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
pdflatex = test.where_is('pdflatex')
if not pdflatex:
- test.skip_test("Could not find pdflatex; skipping test(s).\n")
+ test.skip_test("Could not find 'pdflatex'; skipping test(s).\n")
listings = os.system('kpsewhich listings.sty')
if not listings==0:
diff --git a/test/TEX/makeindex.py b/test/TEX/makeindex.py
index 960ed68..0b81f31 100644
--- a/test/TEX/makeindex.py
+++ b/test/TEX/makeindex.py
@@ -38,8 +38,8 @@ test = TestSCons.TestSCons()
pdflatex = test.where_is('pdflatex')
makeindex = test.where_is('makeindex')
-if not pdflatex or not makeindex:
- test.skip_test("Could not find pdflatex or makeindex; skipping test(s).\n")
+if not all((pdflatex, makeindex)):
+ test.skip_test("Could not find 'pdflatex' and/or 'makeindex'; skipping test(s).\n")
test.write('SConstruct', """\
import os
diff --git a/test/TEX/multi-line_include_options.py b/test/TEX/multi-line_include_options.py
index bb8a5f2..94466b6 100644
--- a/test/TEX/multi-line_include_options.py
+++ b/test/TEX/multi-line_include_options.py
@@ -44,7 +44,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
test.write('SConstruct', """\
import os
diff --git a/test/TEX/multi-run.py b/test/TEX/multi-run.py
index 9de0da4..3c4e901 100644
--- a/test/TEX/multi-run.py
+++ b/test/TEX/multi-run.py
@@ -38,11 +38,8 @@ test = TestSCons.TestSCons()
tex = test.where_is('tex')
latex = test.where_is('latex')
-
-if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
-if not tex and not latex:
- test.skip_test("Could not find tex or latex; skipping test(s).\n")
+if not all((tex, latex)):
+ test.skip_test("Could not find 'tex' and/or 'latex'; skipping test(s).\n")
test.subdir('work1', 'work2', 'work3', 'work4')
diff --git a/test/TEX/newglossary.py b/test/TEX/newglossary.py
index faae7d3..5d868a8 100644
--- a/test/TEX/newglossary.py
+++ b/test/TEX/newglossary.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
gloss = os.system('kpsewhich glossaries.sty')
if not gloss==0:
diff --git a/test/TEX/nomencl.py b/test/TEX/nomencl.py
index 7afb84b..0eb0b84 100644
--- a/test/TEX/nomencl.py
+++ b/test/TEX/nomencl.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
nomencl = os.system('kpsewhich nomencl.sty')
if not nomencl==0:
diff --git a/test/TEX/recursive_scanner_dependencies_import.py b/test/TEX/recursive_scanner_dependencies_import.py
index c8c6569..a7b5e4a 100644
--- a/test/TEX/recursive_scanner_dependencies_import.py
+++ b/test/TEX/recursive_scanner_dependencies_import.py
@@ -42,7 +42,7 @@ test = TestSCons.TestSCons()
pdflatex = test.where_is('pdflatex')
if not pdflatex:
- test.skip_test("Could not find pdflatex; skipping test(s).\n")
+ test.skip_test("Could not find 'pdflatex'; skipping test(s).\n")
latex_import = os.system('kpsewhich import.sty')
if latex_import != 0:
diff --git a/test/TEX/recursive_scanner_dependencies_input.py b/test/TEX/recursive_scanner_dependencies_input.py
index 5f37bf1..5afcbc2 100644
--- a/test/TEX/recursive_scanner_dependencies_input.py
+++ b/test/TEX/recursive_scanner_dependencies_input.py
@@ -36,7 +36,7 @@ test = TestSCons.TestSCons()
pdflatex = test.where_is('pdflatex')
if not pdflatex:
- test.skip_test("Could not find pdflatex; skipping test(s).\n")
+ test.skip_test("Could not find 'pdflatex'; skipping test(s).\n")
test.write(['SConstruct'], """\
env = Environment(tools=['pdftex', 'tex'])
diff --git a/test/TEX/rename_result.py b/test/TEX/rename_result.py
index b06d388..f67e569 100644
--- a/test/TEX/rename_result.py
+++ b/test/TEX/rename_result.py
@@ -38,7 +38,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test('could not find latex; skipping test\n')
+ test.skip_test("could not find 'latex'; skipping test\n")
test.write('SConstruct', """
import os
diff --git a/test/TEX/synctex.py b/test/TEX/synctex.py
index f07db78..385a173 100644
--- a/test/TEX/synctex.py
+++ b/test/TEX/synctex.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
test.write('SConstruct', """\
import os
diff --git a/test/TEX/usepackage.py b/test/TEX/usepackage.py
index 0bb8c22..66510c2 100644
--- a/test/TEX/usepackage.py
+++ b/test/TEX/usepackage.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test('could not find latex; skipping test\n')
+ test.skip_test("could not find 'latex'; skipping test\n")
test.write('SConstruct', """
import os
diff --git a/test/TEX/variant_dir.py b/test/TEX/variant_dir.py
index d81f542..9d05863 100644
--- a/test/TEX/variant_dir.py
+++ b/test/TEX/variant_dir.py
@@ -36,8 +36,9 @@ import TestSCons
test = TestSCons.TestSCons()
latex = test.where_is('latex')
-if not latex:
- test.skip_test("Could not find 'latex'; skipping test.\n")
+dvipdf = test.where_is('dvipdf')
+if not all((latex, dvipdf)):
+ test.skip_test("Could not find 'latex' and/or 'dvipdf'; skipping test(s).\n")
test.subdir(['docs'])
diff --git a/test/TEX/variant_dir_bibunit.py b/test/TEX/variant_dir_bibunit.py
index cd3409e..e127a76 100644
--- a/test/TEX/variant_dir_bibunit.py
+++ b/test/TEX/variant_dir_bibunit.py
@@ -41,8 +41,8 @@ test = TestSCons.TestSCons()
latex = test.where_is('pdflatex')
bibtex = test.where_is('bibtex')
-if not latex or not bibtex:
- test.skip_test("Could not find 'latex' or 'bibtex'; skipping test.\n")
+if not all((latex, bibtex)):
+ test.skip_test("Could not find 'latex' and/or 'bibtex'; skipping test.\n")
bibunits = os.system('kpsewhich bibunits.sty')
if not bibunits==0:
diff --git a/test/TEX/variant_dir_dup0.py b/test/TEX/variant_dir_dup0.py
index 8f4334f..ea6b51e 100644
--- a/test/TEX/variant_dir_dup0.py
+++ b/test/TEX/variant_dir_dup0.py
@@ -42,8 +42,8 @@ latex = test.where_is('latex')
dvipdf = test.where_is('dvipdf')
makeindex = test.where_is('makeindex')
bibtex = test.where_is('bibtex')
-if not latex or not makeindex or not bibtex or not dvipdf:
- test.skip_test("Could not find 'latex', 'makeindex', 'bibtex', or dvipdf; skipping test.\n")
+if not all((latex, makeindex, bibtex, dvipdf)):
+ test.skip_test("Could not find one or more of 'latex', 'makeindex', 'bibtex', or 'dvipdf'; skipping test.\n")
test.subdir(['docs'])
diff --git a/test/TEX/variant_dir_newglossary.py b/test/TEX/variant_dir_newglossary.py
index 1e6ab43..5e4d10d 100644
--- a/test/TEX/variant_dir_newglossary.py
+++ b/test/TEX/variant_dir_newglossary.py
@@ -39,7 +39,7 @@ test = TestSCons.TestSCons()
latex = test.where_is('latex')
if not latex:
- test.skip_test("Could not find latex; skipping test(s).\n")
+ test.skip_test("Could not find 'latex'; skipping test(s).\n")
gloss = os.system('kpsewhich glossaries.sty')
if gloss!=0:
diff --git a/test/TEX/variant_dir_style_dup0.py b/test/TEX/variant_dir_style_dup0.py
index a9649b0..430b792 100644
--- a/test/TEX/variant_dir_style_dup0.py
+++ b/test/TEX/variant_dir_style_dup0.py
@@ -45,8 +45,8 @@ latex = test.where_is('latex')
dvipdf = test.where_is('dvipdf')
makeindex = test.where_is('makeindex')
bibtex = test.where_is('bibtex')
-if not latex or not makeindex or not bibtex or not dvipdf:
- test.skip_test("Could not find 'latex', 'makeindex', 'bibtex', or 'dvipdf'; skipping test.\n")
+if not all((latex, makeindex, bibtex, dvipdf)):
+ test.skip_test("Could not find one or more of 'latex', 'makeindex', 'bibtex', or 'dvipdf'; skipping test.\n")
test.subdir(['docs'])
diff --git a/test/fixture/python_scanner/curdir_reference/helper.py b/test/fixture/python_scanner/curdir_reference/helper.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/curdir_reference/helper.py
diff --git a/test/fixture/python_scanner/curdir_reference/sconstest.skip b/test/fixture/python_scanner/curdir_reference/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/curdir_reference/sconstest.skip
diff --git a/test/fixture/python_scanner/curdir_reference/script.py b/test/fixture/python_scanner/curdir_reference/script.py
new file mode 100644
index 0000000..d533863
--- /dev/null
+++ b/test/fixture/python_scanner/curdir_reference/script.py
@@ -0,0 +1 @@
+from . import helper
diff --git a/test/fixture/python_scanner/from_import_simple_package_module1.py b/test/fixture/python_scanner/from_import_simple_package_module1.py
new file mode 100644
index 0000000..dcc86de
--- /dev/null
+++ b/test/fixture/python_scanner/from_import_simple_package_module1.py
@@ -0,0 +1 @@
+from simple_package import module1
diff --git a/test/fixture/python_scanner/from_import_simple_package_module1_as.py b/test/fixture/python_scanner/from_import_simple_package_module1_as.py
new file mode 100644
index 0000000..51061c6
--- /dev/null
+++ b/test/fixture/python_scanner/from_import_simple_package_module1_as.py
@@ -0,0 +1 @@
+from simple_package import module1 as m1
diff --git a/test/fixture/python_scanner/from_import_simple_package_modules_no_space.py b/test/fixture/python_scanner/from_import_simple_package_modules_no_space.py
new file mode 100644
index 0000000..17b82f8
--- /dev/null
+++ b/test/fixture/python_scanner/from_import_simple_package_modules_no_space.py
@@ -0,0 +1 @@
+from simple_package import module1,module2
diff --git a/test/fixture/python_scanner/from_import_simple_package_modules_with_space.py b/test/fixture/python_scanner/from_import_simple_package_modules_with_space.py
new file mode 100644
index 0000000..169e6f7
--- /dev/null
+++ b/test/fixture/python_scanner/from_import_simple_package_modules_with_space.py
@@ -0,0 +1 @@
+from simple_package import module1, module2
diff --git a/test/fixture/python_scanner/import_simple_package_module1.py b/test/fixture/python_scanner/import_simple_package_module1.py
new file mode 100644
index 0000000..bd85010
--- /dev/null
+++ b/test/fixture/python_scanner/import_simple_package_module1.py
@@ -0,0 +1 @@
+import simple_package.module1
diff --git a/test/fixture/python_scanner/import_simple_package_module1_as.py b/test/fixture/python_scanner/import_simple_package_module1_as.py
new file mode 100644
index 0000000..a706672
--- /dev/null
+++ b/test/fixture/python_scanner/import_simple_package_module1_as.py
@@ -0,0 +1 @@
+import simple_package.module1 as m1
diff --git a/test/fixture/python_scanner/imports_nested3.py b/test/fixture/python_scanner/imports_nested3.py
new file mode 100644
index 0000000..c2929d0
--- /dev/null
+++ b/test/fixture/python_scanner/imports_nested3.py
@@ -0,0 +1 @@
+import nested1.nested2.nested3
diff --git a/test/fixture/python_scanner/imports_simple_package.py b/test/fixture/python_scanner/imports_simple_package.py
new file mode 100644
index 0000000..d974128
--- /dev/null
+++ b/test/fixture/python_scanner/imports_simple_package.py
@@ -0,0 +1 @@
+import simple_package
diff --git a/test/fixture/python_scanner/nested1/__init__.py b/test/fixture/python_scanner/nested1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/__init__.py
diff --git a/test/fixture/python_scanner/nested1/module.py b/test/fixture/python_scanner/nested1/module.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/module.py
diff --git a/test/fixture/python_scanner/nested1/nested2/__init__.py b/test/fixture/python_scanner/nested1/nested2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/__init__.py
diff --git a/test/fixture/python_scanner/nested1/nested2/module.py b/test/fixture/python_scanner/nested1/nested2/module.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/module.py
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/__init__.py b/test/fixture/python_scanner/nested1/nested2/nested3/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/__init__.py
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/imports_grandparent_module.py b/test/fixture/python_scanner/nested1/nested2/nested3/imports_grandparent_module.py
new file mode 100644
index 0000000..06bb7f5
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/imports_grandparent_module.py
@@ -0,0 +1 @@
+from ... import module
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_module.py b/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_module.py
new file mode 100644
index 0000000..be10279
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_module.py
@@ -0,0 +1 @@
+from .. import module
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_then_submodule.py b/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_then_submodule.py
new file mode 100644
index 0000000..39f1a1a
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/imports_parent_then_submodule.py
@@ -0,0 +1 @@
+from ...nested2a import module
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/module.py b/test/fixture/python_scanner/nested1/nested2/nested3/module.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/module.py
diff --git a/test/fixture/python_scanner/nested1/nested2/nested3/sconstest.skip b/test/fixture/python_scanner/nested1/nested2/nested3/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/nested3/sconstest.skip
diff --git a/test/fixture/python_scanner/nested1/nested2/sconstest.skip b/test/fixture/python_scanner/nested1/nested2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2/sconstest.skip
diff --git a/test/fixture/python_scanner/nested1/nested2a/__init__.py b/test/fixture/python_scanner/nested1/nested2a/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2a/__init__.py
diff --git a/test/fixture/python_scanner/nested1/nested2a/module.py b/test/fixture/python_scanner/nested1/nested2a/module.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2a/module.py
diff --git a/test/fixture/python_scanner/nested1/nested2a/sconstest.skip b/test/fixture/python_scanner/nested1/nested2a/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/nested2a/sconstest.skip
diff --git a/test/fixture/python_scanner/nested1/sconstest.skip b/test/fixture/python_scanner/nested1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/nested1/sconstest.skip
diff --git a/test/fixture/python_scanner/sconstest.skip b/test/fixture/python_scanner/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/sconstest.skip
diff --git a/test/fixture/python_scanner/simple_package/__init__.py b/test/fixture/python_scanner/simple_package/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/simple_package/__init__.py
diff --git a/test/fixture/python_scanner/simple_package/module1.py b/test/fixture/python_scanner/simple_package/module1.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/simple_package/module1.py
diff --git a/test/fixture/python_scanner/simple_package/module2.py b/test/fixture/python_scanner/simple_package/module2.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/simple_package/module2.py
diff --git a/test/fixture/python_scanner/simple_package/sconstest.skip b/test/fixture/python_scanner/simple_package/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixture/python_scanner/simple_package/sconstest.skip
diff --git a/test/srcchange.py b/test/srcchange.py
index c2356b6..3c23737 100644
--- a/test/srcchange.py
+++ b/test/srcchange.py
@@ -62,7 +62,7 @@ SubRevision = Action(subrevision)
env=Environment()
content_env=env.Clone()
-content_env.Command('revision.in', [], '%(_python_)s getrevision > $TARGET')
+content_env.Command('revision.in', [], r'%(_python_)s getrevision > $TARGET')
content_env.AlwaysBuild('revision.in')
env.Precious('main.c')
env.Command('main.c', 'revision.in', SubRevision)
diff --git a/testing/framework/test-framework.rst b/testing/framework/test-framework.rst
index 24240ac..a0fe861 100644
--- a/testing/framework/test-framework.rst
+++ b/testing/framework/test-framework.rst
@@ -308,6 +308,9 @@ in that sense: "the fixture for this test is foo", instead of writing
a whole bunch of strings to create files. Since these setups can be
reusable across multiple tests, the *fixture* terminology applies well.
+Note: fixtures must not be treated by SCons as runnable tests. To exclude
+them, see instructions in the above section named "Finding Tests".
+
Directory Fixtures
##################