summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore8
-rw-r--r--HOWTO/subrelease.txt2
-rw-r--r--QMTest/TestSCons.py18
-rw-r--r--README.rst22
-rw-r--r--doc/SConscript80
-rw-r--r--doc/generated/builders.gen25
-rw-r--r--doc/generated/examples/caching_ex-random_1.xml4
-rw-r--r--doc/generated/examples/commandline_Default4_1.xml1
-rw-r--r--doc/generated/examples/troubleshoot_Dump_1.xml3
-rw-r--r--doc/generated/examples/troubleshoot_Dump_2.xml4
-rw-r--r--doc/generated/examples/troubleshoot_explain1_3.xml2
-rw-r--r--doc/generated/examples/troubleshoot_stacktrace_2.xml6
-rw-r--r--doc/generated/tools.gen21
-rw-r--r--doc/generated/tools.mod4
-rw-r--r--doc/generated/variables.gen343
-rw-r--r--doc/generated/variables.mod80
-rw-r--r--doc/man/scons.xml24
-rw-r--r--doc/python10/main.xml8
-rw-r--r--doc/scons.mod5
-rw-r--r--doc/user/factories.xml18
-rw-r--r--doc/user/main.xml2
-rw-r--r--doc/user/sconf.xml20
-rw-r--r--review.py1835
-rw-r--r--rpm/scons.spec.in4
-rw-r--r--src/Announce.txt25
-rw-r--r--src/CHANGES.txt53
-rw-r--r--src/README.txt6
-rw-r--r--src/RELEASE.txt84
-rw-r--r--src/engine/MANIFEST.in3
-rw-r--r--src/engine/SCons/Action.py3
-rw-r--r--src/engine/SCons/ActionTests.py3
-rw-r--r--src/engine/SCons/Defaults.py41
-rw-r--r--src/engine/SCons/Environment.py46
-rw-r--r--src/engine/SCons/EnvironmentTests.py5
-rw-r--r--src/engine/SCons/Platform/aix.py40
-rw-r--r--src/engine/SCons/Platform/posix.py4
-rw-r--r--src/engine/SCons/SConf.py28
-rw-r--r--src/engine/SCons/Script/Main.py64
-rw-r--r--src/engine/SCons/Script/SConscript.py4
-rw-r--r--src/engine/SCons/Tool/DCommon.py56
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py7
-rw-r--r--src/engine/SCons/Tool/MSCommon/vc.py53
-rw-r--r--src/engine/SCons/Tool/ToolTests.py2
-rw-r--r--src/engine/SCons/Tool/__init__.py14
-rw-r--r--src/engine/SCons/Tool/aixc++.py25
-rw-r--r--src/engine/SCons/Tool/aixcc.py18
-rw-r--r--src/engine/SCons/Tool/aixlink.py14
-rw-r--r--src/engine/SCons/Tool/c++.py5
-rw-r--r--src/engine/SCons/Tool/cc.py7
-rw-r--r--src/engine/SCons/Tool/dmd.py188
-rw-r--r--src/engine/SCons/Tool/dmd.xml33
-rw-r--r--src/engine/SCons/Tool/docbook/__init__.py4
-rw-r--r--src/engine/SCons/Tool/docbook/docs/manual.xml2
-rw-r--r--src/engine/SCons/Tool/g++.py30
-rw-r--r--src/engine/SCons/Tool/gcc.py58
-rw-r--r--src/engine/SCons/Tool/gdc.py128
-rw-r--r--src/engine/SCons/Tool/gdc.xml387
-rw-r--r--src/engine/SCons/Tool/gnulink.py11
-rw-r--r--src/engine/SCons/Tool/intelc.py62
-rw-r--r--src/engine/SCons/Tool/ldc.py141
-rw-r--r--src/engine/SCons/Tool/ldc.xml81
-rw-r--r--src/engine/SCons/Tool/link.py14
-rw-r--r--src/engine/SCons/Tool/link.xml9
-rw-r--r--src/engine/SCons/Tool/packaging/rpm.py2
-rw-r--r--src/engine/SCons/Tool/swig.py3
-rw-r--r--src/engine/SCons/Tool/tex.py18
-rw-r--r--src/engine/SCons/Warnings.py3
-rw-r--r--src/engine/SCons/cpp.py7
-rw-r--r--src/engine/SCons/cppTests.py32
-rw-r--r--test/CC/CC.py7
-rw-r--r--test/CC/CCVERSION.py82
-rw-r--r--test/CPPDEFINES/append.py75
-rw-r--r--test/CXX/CXX.py3
-rw-r--r--test/CXX/CXXVERSION.py81
-rw-r--r--test/Configure/Streamer1.py85
-rw-r--r--test/Copy-Symlinks.py174
-rw-r--r--test/D/CoreScanner/Common/__init__.py0
-rw-r--r--test/D/CoreScanner/Common/common.py99
-rw-r--r--test/D/CoreScanner/Common/sconstest.skip0
-rw-r--r--test/D/CoreScanner/Image/SConstruct_template9
-rw-r--r--test/D/CoreScanner/Image/ignored.d3
-rw-r--r--test/D/CoreScanner/Image/module1.d3
-rw-r--r--test/D/CoreScanner/Image/module2.d3
-rw-r--r--test/D/CoreScanner/Image/module3.di3
-rw-r--r--test/D/CoreScanner/Image/p/ignored.d3
-rw-r--r--test/D/CoreScanner/Image/p/submodule1.d3
-rw-r--r--test/D/CoreScanner/Image/p/submodule2.d3
-rw-r--r--test/D/CoreScanner/Image/test1.d9
-rw-r--r--test/D/CoreScanner/Image/test2.d11
-rw-r--r--test/D/CoreScanner/sconstest-dmd.py37
-rw-r--r--test/D/CoreScanner/sconstest-gdc.py37
-rw-r--r--test/D/CoreScanner/sconstest-ldc.py37
-rw-r--r--test/D/DMD2.py64
-rw-r--r--test/D/DMD2_Alt.py64
-rw-r--r--test/D/GDC.py64
-rw-r--r--test/D/GDC_Alt.py64
-rw-r--r--test/D/HSTeoh/ArLibIssue/SConstruct_template3
-rw-r--r--test/D/HSTeoh/ArLibIssue/a.d0
-rw-r--r--test/D/HSTeoh/ArLibIssue/b.d0
-rw-r--r--test/D/HSTeoh/Common/__init__.py0
-rw-r--r--test/D/HSTeoh/Common/arLibIssue.py63
-rw-r--r--test/D/HSTeoh/Common/libCompileOptions.py63
-rw-r--r--test/D/HSTeoh/Common/linkingProblem.py61
-rw-r--r--test/D/HSTeoh/Common/sconstest.skip0
-rw-r--r--test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py66
-rw-r--r--test/D/HSTeoh/LibCompileOptions/SConstruct_template9
-rw-r--r--test/D/HSTeoh/LibCompileOptions/mylib.d0
-rw-r--r--test/D/HSTeoh/LibCompileOptions/prog.d3
-rw-r--r--test/D/HSTeoh/LinkingProblem/SConstruct_template20
-rw-r--r--test/D/HSTeoh/LinkingProblem/cprog.c7
-rw-r--r--test/D/HSTeoh/LinkingProblem/ncurs_impl.c13
-rw-r--r--test/D/HSTeoh/LinkingProblem/prog.d13
-rw-r--r--test/D/HSTeoh/README.txt1
-rw-r--r--test/D/HSTeoh/SingleStringCannotBeMultipleOptions/SConstruct_template16
-rw-r--r--test/D/HSTeoh/SingleStringCannotBeMultipleOptions/cmod.c5
-rw-r--r--test/D/HSTeoh/SingleStringCannotBeMultipleOptions/mod1.d6
-rw-r--r--test/D/HSTeoh/SingleStringCannotBeMultipleOptions/proj.d13
-rw-r--r--test/D/HSTeoh/sconstest-arLibIssue_dmd.py37
-rw-r--r--test/D/HSTeoh/sconstest-arLibIssue_gdc.py37
-rw-r--r--test/D/HSTeoh/sconstest-arLibIssue_ldc.py38
-rw-r--r--test/D/HSTeoh/sconstest-libCompileOptions_dmd.py37
-rw-r--r--test/D/HSTeoh/sconstest-libCompileOptions_gdc.py37
-rw-r--r--test/D/HSTeoh/sconstest-libCompileOptions_ldc.py38
-rw-r--r--test/D/HSTeoh/sconstest-linkingProblem_dmd.py37
-rw-r--r--test/D/HSTeoh/sconstest-linkingProblem_gdc.py37
-rw-r--r--test/D/HSTeoh/sconstest-linkingProblem_ldc.py38
-rw-r--r--test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_dmd.py37
-rw-r--r--test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py37
-rw-r--r--test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_ldc.py37
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/Common/__init__.py0
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/Common/common.py68
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/Common/sconstest.skip0
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/Image/SConstruct_template9
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/Image/helloWorld.d6
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/sconstest-dmd.py37
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/sconstest-gdc.py37
-rw-r--r--test/D/HelloWorld/CompileAndLinkOneStep/sconstest-ldc.py37
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/Common/__init__.py0
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/Common/common.py68
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/Common/sconstest.skip0
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/Image/SConstruct_template11
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/Image/helloWorld.d6
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-dmd.py37
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-gdc.py37
-rw-r--r--test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-ldc.py37
-rw-r--r--test/D/Issues/2939_Ariovistus/Common/__init__.py0
-rw-r--r--test/D/Issues/2939_Ariovistus/Common/correctLinkOptions.py62
-rw-r--r--test/D/Issues/2939_Ariovistus/Common/sconstest.skip0
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/SConstruct_template9
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/test/test1/SConscript14
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.cpp12
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.h10
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/test/test1/test1.cpp5
-rw-r--r--test/D/Issues/2939_Ariovistus/Project/test/test1/test2.d13
-rw-r--r--test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_dmd.py37
-rw-r--r--test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_gdc.py37
-rw-r--r--test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_ldc.py37
-rw-r--r--test/D/Issues/2940_Ariovistus/Common/__init__.py0
-rw-r--r--test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py62
-rw-r--r--test/D/Issues/2940_Ariovistus/Common/sconstest.skip0
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/SConstruct_template9
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/test/test1/SConscript16
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.cpp12
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.h10
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/test/test1/test1.cpp5
-rw-r--r--test/D/Issues/2940_Ariovistus/Project/test/test1/test2.d13
-rw-r--r--test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_dmd.py37
-rw-r--r--test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_gdc.py37
-rw-r--r--test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_ldc.py37
-rw-r--r--test/D/LDC.py71
-rw-r--r--test/D/LDC_Alt.py71
-rw-r--r--test/D/MixedDAndC/Common/__init__.py0
-rw-r--r--test/D/MixedDAndC/Common/common.py56
-rw-r--r--test/D/MixedDAndC/Common/sconstest.skip0
-rw-r--r--test/D/MixedDAndC/Image/SConstruct13
-rw-r--r--test/D/MixedDAndC/Image/cmod.c3
-rw-r--r--test/D/MixedDAndC/Image/dmod.d6
-rw-r--r--test/D/MixedDAndC/Image/proj.d12
-rw-r--r--test/D/MixedDAndC/sconstest-dmd.py37
-rw-r--r--test/D/MixedDAndC/sconstest-gdc.py37
-rw-r--r--test/D/MixedDAndC/sconstest-ldc.py37
-rwxr-xr-xtest/D/Support/executablesSearch.py67
-rw-r--r--test/D/Support/sconstest.skip0
-rw-r--r--test/Depends/no-Builder.py2
-rw-r--r--test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOM.py2
-rw-r--r--test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOMSTR.py2
-rw-r--r--test/Deprecated/SourceCode/BitKeeper/BitKeeper.py2
-rw-r--r--test/Deprecated/SourceCode/CVS/CVS.py2
-rw-r--r--test/Deprecated/SourceCode/CVS/CVSCOM.py2
-rw-r--r--test/Deprecated/SourceCode/CVS/CVSCOMSTR.py2
-rw-r--r--test/Deprecated/SourceCode/Perforce/P4COM.py2
-rw-r--r--test/Deprecated/SourceCode/Perforce/P4COMSTR.py2
-rw-r--r--test/Deprecated/SourceCode/Perforce/Perforce.py2
-rw-r--r--test/Deprecated/SourceCode/RCS/RCS_COCOM.py2
-rw-r--r--test/Deprecated/SourceCode/RCS/RCS_COCOMSTR.py2
-rw-r--r--test/Deprecated/SourceCode/RCS/changed.py2
-rw-r--r--test/Deprecated/SourceCode/RCS/explicit.py2
-rw-r--r--test/Deprecated/SourceCode/SCCS/SCCSCOM.py2
-rw-r--r--test/Deprecated/SourceCode/SCCS/SCCSCOMSTR.py2
-rw-r--r--test/Deprecated/SourceCode/SCCS/diskcheck.py2
-rw-r--r--test/Deprecated/SourceCode/SourceCode.py2
-rw-r--r--test/Deprecated/SourceCode/Subversion.py2
-rw-r--r--test/ExecuteInvalidateCache.py3
-rw-r--r--test/Fortran/F95FLAGS.py6
-rw-r--r--test/Fortran/SHF95FLAGS.py7
-rw-r--r--test/Fortran/USE-MODULE-CASEINSENS.py3
-rw-r--r--test/Java/DerivedSourceTest.py124
-rw-r--r--test/Java/RMIC.py89
-rw-r--r--test/Libs/SharedLibrary-update-deps.py2
-rw-r--r--test/NoClean.py90
-rw-r--r--test/Repository/RMIC.py21
-rw-r--r--test/SWIG/SWIGFLAGS.py6
-rw-r--r--test/SWIG/SWIGOUTDIR-python.py14
-rw-r--r--test/SWIG/SWIGPATH.py1
-rw-r--r--test/SWIG/build-dir.py12
-rw-r--r--test/SWIG/generated_swigfile.py14
-rw-r--r--test/SWIG/implicit-dependencies.py2
-rw-r--r--test/SWIG/live.py11
-rw-r--r--test/SWIG/module-deduced-name.py8
-rw-r--r--test/SWIG/module-parens.py20
-rw-r--r--test/SWIG/module-quoted.py18
-rw-r--r--test/SWIG/module-spaces.py20
-rw-r--r--test/SWIG/remove-modules.py6
-rw-r--r--test/SWIG/subdir.py11
-rw-r--r--test/Scanner/Dir.py2
-rw-r--r--test/TEX/biblatex_plain.py91
-rw-r--r--test/TEX/synctex.py89
-rw-r--r--test/TEX/variant_dir_newglossary.py109
-rw-r--r--test/VariantDir/include-subdir.py2
-rw-r--r--test/YACC/live.py2
-rw-r--r--test/path-change.py77
-rw-r--r--www/patch-submission.html4
232 files changed, 5901 insertions, 2469 deletions
diff --git a/.hgignore b/.hgignore
index 8e181998..27c728a1 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,3 +8,11 @@ syntax:glob
.git
*~
*.xcodeproj
+*.orig
+
+doc/user/scons-user
+doc/user/scons_db.xml
+doc/user/scons_ex.xml
+doc/user/scons_exi.xml
+doc/user/scons_xi.xml
+doc/user/index.html
diff --git a/HOWTO/subrelease.txt b/HOWTO/subrelease.txt
index ecfaa1f6..06b757a1 100644
--- a/HOWTO/subrelease.txt
+++ b/HOWTO/subrelease.txt
@@ -111,4 +111,4 @@ Things to do to release a new X.Y.Z version of SCons:
- Announce to dev@scons.tigris.org.
+ Announce to scons-dev@scons.org
diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py
index ce20ec53..3fe07c3c 100644
--- a/QMTest/TestSCons.py
+++ b/QMTest/TestSCons.py
@@ -150,7 +150,7 @@ def deprecated_python_version(version=sys.version_info):
if deprecated_python_version():
msg = r"""
scons: warning: Support for pre-2.7.0 Python version (%s) is deprecated.
- If this will cause hardship, contact dev@scons.tigris.org.
+ If this will cause hardship, contact scons-dev@scons.org
"""
deprecated_python_expr = re_escape(msg % python_version_string()) + file_expr
@@ -1129,11 +1129,21 @@ SConscript( sconscript )
self.run(program = python, stdin = """\
import os, sys
try:
- py_ver = 'python%d.%d' % sys.version_info[:2]
+ if sys.platform == 'win32':
+ py_ver = 'python%d%d' % sys.version_info[:2]
+ else:
+ py_ver = 'python%d.%d' % sys.version_info[:2]
except AttributeError:
py_ver = 'python' + sys.version[:3]
-print os.path.join(sys.prefix, 'include', py_ver)
-print os.path.join(sys.prefix, 'lib', py_ver, 'config')
+# print include and lib path
+try:
+ import distutils.sysconfig
+ exec_prefix = distutils.sysconfig.EXEC_PREFIX
+ print distutils.sysconfig.get_python_inc()
+ print os.path.join(exec_prefix, 'libs')
+except:
+ print os.path.join(sys.prefix, 'include', py_ver)
+ print os.path.join(sys.prefix, 'lib', py_ver, 'config')
print py_ver
""")
diff --git a/README.rst b/README.rst
index a1025ca1..35dc980d 100644
--- a/README.rst
+++ b/README.rst
@@ -612,10 +612,6 @@ README-local
Similar to this file, but stripped down and modified for people looking at
including SCons in their shipped software.
-review.py
- Script for uploading changes for review to Rietveld installation at
- http://codereview.appspot.com
-
rpm/
The .spec file for building our RPM packages.
@@ -676,7 +672,7 @@ Submission page:
You can also send mail to the SCons developers' mailing list:
- dev@scons.tigris.org
+ scons-dev@scons.org
But even if you send email to the mailing list please make sure that you ALSO
submit a bug report to the project page bug tracker, because bug reports in
@@ -689,12 +685,11 @@ Mailing Lists
An active mailing list for developers of SCons is available. You may
send questions or comments to the list at:
- dev@scons.tigris.org
+ scons-dev@scons.org
-You may request a subscription to the developer's mailing list by sending
-email to:
+You may subscribe to the developer's mailing list using form on this page:
- dev-subscribe@scons.tigris.org
+ http://two.pairlist.net/mailman/listinfo/scons-dev
Subscription to the developer's mailing list is by approval. In practice, no
one is refused list membership, but we reserve the right to limit membership
@@ -731,9 +726,10 @@ Check the SCons web site at:
Author Info
===========
-Steven Knight, knight at baldmt dot com, http://www.baldmt.com/~knight/
-
-With plenty of help from the SCons Development team:
+SCons was originally written by Steven Knight, knight at baldmt dot com.
+Since around 2010 it has been maintained by the SCons
+development team, co-managed by Bill Deegan and Gary Oberbrunner, with
+many contributors, including but not at all limited to:
- Chad Austin
- Dirk Baechle
@@ -745,6 +741,8 @@ With plenty of help from the SCons Development team:
- Gary Oberbrunner
- Anthony Roach
- Greg Spencer
+- Tom Tanner
+- Anatoly Techtonik
- Christoph Wiedemann
- Russel Winder
diff --git a/doc/SConscript b/doc/SConscript
index 386aec71..d9afc238 100644
--- a/doc/SConscript
+++ b/doc/SConscript
@@ -247,18 +247,32 @@ else:
copy_dbfiles(env, toolpath, [], 'zip.py')
#
- # Each document will live in its own subdirectory. List them here
- # by their subfolder names. Note, how the specifiers for each subdir
- # have nothing to do with which formats get created...but which
- # of the outputs get installed to the build folder and added to
- # the different source and binary packages in the end.
- #
- docs = {'design' : ['chunked','pdf'],
- #'python10' : ['chunked','html','pdf'],
- 'reference' : ['chunked','html','pdf'],
- #'developer' : ['chunked','html','pdf'],
- 'user' : ['chunked','html','pdf','epub','text'],
- 'man' : ['man','epub','text']
+ # Each document will live in its own subdirectory "build/doc/xxx".
+ # List them here by their subfolder names. Note, how the specifiers
+ # for each subdir (=DOCTARGETS) have nothing to do with which
+ # formats get created...but which of the outputs get installed
+ # to the build folder and added to the different source and binary
+ # packages in the end.
+ # In addition to the list of target formats (DOCTARGETS), we also
+ # store some dependency information in this dict. The DOCDEPENDS
+ # list contains all files from each local "MANIFEST", after
+ # installing/copying them to the build directory. It basically
+ # links the original sources to the respective build folder,
+ # such that a simple 'python bootstrap.py' rebuilds the
+ # documentation when a file, like 'doc/user/depends.xml'
+ # for example, changes.
+ # Finally, in DOCNODES we store the created PDF and HTML files,
+ # such that we can then install them in the proper places for
+ # getting picked up by the archiving/packaging stages.
+ DOCTARGETS = 0
+ DOCDEPENDS = 1
+ DOCNODES = 2
+ docs = {'design' : (['chunked','pdf'], [], []),
+ #'python10' : (['chunked','html','pdf'], [], []),
+ 'reference' : (['chunked','html','pdf'], [], []),
+ #'developer' : (['chunked','html','pdf'], [], []),
+ 'user' : (['chunked','html','pdf','epub','text'], [], []),
+ 'man' : (['man','epub','text'], [], [])
}
# The names of the target files for the MAN pages
@@ -307,18 +321,18 @@ else:
else:
target_dir = os.path.join(build, doc)
if ext in ['.fig', '.jpg', '.svg']:
- buildsuite.extend(env.Command(build_s, doc_s,
- Copy("$TARGET", "$SOURCE")))
+ docs[doc][DOCDEPENDS].extend(env.Command(build_s, doc_s,
+ Copy("$TARGET", "$SOURCE")))
else:
- revaction([env.File(build_s)],
- [env.File(doc_s)], env)
+ btarget = env.File(build_s)
+ docs[doc][DOCDEPENDS].append(btarget)
+ revaction([btarget], [env.File(doc_s)], env)
#
# For each document, build the document itself in HTML,
# and PDF formats.
#
- docnodes = {}
for doc in docs:
#
@@ -329,16 +343,16 @@ else:
cleanopt = ' -c'
scdir = os.path.join(build, doc)
sctargets = []
- if 'html' in docs[doc]:
+ if 'html' in docs[doc][DOCTARGETS]:
sctargets.append(env.File(os.path.join(scdir, 'index.html')))
- if 'chunked' in docs[doc]:
+ if 'chunked' in docs[doc][DOCTARGETS]:
sctargets.append(env.File(os.path.join(scdir, 'scons-%s' % doc, 'index.html')))
- if 'pdf' in docs[doc]:
+ if 'pdf' in docs[doc][DOCTARGETS]:
sctargets.append(env.File(os.path.join(scdir, 'scons-%s.pdf' % doc)))
- if 'epub' in docs[doc]:
+ if 'epub' in docs[doc][DOCTARGETS]:
sctargets.append(env.File(os.path.join(scdir, 'scons-%s.epub' % doc)))
- if 'man' in docs[doc]:
+ if 'man' in docs[doc][DOCTARGETS]:
for m in man_page_list:
sctargets.append(os.path.join(scdir, m))
man, _1 = os.path.splitext(m)
@@ -346,8 +360,8 @@ else:
sctargets.append(os.path.join(scdir, 'scons-%s.pdf' % man))
sctargets.append(os.path.join(scdir, 'scons-%s.html' % man))
- docnodes[doc] = env.Command(sctargets, buildsuite,
- "cd %s && $PYTHON ${SCONS_PY.abspath}%s" % (scdir, cleanopt))
+ docs[doc][DOCNODES].extend(env.Command(sctargets, buildsuite + docs[doc][DOCDEPENDS],
+ "cd %s && $PYTHON ${SCONS_PY.abspath}%s" % (scdir, cleanopt)))
install_css = False
for doc in docs:
@@ -359,20 +373,20 @@ else:
pdf = os.path.join(build, 'PDF', 'scons-%s.pdf' % doc)
epub = os.path.join(build, 'EPUB', 'scons-%s.epub' % doc)
text = os.path.join(build, 'TEXT', 'scons-%s.txt' % doc)
- if 'chunked' in docs[doc]:
+ if 'chunked' in docs[doc][DOCTARGETS]:
installed_chtml = env.ChunkedInstall(env.Dir(htmldir),
os.path.join(build, doc,'scons-%s' % doc, 'index.html'))
installed_chtml_css = env.Install(env.Dir(htmldir),
os.path.join(build, doc, 'scons.css'))
- env.Depends(installed_chtml, docnodes[doc])
- env.Depends(installed_chtml_css, docnodes[doc])
+ env.Depends(installed_chtml, docs[doc][DOCNODES])
+ env.Depends(installed_chtml_css, docs[doc][DOCNODES])
tar_deps.extend([htmlindex, installed_chtml_css])
tar_list.extend([htmldir])
Local(htmlindex)
env.Ignore(htmlindex, version_xml)
- if 'html' in docs[doc]:
+ if 'html' in docs[doc][DOCTARGETS]:
env.InstallAs(env.File(html), env.File(os.path.join(build, doc,'index.html')))
tar_deps.extend([html])
tar_list.extend([html])
@@ -380,7 +394,7 @@ else:
env.Ignore(html, version_xml)
install_css = True
- if 'pdf' in docs[doc]:
+ if 'pdf' in docs[doc][DOCTARGETS]:
env.InstallAs(env.File(pdf), env.File(os.path.join(build, doc,'scons-%s.pdf' % doc)))
Local(pdf)
env.Ignore(pdf, version_xml)
@@ -388,7 +402,7 @@ else:
tar_deps.append(pdf)
tar_list.append(pdf)
- if 'epub' in docs[doc] and gs:
+ if 'epub' in docs[doc][DOCTARGETS] and gs:
env.InstallAs(env.File(epub), env.File(os.path.join(build, doc,'scons-%s.epub' % doc)))
Local(epub)
env.Ignore(epub, version_xml)
@@ -396,8 +410,8 @@ else:
tar_deps.append(epub)
tar_list.append(epub)
- if ('text' in docs[doc] and lynx and
- (('html' in docs[doc]) or (doc == 'man'))):
+ if ('text' in docs[doc][DOCTARGETS] and lynx and
+ (('html' in docs[doc][DOCTARGETS]) or (doc == 'man'))):
texthtml = os.path.join(build, doc,'index.html')
if doc == 'man':
# Special handling for single MAN file
@@ -412,7 +426,7 @@ else:
tar_list.append(text)
- if 'man' in docs[doc]:
+ if 'man' in docs[doc][DOCTARGETS]:
#
# Man page(s)
#
diff --git a/doc/generated/builders.gen b/doc/generated/builders.gen
index 76219451..3d534b07 100644
--- a/doc/generated/builders.gen
+++ b/doc/generated/builders.gen
@@ -2137,11 +2137,10 @@ below, for more information.
</term>
<listitem>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
-The <function xmlns="http://www.scons.org/dbxsd/v1.0">Substfile</function> builder generates a single text file
-by concatenating the source files.
-Nested lists of sources are flattened.
-<envar xmlns="http://www.scons.org/dbxsd/v1.0">$LINESEPARATOR</envar> is used to separate the source files;
-see the description of <function xmlns="http://www.scons.org/dbxsd/v1.0">Textfile</function> for details.
+The <function xmlns="http://www.scons.org/dbxsd/v1.0">Substfile</function> builder creates a single text file from another file or set of
+files by concatenating them with <envar xmlns="http://www.scons.org/dbxsd/v1.0">$LINESEPARATOR</envar> and replacing text
+using the <envar xmlns="http://www.scons.org/dbxsd/v1.0">$SUBST_DICT</envar> construction variable. Nested lists of source files
+are flattened. See also <function xmlns="http://www.scons.org/dbxsd/v1.0">Textfile</function>.
</para>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
@@ -2159,20 +2158,18 @@ are automatically added to the target if they are not already present.
<para xmlns="http://www.scons.org/dbxsd/v1.0">
If a construction variable named <envar xmlns="http://www.scons.org/dbxsd/v1.0">$SUBST_DICT</envar> is present,
it may be either a Python dictionary or a sequence of (key,value) tuples.
-If the former,
-the dictionary is converted into a list of tuples in an arbitrary order,
+If it is a dictionary it is converted into a list of tuples in an arbitrary order,
so if one key is a prefix of another key
or if one substitution could be further expanded by another subsitition,
-it is unpredictible whether the expansion will occur.
+it is unpredictable whether the expansion will occur.
</para>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Any occurences in the source of a key
+Any occurrences of a key in the source
are replaced by the corresponding value,
which may be a Python callable function or a string.
-If a value is a function,
-it is first called (with no arguments) to produce a string.
-The string is <emphasis>subst</emphasis>-expanded
+If the value is a callable, it is called with no arguments to get a string.
+Strings are <emphasis>subst</emphasis>-expanded
and the result replaces the key.
</para>
@@ -2278,7 +2275,7 @@ env.Tar('foo')
<para xmlns="http://www.scons.org/dbxsd/v1.0">
The <function xmlns="http://www.scons.org/dbxsd/v1.0">Textfile</function> builder generates a single text file.
The source strings constitute the lines;
-nested lists of sources are flattened.
+nested lists of sources are flattened.
<envar xmlns="http://www.scons.org/dbxsd/v1.0">$LINESEPARATOR</envar> is used to separate the strings.
</para>
@@ -2306,7 +2303,7 @@ env.Textfile(target = 'bar',
LINESEPARATOR='|*')
# nested lists are flattened automatically
-env.Textfile(target = 'blob',
+env.Textfile(target = 'blob',
source = ['lalala', ['Goethe', 42 'Schiller'], 'tanteratei'])
# files may be used as input by wraping them in File()
diff --git a/doc/generated/examples/caching_ex-random_1.xml b/doc/generated/examples/caching_ex-random_1.xml
index cfa55a15..2ed1a8f5 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 f1.o -c f1.c
cc -o f2.o -c f2.c
+cc -o f3.o -c f3.c
cc -o f5.o -c f5.c
cc -o f4.o -c f4.c
-cc -o f3.o -c f3.c
-cc -o f1.o -c f1.c
cc -o prog f1.o f2.o f3.o f4.o f5.o
</screen>
diff --git a/doc/generated/examples/commandline_Default4_1.xml b/doc/generated/examples/commandline_Default4_1.xml
index 61d449ed..35e0b106 100644
--- a/doc/generated/examples/commandline_Default4_1.xml
+++ b/doc/generated/examples/commandline_Default4_1.xml
@@ -1,6 +1,7 @@
<?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>
scons: *** No targets specified and no Default() targets found. Stop.
+Found nothing to build
% <userinput>scons -Q .</userinput>
cc -o prog1.o -c prog1.c
cc -o prog1 prog1.o
diff --git a/doc/generated/examples/troubleshoot_Dump_1.xml b/doc/generated/examples/troubleshoot_Dump_1.xml
index 5b392806..248e85c0 100644
--- a/doc/generated/examples/troubleshoot_Dump_1.xml
+++ b/doc/generated/examples/troubleshoot_Dump_1.xml
@@ -53,7 +53,7 @@ scons: Reading SConscript files ...
'SHLIBSUFFIX': '.so',
'SHOBJPREFIX': '$OBJPREFIX',
'SHOBJSUFFIX': '$OBJSUFFIX',
- 'SPAWN': &lt;function spawnvpe_spawn at 0x700000&amp;gt;,
+ 'SPAWN': &lt;function subprocess_spawn at 0x700000&amp;gt;,
'TARGET_ARCH': None,
'TARGET_OS': None,
'TEMPFILE': &lt;class 'SCons.Platform.TempFileMunge'&gt;,
@@ -63,6 +63,7 @@ scons: Reading SConscript files ...
'_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
+ '__DRPATH': '$_DRPATH',
'__RPATH': '$_RPATH',
'_concat': &lt;function _concat at 0x700000&amp;gt;,
'_defines': &lt;function _defines at 0x700000&amp;gt;,
diff --git a/doc/generated/examples/troubleshoot_Dump_2.xml b/doc/generated/examples/troubleshoot_Dump_2.xml
index a6515b06..17c9de51 100644
--- a/doc/generated/examples/troubleshoot_Dump_2.xml
+++ b/doc/generated/examples/troubleshoot_Dump_2.xml
@@ -86,8 +86,8 @@ scons: Reading SConscript files ...
'SHOBJSUFFIX': '$OBJSUFFIX',
'SPAWN': &lt;function spawn at 0x700000&amp;gt;,
'STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME': 1,
- 'TARGET_ARCH': '',
- 'TARGET_OS': 'win32',
+ 'TARGET_ARCH': None,
+ 'TARGET_OS': None,
'TEMPFILE': &lt;class 'SCons.Platform.TempFileMunge'&gt;,
'TEMPFILEPREFIX': '@',
'TOOLS': ['msvc', 'install', 'install'],
diff --git a/doc/generated/examples/troubleshoot_explain1_3.xml b/doc/generated/examples/troubleshoot_explain1_3.xml
index 0879b114..0bdaace1 100644
--- a/doc/generated/examples/troubleshoot_explain1_3.xml
+++ b/doc/generated/examples/troubleshoot_explain1_3.xml
@@ -1,7 +1,7 @@
<?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 --warn=target-not-built</userinput>
-scons: building `file.out' because it doesn't exist
cp file.in file.oout
scons: warning: Cannot find target file.out after building
+File "/home/garyo/src/scons-scons/bootstrap/src/script/scons.py", line 199, in &lt;module&gt;
</screen>
diff --git a/doc/generated/examples/troubleshoot_stacktrace_2.xml b/doc/generated/examples/troubleshoot_stacktrace_2.xml
index 6286d45c..1ab65ee3 100644
--- a/doc/generated/examples/troubleshoot_stacktrace_2.xml
+++ b/doc/generated/examples/troubleshoot_stacktrace_2.xml
@@ -4,10 +4,10 @@ scons: *** [prog.o] Source `prog.c' not found, needed by target `prog.o'.
scons: internal stack trace:
File "bootstrap/src/engine/SCons/Job.py", line 199, in start
task.prepare()
- File "bootstrap/src/engine/SCons/Script/Main.py", line 168, in prepare
+ File "bootstrap/src/engine/SCons/Script/Main.py", line 173, in prepare
return SCons.Taskmaster.OutOfDateTask.prepare(self)
- File "bootstrap/src/engine/SCons/Taskmaster.py", line 189, in prepare
+ File "bootstrap/src/engine/SCons/Taskmaster.py", line 191, in prepare
executor.prepare()
- File "bootstrap/src/engine/SCons/Executor.py", line 392, in prepare
+ File "bootstrap/src/engine/SCons/Executor.py", line 396, in prepare
raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0]))
</screen>
diff --git a/doc/generated/tools.gen b/doc/generated/tools.gen
index 02349b80..dc9b50da 100644
--- a/doc/generated/tools.gen
+++ b/doc/generated/tools.gen
@@ -142,10 +142,9 @@ for the platform on which SCons is running.
<term>dmd</term>
<listitem>
<para xmlns="http://www.scons.org/dbxsd/v1.0">
-Sets construction variables for D language compilers
-(the Digital Mars D compiler, or GDC).
+Sets construction variables for D language compiler DMD.
</para>
-</listitem>
+<para>Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGS;, &cv-link-DPATH;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-RPATHPREFIX;, &cv-link-RPATHSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;, &cv-link-_DDEBUGFLAGS;, &cv-link-_DFLAGS;, &cv-link-_DINCFLAGS;, &cv-link-_DLIBDIRFLAGS;, &cv-link-_DLIBFLAGS;, &cv-link-_DLIBFLAGS;, &cv-link-_DVERFLAGS;, &cv-link-_RPATH;.</para></listitem>
</varlistentry>
<varlistentry id="t-docbook">
<term>docbook</term>
@@ -375,6 +374,14 @@ Set construction variables for the <application xmlns="http://www.scons.org/dbxs
</para>
<para>Sets: &cv-link-CC;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;.</para></listitem>
</varlistentry>
+ <varlistentry id="t-gdc">
+ <term>gdc</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Sets construction variables for the D language compiler GDC.
+</para>
+<para>Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-RPATHPREFIX;, &cv-link-RPATHSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;, &cv-link-_DDEBUGFLAGS;, &cv-link-_DFLAGS;, &cv-link-_DINCFLAGS;, &cv-link-_DLIBFLAGS;, &cv-link-_DVERFLAGS;, &cv-link-_RPATH;.</para></listitem>
+ </varlistentry>
<varlistentry id="t-gettext">
<term>gettext</term>
<listitem>
@@ -586,6 +593,14 @@ Sets construction variables for the <application xmlns="http://www.scons.org/dbx
</para>
<para>Sets: &cv-link-LATEX;, &cv-link-LATEXCOM;, &cv-link-LATEXFLAGS;.</para><para>Uses: &cv-link-LATEXCOMSTR;.</para></listitem>
</varlistentry>
+ <varlistentry id="t-ldc">
+ <term>ldc</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Sets construction variables for the D language compiler LDC2.
+</para>
+<para>Sets: &cv-link-DC;, &cv-link-DCOM;, &cv-link-DDEBUG;, &cv-link-DDEBUGPREFIX;, &cv-link-DDEBUGSUFFIX;, &cv-link-DFILESUFFIX;, &cv-link-DFLAGPREFIX;, &cv-link-DFLAGS;, &cv-link-DFLAGSUFFIX;, &cv-link-DINCPREFIX;, &cv-link-DINCSUFFIX;, &cv-link-DLIB;, &cv-link-DLIBCOM;, &cv-link-DLIBDIRPREFIX;, &cv-link-DLIBDIRSUFFIX;, &cv-link-DLIBFLAGPREFIX;, &cv-link-DLIBFLAGSUFFIX;, &cv-link-DLIBLINKPREFIX;, &cv-link-DLIBLINKSUFFIX;, &cv-link-DLINK;, &cv-link-DLINKCOM;, &cv-link-DLINKFLAGPREFIX;, &cv-link-DLINKFLAGS;, &cv-link-DLINKFLAGSUFFIX;, &cv-link-DPATH;, &cv-link-DVERPREFIX;, &cv-link-DVERSIONS;, &cv-link-DVERSUFFIX;, &cv-link-RPATHPREFIX;, &cv-link-RPATHSUFFIX;, &cv-link-SHDC;, &cv-link-SHDCOM;, &cv-link-SHDLINK;, &cv-link-SHDLINKCOM;, &cv-link-SHDLINKFLAGS;, &cv-link-_DDEBUGFLAGS;, &cv-link-_DFLAGS;, &cv-link-_DINCFLAGS;, &cv-link-_DLIBDIRFLAGS;, &cv-link-_DLIBFLAGS;, &cv-link-_DLIBFLAGS;, &cv-link-_DVERFLAGS;, &cv-link-_RPATH;.</para></listitem>
+ </varlistentry>
<varlistentry id="t-lex">
<term>lex</term>
<listitem>
diff --git a/doc/generated/tools.mod b/doc/generated/tools.mod
index 0a746b03..3c6f71cf 100644
--- a/doc/generated/tools.mod
+++ b/doc/generated/tools.mod
@@ -37,6 +37,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-g77 "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>g77</literal>">
<!ENTITY t-gas "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gas</literal>">
<!ENTITY t-gcc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gcc</literal>">
+<!ENTITY t-gdc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gdc</literal>">
<!ENTITY t-gettext "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gettext</literal>">
<!ENTITY t-gfortran "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gfortran</literal>">
<!ENTITY t-gnulink "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>gnulink</literal>">
@@ -56,6 +57,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-javac "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>javac</literal>">
<!ENTITY t-javah "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>javah</literal>">
<!ENTITY t-latex "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>latex</literal>">
+<!ENTITY t-ldc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>ldc</literal>">
<!ENTITY t-lex "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>lex</literal>">
<!ENTITY t-link "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>link</literal>">
<!ENTITY t-linkloc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>linkloc</literal>">
@@ -144,6 +146,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-link-g77 "<link linkend='t-g77' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>g77</literal></link>">
<!ENTITY t-link-gas "<link linkend='t-gas' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gas</literal></link>">
<!ENTITY t-link-gcc "<link linkend='t-gcc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gcc</literal></link>">
+<!ENTITY t-link-gdc "<link linkend='t-gdc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gdc</literal></link>">
<!ENTITY t-link-gettext "<link linkend='t-gettext' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gettext</literal></link>">
<!ENTITY t-link-gfortran "<link linkend='t-gfortran' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gfortran</literal></link>">
<!ENTITY t-link-gnulink "<link linkend='t-gnulink' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>gnulink</literal></link>">
@@ -163,6 +166,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-link-javac "<link linkend='t-javac' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>javac</literal></link>">
<!ENTITY t-link-javah "<link linkend='t-javah' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>javah</literal></link>">
<!ENTITY t-link-latex "<link linkend='t-latex' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>latex</literal></link>">
+<!ENTITY t-link-ldc "<link linkend='t-ldc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>ldc</literal></link>">
<!ENTITY t-link-lex "<link linkend='t-lex' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>lex</literal></link>">
<!ENTITY t-link-link "<link linkend='t-link' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>link</literal></link>">
<!ENTITY t-link-linkloc "<link linkend='t-linkloc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>linkloc</literal></link>">
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 832c4a38..d21b417a 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -863,6 +863,54 @@ depending on the specific C++ compiler being used.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-DC">
+ <term>DC</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DC.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DCOM">
+ <term>DCOM</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DCOM.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DDEBUG">
+ <term>DDEBUG</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DDEBUG.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-_DDEBUGFLAGS">
+ <term>_DDEBUGFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DDEBUGFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DDEBUGPREFIX">
+ <term>DDEBUGPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DDEBUGPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DDEBUGSUFFIX">
+ <term>DDEBUGSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DDEBUGSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-DESCRIPTION">
<term>DESCRIPTION</term>
<listitem>
@@ -886,6 +934,70 @@ section of an RPM
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-DFILESUFFIX">
+ <term>DFILESUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DFILESUFFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DFLAGPREFIX">
+ <term>DFLAGPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DFLAGPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DFLAGS">
+ <term>DFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-_DFLAGS">
+ <term>_DFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DFLAGSUFFIX">
+ <term>DFLAGSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DFLAGSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-_DINCFLAGS">
+ <term>_DINCFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DINCFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DINCPREFIX">
+ <term>DINCPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DINCPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DINCSUFFIX">
+ <term>DINCSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DINCSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-Dir">
<term>Dir</term>
<listitem>
@@ -909,6 +1021,126 @@ into a list of Dir instances relative to the target being built.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-DLIB">
+ <term>DLIB</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIB.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBCOM">
+ <term>DLIBCOM</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBCOM.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-_DLIBDIRFLAGS">
+ <term>_DLIBDIRFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DLIBDIRFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBDIRPREFIX">
+ <term>DLIBDIRPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBDIRPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBDIRSUFFIX">
+ <term>DLIBDIRSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBDIRSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBFLAGPREFIX">
+ <term>DLIBFLAGPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBFLAGPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-_DLIBFLAGS">
+ <term>_DLIBFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DLIBFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBFLAGSUFFIX">
+ <term>DLIBFLAGSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBFLAGSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBLINKPREFIX">
+ <term>DLIBLINKPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBLINKPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLIBLINKSUFFIX">
+ <term>DLIBLINKSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLIBLINKSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLINK">
+ <term>DLINK</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLINK.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLINKCOM">
+ <term>DLINKCOM</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLINKCOM.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLINKFLAGPREFIX">
+ <term>DLINKFLAGPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLINKFLAGPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLINKFLAGS">
+ <term>DLINKFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLINKFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DLINKFLAGSUFFIX">
+ <term>DLINKFLAGSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DLINKFLAGSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-DOCBOOK_DEFAULT_XSL_EPUB">
<term>DOCBOOK_DEFAULT_XSL_EPUB</term>
<listitem>
@@ -1106,6 +1338,14 @@ for <literal>saxon</literal> and <literal>saxon-xslt</literal>, respectively.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-DPATH">
+ <term>DPATH</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DPATH.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-DSUFFIXES">
<term>DSUFFIXES</term>
<listitem>
@@ -1120,6 +1360,38 @@ The default list is:
</example_commands>
</listitem>
</varlistentry>
+ <varlistentry id="cv-_DVERFLAGS">
+ <term>_DVERFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+_DVERFLAGS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DVERPREFIX">
+ <term>DVERPREFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DVERPREFIX.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DVERSIONS">
+ <term>DVERSIONS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DVERSIONS.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-DVERSUFFIX">
+ <term>DVERSUFFIX</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+DVERSUFFIX.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-DVIPDF">
<term>DVIPDF</term>
<listitem>
@@ -3680,9 +3952,28 @@ If <envar xmlns="http://www.scons.org/dbxsd/v1.0">$MSVC_VERSION</envar> is not s
latest version of Visual C/C++ installed on your system. If the
specified version isn't installed, tool initialization will fail.
This variable must be passed as an argument to the Environment()
-constructor; setting it later has no effect. Set it to an unexpected
-value (e.g. "XXX") to see the valid values on your system.
+constructor; setting it later has no effect.
+</para>
+
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Valid values for Windows are
+<literal>12.0</literal>,
+<literal>12.0Exp</literal>,
+<literal>11.0</literal>,
+<literal>11.0Exp</literal>,
+<literal>10.0</literal>,
+<literal>10.0Exp</literal>,
+<literal>9.0</literal>,
+<literal>9.0Exp</literal>,
+<literal>8.0</literal>,
+<literal>8.0Exp</literal>,
+<literal>7.1</literal>,
+<literal>7.0</literal>,
+and <literal>6.0</literal>.
+Versions ending in <literal>Exp</literal> refer to "Express" or
+"Express for Desktop" editions.
</para>
+
</listitem>
</varlistentry>
<varlistentry id="cv-MSVS">
@@ -5489,6 +5780,46 @@ to generate shared-library objects.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-SHDC">
+ <term>SHDC</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+SHDC.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-SHDCOM">
+ <term>SHDCOM</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+SHDCOM.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-SHDLINK">
+ <term>SHDLINK</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+SHDLINK.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-SHDLINKCOM">
+ <term>SHDLINKCOM</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+SHDLINKCOM.
+</para>
+</listitem>
+ </varlistentry>
+ <varlistentry id="cv-SHDLINKFLAGS">
+ <term>SHDLINKFLAGS</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+SHDLINKFLAGS.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="cv-SHELL">
<term>SHELL</term>
<listitem>
@@ -6061,6 +6392,14 @@ in which the command should be executed.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME">
+ <term>STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME</term>
+ <listitem>
+ <para xmlns="http://www.scons.org/dbxsd/v1.0">
+ When this variable is true, static objects and shared objects are assumed to be the same; that is, SCons does not check for linking static objects into a shared library.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="cv-SUBST_DICT">
<term>SUBST_DICT</term>
<listitem>
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index b55b2188..0a59605a 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -66,10 +66,39 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-CXXFILESUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$CXXFILESUFFIX</envar>">
<!ENTITY cv-CXXFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$CXXFLAGS</envar>">
<!ENTITY cv-CXXVERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$CXXVERSION</envar>">
+<!ENTITY cv-DC "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DC</envar>">
+<!ENTITY cv-DCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DCOM</envar>">
+<!ENTITY cv-DDEBUG "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUG</envar>">
+<!ENTITY cv-_DDEBUGFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DDEBUGFLAGS</envar>">
+<!ENTITY cv-DDEBUGPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUGPREFIX</envar>">
+<!ENTITY cv-DDEBUGSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DDEBUGSUFFIX</envar>">
<!ENTITY cv-DESCRIPTION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DESCRIPTION</envar>">
<!ENTITY cv-DESCRIPTION_lang "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DESCRIPTION_lang</envar>">
+<!ENTITY cv-DFILESUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DFILESUFFIX</envar>">
+<!ENTITY cv-DFLAGPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DFLAGPREFIX</envar>">
+<!ENTITY cv-DFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DFLAGS</envar>">
+<!ENTITY cv-_DFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DFLAGS</envar>">
+<!ENTITY cv-DFLAGSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DFLAGSUFFIX</envar>">
+<!ENTITY cv-_DINCFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DINCFLAGS</envar>">
+<!ENTITY cv-DINCPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DINCPREFIX</envar>">
+<!ENTITY cv-DINCSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DINCSUFFIX</envar>">
<!ENTITY cv-Dir "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$Dir</envar>">
<!ENTITY cv-Dirs "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$Dirs</envar>">
+<!ENTITY cv-DLIB "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIB</envar>">
+<!ENTITY cv-DLIBCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBCOM</envar>">
+<!ENTITY cv-_DLIBDIRFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DLIBDIRFLAGS</envar>">
+<!ENTITY cv-DLIBDIRPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBDIRPREFIX</envar>">
+<!ENTITY cv-DLIBDIRSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBDIRSUFFIX</envar>">
+<!ENTITY cv-DLIBFLAGPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBFLAGPREFIX</envar>">
+<!ENTITY cv-_DLIBFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DLIBFLAGS</envar>">
+<!ENTITY cv-DLIBFLAGSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBFLAGSUFFIX</envar>">
+<!ENTITY cv-DLIBLINKPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBLINKPREFIX</envar>">
+<!ENTITY cv-DLIBLINKSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLIBLINKSUFFIX</envar>">
+<!ENTITY cv-DLINK "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLINK</envar>">
+<!ENTITY cv-DLINKCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLINKCOM</envar>">
+<!ENTITY cv-DLINKFLAGPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLINKFLAGPREFIX</envar>">
+<!ENTITY cv-DLINKFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLINKFLAGS</envar>">
+<!ENTITY cv-DLINKFLAGSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DLINKFLAGSUFFIX</envar>">
<!ENTITY cv-DOCBOOK_DEFAULT_XSL_EPUB "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_DEFAULT_XSL_EPUB</envar>">
<!ENTITY cv-DOCBOOK_DEFAULT_XSL_HTML "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_DEFAULT_XSL_HTML</envar>">
<!ENTITY cv-DOCBOOK_DEFAULT_XSL_HTMLCHUNKED "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED</envar>">
@@ -91,7 +120,12 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-DOCBOOK_XSLTPROCCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_XSLTPROCCOMSTR</envar>">
<!ENTITY cv-DOCBOOK_XSLTPROCFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_XSLTPROCFLAGS</envar>">
<!ENTITY cv-DOCBOOK_XSLTPROCPARAMS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DOCBOOK_XSLTPROCPARAMS</envar>">
+<!ENTITY cv-DPATH "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DPATH</envar>">
<!ENTITY cv-DSUFFIXES "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DSUFFIXES</envar>">
+<!ENTITY cv-_DVERFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$_DVERFLAGS</envar>">
+<!ENTITY cv-DVERPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVERPREFIX</envar>">
+<!ENTITY cv-DVERSIONS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVERSIONS</envar>">
+<!ENTITY cv-DVERSUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVERSUFFIX</envar>">
<!ENTITY cv-DVIPDF "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVIPDF</envar>">
<!ENTITY cv-DVIPDFCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVIPDFCOM</envar>">
<!ENTITY cv-DVIPDFCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$DVIPDFCOMSTR</envar>">
@@ -418,6 +452,11 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-SHCXXCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHCXXCOM</envar>">
<!ENTITY cv-SHCXXCOMSTR "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHCXXCOMSTR</envar>">
<!ENTITY cv-SHCXXFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHCXXFLAGS</envar>">
+<!ENTITY cv-SHDC "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDC</envar>">
+<!ENTITY cv-SHDCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDCOM</envar>">
+<!ENTITY cv-SHDLINK "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLINK</envar>">
+<!ENTITY cv-SHDLINKCOM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLINKCOM</envar>">
+<!ENTITY cv-SHDLINKFLAGS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHDLINKFLAGS</envar>">
<!ENTITY cv-SHELL "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHELL</envar>">
<!ENTITY cv-SHF03 "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHF03</envar>">
<!ENTITY cv-SHF03COM "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SHF03COM</envar>">
@@ -463,6 +502,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-SOURCE_URL "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SOURCE_URL</envar>">
<!ENTITY cv-SOURCES "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SOURCES</envar>">
<!ENTITY cv-SPAWN "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SPAWN</envar>">
+<!ENTITY cv-STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME</envar>">
<!ENTITY cv-SUBST_DICT "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SUBST_DICT</envar>">
<!ENTITY cv-SUBSTFILEPREFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SUBSTFILEPREFIX</envar>">
<!ENTITY cv-SUBSTFILESUFFIX "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$SUBSTFILESUFFIX</envar>">
@@ -648,10 +688,39 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-CXXFILESUFFIX "<link linkend='cv-CXXFILESUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$CXXFILESUFFIX</envar></link>">
<!ENTITY cv-link-CXXFLAGS "<link linkend='cv-CXXFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$CXXFLAGS</envar></link>">
<!ENTITY cv-link-CXXVERSION "<link linkend='cv-CXXVERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$CXXVERSION</envar></link>">
+<!ENTITY cv-link-DC "<link linkend='cv-DC' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DC</envar></link>">
+<!ENTITY cv-link-DCOM "<link linkend='cv-DCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DCOM</envar></link>">
+<!ENTITY cv-link-DDEBUG "<link linkend='cv-DDEBUG' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUG</envar></link>">
+<!ENTITY cv-link-_DDEBUGFLAGS "<link linkend='cv-_DDEBUGFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DDEBUGFLAGS</envar></link>">
+<!ENTITY cv-link-DDEBUGPREFIX "<link linkend='cv-DDEBUGPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUGPREFIX</envar></link>">
+<!ENTITY cv-link-DDEBUGSUFFIX "<link linkend='cv-DDEBUGSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DDEBUGSUFFIX</envar></link>">
<!ENTITY cv-link-DESCRIPTION "<link linkend='cv-DESCRIPTION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DESCRIPTION</envar></link>">
<!ENTITY cv-link-DESCRIPTION_lang "<link linkend='cv-DESCRIPTION_lang' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DESCRIPTION_lang</envar></link>">
+<!ENTITY cv-link-DFILESUFFIX "<link linkend='cv-DFILESUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DFILESUFFIX</envar></link>">
+<!ENTITY cv-link-DFLAGPREFIX "<link linkend='cv-DFLAGPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DFLAGPREFIX</envar></link>">
+<!ENTITY cv-link-DFLAGS "<link linkend='cv-DFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DFLAGS</envar></link>">
+<!ENTITY cv-link-_DFLAGS "<link linkend='cv-_DFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DFLAGS</envar></link>">
+<!ENTITY cv-link-DFLAGSUFFIX "<link linkend='cv-DFLAGSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DFLAGSUFFIX</envar></link>">
+<!ENTITY cv-link-_DINCFLAGS "<link linkend='cv-_DINCFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DINCFLAGS</envar></link>">
+<!ENTITY cv-link-DINCPREFIX "<link linkend='cv-DINCPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DINCPREFIX</envar></link>">
+<!ENTITY cv-link-DINCSUFFIX "<link linkend='cv-DINCSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DINCSUFFIX</envar></link>">
<!ENTITY cv-link-Dir "<link linkend='cv-Dir' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$Dir</envar></link>">
<!ENTITY cv-link-Dirs "<link linkend='cv-Dirs' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$Dirs</envar></link>">
+<!ENTITY cv-link-DLIB "<link linkend='cv-DLIB' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIB</envar></link>">
+<!ENTITY cv-link-DLIBCOM "<link linkend='cv-DLIBCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBCOM</envar></link>">
+<!ENTITY cv-link-_DLIBDIRFLAGS "<link linkend='cv-_DLIBDIRFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DLIBDIRFLAGS</envar></link>">
+<!ENTITY cv-link-DLIBDIRPREFIX "<link linkend='cv-DLIBDIRPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBDIRPREFIX</envar></link>">
+<!ENTITY cv-link-DLIBDIRSUFFIX "<link linkend='cv-DLIBDIRSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBDIRSUFFIX</envar></link>">
+<!ENTITY cv-link-DLIBFLAGPREFIX "<link linkend='cv-DLIBFLAGPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBFLAGPREFIX</envar></link>">
+<!ENTITY cv-link-_DLIBFLAGS "<link linkend='cv-_DLIBFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DLIBFLAGS</envar></link>">
+<!ENTITY cv-link-DLIBFLAGSUFFIX "<link linkend='cv-DLIBFLAGSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBFLAGSUFFIX</envar></link>">
+<!ENTITY cv-link-DLIBLINKPREFIX "<link linkend='cv-DLIBLINKPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBLINKPREFIX</envar></link>">
+<!ENTITY cv-link-DLIBLINKSUFFIX "<link linkend='cv-DLIBLINKSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLIBLINKSUFFIX</envar></link>">
+<!ENTITY cv-link-DLINK "<link linkend='cv-DLINK' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLINK</envar></link>">
+<!ENTITY cv-link-DLINKCOM "<link linkend='cv-DLINKCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLINKCOM</envar></link>">
+<!ENTITY cv-link-DLINKFLAGPREFIX "<link linkend='cv-DLINKFLAGPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLINKFLAGPREFIX</envar></link>">
+<!ENTITY cv-link-DLINKFLAGS "<link linkend='cv-DLINKFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLINKFLAGS</envar></link>">
+<!ENTITY cv-link-DLINKFLAGSUFFIX "<link linkend='cv-DLINKFLAGSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DLINKFLAGSUFFIX</envar></link>">
<!ENTITY cv-link-DOCBOOK_DEFAULT_XSL_EPUB "<link linkend='cv-DOCBOOK_DEFAULT_XSL_EPUB' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_DEFAULT_XSL_EPUB</envar></link>">
<!ENTITY cv-link-DOCBOOK_DEFAULT_XSL_HTML "<link linkend='cv-DOCBOOK_DEFAULT_XSL_HTML' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_DEFAULT_XSL_HTML</envar></link>">
<!ENTITY cv-link-DOCBOOK_DEFAULT_XSL_HTMLCHUNKED "<link linkend='cv-DOCBOOK_DEFAULT_XSL_HTMLCHUNKED' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED</envar></link>">
@@ -673,7 +742,12 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-DOCBOOK_XSLTPROCCOMSTR "<link linkend='cv-DOCBOOK_XSLTPROCCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_XSLTPROCCOMSTR</envar></link>">
<!ENTITY cv-link-DOCBOOK_XSLTPROCFLAGS "<link linkend='cv-DOCBOOK_XSLTPROCFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_XSLTPROCFLAGS</envar></link>">
<!ENTITY cv-link-DOCBOOK_XSLTPROCPARAMS "<link linkend='cv-DOCBOOK_XSLTPROCPARAMS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DOCBOOK_XSLTPROCPARAMS</envar></link>">
+<!ENTITY cv-link-DPATH "<link linkend='cv-DPATH' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DPATH</envar></link>">
<!ENTITY cv-link-DSUFFIXES "<link linkend='cv-DSUFFIXES' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DSUFFIXES</envar></link>">
+<!ENTITY cv-link-_DVERFLAGS "<link linkend='cv-_DVERFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$_DVERFLAGS</envar></link>">
+<!ENTITY cv-link-DVERPREFIX "<link linkend='cv-DVERPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVERPREFIX</envar></link>">
+<!ENTITY cv-link-DVERSIONS "<link linkend='cv-DVERSIONS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVERSIONS</envar></link>">
+<!ENTITY cv-link-DVERSUFFIX "<link linkend='cv-DVERSUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVERSUFFIX</envar></link>">
<!ENTITY cv-link-DVIPDF "<link linkend='cv-DVIPDF' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVIPDF</envar></link>">
<!ENTITY cv-link-DVIPDFCOM "<link linkend='cv-DVIPDFCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVIPDFCOM</envar></link>">
<!ENTITY cv-link-DVIPDFCOMSTR "<link linkend='cv-DVIPDFCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$DVIPDFCOMSTR</envar></link>">
@@ -1000,6 +1074,11 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-SHCXXCOM "<link linkend='cv-SHCXXCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHCXXCOM</envar></link>">
<!ENTITY cv-link-SHCXXCOMSTR "<link linkend='cv-SHCXXCOMSTR' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHCXXCOMSTR</envar></link>">
<!ENTITY cv-link-SHCXXFLAGS "<link linkend='cv-SHCXXFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHCXXFLAGS</envar></link>">
+<!ENTITY cv-link-SHDC "<link linkend='cv-SHDC' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDC</envar></link>">
+<!ENTITY cv-link-SHDCOM "<link linkend='cv-SHDCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDCOM</envar></link>">
+<!ENTITY cv-link-SHDLINK "<link linkend='cv-SHDLINK' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLINK</envar></link>">
+<!ENTITY cv-link-SHDLINKCOM "<link linkend='cv-SHDLINKCOM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLINKCOM</envar></link>">
+<!ENTITY cv-link-SHDLINKFLAGS "<link linkend='cv-SHDLINKFLAGS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHDLINKFLAGS</envar></link>">
<!ENTITY cv-link-SHELL "<link linkend='cv-SHELL' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHELL</envar></link>">
<!ENTITY cv-link-SHF03 "<link linkend='cv-SHF03' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHF03</envar></link>">
<!ENTITY cv-link-SHF03COM "<link linkend='cv-SHF03COM' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SHF03COM</envar></link>">
@@ -1045,6 +1124,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-SOURCE_URL "<link linkend='cv-SOURCE_URL' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SOURCE_URL</envar></link>">
<!ENTITY cv-link-SOURCES "<link linkend='cv-SOURCES' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SOURCES</envar></link>">
<!ENTITY cv-link-SPAWN "<link linkend='cv-SPAWN' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SPAWN</envar></link>">
+<!ENTITY cv-link-STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME "<link linkend='cv-STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME</envar></link>">
<!ENTITY cv-link-SUBST_DICT "<link linkend='cv-SUBST_DICT' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SUBST_DICT</envar></link>">
<!ENTITY cv-link-SUBSTFILEPREFIX "<link linkend='cv-SUBSTFILEPREFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SUBSTFILEPREFIX</envar></link>">
<!ENTITY cv-link-SUBSTFILESUFFIX "<link linkend='cv-SUBSTFILESUFFIX' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$SUBSTFILESUFFIX</envar></link>">
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index d726796e..8d52c1e6 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -52,19 +52,19 @@
<surname>Knight</surname>
</author>
- <corpauthor>Steven Knight</corpauthor>
+ <corpauthor>Steven Knight and the SCons Development Team</corpauthor>
- <pubdate>2004, 2005, 2006, 2007, 2008, 2009, 2010</pubdate>
+ <pubdate>2004 - 2014</pubdate>
<copyright>
- <year>2004, 2005, 2006, 2007, 2008, 2009, 2010</year>
- <holder>Steven Knight</holder>
+ <year>2004 - 2014</year>
+ <holder>The SCons Foundation</holder>
</copyright>
<releaseinfo>version &buildversion;</releaseinfo>
-
+
<mediaobject role="cover"><imageobject><imagedata fileref="cover.jpg" format="JPG"/></imageobject></mediaobject>
-
+
</referenceinfo>
<title>SCons &buildversion;</title>
@@ -4936,7 +4936,7 @@ multi-stage builder.</para>
<term>single_source</term>
<listitem>
<para>Specifies that this builder expects exactly one source file per call. Giving
-more than one source file without target files results in implicitely calling
+more than one source file without target files results in implicitly calling
the builder multiple times (once for each source given). Giving multiple
source files together with target files results in a UserError exception.</para>
@@ -5118,7 +5118,7 @@ function will turn its
<emphasis role="bold">action</emphasis>
keyword argument into an appropriate
internal Action object.
-You can also explicity create Action objects
+You can also explicitly create Action objects
using the
<emphasis role="bold">Action</emphasis>()
global function,
@@ -6125,7 +6125,7 @@ So in the following case:</para>
<literallayout class="monospaced">
env['COND'] = 0
env.Command('foo.out', 'foo.in',
-<!-- '''echo ${COND==1 and 'FOO' or 'BAR'} &gt; $TARGET''') -->
+ '''echo ${COND==1 and 'FOO' or 'BAR'} &gt; $TARGET''')
</literallayout>
<para>the command executed will be either</para>
<literallayout class="monospaced">
@@ -7095,9 +7095,9 @@ source code.</para>
</refsect1>
<refsect1 id='authors'><title>AUTHORS</title>
-<para>Steven Knight &lt;knight@baldmt.com&gt;
-<!-- .br -->
-Anthony Roach &lt;aroach@electriceyeball.com&gt;</para>
+<para>Originally: Steven Knight &lt;knight@baldmt.com&gt; and Anthony Roach &lt;aroach@electriceyeball.com&gt;
+Since 2010: The SCons Development Team &lt;scons-dev@scons.org&gt;
+</para>
</refsect1>
</refentry>
</reference>
diff --git a/doc/python10/main.xml b/doc/python10/main.xml
index 60938527..a7732dab 100644
--- a/doc/python10/main.xml
+++ b/doc/python10/main.xml
@@ -10,7 +10,7 @@
<article 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">
-
+
<!--
__COPYRIGHT__
@@ -35,7 +35,7 @@
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
-
+
<articleinfo>
<title>SCons Design and Implementation</title>
@@ -46,8 +46,8 @@
<copyright>
<year>2001</year>
- <year>2002</year>
- <holder>Steven Knight</holder>
+ <year>2014</year>
+ <holder>The SCons Foundation</holder>
</copyright>
<pubdate>2002</pubdate>
diff --git a/doc/scons.mod b/doc/scons.mod
index 01e9a6da..72dc7ff2 100644
--- a/doc/scons.mod
+++ b/doc/scons.mod
@@ -277,6 +277,7 @@
<!ENTITY CheckLib "<function xmlns='http://www.scons.org/dbxsd/v1.0'>CheckLib</function>">
<!ENTITY CheckLibWithHeader "<function xmlns='http://www.scons.org/dbxsd/v1.0'>CheckLibWithHeader</function>">
<!ENTITY CheckType "<function xmlns='http://www.scons.org/dbxsd/v1.0'>CheckType</function>">
+<!ENTITY CheckTypeSize "<function xmlns='http://www.scons.org/dbxsd/v1.0'>CheckTypeSize</function>">
<!ENTITY TryAction "<function xmlns='http://www.scons.org/dbxsd/v1.0'>TryAction</function>">
<!ENTITY TryBuild "<function xmlns='http://www.scons.org/dbxsd/v1.0'>TryBuild</function>">
<!ENTITY TryCompile "<function xmlns='http://www.scons.org/dbxsd/v1.0'>TryCompile</function>">
@@ -525,8 +526,8 @@
-->
<!ENTITY scons-announce "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>announce@scons.tigris.org</literal>">
-<!ENTITY scons-devel "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>dev@scons.tigris.org</literal>">
-<!ENTITY scons-users "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>users@scons.tigris.org</literal>">
+<!ENTITY scons-devel "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>scons-dev@scons.org</literal>">
+<!ENTITY scons-users "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>scons-users@scons.org</literal>">
<!--
diff --git a/doc/user/factories.xml b/doc/user/factories.xml
index 08f20e6d..c8480dba 100644
--- a/doc/user/factories.xml
+++ b/doc/user/factories.xml
@@ -176,6 +176,24 @@ touch $*
<scons_output_command>scons -Q</scons_output_command>
</scons_output>
+ <para>
+ The &Copy; factory has a third optional argument which controls
+ how symlinks are copied.
+ </para>
+
+ <para>
+ </para>
+
+ <scons_example name="factories_SymlinkCopy">
+ <file name ="SymlinkCopy" printme="1">
+# Symbolic link shallow copied as a new symbolic link:
+Command("LinkIn", "LinkOut", Copy("$TARGET", "$SOURCE"[, True]))
+
+# Symbolic link target copied as a file or directory:
+Command("LinkIn", "FileOrDirectoryOut", Copy("$TARGET", "$SOURCE", False))
+ </file>
+ </scons_example>
+
</section>
<section>
diff --git a/doc/user/main.xml b/doc/user/main.xml
index ae515fa3..a1657776 100644
--- a/doc/user/main.xml
+++ b/doc/user/main.xml
@@ -72,7 +72,7 @@
<surname>Knight</surname>
</author>
- <corpauthor>Steven Knight</corpauthor>
+ <corpauthor>Steven Knight and the SCons Development Team</corpauthor>
<pubdate>2004 - 2014</pubdate>
diff --git a/doc/user/sconf.xml b/doc/user/sconf.xml
index ff39b6b4..214569db 100644
--- a/doc/user/sconf.xml
+++ b/doc/user/sconf.xml
@@ -282,6 +282,26 @@ env = conf.Finish()
</sconstruct>
</section>
+ <section>
+ <title>Checking the size of a datatype</title>
+ <para>
+ Check the size of a datatype by using the &CheckTypeSize; method:
+ </para>
+
+ <sconstruct>
+env = Environment()
+conf = Configure(env)
+int_size = conf.CheckTypeSize('unsigned int')
+print 'sizeof unsigned int is', int_size
+env = conf.Finish()
+ </sconstruct>
+
+ <screen>
+% <userinput>scons -Q</userinput>
+sizeof unsigned int is 4
+scons: `.' is up to date.
+ </screen>
+ </section>
<section>
<title>Adding Your Own Custom Checks</title>
diff --git a/review.py b/review.py
deleted file mode 100644
index a796b2f5..00000000
--- a/review.py
+++ /dev/null
@@ -1,1835 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2007 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from __future__ import print_function
-
-from SCons.compat.six import PY3
-
-"""Tool for uploading diffs from a version control system to the codereview app.
-
-Usage summary: upload.py [options] [-- diff_options] [path...]
-
-Diff options are passed to the diff command of the underlying system.
-
-Supported version control systems:
- Git
- Mercurial
- Subversion
-
-It is important for Git/Mercurial users to specify a tree/node/branch to diff
-against by using the '--rev' option.
-"""
-# This code is derived from appcfg.py in the App Engine SDK (open source),
-# and from ASPN recipe #146306.
-
-if PY3:
- from configparser import ConfigParser
-else:
- from ConfigParser import ConfigParser
-if PY3:
- from http.cookiejar import (
- CookieJar, MozillaCookieJar, LoadError as CookieLoadError)
-else:
- from cookielib import (
- CookieJar, MozillaCookieJar, LoadError as CookieLoadError)
-import fnmatch
-import getpass
-import logging
-import mimetypes
-import optparse
-import os
-import re
-import socket
-import subprocess
-import sys
-if PY3:
- from urllib.request import (
- Request, OpenerDirector,
- ProxyHandler, UnknownHandler, HTTPHandler, HTTPSHandler,
- HTTPDefaultErrorHandler, HTTPErrorProcessor,
- HTTPCookieProcessor)
- from urllib.error import HTTPError
- from urllib.parse import (
- urlencode, urlparse, urlunparse, splituser as urlsplituser)
-else:
- from urllib2 import (
- Request, OpenerDirector,
- ProxyHandler, UnknownHandler, HTTPHandler, HTTPSHandler,
- HTTPDefaultErrorHandler, HTTPErrorProcessor, HTTPError,
- HTTPCookieProcessor,
- urlparse)
- from urllib import urlencode, splituser as urlsplituser
- from urlparse import urlparse, urlunparse
-import urllib.request, urllib.parse, urllib.error
-import urllib.request, urllib.error, urllib.parse
-import urllib.parse
-
-# The md5 module was deprecated in Python 2.5.
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
-try:
- import readline
-except ImportError:
- pass
-
-try:
- import keyring
-except ImportError:
- keyring = None
-
-# The logging verbosity:
-# 0: Errors only.
-# 1: Status messages.
-# 2: Info logs.
-# 3: Debug logs.
-verbosity = 1
-
-# The account type used for authentication.
-# This line could be changed by the review server (see handler for
-# upload.py).
-AUTH_ACCOUNT_TYPE = "GOOGLE"
-
-# URL of the default review server. As for AUTH_ACCOUNT_TYPE, this line could be
-# changed by the review server (see handler for upload.py).
-DEFAULT_REVIEW_SERVER = "codereview.appspot.com"
-
-# Max size of patch or base file.
-MAX_UPLOAD_SIZE = 900 * 1024
-
-# Constants for version control names. Used by GuessVCSName.
-VCS_GIT = "Git"
-VCS_MERCURIAL = "Mercurial"
-VCS_SUBVERSION = "Subversion"
-VCS_UNKNOWN = "Unknown"
-
-# whitelist for non-binary filetypes which do not start with "text/"
-# .mm (Objective-C) shows up as application/x-freemind on my Linux box.
-TEXT_MIMETYPES = ['application/javascript', 'application/x-javascript',
- 'application/xml', 'application/x-freemind',
- 'application/x-sh']
-
-VCS_ABBREVIATIONS = {
- VCS_MERCURIAL.lower(): VCS_MERCURIAL,
- "hg": VCS_MERCURIAL,
- VCS_SUBVERSION.lower(): VCS_SUBVERSION,
- "svn": VCS_SUBVERSION,
- VCS_GIT.lower(): VCS_GIT,
-}
-
-# The result of parsing Subversion's [auto-props] setting.
-svn_auto_props_map = None
-
-def GetEmail(prompt):
- """Prompts the user for their email address and returns it.
-
- The last used email address is saved to a file and offered up as a suggestion
- to the user. If the user presses enter without typing in anything the last
- used email address is used. If the user enters a new address, it is saved
- for next time we prompt.
-
- """
- last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
- last_email = ""
- if os.path.exists(last_email_file_name):
- try:
- last_email_file = open(last_email_file_name, "r")
- last_email = last_email_file.readline().strip("\n")
- last_email_file.close()
- prompt += " [%s]" % last_email
- except IOError as e:
- pass
- email = input(prompt + ": ").strip()
- if email:
- try:
- last_email_file = open(last_email_file_name, "w")
- last_email_file.write(email)
- last_email_file.close()
- except IOError as e:
- pass
- else:
- email = last_email
- return email
-
-
-def StatusUpdate(msg):
- """Print a status message to stdout.
-
- If 'verbosity' is greater than 0, print the message.
-
- Args:
- msg: The string to print.
- """
- if verbosity > 0:
- print(msg)
-
-
-def ErrorExit(msg):
- """Print an error message to stderr and exit."""
- print(msg, file=sys.stderr)
- sys.exit(1)
-
-
-class ClientLoginError(HTTPError):
- """Raised to indicate there was an error authenticating with ClientLogin."""
-
- def __init__(self, url, code, msg, headers, args):
- HTTPError.__init__(self, url, code, msg, headers, None)
- self.args = args
- self.reason = args["Error"]
- self.info = args.get("Info", None)
-
-
-class AbstractRpcServer(object):
- """Provides a common interface for a simple RPC server."""
-
- def __init__(self, host, auth_function, host_override=None, extra_headers={},
- save_cookies=False, account_type=AUTH_ACCOUNT_TYPE):
- """Creates a new HttpRpcServer.
-
- Args:
- host: The host to send requests to.
- auth_function: A function that takes no arguments and returns an
- (email, password) tuple when called. Will be called if authentication
- is required.
- host_override: The host header to send to the server (defaults to host).
- extra_headers: A dict of extra headers to append to every request.
- save_cookies: If True, save the authentication cookies to local disk.
- If False, use an in-memory cookiejar instead. Subclasses must
- implement this functionality. Defaults to False.
- account_type: Account type used for authentication. Defaults to
- AUTH_ACCOUNT_TYPE.
- """
- self.host = host
- if (not self.host.startswith("http://") and
- not self.host.startswith("https://")):
- self.host = "http://" + self.host
- self.host_override = host_override
- self.auth_function = auth_function
- self.authenticated = False
- self.extra_headers = extra_headers
- self.save_cookies = save_cookies
- self.account_type = account_type
- self.opener = self._GetOpener()
- if self.host_override:
- logging.info("Server: %s; Host: %s", self.host, self.host_override)
- else:
- logging.info("Server: %s", self.host)
-
- def _GetOpener(self):
- """Returns an OpenerDirector for making HTTP requests.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- raise NotImplementedError()
-
- def _CreateRequest(self, url, data=None):
- """Creates a new urllib request."""
- logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
- req = Request(url, data=data)
- if self.host_override:
- req.add_header("Host", self.host_override)
- for key, value in self.extra_headers.items():
- req.add_header(key, value)
- return req
-
- def _GetAuthToken(self, email, password):
- """Uses ClientLogin to authenticate the user, returning an auth token.
-
- Args:
- email: The user's email address
- password: The user's password
-
- Raises:
- ClientLoginError: If there was an error authenticating with ClientLogin.
- HTTPError: If there was some other form of HTTP error.
-
- Returns:
- The authentication token returned by ClientLogin.
- """
- account_type = self.account_type
- if self.host.endswith(".google.com"):
- # Needed for use inside Google.
- account_type = "HOSTED"
- req = self._CreateRequest(
- url="https://www.google.com/accounts/ClientLogin",
- data=urlencode({
- "Email": email,
- "Passwd": password,
- "service": "ah",
- "source": "rietveld-codereview-upload",
- "accountType": account_type,
- }),
- )
- try:
- response = self.opener.open(req)
- response_body = response.read()
- response_dict = dict(x.split("=")
- for x in response_body.split("\n") if x)
- return response_dict["Auth"]
- except HTTPError as e:
- if e.code == 403:
- body = e.read()
- response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
- raise ClientLoginError(req.get_full_url(), e.code, e.msg,
- e.headers, response_dict)
- else:
- raise
-
- def _GetAuthCookie(self, auth_token):
- """Fetches authentication cookies for an authentication token.
-
- Args:
- auth_token: The authentication token returned by ClientLogin.
-
- Raises:
- HTTPError: If there was an error fetching the authentication cookies.
- """
- # This is a dummy value to allow us to identify when we're successful.
- continue_location = "http://localhost/"
- args = {"continue": continue_location, "auth": auth_token}
- req = self._CreateRequest("%s/_ah/login?%s" %
- (self.host, urlencode(args)))
- try:
- response = self.opener.open(req)
- except HTTPError as e:
- response = e
- if (response.code != 302 or
- response.info()["location"] != continue_location):
- raise HTTPError(req.get_full_url(), response.code, response.msg,
- response.headers, response.fp)
- self.authenticated = True
-
- def _Authenticate(self):
- """Authenticates the user.
-
- The authentication process works as follows:
- 1) We get a username and password from the user
- 2) We use ClientLogin to obtain an AUTH token for the user
- (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
- 3) We pass the auth token to /_ah/login on the server to obtain an
- authentication cookie. If login was successful, it tries to redirect
- us to the URL we provided.
-
- If we attempt to access the upload API without first obtaining an
- authentication cookie, it returns a 401 response (or a 302) and
- directs us to authenticate ourselves with ClientLogin.
- """
- for i in range(3):
- credentials = self.auth_function()
- try:
- auth_token = self._GetAuthToken(credentials[0], credentials[1])
- except ClientLoginError as e:
- print(file=sys.stderr)
- if e.reason == "BadAuthentication":
- if e.info == "InvalidSecondFactor":
- print("Use an application-specific password instead "
- "of your regular account password.\n"
- "See http://www.google.com/"
- "support/accounts/bin/answer.py?answer=185833",
- file=sys.stderr)
- else:
- print("Invalid username or password.", file=sys.stderr)
- elif e.reason == "CaptchaRequired":
- print("Please go to\n"
- "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
- "and verify you are a human. Then try again.\n"
- "If you are using a Google Apps account the URL is:\n"
- "https://www.google.com/a/yourdomain.com/UnlockCaptcha",
- file=sys.stderr)
- elif e.reason == "NotVerified":
- print("Account not verified.", file=sys.stderr)
- elif e.reason == "TermsNotAgreed":
- print("User has not agreed to TOS.", file=sys.stderr)
- elif e.reason == "AccountDeleted":
- print("The user account has been deleted.", file=sys.stderr)
- elif e.reason == "AccountDisabled":
- print("The user account has been disabled.", file=sys.stderr)
- break
- elif e.reason == "ServiceDisabled":
- print("The user's access to the service has been disabled.",
- file=sys.stderr)
- elif e.reason == "ServiceUnavailable":
- print("The service is not available; try again later.",
- file=sys.stderr)
- else:
- # Unknown error.
- raise
- print(file=sys.stderr)
- continue
- self._GetAuthCookie(auth_token)
- return
-
- def Send(self, request_path, payload=None,
- content_type="application/octet-stream",
- timeout=None,
- extra_headers=None,
- **kwargs):
- """Sends an RPC and returns the response.
-
- Args:
- request_path: The path to send the request to, eg /api/appversion/create.
- payload: The body of the request, or None to send an empty request.
- content_type: The Content-Type header to use.
- timeout: timeout in seconds; default None i.e. no timeout.
- (Note: for large requests on OS X, the timeout doesn't work right.)
- extra_headers: Dict containing additional HTTP headers that should be
- included in the request (string header names mapped to their values),
- or None to not include any additional headers.
- kwargs: Any keyword arguments are converted into query string parameters.
-
- Returns:
- The response body, as a string.
- """
- # TODO: Don't require authentication. Let the server say
- # whether it is necessary.
- if not self.authenticated:
- self._Authenticate()
-
- old_timeout = socket.getdefaulttimeout()
- socket.setdefaulttimeout(timeout)
- try:
- tries = 0
- while True:
- tries += 1
- args = dict(kwargs)
- url = "%s%s" % (self.host, request_path)
- if args:
- url += "?" + urlencode(args)
- req = self._CreateRequest(url=url, data=payload)
- req.add_header("Content-Type", content_type)
- if extra_headers:
- for header, value in extra_headers.items():
- req.add_header(header, value)
- try:
- f = self.opener.open(req)
- response = f.read()
- f.close()
- return response
- except HTTPError as e:
- if tries > 3:
- raise
- elif e.code == 401 or e.code == 302:
- self._Authenticate()
-## elif e.code >= 500 and e.code < 600:
-## # Server Error - try again.
-## continue
- elif e.code == 301:
- # Handle permanent redirect manually.
- url = e.info()["location"]
- url_loc = urlparse(url)
- self.host = '%s://%s' % (url_loc[0], url_loc[1])
- else:
- raise
- finally:
- socket.setdefaulttimeout(old_timeout)
-
-
-class HttpRpcServer(AbstractRpcServer):
- """Provides a simplified RPC-style interface for HTTP requests."""
-
- def _Authenticate(self):
- """Save the cookie jar after authentication."""
- super(HttpRpcServer, self)._Authenticate()
- if self.save_cookies:
- StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
- self.cookie_jar.save()
-
- def _GetOpener(self):
- """Returns an OpenerDirector that supports cookies and ignores redirects.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- opener = OpenerDirector()
- opener.add_handler(ProxyHandler())
- opener.add_handler(UnknownHandler())
- opener.add_handler(HTTPHandler())
- opener.add_handler(HTTPDefaultErrorHandler())
- opener.add_handler(HTTPSHandler())
- opener.add_handler(HTTPErrorProcessor())
- if self.save_cookies:
- self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
- self.cookie_jar = MozillaCookieJar(self.cookie_file)
- if os.path.exists(self.cookie_file):
- try:
- self.cookie_jar.load()
- self.authenticated = True
- StatusUpdate("Loaded authentication cookies from %s" %
- self.cookie_file)
- except (CookieLoadError, IOError):
- # Failed to load cookies - just ignore them.
- pass
- else:
- # Create an empty cookie file with mode 600
- fd = os.open(self.cookie_file, os.O_CREAT, 0o600)
- os.close(fd)
- # Always chmod the cookie file
- os.chmod(self.cookie_file, 0o600)
- else:
- # Don't save cookies across runs of update.py.
- self.cookie_jar = CookieJar()
- opener.add_handler(HTTPCookieProcessor(self.cookie_jar))
- return opener
-
-
-parser = optparse.OptionParser(
- usage="%prog [options] [-- diff_options] [path...]")
-parser.add_option("-y", "--assume_yes", action="store_true",
- dest="assume_yes", default=False,
- help="Assume that the answer to yes/no questions is 'yes'.")
-# Logging
-group = parser.add_option_group("Logging options")
-group.add_option("-q", "--quiet", action="store_const", const=0,
- dest="verbose", help="Print errors only.")
-group.add_option("-v", "--verbose", action="store_const", const=2,
- dest="verbose", default=1,
- help="Print info level logs.")
-group.add_option("--noisy", action="store_const", const=3,
- dest="verbose", help="Print all logs.")
-# Review server
-group = parser.add_option_group("Review server options")
-group.add_option("-s", "--server", action="store", dest="server",
- default=DEFAULT_REVIEW_SERVER,
- metavar="SERVER",
- help=("The server to upload to. The format is host[:port]. "
- "Defaults to '%default'."))
-group.add_option("-e", "--email", action="store", dest="email",
- metavar="EMAIL", default=None,
- help="The username to use. Will prompt if omitted.")
-group.add_option("-H", "--host", action="store", dest="host",
- metavar="HOST", default=None,
- help="Overrides the Host header sent with all RPCs.")
-group.add_option("--no_cookies", action="store_false",
- dest="save_cookies", default=True,
- help="Do not save authentication cookies to local disk.")
-group.add_option("--account_type", action="store", dest="account_type",
- metavar="TYPE", default=AUTH_ACCOUNT_TYPE,
- choices=["GOOGLE", "HOSTED"],
- help=("Override the default account type "
- "(defaults to '%default', "
- "valid choices are 'GOOGLE' and 'HOSTED')."))
-# Issue
-group = parser.add_option_group("Issue options")
-group.add_option("-d", "--description", action="store", dest="description",
- metavar="DESCRIPTION", default=None,
- help="Optional description when creating an issue.")
-group.add_option("-f", "--description_file", action="store",
- dest="description_file", metavar="DESCRIPTION_FILE",
- default=None,
- help="Optional path of a file that contains "
- "the description when creating an issue.")
-group.add_option("-r", "--reviewers", action="store", dest="reviewers",
- metavar="REVIEWERS", default=None,
- help="Add reviewers (comma separated email addresses).")
-group.add_option("--cc", action="store", dest="cc",
- metavar="CC", default="dev@scons.tigris.org",
- help="Add CC (comma separated email addresses).")
-group.add_option("--private", action="store_true", dest="private",
- default=False,
- help="Make the issue restricted to reviewers and those CCed")
-# Upload options
-group = parser.add_option_group("Patch options")
-group.add_option("-m", "--message", action="store", dest="message",
- metavar="MESSAGE", default=None,
- help="A message to identify the patch. "
- "Will prompt if omitted.")
-group.add_option("-i", "--issue", type="int", action="store",
- metavar="ISSUE", default=None,
- help="Issue number to which to add. Defaults to new issue.")
-group.add_option("--base_url", action="store", dest="base_url", default=None,
- help="Base repository URL (listed as \"Base URL\" when "
- "viewing issue). If omitted, will be guessed automatically "
- "for SVN repos and left blank for others.")
-group.add_option("--download_base", action="store_true",
- dest="download_base", default=False,
- help="Base files will be downloaded by the server "
- "(side-by-side diffs may not work on files with CRs).")
-group.add_option("--rev", action="store", dest="revision",
- metavar="REV", default=None,
- help="Base revision/branch/tree to diff against. Use "
- "rev1:rev2 range to review already committed changeset.")
-group.add_option("--send_mail", action="store_true",
- dest="send_mail", default=True,
- help="Send notification email to reviewers.")
-group.add_option("--vcs", action="store", dest="vcs",
- metavar="VCS", default="svn",
- help=("Version control system (optional, usually upload.py "
- "already guesses the right VCS)."))
-group.add_option("--emulate_svn_auto_props", action="store_true",
- dest="emulate_svn_auto_props", default=False,
- help=("Emulate Subversion's auto properties feature."))
-
-
-def GetRpcServer(server, email=None, host_override=None, save_cookies=True,
- account_type=AUTH_ACCOUNT_TYPE):
- """Returns an instance of an AbstractRpcServer.
-
- Args:
- server: String containing the review server URL.
- email: String containing user's email address.
- host_override: If not None, string containing an alternate hostname to use
- in the host header.
- save_cookies: Whether authentication cookies should be saved to disk.
- account_type: Account type for authentication, either 'GOOGLE'
- or 'HOSTED'. Defaults to AUTH_ACCOUNT_TYPE.
-
- Returns:
- A new AbstractRpcServer, on which RPC calls can be made.
- """
-
- rpc_server_class = HttpRpcServer
-
- # If this is the dev_appserver, use fake authentication.
- host = (host_override or server).lower()
- if re.match(r'(http://)?localhost([:/]|$)', host):
- if email is None:
- email = "test@example.com"
- logging.info("Using debug user %s. Override with --email" % email)
- server = rpc_server_class(
- server,
- lambda: (email, "password"),
- host_override=host_override,
- extra_headers={"Cookie":
- 'dev_appserver_login="%s:False"' % email},
- save_cookies=save_cookies,
- account_type=account_type)
- # Don't try to talk to ClientLogin.
- server.authenticated = True
- return server
-
- def GetUserCredentials():
- """Prompts the user for a username and password."""
- # Create a local alias to the email variable to avoid Python's crazy
- # scoping rules.
- local_email = email
- if local_email is None:
- local_email = GetEmail("Email (login for uploading to %s)" % server)
- password = None
- if keyring:
- password = keyring.get_password(host, local_email)
- if password is not None:
- print("Using password from system keyring.")
- else:
- password = getpass.getpass("Password for %s: " % local_email)
- if keyring:
- answer = input("Store password in system keyring?(y/N) ").strip()
- if answer == "y":
- keyring.set_password(host, local_email, password)
- return (local_email, password)
-
- return rpc_server_class(server,
- GetUserCredentials,
- host_override=host_override,
- save_cookies=save_cookies)
-
-
-def EncodeMultipartFormData(fields, files):
- """Encode form fields for multipart/form-data.
-
- Args:
- fields: A sequence of (name, value) elements for regular form fields.
- files: A sequence of (name, filename, value) elements for data to be
- uploaded as files.
- Returns:
- (content_type, body) ready for httplib.HTTP instance.
-
- Source:
- http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
- """
- BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
- CRLF = '\r\n'
- lines = []
- for (key, value) in fields:
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"' % key)
- lines.append('')
- if isinstance(value, str):
- value = value.encode('utf-8')
- lines.append(value)
- for (key, filename, value) in files:
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
- (key, filename))
- lines.append('Content-Type: %s' % GetContentType(filename))
- lines.append('')
- if isinstance(value, str):
- value = value.encode('utf-8')
- lines.append(value)
- lines.append('--' + BOUNDARY + '--')
- lines.append('')
- body = CRLF.join(lines)
- content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
- return content_type, body
-
-
-def GetContentType(filename):
- """Helper to guess the content-type from the filename."""
- return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
-
-
-# Use a shell for subcommands on Windows to get a PATH search.
-use_shell = sys.platform.startswith("win")
-
-def RunShellWithReturnCodeAndStderr(command, print_output=False,
- universal_newlines=True,
- env=os.environ):
- """Executes a command and returns the output from stdout, stderr and the return code.
-
- Args:
- command: Command to execute.
- print_output: If True, the output is printed to stdout.
- If False, both stdout and stderr are ignored.
- universal_newlines: Use universal_newlines flag (default: True).
-
- Returns:
- Tuple (stdout, stderr, return code)
- """
- logging.info("Running %s", command)
- env = env.copy()
- env['LC_MESSAGES'] = 'C'
- p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- shell=use_shell, universal_newlines=universal_newlines,
- env=env)
- if print_output:
- output_array = []
- while True:
- line = p.stdout.readline()
- if not line:
- break
- print(line.strip("\n"))
- output_array.append(line)
- output = "".join(output_array)
- else:
- output = p.stdout.read()
- p.wait()
- errout = p.stderr.read()
- if print_output and errout:
- print(errout, file=sys.stderr)
- p.stdout.close()
- p.stderr.close()
- return output, errout, p.returncode
-
-def RunShellWithReturnCode(command, print_output=False,
- universal_newlines=True,
- env=os.environ):
- """Executes a command and returns the output from stdout and the return code."""
- out, err, retcode = RunShellWithReturnCodeAndStderr(command, print_output,
- universal_newlines, env)
- return out, retcode
-
-def RunShell(command, silent_ok=False, universal_newlines=True,
- print_output=False, env=os.environ):
- data, retcode = RunShellWithReturnCode(command, print_output,
- universal_newlines, env)
- if retcode:
- ErrorExit("Got error status from %s:\n%s" % (command, data))
- if not silent_ok and not data:
- ErrorExit("No output from %s" % command)
- return data
-
-
-class VersionControlSystem(object):
- """Abstract base class providing an interface to the VCS."""
-
- def __init__(self, options):
- """Constructor.
-
- Args:
- options: Command line options.
- """
- self.options = options
-
- def PostProcessDiff(self, diff):
- """Return the diff with any special post processing this VCS needs, e.g.
- to include an svn-style "Index:"."""
- return diff
-
- def GenerateDiff(self, args):
- """Return the current diff as a string.
-
- Args:
- args: Extra arguments to pass to the diff command.
- """
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def CheckForUnknownFiles(self):
- """Show an "are you sure?" prompt if there are unknown files."""
- unknown_files = self.GetUnknownFiles()
- if unknown_files:
- print("The following files are not added to version control:")
- for line in unknown_files:
- print(line)
- prompt = "Are you sure to continue?(y/N) "
- answer = input(prompt).strip()
- if answer != "y":
- ErrorExit("User aborted")
-
- def GetBaseFile(self, filename):
- """Get the content of the upstream version of a file.
-
- Returns:
- A tuple (base_content, new_content, is_binary, status)
- base_content: The contents of the base file.
- new_content: For text files, this is empty. For binary files, this is
- the contents of the new file, since the diff output won't contain
- information to reconstruct the current file.
- is_binary: True iff the file is binary.
- status: The status of the file.
- """
-
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
-
- def GetBaseFiles(self, diff):
- """Helper that calls GetBase file for each file in the patch.
-
- Returns:
- A dictionary that maps from filename to GetBaseFile's tuple. Filenames
- are retrieved based on lines that start with "Index:" or
- "Property changes on:".
- """
- files = {}
- for line in diff.splitlines(True):
- if line.startswith('Index:') or line.startswith('Property changes on:'):
- unused, filename = line.split(':', 1)
- # On Windows if a file has property changes its filename uses '\'
- # instead of '/'.
- filename = filename.strip().replace('\\', '/')
- files[filename] = self.GetBaseFile(filename)
- return files
-
-
- def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
- files):
- """Uploads the base files (and if necessary, the current ones as well)."""
-
- def UploadFile(filename, file_id, content, is_binary, status, is_base):
- """Uploads a file to the server."""
- file_too_large = False
- if is_base:
- type = "base"
- else:
- type = "current"
- if len(content) > MAX_UPLOAD_SIZE:
- print("Not uploading the %s file for %s because it's too large." %
- (type, filename))
- file_too_large = True
- content = ""
- checksum = md5(content).hexdigest()
- if options.verbose > 0 and not file_too_large:
- print("Uploading %s file for %s" % (type, filename))
- url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
- form_fields = [("filename", filename),
- ("status", status),
- ("checksum", checksum),
- ("is_binary", str(is_binary)),
- ("is_current", str(not is_base)),
- ]
- if file_too_large:
- form_fields.append(("file_too_large", "1"))
- if options.email:
- form_fields.append(("user", options.email))
- ctype, body = EncodeMultipartFormData(form_fields,
- [("data", filename, content)])
- response_body = rpc_server.Send(url, body,
- content_type=ctype)
- if not response_body.startswith("OK"):
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
-
- patches = dict()
- [patches.setdefault(v, k) for k, v in patch_list]
- for filename in patches.keys():
- base_content, new_content, is_binary, status = files[filename]
- file_id_str = patches.get(filename)
- if file_id_str.find("nobase") != -1:
- base_content = None
- file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
- file_id = int(file_id_str)
- if base_content != None:
- UploadFile(filename, file_id, base_content, is_binary, status, True)
- if new_content != None:
- UploadFile(filename, file_id, new_content, is_binary, status, False)
-
- def IsImage(self, filename):
- """Returns true if the filename has an image extension."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False
- return mimetype.startswith("image/")
-
- def IsBinary(self, filename):
- """Returns true if the guessed mimetyped isnt't in text group."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False # e.g. README, "real" binaries usually have an extension
- # special case for text files which don't start with text/
- if mimetype in TEXT_MIMETYPES:
- return False
- return not mimetype.startswith("text/")
-
-
-class SubversionVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Subversion."""
-
- def __init__(self, options):
- super(SubversionVCS, self).__init__(options)
- if self.options.revision:
- match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
- if not match:
- ErrorExit("Invalid Subversion revision %s." % self.options.revision)
- self.rev_start = match.group(1)
- self.rev_end = match.group(3)
- else:
- self.rev_start = self.rev_end = None
- # Cache output from "svn list -r REVNO dirname".
- # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
- self.svnls_cache = {}
- # Base URL is required to fetch files deleted in an older revision.
- # Result is cached to not guess it over and over again in GetBaseFile().
- required = self.options.download_base or self.options.revision is not None
- self.svn_base = self._GuessBase(required)
-
- def GuessBase(self, required):
- """Wrapper for _GuessBase."""
- return self.svn_base
-
- def _GuessBase(self, required):
- """Returns base URL for current diff.
-
- Args:
- required: If true, exits if the url can't be guessed, otherwise None is
- returned.
- """
- info = RunShell(["svn", "info"])
- for line in info.splitlines():
- if line.startswith("URL: "):
- url = line.split()[1]
- scheme, netloc, path, params, query, fragment = urlparse(url)
- guess = ""
- if netloc == "svn.python.org" and scheme == "svn+ssh":
- path = "projects" + path
- scheme = "http"
- guess = "Python "
- elif netloc.endswith(".googlecode.com"):
- scheme = "http"
- guess = "Google Code "
- path = path + "/"
- base = urlunparse((scheme, netloc, path, params, query, fragment))
- logging.info("Guessed %sbase = %s", guess, base)
- return base
- if required:
- ErrorExit("Can't find URL in output from svn info")
- return None
-
- def GenerateDiff(self, args):
- cmd = ["svn", "diff"]
- if self.options.revision:
- cmd += ["-r", self.options.revision]
- cmd.extend(args)
- data = RunShell(cmd)
- count = 0
- for line in data.splitlines():
- if line.startswith("Index:") or line.startswith("Property changes on:"):
- count += 1
- logging.info(line)
- if not count:
- ErrorExit("No valid patches found in output from svn diff")
- return data
-
- def _CollapseKeywords(self, content, keyword_str):
- """Collapses SVN keywords."""
- # svn cat translates keywords but svn diff doesn't. As a result of this
- # behavior patching.PatchChunks() fails with a chunk mismatch error.
- # This part was originally written by the Review Board development team
- # who had the same problem (http://reviews.review-board.org/r/276/).
- # Mapping of keywords to known aliases
- svn_keywords = {
- # Standard keywords
- 'Date': ['Date', 'LastChangedDate'],
- 'Revision': ['Revision', 'LastChangedRevision', 'Rev'],
- 'Author': ['Author', 'LastChangedBy'],
- 'HeadURL': ['HeadURL', 'URL'],
- 'Id': ['Id'],
-
- # Aliases
- 'LastChangedDate': ['LastChangedDate', 'Date'],
- 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
- 'LastChangedBy': ['LastChangedBy', 'Author'],
- 'URL': ['URL', 'HeadURL'],
- }
-
- def repl(m):
- if m.group(2):
- return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
- return "$%s$" % m.group(1)
- keywords = [keyword
- for name in keyword_str.split(" ")
- for keyword in svn_keywords.get(name, [])]
- return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
-
- def GetUnknownFiles(self):
- status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
- unknown_files = []
- for line in status.split("\n"):
- if line and line[0] == "?":
- unknown_files.append(line)
- return unknown_files
-
- def ReadFile(self, filename):
- """Returns the contents of a file."""
- file = open(filename, 'rb')
- result = ""
- try:
- result = file.read()
- finally:
- file.close()
- return result
-
- def GetStatus(self, filename):
- """Returns the status of a file."""
- if not self.options.revision:
- status = RunShell(["svn", "status", "--ignore-externals", filename])
- if not status:
- ErrorExit("svn status returned no output for %s" % filename)
- status_lines = status.splitlines()
- # If file is in a cl, the output will begin with
- # "\n--- Changelist 'cl_name':\n". See
- # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
- if (len(status_lines) == 3 and
- not status_lines[0] and
- status_lines[1].startswith("--- Changelist")):
- status = status_lines[2]
- else:
- status = status_lines[0]
- # If we have a revision to diff against we need to run "svn list"
- # for the old and the new revision and compare the results to get
- # the correct status for a file.
- else:
- dirname, relfilename = os.path.split(filename)
- if dirname not in self.svnls_cache:
- cmd = ["svn", "list", "-r", self.rev_start, dirname or "."]
- out, err, returncode = RunShellWithReturnCodeAndStderr(cmd)
- if returncode:
- # Directory might not yet exist at start revison
- # svn: Unable to find repository location for 'abc' in revision nnn
- if re.match('^svn: Unable to find repository location for .+ in revision \d+', err):
- old_files = ()
- else:
- ErrorExit("Failed to get status for %s:\n%s" % (filename, err))
- else:
- old_files = out.splitlines()
- args = ["svn", "list"]
- if self.rev_end:
- args += ["-r", self.rev_end]
- cmd = args + [dirname or "."]
- out, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- ErrorExit("Failed to run command %s" % cmd)
- self.svnls_cache[dirname] = (old_files, out.splitlines())
- old_files, new_files = self.svnls_cache[dirname]
- if relfilename in old_files and relfilename not in new_files:
- status = "D "
- elif relfilename in old_files and relfilename in new_files:
- status = "M "
- else:
- status = "A "
- return status
-
- def GetBaseFile(self, filename):
- status = self.GetStatus(filename)
- base_content = None
- new_content = None
-
- # If a file is copied its status will be "A +", which signifies
- # "addition-with-history". See "svn st" for more information. We need to
- # upload the original file or else diff parsing will fail if the file was
- # edited.
- if status[0] == "A" and status[3] != "+":
- # We'll need to upload the new content if we're adding a binary file
- # since diff's output won't contain it.
- mimetype = RunShell(["svn", "propget", "svn:mime-type", filename],
- silent_ok=True)
- base_content = ""
- is_binary = bool(mimetype) and not mimetype.startswith("text/")
- if is_binary and self.IsImage(filename):
- new_content = self.ReadFile(filename)
- elif (status[0] in ("M", "D", "R") or
- (status[0] == "A" and status[3] == "+") or # Copied file.
- (status[0] == " " and status[1] == "M")): # Property change.
- args = []
- if self.options.revision:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- # Don't change filename, it's needed later.
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:mime-type", url]
- mimetype, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- # File does not exist in the requested revision.
- # Reset mimetype, it contains an error message.
- mimetype = ""
- else:
- mimetype = mimetype.strip()
- get_base = False
- is_binary = (bool(mimetype) and
- not mimetype.startswith("text/") and
- not mimetype in TEXT_MIMETYPES)
- if status[0] == " ":
- # Empty base content just to force an upload.
- base_content = ""
- elif is_binary:
- if self.IsImage(filename):
- get_base = True
- if status[0] == "M":
- if not self.rev_end:
- new_content = self.ReadFile(filename)
- else:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
- new_content = RunShell(["svn", "cat", url],
- universal_newlines=True, silent_ok=True)
- else:
- base_content = ""
- else:
- get_base = True
-
- if get_base:
- if is_binary:
- universal_newlines = False
- else:
- universal_newlines = True
- if self.rev_start:
- # "svn cat -r REV delete_file.txt" doesn't work. cat requires
- # the full URL with "@REV" appended instead of using "-r" option.
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- base_content = RunShell(["svn", "cat", url],
- universal_newlines=universal_newlines,
- silent_ok=True)
- else:
- base_content, ret_code = RunShellWithReturnCode(
- ["svn", "cat", filename], universal_newlines=universal_newlines)
- if ret_code and status[0] == "R":
- # It's a replaced file without local history (see issue208).
- # The base file needs to be fetched from the server.
- url = "%s/%s" % (self.svn_base, filename)
- base_content = RunShell(["svn", "cat", url],
- universal_newlines=universal_newlines,
- silent_ok=True)
- elif ret_code:
- ErrorExit("Got error status from 'svn cat %s'" % filename)
- if not is_binary:
- args = []
- if self.rev_start:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:keywords", url]
- keywords, returncode = RunShellWithReturnCode(cmd)
- if keywords and not returncode:
- base_content = self._CollapseKeywords(base_content, keywords)
- else:
- StatusUpdate("svn status returned unexpected output: %s" % status)
- sys.exit(1)
- return base_content, new_content, is_binary, status[0:5]
-
-
-class GitVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Git."""
-
- def __init__(self, options):
- super(GitVCS, self).__init__(options)
- # Map of filename -> (hash before, hash after) of base file.
- # Hashes for "no such file" are represented as None.
- self.hashes = {}
- # Map of new filename -> old filename for renames.
- self.renames = {}
-
- def PostProcessDiff(self, gitdiff):
- """Converts the diff output to include an svn-style "Index:" line as well
- as record the hashes of the files, so we can upload them along with our
- diff."""
- # Special used by git to indicate "no such content".
- NULL_HASH = "0"*40
-
- def IsFileNew(filename):
- return filename in self.hashes and self.hashes[filename][0] is None
-
- def AddSubversionPropertyChange(filename):
- """Add svn's property change information into the patch if given file is
- new file.
-
- We use Subversion's auto-props setting to retrieve its property.
- See http://svnbook.red-bean.com/en/1.1/ch07.html#svn-ch-7-sect-1.3.2 for
- Subversion's [auto-props] setting.
- """
- if self.options.emulate_svn_auto_props and IsFileNew(filename):
- svnprops = GetSubversionPropertyChanges(filename)
- if svnprops:
- svndiff.append("\n" + svnprops + "\n")
-
- svndiff = []
- filecount = 0
- filename = None
- for line in gitdiff.splitlines():
- match = re.match(r"diff --git a/(.*) b/(.*)$", line)
- if match:
- # Add auto property here for previously seen file.
- if filename is not None:
- AddSubversionPropertyChange(filename)
- filecount += 1
- # Intentionally use the "after" filename so we can show renames.
- filename = match.group(2)
- svndiff.append("Index: %s\n" % filename)
- if match.group(1) != match.group(2):
- self.renames[match.group(2)] = match.group(1)
- else:
- # The "index" line in a git diff looks like this (long hashes elided):
- # index 82c0d44..b2cee3f 100755
- # We want to save the left hash, as that identifies the base file.
- match = re.match(r"index (\w+)\.\.(\w+)", line)
- if match:
- before, after = (match.group(1), match.group(2))
- if before == NULL_HASH:
- before = None
- if after == NULL_HASH:
- after = None
- self.hashes[filename] = (before, after)
- svndiff.append(line + "\n")
- if not filecount:
- ErrorExit("No valid patches found in output from git diff")
- # Add auto property for the last seen file.
- assert filename is not None
- AddSubversionPropertyChange(filename)
- return "".join(svndiff)
-
- def GenerateDiff(self, extra_args):
- extra_args = extra_args[:]
- if self.options.revision:
- if ":" in self.options.revision:
- extra_args = self.options.revision.split(":", 1) + extra_args
- else:
- extra_args = [self.options.revision] + extra_args
-
- # --no-ext-diff is broken in some versions of Git, so try to work around
- # this by overriding the environment (but there is still a problem if the
- # git config key "diff.external" is used).
- env = os.environ.copy()
- if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF']
- return RunShell(["git", "diff", "--no-ext-diff", "--full-index", "-M"]
- + extra_args, env=env)
-
- def GetUnknownFiles(self):
- status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
- silent_ok=True)
- return status.splitlines()
-
- def GetFileContent(self, file_hash, is_binary):
- """Returns the content of a file identified by its git hash."""
- data, retcode = RunShellWithReturnCode(["git", "show", file_hash],
- universal_newlines=not is_binary)
- if retcode:
- ErrorExit("Got error status from 'git show %s'" % file_hash)
- return data
-
- def GetBaseFile(self, filename):
- hash_before, hash_after = self.hashes.get(filename, (None,None))
- base_content = None
- new_content = None
- is_binary = self.IsBinary(filename)
- status = None
-
- if filename in self.renames:
- status = "A +" # Match svn attribute name for renames.
- if filename not in self.hashes:
- # If a rename doesn't change the content, we never get a hash.
- base_content = RunShell(["git", "show", "HEAD:" + filename])
- elif not hash_before:
- status = "A"
- base_content = ""
- elif not hash_after:
- status = "D"
- else:
- status = "M"
-
- is_image = self.IsImage(filename)
-
- # Grab the before/after content if we need it.
- # We should include file contents if it's text or it's an image.
- if not is_binary or is_image:
- # Grab the base content if we don't have it already.
- if base_content is None and hash_before:
- base_content = self.GetFileContent(hash_before, is_binary)
- # Only include the "after" file if it's an image; otherwise it
- # it is reconstructed from the diff.
- if is_image and hash_after:
- new_content = self.GetFileContent(hash_after, is_binary)
-
- return (base_content, new_content, is_binary, status)
-
-
-class MercurialVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Mercurial."""
-
- def __init__(self, options, repo_dir):
- super(MercurialVCS, self).__init__(options)
- # Absolute path to repository (we can be in a subdir)
- self.repo_dir = os.path.normpath(repo_dir)
- # Compute the subdir
- cwd = os.path.normpath(os.getcwd())
- assert cwd.startswith(self.repo_dir)
- self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
- if self.options.revision:
- self.base_rev = self.options.revision
- else:
- self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip()
-
- def _GetRelPath(self, filename):
- """Get relative path of a file according to the current directory,
- given its logical path in the repo."""
- assert filename.startswith(self.subdir), (filename, self.subdir)
- return filename[len(self.subdir):].lstrip(r"\/")
-
- def GenerateDiff(self, extra_args):
- cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
- data = RunShell(cmd, silent_ok=True)
- svndiff = []
- filecount = 0
- for line in data.splitlines():
- m = re.match("diff --git a/(\S+) b/(\S+)", line)
- if m:
- # Modify line to make it look like as it comes from svn diff.
- # With this modification no changes on the server side are required
- # to make upload.py work with Mercurial repos.
- # NOTE: for proper handling of moved/copied files, we have to use
- # the second filename.
- filename = m.group(2)
- svndiff.append("Index: %s" % filename)
- svndiff.append("=" * 67)
- filecount += 1
- logging.info(line)
- else:
- svndiff.append(line)
- if not filecount:
- ErrorExit("No valid patches found in output from hg diff")
- return "\n".join(svndiff) + "\n"
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- args = []
- status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
- silent_ok=True)
- unknown_files = []
- for line in status.splitlines():
- st, fn = line.split(" ", 1)
- if st == "?":
- unknown_files.append(fn)
- return unknown_files
-
- def GetBaseFile(self, filename):
- # "hg status" and "hg cat" both take a path relative to the current subdir
- # rather than to the repo root, but "hg diff" has given us the full path
- # to the repo root.
- base_content = ""
- new_content = None
- is_binary = False
- oldrelpath = relpath = self._GetRelPath(filename)
- # "hg status -C" returns two lines for moved/copied files, one otherwise
- out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
- out = out.splitlines()
- # HACK: strip error message about missing file/directory if it isn't in
- # the working copy
- if out[0].startswith('%s: ' % relpath):
- out = out[1:]
- status, _ = out[0].split(' ', 1)
- if len(out) > 1 and status == "A":
- # Moved/copied => considered as modified, use old filename to
- # retrieve base contents
- oldrelpath = out[1].strip()
- status = "M"
- if ":" in self.base_rev:
- base_rev = self.base_rev.split(":", 1)[0]
- else:
- base_rev = self.base_rev
- if status != "A":
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True)
- is_binary = "\0" in base_content # Mercurial's heuristic
- if status != "R":
- new_content = open(relpath, "rb").read()
- is_binary = is_binary or "\0" in new_content
- if is_binary and base_content:
- # Fetch again without converting newlines
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True, universal_newlines=False)
- if not is_binary or not self.IsImage(relpath):
- new_content = None
- return base_content, new_content, is_binary, status
-
-
-# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
-def SplitPatch(data):
- """Splits a patch into separate pieces for each file.
-
- Args:
- data: A string containing the output of svn diff.
-
- Returns:
- A list of 2-tuple (filename, text) where text is the svn diff output
- pertaining to filename.
- """
- patches = []
- filename = None
- diff = []
- for line in data.splitlines(True):
- new_filename = None
- if line.startswith('Index:'):
- unused, new_filename = line.split(':', 1)
- new_filename = new_filename.strip()
- elif line.startswith('Property changes on:'):
- unused, temp_filename = line.split(':', 1)
- # When a file is modified, paths use '/' between directories, however
- # when a property is modified '\' is used on Windows. Make them the same
- # otherwise the file shows up twice.
- temp_filename = temp_filename.strip().replace('\\', '/')
- if temp_filename != filename:
- # File has property changes but no modifications, create a new diff.
- new_filename = temp_filename
- if new_filename:
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- filename = new_filename
- diff = [line]
- continue
- if diff is not None:
- diff.append(line)
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- return patches
-
-
-def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
- """Uploads a separate patch for each file in the diff output.
-
- Returns a list of [patch_key, filename] for each file.
- """
- patches = SplitPatch(data)
- rv = []
- for patch in patches:
- if len(patch[1]) > MAX_UPLOAD_SIZE:
- print("Not uploading the patch for " + patch[0] +
- " because the file is too large.")
- continue
- form_fields = [("filename", patch[0])]
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- files = [("data", "data.diff", patch[1])]
- ctype, body = EncodeMultipartFormData(form_fields, files)
- url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
- print("Uploading patch for " + patch[0])
- response_body = rpc_server.Send(url, body, content_type=ctype)
- lines = response_body.splitlines()
- if not lines or lines[0] != "OK":
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
- rv.append([lines[1], patch[0]])
- return rv
-
-
-def GuessVCSName():
- """Helper to guess the version control system.
-
- This examines the current directory, guesses which VersionControlSystem
- we're using, and returns an string indicating which VCS is detected.
-
- Returns:
- A pair (vcs, output). vcs is a string indicating which VCS was detected
- and is one of VCS_GIT, VCS_MERCURIAL, VCS_SUBVERSION, or VCS_UNKNOWN.
- output is a string containing any interesting output from the vcs
- detection routine, or None if there is nothing interesting.
- """
- def RunDetectCommand(vcs_type, command):
- """Helper to detect VCS by executing command.
-
- Returns:
- A pair (vcs, output) or None. Throws exception on error.
- """
- try:
- out, returncode = RunShellWithReturnCode(command)
- if returncode == 0:
- return (vcs_type, out.strip())
- except OSError as xxx_todo_changeme:
- (errcode, message) = xxx_todo_changeme.args
- if errcode != errno.ENOENT: # command not found code
- raise
-
- # Mercurial has a command to get the base directory of a repository
- # Try running it, but don't die if we don't have hg installed.
- # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
- res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"])
- if res != None:
- return res
-
- # Subversion has a .svn in all working directories.
- if os.path.isdir('.svn'):
- logging.info("Guessed VCS = Subversion")
- return (VCS_SUBVERSION, None)
-
- # Git has a command to test if you're in a git tree.
- # Try running it, but don't die if we don't have git installed.
- res = RunDetectCommand(VCS_GIT, ["git", "rev-parse",
- "--is-inside-work-tree"])
- if res != None:
- return res
-
- return (VCS_UNKNOWN, None)
-
-
-def GuessVCS(options):
- """Helper to guess the version control system.
-
- This verifies any user-specified VersionControlSystem (by command line
- or environment variable). If the user didn't specify one, this examines
- the current directory, guesses which VersionControlSystem we're using,
- and returns an instance of the appropriate class. Exit with an error
- if we can't figure it out.
-
- Returns:
- A VersionControlSystem instance. Exits if the VCS can't be guessed.
- """
- vcs = options.vcs
- if not vcs:
- vcs = os.environ.get("CODEREVIEW_VCS")
- if vcs:
- v = VCS_ABBREVIATIONS.get(vcs.lower())
- if v is None:
- ErrorExit("Unknown version control system %r specified." % vcs)
- (vcs, extra_output) = (v, None)
- else:
- (vcs, extra_output) = GuessVCSName()
-
- if vcs == VCS_MERCURIAL:
- if extra_output is None:
- extra_output = RunShell(["hg", "root"]).strip()
- return MercurialVCS(options, extra_output)
- elif vcs == VCS_SUBVERSION:
- return SubversionVCS(options)
- elif vcs == VCS_GIT:
- return GitVCS(options)
-
- ErrorExit(("Could not guess version control system. "
- "Are you in a working copy directory?"))
-
-
-def CheckReviewer(reviewer):
- """Validate a reviewer -- either a nickname or an email addres.
-
- Args:
- reviewer: A nickname or an email address.
-
- Calls ErrorExit() if it is an invalid email address.
- """
- if "@" not in reviewer:
- return # Assume nickname
- parts = reviewer.split("@")
- if len(parts) > 2:
- ErrorExit("Invalid email address: %r" % reviewer)
- assert len(parts) == 2
- if "." not in parts[1]:
- ErrorExit("Invalid email address: %r" % reviewer)
-
-
-def LoadSubversionAutoProperties():
- """Returns the content of [auto-props] section of Subversion's config file as
- a dictionary.
-
- Returns:
- A dictionary whose key-value pair corresponds the [auto-props] section's
- key-value pair.
- In following cases, returns empty dictionary:
- - config file doesn't exist, or
- - 'enable-auto-props' is not set to 'true-like-value' in [miscellany].
- """
- if os.name == 'nt':
- subversion_config = os.environ.get("APPDATA") + "\\Subversion\\config"
- else:
- subversion_config = os.path.expanduser("~/.subversion/config")
- if not os.path.exists(subversion_config):
- return {}
- config = ConfigParser()
- config.read(subversion_config)
- if (config.has_section("miscellany") and
- config.has_option("miscellany", "enable-auto-props") and
- config.getboolean("miscellany", "enable-auto-props") and
- config.has_section("auto-props")):
- props = {}
- for file_pattern in config.options("auto-props"):
- props[file_pattern] = ParseSubversionPropertyValues(
- config.get("auto-props", file_pattern))
- return props
- else:
- return {}
-
-def ParseSubversionPropertyValues(props):
- """Parse the given property value which comes from [auto-props] section and
- returns a list whose element is a (svn_prop_key, svn_prop_value) pair.
-
- See the following doctest for example.
-
- >>> ParseSubversionPropertyValues('svn:eol-style=LF')
- [('svn:eol-style', 'LF')]
- >>> ParseSubversionPropertyValues('svn:mime-type=image/jpeg')
- [('svn:mime-type', 'image/jpeg')]
- >>> ParseSubversionPropertyValues('svn:eol-style=LF;svn:executable')
- [('svn:eol-style', 'LF'), ('svn:executable', '*')]
- """
- key_value_pairs = []
- for prop in props.split(";"):
- key_value = prop.split("=")
- assert len(key_value) <= 2
- if len(key_value) == 1:
- # If value is not given, use '*' as a Subversion's convention.
- key_value_pairs.append((key_value[0], "*"))
- else:
- key_value_pairs.append((key_value[0], key_value[1]))
- return key_value_pairs
-
-
-def GetSubversionPropertyChanges(filename):
- """Return a Subversion's 'Property changes on ...' string, which is used in
- the patch file.
-
- Args:
- filename: filename whose property might be set by [auto-props] config.
-
- Returns:
- A string like 'Property changes on |filename| ...' if given |filename|
- matches any entries in [auto-props] section. None, otherwise.
- """
- global svn_auto_props_map
- if svn_auto_props_map is None:
- svn_auto_props_map = LoadSubversionAutoProperties()
-
- all_props = []
- for file_pattern, props in svn_auto_props_map.items():
- if fnmatch.fnmatch(filename, file_pattern):
- all_props.extend(props)
- if all_props:
- return FormatSubversionPropertyChanges(filename, all_props)
- return None
-
-
-def FormatSubversionPropertyChanges(filename, props):
- """Returns Subversion's 'Property changes on ...' strings using given filename
- and properties.
-
- Args:
- filename: filename
- props: A list whose element is a (svn_prop_key, svn_prop_value) pair.
-
- Returns:
- A string which can be used in the patch file for Subversion.
-
- See the following doctest for example.
-
- >>> print(FormatSubversionPropertyChanges('foo.cc', [('svn:eol-style', 'LF')]))
- Property changes on: foo.cc
- ___________________________________________________________________
- Added: svn:eol-style
- + LF
- <BLANKLINE>
- """
- prop_changes_lines = [
- "Property changes on: %s" % filename,
- "___________________________________________________________________"]
- for key, value in props:
- prop_changes_lines.append("Added: " + key)
- prop_changes_lines.append(" + " + value)
- return "\n".join(prop_changes_lines) + "\n"
-
-
-def RealMain(argv, data=None):
- """The real main function.
-
- Args:
- argv: Command line arguments.
- data: Diff contents. If None (default) the diff is generated by
- the VersionControlSystem implementation returned by GuessVCS().
-
- Returns:
- A 2-tuple (issue id, patchset id).
- The patchset id is None if the base files are not uploaded by this
- script (applies only to SVN checkouts).
- """
- options, args = parser.parse_args(argv[1:])
- global verbosity
- verbosity = options.verbose
- if verbosity >= 3:
- logging.getLogger().setLevel(logging.DEBUG)
- elif verbosity >= 2:
- logging.getLogger().setLevel(logging.INFO)
-
- vcs = GuessVCS(options)
-
- base = options.base_url
- if isinstance(vcs, SubversionVCS):
- # Guessing the base field is only supported for Subversion.
- # Note: Fetching base files may become deprecated in future releases.
- guessed_base = vcs.GuessBase(options.download_base)
- if base:
- if guessed_base and base != guessed_base:
- print("Using base URL \"%s\" from --base_url instead of \"%s\"" % \
- (base, guessed_base))
- else:
- base = guessed_base
-
- if not base and options.download_base:
- options.download_base = True
- logging.info("Enabled upload of base file")
- if not options.assume_yes:
- vcs.CheckForUnknownFiles()
- if data is None:
- data = vcs.GenerateDiff(args)
- data = vcs.PostProcessDiff(data)
- files = vcs.GetBaseFiles(data)
- if verbosity >= 1:
- print("Upload server:", options.server, "(change with -s/--server)")
- if options.issue:
- prompt = "Message describing this patch set: "
- else:
- prompt = "New issue subject: "
- message = options.message or input(prompt).strip()
- if not message:
- ErrorExit("A non-empty message is required")
- rpc_server = GetRpcServer(options.server,
- options.email,
- options.host,
- options.save_cookies,
- options.account_type)
- form_fields = [("subject", message)]
- if base:
- b = urlparse(base)
- username, netloc = urlsplituser(b.netloc)
- if username:
- logging.info("Removed username from base URL")
- base = urlunparse((b.scheme, netloc, b.path, b.params,
- b.query, b.fragment))
- form_fields.append(("base", base))
- if options.issue:
- form_fields.append(("issue", str(options.issue)))
- if options.email:
- form_fields.append(("user", options.email))
- if options.reviewers:
- for reviewer in options.reviewers.split(','):
- CheckReviewer(reviewer)
- form_fields.append(("reviewers", options.reviewers))
- if options.cc:
- for cc in options.cc.split(','):
- CheckReviewer(cc)
- form_fields.append(("cc", options.cc))
- description = options.description
- if options.description_file:
- if options.description:
- ErrorExit("Can't specify description and description_file")
- file = open(options.description_file, 'r')
- description = file.read()
- file.close()
- if description:
- form_fields.append(("description", description))
- # Send a hash of all the base file so the server can determine if a copy
- # already exists in an earlier patchset.
- base_hashes = ""
- for file, info in files.items():
- if not info[0] is None:
- checksum = md5(info[0]).hexdigest()
- if base_hashes:
- base_hashes += "|"
- base_hashes += checksum + ":" + file
- form_fields.append(("base_hashes", base_hashes))
- if options.private:
- if options.issue:
- print("Warning: Private flag ignored when updating an existing issue.")
- else:
- form_fields.append(("private", "1"))
- # If we're uploading base files, don't send the email before the uploads, so
- # that it contains the file status.
- if options.send_mail and options.download_base:
- form_fields.append(("send_mail", "1"))
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- if len(data) > MAX_UPLOAD_SIZE:
- print("Patch is large, so uploading file patches separately.")
- uploaded_diff_file = []
- form_fields.append(("separate_patches", "1"))
- else:
- uploaded_diff_file = [("data", "data.diff", data)]
- ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
- response_body = rpc_server.Send("/upload", body, content_type=ctype)
- patchset = None
- if not options.download_base or not uploaded_diff_file:
- lines = response_body.splitlines()
- if len(lines) >= 2:
- msg = lines[0]
- patchset = lines[1].strip()
- patches = [x.split(" ", 1) for x in lines[2:]]
- else:
- msg = response_body
- else:
- msg = response_body
- StatusUpdate(msg)
- if not response_body.startswith("Issue created.") and \
- not response_body.startswith("Issue updated."):
- sys.exit(0)
- issue = msg[msg.rfind("/")+1:]
-
- if not uploaded_diff_file:
- result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
- if not options.download_base:
- patches = result
-
- if not options.download_base:
- vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
- if options.send_mail:
- rpc_server.Send("/" + issue + "/mail", payload="")
- return issue, patchset
-
-
-def main():
- try:
- logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
- "%(lineno)s %(message)s "))
- os.environ['LC_ALL'] = 'C'
- RealMain(sys.argv)
- except KeyboardInterrupt:
- print()
- StatusUpdate("Interrupted.")
- sys.exit(1)
-
-
-if __name__ == "__main__":
- main()
-
diff --git a/rpm/scons.spec.in b/rpm/scons.spec.in
index 312eb44c..9b97a07d 100644
--- a/rpm/scons.spec.in
+++ b/rpm/scons.spec.in
@@ -14,8 +14,8 @@ Group: Development/Tools
BuildRoot: %{_tmppath}/%{name}-buildroot
Prefix: %{_prefix}
BuildArchitectures: noarch
-Vendor: Steven Knight <knight@scons.org>
-Packager: Steven Knight <knight@scons.org>
+Vendor: The SCons Development Team <scons-dev@scons.org>
+Packager: The SCons Development Team <scons-dev@scons.org>
Requires: python >= 2.4
Url: http://www.scons.org/
diff --git a/src/Announce.txt b/src/Announce.txt
index cccf6c9d..83fe4218 100644
--- a/src/Announce.txt
+++ b/src/Announce.txt
@@ -19,7 +19,7 @@ effectively, please go to http://scons.org/lists.php#users to sign up for
the scons-users mailing list.
-RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
+RELEASE 2.3.2.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
Please consult the RELEASE.txt file for a summary of changes since the last
release and consult the CHANGES.txt file for complete a list of changes
@@ -28,6 +28,27 @@ RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
Please note the following important changes since release 2.3.0:
+ -- BitKeeper, CVS, Perforce, RCS, SCCS are deprecated from the
+ default toolset and will be removed from the default toolset
+ in future SCons versions to speed up SCons initialization.
+ The tools themselves continue to be supported.
+
+ -- Support for Visual Studio 12.0Exp and 2013
+
+ -- Revamp of D language support, focusing on D v2.
+ D v1 is now deprecated.
+
+ -- Fixed NoClean() for multi-target builders.
+
+ -- RPM and m4 are no longer in the default toolset on Windows.
+ Should improve startup speed.
+
+ -- TeX fixes: -synctex=1 and cleaning auxiliary files.
+
+ -- Fixes to the Docbook tool.
+
+ Please note the following important changes since release 2.3.0:
+
-- Fix failure to relink when LINKCOM or libs change, introduced in
2.3.0.
@@ -319,7 +340,7 @@ RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
Python 1.5, 2.0 or 2.1 release or sub-release:
scons: warning: Support for pre-2.2 Python (VERSION) is deprecated.
- If this will cause hardship, contact dev@scons.tigris.org.
+ If this will cause hardship, contact scons-dev@scons.org
You may disable all warnings about deprecated features by adding
the option "--warn=no-deprecated" to the command line or to the
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index f65dfd54..aaf3bc87 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -9,6 +9,47 @@ RELEASE 2.3.2.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
From Neal Becker and Stefan Zimmermann:
- Python 3 port and compatibility
+ From Anatoly Techtonik:
+ - Do not fail on EnsureSConsVersion when running from checkout
+
+ From Kendrick Boyd and Rob Managan:
+ - Fixed the newglossary action to work with VariantDir (LaTeX).
+
+ From Manuel Francisco Naranjo:
+ - Added a default for the BUILDERS environment variable,
+ to prevent not defined exception on a Clone().
+
+ From Andrew Featherstone:
+ - Added description of CheckTypeSize method (#1991).
+ - Fixed handling of CPPDEFINE var in Append()
+ for several list-dict combinations (#2900).
+
+ From William Blevins:
+ - Added test for Java derived-source dependency tree generation.
+ - Added Copy Action symlink soft-copy support (#2395).
+ - Various contributions to the documentation (UserGuide).
+
+RELEASE 2.3.2
+
+ From veon on bitbucket:
+ - Fixed handling of nested ifs in CPP scanner PreProcessor class.
+
+ From Michael Haubenwallner:
+ - Respect user's CC/CXX values; don't always overwrite in generate()
+ - Delegate linker Tool.exists() to CC/CXX Tool.exists().
+
+ From Amir Szekely:
+ - Fixed NoClean() for multi-target builders (#2353).
+
+ From Russel Winder:
+ - Revamp of the D language support. Tools for DMD, GDC and LDC provided
+ and integrated with the C and C++ linking. NOTE: This is only tested
+ with D v2. Support for D v1 is now deprecated.
+
+ From Paweł Tomulik:
+ - Fix SConf tests that write output
+
+>>>>>>> other
From Gary Oberbrunner:
- get default RPM architecture more robustly when building RPMs
@@ -27,9 +68,21 @@ RELEASE 2.3.2.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
that were failing because of this extra line in the output
* error message when SCons import fails now lists lookup paths
- Remove support for QMTest harness from runtest.py
+ - Remove RPM and m4 from default tools on Windows
+ - BitKeeper, CVS, Perforce, RCS, SCCS are deprecated from default
+ tools and will be removed in future SCons versions to speed up
+ SCons initialization (it will still be possible to use these tools
+ explicitly)
From Dirk Baechle:
- Update XML doc editor configuration
+ - Fix: Allow varlist to be specified as list of strings for Actions (#2754)
+
+ From Rob Managan:
+ - Updated the TeX builder to support use of the -synctex=1
+ option and the files it creates.
+ - Updated the TeX builder to correctly clean auxiliary files when
+ the biblatex package is used.
RELEASE 2.3.1
diff --git a/src/README.txt b/src/README.txt
index ebc68fcf..5d880c20 100644
--- a/src/README.txt
+++ b/src/README.txt
@@ -174,7 +174,7 @@ Submission page:
You can also send mail to the SCons developers' mailing list:
- dev@scons.tigris.org
+ scons-dev@scons.org
But even if you send email to the mailing list please make sure that you
ALSO submit a bug report to the project page bug tracker, because bug
@@ -187,11 +187,11 @@ MAILING LISTS
An active mailing list for users of SCons is available. You may send
questions or comments to the list at:
- users@scons.tigris.org
+ scons-users@scons.org
You may subscribe to the mailing list by sending email to:
- users-subscribe@scons.tigris.org
+ scons-users-join@scons.org
There is also a low-volume mailing list available for announcements
about SCons. Subscribe by sending email to:
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 63445c2f..7249af47 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -1,80 +1,51 @@
- A new SCons release, 2.3.1, is now available
+ A new SCons release, 2.3.2, is now available
on the SCons download page:
http://www.scons.org/download.php
- This release adds several new features and fixes many issues,
- including a serious regression in linking (failure to re-link if
- linker options are changed).
+ This is a maintenance release, focusing on bug fixes.
- Here is a summary of the changes since 2.3.0:
+ Here is a summary of the changes since 2.3.1:
NEW FUNCTIONALITY
- - Add Pseudo command to mark targets which should not exist after
- they are built.
- - Add support for a readonly cache (--cache-readonly)
- - Added cyglink linker that uses Cygwin naming conventions for
- shared libraries and automatically generates import libraries.
- - Added optional ZIPROOT to Zip tool.
+ - Support for Visual Studio 12.0Exp and 2013 (12.0).
DEPRECATED FUNCTIONALITY
- -
+ - RPM and m4 are no longer in the default toolset on Windows.
+ - BitKeeper, CVS, Perforce, RCS, SCCS are deprecated from the
+ default toolset and will be removed from the default toolset
+ in future SCons versions.
+ - D language, version 1, is now deprecated. Version 2 is
+ supported.
CHANGED/ENHANCED EXISTING FUNCTIONALITY
- - DocBook tool can now output EPUB format
- - Allow multiple options to be specified with --debug=a,b,c
- - Update bootstrap.py so it can be used from any dir, to run
- SCons from a source (non-installed) dir.
- - Added release_target_info() to File nodes, which helps to
- reduce memory consumption in clean builds and update runs
- of large projects.
- - Print full stack on certain errors, for debugging.
- - Improve documentation for Textfile builder.
+ - Revamp of D language support.
+ Tools for DMD, GDC and LDC are provided, and integrated
+ with the C and C++ linking.
+ - TeX builder now supports -synctex=1
+ - TeX builder cleans auxiliary files correctly with biblatex.
FIXES
- - Stop leaking file handles to subprocesses by switching to using subprocess
- always.
- - Generally try harder to print out a message on build errors
- - Added a switch to warn on missing targets
- - Always print stats if requested
- - Check for 8.3 filenames on cygwin as well as win32 to make variant_dir work properly.
- - Make sure SharedLibrary depends on all dependent libs (by depending on SHLINKCOM)
- - Fixed the setup of linker flags for a versioned SharedLibrary
- under OpenBSD (#2916).
- - Improve error if Visual Studio bat file not found.
- - Allow Subst.Literal string objects to be compared with each other,
- so they work better in AddUnique() and Remove().
- - Fixed the handling of long options in the command-line
- parsing (#2929).
- - Fixed misspelled variable in intelc.py (#2928).
- - VS2012 & VS2010: Resolve initialization issues by adding path to reg.exe
- in shell used to run batch files.
- - MSVC Support: fixed defaulting TARGET_ARCH to HOST_ARCH. It should be
- None if not explicitly set.
- - MSVC: Fixed issue where if more than one Architectures compilers are
- detected, it would take the last one found, and not the first.
- - Fixed spelling errors in MAN pages (#2897).
- - Fixed description of ignore_case for EnumVariable in the
- MAN page (#2774).
+ - Fixed handling of nested ifs in CPP scanner PreProcessor class.
+ - Respect user's CC/CXX values; don't always overwrite in generate()
+ - Delegate linker Tool.exists() to CC/CXX Tool.exists().
+ - Fixed NoClean() for multi-target builders (#2353).
+ - Fix SConf tests that write output
+ - get default RPM architecture more robustly when building RPMs
+ - Allow varlist to be specified as list of strings for Actions (#2754)
+ - Fixes to Docbook tool
PACKAGING
- - No changes
+ - Update XML doc editor configuration
DEVELOPMENT
- - Count statistics of instances are now collected only when
- the --debug=count command-line option is used (#2922).
- - Test harness: fail_test() can now print a message to help debugging.
- - Require rpmbuild when building SCons package.
- - Replaced old SGML-based documentation toolchain with a more modern
- approach, that also requires less external dependencies (programs and
- Python packages). Added a customized Docbook XSD for strict validation of
- all input XML files.
+ - Improvements to running scons.py from the source tree
Thanks to:
Dirk Baechle,
@@ -89,8 +60,10 @@ Thanks to:
Luca Falavigna,
Andrew Featherstone,
Alexandre Feblot,
+ Shane Gannon,
Alexander Goomenyuk,
Justin Gullingsrud,
+ Michael Haubenwallner,
Joshua Hughes,
Alexey Klimkin,
Steven Knight,
@@ -109,10 +82,13 @@ Thanks to:
smallbub on Bitbucket,
Sohail Somani,
Stefan Sperling,
+ Amir Szekely,
Tom Tanner,
Anatoly Techtonik,
Bogdan Tenea,
Paweł Tomulik,
+ Sye van der Veen,
+ veon on bitbucket,
Greg Ward,
Allen Weeks,
Russel Winder,
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 0afda501..f62d16e7 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -65,6 +65,7 @@ SCons/Tool/cc.py
SCons/Tool/cyglink.py
SCons/Tool/cvf.py
SCons/Tool/CVS.py
+SCons/Tool/DCommon.py
SCons/Tool/default.py
SCons/Tool/dmd.py
SCons/Tool/docbook/__init__.py
@@ -82,6 +83,7 @@ SCons/Tool/g++.py
SCons/Tool/g77.py
SCons/Tool/gas.py
SCons/Tool/gcc.py
+SCons/Tool/gdc.py
SCons/Tool/gfortran.py
SCons/Tool/gnulink.py
SCons/Tool/gs.py
@@ -102,6 +104,7 @@ SCons/Tool/JavaCommon.py
SCons/Tool/javac.py
SCons/Tool/javah.py
SCons/Tool/latex.py
+SCons/Tool/ldc.py
SCons/Tool/lex.py
SCons/Tool/link.py
SCons/Tool/linkloc.py
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index cec241de..415cc9a8 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -337,7 +337,7 @@ def _do_create_keywords(args, kw):
'You must either pass a string or a callback which '
'accepts (target, source, env) as parameters.')
if len(args) > 1:
- kw['varlist'] = args[1:] + kw['varlist']
+ kw['varlist'] = tuple(SCons.Util.flatten(args[1:])) + kw['varlist']
if kw.get('strfunction', _null) is not _null \
and kw.get('cmdstr', _null) is not _null:
raise SCons.Errors.UserError(
@@ -686,6 +686,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
class f(object):
def read(self): return ''
def readline(self): return ''
+ def __iter__(self): return iter(())
stdout = stderr = f()
return dummyPopen(e)
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 7815413b..8038f7c0 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -211,6 +211,9 @@ def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
assert a.varlist == ('a', 'b', 'c'), a.varlist
+ a = call_action((cmd, cmdstrfunc, ['a', 'b', 'c']))
+ assert a.varlist == ('a', 'b', 'c'), a.varlist
+
kw['varlist'] = 'foo'
a = call_action((cmd, cmdstrfunc))
assert a.varlist == ('foo',), a.varlist
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index 92f23445..2eb9c86d 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -144,6 +144,9 @@ ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
+DAction = SCons.Action.Action("$DCOM", "$DCOMSTR")
+ShDAction = SCons.Action.Action("$SHDCOM", "$SHDCOMSTR")
+
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
@@ -178,20 +181,38 @@ def chmod_strfunc(dest, mode):
Chmod = ActionFactory(chmod_func, chmod_strfunc)
-def copy_func(dest, src):
+def copy_func(dest, src, symlinks=True):
+ """
+ If symlinks (is true), then a symbolic link will be
+ shallow copied and recreated as a symbolic link; otherwise, copying
+ a symbolic link will be equivalent to copying the symbolic link's
+ final target regardless of symbolic link depth.
+ """
+
+ dest = str(dest)
+ src = str(src)
+
SCons.Node.FS.invalidate_node_memos(dest)
if SCons.Util.is_List(src) and os.path.isdir(dest):
for file in src:
shutil.copy2(file, dest)
+ return 0
+ elif os.path.islink(src):
+ linkto = os.readlink(src)
+ if symlinks:
+ return os.symlink(linkto, dest)
+ else:
+ return copy_func(dest, linkto, symlinks)
elif os.path.isfile(src):
shutil.copy2(src, dest)
+ return 0
else:
- shutil.copytree(src, dest, 1)
- return 0
+ return shutil.copytree(src, dest, symlinks)
-Copy = ActionFactory(copy_func,
- lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
- convert=str)
+Copy = ActionFactory(
+ copy_func,
+ lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
+)
def delete_func(dest, must_exist=0):
SCons.Node.FS.invalidate_node_memos(dest)
@@ -321,7 +342,7 @@ def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
where it finds them. This is used by tools (like the GNU linker)
that need to turn something like 'libfoo.a' into '-lfoo'.
"""
-
+
if not itms:
return itms
@@ -335,7 +356,7 @@ def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
c = env_c
else:
c = _concat_ixes
-
+
stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
@@ -413,7 +434,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
"""
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
-
+
class NullCmdGenerator(object):
"""This is a callable class that can be used in place of other
command generators if you don't want them to do anything.
@@ -449,7 +470,7 @@ class Variable_Method_Caller(object):
self.method = method
def __call__(self, *args, **kw):
try: 1//0
- except ZeroDivisionError:
+ except ZeroDivisionError:
# Don't start iterating with the current stack-frame to
# prevent creating reference cycles (f_back is safe).
frame = sys.exc_info()[2].tb_frame.f_back
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 737289b0..59390f76 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -1206,7 +1206,13 @@ class Base(SubstitutionEnvironment):
# based on what we think the value looks like.
if SCons.Util.is_List(val):
if key == 'CPPDEFINES':
- orig = list(orig.items())
+ tmp = []
+ for (k, v) in orig.iteritems():
+ if v is not None:
+ tmp.append((k, v))
+ else:
+ tmp.append((k,))
+ orig = tmp
orig += val
self._dict[key] = orig
else:
@@ -1286,8 +1292,15 @@ class Base(SubstitutionEnvironment):
else:
tmp.append((i,))
val = tmp
+ # Construct a list of (key, value) tuples.
if SCons.Util.is_Dict(dk):
- dk = list(dk.items())
+ tmp = []
+ for (k, v) in dk.iteritems():
+ if v is not None:
+ tmp.append((k, v))
+ else:
+ tmp.append((k,))
+ dk = tmp
elif SCons.Util.is_String(dk):
dk = [(dk,)]
else:
@@ -1327,8 +1340,15 @@ class Base(SubstitutionEnvironment):
else:
tmp.append((i,))
dk = tmp
+ # Construct a list of (key, value) tuples.
if SCons.Util.is_Dict(val):
- val = list(val.items())
+ tmp = []
+ for (k, v) in val.iteritems():
+ if v is not None:
+ tmp.append((k, v))
+ else:
+ tmp.append((k,))
+ val = tmp
elif SCons.Util.is_String(val):
val = [(val,)]
if delete_existing:
@@ -1351,7 +1371,13 @@ class Base(SubstitutionEnvironment):
if SCons.Util.is_String(dk):
dk = [dk]
elif SCons.Util.is_Dict(dk):
- dk = list(dk.items())
+ tmp = []
+ for (k, v) in dk.iteritems():
+ if v is not None:
+ tmp.append((k, v))
+ else:
+ tmp.append((k,))
+ dk = tmp
if SCons.Util.is_String(val):
if val in dk:
val = []
@@ -1378,10 +1404,8 @@ class Base(SubstitutionEnvironment):
(like a function). There are no references to any mutable
objects in the original Environment.
"""
- try:
- builders = self._dict['BUILDERS']
- except KeyError:
- pass
+
+ builders = self._dict.get('BUILDERS', {})
clone = copy.copy(self)
# BUILDERS is not safe to do a simple copy
@@ -1803,8 +1827,8 @@ class Base(SubstitutionEnvironment):
pass
elif SCons.Util.is_String(pathext):
pathext = self.subst(pathext)
- prog = self.subst(prog)
- path = SCons.Util.WhereIs(prog, path, pathext, reject)
+ prog = SCons.Util.CLVar(self.subst(prog)) # support "program --with-args"
+ path = SCons.Util.WhereIs(prog[0], path, pathext, reject)
if path: return path
return None
@@ -2149,7 +2173,7 @@ class Base(SubstitutionEnvironment):
def SourceCode(self, entry, builder):
"""Arrange for a source code builder for (part of) a tree."""
msg = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceCodeWarning, msg)
entries = self.arg2nodes(entry, self.fs.Entry)
for entry in entries:
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index c6e1f3b8..2a3852f2 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -1887,6 +1887,11 @@ def generate(env):
env = env.Clone(KEY_THAT_I_WANT=6, tools=[my_tool])
assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT']
+ # test for pull request #150
+ env = self.TestEnvironment()
+ env._dict.pop('BUILDERS')
+ assert env.has_key('BUILDERS') is False
+ env2 = env.Clone()
def test_Copy(self):
"""Test copying using the old env.Copy() method"""
diff --git a/src/engine/SCons/Platform/aix.py b/src/engine/SCons/Platform/aix.py
index f6853b55..0266dc62 100644
--- a/src/engine/SCons/Platform/aix.py
+++ b/src/engine/SCons/Platform/aix.py
@@ -33,10 +33,14 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
+import subprocess
from . import posix
-def get_xlc(env, xlc=None, xlc_r=None, packages=[]):
+import SCons.Util
+import SCons.Action
+
+def get_xlc(env, xlc=None, packages=[]):
# Use the AIX package installer tool lslpp to figure out where a
# given xl* compiler is installed and what version it is.
xlcPath = None
@@ -44,18 +48,30 @@ def get_xlc(env, xlc=None, xlc_r=None, packages=[]):
if xlc is None:
xlc = env.get('CC', 'xlc')
- if xlc_r is None:
- xlc_r = xlc + '_r'
+ if SCons.Util.is_List(xlc):
+ xlc = xlc[0]
for package in packages:
- cmd = "lslpp -fc " + package + " 2>/dev/null | egrep '" + xlc + "([^-_a-zA-Z0-9].*)?$'"
- line = os.popen(cmd).readline()
- if line:
- v, p = line.split(':')[1:3]
- xlcVersion = v.split()[1]
- xlcPath = p.split()[0]
- xlcPath = xlcPath[:xlcPath.rindex('/')]
- break
- return (xlcPath, xlc, xlc_r, xlcVersion)
+ # find the installed filename, which may be a symlink as well
+ pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package],
+ stdin = 'devnull',
+ stderr = 'devnull',
+ stdout = subprocess.PIPE)
+ # output of lslpp is something like this:
+ # #Path:Fileset:File
+ # /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/exe/xlCcpp
+ # /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/bin/xlc_r -> /usr/vac/bin/xlc
+ for line in pipe.stdout:
+ if xlcPath:
+ continue # read everything to let lslpp terminate
+ fileset, filename = line.split(':')[1:3]
+ filename = filename.split()[0]
+ if ('/' in xlc and filename == xlc) \
+ or ('/' not in xlc and filename.endswith('/' + xlc)):
+ xlcVersion = fileset.split()[1]
+ xlcPath, sep, xlc = filename.rpartition('/')
+ pass
+ pass
+ return (xlcPath, xlc, xlcVersion)
def generate(env):
posix.generate(env)
diff --git a/src/engine/SCons/Platform/posix.py b/src/engine/SCons/Platform/posix.py
index 2e21e5ab..7e69a7c3 100644
--- a/src/engine/SCons/Platform/posix.py
+++ b/src/engine/SCons/Platform/posix.py
@@ -113,6 +113,10 @@ def generate(env):
# This platform supports RPATH specifications.
env['__RPATH'] = '$_RPATH'
+ # GDC is GCC family, but DMD and LDC have different options.
+ # Must be able to have GCC and DMD work in the same build, so:
+ env['__DRPATH'] = '$_DRPATH'
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index be0b9c17..0e6967f1 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -1,6 +1,14 @@
"""SCons.SConf
Autoconf-like configuration support.
+
+In other words, SConf allows to run tests on the build machine to detect
+capabilities of system and do some things based on result: generate config
+files, header files for C/C++, update variables in environment.
+
+Tests on the build system can detect if compiler sees header files, if
+libraries are installed, if some command line options are supported etc.
+
"""
#
@@ -111,16 +119,22 @@ def _createConfigH(target, source, env):
def _stringConfigH(target, source, env):
return "scons: Configure: creating " + str(target[0])
-def CreateConfigHBuilder(env):
- """Called just before the building targets phase begins."""
+
+def NeedConfigHBuilder():
if len(_ac_config_hs) == 0:
- return
+ return False
+ else:
+ return True
+
+def CreateConfigHBuilder(env):
+ """Called if necessary just before the building targets phase begins."""
action = SCons.Action.Action(_createConfigH,
_stringConfigH)
sconfigHBld = SCons.Builder.Builder(action=action)
env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} )
for k in _ac_config_hs.keys():
env.SConfigHBuilder(k, env.Value(_ac_config_hs[k]))
+
class SConfWarning(SCons.Warnings.Warning):
pass
@@ -181,7 +195,13 @@ class Streamer(object):
def write(self, str):
if self.orig:
self.orig.write(str)
- self.s.write(str)
+ try:
+ self.s.write(str)
+ except TypeError as e:
+ if e.message.startswith('unicode argument expected'):
+ self.s.write(str.decode())
+ else:
+ raise
def writelines(self, lines):
for l in lines:
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index 1357e7f5..3ef88c7b 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -316,7 +316,7 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask):
class CleanTask(SCons.Taskmaster.AlwaysTask):
"""An SCons clean task."""
- def fs_delete(self, path, pathstr, remove=1):
+ def fs_delete(self, path, pathstr, remove=True):
try:
if os.path.lexists(path):
if os.path.isfile(path) or os.path.islink(path):
@@ -343,37 +343,41 @@ class CleanTask(SCons.Taskmaster.AlwaysTask):
except (IOError, OSError) as e:
print_("scons: Could not remove '%s':" % pathstr, e.strerror)
- def show(self):
+ def _get_files_to_clean(self):
+ result = []
target = self.targets[0]
- if (target.has_builder() or target.side_effect) and not target.noclean:
- for t in self.targets:
- if not t.isdir():
- display("Removed " + str(t))
- if target in SCons.Environment.CleanTargets:
- files = SCons.Environment.CleanTargets[target]
- for f in files:
- self.fs_delete(f.abspath, str(f), 0)
+ if target.has_builder() or target.side_effect:
+ result = [t for t in self.targets if not t.noclean]
+ return result
- def remove(self):
+ def _clean_targets(self, remove=True):
target = self.targets[0]
- if (target.has_builder() or target.side_effect) and not target.noclean:
- for t in self.targets:
- try:
- removed = t.remove()
- except OSError as e:
- # An OSError may indicate something like a permissions
- # issue, an IOError would indicate something like
- # the file not existing. In either case, print a
- # message and keep going to try to remove as many
- # targets aa possible.
- print_("scons: Could not remove '%s':" % str(t), e.strerror)
- else:
- if removed:
- display("Removed " + str(t))
if target in SCons.Environment.CleanTargets:
files = SCons.Environment.CleanTargets[target]
for f in files:
- self.fs_delete(f.abspath, str(f))
+ self.fs_delete(f.abspath, str(f), remove)
+
+ def show(self):
+ for t in self._get_files_to_clean():
+ if not t.isdir():
+ display("Removed " + str(t))
+ self._clean_targets(remove=False)
+
+ def remove(self):
+ for t in self._get_files_to_clean():
+ try:
+ removed = t.remove()
+ except OSError, e:
+ # An OSError may indicate something like a permissions
+ # issue, an IOError would indicate something like
+ # the file not existing. In either case, print a
+ # message and keep going to try to remove as many
+ # targets aa possible.
+ print(("scons: Could not remove '%s':" % str(t), e.strerror)
+ else:
+ if removed:
+ display("Removed " + str(t))
+ self._clean_targets(remove=True)
execute = remove
@@ -1025,13 +1029,17 @@ def _main(parser):
# in case they disabled the warning in the SConscript files.
if python_version_deprecated():
msg = "Support for pre-%s Python version (%s) is deprecated.\n" + \
- " If this will cause hardship, contact dev@scons.tigris.org."
+ " If this will cause hardship, contact scons-dev@scons.org"
deprecated_version_string = ".".join(map(str, deprecated_python_version))
SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning,
msg % (deprecated_version_string, python_version_string()))
if not options.help:
- SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
+ # [ ] Clarify why we need to create Builder here at all, and
+ # why it is created in DefaultEnvironment
+ # https://bitbucket.org/scons/scons/commits/d27a548aeee8ad5e67ea75c2d19a7d305f784e30
+ if SCons.SConf.NeedConfigHBuilder():
+ SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
# Now re-parse the command-line options (any to the left of a '--'
# argument, that is) with any user-defined command-line options that
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 3ee9464d..d50951da 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -461,6 +461,10 @@ class SConsEnvironment(SCons.Environment.Base):
def EnsureSConsVersion(self, major, minor, revision=0):
"""Exit abnormally if the SCons version is not late enough."""
+ if SCons.__version__ == '__VERSION__':
+ SCons.Warnings.warn(SCons.Warnings.DevelopmentVersionWarning,
+ "EnsureSConsVersion is ignored for development version")
+ return
scons_ver = self._get_major_minor_revision(SCons.__version__)
if scons_ver < (major, minor, revision):
if revision:
diff --git a/src/engine/SCons/Tool/DCommon.py b/src/engine/SCons/Tool/DCommon.py
new file mode 100644
index 00000000..02a5e732
--- /dev/null
+++ b/src/engine/SCons/Tool/DCommon.py
@@ -0,0 +1,56 @@
+"""SCons.Tool.DCommon
+
+Common code for the various D tools.
+
+Coded by Russel Winder (russel@winder.org.uk)
+2012-09-06
+"""
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+
+def isD(env, source):
+ if not source:
+ return 0
+ for s in source:
+ if s.sources:
+ ext = os.path.splitext(str(s.sources[0]))[1]
+ if ext == '.d':
+ return 1
+ return 0
+
+def addDPATHToEnv(env, executable):
+ dPath = env.WhereIs(executable)
+ if dPath:
+ phobosDir = dPath[:dPath.rindex(executable)] + '/../src/phobos'
+ if os.path.isdir(phobosDir):
+ env.Append(DPATH=[phobosDir])
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 156ef975..8b13f9f9 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -65,7 +65,7 @@ if java_parsing:
def __init__(self, version=default_java_version):
if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '1.7',
- '5', '6'):
+ '1.8', '5', '6'):
msg = "Java version %s not supported" % version
raise NotImplementedError(msg)
@@ -171,7 +171,7 @@ if java_parsing:
if self.version in ('1.1', '1.2', '1.3', '1.4'):
clazz = self.listClasses[0]
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
- elif self.version in ('1.5', '1.6', '1.7', '5', '6'):
+ elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6'):
self.stackAnonClassBrackets.append(self.brackets)
className = []
className.extend(self.listClasses)
@@ -244,7 +244,8 @@ if java_parsing:
return self
# If that's an inner class which is declared in a method, it
# requires an index prepended to the class-name, e.g.
- # 'Foo$1Inner' (Tigris Issue 2087)
+ # 'Foo$1Inner'
+ # http://scons.tigris.org/issues/show_bug.cgi?id=2087
if self.outer_state.localClasses and \
self.outer_state.stackBrackets[-1] > \
self.outer_state.stackBrackets[-2]+1:
diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py
index dbfada71..bd7bbd04 100644
--- a/src/engine/SCons/Tool/MSCommon/vc.py
+++ b/src/engine/SCons/Tool/MSCommon/vc.py
@@ -107,7 +107,7 @@ def get_host_target(env):
# PROCESSOR_ARCHITECTURE.
if not host_platform:
host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
-
+
# Retain user requested TARGET_ARCH
req_target_platform = env.get('TARGET_ARCH')
debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform)
@@ -117,7 +117,7 @@ def get_host_target(env):
target_platform = req_target_platform
else:
target_platform = host_platform
-
+
try:
host = _ARCH_TO_CANONICAL[host_platform.lower()]
except KeyError as e:
@@ -164,7 +164,7 @@ _VCVER_TO_PRODUCT_DIR = {
'6.0': [
r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
}
-
+
def msvc_version_to_maj_min(msvc_version):
msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
@@ -244,7 +244,7 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
pdir = find_vc_pdir(msvc_version)
if pdir is None:
raise NoVersionFound("No version of Visual Studio found")
-
+
debug('vc.py: find_batch_file() pdir:%s'%pdir)
# filter out e.g. "Exp" from the version name
@@ -262,7 +262,7 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
if not os.path.exists(batfilename):
debug("Not found: %s" % batfilename)
batfilename = None
-
+
installed_sdks=get_installed_sdks()
for _sdk in installed_sdks:
sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch)
@@ -270,7 +270,7 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
debug("vc.py:find_batch_file() not found:%s"%_sdk)
else:
sdk_bat_file_path = os.path.join(pdir,sdk_bat_file)
- if os.path.exists(sdk_bat_file_path):
+ if os.path.exists(sdk_bat_file_path):
debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path)
return (batfilename,sdk_bat_file_path)
return (batfilename,None)
@@ -305,8 +305,21 @@ def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
__INSTALLED_VCS_RUN = None
+# Running these batch files isn't cheap: most of the time spent in
+# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
+# in multiple environments, for example:
+# env1 = Environment(tools='msvs')
+# env2 = Environment(tools='msvs')
+# we can greatly improve the speed of the second and subsequent Environment
+# (or Clone) calls by memoizing the environment variables set by vcvars*.bat.
+script_env_stdout_cache = {}
def script_env(script, args=None):
- stdout = common.get_output(script, args)
+ cache_key = (script, args)
+ stdout = script_env_stdout_cache.get(cache_key, None)
+ if stdout is None:
+ stdout = common.get_output(script, args)
+ script_env_stdout_cache[cache_key] = stdout
+
# Stupid batch files do not set return code: we take a look at the
# beginning of the output for an error message instead
olines = stdout.splitlines()
@@ -320,7 +333,7 @@ def get_default_version(env):
msvc_version = env.get('MSVC_VERSION')
msvs_version = env.get('MSVS_VERSION')
-
+
debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version))
if msvs_version and not msvc_version:
@@ -370,7 +383,7 @@ def msvc_find_valid_batch_script(env,version):
try_target_archs = [target_platform]
debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform))
- # VS2012 has a "cross compile" environment to build 64 bit
+ # VS2012 has a "cross compile" environment to build 64 bit
# with x86_amd64 as the argument to the batch setup script
if req_target_platform in ('amd64','x86_64'):
try_target_archs.append('x86_amd64')
@@ -388,7 +401,7 @@ def msvc_find_valid_batch_script(env,version):
for tp in try_target_archs:
# Set to current arch.
env['TARGET_ARCH']=tp
-
+
debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp)
host_target = (host_platform, tp)
if not is_host_target_supported(host_target, version):
@@ -396,7 +409,7 @@ def msvc_find_valid_batch_script(env,version):
(host_target, version)
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
-
+
# Try to locate a batch file for this host/target platform combo
try:
(vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp)
@@ -410,7 +423,7 @@ def msvc_find_valid_batch_script(env,version):
warn_msg = warn_msg % (version, cached_get_installed_vcs())
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
continue
-
+
# Try to use the located batch file for this host/target platform combo
debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
if vc_script:
@@ -423,24 +436,24 @@ def msvc_find_valid_batch_script(env,version):
if not vc_script and sdk_script:
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
try:
- d = script_env(sdk_script,args=[])
+ d = script_env(sdk_script)
except BatchFileExecutionError as e:
debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
continue
elif not vc_script and not sdk_script:
debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
continue
-
+
debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg))
break # We've found a working target_platform, so stop looking
-
+
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
# To it's initial value
if not d:
env['TARGET_ARCH']=req_target_platform
-
+
return d
-
+
def msvc_setup_env(env):
debug('msvc_setup_env()')
@@ -459,12 +472,12 @@ def msvc_setup_env(env):
env['MSVS_VERSION'] = version
env['MSVS'] = {}
-
+
use_script = env.get('MSVC_USE_SCRIPT', True)
if SCons.Util.is_String(use_script):
debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script))
d = script_env(use_script)
- elif use_script:
+ elif use_script:
d = msvc_find_valid_batch_script(env,version)
debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d)
if not d:
@@ -485,4 +498,4 @@ def msvc_exists(version=None):
if version is None:
return len(vcs) > 0
return version in vcs
-
+
diff --git a/src/engine/SCons/Tool/ToolTests.py b/src/engine/SCons/Tool/ToolTests.py
index 3e6da5b6..a4353b17 100644
--- a/src/engine/SCons/Tool/ToolTests.py
+++ b/src/engine/SCons/Tool/ToolTests.py
@@ -51,6 +51,8 @@ class ToolTestCase(unittest.TestCase):
return self.dict.__contains__(key)
def has_key(self, key):
return key in self.dict
+ def subst(self, string, *args, **kwargs):
+ return string
env = Environment()
env['BUILDERS'] = {}
env['ENV'] = {}
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index d30159d9..396807f0 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -706,7 +706,7 @@ def tool_list(platform, env):
assemblers = ['masm', 'nasm', 'gas', '386asm' ]
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
ars = ['mslib', 'ar', 'tlib']
- other_plat_tools=['msvs','midl']
+ other_plat_tools = ['msvs', 'midl']
elif str(platform) == 'os2':
"prefer IBM tools on OS/2"
linkers = ['ilink', 'gnulink', ]#'mslink']
@@ -773,6 +773,9 @@ def tool_list(platform, env):
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
ars = ['ar', 'mslib']
+ if not str(platform) == 'win32':
+ other_plat_tools += ['m4', 'rpm']
+
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
# XXX this logic about what tool provides what should somehow be
@@ -796,12 +799,13 @@ def tool_list(platform, env):
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
ar = FindTool(ars, env) or ars[0]
+ d_compilers = ['dmd', 'gdc', 'ldc']
+ d_compiler = FindTool(d_compilers, env) or d_compilers[0]
+
other_tools = FindAllTools(other_plat_tools + [
- 'dmd',
#TODO: merge 'install' into 'filesystem' and
# make 'filesystem' the default
'filesystem',
- 'm4',
'wix', #'midl', 'msvs',
# Parser generators
'lex', 'yacc',
@@ -813,14 +817,14 @@ def tool_list(platform, env):
'dvipdf', 'dvips', 'gs',
'tex', 'latex', 'pdflatex', 'pdftex',
# Archivers
- 'tar', 'zip', 'rpm',
+ 'tar', 'zip',
# SourceCode factories
'BitKeeper', 'CVS', 'Perforce',
'RCS', 'SCCS', # 'Subversion',
], env)
tools = ([linker, c_compiler, cxx_compiler,
- fortran_compiler, assembler, ar]
+ fortran_compiler, assembler, ar, d_compiler]
+ other_tools)
return [x for x in tools if x]
diff --git a/src/engine/SCons/Tool/aixc++.py b/src/engine/SCons/Tool/aixc++.py
index 5aa1eeec..f03f763e 100644
--- a/src/engine/SCons/Tool/aixc++.py
+++ b/src/engine/SCons/Tool/aixc++.py
@@ -43,32 +43,25 @@ packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp']
def get_xlc(env):
xlc = env.get('CXX', 'xlC')
- xlc_r = env.get('SHCXX', 'xlC_r')
- return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages)
-
-def smart_cxxflags(source, target, env, for_signature):
- build_dir = env.GetBuildPath()
- if build_dir:
- return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
- return ''
+ return SCons.Platform.aix.get_xlc(env, xlc, packages)
def generate(env):
"""Add Builders and construction variables for xlC / Visual Age
suite to an Environment."""
- path, _cxx, _shcxx, version = get_xlc(env)
- if path:
+ path, _cxx, version = get_xlc(env)
+ if path and _cxx:
_cxx = os.path.join(path, _cxx)
- _shcxx = os.path.join(path, _shcxx)
+
+ if 'CXX' not in env:
+ env['CXX'] = _cxx
cplusplus.generate(env)
- env['CXX'] = _cxx
- env['SHCXX'] = _shcxx
- env['CXXVERSION'] = version
- env['SHOBJSUFFIX'] = '.pic.o'
+ if version:
+ env['CXXVERSION'] = version
def exists(env):
- path, _cxx, _shcxx, version = get_xlc(env)
+ path, _cxx, version = get_xlc(env)
if path and _cxx:
xlc = os.path.join(path, _cxx)
if os.path.exists(xlc):
diff --git a/src/engine/SCons/Tool/aixcc.py b/src/engine/SCons/Tool/aixcc.py
index b1da31e4..09365b1d 100644
--- a/src/engine/SCons/Tool/aixcc.py
+++ b/src/engine/SCons/Tool/aixcc.py
@@ -42,25 +42,25 @@ packages = ['vac.C', 'ibmcxx.cmp']
def get_xlc(env):
xlc = env.get('CC', 'xlc')
- xlc_r = env.get('SHCC', 'xlc_r')
- return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages)
+ return SCons.Platform.aix.get_xlc(env, xlc, packages)
def generate(env):
"""Add Builders and construction variables for xlc / Visual Age
suite to an Environment."""
- path, _cc, _shcc, version = get_xlc(env)
- if path:
+ path, _cc, version = get_xlc(env)
+ if path and _cc:
_cc = os.path.join(path, _cc)
- _shcc = os.path.join(path, _shcc)
+
+ if 'CC' not in env:
+ env['CC'] = _cc
cc.generate(env)
- env['CC'] = _cc
- env['SHCC'] = _shcc
- env['CCVERSION'] = version
+ if version:
+ env['CCVERSION'] = version
def exists(env):
- path, _cc, _shcc, version = get_xlc(env)
+ path, _cc, version = get_xlc(env)
if path and _cc:
xlc = os.path.join(path, _cc)
if os.path.exists(xlc):
diff --git a/src/engine/SCons/Tool/aixlink.py b/src/engine/SCons/Tool/aixlink.py
index fc65afb9..bfddf0ac 100644
--- a/src/engine/SCons/Tool/aixlink.py
+++ b/src/engine/SCons/Tool/aixlink.py
@@ -62,12 +62,14 @@ def generate(env):
env['SHLIBSUFFIX'] = '.a'
def exists(env):
- path, _cc, _shcc, version = aixcc.get_xlc(env)
- if path and _cc:
- xlc = os.path.join(path, _cc)
- if os.path.exists(xlc):
- return xlc
- return None
+ # TODO: sync with link.smart_link() to choose a linker
+ linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
+ alltools = []
+ for langvar, linktools in linkers.items():
+ if langvar in env: # use CC over CXX when user specified CC but not CXX
+ return SCons.Tool.FindTool(linktools, env)
+ alltools.extend(linktools)
+ return SCons.Tool.FindTool(alltools, env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/c++.py b/src/engine/SCons/Tool/c++.py
index 82a19c5e..430851c8 100644
--- a/src/engine/SCons/Tool/c++.py
+++ b/src/engine/SCons/Tool/c++.py
@@ -72,7 +72,8 @@ def generate(env):
SCons.Tool.cc.add_common_cc_variables(env)
- env['CXX'] = 'c++'
+ if 'CXX' not in env:
+ env['CXX'] = env.Detect(compilers) or compilers[0]
env['CXXFLAGS'] = SCons.Util.CLVar('')
env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['SHCXX'] = '$CXX'
@@ -90,7 +91,7 @@ def generate(env):
env['CXXFILESUFFIX'] = '.cc'
def exists(env):
- return env.Detect(compilers)
+ return env.Detect(env.get('CXX', compilers))
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/cc.py b/src/engine/SCons/Tool/cc.py
index 9b404b2b..590ec5fd 100644
--- a/src/engine/SCons/Tool/cc.py
+++ b/src/engine/SCons/Tool/cc.py
@@ -62,6 +62,8 @@ def add_common_cc_variables(env):
if 'SHCCFLAGS' not in env:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
+compilers = ['cc']
+
def generate(env):
"""
Add Builders and construction variables for C compilers to an Environment.
@@ -76,7 +78,8 @@ def generate(env):
add_common_cc_variables(env)
- env['CC'] = 'cc'
+ if 'CC' not in env:
+ env['CC'] = env.Detect(compilers) or compilers[0]
env['CFLAGS'] = SCons.Util.CLVar('')
env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['SHCC'] = '$CC'
@@ -93,7 +96,7 @@ def generate(env):
env['CFILESUFFIX'] = '.c'
def exists(env):
- return env.Detect('cc')
+ return env.Detect(env.get('CC', compilers))
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/dmd.py b/src/engine/SCons/Tool/dmd.py
index a8faf5dc..082d5c3a 100644
--- a/src/engine/SCons/Tool/dmd.py
+++ b/src/engine/SCons/Tool/dmd.py
@@ -3,14 +3,14 @@
Tool-specific initialization for the Digital Mars D compiler.
(http://digitalmars.com/d)
-Coded by Andy Friesen (andy@ikagames.com)
+Originally coded by Andy Friesen (andy@ikagames.com)
15 November 2003
-Amended by Russel Winder (russel@russel.org.uk)
-2010-02-07
+Evolved by Russel Winder (russel@winder.org.uk)
+2010-02-07 onwards
There are a number of problems with this script at this point in time.
-The one that irritates me the most is the Windows linker setup. The D
+The one that irritates the most is the Windows linker setup. The D
linker doesn't have a way to add lib paths on the commandline, as far
as I can see. You have to specify paths relative to the SConscript or
use absolute paths. To hack around it, add '#/blah'. This will link
@@ -18,14 +18,15 @@ blah.lib from the directory where SConstruct resides.
Compiler variables:
DC - The name of the D compiler to use. Defaults to dmd or gdmd,
- whichever is found.
+ whichever is found.
DPATH - List of paths to search for import modules.
DVERSIONS - List of version tags to enable when compiling.
DDEBUG - List of debug tags to enable when compiling.
Linker related variables:
LIBS - List of library files to link in.
- DLINK - Name of the linker to use. Defaults to dmd or gdmd.
+ DLINK - Name of the linker to use. Defaults to dmd or gdmd,
+ whichever is found.
DLINKFLAGS - List of linker flags.
Lib tool variables:
@@ -60,6 +61,7 @@ Lib tool variables:
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
+import subprocess
import SCons.Action
import SCons.Builder
@@ -67,57 +69,34 @@ import SCons.Defaults
import SCons.Scanner.D
import SCons.Tool
-# Adapted from c++.py
-def isD(source):
- if not source:
- return 0
+import SCons.Tool.DCommon
- for s in source:
- if s.sources:
- ext = os.path.splitext(str(s.sources[0]))[1]
- if ext == '.d':
- return 1
- return 0
-
-smart_link = {}
-
-smart_lib = {}
def generate(env):
- global smart_link
- global smart_lib
-
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
- DAction = SCons.Action.Action('$DCOM', '$DCOMSTR')
-
- static_obj.add_action('.d', DAction)
- shared_obj.add_action('.d', DAction)
+ static_obj.add_action('.d', SCons.Defaults.DAction)
+ shared_obj.add_action('.d', SCons.Defaults.ShDAction)
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
- dc = env.Detect(['dmd', 'gdmd'])
- env['DC'] = dc
+ env['DC'] = env.Detect(['dmd', 'gdmd'])
env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES'
env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)'
env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)'
env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)'
+ env['SHDC'] = '$DC'
+ env['SHDCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -fPIC -of$TARGET $SOURCES'
+
env['DPATH'] = ['#/']
env['DFLAGS'] = []
env['DVERSIONS'] = []
env['DDEBUG'] = []
- if dc:
- # Add the path to the standard library.
- # This is merely for the convenience of the dependency scanner.
- dmd_path = env.WhereIs(dc)
- if dmd_path:
- x = dmd_path.rindex(dc)
- phobosDir = dmd_path[:x] + '/../src/phobos'
- if os.path.isdir(phobosDir):
- env.Append(DPATH = [phobosDir])
+ if env['DC']:
+ SCons.Tool.DCommon.addDPATHToEnv(env, env['DC'])
env['DINCPREFIX'] = '-I'
env['DINCSUFFIX'] = ''
@@ -129,106 +108,39 @@ def generate(env):
env['DFLAGSUFFIX'] = ''
env['DFILESUFFIX'] = '.d'
- # Need to use the Digital Mars linker/lib on windows.
- # *nix can just use GNU link.
- if env['PLATFORM'] == 'win32':
- env['DLINK'] = '$DC'
- env['DLINKCOM'] = '$DLINK -of$TARGET $SOURCES $DFLAGS $DLINKFLAGS $_DLINKLIBFLAGS'
- env['DLIB'] = 'lib'
- env['DLIBCOM'] = '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLINKLIBFLAGS'
-
- env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
- env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
- env['DLINKFLAGS'] = []
- env['DLIBLINKPREFIX'] = ''
- env['DLIBLINKSUFFIX'] = '.lib'
- env['DLIBFLAGPREFIX'] = '-'
- env['DLIBFLAGSUFFIX'] = ''
- env['DLINKFLAGPREFIX'] = '-'
- env['DLINKFLAGSUFFIX'] = ''
-
- SCons.Tool.createStaticLibBuilder(env)
-
- # Basically, we hijack the link and ar builders with our own.
- # these builders check for the presence of D source, and swap out
- # the system's defaults for the Digital Mars tools. If there's no D
- # source, then we silently return the previous settings.
- linkcom = env.get('LINKCOM')
- try:
- env['SMART_LINKCOM'] = smart_link[linkcom]
- except KeyError:
- def _smartLink(source, target, env, for_signature,
- defaultLinker=linkcom):
- if isD(source):
- # XXX I'm not sure how to add a $DLINKCOMSTR variable
- # so that it works with this _smartLink() logic,
- # and I don't have a D compiler/linker to try it out,
- # so we'll leave it alone for now.
- return '$DLINKCOM'
- else:
- return defaultLinker
- env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink
-
- arcom = env.get('ARCOM')
- try:
- env['SMART_ARCOM'] = smart_lib[arcom]
- except KeyError:
- def _smartLib(source, target, env, for_signature,
- defaultLib=arcom):
- if isD(source):
- # XXX I'm not sure how to add a $DLIBCOMSTR variable
- # so that it works with this _smartLib() logic, and
- # I don't have a D compiler/archiver to try it out,
- # so we'll leave it alone for now.
- return '$DLIBCOM'
- else:
- return defaultLib
- env['SMART_ARCOM'] = smart_lib[arcom] = _smartLib
-
- # It is worth noting that the final space in these strings is
- # absolutely pivotal. SCons sees these as actions and not generators
- # if it is not there. (very bad)
- env['ARCOM'] = '$SMART_ARCOM '
- env['LINKCOM'] = '$SMART_LINKCOM '
- else: # assuming linux
- linkcom = env.get('LINKCOM')
- try:
- env['SMART_LINKCOM'] = smart_link[linkcom]
- except KeyError:
- def _smartLink(source, target, env, for_signature,
- defaultLinker=linkcom, dc=dc):
- if isD(source):
- try:
- libs = env['LIBS']
- except KeyError:
- libs = []
- if dc == 'dmd':
- # TODO: This assumes that the dmd executable is in the
- # bin directory and that the libraries are in a peer
- # directory lib. This true of the Digital Mars
- # distribution but . . .
- import glob
- dHome = env.WhereIs(dc).replace('/dmd' , '/..')
- if glob.glob(dHome + '/lib/*phobos2*'):
- if 'phobos2' not in libs:
- env.Append(LIBPATH = [dHome + '/lib'])
- env.Append(LIBS = ['phobos2'])
- # TODO: Find out when there will be a
- # 64-bit version of D.
- env.Append(LINKFLAGS = ['-m32'])
- else:
- if 'phobos' not in libs:
- env.Append(LIBS = ['phobos'])
- elif dc is 'gdmd':
- env.Append(LIBS = ['gphobos'])
- if 'pthread' not in libs:
- env.Append(LIBS = ['pthread'])
- if 'm' not in libs:
- env.Append(LIBS = ['m'])
- return defaultLinker
- env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink
-
- env['LINKCOM'] = '$SMART_LINKCOM '
+ env['DLINK'] = '$DC'
+ env['DLINKFLAGS'] = SCons.Util.CLVar('')
+ env['DLINKCOM'] = '$DLINK -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
+
+ env['DSHLINK'] = '$DC'
+ env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so')
+ env['SHDLINKCOM'] = '$DLINK -of$TARGET $DSHLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
+
+ env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l'
+ env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else ''
+ env['_DLIBFLAGS'] = '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
+
+ env['DLIBDIRPREFIX'] = '-L-L'
+ env['DLIBDIRSUFFIX'] = ''
+ env['_DLIBDIRFLAGS'] = '$( ${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
+
+
+ env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr'
+ env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '')
+
+ #env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
+
+ env['DLIBFLAGPREFIX'] = '-'
+ env['DLIBFLAGSUFFIX'] = ''
+
+ # __RPATH is set to $_RPATH in the platform specification if that
+ # platform supports it.
+ env['DRPATHPREFIX'] = '-L-rpath='
+ env['DRPATHSUFFIX'] = ''
+ env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}'
+
+ SCons.Tool.createStaticLibBuilder(env)
+
def exists(env):
return env.Detect(['dmd', 'gdmd'])
diff --git a/src/engine/SCons/Tool/dmd.xml b/src/engine/SCons/Tool/dmd.xml
index d9568947..f8936c12 100644
--- a/src/engine/SCons/Tool/dmd.xml
+++ b/src/engine/SCons/Tool/dmd.xml
@@ -21,23 +21,23 @@ See its __doc__ string for a discussion of the format.
<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">
+ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0/scons.xsd">
<tool name="dmd">
<summary>
<para>
-Sets construction variables for D language compilers
-(the Digital Mars D compiler, or GDC).
+Sets construction variables for D language compiler DMD.
</para>
</summary>
<sets>
-<item><!--</item>
<item>DC</item>
<item>DCOM</item>
<item>_DINCFLAGS</item>
<item>_DVERFLAGS</item>
<item>_DDEBUGFLAGS</item>
<item>_DFLAGS</item>
+<item>SHDC</item>
+<item>SHDCOM</item>
<item>DPATH</item>
<item>DFLAGS</item>
<item>DVERSIONS</item>
@@ -50,24 +50,27 @@ Sets construction variables for D language compilers
<item>DDEBUGSUFFIX</item>
<item>DFLAGPREFIX</item>
<item>DFLAGSUFFIX</item>
-<item>DFLESUFFIX</item>
+<item>DFILESUFFIX</item>
<item>DLINK</item>
+<item>DLINKFLAGS</item>
<item>DLINKCOM</item>
+<item>SHDLINK</item>
+<item>SHDLINKFLAGS</item>
+<item>SHDLINKCOM</item>
+<item>DLIBLINKPREFIX</item>
+<item>DLIBLINKSUFFIX</item>
+<item>_DLIBFLAGS</item>
+<item>DLIBDIRPREFIX</item>
+<item>DLIBDIRSUFFIX</item>
+<item>_DLIBDIRFLAGS</item>
<item>DLIB</item>
<item>DLIBCOM</item>
-<item>_DLINKLIBFLAGS</item>
<item>_DLIBFLAGS</item>
-<item>DLINKFLAGS</item>
-<item>DLIBLINKPREFIX</item>
-<item>DLIBLINKSUFFIX</item>
<item>DLIBFLAGPREFIX</item>
<item>DLIBFLAGSUFFIX</item>
-<item>DLINKFLAGPREFIX</item>
-<item>DLINKFLAGSUFFIX</item>
-<item>LINKCOM</item>
-<item>ARCOM</item>
-<item>LIBS</item>
-<item>--></item>
+<item>RPATHPREFIX</item>
+<item>RPATHSUFFIX</item>
+<item>_RPATH</item>
</sets>
<uses>
</uses>
diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py
index 627ff51b..77ed3885 100644
--- a/src/engine/SCons/Tool/docbook/__init__.py
+++ b/src/engine/SCons/Tool/docbook/__init__.py
@@ -242,7 +242,7 @@ def __xml_scan(node, env, path, arg):
styledoc = libxml2.parseFile(xsl_file)
style = libxslt.parseStylesheetDoc(styledoc)
- doc = libxml2.parseFile(str(node))
+ doc = libxml2.readFile(str(node), None, libxml2.XML_PARSE_NOENT)
result = style.applyStylesheet(doc, None)
depfiles = []
@@ -348,7 +348,7 @@ def __xinclude_libxml2(target, source, env):
Resolving XIncludes, using the libxml2 module.
"""
doc = libxml2.readFile(str(source[0]), None, libxml2.XML_PARSE_NOENT)
- doc.xincludeProcess()
+ doc.xincludeProcessFlags(libxml2.XML_PARSE_NOENT)
doc.saveFile(str(target[0]))
doc.freeDoc()
diff --git a/src/engine/SCons/Tool/docbook/docs/manual.xml b/src/engine/SCons/Tool/docbook/docs/manual.xml
index e232c6a7..c1297539 100644
--- a/src/engine/SCons/Tool/docbook/docs/manual.xml
+++ b/src/engine/SCons/Tool/docbook/docs/manual.xml
@@ -263,7 +263,7 @@ with large input files may occur. There will definitely arise the need for
adding features, or a variable. Let us know if you can think of a nice
improvement or have worked on a bugfix/patch with success. Enter your issues at the
Launchpad bug tracker for the Docbook Tool, or write to the User General Discussion
-list of SCons at <literal>users@scons.tigris.org</literal>.
+list of SCons at <literal>scons-users@scons.org</literal>.
</para>
</section>
diff --git a/src/engine/SCons/Tool/g++.py b/src/engine/SCons/Tool/g++.py
index 0e1c181a..c5eb5797 100644
--- a/src/engine/SCons/Tool/g++.py
+++ b/src/engine/SCons/Tool/g++.py
@@ -40,16 +40,19 @@ import subprocess
import SCons.Tool
import SCons.Util
+from . import gcc
cplusplus = __import__(__package__+'.c++', globals(), locals(), ['*'])
+
compilers = ['g++']
def generate(env):
"""Add Builders and construction variables for g++ to an Environment."""
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
- cplusplus.generate(env)
+ if 'CXX' not in env:
+ env['CXX'] = env.Detect(compilers) or compilers[0]
- env['CXX'] = env.Detect(compilers)
+ cplusplus.generate(env)
# platform specific settings
if env['PLATFORM'] == 'aix':
@@ -61,26 +64,13 @@ def generate(env):
elif env['PLATFORM'] == 'sunos':
env['SHOBJSUFFIX'] = '.pic.o'
# determine compiler version
- if env['CXX']:
- #pipe = SCons.Action._subproc(env, [env['CXX'], '-dumpversion'],
- pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
- stdin = 'devnull',
- stderr = 'devnull',
- stdout = subprocess.PIPE)
- if pipe.wait() != 0: return
- # -dumpversion was added in GCC 3.0. As long as we're supporting
- # GCC versions older than that, we should use --version and a
- # regular expression.
- #line = pipe.stdout.read().strip()
- #if line:
- # env['CXXVERSION'] = line
- line = SCons.Util.to_str (pipe.stdout.readline())
- match = re.search(r'[0-9]+(\.[0-9]+)+', line)
- if match:
- env['CXXVERSION'] = match.group(0)
+ version = gcc.detect_version(env, env['CXX'])
+ if version:
+ env['CXXVERSION'] = version
def exists(env):
- return env.Detect(compilers)
+ # is executable, and is a GNU compiler (or accepts '--version' at least)
+ return gcc.detect_version(env, env.Detect(env.get('CXX', compilers)))
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/gcc.py b/src/engine/SCons/Tool/gcc.py
index 72f9bfd6..998e35b2 100644
--- a/src/engine/SCons/Tool/gcc.py
+++ b/src/engine/SCons/Tool/gcc.py
@@ -44,34 +44,54 @@ compilers = ['gcc', 'cc']
def generate(env):
"""Add Builders and construction variables for gcc to an Environment."""
+
+ if 'CC' not in env:
+ env['CC'] = env.Detect(compilers) or compilers[0]
+
cc.generate(env)
- env['CC'] = env.Detect(compilers) or 'gcc'
if env['PLATFORM'] in ['cygwin', 'win32']:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
else:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
# determine compiler version
- if env['CC']:
- #pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
- pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
- stdin = 'devnull',
- stderr = 'devnull',
- stdout = subprocess.PIPE)
- if pipe.wait() != 0: return
- # -dumpversion was added in GCC 3.0. As long as we're supporting
- # GCC versions older than that, we should use --version and a
- # regular expression.
- #line = pipe.stdout.read().strip()
- #if line:
- # env['CCVERSION'] = line
- line = SCons.Util.to_str (pipe.stdout.readline())
- match = re.search(r'[0-9]+(\.[0-9]+)+', line)
- if match:
- env['CCVERSION'] = match.group(0)
+ version = detect_version(env, env['CC'])
+ if version:
+ env['CCVERSION'] = version
def exists(env):
- return env.Detect(compilers)
+ # is executable, and is a GNU compiler (or accepts '--version' at least)
+ return detect_version(env, env.Detect(env.get('CC', compilers)))
+
+def detect_version(env, cc):
+ """Return the version of the GNU compiler, or None if it is not a GNU compiler."""
+ cc = env.subst(cc)
+ if not cc:
+ return None
+ version = None
+ #pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'],
+ pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['--version'],
+ stdin = 'devnull',
+ stderr = 'devnull',
+ stdout = subprocess.PIPE)
+ # -dumpversion was added in GCC 3.0. As long as we're supporting
+ # GCC versions older than that, we should use --version and a
+ # regular expression.
+ #line = pipe.stdout.read().strip()
+ #if line:
+ # version = line
+ line = SCons.Util.to_str(pipe.stdout.readline())
+ match = re.search(r'[0-9]+(\.[0-9]+)+', line)
+ if match:
+ version = match.group(0)
+ # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer:
+ # So continue with reading to let the child process actually terminate.
+ while SCons.Util.to_str(pipe.stdout.readline()):
+ pass
+ ret = pipe.wait()
+ if ret != 0:
+ return None
+ return version
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py
new file mode 100644
index 00000000..1178b855
--- /dev/null
+++ b/src/engine/SCons/Tool/gdc.py
@@ -0,0 +1,128 @@
+"""SCons.Tool.gdc
+
+Tool-specific initialization for the GDC compiler.
+(https://github.com/D-Programming-GDC/GDC)
+
+Developed by Russel Winder (russel@winder.org.uk)
+2012-05-09 onwards
+
+Compiler variables:
+ DC - The name of the D compiler to use. Defaults to gdc.
+ DPATH - List of paths to search for import modules.
+ DVERSIONS - List of version tags to enable when compiling.
+ DDEBUG - List of debug tags to enable when compiling.
+
+Linker related variables:
+ LIBS - List of library files to link in.
+ DLINK - Name of the linker to use. Defaults to gdc.
+ DLINKFLAGS - List of linker flags.
+
+Lib tool variables:
+ DLIB - Name of the lib tool to use. Defaults to lib.
+ DLIBFLAGS - List of flags to pass to the lib tool.
+ LIBS - Same as for the linker. (libraries to pull into the .lib)
+"""
+
+#
+# __COPYRIGHT__
+#
+# 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.Action
+import SCons.Defaults
+import SCons.Tool
+
+import SCons.Tool.DCommon
+
+
+def generate(env):
+ static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
+
+ static_obj.add_action('.d', SCons.Defaults.DAction)
+ shared_obj.add_action('.d', SCons.Defaults.ShDAction)
+ static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
+ shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
+
+ env['DC'] = env.Detect('gdc')
+ env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -o $TARGET $SOURCES'
+ env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
+ env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)'
+ env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)'
+ env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)'
+
+ env['SHDC'] = '$DC'
+ env['SHDCOM'] = '$SHDC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -fPIC -c -o $TARGET $SOURCES'
+
+ env['DPATH'] = ['#/']
+ env['DFLAGS'] = []
+ env['DVERSIONS'] = []
+ env['DDEBUG'] = []
+
+ if env['DC']:
+ SCons.Tool.DCommon.addDPATHToEnv(env, env['DC'])
+
+ env['DINCPREFIX'] = '-I'
+ env['DINCSUFFIX'] = ''
+ env['DVERPREFIX'] = '-version='
+ env['DVERSUFFIX'] = ''
+ env['DDEBUGPREFIX'] = '-debug='
+ env['DDEBUGSUFFIX'] = ''
+ env['DFLAGPREFIX'] = '-'
+ env['DFLAGSUFFIX'] = ''
+ env['DFILESUFFIX'] = '.d'
+
+ env['DLINK'] = '$DC'
+ env['DLINKFLAGS'] = SCons.Util.CLVar('')
+ env['DLINKCOM'] = '$DLINK -o $TARGET $DLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+
+ env['SHDLINK'] = '$DC'
+ env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared')
+ env['SHDLINKCOM'] = '$DLINK -o $TARGET $DLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+
+ env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr'
+ env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '')
+
+ env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
+
+ env['DLIBFLAGPREFIX'] = '-'
+ env['DLIBFLAGSUFFIX'] = ''
+ env['DLINKFLAGPREFIX'] = '-'
+ env['DLINKFLAGSUFFIX'] = ''
+
+ # __RPATH is set to $_RPATH in the platform specification if that
+ # platform supports it.
+ env['RPATHPREFIX'] = '-Wl,-rpath='
+ env['RPATHSUFFIX'] = ''
+ env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
+
+ SCons.Tool.createStaticLibBuilder(env)
+
+
+def exists(env):
+ return env.Detect('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/gdc.xml b/src/engine/SCons/Tool/gdc.xml
new file mode 100644
index 00000000..20544b00
--- /dev/null
+++ b/src/engine/SCons/Tool/gdc.xml
@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+
+<!DOCTYPE sconsdoc [
+<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+%scons;
+<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+%builders-mod;
+<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+%functions-mod;
+<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+%tools-mod;
+<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+%variables-mod;
+]>
+
+<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="gdc">
+<summary>
+<para>
+Sets construction variables for the D language compiler GDC.
+</para>
+</summary>
+<sets>
+<item>DC</item>
+<item>DCOM</item>
+<item>_DINCFLAGS</item>
+<item>_DVERFLAGS</item>
+<item>_DDEBUGFLAGS</item>
+<item>_DFLAGS</item>
+<item>SHDC</item>
+<item>SHDCOM</item>
+<item>DPATH</item>
+<item>DFLAGS</item>
+<item>DVERSIONS</item>
+<item>DDEBUG</item>
+<item>DINCPREFIX</item>
+<item>DINCSUFFIX</item>
+<item>DVERPREFIX</item>
+<item>DVERSUFFIX</item>
+<item>DDEBUGPREFIX</item>
+<item>DDEBUGSUFFIX</item>
+<item>DFLAGPREFIX</item>
+<item>DFLAGSUFFIX</item>
+<item>DFILESUFFIX</item>
+<item>DLINK</item>
+<item>DLINKFLAGS</item>
+<item>DLINKCOM</item>
+<item>SHDLINK</item>
+<item>SHDLINKFLAGS</item>
+<item>SHDLINKCOM</item>
+<item>DLIB</item>
+<item>DLIBCOM</item>
+<item>_DLIBFLAGS</item>
+<item>DLIBFLAGPREFIX</item>
+<item>DLIBFLAGSUFFIX</item>
+<item>DLINKFLAGPREFIX</item>
+<item>DLINKFLAGSUFFIX</item>
+<item>RPATHPREFIX</item>
+<item>RPATHSUFFIX</item>
+<item>_RPATH</item>
+</sets>
+<uses>
+</uses>
+</tool>
+
+<cvar name="DC">
+<summary>
+<para>
+DC.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DCOM">
+<summary>
+<para>
+DCOM.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DDEBUG">
+<summary>
+<para>
+DDEBUG.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DDEBUGPREFIX">
+<summary>
+<para>
+DDEBUGPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DDEBUGSUFFIX">
+<summary>
+<para>
+DDEBUGSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DFILESUFFIX">
+<summary>
+<para>
+DFILESUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DFLAGPREFIX">
+<summary>
+<para>
+DFLAGPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DFLAGS">
+<summary>
+<para>
+DFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DFLAGSUFFIX">
+<summary>
+<para>
+DFLAGSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DINCPREFIX">
+<summary>
+<para>
+DINCPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DINCSUFFIX">
+<summary>
+<para>
+DINCSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIB">
+<summary>
+<para>
+DLIB.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBCOM">
+<summary>
+<para>
+DLIBCOM.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBDIRPREFIX">
+<summary>
+<para>
+DLIBDIRPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBDIRSUFFIX">
+<summary>
+<para>
+DLIBDIRSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBFLAGPREFIX">
+<summary>
+<para>
+DLIBFLAGPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBFLAGSUFFIX">
+<summary>
+<para>
+DLIBFLAGSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBLINKPREFIX">
+<summary>
+<para>
+DLIBLINKPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLIBLINKSUFFIX">
+<summary>
+<para>
+DLIBLINKSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLINK">
+<summary>
+<para>
+DLINK.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLINKCOM">
+<summary>
+<para>
+DLINKCOM.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLINKFLAGPREFIX">
+<summary>
+<para>
+DLINKFLAGPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLINKFLAGS">
+<summary>
+<para>
+DLINKFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DLINKFLAGSUFFIX">
+<summary>
+<para>
+DLINKFLAGSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DPATH">
+<summary>
+<para>
+DPATH.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DVERPREFIX">
+<summary>
+<para>
+DVERPREFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DVERSIONS">
+<summary>
+<para>
+DVERSIONS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="DVERSUFFIX">
+<summary>
+<para>
+DVERSUFFIX.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDC">
+<summary>
+<para>
+SHDC.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDCOM">
+<summary>
+<para>
+SHDCOM.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDLINK">
+<summary>
+<para>
+SHDLINK.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDLINKCOM">
+<summary>
+<para>
+SHDLINKCOM.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHDLINKFLAGS">
+<summary>
+<para>
+SHDLINKFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DDEBUGFLAGS">
+<summary>
+<para>
+_DDEBUGFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DFLAGS">
+<summary>
+<para>
+_DFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DINCFLAGS">
+<summary>
+<para>
+_DINCFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DLIBDIRFLAGS">
+<summary>
+<para>
+_DLIBDIRFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DLIBFLAGS">
+<summary>
+<para>
+_DLIBFLAGS.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_DVERFLAGS">
+<summary>
+<para>
+_DVERFLAGS.
+</para>
+</summary>
+</cvar>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py
index ea8d7bd1..6bd94717 100644
--- a/src/engine/SCons/Tool/gnulink.py
+++ b/src/engine/SCons/Tool/gnulink.py
@@ -37,8 +37,6 @@ import SCons.Util
from . import link
-linkers = ['g++', 'gcc']
-
def generate(env):
"""Add Builders and construction variables for gnulink to an Environment."""
link.generate(env)
@@ -53,7 +51,14 @@ def generate(env):
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
def exists(env):
- return env.Detect(linkers)
+ # TODO: sync with link.smart_link() to choose a linker
+ linkers = { 'CXX': ['g++'], 'CC': ['gcc'] }
+ alltools = []
+ for langvar, linktools in linkers.items():
+ if langvar in env: # use CC over CXX when user specified CC but not CXX
+ return SCons.Tool.FindTool(linktools, env)
+ alltools.extend(linktools)
+ return SCons.Tool.FindTool(alltools, env) # find CXX or CC
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/intelc.py b/src/engine/SCons/Tool/intelc.py
index da5f592a..7cc2376d 100644
--- a/src/engine/SCons/Tool/intelc.py
+++ b/src/engine/SCons/Tool/intelc.py
@@ -156,7 +156,43 @@ def get_intel_registry_value(valuename, version=None, abi=None):
try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
except SCons.Util.RegError:
- raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
+ # For version 13 and later, check UUID subkeys for valuename
+ if is_win64:
+ K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper()
+ else:
+ K = 'Software\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper()
+ try:
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
+ uuid = SCons.Util.RegQueryValueEx(k, 'SubKey')[0]
+
+ if is_win64:
+ K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++"
+ else:
+ K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++"
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
+
+ try:
+ v = SCons.Util.RegQueryValueEx(k, valuename)[0]
+ return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
+ except SCons.Util.RegError:
+ if abi.upper() == 'EM64T':
+ abi = 'em64t_native'
+ if is_win64:
+ K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper()
+ else:
+ K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper()
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
+
+ try:
+ v = SCons.Util.RegQueryValueEx(k, valuename)[0]
+ return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
+ except SCons.Util.RegError:
+ raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
+
+ except SCons.Util.RegError:
+ raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
+ except WindowsError:
+ raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
# Get the value:
try:
@@ -180,7 +216,16 @@ def get_all_compiler_versions():
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
keyname)
except WindowsError:
- return []
+ # For version 13 or later, check for default instance UUID
+ if is_win64:
+ keyname = 'Software\\WoW6432Node\\Intel\\Suites'
+ else:
+ keyname = 'Software\\Intel\\Suites'
+ try:
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
+ keyname)
+ except WindowsError:
+ return []
i = 0
versions = []
try:
@@ -192,6 +237,9 @@ def get_all_compiler_versions():
# and then the install directory deleted or moved (rather
# than uninstalling properly), so the registry values
# are still there.
+ if subkey == 'Defaults': # Ignore default instances
+ i = i + 1
+ continue
ok = False
for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'):
try:
@@ -267,9 +315,17 @@ def get_intel_compiler_top(version, abi):
if not SCons.Util.can_read_reg:
raise NoRegistryModuleError("No Windows registry module was found")
top = get_intel_registry_value('ProductDir', version, abi)
+ archdir={'x86_64': 'intel64',
+ 'amd64' : 'intel64',
+ 'em64t' : 'intel64',
+ 'x86' : 'ia32',
+ 'i386' : 'ia32',
+ 'ia32' : 'ia32'
+ }[abi] # for v11 and greater
# pre-11, icl was in Bin. 11 and later, it's in Bin/<abi> apparently.
if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \
- and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")):
+ and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")) \
+ and not os.path.exists(os.path.join(top, "Bin", archdir, "icl.exe")):
raise MissingDirError("Can't find Intel compiler in %s"%(top))
elif is_mac or is_linux:
def find_in_2008style_dir(version):
diff --git a/src/engine/SCons/Tool/ldc.py b/src/engine/SCons/Tool/ldc.py
new file mode 100644
index 00000000..6b215e2f
--- /dev/null
+++ b/src/engine/SCons/Tool/ldc.py
@@ -0,0 +1,141 @@
+"""SCons.Tool.ldc
+
+Tool-specific initialization for the LDC compiler.
+(http://www.dsource.org/projects/ldc)
+
+Developed by Russel Winder (russel@winder.org.uk)
+2012-05-09 onwards
+
+Compiler variables:
+ DC - The name of the D compiler to use. Defaults to ldc2.
+ DPATH - List of paths to search for import modules.
+ DVERSIONS - List of version tags to enable when compiling.
+ DDEBUG - List of debug tags to enable when compiling.
+
+Linker related variables:
+ LIBS - List of library files to link in.
+ DLINK - Name of the linker to use. Defaults to ldc2.
+ DLINKFLAGS - List of linker flags.
+
+Lib tool variables:
+ DLIB - Name of the lib tool to use. Defaults to lib.
+ DLIBFLAGS - List of flags to pass to the lib tool.
+ LIBS - Same as for the linker. (libraries to pull into the .lib)
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import subprocess
+
+import SCons.Action
+import SCons.Builder
+import SCons.Defaults
+import SCons.Scanner.D
+import SCons.Tool
+
+import SCons.Tool.DCommon
+
+
+def generate(env):
+ static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
+
+ static_obj.add_action('.d', SCons.Defaults.DAction)
+ shared_obj.add_action('.d', SCons.Defaults.ShDAction)
+ static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
+ shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
+
+ env['DC'] = env.Detect('ldc2')
+ env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of=$TARGET $SOURCES'
+ env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
+ env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)'
+ env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)'
+ env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)'
+
+ env['SHDC'] = '$DC'
+ env['SHDCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -relocation-model=pic -of=$TARGET $SOURCES'
+
+ env['DPATH'] = ['#/']
+ env['DFLAGS'] = []
+ env['DVERSIONS'] = []
+ env['DDEBUG'] = []
+
+ if env['DC']:
+ SCons.Tool.DCommon.addDPATHToEnv(env, env['DC'])
+
+ env['DINCPREFIX'] = '-I='
+ env['DINCSUFFIX'] = ''
+ env['DVERPREFIX'] = '-version='
+ env['DVERSUFFIX'] = ''
+ env['DDEBUGPREFIX'] = '-debug='
+ env['DDEBUGSUFFIX'] = ''
+ env['DFLAGPREFIX'] = '-'
+ env['DFLAGSUFFIX'] = ''
+ env['DFILESUFFIX'] = '.d'
+
+ env['DLINK'] = '$DC'
+ env['DLINKFLAGS'] = SCons.Util.CLVar('')
+ env['DLINKCOM'] = '$DLINK -of=$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
+
+ env['DSHLINK'] = '$DC'
+ env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared')
+ env['SHDLINKCOM'] = '$DLINK -of=$TARGET $DSHLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
+
+ env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l'
+ env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else ''
+ #env['_DLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
+ env['_DLIBFLAGS'] = '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
+
+ env['DLIBDIRPREFIX'] = '-L-L'
+ env['DLIBDIRSUFFIX'] = ''
+ env['_DLIBDIRFLAGS'] = '$( ${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
+
+
+ env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr'
+ env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '')
+
+ #env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
+
+ env['DLIBFLAGPREFIX'] = '-'
+ env['DLIBFLAGSUFFIX'] = ''
+
+ # __RPATH is set to $_RPATH in the platform specification if that
+ # platform supports it.
+ env['DRPATHPREFIX'] = '-L-rpath='
+ env['DRPATHSUFFIX'] = ''
+ env['_RPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}'
+
+ SCons.Tool.createStaticLibBuilder(env)
+
+
+def exists(env):
+ return env.Detect('ldc2')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/ldc.xml b/src/engine/SCons/Tool/ldc.xml
new file mode 100644
index 00000000..f07144bd
--- /dev/null
+++ b/src/engine/SCons/Tool/ldc.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+
+<!DOCTYPE sconsdoc [
+<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+%scons;
+<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+%builders-mod;
+<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+%functions-mod;
+<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+%tools-mod;
+<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+%variables-mod;
+]>
+
+<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="ldc">
+<summary>
+<para>
+Sets construction variables for the D language compiler LDC2.
+</para>
+</summary>
+<sets>
+<item>DC</item>
+<item>DCOM</item>
+<item>_DINCFLAGS</item>
+<item>_DVERFLAGS</item>
+<item>_DDEBUGFLAGS</item>
+<item>_DFLAGS</item>
+<item>SHDC</item>
+<item>SHDCOM</item>
+<item>DPATH</item>
+<item>DFLAGS</item>
+<item>DVERSIONS</item>
+<item>DDEBUG</item>
+<item>DINCPREFIX</item>
+<item>DINCSUFFIX</item>
+<item>DVERPREFIX</item>
+<item>DVERSUFFIX</item>
+<item>DDEBUGPREFIX</item>
+<item>DDEBUGSUFFIX</item>
+<item>DFLAGPREFIX</item>
+<item>DFLAGSUFFIX</item>
+<item>DFILESUFFIX</item>
+<item>DLINK</item>
+<item>DLINKFLAGS</item>
+<item>DLINKCOM</item>
+<item>SHDLINK</item>
+<item>SHDLINKFLAGS</item>
+<item>SHDLINKCOM</item>
+<item>DLIBLINKPREFIX</item>
+<item>DLIBLINKSUFFIX</item>
+<item>_DLIBFLAGS</item>
+<item>DLIBDIRPREFIX</item>
+<item>DLIBDIRSUFFIX</item>
+<item>_DLIBDIRFLAGS</item>
+<item>DLIB</item>
+<item>DLIBCOM</item>
+<item>_DLIBFLAGS</item>
+<item>DLIBFLAGPREFIX</item>
+<item>DLIBFLAGSUFFIX</item>
+<item>DLINKFLAGPREFIX</item>
+<item>DLINKFLAGSUFFIX</item>
+<item>RPATHPREFIX</item>
+<item>RPATHSUFFIX</item>
+<item>_RPATH</item>
+</sets>
+<uses>
+</uses>
+</tool>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py
index c7c67907..1b030758 100644
--- a/src/engine/SCons/Tool/link.py
+++ b/src/engine/SCons/Tool/link.py
@@ -43,6 +43,7 @@ import SCons.Warnings
from SCons.Tool.FortranCommon import isfortran
+from SCons.Tool.DCommon import isD
cplusplus = __import__(__package__+'.c++', globals(), locals(), ['*'])
issued_mixed_link_warning = False
@@ -50,7 +51,8 @@ issued_mixed_link_warning = False
def smart_link(source, target, env, for_signature):
has_cplusplus = cplusplus.iscplusplus(source)
has_fortran = isfortran(env, source)
- if has_cplusplus and has_fortran:
+ has_d = isD(env, source)
+ if has_cplusplus and has_fortran and not has_d:
global issued_mixed_link_warning
if not issued_mixed_link_warning:
msg = "Using $CXX to link Fortran and C++ code together.\n\t" + \
@@ -60,6 +62,10 @@ def smart_link(source, target, env, for_signature):
msg % env.subst('$CXX'))
issued_mixed_link_warning = True
return '$CXX'
+ elif has_d:
+ env['LINKCOM'] = env['DLINKCOM']
+ env['SHLINKCOM'] = env['SHDLINKCOM']
+ return '$DC'
elif has_fortran:
return '$FORTRAN'
elif has_cplusplus:
@@ -139,7 +145,7 @@ def shlib_emitter_names(target, source, env):
print("shlib_emitter_names: side effect: ", name)
# add version_name to list of names to be a Side effect
version_names.append(version_name)
-
+
except KeyError:
version = None
return version_names
@@ -179,8 +185,8 @@ def generate(env):
# don't set up the emitter, cause AppendUnique will generate a list
# starting with None :-(
env.Append(LDMODULEEMITTER='$SHLIBEMITTER')
- env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
- env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
+ env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
+ env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
diff --git a/src/engine/SCons/Tool/link.xml b/src/engine/SCons/Tool/link.xml
index d3576481..d58b9e26 100644
--- a/src/engine/SCons/Tool/link.xml
+++ b/src/engine/SCons/Tool/link.xml
@@ -223,4 +223,13 @@ for the variable that expands to library search path options.
</summary>
</cvar>
+<cvar name="STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME">
+ <summary>
+ <para>
+ When this variable is true, static objects and shared objects are assumed to be the same; that is, SCons does not check for linking static objects into a shared library.
+ </para>
+ </summary>
+</cvar>
+
+
</sconsdoc>
diff --git a/src/engine/SCons/Tool/packaging/rpm.py b/src/engine/SCons/Tool/packaging/rpm.py
index a9e0fa2e..9bd7dbbb 100644
--- a/src/engine/SCons/Tool/packaging/rpm.py
+++ b/src/engine/SCons/Tool/packaging/rpm.py
@@ -182,7 +182,7 @@ def build_specfile_sections(spec):
spec['X_RPM_PREP'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + '\n%setup -q'
if 'X_RPM_BUILD' not in spec:
- spec['X_RPM_BUILD'] = 'mkdir "$RPM_BUILD_ROOT"'
+ spec['X_RPM_BUILD'] = '[ ! -e "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && mkdir "$RPM_BUILD_ROOT"'
if 'X_RPM_INSTALL' not in spec:
spec['X_RPM_INSTALL'] = 'scons --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"'
diff --git a/src/engine/SCons/Tool/swig.py b/src/engine/SCons/Tool/swig.py
index 5d2264c3..f669f838 100644
--- a/src/engine/SCons/Tool/swig.py
+++ b/src/engine/SCons/Tool/swig.py
@@ -174,7 +174,8 @@ def generate(env):
env.Append(SCANNERS = scanner)
def exists(env):
- return env.Detect(['swig'])
+ swig = env.get('SWIG') or env.Detect(['swig'])
+ return swig
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py
index dac98b7f..0bf37924 100644
--- a/src/engine/SCons/Tool/tex.py
+++ b/src/engine/SCons/Tool/tex.py
@@ -103,6 +103,7 @@ makeacronyms_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE)
beamer_re = re.compile(r"^[^%\n]*\\documentclass\{beamer\}", re.MULTILINE)
regex = r'^[^%\n]*\\newglossary\s*\[([^\]]+)\]?\s*\{([^}]*)\}\s*\{([^}]*)\}\s*\{([^}]*)\}\s*\{([^}]*)\}'
newglossary_re = re.compile(regex, re.MULTILINE)
+biblatex_re = re.compile(r"^[^%\n]*\\usepackage.*\{biblatex\}", re.MULTILINE)
newglossary_suffix = []
@@ -431,7 +432,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
if Verbose:
print("Need to run makeindex for newglossary")
newglfile = suffix_nodes[newglossary_suffix[ig][2]]
- MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARY ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR")
+ MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR")
result = MakeNewGlossaryAction(newglfile, newglfile, env)
if result != 0:
@@ -640,7 +641,7 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi
newglossary_suffix.append(suffix_list)
if Verbose:
print(" new suffixes for newglossary ",newglossary_suffix)
-
+
incResult = includeOnly_re.search(content)
if incResult:
@@ -685,15 +686,18 @@ def tex_emitter_core(target, source, env, graphics_extensions):
auxfilename = targetbase + '.aux'
logfilename = targetbase + '.log'
flsfilename = targetbase + '.fls'
+ syncfilename = targetbase + '.synctex.gz'
env.SideEffect(auxfilename,target[0])
env.SideEffect(logfilename,target[0])
env.SideEffect(flsfilename,target[0])
+ env.SideEffect(syncfilename,target[0])
if Verbose:
- print("side effect :",auxfilename,logfilename,flsfilename)
+ print("side effect :",auxfilename,logfilename,flsfilename,syncfilename)
env.Clean(target[0],auxfilename)
env.Clean(target[0],logfilename)
env.Clean(target[0],flsfilename)
+ env.Clean(target[0],syncfilename)
content = source[0].get_text_contents()
@@ -720,7 +724,8 @@ def tex_emitter_core(target, source, env, graphics_extensions):
makeglossaries_re,
makeacronyms_re,
beamer_re,
- newglossary_re ]
+ newglossary_re,
+ biblatex_re ]
# set up list with the file suffixes that need emitting
# when a feature is found
file_tests_suff = [['.aux','aux_file'],
@@ -738,7 +743,8 @@ def tex_emitter_core(target, source, env, graphics_extensions):
['.glo', '.gls', '.glg','glossaries'],
['.acn', '.acr', '.alg','acronyms'],
['.nav', '.snm', '.out', '.toc','beamer'],
- ['newglossary',] ]
+ ['newglossary',],
+ ['.bcf', '.blg','biblatex'] ]
# for newglossary the suffixes are added as we find the command
# build the list of lists
file_tests = []
@@ -854,7 +860,7 @@ def generate_darwin(env):
except KeyError:
environ = {}
env['ENV'] = environ
-
+
if (platform.system() == 'Darwin'):
try:
ospath = env['ENV']['PATHOSX']
diff --git a/src/engine/SCons/Warnings.py b/src/engine/SCons/Warnings.py
index ca6acee9..5c278252 100644
--- a/src/engine/SCons/Warnings.py
+++ b/src/engine/SCons/Warnings.py
@@ -54,6 +54,9 @@ class CorruptSConsignWarning(WarningOnByDefault):
class DependencyWarning(Warning):
pass
+class DevelopmentVersionWarning(WarningOnByDefault):
+ pass
+
class DuplicateEnvironmentWarning(WarningOnByDefault):
pass
diff --git a/src/engine/SCons/cpp.py b/src/engine/SCons/cpp.py
index 0ba10f59..60cfcea5 100644
--- a/src/engine/SCons/cpp.py
+++ b/src/engine/SCons/cpp.py
@@ -395,9 +395,10 @@ class PreProcessor(object):
"""
d = self.dispatch_table
- d['import'] = self.do_import
- d['include'] = self.do_include
- d['include_next'] = self.do_include
+ p = self.stack[-1] if self.stack else self.default_table
+
+ for k in ('import', 'include', 'include_next'):
+ d[k] = p[k]
def stop_handling_includes(self, t=None):
"""
diff --git a/src/engine/SCons/cppTests.py b/src/engine/SCons/cppTests.py
index 5a06beed..37b4aae3 100644
--- a/src/engine/SCons/cppTests.py
+++ b/src/engine/SCons/cppTests.py
@@ -327,6 +327,22 @@ no_space_input = """
"""
+nested_ifs_input = """
+#define DEFINED
+
+#ifdef NOT_DEFINED
+ #include "file7-no"
+ #ifdef DEFINED
+ #include "file8-no"
+ #else
+ #include "file9-no"
+ #endif
+#else
+ #include "file7-yes"
+#endif
+"""
+
+
# pp_class = PreProcessor
# #pp_class = DumbPreProcessor
@@ -403,6 +419,11 @@ class cppTestCase(unittest.TestCase):
result = self.cpp.process_contents(no_space_input)
assert expect == result, (expect, result)
+ def test_nested_ifs(self):
+ expect = self.nested_ifs_expect
+ result = self.cpp.process_contents(nested_ifs_input)
+ assert expect == result, (expect, result)
+
class cppAllTestCase(cppTestCase):
def setUp(self):
self.cpp = self.cpp_class(current = ".",
@@ -486,6 +507,10 @@ class PreProcessorTestCase(cppAllTestCase):
('include', '"', 'file44-yes'),
]
+ nested_ifs_expect = [
+ ('include', '"', 'file7-yes'),
+ ]
+
class DumbPreProcessorTestCase(cppAllTestCase):
cpp_class = cpp.DumbPreProcessor
@@ -591,6 +616,13 @@ class DumbPreProcessorTestCase(cppAllTestCase):
('include', '"', 'file44-yes'),
]
+ nested_ifs_expect = [
+ ('include', '"', 'file7-no'),
+ ('include', '"', 'file8-no'),
+ ('include', '"', 'file9-no'),
+ ('include', '"', 'file7-yes')
+ ]
+
import os
diff --git a/test/CC/CC.py b/test/CC/CC.py
index 73dc4e6f..9500088d 100644
--- a/test/CC/CC.py
+++ b/test/CC/CC.py
@@ -156,7 +156,8 @@ env.Program(target = 'test2', source = 'test2.C')
test.write("wrapper.py",
"""import os
import sys
-open('%s', 'wb').write("wrapper.py\\n")
+if '--version' not in sys.argv and '-dumpversion' not in sys.argv:
+ open('%s', 'wb').write("wrapper.py\\n")
os.system(" ".join(sys.argv[1:]))
""" % test.workpath('wrapper.out').replace('\\', '\\\\'))
@@ -197,13 +198,13 @@ main(int argc, char *argv[])
test.run(arguments = 'foo' + _exe)
-test.fail_test(os.path.exists(test.workpath('wrapper.out')))
+test.must_not_exist(test.workpath('wrapper.out'))
test.up_to_date(arguments = 'foo' + _exe)
test.run(arguments = 'bar' + _exe)
-test.fail_test(test.read('wrapper.out') != "wrapper.py\n")
+test.must_match('wrapper.out', "wrapper.py\n")
test.up_to_date(arguments = 'bar' + _exe)
diff --git a/test/CC/CCVERSION.py b/test/CC/CCVERSION.py
new file mode 100644
index 00000000..ac28e380
--- /dev/null
+++ b/test/CC/CCVERSION.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import sys
+import TestSCons
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+
+
+test.write("versioned.py",
+"""import os
+import sys
+if '-dumpversion' in sys.argv:
+ print '3.9.9'
+ sys.exit(0)
+if '--version' in sys.argv:
+ print 'this is version 2.9.9 wrapping', sys.argv[2]
+ sys.exit(0)
+if sys.argv[1] not in [ '2.9.9', '3.9.9' ]:
+ print 'wrong version', sys.argv[1], 'when wrapping', sys.argv[2]
+ sys.exit(1)
+os.system(" ".join(sys.argv[2:]))
+""")
+
+test.write('SConstruct', """
+cc = Environment().Dictionary('CC')
+foo = Environment(CC = r'%(_python_)s versioned.py "${CCVERSION}" ' + cc)
+foo.Program(target = 'foo', source = 'foo.c')
+""" % locals())
+
+test.write('foo.c', r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf("foo.c\n");
+ exit (0);
+}
+""")
+
+test.run(arguments = 'foo' + _exe)
+
+test.up_to_date(arguments = 'foo' + _exe)
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/CPPDEFINES/append.py b/test/CPPDEFINES/append.py
index 2dacd8a3..6e69d092 100644
--- a/test/CPPDEFINES/append.py
+++ b/test/CPPDEFINES/append.py
@@ -47,18 +47,17 @@ print env_1738_2.subst('$_CPPDEFFLAGS')
env_2300_1 = Environment(CPPDEFINES = 'foo', CPPDEFPREFIX='-D')
env_2300_1.Append(CPPDEFINES='bar')
print env_2300_1.subst('$_CPPDEFFLAGS')
-#env_2300_1.Object('test_2300_1', 'main.c')
env_2300_2 = Environment(CPPDEFINES = ['foo'], CPPDEFPREFIX='-D') # note the list
env_2300_2.Append(CPPDEFINES='bar')
print env_2300_2.subst('$_CPPDEFFLAGS')
-#env_2300_2.Object('test_2300_2', 'main.c')
# http://scons.tigris.org/issues/show_bug.cgi?id=1152
+# http://scons.tigris.org/issues/show_bug.cgi?id=2900
cases=[('string', 'FOO'),
('list', ['NAME1', 'NAME2']),
('list-of-2lists', [('NAME1','VAL1'), ['NAME2','VAL2']]),
- ('dict', {'NAME1' : 'VAL1', 'NAME2' : 'VAL2'})
+ ('dict', {'NAME1' : 'VAL1', 'NAME2' : 'VAL2', 'NAME3' : None})
]
for (t1, c1) in cases:
@@ -107,13 +106,13 @@ AppendUnique:
result=[('FOO',), ('NAME1', 'VAL1'), ('NAME2', 'VAL2')]
final=-DFOO -DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a dict to a string
- orig = FOO, append = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}
+ orig = FOO, append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result=['FOO', {'NAME2': 'VAL2', 'NAME1': 'VAL1'}]
- final=-DFOO -DNAME2=VAL2 -DNAME1=VAL1
+ result=['FOO', {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}]
+ final=-DFOO -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=['FOO', ('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
- final=-DFOO -DNAME2=VAL2 -DNAME1=VAL1
+ result=['FOO', ('NAME2', 'VAL2'), 'NAME3', ('NAME1', 'VAL1')]
+ final=-DFOO -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a string to a list
orig = ['NAME1', 'NAME2'], append = FOO
Append:
@@ -139,13 +138,13 @@ AppendUnique:
result=[('NAME1',), ('NAME2',), ('NAME1', 'VAL1'), ('NAME2', 'VAL2')]
final=-DNAME1 -DNAME2 -DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a dict to a list
- orig = ['NAME1', 'NAME2'], append = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}
+ orig = ['NAME1', 'NAME2'], append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result=['NAME1', 'NAME2', {'NAME2': 'VAL2', 'NAME1': 'VAL1'}]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME1=VAL1
+ result=['NAME1', 'NAME2', {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}]
+ final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=[('NAME1',), ('NAME2',), ('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME1=VAL1
+ result=[('NAME1',), ('NAME2',), ('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1')]
+ final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a string to a list-of-2lists
orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = FOO
Append:
@@ -171,45 +170,45 @@ AppendUnique:
result=[('NAME1', 'VAL1'), ('NAME2', 'VAL2')]
final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a dict to a list-of-2lists
- orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}
+ orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], {'NAME2': 'VAL2', 'NAME1': 'VAL1'}]
- final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME2=VAL2 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}]
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
- final=-DNAME2=VAL2 -DNAME1=VAL1
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a string to a dict
- orig = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}, append = FOO
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = FOO
Append:
- result={'FOO': None, 'NAME2': 'VAL2', 'NAME1': 'VAL1'}
- final=-DFOO -DNAME1=VAL1 -DNAME2=VAL2
+ result={'FOO': None, 'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ final=-DFOO -DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
AppendUnique:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1'), 'FOO']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DFOO
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), 'FOO']
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DFOO
==== Testing CPPDEFINES, appending a list to a dict
- orig = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}, append = ['NAME1', 'NAME2']
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = ['NAME1', 'NAME2']
Append:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
AppendUnique:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1'), ('NAME1',), ('NAME2',)]
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), ('NAME1',), ('NAME2',)]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
==== Testing CPPDEFINES, appending a list-of-2lists to a dict
- orig = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}, append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1'), ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1=VAL1 -DNAME2=VAL2
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1=VAL1 -DNAME2=VAL2
AppendUnique:
- result=[('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
- final=-DNAME2=VAL2 -DNAME1=VAL1
+ result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a dict to a dict
- orig = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}, append = {'NAME2': 'VAL2', 'NAME1': 'VAL1'}
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result={'NAME2': 'VAL2', 'NAME1': 'VAL1'}
- final=-DNAME1=VAL1 -DNAME2=VAL2
+ result={'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
AppendUnique:
- result={'NAME2': 'VAL2', 'NAME1': 'VAL1'}
- final=-DNAME1=VAL1 -DNAME2=VAL2
+ result={'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
"""
build_output="scons: `.' is up to date.\n"
diff --git a/test/CXX/CXX.py b/test/CXX/CXX.py
index cd354ae7..79dbde45 100644
--- a/test/CXX/CXX.py
+++ b/test/CXX/CXX.py
@@ -186,7 +186,8 @@ env.Program(target = 'test6', source = 'test6.C')
test.write("wrapper.py",
"""import os
import sys
-open('%s', 'wb').write("wrapper.py\\n")
+if '--version' not in sys.argv and '-dumpversion' not in sys.argv:
+ open('%s', 'wb').write("wrapper.py\\n")
os.system(" ".join(sys.argv[1:]))
""" % test.workpath('wrapper.out').replace('\\', '\\\\'))
diff --git a/test/CXX/CXXVERSION.py b/test/CXX/CXXVERSION.py
new file mode 100644
index 00000000..8433aa61
--- /dev/null
+++ b/test/CXX/CXXVERSION.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import sys
+import TestSCons
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+
+
+test.write("versioned.py",
+"""import os
+import sys
+if '-dumpversion' in sys.argv:
+ print '3.9.9'
+ sys.exit(0)
+if '--version' in sys.argv:
+ print 'this is version 2.9.9 wrapping', sys.argv[2]
+ sys.exit(0)
+if sys.argv[1] not in [ '2.9.9', '3.9.9' ]:
+ print 'wrong version', sys.argv[1], 'when wrapping', sys.argv[2]
+ sys.exit(1)
+os.system(" ".join(sys.argv[2:]))
+""")
+
+test.write('SConstruct', """
+cxx = Environment().Dictionary('CXX')
+foo = Environment(CXX = r'%(_python_)s versioned.py "${CXXVERSION}" ' + cxx)
+foo.Program(target = 'foo', source = 'foo.cpp')
+""" % locals())
+
+test.write('foo.cpp', r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(int argc, char *argv[])
+{
+ printf("foo.c\n");
+ exit (0);
+}
+""")
+
+test.run(arguments = 'foo' + _exe)
+
+test.up_to_date(arguments = 'foo' + _exe)
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Configure/Streamer1.py b/test/Configure/Streamer1.py
new file mode 100644
index 00000000..8f353087
--- /dev/null
+++ b/test/Configure/Streamer1.py
@@ -0,0 +1,85 @@
+#!/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 for BitBucket PR 126:
+
+SConf doesn't work well with 'io' module on pre-3.0 Python. This is because
+io.StringIO (used by SCons.SConf.Streamer) accepts only unicode strings.
+Non-unicode input causes it to raise an exception.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+# SConstruct
+#
+# The CheckHello should return 'yes' if everything works fine. Otherwise it
+# returns 'failed'.
+#
+def hello(target, source, env):
+ import traceback
+ try:
+ print 'hello!\\n' # this breaks the script
+ with open(env.subst('$TARGET', target = target),'w') as f:
+ f.write('yes')
+ except:
+ # write to file, as stdout/stderr is broken
+ traceback.print_exc(file=open('traceback','w'))
+ return 0
+
+def CheckHello(context):
+ import sys
+ context.Display('Checking whether hello works... ')
+ stat,out = context.TryAction(hello,'','.in')
+ if stat and out:
+ context.Result(out)
+ else:
+ context.Result('failed')
+ return out
+
+env = Environment()
+cfg = Configure(env)
+
+cfg.AddTest('CheckHello', CheckHello)
+cfg.CheckHello()
+
+env = cfg.Finish()
+""")
+
+test.run(arguments = '.')
+test.must_contain_all_lines(test.stdout(), ['Checking whether hello works... yes'])
+test.must_not_exist('traceback')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Copy-Symlinks.py b/test/Copy-Symlinks.py
new file mode 100644
index 00000000..f8f92d74
--- /dev/null
+++ b/test/Copy-Symlinks.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the Copy() Action symlink soft-copy support works.
+"""
+
+import os
+import stat
+import sys
+import TestSCons
+
+import SCons.Defaults
+SCons.Defaults.DefaultEnvironment( tools = [] )
+
+test = TestSCons.TestSCons()
+
+filelinkToCopy = 'filelinkToCopy'
+fileToLink = 'file.in'
+fileContents = 'stuff n things\n'
+dirToLink = 'dir'
+dirlinkToCopy = 'dirlinkToCopy'
+treeToLink = 'tree'
+treelinkToCopy = 'treelinkToCopy'
+badToLink = 'None' # do not write this item
+badlinkToCopy = 'badlinkToCopy'
+
+try:
+ test.symlink( fileToLink, filelinkToCopy )
+ test.symlink( dirToLink, dirlinkToCopy )
+ test.symlink( treeToLink, treelinkToCopy )
+ test.symlink( badToLink, badlinkToCopy )
+except:
+ test.no_result()
+
+test.write( fileToLink, fileContents )
+test.subdir( dirToLink )
+test.subdir( treeToLink )
+test.write( os.path.join( treeToLink, fileToLink ), fileContents )
+
+test.write('SConstruct',
+"""\
+import SCons.Defaults
+SCons.Defaults.DefaultEnvironment( tools = [] )
+
+Execute( Copy( 'F1', '%(filelinkToCopy)s', False ) )
+Execute( Copy( 'L1', '%(filelinkToCopy)s' ) )
+Execute( Copy( 'L2', '%(filelinkToCopy)s', True ) )
+
+Execute( Copy( 'D1', '%(dirlinkToCopy)s', False ) )
+Execute( Copy( 'L3', '%(dirlinkToCopy)s' ) )
+Execute( Copy( 'L4', '%(dirlinkToCopy)s', True ) )
+
+Execute( Copy( 'T1', '%(treelinkToCopy)s', False ) )
+Execute( Copy( 'L5', '%(treelinkToCopy)s' ) )
+Execute( Copy( 'L6', '%(treelinkToCopy)s', True ) )
+
+Execute( Copy( 'Fails', '%(badlinkToCopy)s', False ) )
+Execute( Copy( 'L7', '%(badlinkToCopy)s' ) )
+Execute( Copy( 'L8', '%(badlinkToCopy)s', True ) )
+"""
+% locals()
+)
+
+test.must_exist( 'SConstruct' )
+test.must_exist( fileToLink )
+test.must_exist( filelinkToCopy )
+test.must_exist( dirlinkToCopy )
+test.must_exist( treelinkToCopy )
+test.must_not_exist( badToLink )
+test.must_exist( badlinkToCopy )
+
+expectStdout = test.wrap_stdout(
+read_str =
+'''\
+Copy("F1", "%(filelinkToCopy)s")
+Copy("L1", "%(filelinkToCopy)s")
+Copy("L2", "%(filelinkToCopy)s")
+Copy("D1", "%(dirlinkToCopy)s")
+Copy("L3", "%(dirlinkToCopy)s")
+Copy("L4", "%(dirlinkToCopy)s")
+Copy("T1", "%(treelinkToCopy)s")
+Copy("L5", "%(treelinkToCopy)s")
+Copy("L6", "%(treelinkToCopy)s")
+Copy("Fails", "badlinkToCopy")
+Copy("L7", "%(badlinkToCopy)s")
+Copy("L8", "%(badlinkToCopy)s")
+''' % locals(),
+build_str =
+'''\
+scons: `.' is up to date.
+'''
+)
+
+expectStderr = \
+'''\
+scons: *** None: No such file or directory
+'''
+
+test.run( stdout = expectStdout, stderr = expectStderr, status = None )
+
+test.must_exist('D1')
+test.must_exist('F1')
+test.must_exist('L2')
+test.must_exist('L3')
+test.must_exist('L4')
+test.must_exist('L5')
+test.must_exist('L6')
+test.must_exist('L7')
+test.must_exist('L8')
+test.must_exist('T1')
+test.must_not_exist( 'Fails' )
+
+test.must_match( fileToLink, fileContents )
+test.must_match( 'F1', fileContents )
+test.must_match( 'L1', fileContents )
+test.must_match( 'L2', fileContents )
+test.must_match( os.path.join( treeToLink, fileToLink ), fileContents )
+
+test.fail_test( condition=os.path.islink('D1') )
+test.fail_test( condition=os.path.islink('F1') )
+test.fail_test( condition=os.path.islink('T1') )
+test.fail_test( condition=(not os.path.isdir('D1')) )
+test.fail_test( condition=(not os.path.isfile('F1')) )
+test.fail_test( condition=(not os.path.isdir('T1')) )
+test.fail_test( condition=(not os.path.islink('L1')) )
+test.fail_test( condition=(not os.path.islink('L2')) )
+test.fail_test( condition=(not os.path.islink('L3')) )
+test.fail_test( condition=(not os.path.islink('L4')) )
+test.fail_test( condition=(not os.path.islink('L5')) )
+test.fail_test( condition=(not os.path.islink('L6')) )
+test.fail_test( condition=(not os.path.islink('L7')) )
+test.fail_test( condition=(not os.path.islink('L8')) )
+test.fail_test( condition=(os.path.exists('L7')) )
+test.fail_test( condition=(os.path.exists('L8')) )
+test.fail_test( condition=(os.readlink(filelinkToCopy) != os.readlink('L1')) )
+test.fail_test( condition=(os.readlink(filelinkToCopy) != os.readlink('L2')) )
+test.fail_test( condition=(os.readlink(dirlinkToCopy) != os.readlink('L3')) )
+test.fail_test( condition=(os.readlink(dirlinkToCopy) != os.readlink('L4')) )
+test.fail_test( condition=(os.readlink(treelinkToCopy) != os.readlink('L5')) )
+test.fail_test( condition=(os.readlink(treelinkToCopy) != os.readlink('L6')) )
+test.fail_test( condition=(os.readlink(badlinkToCopy) != os.readlink('L7')) )
+test.fail_test( condition=(os.readlink(badlinkToCopy) != os.readlink('L8')) )
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/CoreScanner/Common/__init__.py b/test/D/CoreScanner/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/CoreScanner/Common/__init__.py
diff --git a/test/D/CoreScanner/Common/common.py b/test/D/CoreScanner/Common/common.py
new file mode 100644
index 00000000..657e83ee
--- /dev/null
+++ b/test/D/CoreScanner/Common/common.py
@@ -0,0 +1,99 @@
+"""
+Verify that the D scanner can return multiple modules imported by
+a single statement.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ _obj = TestSCons._obj
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Image')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
+
+ arguments = 'test1%(_obj)s test2%(_obj)s' % locals()
+
+ if tool == 'dmd':
+ # The gdmd executable in Debian Unstable as at 2012-05-12, version 4.6.3 puts out messages on stderr
+ # that cause inappropriate failure of the tests, so simply ignore them.
+ test.run(arguments=arguments, stderr=None)
+ else:
+ test.run(arguments=arguments)
+
+ test.up_to_date(arguments=arguments)
+
+ test.write(['module2.d'], """\
+module module2;
+
+int something_else;
+""")
+
+ if tool == 'dmd':
+ # The gdmd executable in Debian Unstable as at 2012-05-12, version 4.6.3 puts out messages on stderr
+ # that cause inappropriate failure of the tests, so simply ignore them.
+ test.not_up_to_date(arguments=arguments, stderr=None)
+ else:
+ test.not_up_to_date(arguments=arguments)
+
+ test.up_to_date(arguments=arguments)
+
+ test.write(['p', 'submodule2.d'], """\
+module p.submodule2;
+
+int something_else;
+""")
+
+ if tool == 'dmd':
+ # The gdmd executable in Debian Unstable as at 2012-05-12, version 4.6.3 puts out messages on stderr
+ # that cause inappropriate failure of the tests, so simply ignore them.
+ test.not_up_to_date(arguments=arguments, stderr=None)
+ else:
+ test.not_up_to_date(arguments=arguments)
+
+ test.up_to_date(arguments=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/D/CoreScanner/Common/sconstest.skip b/test/D/CoreScanner/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/CoreScanner/Common/sconstest.skip
diff --git a/test/D/CoreScanner/Image/SConstruct_template b/test/D/CoreScanner/Image/SConstruct_template
new file mode 100644
index 00000000..a128c67b
--- /dev/null
+++ b/test/D/CoreScanner/Image/SConstruct_template
@@ -0,0 +1,9 @@
+# -*- mode:python; coding:utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ tools=['link', '{}'])
+environment.Program('test1.d')
+environment.Program('test2.d')
diff --git a/test/D/CoreScanner/Image/ignored.d b/test/D/CoreScanner/Image/ignored.d
new file mode 100644
index 00000000..5b54a07b
--- /dev/null
+++ b/test/D/CoreScanner/Image/ignored.d
@@ -0,0 +1,3 @@
+module ignored;
+
+int something;
diff --git a/test/D/CoreScanner/Image/module1.d b/test/D/CoreScanner/Image/module1.d
new file mode 100644
index 00000000..487c3583
--- /dev/null
+++ b/test/D/CoreScanner/Image/module1.d
@@ -0,0 +1,3 @@
+module module1;
+
+int something;
diff --git a/test/D/CoreScanner/Image/module2.d b/test/D/CoreScanner/Image/module2.d
new file mode 100644
index 00000000..198fb748
--- /dev/null
+++ b/test/D/CoreScanner/Image/module2.d
@@ -0,0 +1,3 @@
+module module2;
+
+int something;
diff --git a/test/D/CoreScanner/Image/module3.di b/test/D/CoreScanner/Image/module3.di
new file mode 100644
index 00000000..effd4ebe
--- /dev/null
+++ b/test/D/CoreScanner/Image/module3.di
@@ -0,0 +1,3 @@
+module module3;
+
+int something;
diff --git a/test/D/CoreScanner/Image/p/ignored.d b/test/D/CoreScanner/Image/p/ignored.d
new file mode 100644
index 00000000..43d2bd87
--- /dev/null
+++ b/test/D/CoreScanner/Image/p/ignored.d
@@ -0,0 +1,3 @@
+module p.ignored;
+
+int something;
diff --git a/test/D/CoreScanner/Image/p/submodule1.d b/test/D/CoreScanner/Image/p/submodule1.d
new file mode 100644
index 00000000..1ec03693
--- /dev/null
+++ b/test/D/CoreScanner/Image/p/submodule1.d
@@ -0,0 +1,3 @@
+module p.submodule1;
+
+int something;
diff --git a/test/D/CoreScanner/Image/p/submodule2.d b/test/D/CoreScanner/Image/p/submodule2.d
new file mode 100644
index 00000000..57a28256
--- /dev/null
+++ b/test/D/CoreScanner/Image/p/submodule2.d
@@ -0,0 +1,3 @@
+module p.submodule2;
+
+int something;
diff --git a/test/D/CoreScanner/Image/test1.d b/test/D/CoreScanner/Image/test1.d
new file mode 100644
index 00000000..d386d977
--- /dev/null
+++ b/test/D/CoreScanner/Image/test1.d
@@ -0,0 +1,9 @@
+import module1;
+import module2;
+import module3;
+import p.submodule1;
+import p.submodule2;
+
+int main() {
+ return 0;
+}
diff --git a/test/D/CoreScanner/Image/test2.d b/test/D/CoreScanner/Image/test2.d
new file mode 100644
index 00000000..f880d2fa
--- /dev/null
+++ b/test/D/CoreScanner/Image/test2.d
@@ -0,0 +1,11 @@
+import
+ module1,
+ module2,
+ module3;
+import
+ p.submodule1,
+ p.submodule2;
+
+int main() {
+ return 0;
+}
diff --git a/test/D/CoreScanner/sconstest-dmd.py b/test/D/CoreScanner/sconstest-dmd.py
new file mode 100644
index 00000000..df6ddebd
--- /dev/null
+++ b/test/D/CoreScanner/sconstest-dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/CoreScanner/sconstest-gdc.py b/test/D/CoreScanner/sconstest-gdc.py
new file mode 100644
index 00000000..068f2c4a
--- /dev/null
+++ b/test/D/CoreScanner/sconstest-gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/CoreScanner/sconstest-ldc.py b/test/D/CoreScanner/sconstest-ldc.py
new file mode 100644
index 00000000..f61efbc6
--- /dev/null
+++ b/test/D/CoreScanner/sconstest-ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/DMD2.py b/test/D/DMD2.py
new file mode 100644
index 00000000..cc8ab93c
--- /dev/null
+++ b/test/D/DMD2.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('dmd') and not test.where_is('gdmd'):
+ test.skip_test("Could not find 'dmd' or 'gdmd', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['link', 'dmd'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/DMD2_Alt.py b/test/D/DMD2_Alt.py
new file mode 100644
index 00000000..fbe2f2b8
--- /dev/null
+++ b/test/D/DMD2_Alt.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('dmd') and not test.where_is('gdmd'):
+ test.skip_test("Could not find 'dmd' or 'gdmd', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['dmd', 'link'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/GDC.py b/test/D/GDC.py
new file mode 100644
index 00000000..e24ec438
--- /dev/null
+++ b/test/D/GDC.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('gdc'):
+ test.skip_test("Could not find 'gdc', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['link', 'gdc'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/GDC_Alt.py b/test/D/GDC_Alt.py
new file mode 100644
index 00000000..cac79499
--- /dev/null
+++ b/test/D/GDC_Alt.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('gdc'):
+ test.skip_test("Could not find 'gdc', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['gdc', 'link'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/ArLibIssue/SConstruct_template b/test/D/HSTeoh/ArLibIssue/SConstruct_template
new file mode 100644
index 00000000..81f81f55
--- /dev/null
+++ b/test/D/HSTeoh/ArLibIssue/SConstruct_template
@@ -0,0 +1,3 @@
+env = Environment({})
+
+env.StaticLibrary('mylib', ['a.d', 'b.d'])
diff --git a/test/D/HSTeoh/ArLibIssue/a.d b/test/D/HSTeoh/ArLibIssue/a.d
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HSTeoh/ArLibIssue/a.d
diff --git a/test/D/HSTeoh/ArLibIssue/b.d b/test/D/HSTeoh/ArLibIssue/b.d
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HSTeoh/ArLibIssue/b.d
diff --git a/test/D/HSTeoh/Common/__init__.py b/test/D/HSTeoh/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HSTeoh/Common/__init__.py
diff --git a/test/D/HSTeoh/Common/arLibIssue.py b/test/D/HSTeoh/Common/arLibIssue.py
new file mode 100644
index 00000000..fe5902be
--- /dev/null
+++ b/test/D/HSTeoh/Common/arLibIssue.py
@@ -0,0 +1,63 @@
+"""
+These tests check a problem with the lib/ar setting.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from SCons.Environment import Base
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('ArLibIssue')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format('tools=["{}", "ar"]'.format(tool)))
+
+ test.run()
+
+ test.must_exist(test.workpath('a.o'))
+ test.must_exist(test.workpath('b.o'))
+ test.must_exist(test.workpath('mylib.a' if Base()['PLATFORM'] == 'win32' else 'libmylib.a'))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/Common/libCompileOptions.py b/test/D/HSTeoh/Common/libCompileOptions.py
new file mode 100644
index 00000000..dd95fc8e
--- /dev/null
+++ b/test/D/HSTeoh/Common/libCompileOptions.py
@@ -0,0 +1,63 @@
+"""
+These tests check a problem with the lib/ar setting.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from SCons.Environment import Base
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('LibCompileOptions')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format('tools=["{}", "link", "ar"]'.format(tool)))
+
+ test.run()
+
+ test.must_exist(test.workpath('mylib.o'))
+ test.must_exist(test.workpath('mylib.a' if Base()['PLATFORM'] == 'win32' else 'libmylib.a'))
+ test.must_exist(test.workpath('prog'))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/Common/linkingProblem.py b/test/D/HSTeoh/Common/linkingProblem.py
new file mode 100644
index 00000000..59b409f4
--- /dev/null
+++ b/test/D/HSTeoh/Common/linkingProblem.py
@@ -0,0 +1,61 @@
+"""
+These tests check an issue with the LIBS environment variable.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('LinkingProblem')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
+
+ test.run()
+
+ test.must_exist(test.workpath('ncurs_impl.o'))
+ test.must_exist(test.workpath('cprog'))
+ test.must_exist(test.workpath('prog'))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/Common/sconstest.skip b/test/D/HSTeoh/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HSTeoh/Common/sconstest.skip
diff --git a/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py b/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py
new file mode 100644
index 00000000..4dabf7bf
--- /dev/null
+++ b/test/D/HSTeoh/Common/singleStringCannotBeMultipleOptions.py
@@ -0,0 +1,66 @@
+"""
+These tests verify that SCons fails appropriately where the user has tried to supply multiple command line
+options via a single string rather than providing a list of strings, one string per option.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('SingleStringCannotBeMultipleOptions')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
+
+ test.run(status=2, stdout=None, stderr=None)
+
+ result = {
+ 'dmd': ".*unrecognized switch '-m64 -O'.*",
+ 'gdc': ".*unrecognized command line option.*",
+ 'ldc': ".*Unknown command line argument '-m64 -O'.*",
+ }[tool]
+
+ test.fail_test(not test.match_re_dotall(test.stderr(), result))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/LibCompileOptions/SConstruct_template b/test/D/HSTeoh/LibCompileOptions/SConstruct_template
new file mode 100644
index 00000000..7031f5c4
--- /dev/null
+++ b/test/D/HSTeoh/LibCompileOptions/SConstruct_template
@@ -0,0 +1,9 @@
+env = Environment({})
+
+env.Library('mylib', 'mylib.d')
+
+prog_env = env.Clone(
+ LIBS = ['mylib'],
+ LIBPATH = '#'
+ )
+prog_env.Program('prog', 'prog.d')
diff --git a/test/D/HSTeoh/LibCompileOptions/mylib.d b/test/D/HSTeoh/LibCompileOptions/mylib.d
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HSTeoh/LibCompileOptions/mylib.d
diff --git a/test/D/HSTeoh/LibCompileOptions/prog.d b/test/D/HSTeoh/LibCompileOptions/prog.d
new file mode 100644
index 00000000..33c14ce1
--- /dev/null
+++ b/test/D/HSTeoh/LibCompileOptions/prog.d
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/test/D/HSTeoh/LinkingProblem/SConstruct_template b/test/D/HSTeoh/LinkingProblem/SConstruct_template
new file mode 100644
index 00000000..6815cdf3
--- /dev/null
+++ b/test/D/HSTeoh/LinkingProblem/SConstruct_template
@@ -0,0 +1,20 @@
+# -*- mode:python; coding=utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ tools = ['cc', 'link' , '{}'],
+ LIBS = ['ncurses'])
+
+environment.Object('ncurs_impl.o', 'ncurs_impl.c')
+
+environment.Program('prog', Split("""
+ prog.d
+ ncurs_impl.o
+"""))
+
+environment.Program('cprog', Split("""
+ cprog.c
+ ncurs_impl.o
+"""))
diff --git a/test/D/HSTeoh/LinkingProblem/cprog.c b/test/D/HSTeoh/LinkingProblem/cprog.c
new file mode 100644
index 00000000..674fd964
--- /dev/null
+++ b/test/D/HSTeoh/LinkingProblem/cprog.c
@@ -0,0 +1,7 @@
+extern void ncurs_init();
+extern void ncurs_cleanup();
+
+int main() {
+ ncurs_init();
+ ncurs_cleanup();
+}
diff --git a/test/D/HSTeoh/LinkingProblem/ncurs_impl.c b/test/D/HSTeoh/LinkingProblem/ncurs_impl.c
new file mode 100644
index 00000000..3ca6dd37
--- /dev/null
+++ b/test/D/HSTeoh/LinkingProblem/ncurs_impl.c
@@ -0,0 +1,13 @@
+/* Ncurses wrappers */
+#include <ncurses.h>
+
+void ncurs_init() {
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr, TRUE);
+}
+
+void ncurs_cleanup() {
+ endwin();
+}
diff --git a/test/D/HSTeoh/LinkingProblem/prog.d b/test/D/HSTeoh/LinkingProblem/prog.d
new file mode 100644
index 00000000..1337210e
--- /dev/null
+++ b/test/D/HSTeoh/LinkingProblem/prog.d
@@ -0,0 +1,13 @@
+/*
+ * Simple D program that links to ncurses via a C wrapping file.
+ */
+
+extern(C) {
+ void ncurs_init();
+ void ncurs_cleanup();
+}
+
+void main() {
+ ncurs_init();
+ ncurs_cleanup();
+}
diff --git a/test/D/HSTeoh/README.txt b/test/D/HSTeoh/README.txt
new file mode 100644
index 00000000..cb18b88b
--- /dev/null
+++ b/test/D/HSTeoh/README.txt
@@ -0,0 +1 @@
+The tests here are evolutions of test cases provided by H.S.Teoh via email.
diff --git a/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/SConstruct_template b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/SConstruct_template
new file mode 100644
index 00000000..89c603b1
--- /dev/null
+++ b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/SConstruct_template
@@ -0,0 +1,16 @@
+# -*- mode:python; coding=utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ tools=['link', '{}'],
+ # It might be thought that a single string can contain multiple options space separated. Actually this
+ # is deemed to be a single option, so leads to an error.
+ DFLAGS = '-m64 -O')
+
+environment.Program('proj', Split("""
+proj.d
+mod1.d
+cmod.c
+"""))
diff --git a/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/cmod.c b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/cmod.c
new file mode 100644
index 00000000..41c57f3a
--- /dev/null
+++ b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/cmod.c
@@ -0,0 +1,5 @@
+/* This is a sample C module. */
+
+int csqr(int arg) {
+ return arg*arg;
+}
diff --git a/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/mod1.d b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/mod1.d
new file mode 100644
index 00000000..5f618020
--- /dev/null
+++ b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/mod1.d
@@ -0,0 +1,6 @@
+module mod1;
+import std.stdio;
+
+void print_msg() {
+ writeln("Hello, this is a test program for the new SCons D support");
+}
diff --git a/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/proj.d b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/proj.d
new file mode 100644
index 00000000..e97f9dd7
--- /dev/null
+++ b/test/D/HSTeoh/SingleStringCannotBeMultipleOptions/proj.d
@@ -0,0 +1,13 @@
+import std.stdio;
+import mod1;
+
+extern(C) {
+ int csqr(int arg);
+}
+
+void main() {
+ print_msg();
+
+ auto i = 17;
+ writefln("The square of %d is %d", i, csqr(i));
+}
diff --git a/test/D/HSTeoh/sconstest-arLibIssue_dmd.py b/test/D/HSTeoh/sconstest-arLibIssue_dmd.py
new file mode 100644
index 00000000..0b872b48
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-arLibIssue_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.arLibIssue import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-arLibIssue_gdc.py b/test/D/HSTeoh/sconstest-arLibIssue_gdc.py
new file mode 100644
index 00000000..45e1e363
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-arLibIssue_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.arLibIssue import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-arLibIssue_ldc.py b/test/D/HSTeoh/sconstest-arLibIssue_ldc.py
new file mode 100644
index 00000000..7960d79a
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-arLibIssue_ldc.py
@@ -0,0 +1,38 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.arLibIssue import testForTool
+
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-libCompileOptions_dmd.py b/test/D/HSTeoh/sconstest-libCompileOptions_dmd.py
new file mode 100644
index 00000000..14f23487
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-libCompileOptions_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.libCompileOptions import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-libCompileOptions_gdc.py b/test/D/HSTeoh/sconstest-libCompileOptions_gdc.py
new file mode 100644
index 00000000..7b57546a
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-libCompileOptions_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.libCompileOptions import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-libCompileOptions_ldc.py b/test/D/HSTeoh/sconstest-libCompileOptions_ldc.py
new file mode 100644
index 00000000..74343502
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-libCompileOptions_ldc.py
@@ -0,0 +1,38 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.libCompileOptions import testForTool
+
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-linkingProblem_dmd.py b/test/D/HSTeoh/sconstest-linkingProblem_dmd.py
new file mode 100644
index 00000000..f4bac72f
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-linkingProblem_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.linkingProblem import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-linkingProblem_gdc.py b/test/D/HSTeoh/sconstest-linkingProblem_gdc.py
new file mode 100644
index 00000000..7346b664
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-linkingProblem_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.linkingProblem import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-linkingProblem_ldc.py b/test/D/HSTeoh/sconstest-linkingProblem_ldc.py
new file mode 100644
index 00000000..72c19e42
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-linkingProblem_ldc.py
@@ -0,0 +1,38 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.linkingProblem import testForTool
+
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_dmd.py b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_dmd.py
new file mode 100644
index 00000000..976f8207
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.singleStringCannotBeMultipleOptions import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py
new file mode 100644
index 00000000..d65495ad
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.singleStringCannotBeMultipleOptions import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_ldc.py b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_ldc.py
new file mode 100644
index 00000000..6718a886
--- /dev/null
+++ b/test/D/HSTeoh/sconstest-singleStringCannotBeMultipleOptions_ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.singleStringCannotBeMultipleOptions import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/Common/__init__.py b/test/D/HelloWorld/CompileAndLinkOneStep/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/Common/__init__.py
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/Common/common.py b/test/D/HelloWorld/CompileAndLinkOneStep/Common/common.py
new file mode 100644
index 00000000..618041bd
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/Common/common.py
@@ -0,0 +1,68 @@
+"""
+Support functions for all the tests.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Image')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
+
+ if tool == 'dmd':
+ # The gdmd executable in Debian Unstable as at 2012-05-12, version 4.6.3 puts out messages on stderr
+ # that cause inappropriate failure of the tests, so simply ignore them.
+ test.run(stderr=None)
+ else:
+ test.run()
+
+ test.must_exist(test.workpath('helloWorld.o'))
+ test.must_exist(test.workpath('helloWorld'))
+
+ test.run(program=test.workpath('helloWorld'+TestSCons._exe))
+ test.fail_test(test.stdout() != 'Hello World.\n')
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/Common/sconstest.skip b/test/D/HelloWorld/CompileAndLinkOneStep/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/Common/sconstest.skip
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/Image/SConstruct_template b/test/D/HelloWorld/CompileAndLinkOneStep/Image/SConstruct_template
new file mode 100644
index 00000000..c688ab7f
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/Image/SConstruct_template
@@ -0,0 +1,9 @@
+# -*- mode:python; coding:utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ tools=['link', '{}'])
+
+environment.Program('helloWorld.d')
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/Image/helloWorld.d b/test/D/HelloWorld/CompileAndLinkOneStep/Image/helloWorld.d
new file mode 100644
index 00000000..4d95b240
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/Image/helloWorld.d
@@ -0,0 +1,6 @@
+import std.stdio;
+
+int main(immutable string[] args) {
+ writeln("Hello World.");
+ return 0;
+}
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-dmd.py b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-dmd.py
new file mode 100644
index 00000000..df6ddebd
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-gdc.py b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-gdc.py
new file mode 100644
index 00000000..068f2c4a
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-ldc.py b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-ldc.py
new file mode 100644
index 00000000..f61efbc6
--- /dev/null
+++ b/test/D/HelloWorld/CompileAndLinkOneStep/sconstest-ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/__init__.py b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/__init__.py
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/common.py b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/common.py
new file mode 100644
index 00000000..618041bd
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/common.py
@@ -0,0 +1,68 @@
+"""
+Support functions for all the tests.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Image')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
+
+ if tool == 'dmd':
+ # The gdmd executable in Debian Unstable as at 2012-05-12, version 4.6.3 puts out messages on stderr
+ # that cause inappropriate failure of the tests, so simply ignore them.
+ test.run(stderr=None)
+ else:
+ test.run()
+
+ test.must_exist(test.workpath('helloWorld.o'))
+ test.must_exist(test.workpath('helloWorld'))
+
+ test.run(program=test.workpath('helloWorld'+TestSCons._exe))
+ test.fail_test(test.stdout() != 'Hello World.\n')
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/sconstest.skip b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/Common/sconstest.skip
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/SConstruct_template b/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/SConstruct_template
new file mode 100644
index 00000000..425970a1
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/SConstruct_template
@@ -0,0 +1,11 @@
+# -*- mode:python; coding:utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ tools=['link', '{}'])
+
+objects = environment.Object('helloWorld.d')
+
+environment.Program('helloWorld', objects)
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/helloWorld.d b/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/helloWorld.d
new file mode 100644
index 00000000..4d95b240
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/Image/helloWorld.d
@@ -0,0 +1,6 @@
+import std.stdio;
+
+int main(immutable string[] args) {
+ writeln("Hello World.");
+ return 0;
+}
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-dmd.py b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-dmd.py
new file mode 100644
index 00000000..df6ddebd
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the dmd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-gdc.py b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-gdc.py
new file mode 100644
index 00000000..43bb8ebd
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gcd tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-ldc.py b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-ldc.py
new file mode 100644
index 00000000..f61efbc6
--- /dev/null
+++ b/test/D/HelloWorld/CompileThenLinkTwoSteps/sconstest-ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the ldc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2939_Ariovistus/Common/__init__.py b/test/D/Issues/2939_Ariovistus/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Common/__init__.py
diff --git a/test/D/Issues/2939_Ariovistus/Common/correctLinkOptions.py b/test/D/Issues/2939_Ariovistus/Common/correctLinkOptions.py
new file mode 100644
index 00000000..3b178b94
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Common/correctLinkOptions.py
@@ -0,0 +1,62 @@
+"""
+These tests check a problem with the linker options setting.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from SCons.Environment import Base
+
+from os.path import abspath, dirname, join
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Project')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format('tools=["{}", "link"]'.format(tool)))
+
+ test.run()
+
+ for f in ('libstuff.so', 'stuff.os', 'test1', 'test1.o', 'test2', 'test2.o'):
+ test.must_exist(test.workpath(join('test', 'test1', f)))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2939_Ariovistus/Common/sconstest.skip b/test/D/Issues/2939_Ariovistus/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Common/sconstest.skip
diff --git a/test/D/Issues/2939_Ariovistus/Project/SConstruct_template b/test/D/Issues/2939_Ariovistus/Project/SConstruct_template
new file mode 100644
index 00000000..55f02aa0
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/SConstruct_template
@@ -0,0 +1,9 @@
+from os.path import join
+
+environment = Environment({})
+
+Export('environment')
+
+environment.SConscript([
+ join("test","test1", "SConscript"),
+]);
diff --git a/test/D/Issues/2939_Ariovistus/Project/test/test1/SConscript b/test/D/Issues/2939_Ariovistus/Project/test/test1/SConscript
new file mode 100644
index 00000000..53a1ca01
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/test/test1/SConscript
@@ -0,0 +1,14 @@
+Import('environment')
+
+env = Environment()
+env.SharedLibrary(target='stuff', source=['stuff.cpp'])
+
+env = Environment()
+env.Append(LIBPATH=['.'])
+env.Append(LIBS=['stuff'])
+env.Program(target='test1', source=['test1.cpp'])
+
+env = environment.Clone()
+env.Append(LIBPATH=['.'])
+env.Append(LIBS=['stuff'])
+env.Program(target='test2', source=['test2.d'])
diff --git a/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.cpp b/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.cpp
new file mode 100644
index 00000000..29705495
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.cpp
@@ -0,0 +1,12 @@
+#include "stuff.h"
+
+X::X() {
+ this->i = 1;
+}
+int X::y(){
+ return this->i;
+}
+
+X *SomeX() {
+ return new X();
+}
diff --git a/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.h b/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.h
new file mode 100644
index 00000000..863c3306
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/test/test1/stuff.h
@@ -0,0 +1,10 @@
+
+class X {
+ public:
+ int i;
+
+ X();
+ int y();
+};
+
+X *SomeX();
diff --git a/test/D/Issues/2939_Ariovistus/Project/test/test1/test1.cpp b/test/D/Issues/2939_Ariovistus/Project/test/test1/test1.cpp
new file mode 100644
index 00000000..f4d7208c
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/test/test1/test1.cpp
@@ -0,0 +1,5 @@
+#include "stuff.h"
+
+int main() {
+ X *x = SomeX();
+}
diff --git a/test/D/Issues/2939_Ariovistus/Project/test/test1/test2.d b/test/D/Issues/2939_Ariovistus/Project/test/test1/test2.d
new file mode 100644
index 00000000..4fbfa4d8
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/Project/test/test1/test2.d
@@ -0,0 +1,13 @@
+import std.stdio;
+
+struct X {
+}
+
+extern(C) int _ZN1X1yEv(X* _this);
+extern(C) X* _Z5SomeXv();
+
+void main() {
+ X *x = _Z5SomeXv();
+ int i = _ZN1X1yEv(x);
+ writeln("i: ", i);
+}
diff --git a/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_dmd.py b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_dmd.py
new file mode 100644
index 00000000..2446a28d
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_gdc.py b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_gdc.py
new file mode 100644
index 00000000..baf2921a
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_ldc.py b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_ldc.py
new file mode 100644
index 00000000..a61a94ba
--- /dev/null
+++ b/test/D/Issues/2939_Ariovistus/sconstest-correctLinkOptions_ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2940_Ariovistus/Common/__init__.py b/test/D/Issues/2940_Ariovistus/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Common/__init__.py
diff --git a/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py b/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py
new file mode 100644
index 00000000..3b178b94
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py
@@ -0,0 +1,62 @@
+"""
+These tests check a problem with the linker options setting.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from SCons.Environment import Base
+
+from os.path import abspath, dirname, join
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Project')
+ test.write('SConstruct', open('SConstruct_template', 'r').read().format('tools=["{}", "link"]'.format(tool)))
+
+ test.run()
+
+ for f in ('libstuff.so', 'stuff.os', 'test1', 'test1.o', 'test2', 'test2.o'):
+ test.must_exist(test.workpath(join('test', 'test1', f)))
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2940_Ariovistus/Common/sconstest.skip b/test/D/Issues/2940_Ariovistus/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Common/sconstest.skip
diff --git a/test/D/Issues/2940_Ariovistus/Project/SConstruct_template b/test/D/Issues/2940_Ariovistus/Project/SConstruct_template
new file mode 100644
index 00000000..55f02aa0
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/SConstruct_template
@@ -0,0 +1,9 @@
+from os.path import join
+
+environment = Environment({})
+
+Export('environment')
+
+environment.SConscript([
+ join("test","test1", "SConscript"),
+]);
diff --git a/test/D/Issues/2940_Ariovistus/Project/test/test1/SConscript b/test/D/Issues/2940_Ariovistus/Project/test/test1/SConscript
new file mode 100644
index 00000000..45e517a0
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/test/test1/SConscript
@@ -0,0 +1,16 @@
+Import('environment')
+
+env = Environment()
+env.SharedLibrary(target='stuff', source=['stuff.cpp'])
+
+env = Environment()
+env.Append(LIBPATH=['.'])
+env.Append(LIBS=['stuff'])
+env.Append(RPATH=['.'])
+env.Program(target='test1', source=['test1.cpp'])
+
+env = environment.Clone()
+env.Append(LIBPATH=['.'])
+env.Append(LIBS=['stuff'])
+env.Append(RPATH=['.'])
+env.Program(target='test2', source=['test2.d'])
diff --git a/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.cpp b/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.cpp
new file mode 100644
index 00000000..29705495
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.cpp
@@ -0,0 +1,12 @@
+#include "stuff.h"
+
+X::X() {
+ this->i = 1;
+}
+int X::y(){
+ return this->i;
+}
+
+X *SomeX() {
+ return new X();
+}
diff --git a/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.h b/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.h
new file mode 100644
index 00000000..863c3306
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/test/test1/stuff.h
@@ -0,0 +1,10 @@
+
+class X {
+ public:
+ int i;
+
+ X();
+ int y();
+};
+
+X *SomeX();
diff --git a/test/D/Issues/2940_Ariovistus/Project/test/test1/test1.cpp b/test/D/Issues/2940_Ariovistus/Project/test/test1/test1.cpp
new file mode 100644
index 00000000..f4d7208c
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/test/test1/test1.cpp
@@ -0,0 +1,5 @@
+#include "stuff.h"
+
+int main() {
+ X *x = SomeX();
+}
diff --git a/test/D/Issues/2940_Ariovistus/Project/test/test1/test2.d b/test/D/Issues/2940_Ariovistus/Project/test/test1/test2.d
new file mode 100644
index 00000000..4fbfa4d8
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/Project/test/test1/test2.d
@@ -0,0 +1,13 @@
+import std.stdio;
+
+struct X {
+}
+
+extern(C) int _ZN1X1yEv(X* _this);
+extern(C) X* _Z5SomeXv();
+
+void main() {
+ X *x = _Z5SomeXv();
+ int i = _ZN1X1yEv(x);
+ writeln("i: ", i);
+}
diff --git a/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_dmd.py b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_dmd.py
new file mode 100644
index 00000000..2446a28d
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_gdc.py b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_gdc.py
new file mode 100644
index 00000000..baf2921a
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_ldc.py b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_ldc.py
new file mode 100644
index 00000000..a61a94ba
--- /dev/null
+++ b/test/D/Issues/2940_Ariovistus/sconstest-correctLinkOptions_ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing using the gdc tool.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.correctLinkOptions import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/LDC.py b/test/D/LDC.py
new file mode 100644
index 00000000..94acf1ca
--- /dev/null
+++ b/test/D/LDC.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.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not isExecutableOfToolAvailable(test, 'ldc'):
+ test.skip_test("Could not find 'ldc', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['link', 'ldc'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/LDC_Alt.py b/test/D/LDC_Alt.py
new file mode 100644
index 00000000..571b8f04
--- /dev/null
+++ b/test/D/LDC_Alt.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.
+#
+
+# Amended by Russel Winder <russel@russel.org.uk> 2010-05-05
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not isExecutableOfToolAvailable(test, 'ldc'):
+ test.skip_test("Could not find 'ldc', skipping test.\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(tools=['ldc', 'link'], ENV=os.environ)
+if env['PLATFORM'] == 'cygwin': env['OBJSUFFIX'] = '.obj' # trick DMD
+env.Program('foo', 'foo.d')
+""")
+
+test.write('foo.d', """\
+import std.stdio;
+int main(string[] args) {
+ printf("Hello!");
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/MixedDAndC/Common/__init__.py b/test/D/MixedDAndC/Common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/MixedDAndC/Common/__init__.py
diff --git a/test/D/MixedDAndC/Common/common.py b/test/D/MixedDAndC/Common/common.py
new file mode 100644
index 00000000..66c738fd
--- /dev/null
+++ b/test/D/MixedDAndC/Common/common.py
@@ -0,0 +1,56 @@
+"""
+Test compiling and executing a project with a C module.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from os.path import abspath, dirname
+
+import sys
+sys.path.insert(1, abspath(dirname(__file__) + '/../../Support'))
+
+from executablesSearch import isExecutableOfToolAvailable
+
+def testForTool(tool):
+
+ test = TestSCons.TestSCons()
+
+ if not isExecutableOfToolAvailable(test, tool) :
+ test.skip_test("Required executable for tool '{}' not found, skipping test.\n".format(tool))
+
+ test.dir_fixture('Image')
+
+ test.run()
+
+ test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/MixedDAndC/Common/sconstest.skip b/test/D/MixedDAndC/Common/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/MixedDAndC/Common/sconstest.skip
diff --git a/test/D/MixedDAndC/Image/SConstruct b/test/D/MixedDAndC/Image/SConstruct
new file mode 100644
index 00000000..47870d7a
--- /dev/null
+++ b/test/D/MixedDAndC/Image/SConstruct
@@ -0,0 +1,13 @@
+# -*- codig:utf-8; -*-
+
+import os
+
+environment = Environment(
+ ENV=os.environ,
+ DFLAGS=['-m64', '-O'])
+
+environment.Program('proj', [
+'proj.d',
+'dmod.d',
+'cmod.c',
+])
diff --git a/test/D/MixedDAndC/Image/cmod.c b/test/D/MixedDAndC/Image/cmod.c
new file mode 100644
index 00000000..31be5e9e
--- /dev/null
+++ b/test/D/MixedDAndC/Image/cmod.c
@@ -0,0 +1,3 @@
+int csqr(int arg) {
+ return arg*arg;
+}
diff --git a/test/D/MixedDAndC/Image/dmod.d b/test/D/MixedDAndC/Image/dmod.d
new file mode 100644
index 00000000..c609b9c7
--- /dev/null
+++ b/test/D/MixedDAndC/Image/dmod.d
@@ -0,0 +1,6 @@
+module dmod;
+import std.stdio;
+
+void print_msg() {
+ writeln("Hello, this is a test program for the new SCons D support");
+}
diff --git a/test/D/MixedDAndC/Image/proj.d b/test/D/MixedDAndC/Image/proj.d
new file mode 100644
index 00000000..3e0bf951
--- /dev/null
+++ b/test/D/MixedDAndC/Image/proj.d
@@ -0,0 +1,12 @@
+import std.stdio;
+import dmod;
+
+extern (C) {
+ int csqr(int arg);
+}
+
+void main() {
+ print_msg();
+ auto i = 17;
+ writefln("The square of %d is %d", i, csqr(i));
+}
diff --git a/test/D/MixedDAndC/sconstest-dmd.py b/test/D/MixedDAndC/sconstest-dmd.py
new file mode 100644
index 00000000..df662556
--- /dev/null
+++ b/test/D/MixedDAndC/sconstest-dmd.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing a project with a C module.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('dmd')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/MixedDAndC/sconstest-gdc.py b/test/D/MixedDAndC/sconstest-gdc.py
new file mode 100644
index 00000000..7ac95c08
--- /dev/null
+++ b/test/D/MixedDAndC/sconstest-gdc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing a project with a C module.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('gdc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/MixedDAndC/sconstest-ldc.py b/test/D/MixedDAndC/sconstest-ldc.py
new file mode 100644
index 00000000..f9ab3429
--- /dev/null
+++ b/test/D/MixedDAndC/sconstest-ldc.py
@@ -0,0 +1,37 @@
+"""
+Test compiling and executing a project with a C module.
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+from Common.common import testForTool
+testForTool('ldc')
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/D/Support/executablesSearch.py b/test/D/Support/executablesSearch.py
new file mode 100755
index 00000000..e0487f6c
--- /dev/null
+++ b/test/D/Support/executablesSearch.py
@@ -0,0 +1,67 @@
+#! /usr/bin/env python
+
+"""
+Support functions for all the tests.
+"""
+
+#
+# __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__"
+
+def isExecutableOfToolAvailable(test, tool):
+ for executable in {
+ 'dmd': ['dmd', 'gdmd'],
+ 'gdc': ['gdc'],
+ 'ldc': ['ldc2', 'ldc']}[tool]:
+ if test.where_is(executable):
+ return True
+ return False
+
+if __name__ == '__main__':
+ import unittest
+ import sys
+ import os.path
+ sys.path.append(os.path.abspath('../../../QMTest'))
+ sys.path.append(os.path.abspath('../../../src/engine'))
+ import TestSCons
+
+ class VariousTests(unittest.TestCase):
+ def setUp(self):
+ self.test = TestSCons.TestSCons()
+ def test_None_tool(self):
+ self.assertRaises(KeyError, isExecutableOfToolAvailable, self.test, None)
+ def test_dmd_tool(self):
+ self.assertEqual(
+ self.test.where_is('dmd') is not None or self.test.where_is('gdmd') is not None,
+ isExecutableOfToolAvailable(self.test, 'dmd'))
+ def test_gdc_tool(self):
+ self.assertEqual(
+ self.test.where_is('gdc') is not None,
+ isExecutableOfToolAvailable(self.test, 'gdc'))
+ def test_ldc_tool(self):
+ self.assertEqual(
+ self.test.where_is('ldc2') is not None or self.test.where_is('ldc') is not None,
+ isExecutableOfToolAvailable(self.test, 'ldc'))
+
+ unittest.main()
diff --git a/test/D/Support/sconstest.skip b/test/D/Support/sconstest.skip
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/D/Support/sconstest.skip
diff --git a/test/Depends/no-Builder.py b/test/Depends/no-Builder.py
index 2d49756f..48ab7243 100644
--- a/test/Depends/no-Builder.py
+++ b/test/Depends/no-Builder.py
@@ -40,7 +40,7 @@ file2 = File('file2')
env.Depends(file1, [[file2, 'file3']])
# Verify that a "hidden" file created by another action causes the
# action to run when an explicit Dependency is specified.
-# See tigris.org issue 2647.
+# See http://scons.tigris.org/issues/show_bug.cgi?id=2647
env.Depends('hidden', 'file4.out')
env.Command('file4.out', 'file4.in',
[Copy('$TARGET', '$SOURCE'), Touch('hidden')])
diff --git a/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOM.py b/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOM.py
index eb75a8f0..d5af0ea0 100644
--- a/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOM.py
+++ b/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOM.py
@@ -42,7 +42,7 @@ Environment(tools = ['BitKeeper']).BitKeeper()
msg_bk = """The BitKeeper() factory is deprecated and there is no replacement."""
warn_bk = test.deprecated_fatal('deprecated-build-dir', msg_bk)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('BitKeeper', ['BitKeeper', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOMSTR.py b/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOMSTR.py
index ca58b831..ef70cb82 100644
--- a/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOMSTR.py
+++ b/test/Deprecated/SourceCode/BitKeeper/BITKEEPERCOMSTR.py
@@ -42,7 +42,7 @@ Environment(tools = ['BitKeeper']).BitKeeper()
msg_bk = """The BitKeeper() factory is deprecated and there is no replacement."""
warn_bk = test.deprecated_fatal('deprecated-build-dir', msg_bk)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('BitKeeper', ['BitKeeper', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py b/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py
index 29597363..04dfd9b0 100644
--- a/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py
+++ b/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py
@@ -42,7 +42,7 @@ Environment(tools = ['BitKeeper']).BitKeeper()
msg_bk = """The BitKeeper() factory is deprecated and there is no replacement."""
warn_bk = test.deprecated_fatal('deprecated-build-dir', msg_bk)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.skip_test("Need BitKeeper to debug these tests.\n")
diff --git a/test/Deprecated/SourceCode/CVS/CVS.py b/test/Deprecated/SourceCode/CVS/CVS.py
index b5b51bcf..a1276fe7 100644
--- a/test/Deprecated/SourceCode/CVS/CVS.py
+++ b/test/Deprecated/SourceCode/CVS/CVS.py
@@ -40,7 +40,7 @@ Environment(tools = ['CVS']).CVS('')
msg_cvs = """The CVS() factory is deprecated and there is no replacement."""
warn_cvs = test.deprecated_fatal('deprecated-build-dir', msg_cvs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
cvs = test.where_is('cvs')
diff --git a/test/Deprecated/SourceCode/CVS/CVSCOM.py b/test/Deprecated/SourceCode/CVS/CVSCOM.py
index b9d9c769..a0f84000 100644
--- a/test/Deprecated/SourceCode/CVS/CVSCOM.py
+++ b/test/Deprecated/SourceCode/CVS/CVSCOM.py
@@ -42,7 +42,7 @@ Environment(tools = ['CVS']).CVS('')
msg_cvs = """The CVS() factory is deprecated and there is no replacement."""
warn_cvs = test.deprecated_fatal('deprecated-build-dir', msg_cvs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('CVS', ['CVS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/CVS/CVSCOMSTR.py b/test/Deprecated/SourceCode/CVS/CVSCOMSTR.py
index 9a6cf647..f793d662 100644
--- a/test/Deprecated/SourceCode/CVS/CVSCOMSTR.py
+++ b/test/Deprecated/SourceCode/CVS/CVSCOMSTR.py
@@ -42,7 +42,7 @@ Environment(tools = ['CVS']).CVS('')
msg_cvs = """The CVS() factory is deprecated and there is no replacement."""
warn_cvs = test.deprecated_fatal('deprecated-build-dir', msg_cvs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('CVS', ['CVS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/Perforce/P4COM.py b/test/Deprecated/SourceCode/Perforce/P4COM.py
index 92ae5478..9b9bab1e 100644
--- a/test/Deprecated/SourceCode/Perforce/P4COM.py
+++ b/test/Deprecated/SourceCode/Perforce/P4COM.py
@@ -42,7 +42,7 @@ Environment(tools = ['Perforce']).Perforce()
msg_p4 = """The Perforce() factory is deprecated and there is no replacement."""
warn_p4 = test.deprecated_fatal('deprecated-build-dir', msg_p4)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('Perforce', ['Perforce', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/Perforce/P4COMSTR.py b/test/Deprecated/SourceCode/Perforce/P4COMSTR.py
index d0228244..7a240210 100644
--- a/test/Deprecated/SourceCode/Perforce/P4COMSTR.py
+++ b/test/Deprecated/SourceCode/Perforce/P4COMSTR.py
@@ -43,7 +43,7 @@ Environment(tools = ['Perforce']).Perforce()
msg_p4 = """The Perforce() factory is deprecated and there is no replacement."""
warn_p4 = test.deprecated_fatal('deprecated-build-dir', msg_p4)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('Perforce', ['Perforce', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/Perforce/Perforce.py b/test/Deprecated/SourceCode/Perforce/Perforce.py
index ebf9cfb1..3be22d8d 100644
--- a/test/Deprecated/SourceCode/Perforce/Perforce.py
+++ b/test/Deprecated/SourceCode/Perforce/Perforce.py
@@ -43,7 +43,7 @@ Environment(tools = ['Perforce']).Perforce()
msg_p4 = """The Perforce() factory is deprecated and there is no replacement."""
warn_p4 = test.deprecated_fatal('deprecated-build-dir', msg_p4)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
class TestPerforce(TestSCons.TestSCons):
diff --git a/test/Deprecated/SourceCode/RCS/RCS_COCOM.py b/test/Deprecated/SourceCode/RCS/RCS_COCOM.py
index 20f0da69..765c88cb 100644
--- a/test/Deprecated/SourceCode/RCS/RCS_COCOM.py
+++ b/test/Deprecated/SourceCode/RCS/RCS_COCOM.py
@@ -42,7 +42,7 @@ Environment(tools = ['RCS']).RCS()
msg_rcs = """The RCS() factory is deprecated and there is no replacement."""
warn_rcs = test.deprecated_fatal('deprecated-build-dir', msg_rcs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('RCS', ['RCS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/RCS/RCS_COCOMSTR.py b/test/Deprecated/SourceCode/RCS/RCS_COCOMSTR.py
index 3626376c..57088fa6 100644
--- a/test/Deprecated/SourceCode/RCS/RCS_COCOMSTR.py
+++ b/test/Deprecated/SourceCode/RCS/RCS_COCOMSTR.py
@@ -42,7 +42,7 @@ Environment(tools = ['RCS']).RCS()
msg_rcs = """The RCS() factory is deprecated and there is no replacement."""
warn_rcs = test.deprecated_fatal('deprecated-build-dir', msg_rcs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('RCS', ['RCS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/RCS/changed.py b/test/Deprecated/SourceCode/RCS/changed.py
index 14c80bd7..fec1ba36 100644
--- a/test/Deprecated/SourceCode/RCS/changed.py
+++ b/test/Deprecated/SourceCode/RCS/changed.py
@@ -38,7 +38,7 @@ Environment(tools = ['RCS']).RCS()
msg_rcs = """The RCS() factory is deprecated and there is no replacement."""
warn_rcs = test.deprecated_fatal('deprecated-build-dir', msg_rcs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
rcs = test.where_is('rcs')
diff --git a/test/Deprecated/SourceCode/RCS/explicit.py b/test/Deprecated/SourceCode/RCS/explicit.py
index 53c336af..96ce02f8 100644
--- a/test/Deprecated/SourceCode/RCS/explicit.py
+++ b/test/Deprecated/SourceCode/RCS/explicit.py
@@ -40,7 +40,7 @@ Environment(tools = ['RCS']).RCS()
msg_rcs = """The RCS() factory is deprecated and there is no replacement."""
warn_rcs = test.deprecated_fatal('deprecated-build-dir', msg_rcs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
rcs = test.where_is('rcs')
diff --git a/test/Deprecated/SourceCode/SCCS/SCCSCOM.py b/test/Deprecated/SourceCode/SCCS/SCCSCOM.py
index a08241f1..6ad02ac1 100644
--- a/test/Deprecated/SourceCode/SCCS/SCCSCOM.py
+++ b/test/Deprecated/SourceCode/SCCS/SCCSCOM.py
@@ -42,7 +42,7 @@ Environment(tools = ['SCCS']).SCCS()
msg_sccs = """The SCCS() factory is deprecated and there is no replacement."""
warn_sccs = test.deprecated_fatal('deprecated-build-dir', msg_sccs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('SCCS', ['SCCS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/SCCS/SCCSCOMSTR.py b/test/Deprecated/SourceCode/SCCS/SCCSCOMSTR.py
index 5204ee3e..a7574955 100644
--- a/test/Deprecated/SourceCode/SCCS/SCCSCOMSTR.py
+++ b/test/Deprecated/SourceCode/SCCS/SCCSCOMSTR.py
@@ -42,7 +42,7 @@ Environment(tools = ['SCCS']).SCCS()
msg_sccs = """The SCCS() factory is deprecated and there is no replacement."""
warn_sccs = test.deprecated_fatal('deprecated-build-dir', msg_sccs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
test.subdir('SCCS', ['SCCS', 'sub'], 'sub')
diff --git a/test/Deprecated/SourceCode/SCCS/diskcheck.py b/test/Deprecated/SourceCode/SCCS/diskcheck.py
index d2364b6d..060c7a28 100644
--- a/test/Deprecated/SourceCode/SCCS/diskcheck.py
+++ b/test/Deprecated/SourceCode/SCCS/diskcheck.py
@@ -40,7 +40,7 @@ Environment(tools = ['SCCS']).SCCS()
msg_sccs = """The SCCS() factory is deprecated and there is no replacement."""
warn_sccs = test.deprecated_fatal('deprecated-build-dir', msg_sccs)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
sccs = test.where_is('sccs')
diff --git a/test/Deprecated/SourceCode/SourceCode.py b/test/Deprecated/SourceCode/SourceCode.py
index d440581a..b5c0ba9c 100644
--- a/test/Deprecated/SourceCode/SourceCode.py
+++ b/test/Deprecated/SourceCode/SourceCode.py
@@ -38,7 +38,7 @@ SourceCode('.', None)
""")
msg = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warning = test.deprecated_warning('deprecated-source-code', msg)
test.subdir('sub', 'sub2')
diff --git a/test/Deprecated/SourceCode/Subversion.py b/test/Deprecated/SourceCode/Subversion.py
index 7d45a8ca..7ed4b154 100644
--- a/test/Deprecated/SourceCode/Subversion.py
+++ b/test/Deprecated/SourceCode/Subversion.py
@@ -40,7 +40,7 @@ Environment(tools = ['Subversion']).Subversion('')
msg_svn = """The Subversion() factory is deprecated and there is no replacement."""
warn_svn = test.deprecated_fatal('deprecated-build-dir', msg_svn)
msg_sc = """SourceCode() has been deprecated and there is no replacement.
-\tIf you need this function, please contact dev@scons.tigris.org."""
+\tIf you need this function, please contact scons-dev@scons.org"""
warn_sc = test.deprecated_wrap(msg_sc)
svn = test.where_is('svn')
diff --git a/test/ExecuteInvalidateCache.py b/test/ExecuteInvalidateCache.py
index 88ae3939..a22c5eab 100644
--- a/test/ExecuteInvalidateCache.py
+++ b/test/ExecuteInvalidateCache.py
@@ -26,7 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Test the Execute() functions clears the memoized values of affected target Nodes
-when used with Delete(). Derived from Tigris issue 1307.
+when used with Delete(). Derived from
+http://scons.tigris.org/issues/show_bug.cgi?id=1307
"""
import TestSCons
diff --git a/test/Fortran/F95FLAGS.py b/test/Fortran/F95FLAGS.py
index de188585..8c3ce093 100644
--- a/test/Fortran/F95FLAGS.py
+++ b/test/Fortran/F95FLAGS.py
@@ -104,6 +104,12 @@ g95 = test.detect_tool(fc)
if g95:
+ test.subdir('x')
+
+ test.write(['x','dummy.i'],
+"""
+# Exists only such that -Ix finds the directory...
+""")
test.write("wrapper.py",
"""import os
diff --git a/test/Fortran/SHF95FLAGS.py b/test/Fortran/SHF95FLAGS.py
index b945bac1..8e758789 100644
--- a/test/Fortran/SHF95FLAGS.py
+++ b/test/Fortran/SHF95FLAGS.py
@@ -103,6 +103,13 @@ g95 = test.detect_tool(fc)
if g95:
+ test.subdir('x')
+
+ test.write(['x','dummy.i'],
+"""
+# Exists only such that -Ix finds the directory...
+""")
+
test.write("wrapper.py",
"""import os
import sys
diff --git a/test/Fortran/USE-MODULE-CASEINSENS.py b/test/Fortran/USE-MODULE-CASEINSENS.py
index 79d51251..44c03feb 100644
--- a/test/Fortran/USE-MODULE-CASEINSENS.py
+++ b/test/Fortran/USE-MODULE-CASEINSENS.py
@@ -26,7 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
# This test tests whether a file that defines a module "a" and
# then uses it with a different case ("A") works. Pre-2.0, this
-# gave a spurious dependency cycle error. See Tigris issue #2574.
+# gave a spurious dependency cycle error.
+# See http://scons.tigris.org/issues/show_bug.cgi?id=2574
import TestSCons
diff --git a/test/Java/DerivedSourceTest.py b/test/Java/DerivedSourceTest.py
new file mode 100644
index 00000000..c749cf36
--- /dev/null
+++ b/test/Java/DerivedSourceTest.py
@@ -0,0 +1,124 @@
+#!/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 of javac.py when building java code from derived sources.
+
+Original issue definition:
+Java emitter for derived sources outputs bogus class files.
+
+Repeatable with any N-tier, with N > 1, Java derived-source builds where
+any of the following conditions are meet:
+1. The java class does not belong to the root package.
+2. A java source (*.java) creates N targets (*.class) where N > 1.
+"""
+
+import os
+import TestSCons
+import SCons.Node.FS
+import SCons.Defaults
+
+SCons.Defaults.DefaultEnvironment(tools = [])
+
+test = TestSCons.TestSCons()
+
+# No result if tools not available
+test.no_result( condition=(test.where_is( 'javac' ) is None) )
+test.no_result( condition=(test.where_is( 'jar' ) is None) )
+
+# This test is known to fail as of July 2014; see Tigris issue 1771 and issue 2931.
+# Once the underlying issue is corrected, this test should be re-enabled.
+test.skip_test('Skipping derived-source test until issue 1771 is fixed.\n')
+
+test.write(
+ ['Sample.java'],
+"""
+// Condition 1: class does not exist in the root package.
+package org.sample;
+
+public class Sample {
+ // Condition 2: inner class definition causes javac to create
+ // a second class file.
+ enum InnerEnum {
+ stuff,
+ and,
+ things
+ }
+}
+"""
+)
+
+test.write(
+ ['SConstruct'],
+"""
+import os
+
+env = Environment(
+ tools = [
+ 'javac',
+ 'jar',
+ ]
+)
+
+env.Command(
+ os.path.join( 'org', 'sample', 'Sample.java' ),
+ 'Sample.java',
+ Copy(
+ '$TARGET',
+ '$SOURCE'
+ )
+)
+
+# Copy operation makes the *.java file(s) under org derived-source.
+env.Java(
+ 'build',
+ 'org'
+)
+"""
+)
+
+expected = test.wrap_stdout(
+build_str =
+'''\
+Copy("org/sample/Sample.java", "Sample.java")
+javac -d build -sourcepath org/sample org/sample/Sample.java
++-.
+ +-build
+ | +-build/org
+ | +-build/org/sample
+ | +-build/org/sample/Sample$InnerEnum.class
+ | +-org/sample/Sample.java
+ | +-build/org/sample/Sample.class
+ | +-org/sample/Sample.java
+ +-org
+ +-org/sample
+ +-org/sample/Sample.java
+'''.replace( '/', os.sep )
+)
+
+test.run( arguments = '--tree=derived', stdout = expected )
+
+test.up_to_date(arguments = '.')
diff --git a/test/Java/RMIC.py b/test/Java/RMIC.py
index f88dd147..876ed804 100644
--- a/test/Java/RMIC.py
+++ b/test/Java/RMIC.py
@@ -94,14 +94,31 @@ line 3
where_javac, java_version = test.java_where_javac()
where_rmic = test.java_where_rmic()
-test.write("wrapper.py", """\
+# Try to get the major/minor Java version
+curver = (1, 0)
+if java_version.count('.') == 1:
+ # Check Java version
+ major, minor = java_version.split('.')
+ try:
+ curver = (int(major), int(minor))
+ except:
+ pass
+
+# Check the version of the found Java compiler.
+# If it's 1.8 or higher, we skip the further RMIC test
+# because we'll get warnings about the deprecated API...
+# it's just not state-of-the-art anymore.
+# Note, how we allow simple version strings like "5" and
+# "6" to successfully pass this test.
+if curver < (1, 8):
+ test.write("wrapper.py", """\
import os
import sys
open('%s', 'ab').write("wrapper.py %%s\\n" %% " ".join(sys.argv[1:]))
os.system(" ".join(sys.argv[1:]))
""" % test.workpath('wrapper.out').replace('\\', '\\\\'))
-test.write('SConstruct', """
+ test.write('SConstruct', """
foo = Environment(tools = ['javac', 'rmic'],
JAVAC = r'%(where_javac)s',
RMIC = r'%(where_rmic)s')
@@ -121,15 +138,15 @@ bar_classes = [c for c in bar_classes if str(c).find('Hello') == -1]
bar.RMIC(target = Dir('outdir2'), source = bar_classes)
""" % locals() )
-test.subdir('com',
- ['com', 'other'],
- ['com', 'sub'],
- ['com', 'sub', 'foo'],
- ['com', 'sub', 'bar'],
- 'src3a',
- 'src3b')
-
-test.write(['com', 'sub', 'foo', 'Hello.java'], """\
+ test.subdir('com',
+ ['com', 'other'],
+ ['com', 'sub'],
+ ['com', 'sub', 'foo'],
+ ['com', 'sub', 'bar'],
+ 'src3a',
+ 'src3b')
+
+ test.write(['com', 'sub', 'foo', 'Hello.java'], """\
package com.sub.foo;
import java.rmi.Remote;
@@ -140,7 +157,7 @@ public interface Hello extends Remote {
}
""")
-test.write(['com', 'sub', 'foo', 'Example1.java'], """\
+ test.write(['com', 'sub', 'foo', 'Example1.java'], """\
package com.sub.foo;
import java.rmi.Naming;
@@ -179,7 +196,7 @@ public class Example1 extends UnicastRemoteObject implements Hello {
}
""")
-test.write(['com', 'sub', 'foo', 'Example2.java'], """\
+ test.write(['com', 'sub', 'foo', 'Example2.java'], """\
package com.sub.foo;
import java.rmi.Naming;
@@ -218,7 +235,7 @@ public class Example2 extends UnicastRemoteObject implements Hello {
}
""")
-test.write(['com', 'sub', 'bar', 'Hello.java'], """\
+ test.write(['com', 'sub', 'bar', 'Hello.java'], """\
package com.sub.bar;
import java.rmi.Remote;
@@ -229,7 +246,7 @@ public interface Hello extends Remote {
}
""")
-test.write(['com', 'sub', 'bar', 'Example3.java'], """\
+ test.write(['com', 'sub', 'bar', 'Example3.java'], """\
package com.sub.bar;
import java.rmi.Naming;
@@ -268,7 +285,7 @@ public class Example3 extends UnicastRemoteObject implements Hello {
}
""")
-test.write(['com', 'sub', 'bar', 'Example4.java'], """\
+ test.write(['com', 'sub', 'bar', 'Example4.java'], """\
package com.sub.bar;
import java.rmi.Naming;
@@ -307,26 +324,26 @@ public class Example4 extends UnicastRemoteObject implements Hello {
}
""")
-test.run(arguments = '.')
-
-test.fail_test(test.read('wrapper.out') != "wrapper.py %s -d outdir2 -classpath class2 com.sub.bar.Example3 com.sub.bar.Example4\n" % where_rmic)
-
-test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example1_Stub.class'))
-test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example2_Stub.class'))
-test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example3_Stub.class'))
-test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example4_Stub.class'))
-
-# We used to check for _Skel.class files as well, but they're not
-# generated by default starting with Java 1.5, and they apparently
-# haven't been needed for a while. Don't bother looking, even if we're
-# running Java 1.4. If we think they're needed but they don't exist
-# the test.up_to_date() call below will detect it.
-#test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example1_Skel.class'))
-#test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example2_Skel.class'))
-#test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example3_Skel.class'))
-#test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example4_Skel.class'))
-
-test.up_to_date(arguments = '.')
+ test.run(arguments = '.')
+
+ test.fail_test(test.read('wrapper.out') != "wrapper.py %s -d outdir2 -classpath class2 com.sub.bar.Example3 com.sub.bar.Example4\n" % where_rmic)
+
+ test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example1_Stub.class'))
+ test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example2_Stub.class'))
+ test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example3_Stub.class'))
+ test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example4_Stub.class'))
+
+ # We used to check for _Skel.class files as well, but they're not
+ # generated by default starting with Java 1.5, and they apparently
+ # haven't been needed for a while. Don't bother looking, even if we're
+ # running Java 1.4. If we think they're needed but they don't exist
+ # the test.up_to_date() call below will detect it.
+ #test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example1_Skel.class'))
+ #test.must_exist(test.workpath('outdir1', 'com', 'sub', 'foo', 'Example2_Skel.class'))
+ #test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example3_Skel.class'))
+ #test.must_exist(test.workpath('outdir2', 'com', 'sub', 'bar', 'Example4_Skel.class'))
+
+ test.up_to_date(arguments = '.')
test.pass_test()
diff --git a/test/Libs/SharedLibrary-update-deps.py b/test/Libs/SharedLibrary-update-deps.py
index 5394bc7a..076e3ad0 100644
--- a/test/Libs/SharedLibrary-update-deps.py
+++ b/test/Libs/SharedLibrary-update-deps.py
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Test that SharedLibrary() updates when a different lib is linked, even if it has the same md5.
-This is Tigris bug #2903.
+This is http://scons.tigris.org/issues/show_bug.cgi?id=2903
"""
import sys
diff --git a/test/NoClean.py b/test/NoClean.py
new file mode 100644
index 00000000..01fe209d
--- /dev/null
+++ b/test/NoClean.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__"
+
+#
+# This test ensures that NoClean works correctly, even when it's applied to
+# a single target in the return list of an multi-target Builder.
+#
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+def action(target, source, env):
+ for t in target: open(t.path, 'w')
+Command('1.out', 'SConstruct', action)
+NoClean('1.out')
+""")
+
+test.write('SConstruct.force', """
+def action(target, source, env):
+ for t in target: open(t.path, 'w')
+ open('4.out', 'w')
+res = Command('3.out', 'SConstruct.force', action)
+Clean('4.out', res)
+NoClean('4.out')
+""")
+
+test.write('SConstruct.multi', """
+def action(target, source, env):
+ for t in target: open(t.path, 'w')
+Command(['5.out', '6.out'], 'SConstruct.multi', action)
+NoClean('6.out')
+""")
+
+#
+# Basic check: NoClean keeps files
+#
+test.run()
+test.run(arguments='-c')
+
+test.must_exist('1.out')
+
+#
+# Check: NoClean overrides Clean
+#
+test.run(arguments=['-f', 'SConstruct.force'])
+test.run(arguments=['-f', 'SConstruct.force', '-c'])
+
+test.must_not_exist('3.out')
+test.must_exist('4.out')
+
+#
+# Check: NoClean works for multi-target Builders
+#
+test.run(arguments=['-f', 'SConstruct.multi'])
+test.run(arguments=['-f', 'SConstruct.multi', '-c'])
+
+test.must_not_exist('5.out')
+test.must_exist('6.out')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Repository/RMIC.py b/test/Repository/RMIC.py
index b214b4bd..886ccdbc 100644
--- a/test/Repository/RMIC.py
+++ b/test/Repository/RMIC.py
@@ -35,6 +35,27 @@ python = TestSCons.python
test = TestSCons.TestSCons()
where_javac, java_version = test.java_where_javac()
+
+# Try to get the major/minor Java version
+curver = (1, 0)
+if java_version.count('.') == 1:
+ # Check Java version
+ major, minor = java_version.split('.')
+ try:
+ curver = (int(major), int(minor))
+ except:
+ pass
+
+# Check the version of the found Java compiler.
+# If it's 1.8 or higher, we skip the further RMIC test
+# because we'll get warnings about the deprecated API...
+# it's just not state-of-the-art anymore.
+# Note, how we allow simple version strings like "5" and
+# "6" to successfully pass this test.
+if curver >= (1, 8):
+ test.skip_test('The found version of javac is higher than 1.7, skipping test.\n')
+
+
where_java = test.java_where_java()
where_rmic = test.java_where_rmic()
diff --git a/test/SWIG/SWIGFLAGS.py b/test/SWIG/SWIGFLAGS.py
index 88f51849..cb91699f 100644
--- a/test/SWIG/SWIGFLAGS.py
+++ b/test/SWIG/SWIGFLAGS.py
@@ -28,6 +28,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
Verify that we can use ${SOURCE} expansions in $SWIGFLAGS.
"""
+import sys
import TestSCons
test = TestSCons.TestSCons()
@@ -54,9 +55,10 @@ test.write(['src', 'bar.i'], """\
test.write('SConstruct', """
# Note that setting the -I option in $SWIGFLAGS is not good and the
# documentation says to use $SWIGPATH. This is just for testing.
-env = Environment(SWIGFLAGS='-python -I${SOURCE.dir}')
+env = Environment(SWIGFLAGS='-python -I${SOURCE.dir}',
+ SWIG=r'%(swig)s')
env.CFile(target = 'foo', source = ['src/foo.i'])
-""")
+""" % locals())
test.run()
diff --git a/test/SWIG/SWIGOUTDIR-python.py b/test/SWIG/SWIGOUTDIR-python.py
index c94e509c..db0cc958 100644
--- a/test/SWIG/SWIGOUTDIR-python.py
+++ b/test/SWIG/SWIGOUTDIR-python.py
@@ -31,6 +31,7 @@ that Python files are created in the specified output directory.
import TestSCons
import os
+import sys
test = TestSCons.TestSCons()
@@ -44,8 +45,15 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Can not find %s, skipping test.\n' % Python_h)
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
env = Environment(SWIGFLAGS = '-python -c++',
+ %(swig_arch_var)s
CPPPATH=[r"%(python_include)s"],
SWIG=[r'%(swig)s'],
SWIGOUTDIR='python/build dir',
@@ -64,17 +72,17 @@ test.write('python_foo_interface.i', """\
# subdirectory to hold the generated .py files.
test.run(arguments = '.')
-test.must_exist('python/build dir/foopack.py')
+test.must_exist('python/build dir/foopack.py')
# SCons should remove the built .py files.
test.run(arguments = '-c')
-test.must_not_exist('python/build dir/foopack.py')
+test.must_not_exist('python/build dir/foopack.py')
# SCons should realize it needs to rebuild the removed .py files.
test.not_up_to_date(arguments = '.')
-test.must_exist('python/build dir/foopack.py')
+test.must_exist('python/build dir/foopack.py')
test.pass_test()
diff --git a/test/SWIG/SWIGPATH.py b/test/SWIG/SWIGPATH.py
index 30426da1..55e8d7ea 100644
--- a/test/SWIG/SWIGPATH.py
+++ b/test/SWIG/SWIGPATH.py
@@ -55,6 +55,7 @@ test.write("dependent.i", """\
test.write('SConstruct', """
foo = Environment(SWIGFLAGS='-python',
+ SWIG='%(swig)s',
SWIGPATH=['inc1', 'inc2'])
swig = foo.Dictionary('SWIG')
bar = foo.Clone(SWIG = [r'%(python)s', 'wrapper.py', swig])
diff --git a/test/SWIG/build-dir.py b/test/SWIG/build-dir.py
index 4e5bfe99..304932f7 100644
--- a/test/SWIG/build-dir.py
+++ b/test/SWIG/build-dir.py
@@ -45,7 +45,7 @@ if not swig:
if sys.platform == 'win32':
_dll = '.dll'
else:
- _dll = '.so'
+ _dll = '.so'
test.subdir(['source'])
@@ -55,11 +55,17 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Can not find %s, skipping test.\n' % Python_h)
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
#
# Create the build environment.
#
env = Environment(CPPPATH = [".", r'%(python_include)s'],
+ %(swig_arch_var)s
CPPDEFINES = "NDEBUG",
SWIG = [r'%(swig)s'],
SWIGFLAGS = ["-python", "-c++"],
@@ -123,11 +129,11 @@ class Vector
public:
Vector(int n = 0);
~Vector();
-
+
%extend
{
const char* __str__() { return "linalg.Vector()"; }
-
+
%pythoncode %{
def __iter__(self):
for i in range(len(self)):
diff --git a/test/SWIG/generated_swigfile.py b/test/SWIG/generated_swigfile.py
index 1187df22..d09b4737 100644
--- a/test/SWIG/generated_swigfile.py
+++ b/test/SWIG/generated_swigfile.py
@@ -39,14 +39,14 @@ import TestSCons
if sys.platform == 'win32':
_dll = '.dll'
else:
- _dll = '.so'
+ _dll = '.so'
# swig-python expects specific filenames.
# the platform specific suffix won't necessarily work.
if sys.platform == 'win32':
_dll = '.dll'
else:
- _dll = '.so'
+ _dll = '.so'
test = TestSCons.TestSCons()
@@ -69,17 +69,17 @@ foo = Environment(CPPPATH=[r'%(python_include)s'],
SWIG=[r'%(swig)s'],
LIBPATH=[r'%(python_libpath)s'],
)
-python_interface = foo.Command( 'test_py_swig.i', Value(1), "echo '%%module test_py_swig' > test_py_swig.i" )
+python_interface = foo.Command( 'test_py_swig.i', Value(1), 'echo %%module test_py_swig > test_py_swig.i' )
python_c_file = foo.CFile( target='python_swig_test',source=python_interface, SWIGFLAGS = '-python -c++' )
-java_interface = foo.Command( 'test_java_swig.i', Value(1),"echo '%%module test_java_swig' > test_java_swig.i" )
-java_c_file = foo.CFile( target='java_swig_test' ,source=java_interface, SWIGFLAGS = '-java -c++' )
+java_interface = foo.Command( 'test_java_swig.i', Value(1),'echo %%module test_java_swig > test_java_swig.i' )
+java_c_file = foo.CFile( target='java_swig_test' ,source=java_interface, SWIGFLAGS = '-java -c++' )
""" % locals())
expected_stdout = """\
-echo '%%module test_java_swig' > test_java_swig.i
+echo %%module test_java_swig > test_java_swig.i
%(swig)s -o java_swig_test_wrap.cc -java -c++ test_java_swig.i
-echo '%%module test_py_swig' > test_py_swig.i
+echo %%module test_py_swig > test_py_swig.i
%(swig)s -o python_swig_test_wrap.cc -python -c++ test_py_swig.i
""" % locals()
test.run(arguments = '.',stdout=test.wrap_stdout(expected_stdout))
diff --git a/test/SWIG/implicit-dependencies.py b/test/SWIG/implicit-dependencies.py
index 6d402162..465a0d65 100644
--- a/test/SWIG/implicit-dependencies.py
+++ b/test/SWIG/implicit-dependencies.py
@@ -52,7 +52,7 @@ test.write("dependent.i", """\
""")
test.write('SConstruct', """
-foo = Environment(SWIGFLAGS='-python')
+foo = Environment(SWIGFLAGS='-python', SWIG='%(swig)s')
swig = foo.Dictionary('SWIG')
bar = foo.Clone(SWIG = [r'%(python)s', r'wrapper.py', swig])
foo.CFile(target = 'dependent', source = ['dependent.i'])
diff --git a/test/SWIG/live.py b/test/SWIG/live.py
index 4d4369e6..7d79baed 100644
--- a/test/SWIG/live.py
+++ b/test/SWIG/live.py
@@ -36,7 +36,7 @@ import TestSCons
# swig-python expects specific filenames.
# the platform specific suffix won't necessarily work.
if sys.platform == 'win32':
- _dll = '.dll'
+ _dll = '.pyd'
else:
_dll = '.so'
@@ -55,6 +55,12 @@ if not os.path.exists(Python_h):
# handle testing on other platforms:
ldmodule_prefix = '_'
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write("wrapper.py",
"""import os
import sys
@@ -64,11 +70,12 @@ os.system(" ".join(sys.argv[1:]))
test.write('SConstruct', """\
foo = Environment(SWIGFLAGS='-python',
+ LIBPATH=[r'%(python_libpath)s'],
CPPPATH=[r'%(python_include)s'],
LDMODULEPREFIX='%(ldmodule_prefix)s',
LDMODULESUFFIX='%(_dll)s',
SWIG=[r'%(swig)s'],
- LIBPATH=[r'%(python_libpath)s'],
+ %(swig_arch_var)s
LIBS='%(python_lib)s',
)
diff --git a/test/SWIG/module-deduced-name.py b/test/SWIG/module-deduced-name.py
index 733b6c11..bdaef4f9 100644
--- a/test/SWIG/module-deduced-name.py
+++ b/test/SWIG/module-deduced-name.py
@@ -32,6 +32,7 @@ emitter should return the basename of the module only.
import TestSCons
import os
+import sys
test = TestSCons.TestSCons()
@@ -45,8 +46,15 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Cannot find %s, skipping test.\n' % Python_h)
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
env = Environment(SWIGFLAGS = '-python -c++',
+ %(swig_arch_var)s
CPPPATH=[r"%(python_include)s"],
SWIG=[r'%(swig)s'],
SWIGOUTDIR='python/build dir',
diff --git a/test/SWIG/module-parens.py b/test/SWIG/module-parens.py
index 6ae49244..d8c17444 100644
--- a/test/SWIG/module-parens.py
+++ b/test/SWIG/module-parens.py
@@ -30,6 +30,7 @@ without white space before the opening parenthesis.
"""
import os.path
+import sys
import TestSCons
test = TestSCons.TestSCons()
@@ -44,16 +45,31 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Can not find %s, skipping test.\n' % Python_h)
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+ _dll = '.pyd'
+else:
+ _dll = '.so'
+
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
env = Environment(SWIGFLAGS = '-python -c++',
+ %(swig_arch_var)s
CPPPATH=[r'%(python_include)s'],
SWIG=[r'%(swig)s'],
LIBPATH=[r'%(python_libpath)s'],
LIBS='%(python_lib)s',
+ LDMODULESUFFIX='%(_dll)s',
)
-env.LoadableModule('test1.so', ['test1.i', 'test1.cc'])
-env.LoadableModule('test2.so', ['test2.i', 'test2.cc'])
+env.LoadableModule('test1', ['test1.i', 'test1.cc'])
+env.LoadableModule('test2', ['test2.i', 'test2.cc'])
""" % locals())
test.write(['test1.cc'], """\
diff --git a/test/SWIG/module-quoted.py b/test/SWIG/module-quoted.py
index ec7a1327..6f4b8915 100644
--- a/test/SWIG/module-quoted.py
+++ b/test/SWIG/module-quoted.py
@@ -30,6 +30,7 @@ Verify that we correctly parse quoted module names; e.g. %module "test"
"""
import os.path
+import sys
import TestSCons
test = TestSCons.TestSCons()
@@ -44,15 +45,30 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Can not find %s, skipping test.\n' % Python_h)
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+ _dll = '.pyd'
+else:
+ _dll = '.so'
+
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
env = Environment(SWIGFLAGS = '-python -c++',
+ %(swig_arch_var)s
CPPPATH=[r'%(python_include)s'],
SWIG=[r'%(swig)s'],
LIBPATH=[r'%(python_libpath)s'],
LIBS='%(python_lib)s',
+ LDMODULESUFFIX='%(_dll)s',
)
-env.LoadableModule('test1.so', ['test1.i', 'test1.cc'])
+env.LoadableModule('test1', ['test1.i', 'test1.cc'])
""" % locals())
test.write(['test1.cc'], """\
diff --git a/test/SWIG/module-spaces.py b/test/SWIG/module-spaces.py
index a0056f0c..2833dffc 100644
--- a/test/SWIG/module-spaces.py
+++ b/test/SWIG/module-spaces.py
@@ -30,6 +30,7 @@ the module name ; e.g. "%module test "
"""
import os.path
+import sys
import TestSCons
test = TestSCons.TestSCons()
@@ -44,15 +45,30 @@ Python_h = os.path.join(python_include, 'Python.h')
if not os.path.exists(Python_h):
test.skip_test('Can not find %s, skipping test.\n' % Python_h)
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+ _dll = '.pyd'
+else:
+ _dll = '.so'
+
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write(['SConstruct'], """\
env = Environment(SWIGFLAGS = '-python -c++',
+ %(swig_arch_var)s
CPPPATH=[r'%(python_include)s'],
SWIG=[r'%(swig)s'],
LIBPATH=[r'%(python_libpath)s'],
LIBS='%(python_lib)s',
+ LDMODULESUFFIX='%(_dll)s',
)
-env.LoadableModule('test1.so', ['test1.i', 'test1.cc'])
+env.LoadableModule('test1', ['test1.i', 'test1.cc'])
""" % locals())
test.write(['test1.cc'], """\
@@ -67,7 +83,7 @@ int test1func();
""")
test.write(['test1.i'], """\
-%module test1
+%module test1
%{
#include "test1.h"
diff --git a/test/SWIG/remove-modules.py b/test/SWIG/remove-modules.py
index 964970bb..f5ce60d1 100644
--- a/test/SWIG/remove-modules.py
+++ b/test/SWIG/remove-modules.py
@@ -56,6 +56,11 @@ if not os.path.exists(Python_h):
# handle testing on other platforms:
ldmodule_prefix = '_'
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
test.write("module.i", """\
%module modulename
@@ -63,6 +68,7 @@ test.write("module.i", """\
test.write('SConstruct', """
foo = Environment(SWIGFLAGS='-python',
+ %(swig_arch_var)s
CPPPATH=['%(python_include)s'],
LDMODULEPREFIX='%(ldmodule_prefix)s',
LDMODULESUFFIX='%(_dll)s',
diff --git a/test/SWIG/subdir.py b/test/SWIG/subdir.py
index 0b9f24d4..e23b858c 100644
--- a/test/SWIG/subdir.py
+++ b/test/SWIG/subdir.py
@@ -39,7 +39,7 @@ import TestSCons
if sys.platform == 'win32':
_dll = '.dll'
else:
- _dll = '.so'
+ _dll = '.so'
test = TestSCons.TestSCons()
@@ -58,14 +58,21 @@ if not os.path.exists(Python_h):
# handle testing on other platforms:
ldmodule_prefix = '_'
+# On Windows, build a 32-bit exe if on 32-bit python.
+if sys.platform == 'win32' and sys.maxsize <= 2**32:
+ swig_arch_var="TARGET_ARCH='x86',"
+else:
+ swig_arch_var=""
+
test.write('SConstruct', """
env = Environment(SWIGFLAGS='-python',
+ %(swig_arch_var)s
CPPPATH=['%(python_include)s/'],
LDMODULEPREFIX='%(ldmodule_prefix)s',
LDMODULESUFFIX='%(_dll)s',
SWIG=r'%(swig)s',
LIBPATH=[r'%(python_libpath)s'],
- LIBS='%(python_lib)s',
+ LIBS='%(python_lib)s'
)
env.LoadableModule('sub/_foo',
diff --git a/test/Scanner/Dir.py b/test/Scanner/Dir.py
index 120e08ff..86b80e9f 100644
--- a/test/Scanner/Dir.py
+++ b/test/Scanner/Dir.py
@@ -27,7 +27,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that a simple scanner that returns Dir nodes works correctly.
-Submitted as tigris.org issue #2534.
+Submitted as http://scons.tigris.org/issues/show_bug.cgi?id=2534
"""
import TestSCons
diff --git a/test/TEX/biblatex_plain.py b/test/TEX/biblatex_plain.py
new file mode 100644
index 00000000..68f7cc37
--- /dev/null
+++ b/test/TEX/biblatex_plain.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__"
+
+"""
+Test creation of a Tex document that uses the biblatex package
+
+Test courtesy Rob Managan.
+"""
+
+import TestSCons
+import os
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('pdflatex')
+if not latex:
+ test.skip_test("Could not find 'pdflatex'; skipping test.\n")
+
+biblatex = os.system('kpsewhich biblatex.sty')
+if not biblatex==0:
+ test.skip_test("biblatex.sty not installed; skipping test(s).\n")
+
+
+test.write(['SConstruct'], """\
+#!/usr/bin/env python
+
+import os
+env = Environment(ENV=os.environ)
+main_output = env.PDF(target='biblatextest.pdf', source='biblatextest.tex')
+""")
+
+test.write(['biblatextest.tex'],r"""
+\documentclass{article}
+
+\usepackage{biblatex}
+
+\begin{document}
+
+Hello. This is boring.
+And even more boring.
+
+\end{document}
+""")
+
+
+test.run()
+
+
+# All (?) the files we expect will get created in the docs directory
+files = [
+ 'biblatextest.aux',
+ 'biblatextest.blg',
+ 'biblatextest.fls',
+ 'biblatextest.log',
+ 'biblatextest.pdf',
+ 'biblatextest.run.xml',
+]
+
+for f in files:
+ test.must_exist([ f])
+
+test.run(arguments = '-c .')
+
+for f in files:
+ test.must_not_exist([ f])
+
+test.pass_test()
+
diff --git a/test/TEX/synctex.py b/test/TEX/synctex.py
new file mode 100644
index 00000000..867063a8
--- /dev/null
+++ b/test/TEX/synctex.py
@@ -0,0 +1,89 @@
+#!/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__"
+
+"""
+Validate that use of -synctex command option causes SCons to
+be aware of the created synctex.gz file.
+
+Test configuration contributed by Robert Managan.
+"""
+
+import os
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('latex')
+
+if not latex:
+ test.skip_test("Could not find latex; skipping test(s).\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment()
+env.AppendUnique(PDFLATEXFLAGS = '-synctex=1')
+env.PDF('mysync', 'mysync.tex')
+""")
+
+test.write('mysync.tex', r"""
+\documentclass{article}
+
+\begin{document}
+
+This is a simple test of the synctex.gz file.
+
+\end{document}
+""")
+
+test.run(arguments = '.', stderr=None)
+
+test.must_exist(test.workpath('mysync.synctex.gz'))
+test.must_exist(test.workpath('mysync.aux'))
+test.must_exist(test.workpath('mysync.fls'))
+test.must_exist(test.workpath('mysync.log'))
+test.must_exist(test.workpath('mysync.pdf'))
+
+test.run(arguments = '-c .')
+
+x = "Could not remove 'mysync.aux': No such file or directory"
+test.must_not_contain_any_line(test.stdout(), [x])
+
+test.must_not_exist(test.workpath('mysync.synctex.gz'))
+test.must_not_exist(test.workpath('mysync.aux'))
+test.must_not_exist(test.workpath('mysync.fls'))
+test.must_not_exist(test.workpath('mysync.log'))
+test.must_not_exist(test.workpath('mysync.pdf'))
+
+test.pass_test()
+
+
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/TEX/variant_dir_newglossary.py b/test/TEX/variant_dir_newglossary.py
new file mode 100644
index 00000000..8604270c
--- /dev/null
+++ b/test/TEX/variant_dir_newglossary.py
@@ -0,0 +1,109 @@
+#!/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__"
+
+"""
+Validate the use of \newglossary in TeX source files in conjuction
+with variant_dir.
+
+Test configuration contributed by Kendrick Boyd.
+"""
+
+import os
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('latex')
+
+if not latex:
+ test.skip_test("Could not find latex; skipping test(s).\n")
+
+gloss = os.system('kpsewhich glossaries.sty')
+if gloss!=0:
+ test.skip_test("glossaries.sty not installed; skipping test(s).\n")
+
+
+test.subdir(['src'])
+
+test.write(['SConstruct'], r"""
+import os
+
+env = Environment(TOOLS = ['tex', 'latex'])
+Export(['env'])
+
+SConscript(os.path.join('src','SConscript'), variant_dir='build/', duplicate=1)
+""")
+
+test.write(['src', 'SConscript'], r"""
+Import('env')
+
+test_pdf = env.PDF(source='test.tex')
+
+""")
+
+test.write(['src', 'test.tex'], r"""
+\documentclass{report}
+
+\usepackage{glossaries}
+
+\newglossary[ntg]{notation}{nts}{nto}{List of Notation}
+
+\makeglossary
+
+\newglossaryentry{pi}{type=notation, name={$\pi$}, description={ratio
+ of circumference to diameter of a circle}}
+
+\begin{document}
+
+\glsaddall
+
+\printglossary[type=notation, style=list]
+
+\end{document}
+""")
+
+test.run(arguments = '.', stderr = None)
+
+files = [
+ 'test.aux',
+ 'test.fls',
+ 'test.glg',
+ 'test.glo',
+ 'test.gls',
+ 'test.ist',
+ 'test.log',
+ 'test.ntg',
+ 'test.nto',
+ 'test.nts',
+ 'test.pdf',
+]
+
+for f in files:
+ test.must_exist(['build',f])
+ test.must_not_exist(['src',f])
+
+
+test.pass_test()
diff --git a/test/VariantDir/include-subdir.py b/test/VariantDir/include-subdir.py
index 5ddd623a..d616bba6 100644
--- a/test/VariantDir/include-subdir.py
+++ b/test/VariantDir/include-subdir.py
@@ -32,7 +32,7 @@ we have to make sure that the file gets copied to the variant dir. (This
was not the case for 0.98.5 and earlier)
Test case supplied by Jared Grubb, based on a minimal example supplied
-by Ali Tofigh, filed as issue #2121 at tigris.org.
+by Ali Tofigh, filed as http://scons.tigris.org/issues/show_bug.cgi?id=2121
"""
import TestSCons
diff --git a/test/YACC/live.py b/test/YACC/live.py
index 28e2186d..d567ec38 100644
--- a/test/YACC/live.py
+++ b/test/YACC/live.py
@@ -91,8 +91,6 @@ newline: '\n';
test.write("file.yy", """\
%token GRAPH_T NODE_T EDGE_T DIGRAPH_T EDGEOP_T SUBGRAPH_T
-%pure_parser
-
%%
graph: GRAPH_T
;
diff --git a/test/path-change.py b/test/path-change.py
new file mode 100644
index 00000000..0ca070ff
--- /dev/null
+++ b/test/path-change.py
@@ -0,0 +1,77 @@
+#!/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__"
+
+"""
+Make sure that changing the location - but not the name - of a
+source file triggers a rebuild (issue #2311).
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('src1')
+test.subdir('src2')
+
+test.write('SConstruct', """
+
+vars = Variables()
+vars.AddVariables(
+ PathVariable('SRCDIR', 'name the subdir to take the sources from', 'src1'))
+env = Environment(variables = vars)
+Export('env')
+
+env.Object(target='hello.o', source=['$SRCDIR/hello.c'])
+env.Program(target = 'hello', source = ['hello.o'])
+""")
+
+hello_text=r"""
+
+#include <stdio.h>
+#include <stdlib.h>
+int
+main()
+{
+ printf("%s\n");
+ exit (0);
+}
+
+"""
+
+test.write('src1/hello.c', hello_text % 'src1/hello')
+test.write('src2/hello.c', hello_text % 'src2/hello')
+
+test.not_up_to_date(options='SRCDIR=src1')
+test.up_to_date(options='SRCDIR=src1')
+test.not_up_to_date(options='SRCDIR=src2')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/www/patch-submission.html b/www/patch-submission.html
index c2b5d22a..a2d9b956 100644
--- a/www/patch-submission.html
+++ b/www/patch-submission.html
@@ -64,7 +64,7 @@ due to spambot abuse of the open-door policy.
<li>
<strong>If your patch is extensive, discuss it first on the
-<a href="mailto:dev@scons.tigris.org">dev@scons.tigris.org</a>
+<a href="mailto:scons-dev@scons.org">scons-dev@scons.org</a>
mailing list
</strong>
<p>
@@ -211,7 +211,7 @@ against the regression tests and fixing any problems
If you run your patch against against the regression tests
but can't figure out how to fix all the cases,
the best bet would be to ask the
-<a href="mailto:dev@scons.tigris.org">dev@scons.tigris.org</a>
+<a href="mailto:scons-dev@scons.org">scons-dev@scons.org</a>
mailing list.
</p>
</li>