summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2018-11-13 18:58:06 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2018-11-13 18:58:06 (GMT)
commitc2aba592affffdb12d2f95e251ccfc566b6dd674 (patch)
tree3f1719afc1ec7408135659f154f4b4072f8b44af
parentade84bc59db524fbccd670bfadefa786407c7c0b (diff)
parent648cf42a89845ccad012e02609ca8958e62ce272 (diff)
downloadSCons-c2aba592affffdb12d2f95e251ccfc566b6dd674.zip
SCons-c2aba592affffdb12d2f95e251ccfc566b6dd674.tar.gz
SCons-c2aba592affffdb12d2f95e251ccfc566b6dd674.tar.bz2
Merge remote-tracking branch 'upstream/master' into subst_rewrite
-rw-r--r--.appveyor.yml13
-rw-r--r--.gitignore16
-rw-r--r--.travis.yml6
-rwxr-xr-x.travis/install.sh73
-rw-r--r--SConstruct2
-rw-r--r--doc/SConscript5
-rw-r--r--doc/generated/builders.gen140
-rw-r--r--doc/generated/examples/caching_ex-random_1.xml4
-rw-r--r--doc/generated/examples/troubleshoot_explain1_3.xml2
-rw-r--r--doc/generated/tools.gen20
-rw-r--r--doc/generated/tools.mod4
-rw-r--r--doc/generated/variables.gen270
-rw-r--r--doc/generated/variables.mod6
-rw-r--r--doc/man/scons.xml12
-rw-r--r--doc/user/misc.xml49
-rw-r--r--src/CHANGES.txt67
-rw-r--r--src/README.txt5
-rw-r--r--src/engine/SCons/CacheDir.py2
-rw-r--r--src/engine/SCons/Executor.py2
-rw-r--r--src/engine/SCons/Node/FS.py253
-rw-r--r--src/engine/SCons/Node/FSTests.py172
-rw-r--r--src/engine/SCons/Node/NodeTests.py1
-rw-r--r--src/engine/SCons/Node/Python.py13
-rw-r--r--src/engine/SCons/Node/PythonTests.py6
-rw-r--r--src/engine/SCons/Node/__init__.py73
-rw-r--r--src/engine/SCons/Platform/PlatformTests.py8
-rw-r--r--src/engine/SCons/Platform/__init__.py4
-rw-r--r--src/engine/SCons/Platform/posix.py5
-rw-r--r--src/engine/SCons/Platform/virtualenv.py120
-rw-r--r--src/engine/SCons/Platform/virtualenvTests.py243
-rw-r--r--src/engine/SCons/Platform/win32.py7
-rw-r--r--src/engine/SCons/Script/Main.py8
-rw-r--r--src/engine/SCons/Script/SConsOptions.py14
-rw-r--r--src/engine/SCons/Script/__init__.py2
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py78
-rw-r--r--src/engine/SCons/Tool/docbook/__init__.py2
-rw-r--r--src/engine/SCons/Tool/jar.py12
-rw-r--r--src/engine/SCons/Tool/javac.py17
-rw-r--r--src/engine/SCons/Tool/javac.xml513
-rw-r--r--src/engine/SCons/Tool/javah.py10
-rw-r--r--src/engine/SCons/Tool/rmic.py15
-rw-r--r--src/engine/SCons/Util.py47
-rw-r--r--src/engine/SCons/UtilTests.py252
-rw-r--r--src/engine/SCons/dblite.py9
-rw-r--r--src/script/scons-configure-cache.py129
-rw-r--r--src/script/scons.py101
-rw-r--r--src/script/sconsign.py86
-rw-r--r--test/Builder/multi/different-environments.py4
-rw-r--r--test/Builder/multi/same-overrides.py4
-rw-r--r--test/CacheDir/CacheDir_TryCompile.py71
-rw-r--r--test/Decider/MD5-timestamp-Repository.py91
-rw-r--r--test/Docbook/basic/epub/epub_cmd.py5
-rw-r--r--test/Docbook/basic/epub/image/SConstruct.cmd4
-rw-r--r--test/Docbook/basic/html/html_cmd.py4
-rw-r--r--test/Docbook/basic/html/image/SConstruct.cmd4
-rw-r--r--test/Docbook/basic/htmlchunked/htmlchunked_cmd.py4
-rw-r--r--test/Docbook/basic/htmlchunked/image/SConstruct.cmd4
-rw-r--r--test/Docbook/basic/htmlhelp/htmlhelp_cmd.py4
-rw-r--r--test/Docbook/basic/htmlhelp/image/SConstruct.cmd4
-rw-r--r--test/Docbook/basic/man/image/SConstruct.cmd4
-rw-r--r--test/Docbook/basic/man/man_cmd.py4
-rw-r--r--test/ENV.py3
-rw-r--r--test/Java/JAR.py36
-rw-r--r--test/Java/JARCHDIR.py28
-rw-r--r--test/Java/JARFLAGS.py14
-rw-r--r--test/Java/JAVABOOTCLASSPATH.py7
-rw-r--r--test/Java/JAVACFLAGS.py3
-rw-r--r--test/Java/JAVACLASSPATH.py14
-rw-r--r--test/Java/JAVAH.py6
-rw-r--r--test/Java/JAVASOURCEPATH.py3
-rw-r--r--test/Java/Java-1.6.py262
-rw-r--r--test/Java/Java-1.8.py151
-rw-r--r--test/Java/RMIC.py31
-rw-r--r--test/Java/java_version_image/SConstruct35
-rw-r--r--test/Java/java_version_image/class6/test$1.classbin0 -> 165 bytes
-rw-r--r--test/Java/java_version_image/com/sub/bar/Example4.java11
-rw-r--r--test/Java/java_version_image/com/sub/bar/Example5.java11
-rw-r--r--test/Java/java_version_image/com/sub/bar/Example6.java11
-rw-r--r--test/Java/java_version_image/com/sub/foo/Example1.java11
-rw-r--r--test/Java/java_version_image/com/sub/foo/Example2.java11
-rw-r--r--test/Java/java_version_image/com/sub/foo/Example3.java11
-rw-r--r--test/Java/java_version_image/src1/Example7.java9
-rw-r--r--test/Java/java_version_image/src2/Test.java55
-rw-r--r--test/Java/java_version_image/src4/NestedExample.java31
-rw-r--r--test/Java/java_version_image/src5/TestSCons.java7
-rw-r--r--test/Java/java_version_image/src6/TestSCons.java13
-rw-r--r--test/Java/multi-step.py24
-rw-r--r--test/Java/no-JARCHDIR.py23
-rw-r--r--test/Java/source-files.py6
-rw-r--r--test/Java/swig-dependencies.py28
-rw-r--r--test/Libs/SharedLibrary.py1
-rw-r--r--test/SWIG/build-dir.py40
-rw-r--r--test/SWIG/live.py2
-rw-r--r--test/SWIG/remove-modules.py2
-rw-r--r--test/SWIG/subdir.py2
-rw-r--r--test/Scanner/generated.py6
-rw-r--r--test/TEMPFILEPREFIX.py1
-rwxr-xr-xtest/TEX/biber_biblatex.py2
-rw-r--r--test/TEX/biber_biblatex2.py2
-rwxr-xr-xtest/TEX/biblatex.py2
-rw-r--r--test/TEX/biblatex_plain.py2
-rw-r--r--test/YACC/live.py2
-rw-r--r--test/explain/basic.py3
-rw-r--r--test/fixture/wrapper.py2
-rw-r--r--test/long-lines/signature.py23
-rw-r--r--test/scons-time/run/config/python.py8
-rw-r--r--test/scons-time/run/option/python.py8
-rw-r--r--test/sconsign/script/SConsignFile.py25
-rw-r--r--test/sconsign/script/Signatures.py24
-rw-r--r--test/sconsign/script/no-SConsignFile.py24
-rw-r--r--test/srcchange.py1
-rw-r--r--test/subdivide.py3
-rw-r--r--test/virtualenv/activated/option/enable-virtualenv.py91
-rw-r--r--test/virtualenv/activated/option/ignore-virtualenv.py90
-rw-r--r--test/virtualenv/activated/virtualenv_activated_python.py96
-rw-r--r--test/virtualenv/activated/virtualenv_detect_virtualenv.py58
-rw-r--r--test/virtualenv/always/virtualenv_global_function.py68
-rw-r--r--test/virtualenv/regularenv/virtualenv_detect_regularenv.py57
-rw-r--r--test/virtualenv/unactivated/virtualenv_unactivated_python.py95
-rw-r--r--testing/framework/.TestCommonTests.py.swpbin16384 -> 0 bytes
-rw-r--r--testing/framework/TestCmd.py25
-rw-r--r--testing/framework/TestCommon.py11
-rw-r--r--testing/framework/TestSCons.py80
123 files changed, 3455 insertions, 1365 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index edc8e55..b7252c9 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -1,6 +1,14 @@
+#version: '3.0.1.{build}'
+
image: Visual Studio 2017
shallow_clone: true
+cache:
+ - downloads -> appveyor.yml
+ - '%LOCALAPPDATA%\pip\Cache'
+ - C:\ProgramData\chocolatey\bin -> appveyor.yml
+ - C:\ProgramData\chocolatey\lib -> appveyor.yml
+
install:
- "set PATH=%PYTHON%;%PYTHON%\\Scripts;C:\\cygwin64\\bin;C:\\msys64;%PATH%"
- python --version
@@ -9,7 +17,10 @@ install:
- choco install --allow-empty-checksums dmd
- choco install --allow-empty-checksums ldc
- choco install --allow-empty-checksums swig
- - choco install --allow-empty-checksums vswhere
+ - choco install --allow-empty-checksums vswhere
+ - choco install --allow-empty-checksums xsltproc
+ - choco install --allow-empty-checksums git.install
+
environment:
matrix:
diff --git a/.gitignore b/.gitignore
index 24917ca..9bb82e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,8 @@ __pycache__/
# Distribution / packaging
.Python
-build/**
-bootstrap/**
+/build/**
+/bootstrap/**
.idea/
src/build/**
@@ -28,8 +28,6 @@ ENV/
env.bak/
venv.bak/
-
-
# mypy
.mypy_cache/
@@ -40,3 +38,13 @@ venv.bak/
# Coverage files
.coverage
htmlcov/
+
+# VS Code
+.vscode
+
+# Editor junk
+*.swp
+*.bkp
+*.bak
+*~
+!/test/Decider/switch-rebuild.py
diff --git a/.travis.yml b/.travis.yml
index ea63e57..76f6db0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,11 @@ addons:
apt:
update: true
+os:
+ - linux
+
+sudo: required
+
install:
- ./.travis/install.sh
@@ -16,7 +21,6 @@ matrix:
allow_failures:
- python: pypy
-
jobs:
include:
- &test_job
diff --git a/.travis/install.sh b/.travis/install.sh
index 6f2cfe2..15a36a3 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -1,35 +1,50 @@
#!/usr/bin/env bash
set -x
-# setup clang for clang tests using local clang installation
-sudo ln -s /usr/local/clang-5.0.0/bin/clang /usr/bin/clang
-sudo ln -s /usr/local/clang-5.0.0/bin/clang++ /usr/bin/clang++
+if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ echo "OSX"
+ brew install python --framework --universal
+else
+ # dependencies for clang tests
+ sudo apt-get -y install clang
-# dependencies for gdc tests
-sudo apt-get -y install gdc
-# dependencies for docbook tests
-sudo apt-get -y install docbook-xml xsltproc libxml2-dev libxslt-dev fop docbook-xsl-doc-pdf
-# dependencies for latex tests
-sudo apt-get -y install texlive texlive-latex3 biber texmaker ghostscript
-# need some things for building dependencies for other tests
-sudo apt-get -y install python-pip python-dev build-essential libpcre3-dev autoconf automake libtool bison subversion git
-# dependencies for docbook tests continued
-sudo pip install lxml
-# dependencies for D tests
-sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list
-wget -qO - https://dlang.org/d-keyring.gpg | sudo apt-key add -
-sudo apt-get update && sudo apt-get -y --allow-unauthenticated install dmd-bin
-# dependencies for ldc tests
-wget https://github.com/ldc-developers/ldc/releases/download/v1.4.0/ldc2-1.4.0-linux-x86_64.tar.xz
-tar xf ldc2-1.4.0-linux-x86_64.tar.xz
-sudo cp -rf ldc2-1.4.0-linux-x86_64/* /
+ # setup clang for clang tests using local clang installation
+ if [ ! -f /usr/local/clang-5.0.0/bin/clang ]; then
+ echo "No Clang 5.0.0 trying 7.0.0"
+ sudo ln -s /usr/local/clang-7.0.0/bin/clang /usr/bin/clang
+ sudo ln -s /usr/local/clang-7.0.0/bin/clang++ /usr/bin/clang++
+ else
+ echo "Clang 5.0.0"
+ sudo ln -s /usr/local/clang-5.0.0/bin/clang /usr/bin/clang
+ sudo ln -s /usr/local/clang-5.0.0/bin/clang++ /usr/bin/clang++
+ fi
-ls -l /usr/lib/*python*{so,a}*
+ # dependencies for gdc tests
+ sudo apt-get -y install gdc
+ # dependencies for docbook tests
+ sudo apt-get -y install docbook-xml xsltproc libxml2-dev libxslt-dev fop docbook-xsl-doc-pdf
+ # dependencies for latex tests
+ sudo apt-get -y install texlive-full biber texmaker
+ # need some things for building dependencies for other tests
+ sudo apt-get -y install python-pip python-dev build-essential libpcre3-dev autoconf automake libtool bison subversion git
+ # dependencies for docbook tests continued
+ sudo pip install lxml
+ # dependencies for D tests
+ sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list
+ wget -qO - https://dlang.org/d-keyring.gpg | sudo apt-key add -
+ sudo apt-get update && sudo apt-get -y --allow-unauthenticated install dmd-bin
+ # dependencies for ldc tests
+ wget https://github.com/ldc-developers/ldc/releases/download/v1.4.0/ldc2-1.4.0-linux-x86_64.tar.xz
+ tar xf ldc2-1.4.0-linux-x86_64.tar.xz
+ sudo cp -rf ldc2-1.4.0-linux-x86_64/* /
-# For now skip swig if py27
-if [[ "$PYVER" == 27 ]]; then
- # dependencies for swig tests
- wget https://github.com/swig/swig/archive/rel-3.0.12.tar.gz
- tar xzf rel-3.0.12.tar.gz
- cd swig-rel-3.0.12 && ./autogen.sh && ./configure --prefix=/usr && make && sudo make install && cd ..
-fi \ No newline at end of file
+ ls -l /usr/lib/*python*{so,a}*
+
+ # For now skip swig if py27
+ if [[ "$PYVER" == 27 ]]; then
+ # dependencies for swig tests
+ wget https://github.com/swig/swig/archive/rel-3.0.12.tar.gz
+ tar xzf rel-3.0.12.tar.gz
+ cd swig-rel-3.0.12 && ./autogen.sh && ./configure --prefix=/usr && make && sudo make install && cd ..
+ fi
+fi
diff --git a/SConstruct b/SConstruct
index f644d6d..773bacb 100644
--- a/SConstruct
+++ b/SConstruct
@@ -73,7 +73,7 @@ zip = whereis('zip')
#
date = ARGUMENTS.get('DATE')
if not date:
- date = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time()))
+ date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
developer = ARGUMENTS.get('DEVELOPER')
if not developer:
diff --git a/doc/SConscript b/doc/SConscript
index 82b29a6..5f3d559 100644
--- a/doc/SConscript
+++ b/doc/SConscript
@@ -131,8 +131,9 @@ if skip_doc:
if not os.path.isdir(scdir):
os.makedirs(scdir)
- import datetime
- today = datetime.date.today().strftime("%m/%d/%Y")
+ import time
+ today = time.strftime("%Y-%m-%d",
+ time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
version = env.subst('$VERSION')
for m in man_page_list:
man, _ = os.path.splitext(m)
diff --git a/doc/generated/builders.gen b/doc/generated/builders.gen
index ada4e43..680f72f 100644
--- a/doc/generated/builders.gen
+++ b/doc/generated/builders.gen
@@ -572,75 +572,77 @@ env.Jar(target = 'bar.jar',
<function>env.Java()</function>
</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Builds one or more Java class files.
-The sources may be any combination of explicit
-<filename>.java</filename> files,
-or directory trees which will be scanned
-for <filename>.java</filename> files.
-</para>
-
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-SCons will parse each source <filename>.java</filename> file
-to find the classes
-(including inner classes)
-defined within that file,
-and from that figure out the
-target <filename>.class</filename> files that will be created.
-The class files will be placed underneath
-the specified target directory.
-</para>
-
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-SCons will also search each Java file
-for the Java package name,
-which it assumes can be found on a line
-beginning with the string
-<literal>package</literal>
-in the first column;
-the resulting <filename>.class</filename> files
-will be placed in a directory reflecting
-the specified package name.
-For example,
-the file
-<filename>Foo.java</filename>
-defining a single public
-<classname>Foo</classname>
-class and
-containing a package name of
-<classname>sub.dir</classname>
-will generate a corresponding
-<filename>sub/dir/Foo.class</filename>
-class file.
-</para>
-
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Examples:
-</para>
-
-<example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
-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 xmlns="http://www.scons.org/dbxsd/v1.0">
-Java source files can use the native encoding for the underlying OS.
-Since SCons compiles in simple ASCII mode by default,
-the compiler will generate warnings about unmappable characters,
-which may lead to errors as the file is processed further.
-In this case, the user must specify the <literal>LANG</literal>
-environment variable to tell the compiler what encoding is used.
-For portibility, it's best if the encoding is hard-coded
-so that the compile will work if it is done on a system
-with a different encoding.
-</para>
-
-<example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
-env = Environment()
-env['ENV']['LANG'] = 'en_GB.UTF-8'
-</example_commands>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Builds one or more Java class files.
+ The sources may be any combination of explicit
+ <filename>.java</filename>
+ files,
+ or directory trees which will be scanned
+ for <filename>.java</filename> files.
+ </para>
+
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ SCons will parse each source <filename>.java</filename> file
+ to find the classes
+ (including inner classes)
+ defined within that file,
+ and from that figure out the
+ target <filename>.class</filename> files that will be created.
+ The class files will be placed underneath
+ the specified target directory.
+ </para>
+
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ SCons will also search each Java file
+ for the Java package name,
+ which it assumes can be found on a line
+ beginning with the string
+ <literal>package</literal>
+ in the first column;
+ the resulting <filename>.class</filename> files
+ will be placed in a directory reflecting
+ the specified package name.
+ For example,
+ the file
+ <filename>Foo.java</filename>
+ defining a single public
+ <classname>Foo</classname>
+ class and
+ containing a package name of
+ <classname>sub.dir</classname>
+ will generate a corresponding
+ <filename>sub/dir/Foo.class</filename>
+ class file.
+ </para>
+
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Examples:
+ </para>
+
+ <example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
+ 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 xmlns="http://www.scons.org/dbxsd/v1.0">
+ Java source files can use the native encoding for the underlying OS.
+ Since SCons compiles in simple ASCII mode by default,
+ the compiler will generate warnings about unmappable characters,
+ which may lead to errors as the file is processed further.
+ In this case, the user must specify the
+ <literal>LANG</literal>
+ environment variable to tell the compiler what encoding is used.
+ For portibility, it's best if the encoding is hard-coded
+ so that the compile will work if it is done on a system
+ with a different encoding.
+ </para>
+
+ <example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
+ env = Environment()
+ env['ENV']['LANG'] = 'en_GB.UTF-8'
+ </example_commands>
+ </listitem>
</varlistentry>
<varlistentry id="b-JavaH">
<term>
diff --git a/doc/generated/examples/caching_ex-random_1.xml b/doc/generated/examples/caching_ex-random_1.xml
index 18b04eb..3009e65 100644
--- a/doc/generated/examples/caching_ex-random_1.xml
+++ b/doc/generated/examples/caching_ex-random_1.xml
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<screen xmlns="http://www.scons.org/dbxsd/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">% <userinput>scons -Q</userinput>
-cc -o f3.o -c f3.c
cc -o f5.o -c f5.c
-cc -o f4.o -c f4.c
cc -o f2.o -c f2.c
+cc -o f4.o -c f4.c
cc -o f1.o -c f1.c
+cc -o f3.o -c f3.c
cc -o prog f1.o f2.o f3.o f4.o f5.o
</screen>
diff --git a/doc/generated/examples/troubleshoot_explain1_3.xml b/doc/generated/examples/troubleshoot_explain1_3.xml
index 064fdcb..56a7417 100644
--- a/doc/generated/examples/troubleshoot_explain1_3.xml
+++ b/doc/generated/examples/troubleshoot_explain1_3.xml
@@ -3,5 +3,5 @@
cp file.in file.oout
scons: warning: Cannot find target file.out after building
-File "/home/bdbaddog/scons/git/scons/bootstrap/src/script/scons.py", line 201, in &lt;module&gt;
+File "/home/bdeegan/devel/scons/scons-bugfixes-1/bootstrap/src/script/scons.py", line 201, in &lt;module&gt;
</screen>
diff --git a/doc/generated/tools.gen b/doc/generated/tools.gen
index f858aa4..01fb559 100644
--- a/doc/generated/tools.gen
+++ b/doc/generated/tools.gen
@@ -586,10 +586,10 @@ Sets construction variables for the <application xmlns="http://www.scons.org/dbx
<varlistentry id="t-javac">
<term>javac</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Sets construction variables for the <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
-</para>
-<para>Sets: &cv-link-JAVABOOTCLASSPATH;, &cv-link-JAVAC;, &cv-link-JAVACCOM;, &cv-link-JAVACFLAGS;, &cv-link-JAVACLASSPATH;, &cv-link-JAVACLASSSUFFIX;, &cv-link-JAVASOURCEPATH;, &cv-link-JAVASUFFIX;.</para><para>Uses: &cv-link-JAVACCOMSTR;.</para></listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Sets construction variables for the <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
+ </para>
+ <para>Sets: &cv-link-JAVABOOTCLASSPATH;, &cv-link-JAVAC;, &cv-link-JAVACCOM;, &cv-link-JAVACFLAGS;, &cv-link-JAVACLASSPATH;, &cv-link-JAVACLASSSUFFIX;, &cv-link-JAVAINCLUDES;, &cv-link-JAVASOURCEPATH;, &cv-link-JAVASUFFIX;.</para><para>Uses: &cv-link-JAVACCOMSTR;.</para></listitem>
</varlistentry>
<varlistentry id="t-javah">
<term>javah</term>
@@ -778,19 +778,19 @@ Sets construction variables for the
</para>
<para>Sets: &cv-link-AS;, &cv-link-ASCOM;, &cv-link-ASFLAGS;, &cv-link-ASPPCOM;, &cv-link-ASPPFLAGS;.</para><para>Uses: &cv-link-ASCOMSTR;, &cv-link-ASPPCOMSTR;.</para></listitem>
</varlistentry>
- <varlistentry id="t-Packaging">
- <term>Packaging</term>
+ <varlistentry id="t-packaging">
+ <term>packaging</term>
<listitem>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Sets construction variables for the <function xmlns="http://www.scons.org/dbxsd/v1.0">Package</function> Builder.
+A framework for building binary and source packages.
</para>
</listitem>
</varlistentry>
- <varlistentry id="t-packaging">
- <term>packaging</term>
+ <varlistentry id="t-Packaging">
+ <term>Packaging</term>
<listitem>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
-A framework for building binary and source packages.
+Sets construction variables for the <function xmlns="http://www.scons.org/dbxsd/v1.0">Package</function> Builder.
</para>
</listitem>
</varlistentry>
diff --git a/doc/generated/tools.mod b/doc/generated/tools.mod
index 1209d74..f9bc1d7 100644
--- a/doc/generated/tools.mod
+++ b/doc/generated/tools.mod
@@ -78,8 +78,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-mwcc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>mwcc</literal>">
<!ENTITY t-mwld "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>mwld</literal>">
<!ENTITY t-nasm "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>nasm</literal>">
-<!ENTITY t-Packaging "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Packaging</literal>">
<!ENTITY t-packaging "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>packaging</literal>">
+<!ENTITY t-Packaging "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>Packaging</literal>">
<!ENTITY t-pdf "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>pdf</literal>">
<!ENTITY t-pdflatex "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>pdflatex</literal>">
<!ENTITY t-pdftex "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>pdftex</literal>">
@@ -186,8 +186,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-link-mwcc "<link linkend='t-mwcc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>mwcc</literal></link>">
<!ENTITY t-link-mwld "<link linkend='t-mwld' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>mwld</literal></link>">
<!ENTITY t-link-nasm "<link linkend='t-nasm' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>nasm</literal></link>">
-<!ENTITY t-link-Packaging "<link linkend='t-Packaging' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>Packaging</literal></link>">
<!ENTITY t-link-packaging "<link linkend='t-packaging' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>packaging</literal></link>">
+<!ENTITY t-link-Packaging "<link linkend='t-Packaging' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>Packaging</literal></link>">
<!ENTITY t-link-pdf "<link linkend='t-pdf' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>pdf</literal></link>">
<!ENTITY t-link-pdflatex "<link linkend='t-pdflatex' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>pdflatex</literal></link>">
<!ENTITY t-link-pdftex "<link linkend='t-pdftex' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>pdftex</literal></link>">
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 9246249..17aab7b 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -3269,107 +3269,111 @@ by default.
<varlistentry id="cv-JAVABOOTCLASSPATH">
<term>JAVABOOTCLASSPATH</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Specifies the list of directories that
-will be added to the
-<application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> command line
-via the <option>-bootclasspath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Specifies the list of directories that
+ will be added to the
+ <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> command line
+ via the <option>-bootclasspath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVAC">
<term>JAVAC</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The Java compiler.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The Java compiler.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACCOM">
<term>JAVACCOM</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The command line used to compile a directory tree containing
-Java source files to
-corresponding Java class files.
-Any options specified in the <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JAVACFLAGS"><envar>$JAVACFLAGS</envar></link> construction variable
-are included on this command line.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The command line used to compile a directory tree containing
+ Java source files to
+ corresponding Java class files.
+ Any options specified in the <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JAVACFLAGS"><envar>$JAVACFLAGS</envar></link> construction variable
+ are included on this command line.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACCOMSTR">
<term>JAVACCOMSTR</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The string displayed when compiling
-a directory tree of Java source files to
-corresponding Java class files.
-If this is not set, then <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JAVACCOM"><envar>$JAVACCOM</envar></link> (the command line) is displayed.
-</para>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The string displayed when compiling
+ a directory tree of Java source files to
+ corresponding Java class files.
+ If this is not set, then <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JAVACCOM"><envar>$JAVACCOM</envar></link> (the command line) is displayed.
+ </para>
-<example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
-env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
-</example_commands>
-</listitem>
+ <example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
+ env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
+ </example_commands>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACFLAGS">
<term>JAVACFLAGS</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-General options that are passed to the Java compiler.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ General options that are passed to the Java compiler.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACLASSDIR">
<term>JAVACLASSDIR</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The directory in which Java class files may be found.
-This is stripped from the beginning of any Java .class
-file names supplied to the
-<literal>JavaH</literal>
-builder.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The directory in which Java class files may be found.
+ This is stripped from the beginning of any Java .class
+ file names supplied to the
+ <literal>JavaH</literal>
+ builder.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACLASSPATH">
<term>JAVACLASSPATH</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Specifies the list of directories that
-will be searched for Java
-<filename>.class</filename> file.
-The directories in this list will be added to the
-<application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> and <application xmlns="http://www.scons.org/dbxsd/v1.0">javah</application> command lines
-via the <option>-classpath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Specifies the list of directories that
+ will be searched for Java
+ <filename>.class</filename>
+ file.
+ The directories in this list will be added to the
+ <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> and <application xmlns="http://www.scons.org/dbxsd/v1.0">javah</application> command lines
+ via the <option>-classpath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Note that this currently just adds the specified
-directory via the <option>-classpath</option> option.
-<application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> does not currently search the
-<envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVACLASSPATH</envar> directories for dependency
-<filename>.class</filename> files.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Note that this currently just adds the specified
+ directory via the <option>-classpath</option> option.
+ <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> does not currently search the
+ <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVACLASSPATH</envar> directories for dependency
+ <filename>.class</filename>
+ files.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVACLASSSUFFIX">
<term>JAVACLASSSUFFIX</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The suffix for Java class files;
-<filename>.class</filename>
-by default.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The suffix for Java class files;
+ <filename>.class</filename>
+ by default.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVAH">
<term>JAVAH</term>
@@ -3413,65 +3417,77 @@ for Java classes.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-JAVAINCLUDES">
+ <term>JAVAINCLUDES</term>
+ <listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Include path for Java header files (such as jni.h)
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="cv-JAVASOURCEPATH">
<term>JAVASOURCEPATH</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Specifies the list of directories that
-will be searched for input
-<filename>.java</filename> file.
-The directories in this list will be added to the
-<application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> command line
-via the <option>-sourcepath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Specifies the list of directories that
+ will be searched for input
+ <filename>.java</filename>
+ file.
+ The directories in this list will be added to the
+ <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> command line
+ via the <option>-sourcepath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Note that this currently just adds the specified
-directory via the <option>-sourcepath</option> option.
-<application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> does not currently search the
-<envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVASOURCEPATH</envar> directories for dependency
-<filename>.java</filename> files.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Note that this currently just adds the specified
+ directory via the <option>-sourcepath</option> option.
+ <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> does not currently search the
+ <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVASOURCEPATH</envar> directories for dependency
+ <filename>.java</filename>
+ files.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVASUFFIX">
<term>JAVASUFFIX</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The suffix for Java files;
-<filename>.java</filename>
-by default.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ The suffix for Java files;
+ <filename>.java</filename>
+ by default.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-JAVAVERSION">
<term>JAVAVERSION</term>
<listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Specifies the Java version being used by the <function xmlns="http://www.scons.org/dbxsd/v1.0">Java</function> builder.
-This is <emphasis>not</emphasis> currently used to select one
-version of the Java compiler vs. another.
-Instead, you should set this to specify the version of Java
-supported by your <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
-The default is <literal>1.4</literal>.
-</para>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ Specifies the Java version being used by the <function xmlns="http://www.scons.org/dbxsd/v1.0">Java</function> builder.
+ This is <emphasis>not</emphasis> currently used to select one
+ version of the Java compiler vs. another.
+ Instead, you should set this to specify the version of Java
+ supported by your <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
+ The default is <literal>1.4</literal>.
+ </para>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-This is sometimes necessary because
-Java 1.5 changed the file names that are created
-for nested anonymous inner classes,
-which can cause a mismatch with the files
-that <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> expects will be generated by the <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
-Setting <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVAVERSION</envar> to <literal>1.5</literal>
-(or <literal>1.6</literal>, as appropriate)
-can make <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> realize that a Java 1.5 or 1.6
-build is actually up to date.
-</para>
-</listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ This is sometimes necessary because
+ Java 1.5 changed the file names that are created
+ for nested anonymous inner classes,
+ which can cause a mismatch with the files
+ that <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> expects will be generated by the <application xmlns="http://www.scons.org/dbxsd/v1.0">javac</application> compiler.
+ Setting <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JAVAVERSION</envar> to
+ <literal>1.5</literal>
+ (or <literal>1.6</literal>, as appropriate)
+ can make <application xmlns="http://www.scons.org/dbxsd/v1.0">SCons</application> realize that a Java 1.5 or 1.6
+ build is actually up to date.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry id="cv-LATEX">
<term>LATEX</term>
@@ -6615,16 +6631,6 @@ Example <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-SHLIBVERSION">
</para>
</listitem>
</varlistentry>
- <varlistentry id="cv-SHLIBVERSIONFLAGS">
- <term>SHLIBVERSIONFLAGS</term>
- <listitem>
-<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Extra flags added to <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-SHLINKCOM"><envar>$SHLINKCOM</envar></link> when building versioned
-<link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="b-SharedLibrary"><function>SharedLibrary</function></link>. These flags are only used when <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-SHLIBVERSION"><envar>$SHLIBVERSION</envar></link> is
-set.
-</para>
-</listitem>
- </varlistentry>
<varlistentry id="cv-_SHLIBVERSIONFLAGS">
<term>_SHLIBVERSIONFLAGS</term>
<listitem>
@@ -6638,6 +6644,16 @@ and some extra dynamically generated options (such as
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-SHLIBVERSIONFLAGS">
+ <term>SHLIBVERSIONFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Extra flags added to <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-SHLINKCOM"><envar>$SHLINKCOM</envar></link> when building versioned
+<link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="b-SharedLibrary"><function>SharedLibrary</function></link>. These flags are only used when <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-SHLIBVERSION"><envar>$SHLIBVERSION</envar></link> is
+set.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-SHLINK">
<term>SHLINK</term>
<listitem>
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index 52ee4e1..9106e94 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -232,6 +232,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-JAVAHCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVAHCOM</envar>">
<!ENTITY cv-JAVAHCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVAHCOMSTR</envar>">
<!ENTITY cv-JAVAHFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVAHFLAGS</envar>">
+<!ENTITY cv-JAVAINCLUDES "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVAINCLUDES</envar>">
<!ENTITY cv-JAVASOURCEPATH "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVASOURCEPATH</envar>">
<!ENTITY cv-JAVASUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVASUFFIX</envar>">
<!ENTITY cv-JAVAVERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$JAVAVERSION</envar>">
@@ -496,8 +497,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-_SHLIBSONAME "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_SHLIBSONAME</envar>">
<!ENTITY cv-SHLIBSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLIBSUFFIX</envar>">
<!ENTITY cv-SHLIBVERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLIBVERSION</envar>">
-<!ENTITY cv-SHLIBVERSIONFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLIBVERSIONFLAGS</envar>">
<!ENTITY cv-_SHLIBVERSIONFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_SHLIBVERSIONFLAGS</envar>">
+<!ENTITY cv-SHLIBVERSIONFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLIBVERSIONFLAGS</envar>">
<!ENTITY cv-SHLINK "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLINK</envar>">
<!ENTITY cv-SHLINKCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLINKCOM</envar>">
<!ENTITY cv-SHLINKCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHLINKCOMSTR</envar>">
@@ -862,6 +863,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-JAVAHCOM "<link linkend='cv-JAVAHCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVAHCOM</envar></link>">
<!ENTITY cv-link-JAVAHCOMSTR "<link linkend='cv-JAVAHCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVAHCOMSTR</envar></link>">
<!ENTITY cv-link-JAVAHFLAGS "<link linkend='cv-JAVAHFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVAHFLAGS</envar></link>">
+<!ENTITY cv-link-JAVAINCLUDES "<link linkend='cv-JAVAINCLUDES' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVAINCLUDES</envar></link>">
<!ENTITY cv-link-JAVASOURCEPATH "<link linkend='cv-JAVASOURCEPATH' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVASOURCEPATH</envar></link>">
<!ENTITY cv-link-JAVASUFFIX "<link linkend='cv-JAVASUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVASUFFIX</envar></link>">
<!ENTITY cv-link-JAVAVERSION "<link linkend='cv-JAVAVERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$JAVAVERSION</envar></link>">
@@ -1126,8 +1128,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-_SHLIBSONAME "<link linkend='cv-_SHLIBSONAME' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_SHLIBSONAME</envar></link>">
<!ENTITY cv-link-SHLIBSUFFIX "<link linkend='cv-SHLIBSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLIBSUFFIX</envar></link>">
<!ENTITY cv-link-SHLIBVERSION "<link linkend='cv-SHLIBVERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLIBVERSION</envar></link>">
-<!ENTITY cv-link-SHLIBVERSIONFLAGS "<link linkend='cv-SHLIBVERSIONFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLIBVERSIONFLAGS</envar></link>">
<!ENTITY cv-link-_SHLIBVERSIONFLAGS "<link linkend='cv-_SHLIBVERSIONFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_SHLIBVERSIONFLAGS</envar></link>">
+<!ENTITY cv-link-SHLIBVERSIONFLAGS "<link linkend='cv-SHLIBVERSIONFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLIBVERSIONFLAGS</envar></link>">
<!ENTITY cv-link-SHLINK "<link linkend='cv-SHLINK' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLINK</envar></link>">
<!ENTITY cv-link-SHLINKCOM "<link linkend='cv-SHLINKCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLINKCOM</envar></link>">
<!ENTITY cv-link-SHLINKCOMSTR "<link linkend='cv-SHLINKCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHLINKCOMSTR</envar></link>">
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index abbed4f..9b48f69 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -997,6 +997,12 @@ the mechanisms in the specified order.</para>
</listitem>
</varlistentry>
<varlistentry>
+ <term>--enable-virtualenv</term>
+ <listitem>
+<para>Import virtualenv-related variables to SCons.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term>-f<emphasis> file</emphasis>, --file=<emphasis>file</emphasis>, --makefile=<emphasis>file</emphasis>, --sconstruct=<emphasis>file</emphasis></term>
<listitem>
<para>Use
@@ -1051,6 +1057,12 @@ are used, the directories are searched in the order specified.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>--ignore-virtualenv</term>
+ <listitem>
+<para>Suppress importing virtualenv-related variables to SCons.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>--implicit-cache</term>
<listitem>
diff --git a/doc/user/misc.xml b/doc/user/misc.xml
index e390b7a..a595e59 100644
--- a/doc/user/misc.xml
+++ b/doc/user/misc.xml
@@ -625,4 +625,53 @@ env.Command('directory_build_info',
</section>
+ <section>
+ <title>Virtual environments (virtualenvs)</title>
+
+ <para>
+
+ Virtualenv is a tool to create isolated Python environments.
+ A python application (such as SCons) may be executed within
+ an activated virtualenv. The activation of virtualenv modifies
+ current environment by defining some virtualenv-specific variables
+ and modifying search PATH, such that executables installed within
+ virtualenv's home directory are preferred over the ones installed
+ outside of it.
+
+ </para>
+
+ <para>
+
+ Normally, SCons uses hard-coded PATH when searching for external
+ executables, so it always picks-up executables from these pre-defined
+ locations. This applies also to python interpreter, which is invoked
+ by some custom SCons tools or test suites. This means, when running
+ SCons in a virtualenv, an eventual invocation of python interpreter from
+ SCons script will most probably jump out of virtualenv and execute
+ python executable found in hard-coded SCons PATH, not the one which is
+ executing SCons. Some users may consider this as an inconsistency.
+
+ </para>
+
+ <para>
+ This issue may be overcome by using <literal>--enable-virtualenv</literal>
+ option. The option automatically imports virtualenv-related environment
+ variables to all created construction environment <literal>env['ENV']</literal>,
+ and modifies SCons PATH appropriately to prefer virtualenv's executables.
+ Setting environment variable <literal>SCONS_ENABLE_VIRTUALENV=1</literal>
+ will have same effect. If virtualenv support is enabled system-vide
+ by the environment variable, it may be suppressed with
+ <literal>--ignore-virtualenv</literal> option.
+ </para>
+
+ <para>
+ Inside of SConscript, a global function <literal>Virtualenv</literal> is
+ available. It returns a path to virtualenv's home directory, or
+ <literal>None</literal> if SCons is not running from virtualenv. Note,
+ that this function returns a path even if SCons is run from an
+ unactivated virtualenv.
+ </para>
+
+ </section>
+
</chapter>
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index f0369e0..ef214e0 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -6,14 +6,7 @@
RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
-
- From Daniel Moody:
- - Updated FS.py to handle removal of splitunc function from python 3.7
- - Updated the vc.py to ignore MSVS versions where not compiler could be found
-
- From Matthew Marinets:
- - Fixed an issue that caused the Java emitter to incorrectly parse arguments to constructors that
- implemented a class.
+** Please add to this version's notes ordered by contributors last name. NOT newest at top of list **
From Bernard Blackham:
- Fixed handling of side-effects in task master (fixes #3013).
@@ -22,7 +15,7 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- Fix the PATH created by scons.bat (and other .bat files) to provide a normalized
PATH. Some pythons in the 3.6 series are no longer able to handle paths which
have ".." in them and end up crashing. This is done by cd'ing into the directory
- we want to add to the path and then useing %CD% to give us the normalized directory
+ we want to add to the path and then using %CD% to give us the normalized directory
See bug filed under Python 3.6: https://bugs.python.org/issue32457.
Note: On Win32 PATH's which have not been normalized may cause undefined behavior
by other executables being run by SCons (or any subprocesses of executables being run by SCons).
@@ -31,8 +24,6 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
From William Deegan:
- Remove long deprecated SCons.Options code and tests. This removes BoolOption,EnumOption,
ListOption,PackageOption, and PathOption which have been replaced by *Variable() many years ago.
- - Fix issue # 3106 MSVC if using MSVC_BATCH and target dir had a space would fail due to quirk in
- MSVC's handling of escaped targetdirs when batch compiling.
- Re-Enable parallel SCons (-j) when running via Pypy
- Move SCons test framework files to testing/framework and remove all references to QMtest.
QMTest has not been used by SCons for some time now.
@@ -42,12 +33,28 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- Default path for clang/clangxx : C:\Program Files\LLVM\bin
- Default path for mingw : C:\MinGW\bin and/or C:\mingw-w64\*\mingw64\bin
- Key program to locate mingw : mingw32-make (as the gcc with mingw prefix has no fixed name)
- - Fix GH Issue #3141 unicode string in a TryAction() with python 2.7 crashes.
- Fixed issue causing stack trace when python Action function contains a unicode string when being
run with Python 2.7
- Add alternate path to QT install for Centos in qt tool: /usr/lib64/qt-3.3/bin
+ - Fix Java tools to search reasonable default paths for Win32, Linux, macOS. Add required paths
+ for swig and java native interface to JAVAINCLUDES. You should add these to your CPPPATH if you need
+ to compile with them. This handles spaces in paths in default Java paths on windows.
+ - Added more java paths to match install for Centos 7 of openjdk
+ - Fix new logic which populates JAVAINCLUDES to handle the case where javac is not found.
- Fix GH Issue #2580 - # in FRAMEWORKPATH doesn't get properly expanded. The # is left in the
command line.
+ - Fix issue #2980 with credit to Piotr Bartosik (and William Blevins). This is an issue where using
+ TimeStamp-MD5 Decider and CacheDir can yield incorrect md5's being written into the .sconsign.
+ The difference between Piotr Bartosik's patch and the current code is that the more complicated
+ creation of file to csig map is only done when the count of children for the current node doesn't
+ match the previous count which is loaded from the sconsign.
+ - Fix issue # 3106 MSVC if using MSVC_BATCH and target dir had a space would fail due to quirk in
+ MSVC's handling of escaped targetdirs when batch compiling.
+ - Fix GH Issue #3141 unicode string in a TryAction() with python 2.7 crashes.
+ - Fix GH Issue #3212 - Use of Py3 and CacheDir + Configure's TryCompile (or likely and Python Value Nodes)
+ yielded trying to combine strings and bytes which threw exception.
+ - Fix GH Issue #3225 SCons.Util.Flatten() doesn't handle MappingView's produced by dictionary as return
+ values from dict().{items(), keys(), values()}.
From Andrew Featherstone
- Removed unused --warn options from the man page and source code.
@@ -57,6 +64,10 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
objects when SCons runs with Python 3.
- Added missing FORTRANMODDIRPREFIX to the gfortran tool.
+ From Matthew Marinets:
+ - Fixed an issue that caused the Java emitter to incorrectly parse arguments to constructors that
+ implemented a class.
+
From Fredrik Medley:
- Fix exception when printing of EnviromentError messages.
Specifically, this fixes error reporting of the race condition when
@@ -76,14 +87,8 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- Set the pickling protocal back to highest which was causing issues
with variant dir tests. This will cause issues if reading sconsigns
pickled with the previous lower protocal.
-
-
- From William Deegan:
- - Updated logic for mingw and clang on win32 to search default tool install paths if not
- found in normal SCons PATH. If the user specifies PATH or tool specific paths they
- will be used and the default paths below will be ignored.
- - Default path for clang/clangxx : C:\Program Files\LLVM\bin
- - Default path for mingw : c:\MinGW\bin
+ - Updated FS.py to handle removal of splitunc function from python 3.7
+ - Updated the vc.py to ignore MSVS versions where not compiler could be found
From Gary Oberbrunner:
- Fix bug when Installing multiple subdirs outside the source tree
@@ -99,6 +104,14 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- In the testing framework, module TestCommon, fixed must_contain(),
must_not_contain(), and related methods of TestCommon class to work with
substrings located at zero offset.
+ - Added virtualenv support. A new function Virtualenv() determines whether
+ SCons runs in a virtualenv. The search PATH may also be extended to
+ prefer executables from the current virtualenv over the ones provided by
+ base environment. New option --enable-virtualenv provided to import some
+ virtualenv-related variables to SCons and extend every env['ENV']['PATH']
+ automatically. New option --ignore-virtualenv disables this. Two
+ environment variables, SCONS_ENABLE_VIRTUALENV and
+ SCONS_IGNORE_VIRTUALENV are supported for the same purpose.
From Richard West:
- Add SConstruct.py, Sconstruct.py, sconstruct.py to the search path for the root SConstruct file.
@@ -138,7 +151,8 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
to the specfile without adding specific logic for each one to scons.
- The test for Python.h needed by swig tests is moved to get_python_platform
so it does not have to be repeated in every test; picks up one failure
- which did not make the (previously needed) check.
+ which did not make the (previously needed) check. Windows version
+ of get_python_platform needed some rework in case running in virtualenv.
- If test opens os.devnull, register with atexit so file opens do not leak.
- Fix bugs in Win32 process spawn logic to handle OSError exception correctly.
- Use time.perf_counter instead of time.clock if it exists.
@@ -158,16 +172,21 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- Add xz compression format to packaging choices.
- Syntax cleanups - trailing blanks, use "is" to compare with None, etc.
Three uses of variables not defined are changed.
+ - Some script changes in trying to find scons engine
+ - Update (pep8) configure-cache script, add a --show option.
+ - Fix for a couple of "what if tool not found" exceptions in framework.
- From Hao Wu
- - typo in customized decider example in user guide
+ From Bernhard M. Wiedemann:
+ - Update SCons' internal scons build logic to allow overriding build date
+ with SOURCE_DATE_EPOCH for SCons itself.
+ - Change the datestamps in SCons' docs and embedded in code use ISO 8601 format and UTC
From Hao Wu
+ - Typo in customized decider example in user guide
- Replace usage of unittest.TestSuite with unittest.main() (fix #3113)
-
RELEASE 3.0.1 - Mon, 12 Nov 2017 15:31:33 -0700
From Daniel Moody:
diff --git a/src/README.txt b/src/README.txt
index d80460a..ce65b8d 100644
--- a/src/README.txt
+++ b/src/README.txt
@@ -28,8 +28,7 @@ the latest version by checking the SCons download page at:
EXECUTION REQUIREMENTS
======================
-Running SCons requires Python version 2.7.*. Currently it does not
-run on the Python 3.x release. There should be
+Running SCons requires Python version 2.7.* or 3.5.* and above. There should be
no other dependencies or requirements to run SCons. (There is, however,
an additional requirement to *install* SCons from this particular
package; see the next section.)
@@ -146,7 +145,7 @@ of small examples for getting started using SCons.
Additional documentation for SCons is available at:
- http://www.scons.org/doc.html
+ https://scons.org/documentation.html
LICENSING
diff --git a/src/engine/SCons/CacheDir.py b/src/engine/SCons/CacheDir.py
index ab80808..ab23f31 100644
--- a/src/engine/SCons/CacheDir.py
+++ b/src/engine/SCons/CacheDir.py
@@ -221,7 +221,9 @@ class CacheDir(object):
return None, None
sig = node.get_cachedir_bsig()
+
subdir = sig[:self.config['prefix_len']].upper()
+
dir = os.path.join(self.path, subdir)
return dir, os.path.join(dir, sig)
diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py
index bce1549..01d01cd 100644
--- a/src/engine/SCons/Executor.py
+++ b/src/engine/SCons/Executor.py
@@ -450,6 +450,8 @@ class Executor(object, with_metaclass(NoSlotsPyPy)):
"""Fetch the signature contents. This is the main reason this
class exists, so we can compute this once and cache it regardless
of how many target or source Nodes there are.
+
+ Returns bytes
"""
try:
return self._memo['get_contents']
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index bc15064..77c340f 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -43,6 +43,7 @@ import stat
import sys
import time
import codecs
+from itertools import chain
import SCons.Action
import SCons.Debug
@@ -56,6 +57,7 @@ import SCons.Util
import SCons.Warnings
from SCons.Debug import Trace
+from . import DeciderNeedsNode
print_duplicate = 0
@@ -74,6 +76,9 @@ def sconsign_dir(node):
_sconsign_map = {0 : sconsign_none,
1 : sconsign_dir}
+class FileBuildInfoFileToCsigMappingError(Exception):
+ pass
+
class EntryProxyAttributeError(AttributeError):
"""
An AttributeError subclass for recording and displaying the name
@@ -285,11 +290,13 @@ def set_duplicate(duplicate):
Link_Funcs.append(link_dict[func])
def LinkFunc(target, source, env):
- # Relative paths cause problems with symbolic links, so
- # we use absolute paths, which may be a problem for people
- # who want to move their soft-linked src-trees around. Those
- # people should use the 'hard-copy' mode, softlinks cannot be
- # used for that; at least I have no idea how ...
+ """
+ Relative paths cause problems with symbolic links, so
+ we use absolute paths, which may be a problem for people
+ who want to move their soft-linked src-trees around. Those
+ people should use the 'hard-copy' mode, softlinks cannot be
+ used for that; at least I have no idea how ...
+ """
src = source[0].get_abspath()
dest = target[0].get_abspath()
dir, file = os.path.split(dest)
@@ -690,10 +697,15 @@ class Base(SCons.Node.Node):
@SCons.Memoize.CountMethodCall
def stat(self):
- try: return self._memo['stat']
- except KeyError: pass
- try: result = self.fs.stat(self.get_abspath())
- except os.error: result = None
+ try:
+ return self._memo['stat']
+ except KeyError:
+ pass
+ try:
+ result = self.fs.stat(self.get_abspath())
+ except os.error:
+ result = None
+
self._memo['stat'] = result
return result
@@ -705,13 +717,17 @@ class Base(SCons.Node.Node):
def getmtime(self):
st = self.stat()
- if st: return st[stat.ST_MTIME]
- else: return None
+ if st:
+ return st[stat.ST_MTIME]
+ else:
+ return None
def getsize(self):
st = self.stat()
- if st: return st[stat.ST_SIZE]
- else: return None
+ if st:
+ return st[stat.ST_SIZE]
+ else:
+ return None
def isdir(self):
st = self.stat()
@@ -1056,21 +1072,22 @@ _classEntry = Entry
class LocalFS(object):
-
- # This class implements an abstraction layer for operations involving
- # a local file system. Essentially, this wraps any function in
- # the os, os.path or shutil modules that we use to actually go do
- # anything with or to the local file system.
- #
- # Note that there's a very good chance we'll refactor this part of
- # the architecture in some way as we really implement the interface(s)
- # for remote file system Nodes. For example, the right architecture
- # might be to have this be a subclass instead of a base class.
- # Nevertheless, we're using this as a first step in that direction.
- #
- # We're not using chdir() yet because the calling subclass method
- # needs to use os.chdir() directly to avoid recursion. Will we
- # really need this one?
+ """
+ This class implements an abstraction layer for operations involving
+ a local file system. Essentially, this wraps any function in
+ the os, os.path or shutil modules that we use to actually go do
+ anything with or to the local file system.
+
+ Note that there's a very good chance we'll refactor this part of
+ the architecture in some way as we really implement the interface(s)
+ for remote file system Nodes. For example, the right architecture
+ might be to have this be a subclass instead of a base class.
+ Nevertheless, we're using this as a first step in that direction.
+
+ We're not using chdir() yet because the calling subclass method
+ needs to use os.chdir() directly to avoid recursion. Will we
+ really need this one?
+ """
#def chdir(self, path):
# return os.chdir(path)
def chmod(self, path, mode):
@@ -2470,11 +2487,42 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
if key not in ('__weakref__',):
setattr(self, key, value)
+ def __eq__(self, other):
+ return self.csig == other.csig and self.timestamp == other.timestamp and self.size == other.size
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
class FileBuildInfo(SCons.Node.BuildInfoBase):
- __slots__ = ()
+ """
+ This is info loaded from sconsign.
+
+ Attributes unique to FileBuildInfo:
+ dependency_map : Caches file->csig mapping
+ for all dependencies. Currently this is only used when using
+ MD5-timestamp decider.
+ It's used to ensure that we copy the correct
+ csig from previous build to be written to .sconsign when current build
+ is done. Previously the matching of csig to file was strictly by order
+ they appeared in bdepends, bsources, or bimplicit, and so a change in order
+ or count of any of these could yield writing wrong csig, and then false positive
+ rebuilds
+ """
+ __slots__ = ('dependency_map')
current_version_id = 2
+ def __setattr__(self, key, value):
+
+ # If any attributes are changed in FileBuildInfo, we need to
+ # invalidate the cached map of file name to content signature
+ # heald in dependency_map. Currently only used with
+ # MD5-timestamp decider
+ if key != 'dependency_map' and hasattr(self, 'dependency_map'):
+ del self.dependency_map
+
+ return super(FileBuildInfo, self).__setattr__(key, value)
+
def convert_to_sconsign(self):
"""
Converts this FileBuildInfo object for writing to a .sconsign file
@@ -3243,9 +3291,108 @@ class File(Base):
def changed_state(self, target, prev_ni):
return self.state != SCons.Node.up_to_date
- def changed_timestamp_then_content(self, target, prev_ni):
+
+ # Caching node -> string mapping for the below method
+ __dmap_cache = {}
+ __dmap_sig_cache = {}
+
+
+ def _build_dependency_map(self, binfo):
+ """
+ Build mapping from file -> signature
+
+ Args:
+ self - self
+ binfo - buildinfo from node being considered
+
+ Returns:
+ dictionary of file->signature mappings
+ """
+
+ # For an "empty" binfo properties like bsources
+ # do not exist: check this to avoid exception.
+ if (len(binfo.bsourcesigs) + len(binfo.bdependsigs) + \
+ len(binfo.bimplicitsigs)) == 0:
+ return {}
+
+
+ # store this info so we can avoid regenerating it.
+ binfo.dependency_map = { str(child):signature for child, signature in zip(chain(binfo.bsources, binfo.bdepends, binfo.bimplicit),
+ chain(binfo.bsourcesigs, binfo.bdependsigs, binfo.bimplicitsigs))}
+
+ return binfo.dependency_map
+
+ def _get_previous_signatures(self, dmap):
+ """
+ Return a list of corresponding csigs from previous
+ build in order of the node/files in children.
+
+ Args:
+ self - self
+ dmap - Dictionary of file -> csig
+
+ Returns:
+ List of csigs for provided list of children
+ """
+ prev = []
+
+ # First try the simple name for node
+ c_str = str(self)
+ if os.altsep:
+ c_str = c_str.replace(os.sep, os.altsep)
+ df = dmap.get(c_str, None)
+ if not df:
+ try:
+ # this should yield a path which matches what's in the sconsign
+ c_str = self.get_path()
+ if os.altsep:
+ c_str = c_str.replace(os.sep, os.altsep)
+
+ df = dmap.get(c_str, None)
+
+ except AttributeError as e:
+ raise FileBuildInfoFileToCsigMappingError("No mapping from file name to content signature for :%s"%c_str)
+
+ return df
+
+ def changed_timestamp_then_content(self, target, prev_ni, node=None):
+ """
+ Used when decider for file is Timestamp-MD5
+
+ NOTE: If the timestamp hasn't changed this will skip md5'ing the
+ file and just copy the prev_ni provided. If the prev_ni
+ is wrong. It will propagate it.
+ See: https://github.com/SCons/scons/issues/2980
+
+ Args:
+ self - dependency
+ target - target
+ prev_ni - The NodeInfo object loaded from previous builds .sconsign
+ node - Node instance. This is the only changed* function which requires
+ node to function. So if we detect that it's not passed.
+ we throw DeciderNeedsNode, and caller should handle this and pass node.
+
+ Returns:
+ Boolean - Indicates if node(File) has changed.
+ """
+ if node is None:
+ # We need required node argument to get BuildInfo to function
+ raise DeciderNeedsNode(self.changed_timestamp_then_content)
+
+ # Now get sconsign name -> csig map and then get proper prev_ni if possible
+ bi = node.get_stored_info().binfo
+ rebuilt = False
+ try:
+ dependency_map = bi.dependency_map
+ except AttributeError as e:
+ dependency_map = self._build_dependency_map(bi)
+ rebuilt = True
+
+ prev_ni = self._get_previous_signatures(dependency_map)
+
if not self.changed_timestamp_match(target, prev_ni):
try:
+ # NOTE: We're modifying the current node's csig in a query.
self.get_ninfo().csig = prev_ni.csig
except AttributeError:
pass
@@ -3259,6 +3406,12 @@ class File(Base):
return 1
def changed_timestamp_match(self, target, prev_ni):
+ """
+ Return True if the timestamps don't match or if there is no previous timestamp
+ :param target:
+ :param prev_ni: Information about the node from the previous build
+ :return:
+ """
try:
return self.get_timestamp() != prev_ni.timestamp
except AttributeError:
@@ -3280,7 +3433,9 @@ class File(Base):
# ...and they'd like a local copy.
e = LocalCopy(self, r, None)
if isinstance(e, SCons.Errors.BuildError):
- raise
+ # Likely this should be re-raising exception e
+ # (which would be BuildError)
+ raise e
SCons.Node.store_info_map[self.store_info](self)
if T: Trace(' 1\n')
return 1
@@ -3301,9 +3456,12 @@ class File(Base):
result = self
if not self.exists():
norm_name = _my_normcase(self.name)
- for dir in self.dir.get_all_rdirs():
- try: node = dir.entries[norm_name]
- except KeyError: node = dir.file_on_disk(self.name)
+ for repo_dir in self.dir.get_all_rdirs():
+ try:
+ node = repo_dir.entries[norm_name]
+ except KeyError:
+ node = repo_dir.file_on_disk(self.name)
+
if node and node.exists() and \
(isinstance(node, File) or isinstance(node, Entry)
or not node.is_derived()):
@@ -3325,6 +3483,28 @@ class File(Base):
self._memo['rfile'] = result
return result
+ def find_repo_file(self):
+ """
+ For this node, find if there exists a corresponding file in one or more repositories
+ :return: list of corresponding files in repositories
+ """
+ retvals = []
+
+ norm_name = _my_normcase(self.name)
+ for repo_dir in self.dir.get_all_rdirs():
+ try:
+ node = repo_dir.entries[norm_name]
+ except KeyError:
+ node = repo_dir.file_on_disk(self.name)
+
+ if node and node.exists() and \
+ (isinstance(node, File) or isinstance(node, Entry) \
+ or not node.is_derived()):
+ retvals.append(node)
+
+ return retvals
+
+
def rstr(self):
return str(self.rfile())
@@ -3382,6 +3562,8 @@ class File(Base):
because multiple targets built by the same action will all
have the same build signature, and we have to differentiate
them somehow.
+
+ Signature should normally be string of hex digits.
"""
try:
return self.cachesig
@@ -3391,10 +3573,13 @@ class File(Base):
# Collect signatures for all children
children = self.children()
sigs = [n.get_cachedir_csig() for n in children]
+
# Append this node's signature...
sigs.append(self.get_contents_sig())
+
# ...and it's path
sigs.append(self.get_internal_path())
+
# Merge this all into a single signature
result = self.cachesig = SCons.Util.MD5collect(sigs)
return result
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 698f574..23ec48e 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -41,6 +41,7 @@ import SCons.Errors
import SCons.Node.FS
import SCons.Util
import SCons.Warnings
+import SCons.Environment
built_it = None
@@ -1133,7 +1134,10 @@ class FSTestCase(_tempdirTestCase):
e1 = fs.Entry(p)
e2 = fs.Entry(path)
assert e1 is e2, (e1, e2)
- assert str(e1) is str(e2), (str(e1), str(e2))
+ a=str(e1)
+ b=str(e2)
+ assert a == b, ("Strings should match for same file/node\n%s\n%s"%(a,b))
+
# Test for a bug in 0.04 that did not like looking up
# dirs with a trailing slash on Windows.
@@ -2460,6 +2464,139 @@ class FileTestCase(_tempdirTestCase):
assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1)
assert not os.path.exists(build_f1.get_abspath()), "%s did not get removed after %s was removed" % (build_f1, src_f1)
+ def test_changed(self):
+ """
+ Verify that changes between BuildInfo's list of souces, depends, and implicit
+ dependencies do not corrupt content signature values written to .SConsign
+ when using CacheDir and Timestamp-MD5 decider.
+ This is for issue #2980
+ """
+ # node should have
+ # 1 source (for example main.cpp)
+ # 0 depends
+ # N implicits (for example ['alpha.h', 'beta.h', 'gamma.h', '/usr/bin/g++'])
+
+ class ChangedNode(SCons.Node.FS.File):
+ def __init__(self, name, directory=None, fs=None):
+ SCons.Node.FS.File.__init__(self, name, directory, fs)
+ self.name = name
+ self.Tag('found_includes', [])
+ self.stored_info = None
+ self.build_env = None
+ self.changed_since_last_build = 4
+ self.timestamp = 1
+
+ def get_stored_info(self):
+ return self.stored_info
+
+ def get_build_env(self):
+ return self.build_env
+
+ def get_timestamp(self):
+ """ Fake timestamp so they always match"""
+ return self.timestamp
+
+ def get_contents(self):
+ return self.name
+
+ def get_ninfo(self):
+ """ mocked to ensure csig will equal the filename"""
+ try:
+ return self.ninfo
+ except AttributeError:
+ self.ninfo = FakeNodeInfo(self.name, self.timestamp)
+ return self.ninfo
+
+ def get_csig(self):
+ ninfo = self.get_ninfo()
+ try:
+ return ninfo.csig
+ except AttributeError:
+ pass
+
+ return "Should Never Happen"
+
+ class ChangedEnvironment(SCons.Environment.Base):
+
+ def __init__(self):
+ SCons.Environment.Base.__init__(self)
+ self.decide_source = self._changed_timestamp_then_content
+
+ class FakeNodeInfo(object):
+ def __init__(self, csig, timestamp):
+ self.csig = csig
+ self.timestamp = timestamp
+
+ #Create nodes
+ fs = SCons.Node.FS.FS()
+ d = self.fs.Dir('.')
+
+ node = ChangedNode('main.o',d,fs) # main.o
+ s1 = ChangedNode('main.cpp',d,fs) # main.cpp
+ s1.timestamp = 2 # this changed
+ i1 = ChangedNode('alpha.h',d,fs) # alpha.h - The bug is caused because the second build adds this file
+ i1.timestamp = 2 # This is the new file.
+ i2 = ChangedNode('beta.h',d,fs) # beta.h
+ i3 = ChangedNode('gamma.h',d,fs) # gamma.h - In the bug beta.h's csig from binfo overwrites this ones
+ i4 = ChangedNode('/usr/bin/g++',d,fs) # /usr/bin/g++
+
+ node.add_source([s1])
+ node.add_dependency([])
+ node.implicit = [i1, i2, i3, i4]
+ node.implicit_set = set()
+ # node._add_child(node.implicit, node.implicit_set, [n7, n8, n9])
+ # node._add_child(node.implicit, node.implicit_set, [n10, n11, n12])
+
+ # Mock out node's scan method
+ # node.scan = lambda *args: None
+
+ # Mock out nodes' children() ?
+ # Should return Node's.
+ # All those nodes should have changed_since_last_build set to match Timestamp-MD5's
+ # decider method...
+
+ # Generate sconsign entry needed
+ sconsign_entry = SCons.SConsign.SConsignEntry()
+ sconsign_entry.binfo = node.new_binfo()
+ sconsign_entry.ninfo = node.new_ninfo()
+
+ # mock out loading info from sconsign
+ # This will cause node.get_stored_info() to return our freshly created sconsign_entry
+ node.stored_info = sconsign_entry
+
+ # binfo = information from previous build (from sconsign)
+ # We'll set the following attributes (which are lists): "bsources", "bsourcesigs",
+ # "bdepends","bdependsigs", "bimplicit", "bimplicitsigs"
+ bi = sconsign_entry.binfo
+ bi.bsources = ['main.cpp']
+ bi.bsourcesigs=[FakeNodeInfo('main.cpp',1),]
+
+ bi.bdepends = []
+ bi.bdependsigs = []
+
+ bi.bimplicit = ['beta.h','gamma.h']
+ bi.bimplicitsigs = [FakeNodeInfo('beta.h',1), FakeNodeInfo('gamma.h',1)]
+
+ ni = sconsign_entry.ninfo
+ # We'll set the following attributes (which are lists): sources, depends, implicit lists
+
+ #Set timestamp-md5
+ #Call changed
+ #Check results
+ node.build_env = ChangedEnvironment()
+
+ changed = node.changed()
+
+ # change to true to debug
+ if False:
+ print("Changed:%s"%changed)
+ print("%15s -> csig:%s"%(s1.name, s1.ninfo.csig))
+ print("%15s -> csig:%s"%(i1.name, i1.ninfo.csig))
+ print("%15s -> csig:%s"%(i2.name, i2.ninfo.csig))
+ print("%15s -> csig:%s"%(i3.name, i3.ninfo.csig))
+ print("%15s -> csig:%s"%(i4.name, i4.ninfo.csig))
+
+ self.assertEqual(i2.name,i2.ninfo.csig, "gamma.h's fake csig should equal gamma.h but equals:%s"%i2.ninfo.csig)
class GlobTestCase(_tempdirTestCase):
@@ -3752,38 +3889,7 @@ class AbsolutePathTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
- suite.addTest(VariantDirTestCase())
- suite.addTest(find_fileTestCase())
- suite.addTest(StringDirTestCase())
- suite.addTest(stored_infoTestCase())
- suite.addTest(has_src_builderTestCase())
- suite.addTest(prepareTestCase())
- suite.addTest(SConstruct_dirTestCase())
- suite.addTest(clearTestCase())
- suite.addTest(disambiguateTestCase())
- suite.addTest(postprocessTestCase())
- suite.addTest(SpecialAttrTestCase())
- suite.addTest(SaveStringsTestCase())
- tclasses = [
- AbsolutePathTestCase,
- BaseTestCase,
- CacheDirTestCase,
- DirTestCase,
- DirBuildInfoTestCase,
- DirNodeInfoTestCase,
- EntryTestCase,
- FileTestCase,
- FileBuildInfoTestCase,
- FileNodeInfoTestCase,
- FSTestCase,
- GlobTestCase,
- RepositoryTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index ca6c883..7dc5f5d 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -1349,6 +1349,7 @@ class NodeListTestCase(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index 8c47c97..4a62f04 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -137,6 +137,10 @@ class Value(SCons.Node.Node):
return contents
def get_contents(self):
+ """
+ Get contents for signature calculations.
+ :return: bytes
+ """
text_contents = self.get_text_contents()
try:
return text_contents.encode()
@@ -155,12 +159,17 @@ class Value(SCons.Node.Node):
def get_csig(self, calc=None):
"""Because we're a Python value node and don't have a real
timestamp, we get to ignore the calculator and just use the
- value contents."""
+ value contents.
+
+ Returns string. Ideally string of hex digits. (Not bytes)
+ """
try:
return self.ninfo.csig
except AttributeError:
pass
- contents = self.get_contents()
+
+ contents = self.get_text_contents()
+
self.get_ninfo().csig = contents
return contents
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index 7ef9e52..8a01503 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -88,15 +88,15 @@ class ValueTestCase(unittest.TestCase):
"""
v1 = SCons.Node.Python.Value('aaa')
csig = v1.get_csig(None)
- assert csig.decode() == 'aaa', csig
+ assert csig == 'aaa', csig
v2 = SCons.Node.Python.Value(7)
csig = v2.get_csig(None)
- assert csig.decode() == '7', csig
+ assert csig == '7', csig
v3 = SCons.Node.Python.Value(None)
csig = v3.get_csig(None)
- assert csig.decode() == 'None', csig
+ assert csig == 'None', csig
class ValueNodeInfoTestCase(unittest.TestCase):
def test___init__(self):
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index c18a954..131953b 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -45,6 +45,7 @@ from __future__ import print_function
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
import collections
import copy
from itertools import chain
@@ -139,6 +140,7 @@ def exists_entry(node):
node.disambiguate()
return _exists_map[node._func_exists](node)
+
def exists_file(node):
# Duplicate from source path if we are set up to do this.
if node.duplicate and not node.is_derived() and not node.linked:
@@ -246,6 +248,21 @@ _target_from_source_map = {0 : target_from_source_none,
# used by it.
#
+
+class DeciderNeedsNode(Exception):
+ """
+ Indicate that the decider needs the node as well as the target and the dependency.
+ Normally the node and the target are the same, but in the case of repository
+ They may be different. Also the NodeInfo is retrieved from the node
+ """
+ def __init__(self, call_this_decider):
+ """
+ :param call_this_decider: to return the decider to call directly since deciders
+ are called through several levels of indirection
+ """
+ self.decider = call_this_decider
+
+
#
# First, the single decider functions
#
@@ -269,6 +286,7 @@ def changed_since_last_build_node(node, target, prev_ni):
"""
raise NotImplementedError
+
def changed_since_last_build_alias(node, target, prev_ni):
cur_csig = node.get_csig()
try:
@@ -276,19 +294,24 @@ def changed_since_last_build_alias(node, target, prev_ni):
except AttributeError:
return 1
+
def changed_since_last_build_entry(node, target, prev_ni):
node.disambiguate()
return _decider_map[node.changed_since_last_build](node, target, prev_ni)
+
def changed_since_last_build_state_changed(node, target, prev_ni):
- return (node.state != SCons.Node.up_to_date)
+ return node.state != SCons.Node.up_to_date
+
def decide_source(node, target, prev_ni):
return target.get_build_env().decide_source(node, target, prev_ni)
+
def decide_target(node, target, prev_ni):
return target.get_build_env().decide_target(node, target, prev_ni)
+
def changed_since_last_build_python(node, target, prev_ni):
cur_csig = node.get_csig()
try:
@@ -380,6 +403,7 @@ class NodeInfoBase(object):
"""
state = other.__getstate__()
self.__setstate__(state)
+
def format(self, field_list=None, names=0):
if field_list is None:
try:
@@ -1136,7 +1160,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
if self._specific_sources:
- sources = [ s for s in self.sources if not s in ignore_set]
+ sources = [s for s in self.sources if not s in ignore_set]
else:
sources = executor.get_unignored_sources(self, self.ignore)
@@ -1145,13 +1169,17 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
binfo.bsources = [s for s in sources if s not in seen and not seen.add(s)]
binfo.bsourcesigs = [s.get_ninfo() for s in binfo.bsources]
+ binfo.bdepends = [d for d in self.depends if d not in ignore_set]
+ binfo.bdependsigs = [d.get_ninfo() for d in self.depends]
- binfo.bdepends = self.depends
- binfo.bdependsigs = [d.get_ninfo() for d in self.depends if d not in ignore_set]
-
- binfo.bimplicit = self.implicit or []
- binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit if i not in ignore_set]
-
+ # Because self.implicit is initialized to None (and not empty list [])
+ # we have to handle this case
+ if not self.implicit:
+ binfo.bimplicit = []
+ binfo.bimplicitsigs = []
+ else:
+ binfo.bimplicit = [i for i in self.implicit if i not in ignore_set]
+ binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit]
return binfo
@@ -1213,7 +1241,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
return _exists_map[self._func_exists](self)
def rexists(self):
- """Does this node exist locally or in a repositiory?"""
+ """Does this node exist locally or in a repository?"""
# There are no repositories by default:
return _rexists_map[self._func_rexists](self)
@@ -1452,13 +1480,18 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
result = True
for child, prev_ni in zip(children, then):
- if _decider_map[child.changed_since_last_build](child, self, prev_ni):
- if t: Trace(': %s changed' % child)
- result = True
+ try:
+ if _decider_map[child.changed_since_last_build](child, self, prev_ni):
+ if t: Trace(': %s changed' % child)
+ result = True
+ except DeciderNeedsNode as e:
+ if e.decider(self, prev_ni, node=node):
+ if t: Trace(': %s changed' % child)
+ result = True
- contents = self.get_executor().get_contents()
if self.has_builder():
import SCons.Util
+ contents = self.get_executor().get_contents()
newsig = SCons.Util.MD5signature(contents)
if bi.bactsig != newsig:
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
@@ -1607,7 +1640,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
# so we only print them after running them through this lambda
# to turn them into the right relative Node and then return
# its string.
- def stringify( s, E=self.dir.Entry ) :
+ def stringify( s, E=self.dir.Entry):
if hasattr( s, 'dir' ) :
return str(E(s))
return str(s)
@@ -1616,15 +1649,21 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
removed = [x for x in old_bkids if not x in new_bkids]
if removed:
- removed = list(map(stringify, removed))
+ removed = [stringify(r) for r in removed]
fmt = "`%s' is no longer a dependency\n"
lines.extend([fmt % s for s in removed])
for k in new_bkids:
if not k in old_bkids:
lines.append("`%s' is a new dependency\n" % stringify(k))
- elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
- lines.append("`%s' changed\n" % stringify(k))
+ else:
+ try:
+ changed = _decider_map[k.changed_since_last_build](k, self, osig[k])
+ except DeciderNeedsNode as e:
+ changed = e.decider(self, osig[k], node=self)
+
+ if changed:
+ lines.append("`%s' changed\n" % stringify(k))
if len(lines) == 0 and old_bkids != new_bkids:
lines.append("the dependency order changed:\n" +
diff --git a/src/engine/SCons/Platform/PlatformTests.py b/src/engine/SCons/Platform/PlatformTests.py
index 6f720ec..3f42eae 100644
--- a/src/engine/SCons/Platform/PlatformTests.py
+++ b/src/engine/SCons/Platform/PlatformTests.py
@@ -36,7 +36,7 @@ import SCons.Action
class Environment(collections.UserDict):
def Detect(self, cmd):
return cmd
-
+
def AppendENVPath(self, key, value):
pass
@@ -174,9 +174,9 @@ class TempFileMungeTestCase(unittest.TestCase):
SCons.Action.print_actions = 0
# Create an instance of object derived class to allow setattrb
class Node(object) :
- class Attrs(object):
+ class Attrs(object):
pass
- def __init__(self):
+ def __init__(self):
self.attributes = self.Attrs()
target = [Node()]
cmd = t(target, None, env, 0)
@@ -203,7 +203,7 @@ class PlatformEscapeTestCase(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
-
+
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Platform/__init__.py b/src/engine/SCons/Platform/__init__.py
index 1654d0a..8784d5e 100644
--- a/src/engine/SCons/Platform/__init__.py
+++ b/src/engine/SCons/Platform/__init__.py
@@ -87,6 +87,7 @@ def platform_default():
else:
return sys.platform
+
def platform_module(name = platform_default()):
"""Return the imported module for the platform.
@@ -117,11 +118,13 @@ def platform_module(name = platform_default()):
setattr(SCons.Platform, name, mod)
return sys.modules[full_name]
+
def DefaultToolList(platform, env):
"""Select a default tool list for the specified platform.
"""
return SCons.Tool.tool_list(platform, env)
+
class PlatformSpec(object):
def __init__(self, name, generate):
self.name = name
@@ -133,6 +136,7 @@ class PlatformSpec(object):
def __str__(self):
return self.name
+
class TempFileMunge(object):
"""A callable class. You can set an Environment variable to this,
then call it with a string argument, then it will perform temporary
diff --git a/src/engine/SCons/Platform/posix.py b/src/engine/SCons/Platform/posix.py
index ae2ad1a..ad4e859 100644
--- a/src/engine/SCons/Platform/posix.py
+++ b/src/engine/SCons/Platform/posix.py
@@ -41,6 +41,8 @@ import select
import SCons.Util
from SCons.Platform import TempFileMunge
+from SCons.Platform.virtualenv import ImportVirtualenv
+from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
exitvalmap = {
2 : 127,
@@ -119,6 +121,9 @@ def generate(env):
# Must be able to have GCC and DMD work in the same build, so:
env['__DRPATH'] = '$_DRPATH'
+ if enable_virtualenv and not ignore_virtualenv:
+ ImportVirtualenv(env)
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Platform/virtualenv.py b/src/engine/SCons/Platform/virtualenv.py
new file mode 100644
index 0000000..03fb486
--- /dev/null
+++ b/src/engine/SCons/Platform/virtualenv.py
@@ -0,0 +1,120 @@
+"""SCons.Platform.virtualenv
+
+Support for virtualenv.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import sys
+import SCons.Util
+
+
+virtualenv_enabled_by_default = False
+
+
+def _enable_virtualenv_default():
+ return SCons.Util.get_bool_envvar('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default)
+
+
+def _ignore_virtualenv_default():
+ return SCons.Util.get_bool_envvar('SCONS_IGNORE_VIRTUALENV', False)
+
+
+enable_virtualenv = _enable_virtualenv_default()
+ignore_virtualenv = _ignore_virtualenv_default()
+virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
+
+
+def _running_in_virtualenv():
+ """Returns True, if scons is executed within a virtualenv"""
+ # see https://stackoverflow.com/a/42580137
+ return (hasattr(sys, 'real_prefix') or
+ (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
+
+
+def _is_path_in(path, base):
+ """Returns true, if **path** is located under the **base** directory."""
+ if not path or not base: # empty path may happen, base too
+ return False
+ rp = os.path.relpath(path, base)
+ return ((not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir))
+
+
+def _inject_venv_variables(env):
+ if 'ENV' not in env:
+ env['ENV'] = {}
+ ENV = env['ENV']
+ for name in virtualenv_variables:
+ try:
+ ENV[name] = os.environ[name]
+ except KeyError:
+ pass
+
+def _inject_venv_path(env, path_list=None):
+ """Modify environment such that SCons will take into account its virtualenv
+ when running external tools."""
+ if path_list is None:
+ path_list = os.getenv('PATH')
+ env.PrependENVPath('PATH', select_paths_in_venv(path_list))
+
+
+def select_paths_in_venv(path_list):
+ """Returns a list of paths from **path_list** which are under virtualenv's
+ home directory."""
+ if SCons.Util.is_String(path_list):
+ path_list = path_list.split(os.path.pathsep)
+ # Find in path_list the paths under the virtualenv's home
+ return [path for path in path_list if IsInVirtualenv(path)]
+
+
+def ImportVirtualenv(env):
+ """Copies virtualenv-related environment variables from OS environment
+ to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``.
+ """
+ _inject_venv_variables(env)
+ _inject_venv_path(env)
+
+
+def Virtualenv():
+ """Returns path to the virtualenv home if scons is executing within a
+ virtualenv or None, if not."""
+ if _running_in_virtualenv():
+ return sys.prefix
+ return None
+
+
+def IsInVirtualenv(path):
+ """Returns True, if **path** is under virtualenv's home directory. If not,
+ or if we don't use virtualenv, returns False."""
+ return _is_path_in(path, Virtualenv())
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Platform/virtualenvTests.py b/src/engine/SCons/Platform/virtualenvTests.py
new file mode 100644
index 0000000..02b37ab
--- /dev/null
+++ b/src/engine/SCons/Platform/virtualenvTests.py
@@ -0,0 +1,243 @@
+#
+# __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 unittest
+import os
+import sys
+
+import SCons.Platform.virtualenv
+import SCons.Util
+
+class Environment(collections.UserDict):
+ def Detect(self, cmd):
+ return cmd
+
+ def AppendENVPath(self, key, value):
+ if SCons.Util.is_List(value):
+ value = os.path.pathsep.join(value)
+ if 'ENV' not in self:
+ self['ENV'] = {}
+ current = self['ENV'].get(key)
+ if not current:
+ self['ENV'][key] = value
+ else:
+ self['ENV'][key] = os.path.pathsep.join([current, value])
+
+ def PrependENVPath(self, key, value):
+ if SCons.Util.is_List(value):
+ value = os.path.pathsep.join(value)
+ if 'ENV' not in self:
+ self['ENV'] = {}
+ current = self['ENV'].get(key)
+ if not current:
+ self['ENV'][key] = value
+ else:
+ self['ENV'][key] = os.path.pathsep.join([value, current])
+
+class SysPrefixes(object):
+ """Used to temporarily mock sys.prefix, sys.real_prefix and sys.base_prefix"""
+ def __init__(self, prefix, real_prefix=None, base_prefix=None):
+ self._prefix = prefix
+ self._real_prefix = real_prefix
+ self._base_prefix = base_prefix
+
+ def start(self):
+ self._store()
+ sys.prefix = self._prefix
+ if self._real_prefix is None:
+ if hasattr(sys, 'real_prefix'):
+ del sys.real_prefix
+ else:
+ sys.real_prefix = self._real_prefix
+ if self._base_prefix is None:
+ if hasattr(sys, 'base_prefix'):
+ del sys.base_prefix
+ else:
+ sys.base_prefix = self._base_prefix
+
+ def stop(self):
+ self._restore()
+
+ def __enter__(self):
+ self.start()
+ attrs = ('prefix', 'real_prefix', 'base_prefix')
+ return {k: getattr(sys, k) for k in attrs if hasattr(sys, k)}
+
+ def __exit__(self, *args):
+ self.stop()
+
+ def _store(self):
+ s = dict()
+ if hasattr(sys, 'real_prefix'):
+ s['real_prefix'] = sys.real_prefix
+ if hasattr(sys, 'base_prefix'):
+ s['base_prefix'] = sys.base_prefix
+ s['prefix'] = sys.prefix
+ self._stored = s
+
+ def _restore(self):
+ s = self._stored
+ if 'real_prefix' in s:
+ sys.real_prefix = s['real_prefix']
+ if 'base_prefix' in s:
+ sys.base_prefix = s['base_prefix']
+ if 'prefix' in s:
+ sys.prefix = s['prefix']
+ del self._stored
+
+def _p(p):
+ """Converts path string **p** from posix format to os-specific format."""
+ drive = []
+ if p.startswith('/') and sys.platform == 'win32':
+ drive = ['C:']
+ pieces = p.split('/')
+ return os.path.sep.join(drive + pieces)
+
+
+class _is_path_in_TestCase(unittest.TestCase):
+ def test_false(self):
+ for args in [ ('',''),
+ ('', _p('/foo/bar')),
+ (_p('/foo/bar'), ''),
+ (_p('/foo/bar'), _p('/foo/bar')),
+ (_p('/foo/bar'), _p('/foo/bar/geez')),
+ (_p('/'), _p('/foo')),
+ (_p('foo'), _p('foo/bar')) ]:
+ assert SCons.Platform.virtualenv._is_path_in(*args) is False, "_is_path_in(%r, %r) should be False" % args
+
+ def test__true(self):
+ for args in [ (_p('/foo'), _p('/')),
+ (_p('/foo/bar'), _p('/foo')),
+ (_p('/foo/bar/geez'), _p('/foo/bar')),
+ (_p('/foo//bar//geez'), _p('/foo/bar')),
+ (_p('/foo/bar/geez'), _p('/foo//bar')),
+ (_p('/foo/bar/geez'), _p('//foo//bar')) ]:
+ assert SCons.Platform.virtualenv._is_path_in(*args) is True, "_is_path_in(%r, %r) should be True" % args
+
+class IsInVirtualenvTestCase(unittest.TestCase):
+ def test_false(self):
+ # "without wirtualenv" - always false
+ with SysPrefixes(_p('/prefix')):
+ for p in [ _p(''),
+ _p('/foo'),
+ _p('/prefix'),
+ _p('/prefix/foo') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ # "with virtualenv"
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ for p in [ _p(''),
+ _p('/real/prefix/foo'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/bar/..'),
+ _p('/virtualenv/prefix/bar/../../bleah'),
+ _p('/virtualenv/bleah') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ # "with venv"
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ for p in [ _p(''),
+ _p('/base/prefix/foo'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/bar/..'),
+ _p('/virtualenv/prefix/bar/../../bleah'),
+ _p('/virtualenv/bleah') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ def test_true(self):
+ # "with virtualenv"
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ for p in [ _p('/virtualenv/prefix/foo'),
+ _p('/virtualenv/prefix/foo/bar') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is True, "IsInVirtualenv(%r) should be True" % p
+
+ # "with venv"
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ for p in [ _p('/virtualenv/prefix/foo'),
+ _p('/virtualenv/prefix/foo/bar') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is True, "IsInVirtualenv(%r) should be True" % p
+
+class _inject_venv_pathTestCase(unittest.TestCase):
+ def path_list(self):
+ return [
+ _p('/virtualenv/prefix/bin'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/../bar'),
+ _p('/home/user/.local/bin'),
+ _p('/usr/bin'),
+ _p('/opt/bin')
+ ]
+ def test_with_path_string(self):
+ env = Environment()
+ path_string = os.path.pathsep.join(self.path_list())
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ SCons.Platform.virtualenv._inject_venv_path(env, path_string)
+ assert env['ENV']['PATH'] == _p('/virtualenv/prefix/bin'), env['ENV']['PATH']
+
+ def test_with_path_list(self):
+ env = Environment()
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ SCons.Platform.virtualenv._inject_venv_path(env, self.path_list())
+ assert env['ENV']['PATH'] == _p('/virtualenv/prefix/bin'), env['ENV']['PATH']
+
+class VirtualenvTestCase(unittest.TestCase):
+ def test_none(self):
+ def _msg(given):
+ return "Virtualenv() should be None, not %s" % repr(given)
+
+ with SysPrefixes(_p('/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve is None , _msg(ve)
+ with SysPrefixes(_p('/base/prefix'), base_prefix=_p('/base/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve is None, _msg(ve)
+
+ def test_not_none(self):
+ def _msg(expected, given):
+ return "Virtualenv() should == %r, not %s" % (_p(expected), repr(given))
+
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/virtualenv/prefix'), _msg('/virtualenv/prefix', ve)
+ with SysPrefixes(_p('/same/prefix'), real_prefix=_p('/same/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/same/prefix'), _msg('/same/prefix', ve)
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/virtualenv/prefix'), _msg('/virtualenv/prefix', ve)
+
+
+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/Platform/win32.py b/src/engine/SCons/Platform/win32.py
index ea2fd3f..3b76208 100644
--- a/src/engine/SCons/Platform/win32.py
+++ b/src/engine/SCons/Platform/win32.py
@@ -39,6 +39,8 @@ import tempfile
from SCons.Platform.posix import exitvalmap
from SCons.Platform import TempFileMunge
+from SCons.Platform.virtualenv import ImportVirtualenv
+from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
import SCons.Util
try:
@@ -436,7 +438,7 @@ def generate(env):
if v:
env['ENV']['COMSPEC'] = v
- env.AppendENVPath('PATH', get_system_root() + '\System32')
+ env.AppendENVPath('PATH', get_system_root() + '\\System32')
env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
env['OBJPREFIX'] = ''
@@ -462,6 +464,9 @@ def generate(env):
env['HOST_OS'] = 'win32'
env['HOST_ARCH'] = get_architecture().arch
+ if enable_virtualenv and not ignore_virtualenv:
+ ImportVirtualenv(env)
+
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index 6516a15..2c59808 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -59,6 +59,7 @@ import SCons.Job
import SCons.Node
import SCons.Node.FS
import SCons.Platform
+import SCons.Platform.virtualenv
import SCons.SConf
import SCons.Script
import SCons.Taskmaster
@@ -863,6 +864,13 @@ def _main(parser):
for warning_type, message in delayed_warnings:
SCons.Warnings.warn(warning_type, message)
+ if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ if options.enable_virtualenv:
+ SCons.Platform.virtualenv.enable_virtualenv = True
+
+ if options.ignore_virtualenv:
+ SCons.Platform.virtualenv.ignore_virtualenv = True
+
if options.diskcheck:
SCons.Node.FS.set_diskcheck(options.diskcheck)
diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py
index 60d456e..37dd644 100644
--- a/src/engine/SCons/Script/SConsOptions.py
+++ b/src/engine/SCons/Script/SConsOptions.py
@@ -38,6 +38,7 @@ except ImportError:
_ = gettext
import SCons.Node.FS
+import SCons.Platform.virtualenv
import SCons.Warnings
OptionValueError = optparse.OptionValueError
@@ -706,6 +707,12 @@ def Parser(version):
action="callback", callback=opt_duplicate,
help=opt_duplicate_help)
+ if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ op.add_option('--enable-virtualenv',
+ dest="enable_virtualenv",
+ action="store_true",
+ help="Import certain virtualenv variables to SCons")
+
op.add_option('-f', '--file', '--makefile', '--sconstruct',
nargs=1, type="string",
dest="file", default=[],
@@ -733,6 +740,11 @@ def Parser(version):
help="Search DIR for imported Python modules.",
metavar="DIR")
+ op.add_option('--ignore-virtualenv',
+ dest="ignore_virtualenv",
+ action="store_true",
+ help="Do not import virtualenv variables to SCons")
+
op.add_option('--implicit-cache',
dest='implicit_cache', default=False,
action="store_true",
@@ -906,6 +918,7 @@ def Parser(version):
action="append",
help="Search REPOSITORY for source and target files.")
+
# Options from Make and Cons classic that we do not yet support,
# but which we may support someday and whose (potential) meanings
# we don't want to change. These all get a "the -X option is not
@@ -978,7 +991,6 @@ def Parser(version):
action="callback", callback=opt_not_yet,
# help="Warn when an undefined variable is referenced."
help=SUPPRESS_HELP)
-
return op
# Local Variables:
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 90bc311..d602507 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -82,6 +82,7 @@ import SCons.Builder
import SCons.Environment
import SCons.Node.FS
import SCons.Platform
+import SCons.Platform.virtualenv
import SCons.Scanner
import SCons.SConf
import SCons.Subst
@@ -149,6 +150,7 @@ Environment = SCons.Environment.Environment
#OptParser = SCons.SConsOptions.OptParser
FindPathDirs = SCons.Scanner.FindPathDirs
Platform = SCons.Platform.Platform
+Virtualenv = SCons.Platform.virtualenv.Virtualenv
Return = _SConscript.Return
Scanner = SCons.Scanner.Base
Tool = SCons.Tool.Tool
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 23cc43b..0d4c95a 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -32,6 +32,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
import re
+import glob
java_parsing = 1
@@ -391,6 +392,83 @@ else:
"""
return os.path.split(fn)
+
+
+java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk%s*/bin'
+java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin'
+
+java_macos_include_dir = '/System/Library/Frameworks/JavaVM.framework/Headers/'
+java_macos_version_include_dir = '/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/'
+
+java_linux_include_dirs = ['/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/java-*/include']
+# Need to match path like below (from Centos 7)
+# /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/
+java_linux_version_include_dirs = ['/usr/lib/jvm/java-*-sun-%s*/include',
+ '/usr/lib/jvm/java-%s*-openjdk*/include',
+ '/usr/java/jdk%s*/include']
+
+
+
+def get_java_install_dirs(platform, version=None):
+ """
+ Using patterns above find the java jdk install dir
+ :param platform:
+ :param version: If specified, only look for java sdk's of this version
+ :return: list of default paths for java.
+ """
+ paths = []
+ if platform == 'win32':
+ if version:
+ paths = glob.glob(java_win32_version_dir_glob%version)
+ else:
+ paths = glob.glob(java_win32_dir_glob)
+ else:
+ # do nothing for now
+ pass
+
+ paths=sorted(paths)
+
+ return paths
+
+def get_java_include_paths(env, javac, version):
+ """
+ Return java include paths
+ :param platform:
+ :param javac:
+ :return:
+ """
+ paths = []
+ if not javac:
+ # there are no paths if we've not detected javac.
+ pass
+ elif env['PLATFORM'] == 'win32':
+ javac_bin_dir = os.path.dirname(javac)
+ java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include'))
+ paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')]
+ elif env['PLATFORM'] == 'darwin':
+ if not version:
+ paths = [java_macos_include_dir]
+ else:
+ paths = sorted(glob.glob(java_macos_version_include_dir%version))
+ else:
+ base_paths=[]
+ if not version:
+ for p in java_linux_include_dirs:
+ base_paths.extend(glob.glob(p))
+ else:
+ for p in java_linux_version_include_dirs:
+ base_paths.extend(glob.glob(p%version))
+
+ for p in base_paths:
+ paths.extend([p, os.path.join(p,'linux')])
+
+ #print("PATHS:%s"%paths)
+ return paths
+
+
+
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py
index d60789d..5b98db2 100644
--- a/src/engine/SCons/Tool/docbook/__init__.py
+++ b/src/engine/SCons/Tool/docbook/__init__.py
@@ -166,6 +166,8 @@ xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan']
# see: http://saxon.sourceforge.net/
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
+ # Note if saxon-xslt is version 5.5 the proper arguments are: (swap order of docbook_xsl and source)
+ # 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $SOURCE $DOCBOOK_XSL $DOCBOOK_XSLTPROCPARAMS',
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'}
xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'}
diff --git a/src/engine/SCons/Tool/jar.py b/src/engine/SCons/Tool/jar.py
index 481f8f5..e0a6a69 100644
--- a/src/engine/SCons/Tool/jar.py
+++ b/src/engine/SCons/Tool/jar.py
@@ -32,11 +32,13 @@ selection method.
#
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
import SCons.Subst
import SCons.Util
from SCons.Node.FS import _my_normcase
-import os
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
def jarSources(target, source, env, for_signature):
"""Only include sources that are not a manifest file."""
@@ -206,6 +208,14 @@ def generate(env):
env.AddMethod(Jar)
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for clang
+ jar = SCons.Tool.find_program_path(env, 'jar',
+ default_paths=get_java_install_dirs(env['PLATFORM']))
+ if jar:
+ jar_bin_dir = os.path.dirname(jar)
+ env.AppendENVPath('PATH', jar_bin_dir)
+
env['JAR'] = 'jar'
env['JARFLAGS'] = SCons.Util.CLVar('cf')
env['_JARFLAGS'] = jarFlags
diff --git a/src/engine/SCons/Tool/javac.py b/src/engine/SCons/Tool/javac.py
index 72c48f7..8d98b54 100644
--- a/src/engine/SCons/Tool/javac.py
+++ b/src/engine/SCons/Tool/javac.py
@@ -39,7 +39,7 @@ from collections import OrderedDict
import SCons.Action
import SCons.Builder
from SCons.Node.FS import _my_normcase
-from SCons.Tool.JavaCommon import parse_java_file
+from SCons.Tool.JavaCommon import parse_java_file, get_java_install_dirs, get_java_include_paths
import SCons.Util
def classname(path):
@@ -208,6 +208,21 @@ def generate(env):
env.AddMethod(Java)
+ version = env.get('JAVAVERSION', None)
+
+ javac = SCons.Tool.find_program_path(env, 'javac')
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for javac
+ paths=get_java_install_dirs(env['PLATFORM'], version=version)
+ javac = SCons.Tool.find_program_path(env, 'javac',
+ default_paths=paths)
+ if javac:
+ javac_bin_dir = os.path.dirname(javac)
+ env.AppendENVPath('PATH', javac_bin_dir)
+
+ env['JAVAINCLUDES'] = get_java_include_paths(env, javac, version)
+
+
env['JAVAC'] = 'javac'
env['JAVACFLAGS'] = SCons.Util.CLVar('')
env['JAVABOOTCLASSPATH'] = []
diff --git a/src/engine/SCons/Tool/javac.xml b/src/engine/SCons/Tool/javac.xml
index 543d669..97ec7d2 100644
--- a/src/engine/SCons/Tool/javac.xml
+++ b/src/engine/SCons/Tool/javac.xml
@@ -7,279 +7,298 @@ 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;
-]>
+ <!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="javac">
-<summary>
-<para>
-Sets construction variables for the &javac; compiler.
-</para>
-</summary>
-<sets>
-<item>JAVAC</item>
-<item>JAVACFLAGS</item>
-<item>JAVACCOM</item>
-<item>JAVACLASSSUFFIX</item>
-<item>JAVASUFFIX</item>
-<item>JAVABOOTCLASSPATH</item>
-<item>JAVACLASSPATH</item>
-<item>JAVASOURCEPATH</item>
-</sets>
-<uses>
-<item>JAVACCOMSTR</item>
-</uses>
-</tool>
+ <tool name="javac">
+ <summary>
+ <para>
+ Sets construction variables for the &javac; compiler.
+ </para>
+ </summary>
+ <sets>
+ <item>JAVAC</item>
+ <item>JAVACFLAGS</item>
+ <item>JAVACCOM</item>
+ <item>JAVACLASSSUFFIX</item>
+ <item>JAVAINCLUDES</item>
+ <item>JAVASUFFIX</item>
+ <item>JAVABOOTCLASSPATH</item>
+ <item>JAVACLASSPATH</item>
+ <item>JAVASOURCEPATH</item>
+ </sets>
+ <uses>
+ <item>JAVACCOMSTR</item>
+ </uses>
+ </tool>
-<builder name="Java">
-<summary>
-<para>
-Builds one or more Java class files.
-The sources may be any combination of explicit
-<filename>.java</filename> files,
-or directory trees which will be scanned
-for <filename>.java</filename> files.
-</para>
+ <builder name="Java">
+ <summary>
+ <para>
+ Builds one or more Java class files.
+ The sources may be any combination of explicit
+ <filename>.java</filename>
+ files,
+ or directory trees which will be scanned
+ for <filename>.java</filename> files.
+ </para>
-<para>
-SCons will parse each source <filename>.java</filename> file
-to find the classes
-(including inner classes)
-defined within that file,
-and from that figure out the
-target <filename>.class</filename> files that will be created.
-The class files will be placed underneath
-the specified target directory.
-</para>
+ <para>
+ SCons will parse each source <filename>.java</filename> file
+ to find the classes
+ (including inner classes)
+ defined within that file,
+ and from that figure out the
+ target <filename>.class</filename> files that will be created.
+ The class files will be placed underneath
+ the specified target directory.
+ </para>
-<para>
-SCons will also search each Java file
-for the Java package name,
-which it assumes can be found on a line
-beginning with the string
-<literal>package</literal>
-in the first column;
-the resulting <filename>.class</filename> files
-will be placed in a directory reflecting
-the specified package name.
-For example,
-the file
-<filename>Foo.java</filename>
-defining a single public
-<classname>Foo</classname>
-class and
-containing a package name of
-<classname>sub.dir</classname>
-will generate a corresponding
-<filename>sub/dir/Foo.class</filename>
-class file.
-</para>
+ <para>
+ SCons will also search each Java file
+ for the Java package name,
+ which it assumes can be found on a line
+ beginning with the string
+ <literal>package</literal>
+ in the first column;
+ the resulting <filename>.class</filename> files
+ will be placed in a directory reflecting
+ the specified package name.
+ For example,
+ the file
+ <filename>Foo.java</filename>
+ defining a single public
+ <classname>Foo</classname>
+ class and
+ containing a package name of
+ <classname>sub.dir</classname>
+ will generate a corresponding
+ <filename>sub/dir/Foo.class</filename>
+ class file.
+ </para>
-<para>
-Examples:
-</para>
+ <para>
+ Examples:
+ </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'])
-</example_commands>
+ <example_commands>
+ 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>
-Java source files can use the native encoding for the underlying OS.
-Since SCons compiles in simple ASCII mode by default,
-the compiler will generate warnings about unmappable characters,
-which may lead to errors as the file is processed further.
-In this case, the user must specify the <literal>LANG</literal>
-environment variable to tell the compiler what encoding is used.
-For portibility, it's best if the encoding is hard-coded
-so that the compile will work if it is done on a system
-with a different encoding.
-</para>
+ <para>
+ Java source files can use the native encoding for the underlying OS.
+ Since SCons compiles in simple ASCII mode by default,
+ the compiler will generate warnings about unmappable characters,
+ which may lead to errors as the file is processed further.
+ In this case, the user must specify the
+ <literal>LANG</literal>
+ environment variable to tell the compiler what encoding is used.
+ For portibility, it's best if the encoding is hard-coded
+ so that the compile will work if it is done on a system
+ with a different encoding.
+ </para>
-<example_commands>
-env = Environment()
-env['ENV']['LANG'] = 'en_GB.UTF-8'
-</example_commands>
-</summary>
-</builder>
+ <example_commands>
+ env = Environment()
+ env['ENV']['LANG'] = 'en_GB.UTF-8'
+ </example_commands>
+ </summary>
+ </builder>
-<cvar name="JAVABOOTCLASSPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be added to the
-&javac; command line
-via the <option>-bootclasspath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVABOOTCLASSPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be added to the
+ &javac; command line
+ via the <option>-bootclasspath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVAC">
-<summary>
-<para>
-The Java compiler.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAINCLUDES">
+ <summary>
+ <para>
+ Include path for Java header files (such as jni.h)
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACCOM">
-<summary>
-<para>
-The command line used to compile a directory tree containing
-Java source files to
-corresponding Java class files.
-Any options specified in the &cv-link-JAVACFLAGS; construction variable
-are included on this command line.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAC">
+ <summary>
+ <para>
+ The Java compiler.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACCOMSTR">
-<summary>
-<para>
-The string displayed when compiling
-a directory tree of Java source files to
-corresponding Java class files.
-If this is not set, then &cv-link-JAVACCOM; (the command line) is displayed.
-</para>
+ <cvar name="JAVACCOM">
+ <summary>
+ <para>
+ The command line used to compile a directory tree containing
+ Java source files to
+ corresponding Java class files.
+ Any options specified in the &cv-link-JAVACFLAGS; construction variable
+ are included on this command line.
+ </para>
+ </summary>
+ </cvar>
-<example_commands>
-env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
-</example_commands>
-</summary>
-</cvar>
+ <cvar name="JAVACCOMSTR">
+ <summary>
+ <para>
+ The string displayed when compiling
+ a directory tree of Java source files to
+ corresponding Java class files.
+ If this is not set, then &cv-link-JAVACCOM; (the command line) is displayed.
+ </para>
-<cvar name="JAVACFLAGS">
-<summary>
-<para>
-General options that are passed to the Java compiler.
-</para>
-</summary>
-</cvar>
+ <example_commands>
+ env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
+ </example_commands>
+ </summary>
+ </cvar>
-<cvar name="JAVACLASSDIR">
-<summary>
-<para>
-The directory in which Java class files may be found.
-This is stripped from the beginning of any Java .class
-file names supplied to the
-<literal>JavaH</literal>
-builder.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVACFLAGS">
+ <summary>
+ <para>
+ General options that are passed to the Java compiler.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACLASSPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be searched for Java
-<filename>.class</filename> file.
-The directories in this list will be added to the
-&javac; and &javah; command lines
-via the <option>-classpath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <cvar name="JAVACLASSDIR">
+ <summary>
+ <para>
+ The directory in which Java class files may be found.
+ This is stripped from the beginning of any Java .class
+ file names supplied to the
+ <literal>JavaH</literal>
+ builder.
+ </para>
+ </summary>
+ </cvar>
-<para>
-Note that this currently just adds the specified
-directory via the <option>-classpath</option> option.
-&SCons; does not currently search the
-&cv-JAVACLASSPATH; directories for dependency
-<filename>.class</filename> files.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVACLASSPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be searched for Java
+ <filename>.class</filename>
+ file.
+ The directories in this list will be added to the
+ &javac; and &javah; command lines
+ via the <option>-classpath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<cvar name="JAVACLASSSUFFIX">
-<summary>
-<para>
-The suffix for Java class files;
-<filename>.class</filename>
-by default.
-</para>
-</summary>
-</cvar>
+ <para>
+ Note that this currently just adds the specified
+ directory via the <option>-classpath</option> option.
+ &SCons; does not currently search the
+ &cv-JAVACLASSPATH; directories for dependency
+ <filename>.class</filename>
+ files.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVASOURCEPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be searched for input
-<filename>.java</filename> file.
-The directories in this list will be added to the
-&javac; command line
-via the <option>-sourcepath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <cvar name="JAVACLASSSUFFIX">
+ <summary>
+ <para>
+ The suffix for Java class files;
+ <filename>.class</filename>
+ by default.
+ </para>
+ </summary>
+ </cvar>
-<para>
-Note that this currently just adds the specified
-directory via the <option>-sourcepath</option> option.
-&SCons; does not currently search the
-&cv-JAVASOURCEPATH; directories for dependency
-<filename>.java</filename> files.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVASOURCEPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be searched for input
+ <filename>.java</filename>
+ file.
+ The directories in this list will be added to the
+ &javac; command line
+ via the <option>-sourcepath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<cvar name="JAVASUFFIX">
-<summary>
-<para>
-The suffix for Java files;
-<filename>.java</filename>
-by default.
-</para>
-</summary>
-</cvar>
+ <para>
+ Note that this currently just adds the specified
+ directory via the <option>-sourcepath</option> option.
+ &SCons; does not currently search the
+ &cv-JAVASOURCEPATH; directories for dependency
+ <filename>.java</filename>
+ files.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVAVERSION">
-<summary>
-<para>
-Specifies the Java version being used by the &b-Java; builder.
-This is <emphasis>not</emphasis> currently used to select one
-version of the Java compiler vs. another.
-Instead, you should set this to specify the version of Java
-supported by your &javac; compiler.
-The default is <literal>1.4</literal>.
-</para>
+ <cvar name="JAVASUFFIX">
+ <summary>
+ <para>
+ The suffix for Java files;
+ <filename>.java</filename>
+ by default.
+ </para>
+ </summary>
+ </cvar>
-<para>
-This is sometimes necessary because
-Java 1.5 changed the file names that are created
-for nested anonymous inner classes,
-which can cause a mismatch with the files
-that &SCons; expects will be generated by the &javac; compiler.
-Setting &cv-JAVAVERSION; to <literal>1.5</literal>
-(or <literal>1.6</literal>, as appropriate)
-can make &SCons; realize that a Java 1.5 or 1.6
-build is actually up to date.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAVERSION">
+ <summary>
+ <para>
+ Specifies the Java version being used by the &b-Java; builder.
+ This is <emphasis>not</emphasis> currently used to select one
+ version of the Java compiler vs. another.
+ Instead, you should set this to specify the version of Java
+ supported by your &javac; compiler.
+ The default is <literal>1.4</literal>.
+ </para>
+
+ <para>
+ This is sometimes necessary because
+ Java 1.5 changed the file names that are created
+ for nested anonymous inner classes,
+ which can cause a mismatch with the files
+ that &SCons; expects will be generated by the &javac; compiler.
+ Setting &cv-JAVAVERSION; to
+ <literal>1.5</literal>
+ (or <literal>1.6</literal>, as appropriate)
+ can make &SCons; realize that a Java 1.5 or 1.6
+ build is actually up to date.
+ </para>
+ </summary>
+ </cvar>
</sconsdoc>
diff --git a/src/engine/SCons/Tool/javah.py b/src/engine/SCons/Tool/javah.py
index c092273..f514479 100644
--- a/src/engine/SCons/Tool/javah.py
+++ b/src/engine/SCons/Tool/javah.py
@@ -40,6 +40,8 @@ import SCons.Builder
import SCons.Node.FS
import SCons.Tool.javac
import SCons.Util
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
def emit_java_headers(target, source, env):
"""Create and return lists of Java stub header files that will
@@ -120,6 +122,14 @@ def generate(env):
java_javah = SCons.Tool.CreateJavaHBuilder(env)
java_javah.emitter = emit_java_headers
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for clang
+ javah = SCons.Tool.find_program_path(env, 'javah',
+ default_paths=get_java_install_dirs(env['PLATFORM']))
+ if javah:
+ javah_bin_dir = os.path.dirname(javah)
+ env.AppendENVPath('PATH', javah_bin_dir)
+
env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator
env['JAVAH'] = 'javah'
env['JAVAHFLAGS'] = SCons.Util.CLVar('')
diff --git a/src/engine/SCons/Tool/rmic.py b/src/engine/SCons/Tool/rmic.py
index 4d1bd28..173ef5f 100644
--- a/src/engine/SCons/Tool/rmic.py
+++ b/src/engine/SCons/Tool/rmic.py
@@ -40,6 +40,9 @@ import SCons.Builder
import SCons.Node.FS
import SCons.Util
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
+
def emit_rmic_classes(target, source, env):
"""Create and return lists of Java RMI stub and skeleton
class files to be created from a set of class files.
@@ -105,6 +108,18 @@ def generate(env):
"""Add Builders and construction variables for rmic to an Environment."""
env['BUILDERS']['RMIC'] = RMICBuilder
+ if env['PLATFORM'] == 'win32':
+ version = env.get('JAVAVERSION', None)
+ default_paths=get_java_install_dirs(env['PLATFORM'], version=version)
+
+ # Ensure that we have a proper path for rmic
+ rmic = SCons.Tool.find_program_path(env, 'rmic', default_paths=default_paths)
+
+ # print("RMIC: %s"%rmic)
+ if rmic:
+ rmic_bin_dir = os.path.dirname(rmic)
+ env.AppendENVPath('PATH', rmic_bin_dir)
+
env['RMIC'] = 'rmic'
env['RMICFLAGS'] = SCons.Util.CLVar('')
env['RMICCOM'] = '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}'
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 480d087..67639b3 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -44,7 +44,7 @@ except ImportError:
from UserString import UserString
try:
- from collections.abc import Iterable
+ from collections.abc import Iterable, MappingView
except ImportError:
from collections import Iterable
@@ -368,7 +368,13 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
DictTypes = (dict, UserDict)
ListTypes = (list, UserList)
-SequenceTypes = (list, tuple, UserList)
+
+try:
+ # Handle getting dictionary views.
+ SequenceTypes = (list, tuple, UserList, MappingView)
+except NameError:
+ SequenceTypes = (list, tuple, UserList)
+
# Note that profiling data shows a speed-up when comparing
# explicitly with str and unicode instead of simply comparing
@@ -1476,6 +1482,11 @@ else:
md5 = True
def MD5signature(s):
+ """
+ Generate a String of Hex digits representing the md5 signature of the string
+ :param s: either string or bytes. Normally should be bytes
+ :return: String of hex digits
+ """
m = hashlib.md5()
try:
@@ -1486,6 +1497,11 @@ else:
return m.hexdigest()
def MD5filesignature(fname, chunksize=65536):
+ """
+ :param fname:
+ :param chunksize:
+ :return: String of Hex digits
+ """
m = hashlib.md5()
f = open(fname, "rb")
while True:
@@ -1496,6 +1512,7 @@ else:
f.close()
return m.hexdigest()
+
def MD5collect(signatures):
"""
Collects a list of signatures into an aggregate signature.
@@ -1597,6 +1614,32 @@ def cmp(a, b):
return (a > b) - (a < b)
+def get_bool_envvar(name, default=False):
+ """
+ Get a value of OS environment variable converting it to boolean.
+
+ - FOO=1, FOO=123, FOO=true, FOO=yes, FOO=y, FOO=on are examples of ``True``
+ values.
+ - FOO=0, FOO=false, FOO=no, FOO=n, FOO=off are examples of ``False``
+ values.
+
+ If a variable can't be converted to a boolean, default value is returned
+ (``False`` by default)
+ """
+ try:
+ var = os.environ[name]
+ except KeyError:
+ return default
+ try:
+ return bool(int(var))
+ except ValueError:
+ if str(var).lower() in ('true', 'yes', 'y', 'on'):
+ return True
+ elif str(var).lower() in ('false', 'no', 'n', 'off'):
+ return False
+ else:
+ return default
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 81ec09d..6067c98 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -37,9 +37,13 @@ import SCons.Errors
from SCons.Util import *
-try: eval('unicode')
-except NameError: HasUnicode = False
-else: HasUnicode = True
+try:
+ eval('unicode')
+except NameError:
+ HasUnicode = False
+else:
+ HasUnicode = True
+
class OutBuffer(object):
def __init__(self):
@@ -48,47 +52,59 @@ class OutBuffer(object):
def write(self, str):
self.buffer = self.buffer + str
+
class dictifyTestCase(unittest.TestCase):
def test_dictify(self):
"""Test the dictify() function"""
r = SCons.Util.dictify(['a', 'b', 'c'], [1, 2, 3])
- assert r == {'a':1, 'b':2, 'c':3}, r
+ assert r == {'a': 1, 'b': 2, 'c': 3}, r
r = {}
SCons.Util.dictify(['a'], [1], r)
SCons.Util.dictify(['b'], [2], r)
SCons.Util.dictify(['c'], [3], r)
- assert r == {'a':1, 'b':2, 'c':3}, r
+ assert r == {'a': 1, 'b': 2, 'c': 3}, r
+
class UtilTestCase(unittest.TestCase):
def test_splitext(self):
- assert splitext('foo') == ('foo','')
- assert splitext('foo.bar') == ('foo','.bar')
- assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
+ assert splitext('foo') == ('foo', '')
+ assert splitext('foo.bar') == ('foo', '.bar')
+ assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'), '')
class Node(object):
def __init__(self, name, children=[]):
self.children = children
self.name = name
self.nocache = None
+
def __str__(self):
return self.name
+
def exists(self):
return 1
+
def rexists(self):
return 1
+
def has_builder(self):
return 1
+
def has_explicit_builder(self):
return 1
+
def side_effect(self):
return 1
+
def precious(self):
return 1
+
def always_build(self):
return 1
+
def is_up_to_date(self):
return 1
+
def noclean(self):
return 1
@@ -115,7 +131,7 @@ class UtilTestCase(unittest.TestCase):
"""
lines = expect.split('\n')[:-1]
- lines = ['[E BSPACN ]'+l for l in lines]
+ lines = ['[E BSPACN ]' + l for l in lines]
withtags = '\n'.join(lines) + '\n'
return foo, expect, withtags
@@ -150,13 +166,14 @@ class UtilTestCase(unittest.TestCase):
"""
lines = expect.split('\n')[:-1]
- lines = ['[E BSPACN ]'+l for l in lines]
+ lines = ['[E BSPACN ]' + l for l in lines]
withtags = '\n'.join(lines) + '\n'
return blat_o, expect, withtags
def test_render_tree(self):
"""Test the render_tree() function"""
+
def get_children(node):
return node.children
@@ -177,6 +194,7 @@ class UtilTestCase(unittest.TestCase):
def test_print_tree(self):
"""Test the print_tree() function"""
+
def get_children(node):
return node.children
@@ -243,7 +261,7 @@ class UtilTestCase(unittest.TestCase):
assert is_Dict(UserDict())
# os.environ is not a dictionary in python 3
- if sys.version_info < (3,0):
+ if sys.version_info < (3, 0):
assert is_Dict(os.environ)
try:
@@ -313,42 +331,42 @@ class UtilTestCase(unittest.TestCase):
bytearray(u'Hello', 'utf-8'),
"Check that to_bytes creates byte array when presented with unicode string. PY2 only")
-
def test_to_String(self):
"""Test the to_String() method."""
assert to_String(1) == "1", to_String(1)
- assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
+ assert to_String([1, 2, 3]) == str([1, 2, 3]), to_String([1, 2, 3])
assert to_String("foo") == "foo", to_String("foo")
assert to_String(None) == 'None'
# test low level string converters too
assert to_str(None) == 'None'
assert to_bytes(None) == b'None'
- s1=UserString('blah')
+ s1 = UserString('blah')
assert to_String(s1) == s1, s1
assert to_String(s1) == 'blah', s1
class Derived(UserString):
pass
+
s2 = Derived('foo')
assert to_String(s2) == s2, s2
assert to_String(s2) == 'foo', s2
if HasUnicode:
- s3=UserString(unicode('bar'))
+ 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))
+ 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))
+ type(to_String(s4))
def test_WhereIs(self):
- test = TestCmd.TestCmd(workdir = '')
+ test = TestCmd.TestCmd(workdir='')
sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
@@ -371,17 +389,17 @@ class UtilTestCase(unittest.TestCase):
env_path = os.environ['PATH']
try:
- pathdirs_1234 = [ test.workpath('sub1'),
- test.workpath('sub2'),
- test.workpath('sub3'),
- test.workpath('sub4'),
- ] + env_path.split(os.pathsep)
-
- pathdirs_1243 = [ test.workpath('sub1'),
- test.workpath('sub2'),
- test.workpath('sub4'),
- test.workpath('sub3'),
- ] + env_path.split(os.pathsep)
+ pathdirs_1234 = [test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub3'),
+ test.workpath('sub4'),
+ ] + env_path.split(os.pathsep)
+
+ pathdirs_1243 = [test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub4'),
+ test.workpath('sub3'),
+ ] + env_path.split(os.pathsep)
os.environ['PATH'] = os.pathsep.join(pathdirs_1234)
wi = WhereIs('xxx.exe')
@@ -391,9 +409,9 @@ class UtilTestCase(unittest.TestCase):
wi = WhereIs('xxx.exe', os.pathsep.join(pathdirs_1243))
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx.exe',reject = sub3_xxx_exe)
+ wi = WhereIs('xxx.exe', reject=sub3_xxx_exe)
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
+ wi = WhereIs('xxx.exe', pathdirs_1243, reject=sub3_xxx_exe)
assert wi == test.workpath(sub4_xxx_exe), wi
os.environ['PATH'] = os.pathsep.join(pathdirs_1243)
@@ -405,19 +423,19 @@ class UtilTestCase(unittest.TestCase):
assert wi == test.workpath(sub3_xxx_exe), wi
if sys.platform == 'win32':
- wi = WhereIs('xxx', pathext = '')
+ wi = WhereIs('xxx', pathext='')
assert wi is None, wi
- wi = WhereIs('xxx', pathext = '.exe')
+ wi = WhereIs('xxx', pathext='.exe')
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
+ wi = WhereIs('xxx', path=pathdirs_1234, pathext='.BAT;.EXE')
assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
# Test that we return a normalized path even when
# the path contains forward slashes.
forward_slash = test.workpath('') + '/sub3'
- wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
+ wi = WhereIs('xxx', path=forward_slash, pathext='.EXE')
assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
del os.environ['PATH']
@@ -437,24 +455,27 @@ class UtilTestCase(unittest.TestCase):
assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
- assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
+ assert get_environment_var("${some('complex expression')}") == None, get_environment_var(
+ "${some('complex expression')}")
def test_Proxy(self):
"""Test generic Proxy class."""
+
class Subject(object):
def foo(self):
return 1
+
def bar(self):
return 2
- s=Subject()
+ s = Subject()
s.baz = 3
class ProxyTest(Proxy):
def bar(self):
return 4
- p=ProxyTest(s)
+ p = ProxyTest(s)
assert p.foo() == 1, p.foo()
assert p.bar() == 4, p.bar()
@@ -503,49 +524,49 @@ class UtilTestCase(unittest.TestCase):
p1 = r'C:\dir\num\one;C:\dir\num\two'
p2 = r'C:\mydir\num\one;C:\mydir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
- p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
- p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
- p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
- assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
- assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+ p1 = PrependPath(p1, r'C:\dir\num\two', sep=';')
+ p1 = PrependPath(p1, r'C:\dir\num\three', sep=';')
+ p2 = PrependPath(p2, r'C:\mydir\num\three', sep=';')
+ p2 = PrependPath(p2, r'C:\mydir\num\one', sep=';')
+ assert (p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+ assert (p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
def test_AppendPath(self):
"""Test appending to a path."""
p1 = r'C:\dir\num\one;C:\dir\num\two'
p2 = r'C:\mydir\num\one;C:\mydir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
- p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
- p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
- p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
- assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
- assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+ p1 = AppendPath(p1, r'C:\dir\num\two', sep=';')
+ p1 = AppendPath(p1, r'C:\dir\num\three', sep=';')
+ p2 = AppendPath(p2, r'C:\mydir\num\three', sep=';')
+ p2 = AppendPath(p2, r'C:\mydir\num\one', sep=';')
+ assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ assert (p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
def test_PrependPathPreserveOld(self):
"""Test prepending to a path while preserving old paths"""
p1 = r'C:\dir\num\one;C:\dir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';', delete_existing=0)
- p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
- assert(p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two')
+ p1 = PrependPath(p1, r'C:\dir\num\two', sep=';', delete_existing=0)
+ p1 = PrependPath(p1, r'C:\dir\num\three', sep=';')
+ assert (p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two')
def test_AppendPathPreserveOld(self):
"""Test appending to a path while preserving old paths"""
p1 = r'C:\dir\num\one;C:\dir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = AppendPath(p1,r'C:\dir\num\one',sep = ';', delete_existing=0)
- p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
- assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ p1 = AppendPath(p1, r'C:\dir\num\one', sep=';', delete_existing=0)
+ p1 = AppendPath(p1, r'C:\dir\num\three', sep=';')
+ assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
def test_addPathIfNotExists(self):
"""Test the AddPathIfNotExists() function"""
- env_dict = { 'FOO' : os.path.normpath('/foo/bar') + os.pathsep + \
- os.path.normpath('/baz/blat'),
- 'BAR' : os.path.normpath('/foo/bar') + os.pathsep + \
- os.path.normpath('/baz/blat'),
- 'BLAT' : [ os.path.normpath('/foo/bar'),
- os.path.normpath('/baz/blat') ] }
+ env_dict = {'FOO': os.path.normpath('/foo/bar') + os.pathsep + \
+ os.path.normpath('/baz/blat'),
+ 'BAR': os.path.normpath('/foo/bar') + os.pathsep + \
+ os.path.normpath('/baz/blat'),
+ 'BLAT': [os.path.normpath('/foo/bar'),
+ os.path.normpath('/baz/blat')]}
AddPathIfNotExists(env_dict, 'FOO', os.path.normpath('/foo/bar'))
AddPathIfNotExists(env_dict, 'BAR', os.path.normpath('/bar/foo'))
AddPathIfNotExists(env_dict, 'BAZ', os.path.normpath('/foo/baz'))
@@ -558,9 +579,9 @@ class UtilTestCase(unittest.TestCase):
os.path.normpath('/foo/bar') + os.pathsep + \
os.path.normpath('/baz/blat'), env_dict['BAR']
assert env_dict['BAZ'] == os.path.normpath('/foo/baz'), env_dict['BAZ']
- assert env_dict['BLAT'] == [ os.path.normpath('/baz/foo'),
- os.path.normpath('/foo/bar'),
- os.path.normpath('/baz/blat') ], env_dict['BLAT' ]
+ assert env_dict['BLAT'] == [os.path.normpath('/baz/foo'),
+ os.path.normpath('/foo/bar'),
+ os.path.normpath('/baz/blat')], env_dict['BLAT']
def test_CLVar(self):
"""Test the command-line construction variable class"""
@@ -669,10 +690,11 @@ class UtilTestCase(unittest.TestCase):
def __str__(self):
return self.name
+
def get_suffix(self):
return os.path.splitext(self.name)[1]
- s = Selector({'a' : 'AAA', 'b' : 'BBB'})
+ s = Selector({'a': 'AAA', 'b': 'BBB'})
assert s['a'] == 'AAA', s['a']
assert s['b'] == 'BBB', s['b']
exc_caught = None
@@ -692,7 +714,7 @@ class UtilTestCase(unittest.TestCase):
env = DummyEnv()
- s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
+ s = Selector({'.d': 'DDD', '.e': 'EEE'})
ret = s(env, [])
assert ret is None, ret
ret = s(env, [MyNode('foo.d')])
@@ -705,9 +727,9 @@ class UtilTestCase(unittest.TestCase):
ret = s(env, [MyNode('bar.x')])
assert ret == 'XXX', ret
- env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
+ env = DummyEnv({'FSUFF': '.f', 'GSUFF': '.g'})
- s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
+ s = Selector({'$FSUFF': 'FFF', '$GSUFF': 'GGG'})
ret = s(env, [MyNode('foo.f')])
assert ret == 'FFF', ret
ret = s(env, [MyNode('bar.g')])
@@ -793,9 +815,11 @@ class MD5TestCase(unittest.TestCase):
s = MD5signature('222')
assert 'bcbe3365e6ac95ea2c0343a2395834dd' == s, s
+
class NodeListTestCase(unittest.TestCase):
def test_simple_attributes(self):
"""Test simple attributes of a NodeList class"""
+
class TestClass(object):
def __init__(self, name, child=None):
self.child = child
@@ -806,18 +830,21 @@ class NodeListTestCase(unittest.TestCase):
t3 = TestClass('t3')
nl = NodeList([t1, t2, t3])
- assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
- assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
- nl[0:2].child.bar
+ assert nl.bar == ['t1', 't2', 't3'], nl.bar
+ assert nl[0:2].child.bar == ['t1child', 't2child'], \
+ nl[0:2].child.bar
def test_callable_attributes(self):
"""Test callable attributes of a NodeList class"""
+
class TestClass(object):
def __init__(self, name, child=None):
self.child = child
self.bar = name
+
def foo(self):
return self.bar + "foo"
+
def getself(self):
return self
@@ -826,13 +853,13 @@ class NodeListTestCase(unittest.TestCase):
t3 = TestClass('t3')
nl = NodeList([t1, t2, t3])
- assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
- assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
- assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
- assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
- nl[0:2].child.foo()
- assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
- nl[0:2].child.bar
+ assert nl.foo() == ['t1foo', 't2foo', 't3foo'], nl.foo()
+ assert nl.bar == ['t1', 't2', 't3'], nl.bar
+ assert nl.getself().bar == ['t1', 't2', 't3'], nl.getself().bar
+ assert nl[0:2].child.foo() == ['t1childfoo', 't2childfoo'], \
+ nl[0:2].child.foo()
+ assert nl[0:2].child.bar == ['t1child', 't2child'], \
+ nl[0:2].child.bar
def test_null(self):
"""Test a null NodeList"""
@@ -848,13 +875,76 @@ class flattenTestCase(unittest.TestCase):
def test_scalar(self):
"""Test flattening a scalar"""
result = flatten('xyz')
- assert result == ['xyz'], result
+ self.assertEqual(result,['xyz'], result)
+
+ def test_dictionary_values(self):
+ """Test flattening the dictionary values"""
+ items = {"a": 1, "b": 2, "c": 3}
+ result = flatten(items.values())
+ self.assertEqual(sorted(result),[1,2,3])
+
+
+class OsEnviron(object):
+ """Used to temporarily mock os.environ"""
+ def __init__(self, environ):
+ self._environ = environ
+
+ def start(self):
+ self._stored = os.environ
+ os.environ = self._environ
+
+ def stop(self):
+ os.environ = self._stored
+ del self._stored
+
+ def __enter__(self):
+ self.start()
+ return os.environ
+
+ def __exit__(self, *args):
+ self.stop()
+
+
+class get_bool_envvarTestCase(unittest.TestCase):
+ def test_missing(self):
+ with OsEnviron(dict()):
+ var = get_bool_envvar('FOO')
+ assert var is False, "var should be False, not %s" % repr(var)
+ with OsEnviron({'FOO': '1'}):
+ var = get_bool_envvar('BAR')
+ assert var is False, "var should be False, not %s" % repr(var)
+
+ def test_true(self):
+ for foo in [ 'TRUE', 'True', 'true',
+ 'YES', 'Yes', 'yes',
+ 'Y', 'y',
+ 'ON', 'On', 'on',
+ '1', '20', '-1']:
+ with OsEnviron({'FOO': foo}):
+ var = get_bool_envvar('FOO')
+ assert var is True, 'var should be True, not %s' % repr(var)
+
+ def test_false(self):
+ for foo in [ 'FALSE', 'False', 'false',
+ 'NO', 'No', 'no',
+ 'N', 'n',
+ 'OFF', 'Off', 'off',
+ '0']:
+ with OsEnviron({'FOO': foo}):
+ var = get_bool_envvar('FOO', True)
+ assert var is False, 'var should be True, not %s' % repr(var)
+
+ def test_default(self):
+ with OsEnviron({'FOO': 'other'}):
+ var = get_bool_envvar('FOO', True)
+ assert var is True, 'var should be True, not %s' % repr(var)
+ var = get_bool_envvar('FOO', False)
+ assert var is False, 'var should be False, not %s' % repr(var)
if __name__ == "__main__":
unittest.main()
-
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/dblite.py b/src/engine/SCons/dblite.py
index 87a1763..628182b 100644
--- a/src/engine/SCons/dblite.py
+++ b/src/engine/SCons/dblite.py
@@ -75,7 +75,8 @@ class dblite(object):
def __init__(self, file_base_name, flag, mode):
assert flag in (None, "r", "w", "c", "n")
- if (flag is None): flag = "r"
+ if flag is None:
+ flag = "r"
base, ext = os.path.splitext(file_base_name)
if ext == dblite_suffix:
@@ -106,13 +107,13 @@ class dblite(object):
self._chown_to = -1 # don't chown
self._chgrp_to = -1 # don't chgrp
- if (self._flag == "n"):
+ if self._flag == "n":
self._open(self._file_name, "wb", self._mode)
else:
try:
f = self._open(self._file_name, "rb")
except IOError as e:
- if (self._flag != "c"):
+ if self._flag != "c":
raise e
self._open(self._file_name, "wb", self._mode)
else:
@@ -132,7 +133,7 @@ class dblite(object):
corruption_warning(self._file_name)
def close(self):
- if (self._needs_sync):
+ if self._needs_sync:
self.sync()
def __del__(self):
diff --git a/src/script/scons-configure-cache.py b/src/script/scons-configure-cache.py
index 0fc7b48..3c096e1 100644
--- a/src/script/scons-configure-cache.py
+++ b/src/script/scons-configure-cache.py
@@ -23,7 +23,19 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+'''Show or convert the configuration of an SCons cache directory.
+
+A cache of derived files is stored by file signature.
+The files are split into directories named by the first few
+digits of the signature. The prefix length used for directory
+names can be changed by this script.
+'''
+
from __future__ import print_function
+import argparse
+import glob
+import json
+import os
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
@@ -37,88 +49,113 @@ __date__ = "__DATE__"
__developer__ = "__DEVELOPER__"
-import argparse
-import glob
-import json
-import os
def rearrange_cache_entries(current_prefix_len, new_prefix_len):
- print('Changing prefix length from', current_prefix_len, 'to', new_prefix_len)
+ '''Move cache files if prefix length changed.
+
+ Move the existing cache files to new directories of the
+ appropriate name length and clean up the old directories.
+ '''
+ print('Changing prefix length from', current_prefix_len,
+ 'to', new_prefix_len)
dirs = set()
old_dirs = set()
for file in glob.iglob(os.path.join('*', '*')):
name = os.path.basename(file)
- dir = name[:current_prefix_len].upper()
- if dir not in old_dirs:
- print('Migrating', dir)
- old_dirs.add(dir)
- dir = name[:new_prefix_len].upper()
- if dir not in dirs:
- os.mkdir(dir)
- dirs.add(dir)
- os.rename(file, os.path.join(dir, name))
+ dname = name[:current_prefix_len].upper()
+ if dname not in old_dirs:
+ print('Migrating', dname)
+ old_dirs.add(dname)
+ dname = name[:new_prefix_len].upper()
+ if dname not in dirs:
+ os.mkdir(dname)
+ dirs.add(dname)
+ os.rename(file, os.path.join(dname, name))
# Now delete the original directories
- for dir in old_dirs:
- os.rmdir(dir)
+ for dname in old_dirs:
+ os.rmdir(dname)
+
-# This dictionary should have one entry per entry in the cache config
-# Each entry should have the following:
+# The configuration dictionary should have one entry per entry in the
+# cache config. The value of each entry should include the following:
# implicit - (optional) This is to allow adding a new config entry and also
# changing the behaviour of the system at the same time. This
-# indicates the value the config entry would have had if it had been
-# specified.
+# indicates the value the config entry would have had if it had
+# been specified.
# default - The value the config entry should have if it wasn't previously
# specified
# command-line - parameters to pass to ArgumentParser.add_argument
-# converter - (optional) Function to call if it's necessary to do some work
+# converter - (optional) Function to call if conversion is required
# if this configuration entry changes
config_entries = {
- 'prefix_len' : {
- 'implicit' : 1,
- 'default' : 2 ,
- 'command-line' : {
- 'help' : 'Length of cache file name used as subdirectory prefix',
- 'metavar' : '<number>',
- 'type' : int
- },
- 'converter' : rearrange_cache_entries
+ 'prefix_len': {
+ 'implicit': 1,
+ 'default': 2,
+ 'command-line': {
+ 'help': 'Length of cache file name used as subdirectory prefix',
+ 'metavar': '<number>',
+ 'type': int
+ },
+ 'converter': rearrange_cache_entries
}
}
+
parser = argparse.ArgumentParser(
- description = 'Modify the configuration of an scons cache directory',
- epilog = '''
- Unless you specify an option, it will not be changed (if it is
- already set in the cache config), or changed to an appropriate
- default (it it is not set).
- '''
- )
+ description='Modify the configuration of an scons cache directory',
+ epilog='''
+ Unspecified options will not be changed unless they are not
+ set at all, in which case they are set to an appropriate default.
+ ''')
parser.add_argument('cache-dir', help='Path to scons cache directory')
for param in config_entries:
- parser.add_argument('--' + param.replace('_', '-'),
+ parser.add_argument('--' + param.replace('_', '-'),
**config_entries[param]['command-line'])
-parser.add_argument('--version', action='version', version='%(prog)s 1.0')
+parser.add_argument('--version',
+ action='version',
+ version='%(prog)s 1.0')
+parser.add_argument('--show',
+ action="store_true",
+ help="show current configuration")
# Get the command line as a dict without any of the unspecified entries.
args = dict([x for x in vars(parser.parse_args()).items() if x[1]])
# It seems somewhat strange to me, but positional arguments don't get the -
# in the name changed to _, whereas optional arguments do...
-os.chdir(args['cache-dir'])
+cache = args['cache-dir']
+if not os.path.isdir(cache):
+ raise RuntimeError("There is no cache directory named %s" % cache)
+os.chdir(cache)
del args['cache-dir']
if not os.path.exists('config'):
+ # old config dirs did not have a 'config' file. Try to update.
# Validate the only files in the directory are directories 0-9, a-f
- expected = [ '{:X}'.format(x) for x in range(0, 16) ]
+ expected = ['{:X}'.format(x) for x in range(0, 16)]
if not set(os.listdir('.')).issubset(expected):
- raise RuntimeError("This doesn't look like a version 1 cache directory")
+ raise RuntimeError(
+ "%s does not look like a valid version 1 cache directory" % cache)
config = dict()
else:
with open('config') as conf:
config = json.load(conf)
-# Find any keys that aren't currently set but should be
+if args.get('show', None):
+ print("Current configuration in '%s':" % cache)
+ print(json.dumps(config, sort_keys=True,
+ indent=4, separators=(',', ': ')))
+ # in case of the show argument, emit some stats as well
+ file_count = 0
+ for _, _, files in os.walk('.'):
+ file_count += len(files)
+ if file_count: # skip config file if it exists
+ file_count -= 1
+ print("Cache contains %s files" % file_count)
+ del args['show']
+
+# Find any keys that are not currently set but should be
for key in config_entries:
if key not in config:
if 'implicit' in config_entries[key]:
@@ -128,10 +165,10 @@ for key in config_entries:
if key not in args:
args[key] = config_entries[key]['default']
-#Now we go through each entry in args to see if it changes an existing config
-#setting.
+# Now go through each entry in args to see if it changes an existing config
+# setting.
for key in args:
- if args[key] != config[key]:
+ if args[key] != config[key]:
if 'converter' in config_entries[key]:
config_entries[key]['converter'](config[key], args[key])
config[key] = args[key]
diff --git a/src/script/scons.py b/src/script/scons.py
index f2a44f8..d22e76b 100644
--- a/src/script/scons.py
+++ b/src/script/scons.py
@@ -37,10 +37,18 @@ __date__ = "__DATE__"
__developer__ = "__DEVELOPER__"
+# This is the entry point to the SCons program.
+# The only job of this script is to work out where the guts of the program
+# could be and import them, where the real work begins.
+# SCons can be invoked several different ways
+# - from an installed location
+# - from a "local install" copy
+# - from a source tree, which has a different dir struture than the other two
+# Try to account for all those possibilities.
+
import os
import sys
-
##############################################################################
# BEGIN STANDARD SCons SCRIPT HEADER
#
@@ -50,57 +58,53 @@ import sys
# should also change other scripts that use this same header.
##############################################################################
-# Strip the script directory from sys.path() so on case-insensitive
-# (WIN32) systems Python doesn't think that the "scons" script is the
-# "SCons" package. Replace it with our own library directories
-# (version-specific first, in case they installed by hand there,
-# followed by generic) so we pick up the right version of the build
-# engine modules if they're in either directory.
-
-
+# compatibility check
if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0):
msg = "scons: *** SCons version %s does not run under Python version %s.\n\
-Python < 3.5 is not yet supported.\n"
+Python 2.7 or >= 3.5 is required.\n"
sys.stderr.write(msg % (__version__, sys.version.split()[0]))
sys.exit(1)
-
-script_dir = os.path.dirname(os.path.realpath(__file__))
-
-if script_dir in sys.path:
- sys.path.remove(script_dir)
+# Strip the script directory from sys.path so on case-insensitive
+# (WIN32) systems Python doesn't think that the "scons" script is the
+# "SCons" package.
+script_dir = os.path.dirname(__file__)
+script_path = os.path.realpath(os.path.dirname(__file__))
+if script_path in sys.path:
+ sys.path.remove(script_path)
libs = []
if "SCONS_LIB_DIR" in os.environ:
libs.append(os.environ["SCONS_LIB_DIR"])
-# - running from source takes priority (since 2.3.2), excluding SCONS_LIB_DIR settings
-script_path = os.path.abspath(os.path.dirname(__file__))
-source_path = os.path.join(script_path, '..', 'engine')
-libs.append(source_path)
+# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR
+source_path = os.path.join(script_path, os.pardir, 'engine')
+if os.path.isdir(source_path):
+ libs.append(source_path)
+# add local-install locations
local_version = 'scons-local-' + __version__
local = 'scons-local'
if script_dir:
local_version = os.path.join(script_dir, local_version)
local = os.path.join(script_dir, local)
-libs.append(os.path.abspath(local_version))
-libs.append(os.path.abspath(local))
+if os.path.isdir(local_version):
+ libs.append(os.path.abspath(local_version))
+if os.path.isdir(local):
+ libs.append(os.path.abspath(local))
scons_version = 'scons-%s' % __version__
# preferred order of scons lookup paths
prefs = []
-
-# - running from egg check
+# if we can find package information, use it
try:
import pkg_resources
except ImportError:
pass
else:
- # when running from an egg add the egg's directory
try:
d = pkg_resources.get_distribution('scons')
except pkg_resources.DistributionNotFound:
@@ -109,18 +113,18 @@ else:
prefs.append(d.location)
if sys.platform == 'win32':
- # sys.prefix is (likely) C:\Python*;
- # check only C:\Python*.
+ # Use only sys.prefix on Windows
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))
else:
# On other (POSIX) platforms, things are more complicated due to
- # the variety of path names and library locations. Try to be smart
- # about it.
+ # the variety of path names and library locations.
+ # Build up some possibilities, then transform them into candidates
+ temp = []
if script_dir == 'bin':
# script_dir is `pwd`/bin;
# check `pwd`/lib/scons*.
- prefs.append(os.getcwd())
+ temp.append(os.getcwd())
else:
if script_dir == '.' or script_dir == '':
script_dir = os.getcwd()
@@ -128,42 +132,41 @@ else:
if tail == "bin":
# script_dir is /foo/bin;
# check /foo/lib/scons*.
- prefs.append(head)
+ temp.append(head)
head, tail = os.path.split(sys.prefix)
if tail == "usr":
# sys.prefix is /foo/usr;
# check /foo/usr/lib/scons* first,
# then /foo/usr/local/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(os.path.join(sys.prefix, "local"))
+ temp.append(sys.prefix)
+ temp.append(os.path.join(sys.prefix, "local"))
elif tail == "local":
h, t = os.path.split(head)
if t == "usr":
# sys.prefix is /foo/usr/local;
# check /foo/usr/local/lib/scons* first,
# then /foo/usr/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(head)
+ temp.append(sys.prefix)
+ temp.append(head)
else:
# sys.prefix is /foo/local;
# check only /foo/local/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
else:
# sys.prefix is /foo (ends in neither /usr or /local);
# check only /foo/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
+
+ # suffix these to add to our original prefs:
+ prefs.extend([os.path.join(x, 'lib') for x in temp])
+ prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3],
+ 'site-packages') for x in temp])
- temp = [os.path.join(x, 'lib') for x in prefs]
- temp.extend([os.path.join(x,
- 'lib',
- 'python' + sys.version[:3],
- 'site-packages') for x in prefs])
- prefs = temp
# Add the parent directory of the current python's library to the
- # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64,
- # not /usr/lib.
+ # preferences. This picks up differences between, e.g., lib and lib64,
+ # and finds the base location in case of a non-copying virtualenv.
try:
libpath = os.__file__
except AttributeError:
@@ -177,9 +180,9 @@ else:
prefs.append(libpath)
# Look first for 'scons-__version__' in all of our preference libs,
-# then for 'scons'.
-libs.extend([os.path.join(x, scons_version) for x in prefs])
-libs.extend([os.path.join(x, 'scons') for x in prefs])
+# then for 'scons'. Skip paths that do not exist.
+libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)])
+libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)])
sys.path = libs + sys.path
@@ -191,9 +194,9 @@ if __name__ == "__main__":
try:
import SCons.Script
except ImportError:
- print("SCons import failed. Unable to find engine files in:")
+ sys.stderr.write("SCons import failed. Unable to find engine files in:\n")
for path in libs:
- print(" {}".format(path))
+ sys.stderr.write(" {}\n".format(path))
raise
# this does all the work, and calls sys.exit
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index 559dffe..2337f67 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -49,48 +49,53 @@ import sys
# should also change other scripts that use this same header.
##############################################################################
-# Strip the script directory from sys.path() so on case-insensitive
+# compatibility check
+if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0):
+ msg = "scons: *** SCons version %s does not run under Python version %s.\n\
+Python 2.7 or >= 3.5 is required.\n"
+ sys.stderr.write(msg % (__version__, sys.version.split()[0]))
+ sys.exit(1)
+
+# Strip the script directory from sys.path so on case-insensitive
# (WIN32) systems Python doesn't think that the "scons" script is the
-# "SCons" package. Replace it with our own library directories
-# (version-specific first, in case they installed by hand there,
-# followed by generic) so we pick up the right version of the build
-# engine modules if they're in either directory.
-
-
-script_dir = os.path.dirname(os.path.realpath(__file__))
-
-if script_dir in sys.path:
- sys.path.remove(script_dir)
+# "SCons" package.
+script_dir = os.path.dirname(__file__)
+script_path = os.path.realpath(os.path.dirname(__file__))
+if script_path in sys.path:
+ sys.path.remove(script_path)
libs = []
if "SCONS_LIB_DIR" in os.environ:
libs.append(os.environ["SCONS_LIB_DIR"])
-# - running from source takes priority (since 2.3.2), excluding SCONS_LIB_DIR settings
-script_path = os.path.abspath(os.path.dirname(__file__))
-source_path = os.path.join(script_path, '..', 'engine')
-libs.append(source_path)
+# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR
+source_path = os.path.join(script_path, os.pardir, 'engine')
+if os.path.isdir(source_path):
+ libs.append(source_path)
+# add local-install locations
local_version = 'scons-local-' + __version__
local = 'scons-local'
if script_dir:
local_version = os.path.join(script_dir, local_version)
local = os.path.join(script_dir, local)
-libs.append(os.path.abspath(local_version))
-libs.append(os.path.abspath(local))
+if os.path.isdir(local_version):
+ libs.append(os.path.abspath(local_version))
+if os.path.isdir(local):
+ libs.append(os.path.abspath(local))
scons_version = 'scons-%s' % __version__
# preferred order of scons lookup paths
prefs = []
+# if we can find package information, use it
try:
import pkg_resources
except ImportError:
pass
else:
- # when running from an egg add the egg's directory
try:
d = pkg_resources.get_distribution('scons')
except pkg_resources.DistributionNotFound:
@@ -99,18 +104,18 @@ else:
prefs.append(d.location)
if sys.platform == 'win32':
- # sys.prefix is (likely) C:\Python*;
- # check only C:\Python*.
+ # Use only sys.prefix on Windows
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))
else:
# On other (POSIX) platforms, things are more complicated due to
- # the variety of path names and library locations. Try to be smart
- # about it.
+ # the variety of path names and library locations.
+ # Build up some possibilities, then transform them into candidates
+ temp = []
if script_dir == 'bin':
# script_dir is `pwd`/bin;
# check `pwd`/lib/scons*.
- prefs.append(os.getcwd())
+ temp.append(os.getcwd())
else:
if script_dir == '.' or script_dir == '':
script_dir = os.getcwd()
@@ -118,42 +123,41 @@ else:
if tail == "bin":
# script_dir is /foo/bin;
# check /foo/lib/scons*.
- prefs.append(head)
+ temp.append(head)
head, tail = os.path.split(sys.prefix)
if tail == "usr":
# sys.prefix is /foo/usr;
# check /foo/usr/lib/scons* first,
# then /foo/usr/local/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(os.path.join(sys.prefix, "local"))
+ temp.append(sys.prefix)
+ temp.append(os.path.join(sys.prefix, "local"))
elif tail == "local":
h, t = os.path.split(head)
if t == "usr":
# sys.prefix is /foo/usr/local;
# check /foo/usr/local/lib/scons* first,
# then /foo/usr/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(head)
+ temp.append(sys.prefix)
+ temp.append(head)
else:
# sys.prefix is /foo/local;
# check only /foo/local/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
else:
# sys.prefix is /foo (ends in neither /usr or /local);
# check only /foo/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
+
+ # suffix these to add to our original prefs:
+ prefs.extend([os.path.join(x, 'lib') for x in temp])
+ prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3],
+ 'site-packages') for x in temp])
- temp = [os.path.join(x, 'lib') for x in prefs]
- temp.extend([os.path.join(x,
- 'lib',
- 'python' + sys.version[:3],
- 'site-packages') for x in prefs])
- prefs = temp
# Add the parent directory of the current python's library to the
- # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64,
- # not /usr/lib.
+ # preferences. This picks up differences between, e.g., lib and lib64,
+ # and finds the base location in case of a non-copying virtualenv.
try:
libpath = os.__file__
except AttributeError:
@@ -167,9 +171,9 @@ else:
prefs.append(libpath)
# Look first for 'scons-__version__' in all of our preference libs,
-# then for 'scons'.
-libs.extend([os.path.join(x, scons_version) for x in prefs])
-libs.extend([os.path.join(x, 'scons') for x in prefs])
+# then for 'scons'. Skip paths that do not exist.
+libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)])
+libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)])
sys.path = libs + sys.path
diff --git a/test/Builder/multi/different-environments.py b/test/Builder/multi/different-environments.py
index 686e15c..9ce09b9 100644
--- a/test/Builder/multi/different-environments.py
+++ b/test/Builder/multi/different-environments.py
@@ -36,11 +36,11 @@ test = TestSCons.TestSCons(match=TestSCons.match_re)
_python_ = TestSCons._python_
-test.write('build.py', r"""#!/usr/bin/env python
+test.write('build.py', r"""\
import sys
def build(num, target, source):
file = open(str(target), 'wb')
- file.write('%s\n'%num)
+ file.write('%s\n' % num)
for s in source:
file.write(open(str(s), 'rb').read())
build(sys.argv[1],sys.argv[2],sys.argv[3:])
diff --git a/test/Builder/multi/same-overrides.py b/test/Builder/multi/same-overrides.py
index e51b2ef..c4c1893 100644
--- a/test/Builder/multi/same-overrides.py
+++ b/test/Builder/multi/same-overrides.py
@@ -34,11 +34,11 @@ test = TestSCons.TestSCons(match=TestSCons.match_re)
_python_ = TestSCons._python_
-test.write('build.py', r"""#!/usr/bin/env python
+test.write('build.py', r"""\
import sys
def build(num, target, source):
file = open(str(target), 'wb')
- file.write(bytearray('%s\n'%num,'utf-8'))
+ file.write(bytearray('%s\n'% num,'utf-8'))
for s in source:
file.write(open(str(s), 'rb').read())
build(sys.argv[1],sys.argv[2],sys.argv[3:])
diff --git a/test/CacheDir/CacheDir_TryCompile.py b/test/CacheDir/CacheDir_TryCompile.py
new file mode 100644
index 0000000..bb22835
--- /dev/null
+++ b/test/CacheDir/CacheDir_TryCompile.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that CacheDir functions with TryCompile.
+
+With Py3 there was an issue where the generated cache signature from Python Value nodes
+could be bytes instead of a string which would fail when combining cache signatures
+which ended up a mixture of bytes and strings.
+"""
+
+import os
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+cache = test.workpath('cache')
+
+test.subdir('cache', 'src')
+
+test.write(['src', 'SConstruct'], """\
+DefaultEnvironment(tools=[])
+env = Environment()
+env.CacheDir(r'%(cache)s')
+
+conf = Configure(env)
+
+conf.TryCompile('int a;', '.c')
+
+env = conf.Finish()
+""" % locals())
+
+# Verify that a normal build works correctly, and clean up.
+# This should populate the cache with our derived files.
+test.run(chdir = 'src', arguments = '.')
+
+test.up_to_date(chdir = 'src', arguments = '.')
+
+test.run(chdir = 'src', arguments = '-c .')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Decider/MD5-timestamp-Repository.py b/test/Decider/MD5-timestamp-Repository.py
new file mode 100644
index 0000000..1826f68
--- /dev/null
+++ b/test/Decider/MD5-timestamp-Repository.py
@@ -0,0 +1,91 @@
+#!/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 behavior of the MD5-timestamp Decider() setting when combined with Repository() usage
+"""
+
+import os
+import stat
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('Repository', 'work')
+repository = test.workpath('Repository')
+
+
+test.write(['Repository','content1.in'], "content1.in 1\n")
+test.write(['Repository','content2.in'], "content2.in 1\n")
+test.write(['Repository','content3.in'], "content3.in 1\n")
+# test.writable('Repository', 0)
+
+
+test.write(['work','SConstruct'], """\
+Repository(r'%s')
+DefaultEnvironment(tools=[])
+m = Environment(tools=[])
+m.Decider('MD5-timestamp')
+m.Command('content1.out', 'content1.in', Copy('$TARGET', '$SOURCE'))
+m.Command('content2.out', 'content2.in', Copy('$TARGET', '$SOURCE'))
+m.Command('content3.out', 'content3.in', Copy('$TARGET', '$SOURCE'))
+"""%repository)
+
+test.run(chdir='work',arguments='.')
+
+test.up_to_date(chdir='work',arguments='.')
+
+test.sleep()
+
+test.write(['Repository','content1.in'], "content1.in 2\n")
+
+test.touch(['Repository','content2.in'])
+
+time_content = os.stat(os.path.join(repository,'content3.in'))[stat.ST_MTIME]
+test.write(['Repository','content3.in'], "content3.in 2\n")
+test.touch(['Repository','content3.in'], time_content)
+
+# We should only see content1.out rebuilt. The timestamp of content2.in
+# has changed, but its content hasn't, so the follow-on content check says
+# to not rebuild it. The content of content3.in has changed, but that's
+# masked by the fact that its timestamp is the same as the last run.
+
+expect = test.wrap_stdout("""\
+Copy("content1.out", "%s")
+"""%os.path.join(repository,'content1.in'))
+
+test.run(chdir='work', arguments='.', stdout=expect)
+
+test.up_to_date(chdir='work', 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/Docbook/basic/epub/epub_cmd.py b/test/Docbook/basic/epub/epub_cmd.py
index b79d185..285d940 100644
--- a/test/Docbook/basic/epub/epub_cmd.py
+++ b/test/Docbook/basic/epub/epub_cmd.py
@@ -34,18 +34,17 @@ test = TestSCons.TestSCons()
xsltproc = test.where_is('xsltproc')
if not xsltproc:
test.skip_test('No xsltproc executable found, skipping test.\n')
-
test.dir_fixture('image')
# Normal invocation
-test.run(arguments=['-f','SConstruct.cmd'], stderr=None)
+test.run(arguments=['-f','SConstruct.cmd','DOCBOOK_XSLTPROC=%s'%xsltproc], stderr=None)
test.must_exist(test.workpath('manual.epub'))
test.must_exist(test.workpath('OEBPS','toc.ncx'))
test.must_exist(test.workpath('OEBPS','content.opf'))
test.must_exist(test.workpath('META-INF','container.xml'))
# Cleanup
-test.run(arguments=['-f','SConstruct.cmd','-c'])
+test.run(arguments=['-f','SConstruct.cmd','-c','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_not_exist(test.workpath('manual.epub'))
test.must_not_exist(test.workpath('OEBPS'))
test.must_not_exist(test.workpath('META-INF'))
diff --git a/test/Docbook/basic/epub/image/SConstruct.cmd b/test/Docbook/basic/epub/image/SConstruct.cmd
index 27cf2c8..9b5e4cb 100644
--- a/test/Docbook/basic/epub/image/SConstruct.cmd
+++ b/test/Docbook/basic/epub/image/SConstruct.cmd
@@ -1,2 +1,6 @@
env = Environment(DOCBOOK_PREFER_XSLTPROC=1, tools=['docbook'])
+DOCBOOK_XSLTPROC = ARGUMENTS.get('DOCBOOK_XSLTPROC', "")
+if DOCBOOK_XSLTPROC:
+ env['DOCBOOK_XSLTPROC'] = DOCBOOK_XSLTPROC
+
env.DocbookEpub('manual')
diff --git a/test/Docbook/basic/html/html_cmd.py b/test/Docbook/basic/html/html_cmd.py
index acb4dad..cfc71b0 100644
--- a/test/Docbook/basic/html/html_cmd.py
+++ b/test/Docbook/basic/html/html_cmd.py
@@ -38,11 +38,11 @@ if not xsltproc:
test.dir_fixture('image')
# Normal invocation
-test.run(arguments=['-f','SConstruct.cmd'])
+test.run(arguments=['-f','SConstruct.cmd','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_exist(test.workpath('manual.html'))
# Cleanup
-test.run(arguments=['-f','SConstruct.cmd','-c'])
+test.run(arguments=['-f','SConstruct.cmd','-c','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_not_exist(test.workpath('manual.html'))
test.pass_test()
diff --git a/test/Docbook/basic/html/image/SConstruct.cmd b/test/Docbook/basic/html/image/SConstruct.cmd
index 20b4aa2..3e58102 100644
--- a/test/Docbook/basic/html/image/SConstruct.cmd
+++ b/test/Docbook/basic/html/image/SConstruct.cmd
@@ -1,3 +1,7 @@
env = Environment(DOCBOOK_PREFER_XSLTPROC=1, tools=['docbook'])
+DOCBOOK_XSLTPROC = ARGUMENTS.get('DOCBOOK_XSLTPROC', "")
+if DOCBOOK_XSLTPROC:
+ env['DOCBOOK_XSLTPROC'] = DOCBOOK_XSLTPROC
+
env.DocbookHtml('manual')
diff --git a/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py b/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py
index e1ad49a..b194b70 100644
--- a/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py
+++ b/test/Docbook/basic/htmlchunked/htmlchunked_cmd.py
@@ -39,11 +39,11 @@ if not xsltproc:
test.dir_fixture('image')
# Normal invocation
-test.run(arguments=['-f','SConstruct.cmd'], stderr=None)
+test.run(arguments=['-f','SConstruct.cmd','DOCBOOK_XSLTPROC=%s'%xsltproc], stderr=None)
test.must_exist(test.workpath('index.html'))
# Cleanup
-test.run(arguments=['-f','SConstruct.cmd','-c'])
+test.run(arguments=['-f','SConstruct.cmd','-c','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_not_exist(test.workpath('index.html'))
test.pass_test()
diff --git a/test/Docbook/basic/htmlchunked/image/SConstruct.cmd b/test/Docbook/basic/htmlchunked/image/SConstruct.cmd
index e2406f2..8734147 100644
--- a/test/Docbook/basic/htmlchunked/image/SConstruct.cmd
+++ b/test/Docbook/basic/htmlchunked/image/SConstruct.cmd
@@ -1,3 +1,7 @@
env = Environment(DOCBOOK_PREFER_XSLTPROC=1, tools=['docbook'])
+DOCBOOK_XSLTPROC = ARGUMENTS.get('DOCBOOK_XSLTPROC', "")
+if DOCBOOK_XSLTPROC:
+ env['DOCBOOK_XSLTPROC'] = DOCBOOK_XSLTPROC
+
env.DocbookHtmlChunked('manual')
diff --git a/test/Docbook/basic/htmlhelp/htmlhelp_cmd.py b/test/Docbook/basic/htmlhelp/htmlhelp_cmd.py
index 8e1c1b6..541ef75 100644
--- a/test/Docbook/basic/htmlhelp/htmlhelp_cmd.py
+++ b/test/Docbook/basic/htmlhelp/htmlhelp_cmd.py
@@ -38,13 +38,13 @@ if not xsltproc:
test.dir_fixture('image')
# Normal invocation
-test.run(arguments=['-f','SConstruct.cmd'], stderr=None)
+test.run(arguments=['-f','SConstruct.cmd','DOCBOOK_XSLTPROC=%s'%xsltproc], stderr=None)
test.must_exist(test.workpath('index.html'))
test.must_exist(test.workpath('htmlhelp.hhp'))
test.must_exist(test.workpath('toc.hhc'))
# Cleanup
-test.run(arguments=['-f','SConstruct.cmd','-c'])
+test.run(arguments=['-f','SConstruct.cmd','-c','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_not_exist(test.workpath('index.html'))
test.must_not_exist(test.workpath('htmlhelp.hhp'))
test.must_not_exist(test.workpath('toc.hhc'))
diff --git a/test/Docbook/basic/htmlhelp/image/SConstruct.cmd b/test/Docbook/basic/htmlhelp/image/SConstruct.cmd
index 29fb4fa..e3e0193 100644
--- a/test/Docbook/basic/htmlhelp/image/SConstruct.cmd
+++ b/test/Docbook/basic/htmlhelp/image/SConstruct.cmd
@@ -1,3 +1,7 @@
env = Environment(DOCBOOK_PREFER_XSLTPROC=1, tools=['docbook'])
+DOCBOOK_XSLTPROC = ARGUMENTS.get('DOCBOOK_XSLTPROC', "")
+if DOCBOOK_XSLTPROC:
+ env['DOCBOOK_XSLTPROC'] = DOCBOOK_XSLTPROC
+
env.DocbookHtmlhelp('manual')
diff --git a/test/Docbook/basic/man/image/SConstruct.cmd b/test/Docbook/basic/man/image/SConstruct.cmd
index 8b1406b..122c0ce 100644
--- a/test/Docbook/basic/man/image/SConstruct.cmd
+++ b/test/Docbook/basic/man/image/SConstruct.cmd
@@ -1,3 +1,7 @@
env = Environment(DOCBOOK_PREFER_XSLTPROC=1, tools=['docbook'])
+DOCBOOK_XSLTPROC = ARGUMENTS.get('DOCBOOK_XSLTPROC', "")
+if DOCBOOK_XSLTPROC:
+ env['DOCBOOK_XSLTPROC'] = DOCBOOK_XSLTPROC
+
env.DocbookMan('refdb')
diff --git a/test/Docbook/basic/man/man_cmd.py b/test/Docbook/basic/man/man_cmd.py
index f5127e3..ecfc9bd 100644
--- a/test/Docbook/basic/man/man_cmd.py
+++ b/test/Docbook/basic/man/man_cmd.py
@@ -38,12 +38,12 @@ if not xsltproc:
test.dir_fixture('image')
# Normal invocation
-test.run(arguments=['-f','SConstruct.cmd'], stderr=None)
+test.run(arguments=['-f','SConstruct.cmd','DOCBOOK_XSLTPROC=%s'%xsltproc], stderr=None)
test.must_exist(test.workpath('refdb.8'))
test.must_exist(test.workpath('refdb.sh.8'))
# Cleanup
-test.run(arguments=['-f','SConstruct.cmd','-c'])
+test.run(arguments=['-f','SConstruct.cmd','-c','DOCBOOK_XSLTPROC=%s'%xsltproc])
test.must_not_exist(test.workpath('refdb.8'))
test.must_not_exist(test.workpath('refdb.sh.8'))
diff --git a/test/ENV.py b/test/ENV.py
index 59b1cdb..36ad844 100644
--- a/test/ENV.py
+++ b/test/ENV.py
@@ -25,7 +25,6 @@
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
-
import TestSCons
_python_ = TestSCons._python_
@@ -47,7 +46,7 @@ env2.Bld(target = 'env2.out', source = 'input')
""" % locals())
test.write('build.py',
-r"""#!/usr/bin/env python
+r"""\
import os
import sys
contents = open(sys.argv[2], 'r').read()
diff --git a/test/Java/JAR.py b/test/Java/JAR.py
index faf01a3..d5425af 100644
--- a/test/Java/JAR.py
+++ b/test/Java/JAR.py
@@ -26,11 +26,16 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import TestSCons
+import sys
_python_ = TestSCons._python_
test = TestSCons.TestSCons()
+# Keep this logic because it skips the test if javac or jar not found.
+where_javac, java_version = test.java_where_javac()
+where_jar = test.java_where_jar()
+
test.write('myjar.py', r"""
import sys
args = sys.argv[1:]
@@ -119,22 +124,13 @@ test.run(arguments='classes.jar')
test.must_match('classes.jar',
'cvfm classes.jar foo.mf -C testdir bar.class\n', mode='r')
-
-
-where_javac, java_version = test.java_where_javac()
-where_jar = test.java_where_jar()
-
-
-
test.file_fixture('wrapper_with_args.py')
test.write('SConstruct', """
DefaultEnvironment(tools=[])
-foo = Environment(tools = ['javac', 'jar'],
- JAVAC = r'%(where_javac)s',
- JAR = r'%(where_jar)s')
-jar = foo.Dictionary('JAR')
-bar = foo.Clone(JAR = r'%(_python_)s wrapper_with_args.py ' + jar)
+foo = Environment(tools = ['javac', 'jar'])
+# jar = foo.Dictionary('JAR')
+bar = foo.Clone(JAR = r'%(_python_)s wrapper_with_args.py jar')
foo.Java(target = 'classes', source = 'com/sub/foo')
bar.Java(target = 'classes', source = 'com/sub/bar')
foo.Jar(target = 'foo', source = 'classes/com/sub/foo')
@@ -232,7 +228,7 @@ public class Example6
test.run(arguments = '.')
-expected_wrapper_out = "wrapper_with_args.py %(where_jar)s cf bar.jar classes/com/sub/bar\n"
+expected_wrapper_out = "wrapper_with_args.py jar cf bar.jar classes/com/sub/bar\n"
expected_wrapper_out = expected_wrapper_out.replace('/', os.sep)
test.must_match('wrapper.out',
expected_wrapper_out % locals(), mode='r')
@@ -310,14 +306,16 @@ public class JavaFile3
}
""")
-test.run(chdir='testdir2')
# check the output and make sure the java files got converted to classes
-if("jar cf foo.jar " +
- "-C com/javasource/JavaFile1 com/javasource/JavaFile1.class " +
- "-C com/javasource/JavaFile2 com/javasource/JavaFile2.class " +
- "-C com/javasource/JavaFile3 com/javasource/JavaFile3.class" not in test.stdout()):
- test.fail_test()
+# use regex . for dirsep so this will work on both windows and other platforms.
+expect = ".*jar cf foo.jar -C com.javasource.JavaFile1 com.javasource.JavaFile1.class -C com.javasource.JavaFile2 com.javasource.JavaFile2.class -C com.javasource.JavaFile3 com.javasource.JavaFile3.class.*"
+
+test.run(chdir='testdir2',
+ match=TestSCons.match_re_dotall,
+ stdout = expect)
+
+
#test single target jar
test.must_exist(['testdir2','foobar.jar'])
diff --git a/test/Java/JARCHDIR.py b/test/Java/JARCHDIR.py
index d574fe7..59bf082 100644
--- a/test/Java/JARCHDIR.py
+++ b/test/Java/JARCHDIR.py
@@ -38,17 +38,14 @@ import os
import TestSCons
test = TestSCons.TestSCons()
-
+# Keep this logic because it skips the test if javac or jar not found.
where_javac, java_version = test.java_where_javac()
where_jar = test.java_where_jar()
-
-
test.write('SConstruct', """
+DefaultEnvironment(tools=[])
dir = 'dist'
env = Environment(tools = ['javac', 'jar'],
- JAVAC = r'%(where_javac)s',
- JAR = r'%(where_jar)s',
JARCHDIR = dir)
bin = env.Java(dir, Dir('./'))
jar = env.Jar(File('c.jar', dir), bin)
@@ -58,8 +55,9 @@ jar = env.Jar(File('c.jar', dir), bin)
env = env.Clone(JARCHDIR = '.')
inner = env.Jar('inner.jar', 'Inner$$Class.class')
-target_env = env.Clone(JARCHDIR = '${TARGET.dir}')
-target_env.Jar('out/t.jar', 'in/t.class')
+# Commented out as this logic doesn't work as is.
+# target_env = env.Clone(JARCHDIR = '${TARGET.dir}')
+# target_env.Jar('out/t.jar', 'in/t.class')
source_env = env.Clone(JARCHDIR = '${SOURCE.dir}')
source_env.Jar('out/s.jar', 'in/s.class')
@@ -67,8 +65,6 @@ source_env.Jar('out/s.jar', 'in/s.class')
Default(bin, jar, inner)
""" % locals())
-
-
test.subdir('in')
test.write('a.java', """\
@@ -98,21 +94,19 @@ test.write(['in', 's.class'], "s.class\n")
# don't blow up (i.e., validates that we pass the right arguments to
# env.subst() in the code that handle jar).
-p = test.workpath('out')
-for d in test.workpath('in').split(os.sep):
- p = p + d
- test.subdir(p)
- p = p + os.sep
+# p = test.workpath('out')
+# for d in test.workpath('in').split(os.sep):
+# p = p + d
+# test.subdir(p)
+# p = p + os.sep
-test.write([p, 't.class'], "t.class\n")
+# test.write([p, 't.class'], "t.class\n")
test.write(['in', 't.class'], "t.class\n")
test.write('Inner$Class.class', "Inner$Class.class\n")
test.run(arguments = '.')
-
-
test.pass_test()
# Local Variables:
diff --git a/test/Java/JARFLAGS.py b/test/Java/JARFLAGS.py
index c0ae627..39a0a6c 100644
--- a/test/Java/JARFLAGS.py
+++ b/test/Java/JARFLAGS.py
@@ -30,17 +30,14 @@ import TestSCons
test = TestSCons.TestSCons()
-test.subdir('src')
-
+# Keep this logic because it skips the test if javac or jar not found.
where_javac, java_version = test.java_where_javac()
where_jar = test.java_where_jar()
-
+test.subdir('src')
test.write('SConstruct', """
env = Environment(tools = ['javac', 'jar'],
- JAVAC = r'%(where_javac)s',
- JAR = r'%(where_jar)s',
JARFLAGS = 'cvf')
env['JARFLAGS'] = 'cvf'
class_files = env.Java(target = 'classes', source = 'src')
@@ -62,13 +59,12 @@ public class Example1
""")
expect = test.wrap_stdout("""\
-%(where_javac)s -d classes -sourcepath src src/Example1\.java
-%(where_jar)s cvf test.jar -C classes src/Example1\.class
+javac -d classes -sourcepath src src.Example1\.java
+jar cvf test.jar -C classes src.Example1\.class
.*
-adding: src/Example1\.class.*
+adding: src.Example1\.class.*
""" % locals())
-expect = expect.replace('/', os.sep)
test.run(arguments = '.',
match=TestSCons.match_re_dotall,
diff --git a/test/Java/JAVABOOTCLASSPATH.py b/test/Java/JAVABOOTCLASSPATH.py
index 6913c6a..196cc54 100644
--- a/test/Java/JAVABOOTCLASSPATH.py
+++ b/test/Java/JAVABOOTCLASSPATH.py
@@ -42,7 +42,6 @@ where_javah = test.java_where_javah()
test.write('SConstruct', """
env = Environment(tools = ['javac', 'javah'],
- JAVAC = r'%(where_javac)s',
JAVABOOTCLASSPATH = ['dir1', 'dir2'])
j1 = env.Java(target = 'class', source = 'com/Example1.java')
j2 = env.Java(target = 'class', source = 'com/Example2.java')
@@ -85,11 +84,11 @@ public class Example2
bootclasspath = os.pathsep.join(['dir1', 'dir2'])
expect = """\
-%(where_javac)s -bootclasspath %(bootclasspath)s -d class -sourcepath com com/Example1.java
-%(where_javac)s -bootclasspath %(bootclasspath)s -d class -sourcepath com com/Example2.java
+javac -bootclasspath %(bootclasspath)s -d class -sourcepath com com.Example1\.java
+javac -bootclasspath %(bootclasspath)s -d class -sourcepath com com.Example2\.java
""" % locals()
-test.run(arguments = '-Q -n .', stdout = expect)
+test.run(arguments = '-Q -n .', stdout = expect, match=TestSCons.match_re)
test.pass_test()
diff --git a/test/Java/JAVACFLAGS.py b/test/Java/JAVACFLAGS.py
index 6afd1b9..28c58c1 100644
--- a/test/Java/JAVACFLAGS.py
+++ b/test/Java/JAVACFLAGS.py
@@ -36,7 +36,6 @@ test.subdir('src')
test.write('SConstruct', """
env = Environment(tools = ['javac'],
- JAVAC = r'%(where_javac)s',
JAVACFLAGS = '-O')
env.Java(target = 'classes', source = 'src')
""" % locals())
@@ -55,7 +54,7 @@ public class Example1
}
""")
-expected_wrapper_out = "%(where_javac)s -O -d classes -sourcepath src src/Example1.java\n"
+expected_wrapper_out = "javac -O -d classes -sourcepath src src/Example1.java\n"
expected_wrapper_out = expected_wrapper_out.replace('/', os.sep)
test.run(arguments = '.',
stdout = test.wrap_stdout(expected_wrapper_out % locals()))
diff --git a/test/Java/JAVACLASSPATH.py b/test/Java/JAVACLASSPATH.py
index bc3bb21..fb2b33f 100644
--- a/test/Java/JAVACLASSPATH.py
+++ b/test/Java/JAVACLASSPATH.py
@@ -40,17 +40,15 @@ where_javac, java_version = test.java_where_javac()
where_javah = test.java_where_javah()
test.write('SConstruct', """
-env = Environment(tools = ['javac', 'javah'],
- JAVAC = r'%(where_javac)s',
- JAVAH = r'%(where_javah)s')
-j1 = env.Java(target = 'class1', source = 'com1/Example1.java')
-j2 = env.Java(target = 'class2', source = 'com2/Example2.java')
+env = Environment(tools = ['javac', 'javah'])
+j1 = env.Java(target = 'class1', source = 'com.1/Example1.java')
+j2 = env.Java(target = 'class2', source = 'com.2/Example2.java')
env.JavaH(target = 'outdir', source = [j1, j2], JAVACLASSPATH = 'class2')
""" % locals())
-test.subdir('com1', 'com2')
+test.subdir('com.1', 'com.2')
-test.write(['com1', 'Example1.java'], """\
+test.write(['com.1', 'Example1.java'], """\
package com;
public class Example1
@@ -64,7 +62,7 @@ public class Example1
}
""")
-test.write(['com2', 'Example2.java'], """\
+test.write(['com.2', 'Example2.java'], """\
package com;
public class Example2
diff --git a/test/Java/JAVAH.py b/test/Java/JAVAH.py
index f07ebb9..c7ac334 100644
--- a/test/Java/JAVAH.py
+++ b/test/Java/JAVAH.py
@@ -108,9 +108,7 @@ if test.javac_is_gcj:
test.file_fixture('wrapper_with_args.py')
test.write('SConstruct', """
-foo = Environment(tools = ['javac', 'javah', 'install'],
- JAVAC = r'%(where_javac)s',
- JAVAH = r'%(where_javah)s')
+foo = Environment(tools = ['javac', 'javah', 'install'])
jv = %(java_version)s
if jv:
foo['JAVAVERSION'] = jv
@@ -282,7 +280,7 @@ class Private {
test.run(arguments = '.')
-test.must_match('wrapper.out', "wrapper_with_args.py %(where_javah)s -d outdir2 -classpath class2 com.sub.bar.Example4 com.other.Example5 com.sub.bar.Example6\n" % locals(),
+test.must_match('wrapper.out', "wrapper_with_args.py javah -d outdir2 -classpath class2 com.sub.bar.Example4 com.other.Example5 com.sub.bar.Example6\n" % locals(),
mode='r')
test.must_exist(['outdir1', 'com_sub_foo_Example1.h'])
diff --git a/test/Java/JAVASOURCEPATH.py b/test/Java/JAVASOURCEPATH.py
index 5f19004..8e7b762 100644
--- a/test/Java/JAVASOURCEPATH.py
+++ b/test/Java/JAVASOURCEPATH.py
@@ -39,8 +39,7 @@ test = TestSCons.TestSCons()
where_javac, java_version = test.java_where_javac()
test.write('SConstruct', """
-env = Environment(tools = ['javac', 'javah'],
- JAVAC = r'%(where_javac)s')
+env = Environment(tools = ['javac', 'javah'])
bar = env.Java(target = 'bar/classes',
source = 'bar/src/TestBar.java',
JAVASOURCEPATH = ['foo/src'])
diff --git a/test/Java/Java-1.6.py b/test/Java/Java-1.6.py
index 04a9155..7bda650 100644
--- a/test/Java/Java-1.6.py
+++ b/test/Java/Java-1.6.py
@@ -35,258 +35,19 @@ import TestSCons
_python_ = TestSCons._python_
test = TestSCons.TestSCons()
+test.dir_fixture('java_version_image')
-where_javac, java_version = test.java_where_javac('1.6')
+version = '1.6'
+where_javac, java_version = test.java_where_javac(version)
+javac_path=os.path.dirname(where_javac)
+# test.verbose_set(1)
+if ' ' in javac_path:
+ javac_path ='"%s"'%javac_path
+java_arguments=["--javac_path=%s"%javac_path,"--java_version=%s"%version]
-test.write('SConstruct', """
-env = Environment(tools = ['javac'],
- JAVAVERSION = '1.6',
- JAVAC = r'%(where_javac)s')
-env.Java(target = 'class1', source = 'com/sub/foo')
-env.Java(target = 'class2', source = 'com/sub/bar')
-env.Java(target = 'class3', source = ['src1', 'src2'])
-env.Java(target = 'class4', source = ['src4'])
-env.Java(target = 'class5', source = ['src5'])
-env.Java(target = 'class6', source = ['src6'])
-""" % locals())
-
-test.subdir('com',
- ['com', 'sub'],
- ['com', 'sub', 'foo'],
- ['com', 'sub', 'bar'],
- 'src1',
- 'src2',
- 'src4',
- 'src5',
- 'src6')
-
-test.write(['com', 'sub', 'foo', 'Example1.java'], """\
-package com.sub.foo;
-
-public class Example1
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['com', 'sub', 'foo', 'Example2.java'], """\
-package com.other;
-
-public class Example2
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['com', 'sub', 'foo', 'Example3.java'], """\
-package com.sub.foo;
-
-public class Example3
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['com', 'sub', 'bar', 'Example4.java'], """\
-package com.sub.bar;
-
-public class Example4
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['com', 'sub', 'bar', 'Example5.java'], """\
-package com.other;
-
-public class Example5
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['com', 'sub', 'bar', 'Example6.java'], """\
-package com.sub.bar;
-
-public class Example6
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-test.write(['src1', 'Example7.java'], """\
-public class Example7
-{
-
- public static void main(String[] args)
- {
-
- }
-
-}
-""")
-
-# Acid-test file for parsing inner Java classes, courtesy Chad Austin.
-test.write(['src2', 'Test.java'], """\
-class Empty {
-}
-
-interface Listener {
- public void execute();
-}
-
-public
-class
-Test {
- class Inner {
- void go() {
- use(new Listener() {
- public void execute() {
- System.out.println("In Inner");
- }
- });
- }
- String s1 = "class A";
- String s2 = "new Listener() { }";
- /* class B */
- /* new Listener() { } */
- }
-
- public static void main(String[] args) {
- new Test().run();
- }
-
- void run() {
- use(new Listener() {
- public void execute() {
- use(new Listener( ) {
- public void execute() {
- System.out.println("Inside execute()");
- }
- });
- }
- });
-
- new Inner().go();
- }
-
- void use(Listener l) {
- l.execute();
- }
-}
-
-class Private {
- void run() {
- new Listener() {
- public void execute() {
- }
- };
- }
-}
-""")
-
-# Testing nested anonymous inner classes, courtesy Brandon Mansfield.
-test.write(['src4', 'NestedExample.java'], """\
-// import java.util.*;
-
-public class NestedExample
-{
- public NestedExample()
- {
- new Thread() {
- public void start()
- {
- new Thread() {
- public void start()
- {
- try {Thread.sleep(200);}
- catch (Exception e) {}
- }
- };
- while (true)
- {
- try {Thread.sleep(200);}
- catch (Exception e) {}
- }
- }
- };
- }
-
-
- public static void main(String argv[])
- {
- new NestedExample();
- }
-}
-""")
-
-# Test not finding an anonymous class when the second token after a
-# "new" is a closing brace. This duplicates a test from the unit tests,
-# but lets us make sure that we correctly determine that everything is
-# up-to-date after the build.
-test.write(['src5', 'TestSCons.java'], """\
-class TestSCons {
- public static void main(String[] args) {
- Foo[] fooArray = new Foo[] { new Foo() };
- }
-}
-
-class Foo { }
-""")
-
-# Test private inner class instantiation, courtesy Tilo Prutz:
-# https://github.com/SCons/scons/issues/1594
-test.write(['src6', 'TestSCons.java'], """\
-class test
-{
- test()
- {
- super();
- new inner();
- }
-
- static class inner
- {
- private inner() {}
- }
-}
-""")
-
-
-
-test.run(arguments = '.')
+test.run(arguments = ['.']+java_arguments)
expect_1 = [
test.workpath('class1', 'com', 'other', 'Example2.class'),
@@ -362,9 +123,10 @@ classes_must_match('class6', expect_6)
test.fail_test(failed)
-test.up_to_date(options='--debug=explain', arguments = '.')
+test.up_to_date(options=["--debug=explain"]+java_arguments,
+ arguments = '.')
-test.run(arguments = '-c .')
+test.run(arguments = ['-c','.']+java_arguments)
classes_must_not_exist('class1', expect_1)
classes_must_not_exist('class2', expect_2)
diff --git a/test/Java/Java-1.8.py b/test/Java/Java-1.8.py
new file mode 100644
index 0000000..8e85889
--- /dev/null
+++ b/test/Java/Java-1.8.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test Java compilation with a live Java 1.8 "javac" compiler.
+"""
+
+import os
+import sys
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+test.dir_fixture('java_version_image')
+
+version = '1.8'
+where_javac, java_version = test.java_where_javac(version)
+javac_path=os.path.dirname(where_javac)
+
+# test.verbose_set(1)
+
+if ' ' in javac_path:
+ javac_path ='"%s"'%javac_path
+java_arguments=["--javac_path=%s"%javac_path,"--java_version=%s"%version]
+
+test.run(arguments = ['.']+java_arguments)
+
+expect_1 = [
+ test.workpath('class1', 'com', 'other', 'Example2.class'),
+ test.workpath('class1', 'com', 'sub', 'foo', 'Example1.class'),
+ test.workpath('class1', 'com', 'sub', 'foo', 'Example3.class'),
+]
+
+expect_2 = [
+ test.workpath('class2', 'com', 'other', 'Example5.class'),
+ test.workpath('class2', 'com', 'sub', 'bar', 'Example4.class'),
+ test.workpath('class2', 'com', 'sub', 'bar', 'Example6.class'),
+]
+
+expect_3 = [
+ test.workpath('class3', 'Empty.class'),
+ test.workpath('class3', 'Example7.class'),
+ test.workpath('class3', 'Listener.class'),
+ test.workpath('class3', 'Private$1.class'),
+ test.workpath('class3', 'Private.class'),
+ test.workpath('class3', 'Test$1$1.class'),
+ test.workpath('class3', 'Test$1.class'),
+ test.workpath('class3', 'Test$Inner$1.class'),
+ test.workpath('class3', 'Test$Inner.class'),
+ test.workpath('class3', 'Test.class'),
+]
+
+expect_4 = [
+ test.workpath('class4', 'NestedExample$1$1.class'),
+ test.workpath('class4', 'NestedExample$1.class'),
+ test.workpath('class4', 'NestedExample.class'),
+]
+
+expect_5 = [
+ test.workpath('class5', 'Foo.class'),
+ test.workpath('class5', 'TestSCons.class'),
+]
+
+expect_6 = [
+ test.workpath('class6', 'test$1.class'),
+ test.workpath('class6', 'test$inner.class'),
+ test.workpath('class6', 'test.class'),
+]
+
+failed = None
+
+def classes_must_match(dir, expect):
+ global failed
+ got = test.java_get_class_files(test.workpath(dir))
+ if expect != got:
+ sys.stderr.write("Expected the following class files in '%s':\n" % dir)
+ for c in expect:
+ sys.stderr.write(' %s\n' % c)
+ sys.stderr.write("Got the following class files in '%s':\n" % dir)
+ for c in got:
+ sys.stderr.write(' %s\n' % c)
+ failed = 1
+
+def classes_must_not_exist(dir, expect):
+ global failed
+ present = [path for path in expect if os.path.exists(path)]
+ if present:
+ sys.stderr.write("Found the following unexpected class files in '%s' after cleaning:\n" % dir)
+ for c in present:
+ sys.stderr.write(' %s\n' % c)
+ failed = 1
+
+classes_must_match('class1', expect_1)
+classes_must_match('class2', expect_2)
+classes_must_match('class3', expect_3)
+classes_must_match('class4', expect_4)
+classes_must_match('class5', expect_5)
+classes_must_match('class6', expect_6)
+
+test.fail_test(failed)
+
+test.up_to_date(options=["--debug=explain"]+java_arguments,
+ arguments = '.')
+
+test.run(arguments = ['-c','.']+java_arguments)
+
+classes_must_not_exist('class1', expect_1)
+classes_must_not_exist('class2', expect_2)
+classes_must_not_exist('class3', expect_3)
+classes_must_not_exist('class4', expect_4)
+classes_must_not_exist('class5', expect_5)
+# This test case should pass, but doesn't.
+# The expect_6 list contains the class files that the Java compiler
+# actually creates, apparently because of the "private" instantiation
+# of the "inner" class. Our parser doesn't currently detect this, so
+# it doesn't know to remove that generated class file.
+#classes_must_not_exist('class6', expect_6)
+
+test.fail_test(failed)
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Java/RMIC.py b/test/Java/RMIC.py
index 19e799e..021f666 100644
--- a/test/Java/RMIC.py
+++ b/test/Java/RMIC.py
@@ -32,6 +32,8 @@ _python_ = TestSCons._python_
test = TestSCons.TestSCons()
+# test.verbose_set(1)
+
test.write('myrmic.py', r"""
import os
import sys
@@ -74,7 +76,6 @@ test.run(arguments = '.', stderr = None)
test.must_match(['outdir', 'test1.class'], "test1.java\nline 3\n", mode='r')
if os.path.normcase('.java') == os.path.normcase('.JAVA'):
-
test.write('SConstruct', """\
env = Environment(tools = ['rmic'],
RMIC = r'%(_python_)s myrmic.py')
@@ -103,6 +104,12 @@ if java_version.count('.') == 1:
curver = (int(major), int(minor))
except:
pass
+elif java_version.count('.') == 0:
+ # java 11?
+ try:
+ curver = (int(java_version), 0)
+ except:
+ pass
# Check the version of the found Java compiler.
# If it's 1.8 or higher, we skip the further RMIC test
@@ -118,9 +125,7 @@ if curver < (1, 8):
test.file_fixture('wrapper_with_args.py')
test.write('SConstruct', """
-foo = Environment(tools = ['javac', 'rmic'],
- JAVAC = r'%(where_javac)s',
- RMIC = r'%(where_rmic)s')
+foo = Environment(tools = ['javac', 'rmic'])
foo.Java(target = 'class1', source = 'com/sub/foo')
foo.RMIC(target = 'outdir1',
source = ['class1/com/sub/foo/Example1.class',
@@ -161,7 +166,7 @@ package com.sub.foo;
import java.rmi.Naming;
import java.rmi.RemoteException;
-import java.rmi.RMISecurityManager;
+import java.lang.SecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class Example1 extends UnicastRemoteObject implements Hello {
@@ -178,7 +183,7 @@ public class Example1 extends UnicastRemoteObject implements Hello {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
- System.setSecurityManager(new RMISecurityManager());
+ System.setSecurityManager(new SecurityManager());
}
try {
@@ -200,7 +205,7 @@ package com.sub.foo;
import java.rmi.Naming;
import java.rmi.RemoteException;
-import java.rmi.RMISecurityManager;
+import java.lang.SecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class Example2 extends UnicastRemoteObject implements Hello {
@@ -217,7 +222,7 @@ public class Example2 extends UnicastRemoteObject implements Hello {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
- System.setSecurityManager(new RMISecurityManager());
+ System.setSecurityManager(new SecurityManager());
}
try {
@@ -250,7 +255,7 @@ package com.sub.bar;
import java.rmi.Naming;
import java.rmi.RemoteException;
-import java.rmi.RMISecurityManager;
+import java.lang.SecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class Example3 extends UnicastRemoteObject implements Hello {
@@ -267,7 +272,7 @@ public class Example3 extends UnicastRemoteObject implements Hello {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
- System.setSecurityManager(new RMISecurityManager());
+ System.setSecurityManager(new SecurityManager());
}
try {
@@ -289,7 +294,7 @@ package com.sub.bar;
import java.rmi.Naming;
import java.rmi.RemoteException;
-import java.rmi.RMISecurityManager;
+import java.lang.SecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class Example4 extends UnicastRemoteObject implements Hello {
@@ -306,7 +311,7 @@ public class Example4 extends UnicastRemoteObject implements Hello {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
- System.setSecurityManager(new RMISecurityManager());
+ System.setSecurityManager(new SecurityManager());
}
try {
@@ -326,7 +331,7 @@ public class Example4 extends UnicastRemoteObject implements Hello {
test.run(arguments = '.')
test.must_match('wrapper.out',
- "wrapper_with_args.py %s -d outdir2 -classpath class2 com.sub.bar.Example3 com.sub.bar.Example4\n" % where_rmic,
+ "wrapper_with_args.py rmic -d outdir2 -classpath class2 com.sub.bar.Example3 com.sub.bar.Example4\n",
mode='r')
test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example1_Stub.class'))
diff --git a/test/Java/java_version_image/SConstruct b/test/Java/java_version_image/SConstruct
new file mode 100644
index 0000000..945c864
--- /dev/null
+++ b/test/Java/java_version_image/SConstruct
@@ -0,0 +1,35 @@
+
+AddOption('--javac_path',
+ dest='javac_path',
+ action='store',
+ default='/usr/bin',
+ type='string')
+
+AddOption('--java_version',
+ dest='java_version',
+ action='store',
+ default='1.6',
+ type='string')
+
+path=GetOption('javac_path')
+if path[0] == "'":
+ path = path[1:-1]
+
+version = GetOption('java_version')
+
+env = Environment(tools = ['javac'],
+ JAVAVERSION = version,
+ )
+
+
+env.AppendENVPath('PATH',path)
+
+# print('PATH:%s'%env['ENV']['PATH'])
+
+
+env.Java(target = 'class1', source = 'com/sub/foo')
+env.Java(target = 'class2', source = 'com/sub/bar')
+env.Java(target = 'class3', source = ['src1', 'src2'])
+env.Java(target = 'class4', source = ['src4'])
+env.Java(target = 'class5', source = ['src5'])
+env.Java(target = 'class6', source = ['src6'])
diff --git a/test/Java/java_version_image/class6/test$1.class b/test/Java/java_version_image/class6/test$1.class
new file mode 100644
index 0000000..dd58d98
--- /dev/null
+++ b/test/Java/java_version_image/class6/test$1.class
Binary files differ
diff --git a/test/Java/java_version_image/com/sub/bar/Example4.java b/test/Java/java_version_image/com/sub/bar/Example4.java
new file mode 100644
index 0000000..0748d54
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/bar/Example4.java
@@ -0,0 +1,11 @@
+package com.sub.bar;
+
+public class Example4
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/com/sub/bar/Example5.java b/test/Java/java_version_image/com/sub/bar/Example5.java
new file mode 100644
index 0000000..69d2937
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/bar/Example5.java
@@ -0,0 +1,11 @@
+package com.other;
+
+public class Example5
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/com/sub/bar/Example6.java b/test/Java/java_version_image/com/sub/bar/Example6.java
new file mode 100644
index 0000000..1811b80
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/bar/Example6.java
@@ -0,0 +1,11 @@
+package com.sub.bar;
+
+public class Example6
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/com/sub/foo/Example1.java b/test/Java/java_version_image/com/sub/foo/Example1.java
new file mode 100644
index 0000000..82aac2e
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/foo/Example1.java
@@ -0,0 +1,11 @@
+package com.sub.foo;
+
+public class Example1
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/com/sub/foo/Example2.java b/test/Java/java_version_image/com/sub/foo/Example2.java
new file mode 100644
index 0000000..6349ac9
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/foo/Example2.java
@@ -0,0 +1,11 @@
+package com.other;
+
+public class Example2
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/com/sub/foo/Example3.java b/test/Java/java_version_image/com/sub/foo/Example3.java
new file mode 100644
index 0000000..092f0cd
--- /dev/null
+++ b/test/Java/java_version_image/com/sub/foo/Example3.java
@@ -0,0 +1,11 @@
+package com.sub.foo;
+
+public class Example3
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/src1/Example7.java b/test/Java/java_version_image/src1/Example7.java
new file mode 100644
index 0000000..80d94f2
--- /dev/null
+++ b/test/Java/java_version_image/src1/Example7.java
@@ -0,0 +1,9 @@
+public class Example7
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
diff --git a/test/Java/java_version_image/src2/Test.java b/test/Java/java_version_image/src2/Test.java
new file mode 100644
index 0000000..6f224b0
--- /dev/null
+++ b/test/Java/java_version_image/src2/Test.java
@@ -0,0 +1,55 @@
+class Empty {
+}
+
+interface Listener {
+ public void execute();
+}
+
+public
+class
+Test {
+ class Inner {
+ void go() {
+ use(new Listener() {
+ public void execute() {
+ System.out.println("In Inner");
+ }
+ });
+ }
+ String s1 = "class A";
+ String s2 = "new Listener() { }";
+ /* class B */
+ /* new Listener() { } */
+ }
+
+ public static void main(String[] args) {
+ new Test().run();
+ }
+
+ void run() {
+ use(new Listener() {
+ public void execute() {
+ use(new Listener( ) {
+ public void execute() {
+ System.out.println("Inside execute()");
+ }
+ });
+ }
+ });
+
+ new Inner().go();
+ }
+
+ void use(Listener l) {
+ l.execute();
+ }
+}
+
+class Private {
+ void run() {
+ new Listener() {
+ public void execute() {
+ }
+ };
+ }
+}
diff --git a/test/Java/java_version_image/src4/NestedExample.java b/test/Java/java_version_image/src4/NestedExample.java
new file mode 100644
index 0000000..531f2e9
--- /dev/null
+++ b/test/Java/java_version_image/src4/NestedExample.java
@@ -0,0 +1,31 @@
+// import java.util.*;
+
+public class NestedExample
+{
+ public NestedExample()
+ {
+ new Thread() {
+ public void start()
+ {
+ new Thread() {
+ public void start()
+ {
+ try {Thread.sleep(200);}
+ catch (Exception e) {}
+ }
+ };
+ while (true)
+ {
+ try {Thread.sleep(200);}
+ catch (Exception e) {}
+ }
+ }
+ };
+ }
+
+
+ public static void main(String argv[])
+ {
+ new NestedExample();
+ }
+}
diff --git a/test/Java/java_version_image/src5/TestSCons.java b/test/Java/java_version_image/src5/TestSCons.java
new file mode 100644
index 0000000..46572c4
--- /dev/null
+++ b/test/Java/java_version_image/src5/TestSCons.java
@@ -0,0 +1,7 @@
+class TestSCons {
+ public static void main(String[] args) {
+ Foo[] fooArray = new Foo[] { new Foo() };
+ }
+}
+
+class Foo { }
diff --git a/test/Java/java_version_image/src6/TestSCons.java b/test/Java/java_version_image/src6/TestSCons.java
new file mode 100644
index 0000000..1aeed2f
--- /dev/null
+++ b/test/Java/java_version_image/src6/TestSCons.java
@@ -0,0 +1,13 @@
+class test
+{
+ test()
+ {
+ super();
+ new inner();
+ }
+
+ static class inner
+ {
+ private inner() {}
+ }
+}
diff --git a/test/Java/multi-step.py b/test/Java/multi-step.py
index 01a3163..f5ee257 100644
--- a/test/Java/multi-step.py
+++ b/test/Java/multi-step.py
@@ -35,6 +35,7 @@ import os
import TestSCons
test = TestSCons.TestSCons()
+# test.verbose_set(1)
where_javac, java_version = test.java_where_javac()
where_javah = test.java_where_javah()
@@ -44,15 +45,14 @@ swig = test.where_is('swig')
if not swig:
test.skip_test('Can not find installed "swig", skipping test.\n')
+# Skip this test on AppVeyor
+
# Skip this test as SCons doesn't (currently) predict the generated
# inner/anonymous class generated .class files generated by gcj
# and so will always fail
if test.javac_is_gcj:
test.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n')
-
-
-
test.subdir(['src'],
['src', 'HelloApplet'],
['src', 'HelloApplet', 'com'],
@@ -74,12 +74,17 @@ test.subdir(['src'],
test.write(['SConstruct'], """\
import os,sys
-env=Environment(tools = ['default', 'javac', 'javah', 'swig'],
- CPPPATH=%(where_java_include)s,
- JAVAC = r'%(where_javac)s',
- JAVAH = r'%(where_javah)s')
+
+if sys.platform == 'win32':
+ # Ensure tests don't pick up link from mingw or cygwin
+ tools = ['msvc', 'mslink', 'jar', 'javac', 'javah', 'swig']
+else:
+ tools = ['default', 'javac', 'javah', 'swig']
+
+env=Environment(tools = tools,
+ CPPPATH=["$JAVAINCLUDES"])
Export('env')
-env.PrependENVPath('PATH',os.environ.get('PATH',[]))
+# env.PrependENVPath('PATH',os.environ.get('PATH',[]))
env['INCPREFIX']='-I'
env.Append(SWIGFLAGS=['-c++','$_CPPINCFLAGS'])
@@ -154,6 +159,9 @@ public class Hello extends Applet {
test.write(['src', 'javah', 'MyID.cc'], """\
#include "MyID.h"
+#ifdef _MSC_VER
+__declspec(dllexport)
+#endif
int getMyID()
{
return 0;
diff --git a/test/Java/no-JARCHDIR.py b/test/Java/no-JARCHDIR.py
index 2037524..11754c0 100644
--- a/test/Java/no-JARCHDIR.py
+++ b/test/Java/no-JARCHDIR.py
@@ -35,13 +35,12 @@ import TestSCons
test = TestSCons.TestSCons()
+# will skip tests when needed tools not present.
where_javac, java_version = test.java_where_javac()
where_jar = test.java_where_jar()
test.subdir('src')
-
-
test.write(['src', 'a.java'], """\
package foo.bar;
public class a {}
@@ -52,20 +51,13 @@ package foo.bar;
public class b {}
""")
-
-
test.write('SConstruct', """\
-env = Environment(tools = ['javac', 'jar'],
- JAVAC = r'%(where_javac)s',
- JAR = r'%(where_jar)s')
+env = Environment(tools = ['javac', 'jar'])
jar = env.Jar('x.jar', env.Java(target = 'classes', source = 'src'))
""" % locals())
test.run(arguments = '.')
-
-
-
test.run(program = where_jar, arguments = 'tf x.jar')
expect = """\
@@ -75,16 +67,10 @@ foo/bar/b.class
test.must_contain_all_lines(test.stdout(), [expect])
-
-
test.run(arguments = '-c')
-
-
test.write('SConstruct', """\
env = Environment(tools = ['javac', 'jar'],
- JAVAC = r'%(where_javac)s',
- JAR = r'%(where_jar)s',
JARCHDIR = None)
jar = env.Jar('x.jar', env.Java(target = 'classes', source = 'src'))
@@ -92,8 +78,6 @@ jar = env.Jar('x.jar', env.Java(target = 'classes', source = 'src'))
test.run(arguments = '.')
-
-
test.run(program = where_jar, arguments = 'tf x.jar')
expect = """\
@@ -102,9 +86,6 @@ classes/foo/bar/b.class
"""
test.must_contain_all_lines(test.stdout(), [expect])
-
-
-
test.pass_test()
# Local Variables:
diff --git a/test/Java/source-files.py b/test/Java/source-files.py
index bf263cf..e5cb8b6 100644
--- a/test/Java/source-files.py
+++ b/test/Java/source-files.py
@@ -35,12 +35,12 @@ _python_ = TestSCons._python_
test = TestSCons.TestSCons()
+# Keep this logic because it skips the test if javac or jar not found.
where_javac, java_version = test.java_where_javac()
-
+where_jar = test.java_where_jar()
test.write('SConstruct', """
-env = Environment(tools = ['javac', 'javah'],
- JAVAC = r'%(where_javac)s')
+env = Environment(tools = ['javac', 'javah'])
env.Java(target = 'class1', source = 'com/Example1.java')
env.Java(target = 'class2', source = ['com/Example2.java', 'com/Example3.java'])
""" % locals())
diff --git a/test/Java/swig-dependencies.py b/test/Java/swig-dependencies.py
index bd7a576..a3af9ec 100644
--- a/test/Java/swig-dependencies.py
+++ b/test/Java/swig-dependencies.py
@@ -40,7 +40,6 @@ if not swig:
where_javac, java_version = test.java_where_javac()
where_javah = test.java_where_javah()
-#where_jar = test.java_where_jar()
where_java_include=test.java_where_includes()
@@ -51,12 +50,10 @@ test.subdir(['foo'],
test.write(['SConstruct'], """\
import os
-env = Environment(ENV = os.environ,
- CPPPATH=%(where_java_include)s,
- JAVAC = r'%(where_javac)s',
- JAVAH = r'%(where_javah)s')
-
-env.Append(CPPFLAGS = ' -g -Wall')
+env = Environment(ENV = os.environ)
+if env['PLATFORM'] != 'win32':
+ env.Append(CPPFLAGS = ' -g -Wall')
+env['CPPPATH'] ='$JAVAINCLUDES'
Export('env')
@@ -79,13 +76,28 @@ int fooAdd(int a, int b) {
""")
test.write(['foo', 'foo.h'], """\
+#ifdef _MSC_VER
+__declspec(dllexport)
+#endif
int fooAdd(int, int);
""")
test.write(['java', 'Java_foo_interface.i'], """\
#include "foo.h"
+#include <windows.i>
+
%module foopack
+
+%{
+
+#ifdef _MSC_VER
+__declspec(dllexport)
+#endif
+int hello(){
+ return 1;
+}
+%}
""")
test.write(['java', 'SConscript'], """\
@@ -103,7 +115,7 @@ libadd = ['foo',]
libpath = ['#foo',]
#swigflags = '-c++ -java -Wall -package foopack -Ifoo'
-swigflags = '-c++ -java -Wall -Ifoo'
+swigflags = '-c++ -java -Wall -Ifoo -DTEST_$PLATFORM'
Java_foo_interface = env.SharedLibrary(
'Java_foo_interface',
diff --git a/test/Libs/SharedLibrary.py b/test/Libs/SharedLibrary.py
index eac575c..cc3fa66 100644
--- a/test/Libs/SharedLibrary.py
+++ b/test/Libs/SharedLibrary.py
@@ -30,6 +30,7 @@ import sys
import TestSCons
test = TestSCons.TestSCons()
+test.verbose_set(1)
test.write('SConstruct', """
import sys
diff --git a/test/SWIG/build-dir.py b/test/SWIG/build-dir.py
index d268c87..bc105a5 100644
--- a/test/SWIG/build-dir.py
+++ b/test/SWIG/build-dir.py
@@ -139,25 +139,27 @@ public:
};
""")
-test.write(['source', 'test.py'], """\
-#!/usr/bin/env python
-from __future__ import print_function
-
-import linalg
-
-
-x = linalg.Vector(5)
-print(x)
-
-x[1] = 99.5
-x[3] = 8.3
-x[4] = 11.1
-
-
-for i, v in enumerate(x):
- print("\tx[%d] = %g" % (i, v))
-
-""")
+## _python_ = TestSCons._python_
+## XXX: @ptomulik: looks like it was unused?
+## test.write(['source', 'test.py'], """\
+## #!%(_python_)s
+## from __future__ import print_function
+##
+## import linalg
+##
+##
+## x = linalg.Vector(5)
+## print(x)
+##
+## x[1] = 99.5
+## x[3] = 8.3
+## x[4] = 11.1
+##
+##
+## for i, v in enumerate(x):
+## print("\tx[%%d] = %%g" %% (i, v))
+##
+## """ % locals())
test.run(arguments = '.')
diff --git a/test/SWIG/live.py b/test/SWIG/live.py
index a64defe..e01597d 100644
--- a/test/SWIG/live.py
+++ b/test/SWIG/live.py
@@ -145,7 +145,7 @@ test.up_to_date(arguments = ldmodule_prefix+'foo' + _dll)
test.run(arguments = ldmodule_prefix+'bar' + _dll)
-test.must_match('wrapper.out', "wrapper.py" + os.linesep)
+test.must_match('wrapper.out', "wrapper.py\n")
test.run(program = python, stdin = """\
from __future__ import print_function
diff --git a/test/SWIG/remove-modules.py b/test/SWIG/remove-modules.py
index a4d7b16..4ce8eab 100644
--- a/test/SWIG/remove-modules.py
+++ b/test/SWIG/remove-modules.py
@@ -65,7 +65,7 @@ test.write("module.i", """\
test.write('SConstruct', """
foo = Environment(SWIGFLAGS='-python',
%(swig_arch_var)s
- CPPPATH=['%(python_include)s'],
+ CPPPATH=[r'%(python_include)s'],
LDMODULEPREFIX='%(ldmodule_prefix)s',
LDMODULESUFFIX='%(_dll)s',
SWIG=[r'%(swig)s'],
diff --git a/test/SWIG/subdir.py b/test/SWIG/subdir.py
index 6951753..9336f19 100644
--- a/test/SWIG/subdir.py
+++ b/test/SWIG/subdir.py
@@ -63,7 +63,7 @@ else:
test.write('SConstruct', """
env = Environment(SWIGFLAGS='-python',
%(swig_arch_var)s
- CPPPATH=['%(python_include)s/'],
+ CPPPATH=[r'%(python_include)s/'],
LDMODULEPREFIX='%(ldmodule_prefix)s',
LDMODULESUFFIX='%(_dll)s',
SWIG=r'%(swig)s',
diff --git a/test/Scanner/generated.py b/test/Scanner/generated.py
index 4a368b4..3e08549 100644
--- a/test/Scanner/generated.py
+++ b/test/Scanner/generated.py
@@ -36,6 +36,8 @@ complexity is valuable in its own right.
import TestSCons
+_python_ = TestSCons._python_
+
test = TestSCons.TestSCons()
test.subdir('reftree',
@@ -282,7 +284,7 @@ recurse_env.Command([lib_fullname] + lib_objs,
""")
test.write(['src', 'lib_geng', 'MAKE-HEADER.py'], """\
-#!/usr/bin/env python
+#!%(_python_)s
import os
import os.path
@@ -293,7 +295,7 @@ os.chdir(os.path.split(sys.argv[0])[0])
for h in ['libg_gx.h', 'libg_gy.h', 'libg_gz.h']:
open(h, 'w').write('')
-""")
+""" % locals())
test.write(['src', 'lib_geng', 'SConstruct'], """\
import os
diff --git a/test/TEMPFILEPREFIX.py b/test/TEMPFILEPREFIX.py
index f0743e6..c47ebc4 100644
--- a/test/TEMPFILEPREFIX.py
+++ b/test/TEMPFILEPREFIX.py
@@ -37,7 +37,6 @@ import TestSCons
test = TestSCons.TestSCons(match = TestSCons.match_re)
test.write('echo.py', """\
-#!/usr/bin/env python
from __future__ import print_function
import sys
print(sys.argv)
diff --git a/test/TEX/biber_biblatex.py b/test/TEX/biber_biblatex.py
index a63fb3f..b4a4969 100755
--- a/test/TEX/biber_biblatex.py
+++ b/test/TEX/biber_biblatex.py
@@ -49,8 +49,6 @@ if not gloss==0:
test.write(['SConstruct'], """\
-#!/usr/bin/env python
-
import os
env = Environment(ENV=os.environ)
env['BIBTEX'] = 'biber'
diff --git a/test/TEX/biber_biblatex2.py b/test/TEX/biber_biblatex2.py
index 95b5617..e9893ee 100644
--- a/test/TEX/biber_biblatex2.py
+++ b/test/TEX/biber_biblatex2.py
@@ -55,8 +55,6 @@ if not biblatex==0:
test.write(['SConstruct'], """\
-#!/usr/bin/env python
-
import os
env = Environment(ENV=os.environ)
main_output = env.PDF('bibertest.tex')
diff --git a/test/TEX/biblatex.py b/test/TEX/biblatex.py
index a6fbd48..21e1a93 100755
--- a/test/TEX/biblatex.py
+++ b/test/TEX/biblatex.py
@@ -45,8 +45,6 @@ if not biblatex==0:
test.write(['SConstruct'], """\
-#!/usr/bin/env python
-
import os
env = Environment(ENV=os.environ)
main_output = env.PDF(target='biblatextest.pdf', source='biblatextest.tex')
diff --git a/test/TEX/biblatex_plain.py b/test/TEX/biblatex_plain.py
index 68f7cc3..06b3cc6 100644
--- a/test/TEX/biblatex_plain.py
+++ b/test/TEX/biblatex_plain.py
@@ -45,8 +45,6 @@ if not biblatex==0:
test.write(['SConstruct'], """\
-#!/usr/bin/env python
-
import os
env = Environment(ENV=os.environ)
main_output = env.PDF(target='biblatextest.pdf', source='biblatextest.tex')
diff --git a/test/YACC/live.py b/test/YACC/live.py
index 35f6c37..a79d3db 100644
--- a/test/YACC/live.py
+++ b/test/YACC/live.py
@@ -158,7 +158,7 @@ test.run(arguments = 'bar' + _exe)
test.up_to_date(arguments = 'bar' + _exe)
-test.must_match(test.workpath('wrapper.out'), "wrapper.py" + os.linesep)
+test.must_match(test.workpath('wrapper.out'), "wrapper.py\n")
test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "bar.y\n")
diff --git a/test/explain/basic.py b/test/explain/basic.py
index 19fc328..99942cd 100644
--- a/test/explain/basic.py
+++ b/test/explain/basic.py
@@ -29,7 +29,6 @@ Verify a lot of the basic operation of the --debug=explain option.
"""
import os
-
import TestSCons
test = TestSCons.TestSCons()
@@ -52,7 +51,7 @@ inc_bbb_k = test.workpath('inc', 'bbb.k')
-test.write(cat_py, r"""#!/usr/bin/env python
+test.write(cat_py, r"""\
from __future__ import print_function
import sys
diff --git a/test/fixture/wrapper.py b/test/fixture/wrapper.py
index bd8187c..f02ea03 100644
--- a/test/fixture/wrapper.py
+++ b/test/fixture/wrapper.py
@@ -2,5 +2,5 @@ import os
import sys
if '--version' not in sys.argv and '-dumpversion' not in sys.argv:
path = os.path.join(os.path.dirname(os.path.relpath(__file__)), 'wrapper.out')
- open(path, 'w').write("wrapper.py\n")
+ open(path, 'wb').write(b"wrapper.py\n")
os.system(" ".join(sys.argv[1:]))
diff --git a/test/long-lines/signature.py b/test/long-lines/signature.py
index af234a3..64214b4 100644
--- a/test/long-lines/signature.py
+++ b/test/long-lines/signature.py
@@ -30,26 +30,27 @@ surrounded by $( $) from the signature calculation.
"""
import os
-
import TestSCons
+_python_ = TestSCons._python_
+
test = TestSCons.TestSCons()
build_py = test.workpath('build.py')
test.write(build_py, """\
-#!/usr/bin/env python
+#!%(_python_)s
import sys
if sys.argv[1][0] == '@':
- args = open(sys.argv[1][1:], 'rb').read()
+ args = open(sys.argv[1][1:], 'r').read()
args = args.split()
else:
args = sys.argv[1:]
-fp = open(args[0], 'wb')
-fp.write(open(args[1], 'rb').read())
-fp.write('FILEFLAG=%s\\n' % args[2])
-fp.write('TIMESTAMP=%s\\n' % args[3])
-""")
+fp = open(args[0], 'w')
+fp.write(open(args[1], 'r').read())
+fp.write('FILEFLAG=%%s\\n' %% args[2])
+fp.write('TIMESTAMP=%%s\\n' %% args[3])
+""" % locals())
os.chmod(build_py, 0o755)
@@ -74,17 +75,17 @@ env.Command('file.out', 'file.in',
'${TEMPFILE(FILECOM)}')
""" % locals())
-test.write('file.in', "file.in\n")
+test.write('file.in', "file.in\n", mode='w')
test.run(arguments='FILEFLAG=first TIMESTAMP=20090207 .')
-test.must_match('file.out', "file.in\nFILEFLAG=first\nTIMESTAMP=20090207\n")
+test.must_match('file.out', "file.in\nFILEFLAG=first\nTIMESTAMP=20090207\n", mode='r')
test.up_to_date(options='FILEFLAG=first TIMESTAMP=20090208', arguments = '.')
test.run(arguments='FILEFLAG=second TIMESTAMP=20090208 .')
-test.must_match('file.out', "file.in\nFILEFLAG=second\nTIMESTAMP=20090208\n")
+test.must_match('file.out', "file.in\nFILEFLAG=second\nTIMESTAMP=20090208\n", mode='r')
test.up_to_date(options='FILEFLAG=second TIMESTAMP=20090209', arguments = '.')
diff --git a/test/scons-time/run/config/python.py b/test/scons-time/run/config/python.py
index 0734730..c8842c1 100644
--- a/test/scons-time/run/config/python.py
+++ b/test/scons-time/run/config/python.py
@@ -32,6 +32,8 @@ import os
import TestSCons_time
+_python_ = TestSCons_time._python_
+
test = TestSCons_time.TestSCons_time()
test.write_sample_project('foo.tar.gz')
@@ -43,7 +45,7 @@ python = r'%(my_python_py)s'
""" % locals())
test.write(my_python_py, """\
-#!/usr/bin/env python
+#!%(_python_)s
from __future__ import print_function
import sys
profile = ''
@@ -51,8 +53,8 @@ for arg in sys.argv[1:]:
if arg.startswith('--profile='):
profile = arg[10:]
break
-print('my_python.py: %s' % profile)
-""")
+print('my_python.py: %%s' %% profile)
+""" % locals())
os.chmod(my_python_py, 0o755)
diff --git a/test/scons-time/run/option/python.py b/test/scons-time/run/option/python.py
index d0592b6..27ca072 100644
--- a/test/scons-time/run/option/python.py
+++ b/test/scons-time/run/option/python.py
@@ -32,6 +32,8 @@ import os
import TestSCons_time
+_python_ = TestSCons_time._python_
+
test = TestSCons_time.TestSCons_time()
test.write_sample_project('foo.tar.gz')
@@ -39,15 +41,15 @@ test.write_sample_project('foo.tar.gz')
my_python_py = test.workpath('my_python.py')
test.write(my_python_py, """\
-#!/usr/bin/env python
+#!%(_python_)s
import sys
profile = ''
for arg in sys.argv[1:]:
if arg.startswith('--profile='):
profile = arg[10:]
break
-sys.stdout.write('my_python.py: %s\\n' % profile)
-""")
+sys.stdout.write('my_python.py: %%s\\n' %% profile)
+""" % locals())
os.chmod(my_python_py, 0o755)
diff --git a/test/sconsign/script/SConsignFile.py b/test/sconsign/script/SConsignFile.py
index dc45cc1..5e56624 100644
--- a/test/sconsign/script/SConsignFile.py
+++ b/test/sconsign/script/SConsignFile.py
@@ -30,10 +30,11 @@ using the signatures in an SConsignFile().
"""
import re
-
import TestSCons
import TestSConsign
+_python_ = TestSCons._python_
+
test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
test.subdir('sub1', 'sub2')
@@ -41,22 +42,22 @@ test.subdir('sub1', 'sub2')
fake_cc_py = test.workpath('fake_cc.py')
fake_link_py = test.workpath('fake_link.py')
-test.write(fake_cc_py, r"""#!/usr/bin/env python
+test.write(fake_cc_py, r"""#!%(_python_)s
import os
import re
import sys
path = sys.argv[1].split()
-output = open(sys.argv[2], 'wb')
-input = open(sys.argv[3], 'rb')
+output = open(sys.argv[2], 'w')
+input = open(sys.argv[3], 'r')
-output.write('fake_cc.py: %s\n' % sys.argv)
+output.write('fake_cc.py: %%s\n' %% sys.argv)
def find_file(f):
for dir in path:
p = dir + os.sep + f
if os.path.exists(p):
- return open(p, 'rb')
+ return open(p, 'r')
return None
def process(infp, outfp):
@@ -71,20 +72,20 @@ def process(infp, outfp):
process(input, output)
sys.exit(0)
-""")
+""" % locals())
-test.write(fake_link_py, r"""#!/usr/bin/env python
+test.write(fake_link_py, r"""#!%(_python_)s
import sys
-output = open(sys.argv[1], 'wb')
-input = open(sys.argv[2], 'rb')
+output = open(sys.argv[1], 'w')
+input = open(sys.argv[2], 'r')
-output.write('fake_link.py: %s\n' % sys.argv)
+output.write('fake_link.py: %%s\n' %% sys.argv)
output.write(input.read())
sys.exit(0)
-""")
+""" % locals())
test.chmod(fake_cc_py, 0o755)
test.chmod(fake_link_py, 0o755)
diff --git a/test/sconsign/script/Signatures.py b/test/sconsign/script/Signatures.py
index 5babe67..7797bce 100644
--- a/test/sconsign/script/Signatures.py
+++ b/test/sconsign/script/Signatures.py
@@ -36,6 +36,8 @@ SourceSignatures('timestamp') with TargetSignatures('content').
import TestSCons
import TestSConsign
+_python_ = TestSCons._python_
+
test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
# Note: We don't use os.path.join() representations of the file names
@@ -60,22 +62,22 @@ test.subdir('sub1', 'sub2')
fake_cc_py = test.workpath('fake_cc.py')
fake_link_py = test.workpath('fake_link.py')
-test.write(fake_cc_py, r"""#!/usr/bin/env python
+test.write(fake_cc_py, r"""#!%(_python_)s
import os
import re
import sys
path = sys.argv[1].split()
-output = open(sys.argv[2], 'wb')
-input = open(sys.argv[3], 'rb')
+output = open(sys.argv[2], 'w')
+input = open(sys.argv[3], 'r')
-output.write('fake_cc.py: %s\n' % sys.argv)
+output.write('fake_cc.py: %%s\n' %% sys.argv)
def find_file(f):
for dir in path:
p = dir + os.sep + f
if os.path.exists(p):
- return open(p, 'rb')
+ return open(p, 'r')
return None
def process(infp, outfp):
@@ -90,20 +92,20 @@ def process(infp, outfp):
process(input, output)
sys.exit(0)
-""")
+""" % locals())
-test.write(fake_link_py, r"""#!/usr/bin/env python
+test.write(fake_link_py, r"""#!%(_python_)s
import sys
-output = open(sys.argv[1], 'wb')
-input = open(sys.argv[2], 'rb')
+output = open(sys.argv[1], 'w')
+input = open(sys.argv[2], 'r')
-output.write('fake_link.py: %s\n' % sys.argv)
+output.write('fake_link.py: %%s\n' %% sys.argv)
output.write(input.read())
sys.exit(0)
-""")
+""" % locals())
test.chmod(fake_cc_py, 0o755)
test.chmod(fake_link_py, 0o755)
diff --git a/test/sconsign/script/no-SConsignFile.py b/test/sconsign/script/no-SConsignFile.py
index 4e9915b..d9ab51f 100644
--- a/test/sconsign/script/no-SConsignFile.py
+++ b/test/sconsign/script/no-SConsignFile.py
@@ -32,6 +32,8 @@ Verify that the sconsign script works when using an individual
import TestSCons
import TestSConsign
+_python_ = TestSCons._python_
+
test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
test.subdir('sub1', 'sub2')
@@ -49,22 +51,22 @@ test.subdir('sub1', 'sub2')
fake_cc_py = test.workpath('fake_cc.py')
fake_link_py = test.workpath('fake_link.py')
-test.write(fake_cc_py, r"""#!/usr/bin/env python
+test.write(fake_cc_py, r"""#!%(_python_)s
import os
import re
import sys
path = sys.argv[1].split()
-output = open(sys.argv[2], 'wb')
-input = open(sys.argv[3], 'rb')
+output = open(sys.argv[2], 'w')
+input = open(sys.argv[3], 'r')
-output.write('fake_cc.py: %s\n' % sys.argv)
+output.write('fake_cc.py: %%s\n' %% sys.argv)
def find_file(f):
for dir in path:
p = dir + os.sep + f
if os.path.exists(p):
- return open(p, 'rb')
+ return open(p, 'r')
return None
def process(infp, outfp):
@@ -79,20 +81,20 @@ def process(infp, outfp):
process(input, output)
sys.exit(0)
-""")
+""" % locals())
-test.write(fake_link_py, r"""#!/usr/bin/env python
+test.write(fake_link_py, r"""#!%(_python_)s
import sys
-output = open(sys.argv[1], 'wb')
-input = open(sys.argv[2], 'rb')
+output = open(sys.argv[1], 'w')
+input = open(sys.argv[2], 'r')
-output.write('fake_link.py: %s\n' % sys.argv)
+output.write('fake_link.py: %%s\n' %% sys.argv)
output.write(input.read())
sys.exit(0)
-""")
+""" % locals())
test.chmod(fake_cc_py, 0o755)
test.chmod(fake_link_py, 0o755)
diff --git a/test/srcchange.py b/test/srcchange.py
index a156d9b..6916d50 100644
--- a/test/srcchange.py
+++ b/test/srcchange.py
@@ -43,7 +43,6 @@ _python_ = TestSCons._python_
test = TestSCons.TestSCons()
test.write('getrevision', """
-#!/usr/bin/env python
from __future__ import print_function
print(open('revnum.in','r').read().strip(), end='')
""")
diff --git a/test/subdivide.py b/test/subdivide.py
index 8c8eff0..7ddc2e9 100644
--- a/test/subdivide.py
+++ b/test/subdivide.py
@@ -36,7 +36,6 @@ being the equivalent of Decider('content').
"""
import os
-
import TestSCons
test = TestSCons.TestSCons()
@@ -59,7 +58,6 @@ fake_cc_py = test.workpath('fake_cc.py')
fake_link_py = test.workpath('fake_link.py')
test.write(fake_cc_py, """\
-#!/usr/bin/env python
import sys
ofp = open(sys.argv[1], 'w')
ofp.write('fake_cc.py: %s\\n' % sys.argv)
@@ -68,7 +66,6 @@ for s in sys.argv[2:]:
""")
test.write(fake_link_py, """\
-#!/usr/bin/env python
import sys
ofp = open(sys.argv[1], 'w')
ofp.write('fake_link.py: %s\\n' % sys.argv)
diff --git a/test/virtualenv/activated/option/enable-virtualenv.py b/test/virtualenv/activated/option/enable-virtualenv.py
new file mode 100644
index 0000000..a5ceecc
--- /dev/null
+++ b/test/virtualenv/activated/option/enable-virtualenv.py
@@ -0,0 +1,91 @@
+#!/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__"
+
+"""
+Ensure that the --enable-virtualenv flag works.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+import os
+import re
+
+test = TestSCons.TestSCons()
+
+if SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ test.skip_test("Virtualenv support enabled by default, the option --enable-virtualenv is unavailable, skipping\n")
+
+if not SCons.Platform.virtualenv.Virtualenv():
+ test.skip_test("No virtualenv detected, skipping\n")
+
+if not SCons.Platform.virtualenv.select_paths_in_venv(os.getenv('PATH','')):
+ test.skip_test("Virtualenv detected but looks like unactivated, skipping\n")
+
+test.write('SConstruct', """
+import sys
+import SCons.Platform.virtualenv
+env = DefaultEnvironment(tools=[])
+print("sys.executable: %r" % sys.executable)
+print("env.WhereIs('python'): %r" % env.WhereIs('python'))
+""")
+
+test.run(['-Q', '--enable-virtualenv'])
+s = test.stdout()
+m = re.search(r"""^sys\.executable:\s*(?P<py>["'][^"']+["'])\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""\
+can't determine sys.executable from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+interpreter = eval(m.group('py'))
+
+m = re.search(r"""^\s*env.WhereIs\('python'\):\s*(?P<py>["']?[^"']+["']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""
+can't determine env.WhereIs('python') from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+python = eval(m.group('py'))
+
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(interpreter),
+ message="sys.executable points outside of virtualenv")
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(python),
+ message="env.WhereIs('python') points to virtualenv")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/activated/option/ignore-virtualenv.py b/test/virtualenv/activated/option/ignore-virtualenv.py
new file mode 100644
index 0000000..ac6f945
--- /dev/null
+++ b/test/virtualenv/activated/option/ignore-virtualenv.py
@@ -0,0 +1,90 @@
+#!/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__"
+
+"""
+Ensure that the --ignore-virtualenv flag works.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+import os
+import re
+
+test = TestSCons.TestSCons()
+
+if not SCons.Platform.virtualenv.Virtualenv():
+ test.skip_test("No virtualenv detected, skipping\n")
+
+if not SCons.Platform.virtualenv.select_paths_in_venv(os.getenv('PATH','')):
+ test.skip_test("Virtualenv detected but looks like unactivated, skipping\n")
+
+test.write('SConstruct', """
+import sys
+import SCons.Platform.virtualenv
+env = DefaultEnvironment(tools=[])
+print("sys.executable: %s" % repr(sys.executable))
+print("env.WhereIs('python'): %s" % repr(env.WhereIs('python')))
+""")
+
+os.environ['SCONS_ENABLE_VIRTUALENV'] = '1'
+
+test.run(['-Q', '--ignore-virtualenv'])
+s = test.stdout()
+m = re.search(r"""^sys\.executable:\s*(?P<py>["']?[^"']+["']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""\
+can't determine sys.executable from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+interpreter = eval(m.group('py'))
+
+m = re.search(r"""^\s*env.WhereIs\('python'\):\s*(?P<py>["']?[^"']+["']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""
+can't determine env.WhereIs('python') from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+python = eval(m.group('py'))
+
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(interpreter),
+ message="sys.executable points outside of virtualenv")
+test.fail_test(SCons.Platform.virtualenv.IsInVirtualenv(python),
+ message="env.WhereIs('python') points to virtualenv")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/activated/virtualenv_activated_python.py b/test/virtualenv/activated/virtualenv_activated_python.py
new file mode 100644
index 0000000..c673ae1
--- /dev/null
+++ b/test/virtualenv/activated/virtualenv_activated_python.py
@@ -0,0 +1,96 @@
+#!/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__"
+
+"""
+Check which python executable is running scons and which python executable
+would be used by scons, when we run under activated virtualenv (i.e. PATH
+contains the virtualenv's bin path). This test is skipped when ran in regular
+environment or in unactivated virtualenv.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+import os
+import re
+
+test = TestSCons.TestSCons()
+
+if not SCons.Platform.virtualenv.Virtualenv():
+ test.skip_test("No virtualenv detected, skipping\n")
+
+if not SCons.Platform.virtualenv.select_paths_in_venv(os.getenv('PATH')):
+ test.skip_test("Virtualenv detected but looks like unactivated, skipping\n")
+
+
+test.write('SConstruct', """
+import sys
+env = DefaultEnvironment(tools=[])
+print("sys.executable: %s" % repr(sys.executable))
+print("env.WhereIs('python'): %s" % repr(env.WhereIs('python')))
+""")
+
+if SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ test.run(['-Q'])
+else:
+ test.run(['-Q', '--enable-virtualenv'])
+
+s = test.stdout()
+m = re.search(r"""^sys\.executable:\s*(?P<py>["']?[^"']+["']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""\
+can't determine sys.executable from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+interpreter = eval(m.group('py'))
+
+m = re.search(r"""^\s*env\.WhereIs\('python'\):\s*(?P<py>["'][^"']+["'])\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""
+can't determine env.WhereIs('python') from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+python = eval(m.group('py'))
+
+# runing in activated virtualenv (after "activate") - PATH includes virtualenv's bin directory
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(interpreter),
+ message="sys.executable points outside of virtualenv")
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(python),
+ message="env.WhereIs('python') points outside of virtualenv")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/activated/virtualenv_detect_virtualenv.py b/test/virtualenv/activated/virtualenv_detect_virtualenv.py
new file mode 100644
index 0000000..2c00793
--- /dev/null
+++ b/test/virtualenv/activated/virtualenv_detect_virtualenv.py
@@ -0,0 +1,58 @@
+#!/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__"
+
+"""
+Check if SCons.Platform.virtualenv.Virtualenv() works in SConscripts.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+
+test = TestSCons.TestSCons()
+
+ve = SCons.Platform.virtualenv.Virtualenv()
+if not ve:
+ test.skip_test("Virtualenv is not active, skipping\n")
+
+test.write('SConstruct', """
+print("virtualenv: %r" % Virtualenv())
+""")
+
+if SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ test.run(['-Q'])
+else:
+ test.run(['-Q', '--enable-virtualenv'])
+
+test.must_contain_all_lines(test.stdout(), ['virtualenv: %r' % ve])
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/always/virtualenv_global_function.py b/test/virtualenv/always/virtualenv_global_function.py
new file mode 100644
index 0000000..8f2c291
--- /dev/null
+++ b/test/virtualenv/always/virtualenv_global_function.py
@@ -0,0 +1,68 @@
+#!/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__"
+
+"""
+Check which python executable is running scons and which python executable
+would be used by scons, when we run under activated virtualenv (i.e. PATH
+contains the virtualenv's bin path).
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import re
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+print("Virtualenv(): %r" % Virtualenv())
+""")
+
+test.run(['-Q'])
+
+s = test.stdout()
+m = re.search(r"^Virtualenv\(\):\s*(?P<ve>.+\S)\s*$", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""\
+can't determine Virtualenv() result from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+scons_ve = m.group('ve')
+our_ve = "%r" % SCons.Platform.virtualenv.Virtualenv()
+
+# runing in activated virtualenv (after "activate") - PATH includes virtualenv's bin directory
+test.fail_test(scons_ve != our_ve,
+ message="Virtualenv() from SCons != Virtualenv() from caller script (%r != %r)" % (scons_ve, our_ve))
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/regularenv/virtualenv_detect_regularenv.py b/test/virtualenv/regularenv/virtualenv_detect_regularenv.py
new file mode 100644
index 0000000..57a0d4f
--- /dev/null
+++ b/test/virtualenv/regularenv/virtualenv_detect_regularenv.py
@@ -0,0 +1,57 @@
+#!/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__"
+
+"""
+Check if SCons.Platform.virtualenv.Virtualenv() works in SConscript.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+
+test = TestSCons.TestSCons()
+
+if SCons.Platform.virtualenv.Virtualenv():
+ test.skip_test("Virtualenv is active, skipping\n")
+
+test.write('SConstruct', """
+print("virtualenv: %r" % Virtualenv())
+""")
+
+if SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ test.run(['-Q'])
+else:
+ test.run(['-Q', '--enable-virtualenv'])
+
+test.must_contain_all_lines(test.stdout(), ['virtualenv: %r' % None])
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/virtualenv/unactivated/virtualenv_unactivated_python.py b/test/virtualenv/unactivated/virtualenv_unactivated_python.py
new file mode 100644
index 0000000..a4dc240
--- /dev/null
+++ b/test/virtualenv/unactivated/virtualenv_unactivated_python.py
@@ -0,0 +1,95 @@
+#!/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__"
+
+"""
+Check which python executable is running scons and which python executable
+would be used by scons, when we run under an unactivated virtualenv (i.e. PATH
+does not contain virtualenv's bin path). This test is skipped if ran in
+a regular environment or in an activated virtualenv.
+"""
+
+import TestSCons
+import SCons.Platform.virtualenv
+import sys
+import os
+import re
+
+test = TestSCons.TestSCons()
+
+if not SCons.Platform.virtualenv.Virtualenv():
+ test.skip_test("No virtualenv detected, skipping\n")
+
+if SCons.Platform.virtualenv.select_paths_in_venv(os.getenv('PATH')):
+ test.skip_test("Virtualenv detected and it looks like activated, skipping\n")
+
+test.write('SConstruct', """
+import sys
+env = DefaultEnvironment(tools=[])
+print("sys.executable: %s" % repr(sys.executable))
+print("env.WhereIs('python'): %s" % repr(env.WhereIs('python')))
+""")
+
+if SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ test.run(['-Q'])
+else:
+ test.run(['-Q', '--enable-virtualenv'])
+
+s = test.stdout()
+m = re.search(r"""^sys\.executable:\s*(?P<py>["']?[^\"']+["']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""\
+can't determine sys.executable from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+interpreter = eval(m.group('py'))
+
+m = re.search(r"""^\s*env\.WhereIs\('python'\):\s*(?P<py>["']?[^"']+[\"']?)\s*$""", s, re.MULTILINE)
+if not m:
+ test.fail_test(message="""
+can't determine env.WhereIs('python') from stdout:
+========= STDOUT =========
+%s
+==========================
+""" % s)
+
+python = eval(m.group('py'))
+
+# running without activating virtualenv (by just /path/to/virtualenv/bin/python runtest.py ...).
+test.fail_test(not SCons.Platform.virtualenv.IsInVirtualenv(interpreter),
+ message="sys.executable points outside of virtualenv")
+test.fail_test(SCons.Platform.virtualenv.IsInVirtualenv(python),
+ message="env.WhereIs('python') points to virtualenv")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/testing/framework/.TestCommonTests.py.swp b/testing/framework/.TestCommonTests.py.swp
deleted file mode 100644
index fcee08e..0000000
--- a/testing/framework/.TestCommonTests.py.swp
+++ /dev/null
Binary files differ
diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py
index 9499ff4..cccbccb 100644
--- a/testing/framework/TestCmd.py
+++ b/testing/framework/TestCmd.py
@@ -1579,18 +1579,28 @@ class TestCmd(object):
return self._stderr[run]
def stdout(self, run=None):
- """Returns the standard output from the specified run number.
- If there is no specified run number, then returns the standard
- output of the last run. If the run number is less than zero,
- then returns the standard output from that many runs back from
- the current run.
+ """
+ Returns the stored standard output from a given run.
+
+ Args:
+ run: run number to select. If run number is omitted,
+ return the standard output of the most recent run.
+ If negative, use as a relative offset, so that -2
+ means the run two prior to the most recent.
+
+ Returns:
+ selected stdout string or None if there are no
+ stored runs.
"""
if not run:
run = len(self._stdout)
elif run < 0:
run = len(self._stdout) + run
run = run - 1
- return self._stdout[run]
+ try:
+ return self._stdout[run]
+ except IndexError:
+ return None
def subdir(self, *subdirs):
"""Create new subdirectories under the temporary working
@@ -1612,7 +1622,8 @@ class TestCmd(object):
new = os.path.join(self.workdir, sub)
try:
os.mkdir(new)
- except OSError:
+ except OSError as e:
+ print("Got error :%s"%e)
pass
else:
count = count + 1
diff --git a/testing/framework/TestCommon.py b/testing/framework/TestCommon.py
index 6b4b0bd..ca4a147 100644
--- a/testing/framework/TestCommon.py
+++ b/testing/framework/TestCommon.py
@@ -264,11 +264,16 @@ class TestCommon(TestCmd):
if options:
if arguments is None:
return options
+
+ # If not list, then split into lists
+ # this way we're not losing arguments specified with
+ # Spaces in quotes.
if isinstance(options, str):
- options = [options]
+ options = options.split()
if isinstance(arguments, str):
- arguments = [arguments]
- arguments = ' '.join(options + arguments)
+ arguments = arguments.split()
+ arguments = options + arguments
+
return arguments
def must_be_writable(self, *files):
diff --git a/testing/framework/TestSCons.py b/testing/framework/TestSCons.py
index bf6aabb..a874e5a 100644
--- a/testing/framework/TestSCons.py
+++ b/testing/framework/TestSCons.py
@@ -293,16 +293,25 @@ class TestSCons(TestCommon):
def detect(self, var, prog=None, ENV=None, norm=None):
"""
- Detect a program named 'prog' by first checking the construction
- variable named 'var' and finally searching the path used by
- SCons. If either method fails to detect the program, then false
- is returned, otherwise the full path to prog is returned. If
- prog is None, then the value of the environment variable will be
- used as prog.
+ Return the detected path to a tool program.
+
+ Searches first the named construction variable, then
+ the SCons path.
+
+ Args:
+ var: name of construction variable to check for tool name.
+ prog: tool program to check for.
+ ENV: if present, kwargs to initialize an environment that
+ will be created to perform the lookup.
+ norm: if true, normalize any returned path looked up in
+ the environment to use UNIX-style path separators.
+
+ Returns: full path to the tool, or None.
+
"""
env = self.Environment(ENV)
if env:
- v = env.subst('$'+var)
+ v = env.subst('$' + var)
if not v:
return None
if prog is None:
@@ -310,7 +319,7 @@ class TestSCons(TestCommon):
if v != prog:
return None
result = env.WhereIs(prog)
- if norm and os.sep != '/':
+ if result and norm and os.sep != '/':
result = result.replace(os.sep, '/')
return result
@@ -333,7 +342,7 @@ class TestSCons(TestCommon):
return None
return env.Detect([prog])
- def where_is(self, prog, path=None):
+ def where_is(self, prog, path=None, pathext=None):
"""
Given a program, search for it in the specified external PATH,
or in the actual external PATH if none is specified.
@@ -343,26 +352,14 @@ class TestSCons(TestCommon):
if self.external:
if isinstance(prog, str):
prog = [prog]
- import stat
- paths = path.split(os.pathsep)
for p in prog:
- for d in paths:
- f = os.path.join(d, p)
- if os.path.isfile(f):
- try:
- st = os.stat(f)
- except OSError:
- # os.stat() raises OSError, not IOError if the file
- # doesn't exist, so in this case we let IOError get
- # raised so as to not mask possibly serious disk or
- # network issues.
- continue
- if stat.S_IMODE(st[stat.ST_MODE]) & 0o111:
- return os.path.normpath(f)
+ result = TestCmd.where_is(self, p, path, pathext)
+ if result:
+ return os.path.normpath(result)
else:
import SCons.Environment
env = SCons.Environment.Environment()
- return env.WhereIs(prog, path)
+ return env.WhereIs(prog, path, pathext)
return None
@@ -418,6 +415,10 @@ class TestSCons(TestCommon):
# TestCommon.run(self, *args, **kw)
def up_to_date(self, arguments = '.', read_str = "", **kw):
+ """Asserts that all of the targets listed in arguments is
+ up to date, but does not make any assumptions on other targets.
+ This function is most useful in conjunction with the -n option.
+ """
s = ""
for arg in arguments.split():
s = s + "scons: `%s' is up to date.\n" % arg
@@ -853,11 +854,15 @@ class TestSCons(TestCommon):
fmt = "Could not find javac for Java version %s, skipping test(s).\n"
self.skip_test(fmt % version)
else:
- m = re.search(r'javac (\d\.\d)', self.stderr())
+ m = re.search(r'javac (\d\.*\d)', self.stderr())
+ # Java 11 outputs this to stdout
+ if not m:
+ m = re.search(r'javac (\d\.*\d)', self.stdout())
+
if m:
version = m.group(1)
self.javac_is_gcj = False
- elif self.stderr().find('gcj'):
+ elif self.stderr().find('gcj') != -1:
version='1.2'
self.javac_is_gcj = True
else:
@@ -1278,11 +1283,9 @@ SConscript( sconscript )
if sys.platform == 'win32':
self.run(program=python, stdin="""\
import sysconfig, sys, os.path
-try:
- py_ver = 'python%d%d' % sys.version_info[:2]
-except AttributeError:
- py_ver = 'python' + sys.version[:3]
-# print include and lib path
+py_ver = 'python%d%d' % sys.version_info[:2]
+# use distutils to help find include and lib path
+# TODO: PY3 fine to use sysconfig.get_config_var("INCLUDEPY")
try:
import distutils.sysconfig
exec_prefix = distutils.sysconfig.EXEC_PREFIX
@@ -1290,12 +1293,23 @@ try:
print(include)
lib_path = os.path.join(exec_prefix, 'libs')
if not os.path.exists(lib_path):
+ # check for virtualenv path.
+ # this might not build anything different than first try.
+ def venv_path():
+ if hasattr(sys, 'real_prefix'):
+ return sys.real_prefix
+ if hasattr(sys, 'base_prefix'):
+ return sys.base_prefix
+ lib_path = os.path.join(venv_path(), 'libs')
+ if not os.path.exists(lib_path):
+ # not clear this is useful: 'lib' does not contain linkable libs
lib_path = os.path.join(exec_prefix, 'lib')
print(lib_path)
except:
include = os.path.join(sys.prefix, 'include', py_ver)
print(include)
- print(os.path.join(sys.prefix, 'lib', py_ver, 'config'))
+ lib_path = os.path.join(sys.prefix, 'lib', py_ver, 'config')
+ print(lib_path)
print(py_ver)
Python_h = os.path.join(include, "Python.h")
if os.path.exists(Python_h):