summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2017-08-19 20:42:08 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2017-08-19 20:42:08 (GMT)
commit4057431ac3b09bf0b57cfd878d51b8c2bf53d11b (patch)
tree13f7994c9646985733c90bedf727e7b9f19e71cc
parent2b7d176087d63dcb6da9f450c34747eff5df8d89 (diff)
parent90f842616029050abffdabec078fe9a1f1b1d1a9 (diff)
downloadSCons-4057431ac3b09bf0b57cfd878d51b8c2bf53d11b.zip
SCons-4057431ac3b09bf0b57cfd878d51b8c2bf53d11b.tar.gz
SCons-4057431ac3b09bf0b57cfd878d51b8c2bf53d11b.tar.bz2
merge default
-rw-r--r--QMTest/TestCmd.py40
-rw-r--r--QMTest/TestSCons.py2
-rw-r--r--SConstruct110
-rw-r--r--bench/lvars-gvars.py6
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--doc/generated/functions.gen25
-rw-r--r--doc/generated/functions.mod4
-rw-r--r--doc/generated/tools.gen16
-rw-r--r--doc/generated/tools.mod4
-rw-r--r--doc/generated/variables.gen29
-rw-r--r--doc/generated/variables.mod2
-rw-r--r--doc/man/scons.xml16
-rw-r--r--doc/scons.mod1
-rw-r--r--doc/user/environments.xml169
-rwxr-xr-xruntest.py2
-rw-r--r--src/CHANGES.txt80
-rw-r--r--src/engine/SCons/Action.py83
-rw-r--r--src/engine/SCons/ActionTests.py146
-rw-r--r--src/engine/SCons/Debug.py4
-rw-r--r--src/engine/SCons/Environment.py37
-rw-r--r--src/engine/SCons/Environment.xml23
-rw-r--r--src/engine/SCons/EnvironmentValues.py97
-rw-r--r--src/engine/SCons/EnvironmentValuesTest.py16
-rw-r--r--src/engine/SCons/Node/FS.py29
-rw-r--r--src/engine/SCons/PathList.py4
-rw-r--r--src/engine/SCons/Script/__init__.py1
-rw-r--r--src/engine/SCons/Subst.py31
-rw-r--r--src/engine/SCons/SubstTests.py25
-rw-r--r--src/engine/SCons/Tool/MSCommon/common.py7
-rw-r--r--src/engine/SCons/Tool/MSCommon/vc.py81
-rw-r--r--src/engine/SCons/Tool/MSCommon/vs.py11
-rw-r--r--src/engine/SCons/Tool/__init__.py43
-rw-r--r--src/engine/SCons/Tool/clang.py83
-rw-r--r--src/engine/SCons/Tool/clang.xml39
-rw-r--r--src/engine/SCons/Tool/clangxx.py91
-rw-r--r--src/engine/SCons/Tool/clangxx.xml41
-rw-r--r--src/engine/SCons/Tool/dmd.py6
-rw-r--r--src/engine/SCons/Tool/gdc.py4
-rw-r--r--src/engine/SCons/Tool/gxx.py4
-rw-r--r--src/engine/SCons/Tool/ldc.py14
-rw-r--r--src/engine/SCons/Tool/linkloc.py4
-rw-r--r--src/engine/SCons/Tool/msvc.xml25
-rw-r--r--src/engine/SCons/Tool/zip.py44
-rw-r--r--src/engine/SCons/Util.py5
-rw-r--r--src/engine/SCons/Variables/__init__.py4
-rw-r--r--src/engine/SCons/cpp.py3
-rw-r--r--src/script/scons.py10
-rw-r--r--src/setup.py304
-rw-r--r--test/Clang/clang_default_environment.py64
-rw-r--r--test/Clang/clang_shared_library.py71
-rw-r--r--test/Clang/clang_specific_environment.py60
-rw-r--r--test/Clang/clang_static_library.py56
-rw-r--r--test/Clang/clangxx_default_environment.py64
-rw-r--r--test/Clang/clangxx_shared_library.py72
-rw-r--r--test/Clang/clangxx_specific_environment.py60
-rw-r--r--test/Clang/clangxx_static_library.py56
-rw-r--r--test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py5
-rw-r--r--test/D/SharedObjects/Common/common.py5
-rw-r--r--test/D/SharedObjects/Image/SConstruct_template7
-rw-r--r--test/Dir/PyPackageDir/PyPackageDir.py56
-rw-r--r--test/Dir/PyPackageDir/image/SConstruct29
-rw-r--r--test/Dir/PyPackageDir/image/sconstest.skip0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/sconstest.skip0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/__init__.py0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip0
-rw-r--r--test/Dir/PyPackageDir/image/syspath/testmod2.py0
-rw-r--r--test/MSVC/MSVC_UWP_APP.py132
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool1.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/__init__.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/__init__.py0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_1.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/__init__.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/__init__.py0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_1.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py4
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/__init__.py0
-rw-r--r--test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/SConstruct69
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool1.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/__init__.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/__init__.py0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_1.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/__init__.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/__init__.py0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_1.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py4
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/__init__.py0
-rw-r--r--test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/sconstest.skip0
-rw-r--r--test/toolpath/nested/nested.py75
-rw-r--r--test/toolpath/relative_import/image/SConstruct10
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_1.py4
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_1.py4
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/__init__.py4
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/sconstest.skip0
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/__init__.py11
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/sconstest.skip0
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/__init__.py9
-rw-r--r--test/toolpath/relative_import/image/tools/TestTool1/sconstest.skip0
-rw-r--r--test/toolpath/relative_import/relative_import.py53
116 files changed, 2406 insertions, 451 deletions
diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py
index e4c69a6..0aab9a8 100644
--- a/QMTest/TestCmd.py
+++ b/QMTest/TestCmd.py
@@ -307,7 +307,8 @@ import traceback
import types
-PY3 = sys.version_info[0] == 3
+IS_PY3 = sys.version_info[0] == 3
+IS_WINDOWS = sys.platform == 'win32'
class null(object):
@@ -1245,7 +1246,7 @@ class TestCmd(object):
file = self.canonicalize(file)
if mode[0] != 'r':
raise ValueError("mode must begin with 'r'")
- if PY3 and 'b' not in mode:
+ if IS_PY3 and 'b' not in mode:
return open(file, mode, newline=newline).read()
else:
return open(file, mode).read()
@@ -1406,29 +1407,22 @@ class TestCmd(object):
self.timer = threading.Timer(float(timeout), self._timeout)
self.timer.start()
- if sys.version_info[0] == 3 and sys.platform == 'win32':
+ if IS_PY3 and sys.platform == 'win32':
# Set this otherwist stdout/stderr pipes default to
# windows default locale cp1252 which will throw exception
# if using non-ascii characters.
# For example test/Install/non-ascii-name.py
os.environ['PYTHONIOENCODING'] = 'utf-8'
- if sys.version_info[0] == 2 or sys.version_info[0:2] < (3, 6):
- p = Popen(cmd,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=stderr_value,
- env=os.environ,
- universal_newlines=False)
- else:
- # this will only work on py3.6, encoding
- p = Popen(cmd,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=stderr_value,
- env=os.environ,
- universal_newlines=universal_newlines,
- encoding='utf-8')
+ # It seems that all pythons up to py3.6 still set text mode if you set encoding.
+ # TODO: File enhancement request on python to propagate universal_newlines even
+ # if encoding is set.hg c
+ p = Popen(cmd,
+ stdin=stdin,
+ stdout=subprocess.PIPE,
+ stderr=stderr_value,
+ env=os.environ,
+ universal_newlines=False)
self.process = p
return p
@@ -1451,7 +1445,9 @@ class TestCmd(object):
if not stream:
return stream
- elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
+ # TODO: Run full tests on both platforms and see if this fixes failures
+ # It seems that py3.6 still sets text mode if you set encoding.
+ elif sys.version_info[0] == 3:# TODO and sys.version_info[1] < 6:
stream = stream.decode('utf-8')
stream = stream.replace('\r\n', '\n')
elif sys.version_info[0] == 2:
@@ -1520,8 +1516,8 @@ class TestCmd(object):
if is_List(stdin):
stdin = ''.join(stdin)
- if stdin and sys.version_info[0] == 3 and sys.version_info[1] < 6:
- stdin = bytearray(stdin,'utf-8')
+ if stdin and IS_PY3:# and sys.version_info[1] < 6:
+ stdin = to_bytes(stdin)
# TODO(sgk): figure out how to re-use the logic in the .finish()
# method above. Just calling it from here causes problems with
diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py
index 66d6b23..6941e1c 100644
--- a/QMTest/TestSCons.py
+++ b/QMTest/TestSCons.py
@@ -270,7 +270,7 @@ class TestSCons(TestCommon):
SCons.Node.FS.default_fs = SCons.Node.FS.FS()
try:
- self.fixture_dirs = (os.environ['FIXTURE_DIRS']).split(':')
+ self.fixture_dirs = (os.environ['FIXTURE_DIRS']).split(os.pathsep)
except KeyError:
pass
diff --git a/SConstruct b/SConstruct
index f30b4c4..bfd12ca 100644
--- a/SConstruct
+++ b/SConstruct
@@ -41,6 +41,7 @@ import re
import stat
import sys
import tempfile
+import time
import bootstrap
@@ -98,9 +99,13 @@ zip = whereis('zip')
#
date = ARGUMENTS.get('DATE')
if not date:
- import time
date = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time()))
+# Datestring for debian
+# Should look like: Mon, 03 Nov 2016 13:37:42 -0700
+deb_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
+
+
developer = ARGUMENTS.get('DEVELOPER')
if not developer:
for variable in ['USERNAME', 'LOGNAME', 'USER']:
@@ -385,22 +390,35 @@ def SCons_revision(target, source, env):
"""
t = str(target[0])
s = source[0].rstr()
- with open(s, 'r') as fp:
- contents = fp.read()
- # Note: We construct the __*__ substitution strings here
- # so that they don't get replaced when this file gets
- # copied into the tree for packaging.
- contents = contents.replace('__BUILD' + '__', env['BUILD'])
- contents = contents.replace('__BUILDSYS' + '__', env['BUILDSYS'])
- contents = contents.replace('__COPYRIGHT' + '__', env['COPYRIGHT'])
- contents = contents.replace('__DATE' + '__', env['DATE'])
- contents = contents.replace('__DEVELOPER' + '__', env['DEVELOPER'])
- contents = contents.replace('__FILE' + '__', str(source[0]).replace('\\', '/'))
- contents = contents.replace('__MONTH_YEAR'+ '__', env['MONTH_YEAR'])
- contents = contents.replace('__REVISION' + '__', env['REVISION'])
- contents = contents.replace('__VERSION' + '__', env['VERSION'])
- contents = contents.replace('__NULL' + '__', '')
- open(t, 'w').write(contents)
+
+ try:
+ with open(s, 'r') as fp:
+ contents = fp.read()
+
+
+ # Note: We construct the __*__ substitution strings here
+ # so that they don't get replaced when this file gets
+ # copied into the tree for packaging.
+ contents = contents.replace('__BUILD' + '__', env['BUILD'])
+ contents = contents.replace('__BUILDSYS' + '__', env['BUILDSYS'])
+ contents = contents.replace('__COPYRIGHT' + '__', env['COPYRIGHT'])
+ contents = contents.replace('__DATE' + '__', env['DATE'])
+ contents = contents.replace('__DEB_DATE' + '__', env['DEB_DATE'])
+
+ contents = contents.replace('__DEVELOPER' + '__', env['DEVELOPER'])
+ contents = contents.replace('__FILE' + '__', str(source[0]).replace('\\', '/'))
+ contents = contents.replace('__MONTH_YEAR'+ '__', env['MONTH_YEAR'])
+ contents = contents.replace('__REVISION' + '__', env['REVISION'])
+ contents = contents.replace('__VERSION' + '__', env['VERSION'])
+ contents = contents.replace('__NULL' + '__', '')
+ open(t, 'w').write(contents)
+ except UnicodeDecodeError as e:
+ print("Error decoding file:%s just copying no revision edit")
+ with open(s, 'rb') as fp:
+ contents = fp.read()
+ open(t, 'wb').write(contents)
+
+
os.chmod(t, os.stat(s)[0])
@@ -452,6 +470,7 @@ env = Environment(
BUILDSYS = build_system,
COPYRIGHT = copyright,
DATE = date,
+ DEB_DATE = deb_date,
DEVELOPER = developer,
DISTDIR = os.path.join(build_dir, 'dist'),
MONTH_YEAR = month_year,
@@ -594,43 +613,6 @@ finally:
except EnvironmentError:
pass
-#
-# The original packaging scheme would have have required us to push
-# the Python version number into the package name (python1.5-scons,
-# python2.0-scons, etc.), which would have required a definition
-# like the following. Leave this here in case we ever decide to do
-# this in the future, but note that this would require some modification
-# to src/engine/setup.py before it would really work.
-#
-#python2_scons = {
-# 'pkg' : 'python2-' + project,
-# 'src_subdir' : 'engine',
-# 'inst_subdir' : os.path.join('lib', 'python2.2', 'site-packages'),
-#
-# 'debian_deps' : [
-# 'debian/changelog',
-# 'debian/control',
-# 'debian/copyright',
-# 'debian/dirs',
-# 'debian/docs',
-# 'debian/postinst',
-# 'debian/prerm',
-# 'debian/rules',
-# ],
-#
-# 'files' : [
-# 'LICENSE.txt',
-# 'README.txt',
-# 'setup.cfg',
-# 'setup.py',
-# ],
-# 'filemap' : {
-# 'LICENSE.txt' : '../LICENSE.txt',
-# },
-# 'buildermap' : {},
-#}
-#
-
scons_script = {
'pkg' : project + '-script',
'src_subdir' : 'script',
@@ -836,6 +818,7 @@ for p in [ scons ]:
builder = p['buildermap'].get(b, env.SCons_revision)
x = builder(os.path.join(build, b), s)
+
Local(x)
#
@@ -944,11 +927,14 @@ for p in [ scons ]:
ebuild = os.path.join(gentoo, 'scons-%s.ebuild' % version)
digest = os.path.join(gentoo, 'files', 'digest-scons-%s' % version)
env.Command(ebuild, os.path.join('gentoo', 'scons.ebuild.in'), SCons_revision)
+
def Digestify(target, source, env):
- import md5
+ import hashlib
src = source[0].rfile()
- contents = open(str(src)).read()
- sig = md5.new(contents).hexdigest()
+ contents = open(str(src),'rb').read()
+ m = hashlib.md5()
+ m.update(contents)
+ sig = m.hexdigest()
bytes = os.stat(str(src))[6]
open(str(target[0]), 'w').write("MD5 %s %s %d\n" % (sig,
src.name,
@@ -1068,9 +1054,9 @@ for p in [ scons ]:
# Our Debian packaging builds directly into build/dist,
# so we don't need to Install() the .debs.
# The built deb is called just x.y.z, not x.y.z.final.0 so strip those off:
- deb_version = '.'.join(version.split('.')[0:3])
+ deb_version = version #'.'.join(version.split('.')[0:3])
deb = os.path.join(build_dir, 'dist', "%s_%s_all.deb" % (pkg, deb_version))
- # print("Building deb into %s (version=%s)"%(deb, deb_version))
+ print("Building deb into %s (version=%s)"%(deb, deb_version))
for d in p['debian_deps']:
b = env.SCons_revision(os.path.join(build, d), d)
env.Depends(deb, b)
@@ -1268,7 +1254,11 @@ if sfiles:
Local(src_tar_gz, src_zip)
for file in sfiles:
- env.SCons_revision(os.path.join(b_ps, file), file)
+ if file.endswith('jpg') or file.endswith('png'):
+ # don't revision binary files.
+ env.Install(os.path.dirname(os.path.join(b_ps,file)), file)
+ else:
+ env.SCons_revision(os.path.join(b_ps, file), file)
b_ps_files = [os.path.join(b_ps, x) for x in sfiles]
cmds = [
diff --git a/bench/lvars-gvars.py b/bench/lvars-gvars.py
index bdb09ef..1511203 100644
--- a/bench/lvars-gvars.py
+++ b/bench/lvars-gvars.py
@@ -45,6 +45,12 @@ def Func4(var, gvars, lvars):
except NameError:
x = ''
+def Func5(var, gvars, lvars):
+ """Chained get with default values"""
+ for i in IterationList:
+ x = lvars.get(var,gvars.get(var,''))
+
+
# Data to pass to the functions on each run. Each entry is a
# three-element tuple:
#
diff --git a/debian/changelog b/debian/changelog
index 0808546..4e7470d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+scons (__VERSION__) unstable; urgency=low
+
+ * Maintenance Release
+
+ -- __DEVELOPER__ <bill@baddogconsulting.com> __DATE__
+
scons (2.5.1) unstable; urgency=low
* Maintenance Release
diff --git a/debian/control b/debian/control
index 5fbf0eb..d0a61fa 100644
--- a/debian/control
+++ b/debian/control
@@ -7,7 +7,7 @@ Standards-Version: 3.5.6
Package: scons
Architecture: all
-Depends: python (>> 2.4)
+Depends: python (>> 2.7)
Description: A replacement for Make
SCons is an Open Source software construction tool--that is, a build
tool; an improved substitute for the classic Make utility; a better
diff --git a/doc/generated/functions.gen b/doc/generated/functions.gen
index 8181d56..e72740a 100644
--- a/doc/generated/functions.gen
+++ b/doc/generated/functions.gen
@@ -3320,6 +3320,31 @@ Multiple targets can be passed in to a single call to
</para>
</listitem>
</varlistentry>
+ <varlistentry id="f-PyPackageDir">
+ <term>
+ <literal>PyPackageDir(modulename)</literal>
+ </term>
+ <term>
+ <literal>env.PyPackageDir(modulename)</literal>
+ </term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+This returns a Directory Node similar to Dir.
+The python module / package is looked up and if located
+the directory is returned for the location.
+<varname>modulename</varname>
+Is a named python package / module to
+lookup the directory for it's location.
+</para>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+If
+<varname>modulename</varname>
+is a list, SCons returns a list of Dir nodes.
+Construction variables are expanded in
+<varname>modulename</varname>.
+</para>
+</listitem>
+ </varlistentry>
<varlistentry id="f-Replace">
<term>
<literal>env.Replace(key=val, [...])</literal>
diff --git a/doc/generated/functions.mod b/doc/generated/functions.mod
index 6183293..e460aaf 100644
--- a/doc/generated/functions.mod
+++ b/doc/generated/functions.mod
@@ -69,6 +69,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY f-PrependUnique "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PrependUnique</function>">
<!ENTITY f-Progress "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Progress</function>">
<!ENTITY f-Pseudo "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Pseudo</function>">
+<!ENTITY f-PyPackageDir "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PyPackageDir</function>">
<!ENTITY f-Replace "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Replace</function>">
<!ENTITY f-Repository "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Repository</function>">
<!ENTITY f-Requires "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Requires</function>">
@@ -152,6 +153,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY f-env-PrependUnique "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.PrependUnique</function>">
<!ENTITY f-env-Progress "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.Progress</function>">
<!ENTITY f-env-Pseudo "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.Pseudo</function>">
+<!ENTITY f-env-PyPackageDir "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.PyPackageDir</function>">
<!ENTITY f-env-Replace "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.Replace</function>">
<!ENTITY f-env-Repository "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.Repository</function>">
<!ENTITY f-env-Requires "<function xmlns='http://www.scons.org/dbxsd/v1.0'>env.Requires</function>">
@@ -245,6 +247,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY f-link-PrependUnique "<link linkend='f-PrependUnique' xmlns='http://www.scons.org/dbxsd/v1.0'><function>PrependUnique</function></link>">
<!ENTITY f-link-Progress "<link linkend='f-Progress' xmlns='http://www.scons.org/dbxsd/v1.0'><function>Progress</function></link>">
<!ENTITY f-link-Pseudo "<link linkend='f-Pseudo' xmlns='http://www.scons.org/dbxsd/v1.0'><function>Pseudo</function></link>">
+<!ENTITY f-link-PyPackageDir "<link linkend='f-PyPackageDir' xmlns='http://www.scons.org/dbxsd/v1.0'><function>PyPackageDir</function></link>">
<!ENTITY f-link-Replace "<link linkend='f-Replace' xmlns='http://www.scons.org/dbxsd/v1.0'><function>Replace</function></link>">
<!ENTITY f-link-Repository "<link linkend='f-Repository' xmlns='http://www.scons.org/dbxsd/v1.0'><function>Repository</function></link>">
<!ENTITY f-link-Requires "<link linkend='f-Requires' xmlns='http://www.scons.org/dbxsd/v1.0'><function>Requires</function></link>">
@@ -328,6 +331,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY f-link-env-PrependUnique "<link linkend='f-PrependUnique' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.PrependUnique</function></link>">
<!ENTITY f-link-env-Progress "<link linkend='f-Progress' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.Progress</function></link>">
<!ENTITY f-link-env-Pseudo "<link linkend='f-Pseudo' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.Pseudo</function></link>">
+<!ENTITY f-link-env-PyPackageDir "<link linkend='f-PyPackageDir' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.PyPackageDir</function></link>">
<!ENTITY f-link-env-Replace "<link linkend='f-Replace' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.Replace</function></link>">
<!ENTITY f-link-env-Repository "<link linkend='f-Repository' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.Repository</function></link>">
<!ENTITY f-link-env-Requires "<link linkend='f-Requires' xmlns='http://www.scons.org/dbxsd/v1.0'><function>env.Requires</function></link>">
diff --git a/doc/generated/tools.gen b/doc/generated/tools.gen
index c0cc2f7..e3bc27f 100644
--- a/doc/generated/tools.gen
+++ b/doc/generated/tools.gen
@@ -95,6 +95,22 @@ Sets construction variables for generic POSIX C copmilers.
</para>
<para>Sets: &cv-link-CC;, &cv-link-CCCOM;, &cv-link-CCFLAGS;, &cv-link-CFILESUFFIX;, &cv-link-CFLAGS;, &cv-link-CPPDEFPREFIX;, &cv-link-CPPDEFSUFFIX;, &cv-link-FRAMEWORKPATH;, &cv-link-FRAMEWORKS;, &cv-link-INCPREFIX;, &cv-link-INCSUFFIX;, &cv-link-SHCC;, &cv-link-SHCCCOM;, &cv-link-SHCCFLAGS;, &cv-link-SHCFLAGS;, &cv-link-SHOBJSUFFIX;.</para><para>Uses: &cv-link-PLATFORM;.</para></listitem>
</varlistentry>
+ <varlistentry id="t-clang">
+ <term>clang</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Set construction variables for the Clang C compiler.
+</para>
+<para>Sets: &cv-link-CC;, &cv-link-CCVERSION;, &cv-link-SHCCFLAGS;.</para></listitem>
+ </varlistentry>
+ <varlistentry id="t-clangxx">
+ <term>clangxx</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Set construction variables for the Clang C++ compiler.
+</para>
+<para>Sets: &cv-link-CXX;, &cv-link-CXXVERSION;, &cv-link-SHCXXFLAGS;, &cv-link-SHOBJSUFFIX;, &cv-link-STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME;.</para></listitem>
+ </varlistentry>
<varlistentry id="t-cvf">
<term>cvf</term>
<listitem>
diff --git a/doc/generated/tools.mod b/doc/generated/tools.mod
index bf552c3..1209d74 100644
--- a/doc/generated/tools.mod
+++ b/doc/generated/tools.mod
@@ -18,6 +18,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-as "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>as</literal>">
<!ENTITY t-bcc32 "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>bcc32</literal>">
<!ENTITY t-cc "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>cc</literal>">
+<!ENTITY t-clang "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>clang</literal>">
+<!ENTITY t-clangxx "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>clangxx</literal>">
<!ENTITY t-cvf "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>cvf</literal>">
<!ENTITY t-cXX "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>cXX</literal>">
<!ENTITY t-cyglink "<literal xmlns='http://www.scons.org/dbxsd/v1.0'>cyglink</literal>">
@@ -124,6 +126,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY t-link-as "<link linkend='t-as' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>as</literal></link>">
<!ENTITY t-link-bcc32 "<link linkend='t-bcc32' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>bcc32</literal></link>">
<!ENTITY t-link-cc "<link linkend='t-cc' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>cc</literal></link>">
+<!ENTITY t-link-clang "<link linkend='t-clang' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>clang</literal></link>">
+<!ENTITY t-link-clangxx "<link linkend='t-clangxx' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>clangxx</literal></link>">
<!ENTITY t-link-cvf "<link linkend='t-cvf' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>cvf</literal></link>">
<!ENTITY t-link-cXX "<link linkend='t-cXX' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>cXX</literal></link>">
<!ENTITY t-link-cyglink "<link linkend='t-cyglink' xmlns='http://www.scons.org/dbxsd/v1.0'><literal>cyglink</literal></link>">
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 6ad5b6b..3941137 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -3046,7 +3046,7 @@ The command line used to call the Java archive tool.
<para xmlns="http://www.scons.org/dbxsd/v1.0">
The string displayed when the Java archive tool
is called
-If this is not set, then <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JARCOM"><envar>$JARCOM</envar></link> (the command line) is displayed.
+If this is not set, then <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JARCOM</envar> (the command line) is displayed.
</para>
<example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
@@ -3056,7 +3056,7 @@ env = Environment(JARCOMSTR = "JARchiving $SOURCES into $TARGET")
<para xmlns="http://www.scons.org/dbxsd/v1.0">
The string displayed when the Java archive tool
is called
-If this is not set, then <envar xmlns="http://www.scons.org/dbxsd/v1.0">$JARCOM</envar> (the command line) is displayed.
+If this is not set, then <link xmlns="http://www.scons.org/dbxsd/v1.0" linkend="cv-JARCOM"><envar>$JARCOM</envar></link> (the command line) is displayed.
</para>
<example_commands xmlns="http://www.scons.org/dbxsd/v1.0">
@@ -4179,6 +4179,29 @@ window and importing the shell's environment variables.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="cv-MSVC_UWP_APP">
+ <term>MSVC_UWP_APP</term>
+ <listitem>
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Build libraries for a Universal Windows Platform (UWP) Application.
+</para>
+
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+If <envar xmlns="http://www.scons.org/dbxsd/v1.0">$MSVC_UWP_APP</envar> is set, the Visual Studio environment will be set up to point
+to the Windows Store compatible libraries and Visual Studio runtimes. In doing so,
+any libraries that are built will be able to be used in a UWP App and published
+to the Windows Store.
+This flag will only have an effect with Visual Studio 2015+.
+This variable must be passed as an argument to the Environment()
+constructor; setting it later has no effect.
+</para>
+
+<para xmlns="http://www.scons.org/dbxsd/v1.0">
+Valid values are '1' or '0'
+</para>
+
+</listitem>
+ </varlistentry>
<varlistentry id="cv-MSVC_VERSION">
<term>MSVC_VERSION</term>
<listitem>
@@ -4196,6 +4219,8 @@ constructor; setting it later has no effect.
<para xmlns="http://www.scons.org/dbxsd/v1.0">
Valid values for Windows are
+<literal>14.0</literal>,
+<literal>14.0Exp</literal>,
<literal>12.0</literal>,
<literal>12.0Exp</literal>,
<literal>11.0</literal>,
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index 43d2604..319ac66 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -304,6 +304,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-MSSDK_VERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSSDK_VERSION</envar>">
<!ENTITY cv-MSVC_BATCH "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVC_BATCH</envar>">
<!ENTITY cv-MSVC_USE_SCRIPT "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVC_USE_SCRIPT</envar>">
+<!ENTITY cv-MSVC_UWP_APP "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVC_UWP_APP</envar>">
<!ENTITY cv-MSVC_VERSION "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVC_VERSION</envar>">
<!ENTITY cv-MSVS "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVS</envar>">
<!ENTITY cv-MSVS_ARCH "<envar xmlns='http://www.scons.org/dbxsd/v1.0'>$MSVS_ARCH</envar>">
@@ -927,6 +928,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
<!ENTITY cv-link-MSSDK_VERSION "<link linkend='cv-MSSDK_VERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSSDK_VERSION</envar></link>">
<!ENTITY cv-link-MSVC_BATCH "<link linkend='cv-MSVC_BATCH' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVC_BATCH</envar></link>">
<!ENTITY cv-link-MSVC_USE_SCRIPT "<link linkend='cv-MSVC_USE_SCRIPT' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVC_USE_SCRIPT</envar></link>">
+<!ENTITY cv-link-MSVC_UWP_APP "<link linkend='cv-MSVC_UWP_APP' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVC_UWP_APP</envar></link>">
<!ENTITY cv-link-MSVC_VERSION "<link linkend='cv-MSVC_VERSION' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVC_VERSION</envar></link>">
<!ENTITY cv-link-MSVS "<link linkend='cv-MSVS' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVS</envar></link>">
<!ENTITY cv-link-MSVS_ARCH "<link linkend='cv-MSVS_ARCH' xmlns='http://www.scons.org/dbxsd/v1.0'><envar>$MSVS_ARCH</envar></link>">
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index b68f27a..3268860 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -2187,6 +2187,22 @@ platform name when the Environment is constructed. Changing the PATH
variable after the Environment is constructed will not cause the tools to
be redetected.</para>
+<para> One feature now present within Scons is the ability to have nested tools.
+Tools which can be located within a subdirectory in the toolpath.
+With a nested tool name the dot represents a directory seperator</para>
+
+<programlisting>
+# namespaced builder
+env = Environment(ENV = os.environ, tools = ['SubDir1.SubDir2.SomeTool'])
+env.SomeTool(targets, sources)
+
+# Search Paths
+# SCons\Tool\SubDir1\SubDir2\SomeTool.py
+# SCons\Tool\SubDir1\SubDir2\SomeTool\__init__.py
+# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool.py
+# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool\__init__.py
+</programlisting>
+
<para>SCons supports the following tool specifications out of the box:</para>
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
diff --git a/doc/scons.mod b/doc/scons.mod
index 8d64054..448a212 100644
--- a/doc/scons.mod
+++ b/doc/scons.mod
@@ -243,6 +243,7 @@
<!ENTITY PrependENVPath "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PrependENVPath</function>">
<!ENTITY PrependUnique "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PrependUnique</function>">
<!ENTITY Progress "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Progress</function>">
+<!ENTITY PyPackageDir "<function xmlns='http://www.scons.org/dbxsd/v1.0'>PyPackageDir</function>">
<!ENTITY Replace "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Replace</function>">
<!ENTITY Repository "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Repository</function>">
<!ENTITY Requires "<function xmlns='http://www.scons.org/dbxsd/v1.0'>Requires</function>">
diff --git a/doc/user/environments.xml b/doc/user/environments.xml
index d1da3f9..ae670a8 100644
--- a/doc/user/environments.xml
+++ b/doc/user/environments.xml
@@ -1765,4 +1765,173 @@ env.AppendENVPath('LIB', '/usr/local/lib')
</section>
+
+ <section id="sect-environment-toolpath">
+ <title>Using the toolpath for external Tools</title>
+
+ <section>
+ <title>The default tool search path</title>
+
+ <para>
+ Normally when using a tool from the construction environment,
+ several different search locations are checked by default.
+ This includes the <literal>Scons/Tools/</literal> directory
+ inbuilt to scons and the directory <literal>site_scons/site_tools</literal>
+ relative to the root SConstruct file.
+ </para>
+
+ <sconstruct>
+# Builtin tool or tool located within site_tools
+env = Environment(tools = ['SomeTool'])
+env.SomeTool(targets, sources)
+
+# The search locations would include by default
+SCons/Tool/SomeTool.py
+SCons/Tool/SomeTool/__init__.py
+./site_scons/site_tools/SomeTool.py
+./site_scons/site_tools/SomeTool/__init__.py
+ </sconstruct>
+
+ </section>
+
+ <section>
+ <title>Providing an external directory to toolpath</title>
+
+ <para>
+ In some cases you may want to specify a different location to search for tools.
+ The Environment constructor contains an option for this called toolpath
+ This can be used to add additional search directories.
+ </para>
+
+ <sconstruct>
+# Tool located within the toolpath directory option
+env = Environment(tools = ['SomeTool'], toolpath = ['/opt/SomeToolPath', '/opt/SomeToolPath2'])
+env.SomeTool(targets, sources)
+
+# The search locations in this example would include:
+/opt/SomeToolPath/SomeTool.py
+/opt/SomeToolPath/SomeTool/__init__.py
+/opt/SomeToolPath2/SomeTool.py
+/opt/SomeToolPath2/SomeTool/__init__.py
+SCons/Tool/SomeTool.py
+SCons/Tool/SomeTool/__init__.py
+./site_scons/site_tools/SomeTool.py
+./site_scons/site_tools/SomeTool/__init__.py
+ </sconstruct>
+
+ </section>
+
+ <section>
+ <title>Nested Tools within a toolpath</title>
+
+ <para>
+ &SCons; 3.0 now supports the ability for a Builder to be located
+ within a sub-directory / sub-package of the toolpath.
+ This is similar to namespacing within python.
+ With nested or namespaced tools we can use the dot notation
+ to specify a sub-directory that the tool is located under.
+ </para>
+
+ <sconstruct>
+# namespaced target
+env = Environment(tools = ['SubDir1.SubDir2.SomeTool'], toolpath = ['/opt/SomeToolPath'])
+env.SomeTool(targets, sources)
+
+# With this example the search locations would include
+/opt/SomeToolPath/SubDir1/SubDir2/SomeTool.py
+/opt/SomeToolPath/SubDir1/SubDir2/SomeTool/__init__.py
+SCons/Tool/SubDir1/SubDir2/SomeTool.py
+SCons/Tool/SubDir1/SubDir2/SomeTool/__init__.py
+./site_scons/site_tools/SubDir1/SubDir2/SomeTool.py
+./site_scons/site_tools/SubDir1/SubDir2/SomeTool/__init__.py
+ </sconstruct>
+
+ <para>
+ For python2 It's important to note when creating tools within sub-directories,
+ there needs to be a __init__.py file within each directory.
+ This file can just be empty.
+ This is the same constraint used by python when loading modules
+ from within sub-directories (packages).
+ For python3 this appears to be no longer a requirement.
+ </para>
+ </section>
+
+ <section>
+ <title>Using sys.path within the toolpath</title>
+
+ <para>
+ If we want to access tools externally to scons on the sys.path
+ (one example would be tools installed via the pip package manager)
+ One way to do this is to use sys.path with the toolpath.
+
+ One thing to watch out for with this approach is that sys.path
+ can sometimes contains paths to .egg files instead of directories.
+ So we need to filter those out with this approach.
+ </para>
+
+ <sconstruct>
+# namespaced target using sys.path within toolpath
+
+searchpaths = []
+for item in sys.path:
+ if os.path.isdir(item): searchpaths.append(item)
+
+env = Environment(tools = ['someinstalledpackage.SomeTool'], toolpath = searchpaths)
+env.SomeTool(targets, sources)
+ </sconstruct>
+
+ <para>
+ By using sys.path with the toolpath argument
+ and by using the nested syntax we can have scons search
+ packages installed via pip for Tools.
+ </para>
+
+<sconstruct>
+# For Windows based on the python version and install directory, this may be something like
+C:\Python35\Lib\site-packages\someinstalledpackage\SomeTool.py
+C:\Python35\Lib\site-packages\someinstalledpackage\SomeTool\__init__.py
+
+# For Linux this could be something like:
+/usr/lib/python3/dist-packages/someinstalledpackage/SomeTool.py
+/usr/lib/python3/dist-packages/someinstalledpackage/SomeTool/__init__.py
+</sconstruct>
+
+ </section>
+
+ <section>
+ <title>Using the &PyPackageDir; function to add to the toolpath</title>
+
+ <para>
+ In some cases you may want to use a tool
+ located within a installed external pip package.
+ This is possible by the use of sys.path with the toolpath.
+ However in that situation you need to provide a prefix to the toolname
+ to indicate where it is located within sys.path
+ </para>
+
+ <sconstruct>
+searchpaths = []
+for item in sys.path:
+ if os.path.isdir(item): searchpaths.append(item)
+env = Environment(tools = ['tools_example.subdir1.subdir2.SomeTool'], toolpath = searchpaths)
+env.SomeTool(targets, sources)
+ </sconstruct>
+
+ <para>
+ To avoid the use of a prefix within the name of the tool or filtering sys.path for directories,
+ we can use the <function>PyPackageDir(modulename)</function> function to locate the directory of the python package.
+ <function>PyPackageDir</function> returns a Dir object which represents the path of the directory
+ for the python package / module specified as a parameter.
+ </para>
+
+ <sconstruct>
+# namespaced target using sys.path
+env = Environment(tools = ['SomeTool'], toolpath = [PyPackageDir('tools_example.subdir1.subdir2')])
+env.SomeTool(targets, sources)
+ </sconstruct>
+
+ </section>
+
+ </section>
+
</chapter>
diff --git a/runtest.py b/runtest.py
index 18d4121..487100b 100755
--- a/runtest.py
+++ b/runtest.py
@@ -810,7 +810,7 @@ def run_test(t, io_lock, async=True):
if head:
fixture_dirs.append(head)
fixture_dirs.append(os.path.join(scriptpath, 'test', 'fixture'))
- os.environ['FIXTURE_DIRS'] = ':'.join(fixture_dirs)
+ os.environ['FIXTURE_DIRS'] = os.pathsep.join(fixture_dirs)
test_start_time = time_func()
if execute_tests:
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 5d670fd..b0e88c7 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -7,6 +7,10 @@
RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
+NOTE: This is a major release. You should expect that some targets may rebuild when upgrading.
+Significant changes in some python action signatures. Also switching between PY 2 and PY 3.5, 3.6
+may cause rebuilds. In no case should rebuilds not happen.
+
From William Blevins:
- Updated D language scanner support to latest: 2.071.1. (PR #1924)
https://dlang.org/spec/module.html accessed 11 August 2016
@@ -28,6 +32,12 @@ RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
tool found is used)
- Fixed MSVSProject example code (http://scons.tigris.org/issues/show_bug.cgi?id=2979)
- Defined MS SDK 10.0 and Changed VS 2015 to use SDK 10.0
+ - Changes to Action Function and Action Class signiture creation. NOTE: This will cause rebuilds
+ for many builds when upgrading to SCons 3.0
+
+ From Ibrahim Esmat:
+ - Added the capability to build Windows Store Compatible libraries that can be used
+ with Universal Windows Platform (UWP) Apps and published to the store
From Daniel Holth:
- Add basic support for PyPy (by deleting __slots__ from Node with a
@@ -35,6 +45,7 @@ RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
avoid too many open files.
- Add __main__.py for `python -m SCons` in case it is on PYTHONPATH.
- Always use highest available pickle protocol for efficiency.
+ - Remove unused command line fallback for the zip tool.
From Gaurav Juvekar:
- Fix issue #2832: Expand construction variables in 'chdir' argument of builders. (PR #463)
@@ -44,6 +55,7 @@ RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
From Alexey Klimkin:
- Use memoization to optimize PATH evaluation across all dependencies per
node. (PR #345)
+ - Use set() where it is applicable (PR #344)
From M. Limber:
- Fixed msvs.py for Visual Studio Express editions that would report
@@ -52,6 +64,13 @@ RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
From Rick Lupton:
- Update LaTeX scanner to understand \import and related commands
+ From Steve Robinson:
+ - Add support for Visual Studio 2017. This support requires vswhere.exe a helper
+ tool installed with newer installs of 2017. SCons expects it to be located at
+ "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
+ It can be downloaded separately at
+ https://github.com/Microsoft/vswhere
+
From Paweł Tomulik:
- Fixed the issue with LDMODULEVERSIONFLAGS reported by Tim Jennes
(https://pairlist4.pair.net/pipermail/scons-users/2016-May/004893.html).
@@ -70,11 +89,26 @@ RELEASE 3.0.0.alpha.20170614 - Mon, 14 Jun 2017 12:23:56 -0400
- Fixed PCHPDBFLAGS causing a deprecation warning on MSVC v8 and later when
using PCHs and PDBs together.
+
+ From Richard West:
+ - Added nested / namespace tool support
+ - Added a small fix to the python3 tool loader when loading a tool as a package
+ - Added additional documentation to the user manual on using toolpaths with the environment
+ This includes the use of sys.path to search for tools installed via pip or package managers
+ - Added support for a PyPackageDir function for use with the toolpath
+
From Russel Winder:
- Reordered the default D tools from "dmd, gdc, ldc" to "dmd, ldc, gdc".
- Add a ProgramAllAtOnce builder to the dmd, ldc, and gdc tools. (PR #448)
- - Deprecate a file name exception for very old Fedora LDC installation.
+ - Remove a file name exception for very old Fedora LDC installation.
- gdc can now handle building shared objects (tested for version 6.3.0).
+ - Remove establishing the SharedLibrary builder in the dmd, ldc, and gdc
+ tools, must now include the ar tool to get this builder as is required for
+ other compiler tools.
+ - Add clang and clang++ tools based on Paweł Tomulik's work.
+
+ From Tom Tanner:
+ - Allow nested $( ... $) sections
RELEASE 2.5.1 - Mon, 03 Nov 2016 13:37:42 -0400
@@ -311,35 +345,40 @@ RELEASE 2.3.3 - Sun, 24 Aug 2014 21:08:33 -0400
RELEASE 2.3.2
+ From Dirk Baechle:
+ - Update XML doc editor configuration
+ - Fix: Allow varlist to be specified as list of strings for Actions (#2754)
+
From veon on bitbucket:
- Fixed handling of nested ifs in CPP scanner PreProcessor class.
+ From Shane Gannon:
+ - Support for Visual Studio 2013 (12.0)
+
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 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.
+
+ From Gary Oberbrunner:
+ - get default RPM architecture more robustly when building RPMs
+
From Amir Szekely:
- Fixed NoClean() for multi-target builders (#2353).
+ From Paweł Tomulik:
+ - Fix SConf tests that write output
+
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
-
- From Shane Gannon:
- - Support for Visual Studio 2013 (12.0)
-
- From Sye van der Veen:
- - Support for Visual Studio 12.0Exp, and fixes for earlier MSVS
- versions.
-
From Anatoly Techtonik:
- Several improvements for running scons.py from source:
* engine files form source directory take priority over all other
@@ -354,15 +393,10 @@ RELEASE 2.3.2
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 Sye van der Veen:
+ - Support for Visual Studio 12.0Exp, and fixes for earlier MSVS
+ versions.
- 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/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 118c495..d6fe30b 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -105,6 +105,8 @@ import pickle
import re
import sys
import subprocess
+import itertools
+import inspect
import SCons.Debug
from SCons.Debug import logInstanceCreation
@@ -195,8 +197,11 @@ def _object_contents(obj):
except AttributeError as ae:
# Should be a pickle-able Python object.
try:
- return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL)
- except (pickle.PicklingError, TypeError, AttributeError):
+ return _object_instance_content(obj)
+ # pickling an Action instance or object doesn't yield a stable
+ # content as instance property may be dumped in different orders
+ # return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL)
+ except (pickle.PicklingError, TypeError, AttributeError) as ex:
# This is weird, but it seems that nested classes
# are unpickable. The Python docs say it should
# always be a PicklingError, but some Python
@@ -205,7 +210,7 @@ def _object_contents(obj):
return bytearray(repr(obj), 'utf-8')
-def _code_contents(code):
+def _code_contents(code, docstring=None):
"""Return the signature contents of a code object.
By providing direct access to the code object of the
@@ -252,12 +257,7 @@ def _code_contents(code):
# function. Note that we have to call _object_contents on each
# constants because the code object of nested functions can
# show-up among the constants.
- #
- # Note that we also always ignore the first entry of co_consts
- # which contains the function doc string. We assume that the
- # function does not access its doc string.
- # NOTE: This is not necessarily true. If no docstring, then co_consts[0] does
- # have a string which is used.
+
z = [_object_contents(cc) for cc in code.co_consts[1:]]
contents.extend(b',(')
contents.extend(bytearray(',', 'utf-8').join(z))
@@ -296,7 +296,7 @@ def _function_contents(func):
func.__closure__ - None or a tuple of cells that contain bindings for the function's free variables.
"""
- contents = [_code_contents(func.__code__)]
+ contents = [_code_contents(func.__code__, func.__doc__)]
# The function contents depends on the value of defaults arguments
if func.__defaults__:
@@ -308,15 +308,12 @@ def _function_contents(func):
defaults.extend(b')')
contents.append(defaults)
-
- # contents.append(bytearray(',(','utf-8') + b','.join(function_defaults_contents) + bytearray(')','utf-8'))
else:
contents.append(b',()')
# The function contents depends on the closure captured cell values.
closure = func.__closure__ or []
- #xxx = [_object_contents(x.cell_contents) for x in closure]
try:
closure_contents = [_object_contents(x.cell_contents) for x in closure]
except AttributeError:
@@ -325,10 +322,66 @@ def _function_contents(func):
contents.append(b',(')
contents.append(bytearray(b',').join(closure_contents))
contents.append(b')')
- # contents.append(b'BBBBBBBB')
- return bytearray(b'').join(contents)
+ retval = bytearray(b'').join(contents)
+ return retval
+
+def _object_instance_content(obj):
+ """
+ Returns consistant content for a action class or an instance thereof
+ :param obj: Should be either and action class or an instance thereof
+ :return: bytearray or bytes representing the obj suitable for generating
+ a signiture from.
+ """
+ retval = bytearray()
+
+ if obj is None:
+ return b'N.'
+
+ if isinstance(obj, SCons.Util.BaseStringTypes):
+ return SCons.Util.to_bytes(obj)
+
+ inst_class = obj.__class__
+ inst_class_name = bytearray(obj.__class__.__name__,'utf-8')
+ inst_class_module = bytearray(obj.__class__.__module__,'utf-8')
+ inst_class_hierarchy = bytearray(repr(inspect.getclasstree([obj.__class__,])),'utf-8')
+ # print("ICH:%s : %s"%(inst_class_hierarchy, repr(obj)))
+
+ properties = [(p, getattr(obj, p, "None")) for p in dir(obj) if not (p[:2] == '__' or inspect.ismethod(getattr(obj, p)) or inspect.isbuiltin(getattr(obj,p))) ]
+ properties.sort()
+ properties_str = ','.join(["%s=%s"%(p[0],p[1]) for p in properties])
+ properties_bytes = bytearray(properties_str,'utf-8')
+
+ methods = [p for p in dir(obj) if inspect.ismethod(getattr(obj, p))]
+ methods.sort()
+
+ method_contents = []
+ for m in methods:
+ # print("Method:%s"%m)
+ v = _function_contents(getattr(obj, m))
+ # print("[%s->]V:%s [%s]"%(m,v,type(v)))
+ method_contents.append(v)
+
+ retval = bytearray(b'{')
+ retval.extend(inst_class_name)
+ retval.extend(b":")
+ retval.extend(inst_class_module)
+ retval.extend(b'}[[')
+ retval.extend(inst_class_hierarchy)
+ retval.extend(b']]{{')
+ retval.extend(bytearray(b",").join(method_contents))
+ retval.extend(b"}}{{{")
+ retval.extend(properties_bytes)
+ retval.extend(b'}}}')
+ return retval
+
+ # print("class :%s"%inst_class)
+ # print("class_name :%s"%inst_class_name)
+ # print("class_module :%s"%inst_class_module)
+ # print("Class hier :\n%s"%pp.pformat(inst_class_hierarchy))
+ # print("Inst Properties:\n%s"%pp.pformat(properties))
+ # print("Inst Methods :\n%s"%pp.pformat(methods))
def _actionAppend(act1, act2):
# This function knows how to slap two actions together.
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 82c5e0e..2398c10 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -1241,8 +1241,8 @@ class CommandActionTestCase(unittest.TestCase):
(env["foo"], env["bar"])
# The number 1 is there to make sure all args get converted to strings.
- a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
- "$)", "|", "$baz", 1])
+ a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$(", "$bar",
+ "$)", "stuff", "$)", "|", "$baz", 1])
c = a.get_contents(target=[], source=[],
env=Environment(foo = 'FFF', bar = 'BBB',
baz = CmdGen))
@@ -1257,7 +1257,7 @@ class CommandActionTestCase(unittest.TestCase):
c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
baz = 'ZZZ'))
- assert c == b'subst_target_source: | $( $foo | $bar $) | $baz 1', c
+ assert c == b'subst_target_source: | $( $foo | $( $bar $) stuff $) | $baz 1', c
# We've discussed using the real target and source names in a
# CommandAction's signature contents. This would have have the
@@ -1428,10 +1428,12 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def LocalFunc():
pass
- func_matches = [
- b"0, 0, 0, 0,(),(),(d\000\000S),(),()",
- b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()",
- ]
+ # Since the python bytecode has per version differences, we need different expected results per version
+ func_matches = {
+ (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ }
meth_matches = [
b"1, 1, 0, 0,(),(),(d\000\000S),(),()",
@@ -1448,11 +1450,11 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
a = self.factory(f_global)
c = a.get_contents(target=[], source=[], env=env)
- assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]])
a = self.factory(f_local)
c = a.get_contents(target=[], source=[], env=env)
- assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]])
def f_global(target, source, env, for_signature):
return SCons.Action.Action(GlobalFunc, varlist=['XYZ'])
@@ -1460,7 +1462,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def f_local(target, source, env, for_signature):
return SCons.Action.Action(LocalFunc, varlist=['XYZ'])
- matches_foo = [x + b"foo" for x in func_matches]
+ matches_foo = func_matches[sys.version_info[:2]] + b'foo'
a = self.factory(f_global)
c = a.get_contents(target=[], source=[], env=env)
@@ -1590,42 +1592,48 @@ class FunctionActionTestCase(unittest.TestCase):
def LocalFunc():
pass
- func_matches = [
- b"0, 0, 0, 0,(),(),(d\000\000S),(),()",
- b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()",
- ]
+ func_matches = {
+ (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ }
- meth_matches = [
- b"1, 1, 0, 0,(),(),(d\000\000S),(),()",
- b"1, 1, 0, 0,(),(),(d\x00\x00S),(),()",
- ]
+ meth_matches = {
+ (2,7) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,5) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,6) : bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
+ }
def factory(act, **kw):
return SCons.Action.FunctionAction(act, kw)
a = factory(GlobalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- # assert c in func_matches, repr(c)
- assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
a = factory(LocalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c in func_matches, repr(c)
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
- matches_foo = [x + b"foo" for x in func_matches]
+ matches_foo = func_matches[sys.version_info[:2]] + b'foo'
a = factory(GlobalFunc, varlist=['XYZ'])
c = a.get_contents(target=[], source=[], env=Environment())
- assert c in func_matches, repr(c)
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+ # assert c in func_matches, repr(c)
+
c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
- assert c in matches_foo, repr(c)
+ assert c == matches_foo, repr(c)
##TODO: is this set of tests still needed?
# Make sure a bare string varlist works
a = factory(GlobalFunc, varlist='XYZ')
c = a.get_contents(target=[], source=[], env=Environment())
- assert c in func_matches, repr(c)
+ # assert c in func_matches, repr(c)
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+
+
c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
assert c in matches_foo, repr(c)
@@ -1642,7 +1650,7 @@ class FunctionActionTestCase(unittest.TestCase):
lc = LocalClass()
a = factory(lc.LocalMethod)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c in meth_matches, repr(c)
+ assert c == meth_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(meth_matches[sys.version_info[:2]])
def test_strfunction(self):
"""Test the FunctionAction.strfunction() method
@@ -1808,10 +1816,12 @@ class LazyActionTestCase(unittest.TestCase):
def LocalFunc():
pass
- func_matches = [
- b"0, 0, 0, 0,(),(),(d\000\000S),(),()",
- b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()",
- ]
+
+ func_matches = {
+ (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ }
meth_matches = [
b"1, 1, 0, 0,(),(),(d\000\000S),(),()",
@@ -1826,17 +1836,22 @@ class LazyActionTestCase(unittest.TestCase):
env = Environment(FOO = factory(GlobalFunc))
c = a.get_contents(target=[], source=[], env=env)
- assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
+ # assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+
+
env = Environment(FOO = factory(LocalFunc))
c = a.get_contents(target=[], source=[], env=env)
- assert c in func_matches, repr(c)
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+
+ # matches_foo = [x + b"foo" for x in func_matches]
+ matches_foo = func_matches[sys.version_info[:2]] + b'foo'
- matches_foo = [x + b"foo" for x in func_matches]
env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ']))
c = a.get_contents(target=[], source=[], env=env)
- assert c in func_matches, repr(c)
+ assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
env['XYZ'] = 'foo'
c = a.get_contents(target=[], source=[], env=env)
@@ -1859,25 +1874,23 @@ class ActionCallerTestCase(unittest.TestCase):
def LocalFunc():
pass
- matches = [
- b"d\000\000S",
- b"d\\x00\\x00S"
- ]
+
+ matches = {
+ (2,7) : b'd\x00\x00S',
+ (3,5) : b'd\x00\x00S',
+ (3,6) : b'd\x00S\x00',
+ }
+
af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c in matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in matches])
+ assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
af = SCons.Action.ActionFactory(LocalFunc, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c in matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in matches])
-
- matches = [
- b'd\000\000S',
- b"d\x00\x00S"
- ]
+ assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
class LocalActFunc(object):
def __call__(self):
@@ -1886,12 +1899,12 @@ class ActionCallerTestCase(unittest.TestCase):
af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c in matches, "C [%s] not in matches [%s]"%(repr(c),matches)
+ assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c in matches, repr(c)
+ assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
matches = [
b"<built-in function str>",
@@ -2025,7 +2038,7 @@ class ActionCompareTestCase(unittest.TestCase):
assert dog.get_name(env) == 'DOG', dog.get_name(env)
-class TestClass:
+class TestClass(object):
"""A test class used by ObjectContentsTestCase.test_object_contents"""
def __init__(self):
self.a = "a"
@@ -2043,31 +2056,49 @@ class ObjectContentsTestCase(unittest.TestCase):
"""A test function"""
return a
+ # Since the python bytecode has per version differences, we need different expected results per version
+ expected = {
+ (2,7) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
+ (3,5) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
+ (3,6) : bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
+ }
+
c = SCons.Action._function_contents(func1)
- expected = bytearray('3, 3, 0, 0,(),(),(|\x00\x00S),(),()','utf-8')
- assert expected == c, "Got\n"+repr(c)+"\nExpected \n"+repr(expected)+"\n"
+ assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]])
- # @unittest.skip("Results vary between py2 and py3, not sure if test makes sense to implement")
def test_object_contents(self):
"""Test that Action._object_contents works"""
# See definition above
o = TestClass()
c = SCons.Action._object_contents(o)
- expected = bytearray("(i__main__\nTestClass\np1\n(dp2\nS'a'\nS'a'\nsS'b'\nS'b'\nsb.", 'utf-8')
- assert expected == c, "Got\n" + repr(c) + "\nExpected\n" + repr(expected)
- # @unittest.skip("Results vary between py2 and py3, not sure if test makes sense to implement")
+ # c = SCons.Action._object_instance_content(o)
+
+ # Since the python bytecode has per version differences, we need different expected results per version
+ expected = {
+ (2,7): bytearray(b"{TestClass:__main__}[[[(<type \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<type \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
+ (3,5): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
+ (3,6): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"),
+ }
+
+ assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]])
+
def test_code_contents(self):
"""Test that Action._code_contents works"""
code = compile("print('Hello, World!')", '<string>', 'exec')
c = SCons.Action._code_contents(code)
- expected = bytearray("0, 0, 0, 0,(N.),(),(d\x00\x00GHd\x01\x00S)", 'utf-8')
- assert expected == c, "Got\n" + repr(c) + "\nExpected\n" + repr(expected)
+ # Since the python bytecode has per version differences, we need different expected results per version
+ expected = {
+ (2,7) : bytearray(b'0, 0, 0, 0,(N.),(),(d\x00\x00GHd\x01\x00S)'),
+ (3,5) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'),
+ (3,6) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
+ }
+ assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+expected[sys.version_info[:2]]
@@ -2090,6 +2121,9 @@ if __name__ == "__main__":
TestUnit.run(suite)
+ # Swap this for above to debug otherwise you can't run individual tests as TestUnit is swallowing arguments
+ # unittest.main()
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Debug.py b/src/engine/SCons/Debug.py
index 9e520ff..706b4c4 100644
--- a/src/engine/SCons/Debug.py
+++ b/src/engine/SCons/Debug.py
@@ -97,7 +97,8 @@ def dumpLoggedInstances(classes, file=sys.stdout):
if sys.platform[:5] == "linux":
# Linux doesn't actually support memory usage stats from getrusage().
def memory():
- mstr = open('/proc/self/stat').read()
+ with open('/proc/self/stat') as f:
+ mstr = f.read()
mstr = mstr.split()[22]
return int(mstr)
elif sys.platform[:6] == 'darwin':
@@ -233,6 +234,7 @@ def Trace(msg, file=None, mode='w', tstamp=None):
PreviousTime = now
fp.write(msg)
fp.flush()
+ fp.close()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 85f9fa7..4f8e41b 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -167,7 +167,7 @@ def _set_SCANNERS(env, key, value):
def _delete_duplicates(l, keep_last):
"""Delete duplicates from a sequence, keeping the first or last."""
- seen={}
+ seen=set()
result=[]
if keep_last: # reverse in & out, then keep first
l.reverse()
@@ -175,7 +175,7 @@ def _delete_duplicates(l, keep_last):
try:
if i not in seen:
result.append(i)
- seen[i]=1
+ seen.add(i)
except TypeError:
# probably unhashable. Just keep it.
result.append(i)
@@ -1983,6 +1983,15 @@ class Base(SubstitutionEnvironment):
return result
return self.fs.Dir(s, *args, **kw)
+ def PyPackageDir(self, modulename):
+ s = self.subst(modulename)
+ if SCons.Util.is_Sequence(s):
+ result=[]
+ for e in s:
+ result.append(self.fs.PyPackageDir(e))
+ return result
+ return self.fs.PyPackageDir(s)
+
def NoClean(self, *targets):
"""Tags a target so that it will not be cleaned by -c"""
tlist = []
@@ -2368,19 +2377,21 @@ class OverrideEnvironment(Base):
Environment = Base
-# An entry point for returning a proxy subclass instance that overrides
-# the subst*() methods so they don't actually perform construction
-# variable substitution. This is specifically intended to be the shim
-# layer in between global function calls (which don't want construction
-# variable substitution) and the DefaultEnvironment() (which would
-# substitute variables if left to its own devices)."""
-#
-# We have to wrap this in a function that allows us to delay definition of
-# the class until it's necessary, so that when it subclasses Environment
-# it will pick up whatever Environment subclass the wrapper interface
-# might have assigned to SCons.Environment.Environment.
def NoSubstitutionProxy(subject):
+ """
+ An entry point for returning a proxy subclass instance that overrides
+ the subst*() methods so they don't actually perform construction
+ variable substitution. This is specifically intended to be the shim
+ layer in between global function calls (which don't want construction
+ variable substitution) and the DefaultEnvironment() (which would
+ substitute variables if left to its own devices).
+
+ We have to wrap this in a function that allows us to delay definition of
+ the class until it's necessary, so that when it subclasses Environment
+ it will pick up whatever Environment subclass the wrapper interface
+ might have assigned to SCons.Environment.Environment.
+ """
class _NoSubstitutionProxy(Environment):
def __init__(self, subject):
self.__dict__['__subject'] = subject
diff --git a/src/engine/SCons/Environment.xml b/src/engine/SCons/Environment.xml
index 92bc21a..ccee68d 100644
--- a/src/engine/SCons/Environment.xml
+++ b/src/engine/SCons/Environment.xml
@@ -2504,6 +2504,29 @@ env.PrependUnique(CCFLAGS = '-g', FOO = ['foo.yyy'])
</summary>
</scons_function>
+<scons_function name="PyPackageDir">
+<arguments>
+(modulename)
+</arguments>
+<summary>
+<para>
+This returns a Directory Node similar to Dir.
+The python module / package is looked up and if located
+the directory is returned for the location.
+<varname>modulename</varname>
+Is a named python package / module to
+lookup the directory for it's location.
+</para>
+<para>
+If
+<varname>modulename</varname>
+is a list, SCons returns a list of Dir nodes.
+Construction variables are expanded in
+<varname>modulename</varname>.
+</para>
+</summary>
+</scons_function>
+
<scons_function name="Replace">
<arguments signature="env">
(key=val, [...])
diff --git a/src/engine/SCons/EnvironmentValues.py b/src/engine/SCons/EnvironmentValues.py
new file mode 100644
index 0000000..e2efccb
--- /dev/null
+++ b/src/engine/SCons/EnvironmentValues.py
@@ -0,0 +1,97 @@
+import re
+
+_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
+
+_rm = re.compile(r'\$[()]')
+_remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)')
+
+# Regular expressions for splitting strings and handling substitutions,
+# for use by the scons_subst() and scons_subst_list() functions:
+#
+# The first expression compiled matches all of the $-introduced tokens
+# that we need to process in some way, and is used for substitutions.
+# The expressions it matches are:
+#
+# "$$"
+# "$("
+# "$)"
+# "$variable" [must begin with alphabetic or underscore]
+# "${any stuff}"
+#
+# The second expression compiled is used for splitting strings into tokens
+# to be processed, and it matches all of the tokens listed above, plus
+# the following that affect how arguments do or don't get joined together:
+#
+# " " [white space]
+# "non-white-space" [without any dollar signs]
+# "$" [single dollar sign]
+#
+_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
+_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
+_separate_args = re.compile(r'(%s|\s+|[^\s\$]+|\$)' % _dollar_exps_str)
+
+# This regular expression is used to replace strings of multiple white
+# space characters in the string result from the scons_subst() function.
+_space_sep = re.compile(r'[\t ]+(?![^{]*})')
+
+class ValueTypes(object):
+ """
+ Enum to store what type of value the variable holds.
+ """
+ UNKNOWN = 0
+ STRING = 1
+ CALLABLE = 2
+ VARIABLE = 3
+
+
+class EnvironmentValue(object):
+ """
+ Hold a single value. We're going to cache parsed version of the file
+ We're going to keep track of variables which feed into this values evaluation
+ """
+ def __init__(self, value):
+ self.value = value
+ self.var_type = ValueTypes.UNKNOWN
+
+ if callable(self.value):
+ self.var_type = ValueTypes.CALLABLE
+ else:
+ self.parse_value()
+
+
+ def parse_value(self):
+ """
+ Scan the string and break into component values
+ """
+
+ try:
+ if '$' not in self.value:
+ self._parsed = self.value
+ self.var_type = ValueTypes.STRING
+ else:
+ # Now we need to parse the specified string
+ result = _dollar_exps.sub(sub_match, args)
+ print(result)
+ pass
+ except TypeError:
+ # likely callable? either way we don't parse
+ self._parsed = self.value
+
+ def parse_trial(self):
+ """
+ Try alternate parsing methods.
+ :return:
+ """
+ parts = []
+ for c in self.value:
+
+
+
+class EnvironmentValues(object):
+ """
+ A class to hold all the environment variables
+ """
+ def __init__(self, **kw):
+ self._dict = {}
+ for k in kw:
+ self._dict[k] = EnvironmentValue(kw[k])
diff --git a/src/engine/SCons/EnvironmentValuesTest.py b/src/engine/SCons/EnvironmentValuesTest.py
new file mode 100644
index 0000000..58ee9cf
--- /dev/null
+++ b/src/engine/SCons/EnvironmentValuesTest.py
@@ -0,0 +1,16 @@
+import unittest
+
+from SCons.EnvironmentValues import EnvironmentValues
+
+class MyTestCase(unittest.TestCase):
+ def test_simple_environmentValues(self):
+ """Test comparing SubstitutionEnvironments
+ """
+
+ env1 = EnvironmentValues(XXX='x')
+ env2 = EnvironmentValues(XXX='x',XX="$X", X1="${X}", X2="$($X$)")
+
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index d98f7d0..8c1161d 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -1390,6 +1390,35 @@ class FS(LocalFS):
if not isinstance(d, SCons.Node.Node):
d = self.Dir(d)
self.Top.addRepository(d)
+
+ def PyPackageDir(self, modulename):
+ """Locate the directory of a given python module name
+
+ For example scons might resolve to
+ Windows: C:\Python27\Lib\site-packages\scons-2.5.1
+ Linux: /usr/lib/scons
+
+ This can be useful when we want to determine a toolpath based on a python module name"""
+
+ dirpath = ''
+ if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
+ # Python2 Code
+ import imp
+ splitname = modulename.split('.')
+ srchpths = sys.path
+ for item in splitname:
+ file, path, desc = imp.find_module(item, srchpths)
+ if file is not None:
+ path = os.path.dirname(path)
+ srchpths = [path]
+ dirpath = path
+ else:
+ # Python3 Code
+ import importlib.util
+ modspec = importlib.util.find_spec(modulename)
+ dirpath = os.path.dirname(modspec.origin)
+ return self._lookup(dirpath, None, Dir, True)
+
def variant_dir_target_climb(self, orig, dir, tail):
"""Create targets in corresponding variant directories
diff --git a/src/engine/SCons/PathList.py b/src/engine/SCons/PathList.py
index 77e30c4..76cbeab 100644
--- a/src/engine/SCons/PathList.py
+++ b/src/engine/SCons/PathList.py
@@ -104,11 +104,11 @@ class _PathList(object):
pl = []
for p in pathlist:
try:
- index = p.find('$')
+ found = '$' in p
except (AttributeError, TypeError):
type = TYPE_OBJECT
else:
- if index == -1:
+ if not found:
type = TYPE_STRING_NO_SUBST
else:
type = TYPE_STRING_SUBST
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 3fa3a48..5bdd63e 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -337,6 +337,7 @@ GlobalDefaultEnvironmentFunctions = [
'Local',
'ParseDepends',
'Precious',
+ 'PyPackageDir',
'Repository',
'Requires',
'SConsignFile',
diff --git a/src/engine/SCons/Subst.py b/src/engine/SCons/Subst.py
index 3c9b390..a68b54d 100644
--- a/src/engine/SCons/Subst.py
+++ b/src/engine/SCons/Subst.py
@@ -338,24 +338,28 @@ SUBST_RAW = 1
SUBST_SIG = 2
_rm = re.compile(r'\$[()]')
-_remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)')
+_rm_split = re.compile(r'(\$[()])')
# Indexed by the SUBST_* constants above.
-_regex_remove = [ _rm, None, _remove ]
+_regex_remove = [ _rm, None, _rm_split ]
def _rm_list(list):
return [l for l in list if not l in ('$(', '$)')]
def _remove_list(list):
result = []
- do_append = result.append
+ depth = 0
for l in list:
if l == '$(':
- do_append = lambda x: None
+ depth += 1
elif l == '$)':
- do_append = result.append
- else:
- do_append(l)
+ depth -= 1
+ if depth < 0:
+ break
+ elif depth == 0:
+ result.append(l)
+ if depth != 0:
+ return None
return result
# Indexed by the SUBST_* constants above.
@@ -438,7 +442,7 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
return s
else:
key = s[1:]
- if key[0] == '{' or key.find('.') >= 0:
+ if key[0] == '{' or '.' in key:
if key[0] == '{':
key = key[1:-1]
try:
@@ -562,12 +566,19 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
except KeyError:
pass
+ res = result
if is_String(result):
# Remove $(-$) pairs and any stuff in between,
# if that's appropriate.
remove = _regex_remove[mode]
if remove:
- result = remove.sub('', result)
+ if mode == SUBST_SIG:
+ result = _list_remove[mode](remove.split(result))
+ if result is None:
+ raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
+ result = ' '.join(result)
+ else:
+ result = remove.sub('', result)
if mode != SUBST_RAW:
# Compress strings of white space characters into
# a single space.
@@ -576,6 +587,8 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
remove = _list_remove[mode]
if remove:
result = remove(result)
+ if result is None:
+ raise SCons.Errors.UserError("Unbalanced $(/$) in: " + str(res))
return result
diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py
index c11f247..6604128 100644
--- a/src/engine/SCons/SubstTests.py
+++ b/src/engine/SCons/SubstTests.py
@@ -183,6 +183,9 @@ class SubstTestCase(unittest.TestCase):
'HHH' : 'III',
'FFFIII' : 'BADNEWS',
+ 'THING1' : "$(STUFF$)",
+ 'THING2' : "$THING1",
+
'LITERAL' : TestLiteral("$XXX"),
# Test that we can expand to and return a function.
@@ -405,6 +408,11 @@ class scons_subst_TestCase(SubstTestCase):
"test",
"test",
+ "test $( $THING2 $)",
+ "test $( $(STUFF$) $)",
+ "test STUFF",
+ "test",
+
"$AAA ${AAA}A $BBBB $BBB",
"a aA b",
"a aA b",
@@ -544,6 +552,23 @@ class scons_subst_TestCase(SubstTestCase):
else:
raise AssertionError("did not catch expected UserError")
+ def test_subst_balance_errors(self):
+ """Test scons_subst(): handling syntax errors"""
+ env = DummyEnv(self.loc)
+ try:
+ scons_subst('$(', env, mode=SUBST_SIG)
+ except SCons.Errors.UserError as e:
+ assert str(e) == "Unbalanced $(/$) in: $(", str(e)
+ else:
+ raise AssertionError("did not catch expected UserError")
+
+ try:
+ scons_subst('$)', env, mode=SUBST_SIG)
+ except SCons.Errors.UserError as e:
+ assert str(e) == "Unbalanced $(/$) in: $)", str(e)
+ else:
+ raise AssertionError("did not catch expected UserError")
+
def test_subst_type_errors(self):
"""Test scons_subst(): handling type errors"""
env = DummyEnv(self.loc)
diff --git a/src/engine/SCons/Tool/MSCommon/common.py b/src/engine/SCons/Tool/MSCommon/common.py
index a846cfc..b60cd5b 100644
--- a/src/engine/SCons/Tool/MSCommon/common.py
+++ b/src/engine/SCons/Tool/MSCommon/common.py
@@ -130,6 +130,13 @@ def normalize_env(env, keys, force=False):
if sys32_dir not in normenv['PATH']:
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir
+ # Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
+ # error starting with Visual Studio 2017, although the script still
+ # seems to work anyway.
+ sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem')
+ if sys32_wbem_dir not in normenv['PATH']:
+ normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
+
debug("PATH: %s"%normenv['PATH'])
return normenv
diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py
index 7b8dd9d..7c9eab5 100644
--- a/src/engine/SCons/Tool/MSCommon/vc.py
+++ b/src/engine/SCons/Tool/MSCommon/vc.py
@@ -37,6 +37,7 @@ __doc__ = """Module for Visual C/C++ detection and configuration.
import SCons.compat
import SCons.Util
+import subprocess
import os
import platform
from string import digits as string_digits
@@ -135,9 +136,11 @@ def get_host_target(env):
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
# MSVC_VERSION documentation in Tool/msvc.xml.
-_VCVER = ["14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
+_VCVER = ["14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
_VCVER_TO_PRODUCT_DIR = {
+ '14.1' : [
+ (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore
'14.0' : [
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
'14.0Exp' : [
@@ -185,18 +188,17 @@ _VCVER_TO_PRODUCT_DIR = {
}
def msvc_version_to_maj_min(msvc_version):
-
msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
t = msvc_version_numeric.split(".")
if not len(t) == 2:
- raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
+ raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
try:
- maj = int(t[0])
- min = int(t[1])
- return maj, min
+ maj = int(t[0])
+ min = int(t[1])
+ return maj, min
except ValueError as e:
- raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
+ raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
def is_host_target_supported(host_target, msvc_version):
"""Return True if the given (host, target) tuple is supported given the
@@ -223,6 +225,33 @@ def is_host_target_supported(host_target, msvc_version):
return True
+
+def find_vc_pdir_vswhere(msvc_version):
+ """
+ Find the MSVC product directory using vswhere.exe .
+ Run it asking for specified version and get MSVS install location
+ :param msvc_version:
+ :return: MSVC install dir
+ """
+ vswhere_path = os.path.join(
+ 'C:\\',
+ 'Program Files (x86)',
+ 'Microsoft Visual Studio',
+ 'Installer',
+ 'vswhere.exe'
+ )
+ vswhere_cmd = [vswhere_path, '-version', msvc_version, '-property', 'installationPath']
+
+ if os.path.exists(vswhere_path):
+ sp = subprocess.Popen(vswhere_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ vsdir, err = sp.communicate()
+ vc_pdir = os.path.join(vsdir.rstrip(), 'VC')
+ return vc_pdir
+ else:
+ # No vswhere on system, no install info available
+ return None
+
+
def find_vc_pdir(msvc_version):
"""Try to find the product directory for the given
version.
@@ -241,16 +270,22 @@ def find_vc_pdir(msvc_version):
for hkroot, key in hkeys:
try:
comps = None
- if common.is_win64():
- try:
- # ordinally at win64, try Wow6432Node first.
- comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
- except SCons.Util.WinError as e:
- # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node
- pass
- if not comps:
- # not Win64, or Microsoft Visual Studio for Python 2.7
- comps = common.read_reg(root + key, hkroot)
+ if not key:
+ comps = find_vc_pdir_vswhere(msvc_version)
+ if not comps:
+ debug('find_vc_dir(): no VC found via vswhere for version {}'.format(repr(key)))
+ raise SCons.Util.WinError
+ else:
+ if common.is_win64():
+ try:
+ # ordinally at win64, try Wow6432Node first.
+ comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
+ except SCons.Util.WinError as e:
+ # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node
+ pass
+ if not comps:
+ # not Win64, or Microsoft Visual Studio for Python 2.7
+ comps = common.read_reg(root + key, hkroot)
except SCons.Util.WinError as e:
debug('find_vc_dir(): no VC registry key {}'.format(repr(key)))
else:
@@ -282,8 +317,10 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
elif vernum < 7:
pdir = os.path.join(pdir, "Bin")
batfilename = os.path.join(pdir, "vcvars32.bat")
- else: # >= 8
+ elif 8 <= vernum <= 14:
batfilename = os.path.join(pdir, "vcvarsall.bat")
+ else: # vernum >= 14.1 VS2017 and above
+ batfilename = os.path.join(pdir, "Auxiliary", "Build", "vcvarsall.bat")
if not os.path.exists(batfilename):
debug("Not found: %s" % batfilename)
@@ -435,6 +472,14 @@ 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]
+
+ # Get just version numbers
+ maj, min = msvc_version_to_maj_min(version)
+ # VS2015+
+ if maj >= 14:
+ if env.get('MSVC_UWP_APP') == '1':
+ # Initialize environment variables with store/universal paths
+ arg += ' store'
# Try to locate a batch file for this host/target platform combo
try:
diff --git a/src/engine/SCons/Tool/MSCommon/vs.py b/src/engine/SCons/Tool/MSCommon/vs.py
index cff05d5..f9382fb 100644
--- a/src/engine/SCons/Tool/MSCommon/vs.py
+++ b/src/engine/SCons/Tool/MSCommon/vs.py
@@ -199,6 +199,17 @@ class VisualStudio(object):
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
SupportedVSList = [
+ # Visual Studio 2017
+ VisualStudio('14.1',
+ vc_version='14.1',
+ sdk_version='10.0A',
+ hkeys=[],
+ common_tools_var='VS150COMNTOOLS',
+ executable_path=r'Common7\IDE\devenv.com',
+ batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat',
+ supported_arch=['x86', 'amd64', "arm"],
+ ),
+
# Visual Studio 2015
VisualStudio('14.0',
vc_version='14.0',
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 61b7788..6408f8b 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -101,7 +101,10 @@ for suffix in LaTeXSuffixes:
# Tool aliases are needed for those tools whos module names also
# occur in the python standard library. This causes module shadowing and
# can break using python library functions under python3
-TOOL_ALIASES = {'gettext':'gettext_tool'}
+TOOL_ALIASES = {
+ 'gettext':'gettext_tool',
+ 'clang++': 'clangxx',
+}
class Tool(object):
def __init__(self, name, toolpath=[], **kw):
@@ -118,6 +121,16 @@ class Tool(object):
if hasattr(module, 'options'):
self.options = module.options
+ def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None):
+ splitname = short_name.split('.')
+ index = 0
+ srchpths = searchpaths
+ for item in splitname:
+ file, path, desc = imp.find_module(item, srchpths)
+ mod = imp.load_module(full_name, file, path, desc)
+ srchpths = [path]
+ return mod, file
+
def _tool_module(self):
oldpythonpath = sys.path
sys.path = self.toolpath + sys.path
@@ -127,15 +140,16 @@ class Tool(object):
# Py 2 code
try:
try:
- file, path, desc = imp.find_module(self.name, self.toolpath)
+ file = None
try:
- return imp.load_module(self.name, file, path, desc)
-
+ mod, file = self._load_dotted_module_py2(self.name, self.name, self.toolpath)
+ return mod
finally:
if file:
file.close()
except ImportError as e:
- if str(e)!="No module named %s"%self.name:
+ splitname = self.name.split('.')
+ if str(e)!="No module named %s"%splitname[0]:
raise SCons.Errors.EnvironmentError(e)
try:
import zipimport
@@ -169,8 +183,9 @@ class Tool(object):
found_name = self.name
add_to_scons_tools_namespace = False
for path in self.toolpath:
- file_path = os.path.join(path, "%s.py"%self.name)
- file_package = os.path.join(path, self.name)
+ sepname = self.name.replace('.', os.path.sep)
+ file_path = os.path.join(path, "%s.py"%sepname)
+ file_package = os.path.join(path, sepname)
if debug: sys.stderr.write("Trying:%s %s\n"%(file_path, file_package))
@@ -179,6 +194,7 @@ class Tool(object):
if debug: print("file_Path:%s FOUND"%file_path)
break
elif os.path.isdir(file_package):
+ file_package = os.path.join(file_package, '__init__.py')
spec = importlib.util.spec_from_file_location(self.name, file_package)
if debug: print("PACKAGE:%s Found"%file_package)
break
@@ -212,7 +228,7 @@ class Tool(object):
# Not sure what to do in the case that there already
# exists sys.modules[self.name] but the source file is
# different.. ?
- spec.loader.exec_module(module)
+ module = spec.loader.load_module(spec.name)
sys.modules[found_name] = module
if add_to_scons_tools_namespace:
@@ -231,8 +247,7 @@ class Tool(object):
try:
smpath = sys.modules['SCons.Tool'].__path__
try:
- file, path, desc = imp.find_module(self.name, smpath)
- module = imp.load_module(full_name, file, path, desc)
+ module, file = self._load_dotted_module_py2(self.name, full_name, smpath)
setattr(SCons.Tool, self.name, module)
if file:
file.close()
@@ -1157,12 +1172,12 @@ def tool_list(platform, env):
ars = ['ar', 'mslib']
else:
"prefer GNU tools on all other platforms"
- linkers = ['gnulink', 'mslink', 'ilink']
- c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
- cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx']
+ linkers = ['gnulink', 'ilink']
+ c_compilers = ['gcc', 'intelc', 'icc', 'cc']
+ cxx_compilers = ['g++', 'intelc', 'icc', 'cxx']
assemblers = ['gas', 'nasm', 'masm']
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
- ars = ['ar', 'mslib']
+ ars = ['ar',]
if not str(platform) == 'win32':
other_plat_tools += ['m4', 'rpm']
diff --git a/src/engine/SCons/Tool/clang.py b/src/engine/SCons/Tool/clang.py
new file mode 100644
index 0000000..177e6b2
--- /dev/null
+++ b/src/engine/SCons/Tool/clang.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8; -*-
+
+"""SCons.Tool.clang
+
+Tool-specific initialization for clang.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+#
+# __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__"
+
+# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
+# Brought into the SCons mainline by Russel Winder 2017.
+
+import os
+import re
+import subprocess
+import sys
+
+import SCons.Util
+import SCons.Tool.cc
+
+compilers = ['clang']
+
+def generate(env):
+ """Add Builders and construction variables for clang to an Environment."""
+ SCons.Tool.cc.generate(env)
+
+ env['CC'] = env.Detect(compilers) or 'clang'
+ 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
+ # clang -dumpversion is of no use
+ line = pipe.stdout.readline()
+ if sys.version_info[0] > 2:
+ line = line.decode()
+ match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
+ if match:
+ env['CCVERSION'] = match.group(1)
+
+def exists(env):
+ return env.Detect(compilers)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/clang.xml b/src/engine/SCons/Tool/clang.xml
new file mode 100644
index 0000000..e2e50d4
--- /dev/null
+++ b/src/engine/SCons/Tool/clang.xml
@@ -0,0 +1,39 @@
+<?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 http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="clang">
+<summary>
+<para>
+Set construction variables for the Clang C compiler.
+</para>
+</summary>
+<sets>
+<item>CC</item>
+<item>SHCCFLAGS</item>
+<item>CCVERSION</item>
+</sets>
+</tool>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/clangxx.py b/src/engine/SCons/Tool/clangxx.py
new file mode 100644
index 0000000..dd501af
--- /dev/null
+++ b/src/engine/SCons/Tool/clangxx.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8; -*-
+
+"""SCons.Tool.clang++
+
+Tool-specific initialization for clang++.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+#
+# __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__"
+
+# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
+# Brought into the SCons mainline by Russel Winder 2017.
+
+import os.path
+import re
+import subprocess
+import sys
+
+import SCons.Tool
+import SCons.Util
+import SCons.Tool.cxx
+
+compilers = ['clang++']
+
+def generate(env):
+ """Add Builders and construction variables for clang++ to an Environment."""
+ static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
+
+ SCons.Tool.cxx.generate(env)
+
+ env['CXX'] = env.Detect(compilers) or 'clang++'
+
+ # platform specific settings
+ if env['PLATFORM'] == 'aix':
+ env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
+ env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
+ env['SHOBJSUFFIX'] = '$OBJSUFFIX'
+ elif env['PLATFORM'] == 'hpux':
+ env['SHOBJSUFFIX'] = '.pic.o'
+ elif env['PLATFORM'] == 'sunos':
+ env['SHOBJSUFFIX'] = '.pic.o'
+ # determine compiler version
+ if env['CXX']:
+ pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
+ stdin='devnull',
+ stderr='devnull',
+ stdout=subprocess.PIPE)
+ if pipe.wait() != 0: return
+ # clang -dumpversion is of no use
+ line = pipe.stdout.readline()
+ if sys.version_info[0] > 2:
+ line = line.decode()
+ match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
+ if match:
+ env['CXXVERSION'] = match.group(1)
+
+def exists(env):
+ return env.Detect(compilers)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Tool/clangxx.xml b/src/engine/SCons/Tool/clangxx.xml
new file mode 100644
index 0000000..2c1c2ca
--- /dev/null
+++ b/src/engine/SCons/Tool/clangxx.xml
@@ -0,0 +1,41 @@
+<?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 http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="clangxx">
+<summary>
+<para>
+Set construction variables for the Clang C++ compiler.
+</para>
+</summary>
+<sets>
+<item>CXX</item>
+<item>SHCXXFLAGS</item>
+<item>STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME</item>
+<item>SHOBJSUFFIX</item>
+<item>CXXVERSION</item>
+</sets>
+</tool>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/dmd.py b/src/engine/SCons/Tool/dmd.py
index 64beea5..7c142eb 100644
--- a/src/engine/SCons/Tool/dmd.py
+++ b/src/engine/SCons/Tool/dmd.py
@@ -75,7 +75,7 @@ def generate(env):
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
- env['DC'] = env.Detect(['dmd', 'gdmd'])
+ env['DC'] = env.Detect(['dmd', 'ldmd2', 'gdmd']) or 'dmd'
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__)}'
@@ -129,7 +129,7 @@ def generate(env):
# __RPATH is set to $_RPATH in the platform specification if that
# platform supports it.
- env['DRPATHPREFIX'] = '-L-rpath='
+ env['DRPATHPREFIX'] = '-L-rpath,' if env['PLATFORM'] == 'darwin' else '-L-rpath='
env['DRPATHSUFFIX'] = ''
env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}'
@@ -144,8 +144,6 @@ def generate(env):
env['DSHLIBVERSION'] = '$SHLIBVERSION'
env['DSHLIBVERSIONFLAGS'] = []
- SCons.Tool.createStaticLibBuilder(env)
-
env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder(
action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS',
emitter=DCommon.allAtOnceEmitter,
diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py
index fdfe867..a8e037c 100644
--- a/src/engine/SCons/Tool/gdc.py
+++ b/src/engine/SCons/Tool/gdc.py
@@ -65,7 +65,7 @@ def generate(env):
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
- env['DC'] = env.Detect('gdc')
+ env['DC'] = env.Detect('gdc') or '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__)}'
@@ -128,8 +128,6 @@ def generate(env):
env['DSHLIBVERSION'] = '$SHLIBVERSION'
env['DSHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
- SCons.Tool.createStaticLibBuilder(env)
-
env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder(
action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -o $TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS',
emitter=DCommon.allAtOnceEmitter,
diff --git a/src/engine/SCons/Tool/gxx.py b/src/engine/SCons/Tool/gxx.py
index c5eb579..574fd8e 100644
--- a/src/engine/SCons/Tool/gxx.py
+++ b/src/engine/SCons/Tool/gxx.py
@@ -41,7 +41,7 @@ import SCons.Tool
import SCons.Util
from . import gcc
-cplusplus = __import__(__package__+'.c++', globals(), locals(), ['*'])
+from . import cxx
compilers = ['g++']
@@ -52,7 +52,7 @@ def generate(env):
if 'CXX' not in env:
env['CXX'] = env.Detect(compilers) or compilers[0]
- cplusplus.generate(env)
+ cxx.generate(env)
# platform specific settings
if env['PLATFORM'] == 'aix':
diff --git a/src/engine/SCons/Tool/ldc.py b/src/engine/SCons/Tool/ldc.py
index 215c3e7..b10bb75 100644
--- a/src/engine/SCons/Tool/ldc.py
+++ b/src/engine/SCons/Tool/ldc.py
@@ -70,7 +70,7 @@ def generate(env):
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
- env['DC'] = env.Detect('ldc2')
+ env['DC'] = env.Detect('ldc2') or '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__)}'
@@ -105,13 +105,7 @@ def generate(env):
env['DSHLINK'] = '$DC'
env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=phobos2-ldc')
- #### START DEPRECATION 2017-05-21
- # Hack for Fedora the packages of which use the wrong name :-(
- if os.path.exists('/usr/lib64/libphobos-ldc.so') or os.path.exists('/usr/lib32/libphobos-ldc.so') or os.path.exists('/usr/lib/libphobos-ldc.so'):
- env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=phobos-ldc')
- #### END DEPRECATION 2017-05-21
-
- env['SHDLINKCOM'] = '$DLINK -of=$TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
+ env['SHDLINKCOM'] = '$DLINK -of=$TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS -L-ldruntime-ldc'
env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l'
env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else ''
@@ -132,7 +126,7 @@ def generate(env):
# __RPATH is set to $_RPATH in the platform specification if that
# platform supports it.
- env['DRPATHPREFIX'] = '-L-rpath='
+ env['DRPATHPREFIX'] = '-L-Wl,-rpath,' if env['PLATFORM'] == 'darwin' else '-L-rpath='
env['DRPATHSUFFIX'] = ''
env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}'
@@ -147,8 +141,6 @@ def generate(env):
env['DSHLIBVERSION'] = '$SHLIBVERSION'
env['DSHLIBVERSIONFLAGS'] = []
- SCons.Tool.createStaticLibBuilder(env)
-
env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder(
action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of=$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS',
emitter=DCommon.allAtOnceEmitter,
diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py
index bd643f7..c73852b 100644
--- a/src/engine/SCons/Tool/linkloc.py
+++ b/src/engine/SCons/Tool/linkloc.py
@@ -52,8 +52,8 @@ def repl_linker_command(m):
# Replaces any linker command file directives (e.g. "@foo.lnk") with
# the actual contents of the file.
try:
- f=open(m.group(2), "r")
- return m.group(1) + f.read()
+ with open(m.group(2), "r") as f:
+ return m.group(1) + f.read()
except IOError:
# the linker should return an error if it can't
# find the linker command file so we will remain quiet.
diff --git a/src/engine/SCons/Tool/msvc.xml b/src/engine/SCons/Tool/msvc.xml
index 2b4619e..1823a89 100644
--- a/src/engine/SCons/Tool/msvc.xml
+++ b/src/engine/SCons/Tool/msvc.xml
@@ -352,6 +352,8 @@ constructor; setting it later has no effect.
<para>
Valid values for Windows are
+<literal>14.0</literal>,
+<literal>14.0Exp</literal>,
<literal>12.0</literal>,
<literal>12.0Exp</literal>,
<literal>11.0</literal>,
@@ -440,4 +442,27 @@ For example, if you want to compile 64-bit binaries, you would set
</summary>
</cvar>
+<cvar name="MSVC_UWP_APP">
+<summary>
+<para>
+Build libraries for a Universal Windows Platform (UWP) Application.
+</para>
+
+<para>
+If &cv-MSVC_UWP_APP; is set, the Visual Studio environment will be set up to point
+to the Windows Store compatible libraries and Visual Studio runtimes. In doing so,
+any libraries that are built will be able to be used in a UWP App and published
+to the Windows Store.
+This flag will only have an effect with Visual Studio 2015+.
+This variable must be passed as an argument to the Environment()
+constructor; setting it later has no effect.
+</para>
+
+<para>
+Valid values are '1' or '0'
+</para>
+
+</summary>
+</cvar>
+
</sconsdoc>
diff --git a/src/engine/SCons/Tool/zip.py b/src/engine/SCons/Tool/zip.py
index 2613bfc..23d540f 100644
--- a/src/engine/SCons/Tool/zip.py
+++ b/src/engine/SCons/Tool/zip.py
@@ -40,31 +40,23 @@ import SCons.Defaults
import SCons.Node.FS
import SCons.Util
-try:
- import zipfile
- internal_zip = 1
-except ImportError:
- internal_zip = 0
-
-if internal_zip:
- zipcompression = zipfile.ZIP_DEFLATED
- def zip(target, source, env):
- compression = env.get('ZIPCOMPRESSION', 0)
- zf = zipfile.ZipFile(str(target[0]), 'w', compression)
- for s in source:
- if s.isdir():
- for dirpath, dirnames, filenames in os.walk(str(s)):
- for fname in filenames:
- path = os.path.join(dirpath, fname)
- if os.path.isfile(path):
- zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))))
- else:
- zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', ''))))
- zf.close()
-else:
- zipcompression = 0
- zip = "$ZIP $ZIPFLAGS ${TARGET.abspath} $SOURCES"
-
+import zipfile
+
+zipcompression = zipfile.ZIP_DEFLATED
+def zip(target, source, env):
+ compression = env.get('ZIPCOMPRESSION', 0)
+ zf = zipfile.ZipFile(str(target[0]), 'w', compression)
+ for s in source:
+ if s.isdir():
+ for dirpath, dirnames, filenames in os.walk(str(s)):
+ for fname in filenames:
+ path = os.path.join(dirpath, fname)
+ if os.path.isfile(path):
+
+ zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))))
+ else:
+ zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', ''))))
+ zf.close()
zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION'])
@@ -91,7 +83,7 @@ def generate(env):
env['ZIPROOT'] = SCons.Util.CLVar('')
def exists(env):
- return internal_zip or env.Detect('zip')
+ return True
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 4d0df22..846d06c 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -1506,9 +1506,8 @@ def MD5signature(s):
def MD5filesignature(fname, chunksize=65536):
- f = open(fname, "rb")
- result = f.read()
- f.close()
+ with open(fname, "rb") as f:
+ result = f.read()
return result
try:
diff --git a/src/engine/SCons/Variables/__init__.py b/src/engine/SCons/Variables/__init__.py
index cd66604..1fe4435 100644
--- a/src/engine/SCons/Variables/__init__.py
+++ b/src/engine/SCons/Variables/__init__.py
@@ -175,7 +175,9 @@ class Variables(object):
sys.path.insert(0, dir)
try:
values['__name__'] = filename
- exec(open(filename, 'r').read(), {}, values)
+ with open(filename, 'r') as f:
+ contents = f.read()
+ exec(contents, {}, values)
finally:
if dir:
del sys.path[0]
diff --git a/src/engine/SCons/cpp.py b/src/engine/SCons/cpp.py
index f282ba7..2e20017 100644
--- a/src/engine/SCons/cpp.py
+++ b/src/engine/SCons/cpp.py
@@ -379,7 +379,8 @@ class PreProcessor(object):
return None
def read_file(self, file):
- return open(file).read()
+ with open(file) as f:
+ return f.read()
# Start and stop processing include lines.
diff --git a/src/script/scons.py b/src/script/scons.py
index 1cf9469..bdf0cea 100644
--- a/src/script/scons.py
+++ b/src/script/scons.py
@@ -58,11 +58,11 @@ import sys
# engine modules if they're in either directory.
-## if sys.version_info >= (3,0,0):
-## msg = "scons: *** SCons version %s does not run under Python version %s.\n\
-## Python 3 is not yet supported.\n"
-## sys.stderr.write(msg % (__version__, sys.version.split()[0]))
-## sys.exit(1)
+if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0):
+ msg = "scons: *** SCons version %s does not run under Python version %s.\n\
+Python < 3.5 is not yet supported.\n"
+ sys.stderr.write(msg % (__version__, sys.version.split()[0]))
+ sys.exit(1)
script_dir = sys.path[0]
diff --git a/src/setup.py b/src/setup.py
index 41fc35a..1957db6 100644
--- a/src/setup.py
+++ b/src/setup.py
@@ -54,7 +54,6 @@ if head:
os.chdir(head)
sys.argv[0] = tail
-
# flag if setup.py is run on win32 or _for_ win32 platform,
# (when building windows installer on linux, for example)
is_win32 = 0
@@ -67,7 +66,6 @@ if not sys.platform == 'win32':
else:
is_win32 = 1
-
import distutils
import distutils.core
import distutils.command.install
@@ -77,6 +75,7 @@ import distutils.command.install_scripts
import distutils.command.build_scripts
import distutils.msvccompiler
+
def get_build_version():
""" monkey patch distutils msvc version if we're not on windows.
We need to use vc version 9 for python 2.7.x and it defaults to 6
@@ -84,6 +83,7 @@ def get_build_version():
monkey patching"""
return 9
+
distutils.msvccompiler.get_build_version = get_build_version
_install = distutils.command.install.install
@@ -92,13 +92,16 @@ _install_lib = distutils.command.install_lib.install_lib
_install_scripts = distutils.command.install_scripts.install_scripts
_build_scripts = distutils.command.build_scripts.build_scripts
+
class _options(object):
pass
+
Options = _options()
Installed = []
+
def set_explicitly(name, args):
"""
Return if the installation directory was set explicitly by the
@@ -119,51 +122,52 @@ def set_explicitly(name, args):
break
return set
+
class install(_install):
user_options = _install.user_options + [
- ('no-scons-script', None,
- "don't install 'scons', only install 'scons-%s'" % Version),
- ('no-version-script', None,
- "don't install 'scons-%s', only install 'scons'" % Version),
- ('install-bat', None,
- "install 'scons.bat' script"),
- ('no-install-bat', None,
- "do not install 'scons.bat' script"),
- ('install-man', None,
- "install SCons man pages"),
- ('no-install-man', None,
- "do not install SCons man pages"),
- ('standard-lib', None,
- "install SCons library in standard Python location"),
- ('standalone-lib', None,
- "install SCons library in separate standalone directory"),
- ('version-lib', None,
- "install SCons library in version-numbered directory"),
- ]
+ ('no-scons-script', None,
+ "don't install 'scons', only install 'scons-%s'" % Version),
+ ('no-version-script', None,
+ "don't install 'scons-%s', only install 'scons'" % Version),
+ ('install-bat', None,
+ "install 'scons.bat' script"),
+ ('no-install-bat', None,
+ "do not install 'scons.bat' script"),
+ ('install-man', None,
+ "install SCons man pages"),
+ ('no-install-man', None,
+ "do not install SCons man pages"),
+ ('standard-lib', None,
+ "install SCons library in standard Python location"),
+ ('standalone-lib', None,
+ "install SCons library in separate standalone directory"),
+ ('version-lib', None,
+ "install SCons library in version-numbered directory"),
+ ]
boolean_options = _install.boolean_options + [
- 'no-scons-script',
- 'no-version-script',
- 'install-bat',
- 'no-install-bat',
- 'install-man',
- 'no-install-man',
- 'standard-lib',
- 'standalone-lib',
- 'version-lib'
- ]
+ 'no-scons-script',
+ 'no-version-script',
+ 'install-bat',
+ 'no-install-bat',
+ 'install-man',
+ 'no-install-man',
+ 'standard-lib',
+ 'standalone-lib',
+ 'version-lib'
+ ]
if hasattr(os, 'link'):
user_options.append(
- ('hardlink-scons', None,
- "hard link 'scons' to the version-numbered script, don't make a separate 'scons' copy"),
- )
+ ('hardlink-scons', None,
+ "hard link 'scons' to the version-numbered script, don't make a separate 'scons' copy"),
+ )
boolean_options.append('hardlink-script')
if hasattr(os, 'symlink'):
user_options.append(
- ('symlink-scons', None,
- "make 'scons' a symbolic link to the version-numbered script, don't make a separate 'scons' copy"),
- )
+ ('symlink-scons', None,
+ "make 'scons' a symbolic link to the version-numbered script, don't make a separate 'scons' copy"),
+ )
boolean_options.append('symlink-script')
def initialize_options(self):
@@ -201,6 +205,7 @@ class install(_install):
Options.hardlink_scons = self.hardlink_scons
Options.symlink_scons = self.symlink_scons
+
def get_scons_prefix(libdir, is_win32):
"""
Return the right prefix for SCons library installation. Find
@@ -225,6 +230,7 @@ def get_scons_prefix(libdir, is_win32):
return os.path.join(drive + head)
return libdir
+
def force_to_usr_local(self):
"""
A hack to decide if we need to "force" the installation directories
@@ -236,6 +242,7 @@ def force_to_usr_local(self):
(self.install_dir[:9] == '/Library/' or
self.install_dir[:16] == '/System/Library/'))
+
class install_lib(_install_lib):
def finalize_options(self):
_install_lib.finalize_options(self)
@@ -258,6 +265,7 @@ class install_lib(_install_lib):
msg = "Installed SCons library modules into %s" % self.install_dir
Installed.append(msg)
+
class install_scripts(_install_scripts):
def finalize_options(self):
_install_scripts.finalize_options(self)
@@ -271,18 +279,24 @@ class install_scripts(_install_scripts):
pass
def hardlink_scons(self, src, dst, ver):
- try: os.unlink(dst)
- except OSError: pass
+ try:
+ os.unlink(dst)
+ except OSError:
+ pass
os.link(ver, dst)
def symlink_scons(self, src, dst, ver):
- try: os.unlink(dst)
- except OSError: pass
+ try:
+ os.unlink(dst)
+ except OSError:
+ pass
os.symlink(os.path.split(ver)[1], dst)
def copy_scons(self, src, dst, *args):
- try: os.unlink(dst)
- except OSError: pass
+ try:
+ os.unlink(dst)
+ except OSError:
+ pass
self.copy_file(src, dst)
self.outfiles.append(dst)
@@ -337,7 +351,7 @@ class install_scripts(_install_scripts):
self.copy_scons(src, scons_version_bat)
# --- distutils copy/paste ---
- if hasattr(os, 'chmod') and hasattr(os,'stat'):
+ if hasattr(os, 'chmod') and hasattr(os, 'stat'):
# Set the executable bits (owner, group, and world) on
# all the scripts we just installed.
for file in self.get_outputs():
@@ -347,20 +361,23 @@ class install_scripts(_install_scripts):
else:
# Use symbolic versions of permissions so this script doesn't fail to parse under python3.x
exec_and_read_permission = stat.S_IXOTH | stat.S_IXUSR | stat.S_IXGRP | stat.S_IROTH | stat.S_IRUSR | stat.S_IRGRP
- mode_mask = 4095 # Octal 07777 used because python3 has different octal syntax than python 2
+ mode_mask = 4095 # Octal 07777 used because python3 has different octal syntax than python 2
mode = ((os.stat(file)[stat.ST_MODE]) | exec_and_read_permission) & mode_mask
# log.info("changing mode of %s to %o", file, mode)
os.chmod(file, mode)
- # --- /distutils copy/paste ---
+ # --- /distutils copy/paste ---
+
class build_scripts(_build_scripts):
def finalize_options(self):
_build_scripts.finalize_options(self)
self.build_dir = os.path.join('build', 'scripts')
+
class install_data(_install_data):
def initialize_options(self):
_install_data.initialize_options(self)
+
def finalize_options(self):
_install_data.finalize_options(self)
if force_to_usr_local(self):
@@ -377,6 +394,7 @@ class install_data(_install_data):
else:
self.data_files = []
+
description = "Open Source next-generation build tool."
long_description = """Open Source next-generation build tool.
@@ -398,103 +416,103 @@ scripts = [
]
arguments = {
- 'name' : "scons",
- 'version' : Version,
- 'description' : description,
- 'long_description' : long_description,
- 'author' : 'Steven Knight',
- 'author_email' : 'knight@baldmt.com',
- 'url' : "http://www.scons.org/",
- 'packages' : ["SCons",
- "SCons.compat",
- "SCons.Node",
- "SCons.Options",
- "SCons.Platform",
- "SCons.Scanner",
- "SCons.Script",
- "SCons.Tool",
- "SCons.Tool.docbook",
- "SCons.Tool.MSCommon",
- "SCons.Tool.packaging",
- "SCons.Variables",
- ],
- 'package_dir' : {'' : 'engine',
- 'SCons.Tool.docbook' : 'engine/SCons/Tool/docbook'},
- 'package_data' : {'SCons.Tool.docbook' : ['docbook-xsl-1.76.1/*',
- 'docbook-xsl-1.76.1/common/*',
- 'docbook-xsl-1.76.1/docsrc/*',
- 'docbook-xsl-1.76.1/eclipse/*',
- 'docbook-xsl-1.76.1/epub/*',
- 'docbook-xsl-1.76.1/epub/bin/*',
- 'docbook-xsl-1.76.1/epub/bin/lib/*',
- 'docbook-xsl-1.76.1/epub/bin/xslt/*',
- 'docbook-xsl-1.76.1/extensions/*',
- 'docbook-xsl-1.76.1/fo/*',
- 'docbook-xsl-1.76.1/highlighting/*',
- 'docbook-xsl-1.76.1/html/*',
- 'docbook-xsl-1.76.1/htmlhelp/*',
- 'docbook-xsl-1.76.1/images/*',
- 'docbook-xsl-1.76.1/images/callouts/*',
- 'docbook-xsl-1.76.1/images/colorsvg/*',
- 'docbook-xsl-1.76.1/javahelp/*',
- 'docbook-xsl-1.76.1/lib/*',
- 'docbook-xsl-1.76.1/manpages/*',
- 'docbook-xsl-1.76.1/params/*',
- 'docbook-xsl-1.76.1/profiling/*',
- 'docbook-xsl-1.76.1/roundtrip/*',
- 'docbook-xsl-1.76.1/slides/browser/*',
- 'docbook-xsl-1.76.1/slides/fo/*',
- 'docbook-xsl-1.76.1/slides/graphics/*',
- 'docbook-xsl-1.76.1/slides/graphics/active/*',
- 'docbook-xsl-1.76.1/slides/graphics/inactive/*',
- 'docbook-xsl-1.76.1/slides/graphics/toc/*',
- 'docbook-xsl-1.76.1/slides/html/*',
- 'docbook-xsl-1.76.1/slides/htmlhelp/*',
- 'docbook-xsl-1.76.1/slides/keynote/*',
- 'docbook-xsl-1.76.1/slides/keynote/xsltsl/*',
- 'docbook-xsl-1.76.1/slides/svg/*',
- 'docbook-xsl-1.76.1/slides/xhtml/*',
- 'docbook-xsl-1.76.1/template/*',
- 'docbook-xsl-1.76.1/tests/*',
- 'docbook-xsl-1.76.1/tools/bin/*',
- 'docbook-xsl-1.76.1/tools/make/*',
- 'docbook-xsl-1.76.1/webhelp/*',
- 'docbook-xsl-1.76.1/webhelp/docs/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/css/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/images/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/theme-redmond/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/theme-redmond/images/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/*',
- 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/images/*',
- 'docbook-xsl-1.76.1/webhelp/docs/content/*',
- 'docbook-xsl-1.76.1/webhelp/docs/content/search/*',
- 'docbook-xsl-1.76.1/webhelp/docs/content/search/stemmers/*',
- 'docbook-xsl-1.76.1/webhelp/docsrc/*',
- 'docbook-xsl-1.76.1/webhelp/template/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/css/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/images/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/jquery/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/jquery/theme-redmond/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/jquery/theme-redmond/images/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/jquery/treeview/*',
- 'docbook-xsl-1.76.1/webhelp/template/common/jquery/treeview/images/*',
- 'docbook-xsl-1.76.1/webhelp/template/content/search/*',
- 'docbook-xsl-1.76.1/webhelp/template/content/search/stemmers/*',
- 'docbook-xsl-1.76.1/webhelp/xsl/*',
- 'docbook-xsl-1.76.1/website/*',
- 'docbook-xsl-1.76.1/xhtml/*',
- 'docbook-xsl-1.76.1/xhtml-1_1/*',
- 'utils/*']},
- 'data_files' : [('man/man1', man_pages)],
- 'scripts' : scripts,
- 'cmdclass' : {'install' : install,
- 'install_lib' : install_lib,
- 'install_data' : install_data,
- 'install_scripts' : install_scripts,
- 'build_scripts' : build_scripts}
+ 'name': "scons",
+ 'version': Version,
+ 'description': description,
+ 'long_description': long_description,
+ 'author': 'Steven Knight',
+ 'author_email': 'knight@baldmt.com',
+ 'url': "http://www.scons.org/",
+ 'packages': ["SCons",
+ "SCons.compat",
+ "SCons.Node",
+ "SCons.Options",
+ "SCons.Platform",
+ "SCons.Scanner",
+ "SCons.Script",
+ "SCons.Tool",
+ "SCons.Tool.docbook",
+ "SCons.Tool.MSCommon",
+ "SCons.Tool.packaging",
+ "SCons.Variables",
+ ],
+ 'package_dir': {'': 'engine',
+ 'SCons.Tool.docbook': 'engine/SCons/Tool/docbook'},
+ 'package_data': {'SCons.Tool.docbook': ['docbook-xsl-1.76.1/*',
+ 'docbook-xsl-1.76.1/common/*',
+ 'docbook-xsl-1.76.1/docsrc/*',
+ 'docbook-xsl-1.76.1/eclipse/*',
+ 'docbook-xsl-1.76.1/epub/*',
+ 'docbook-xsl-1.76.1/epub/bin/*',
+ 'docbook-xsl-1.76.1/epub/bin/lib/*',
+ 'docbook-xsl-1.76.1/epub/bin/xslt/*',
+ 'docbook-xsl-1.76.1/extensions/*',
+ 'docbook-xsl-1.76.1/fo/*',
+ 'docbook-xsl-1.76.1/highlighting/*',
+ 'docbook-xsl-1.76.1/html/*',
+ 'docbook-xsl-1.76.1/htmlhelp/*',
+ 'docbook-xsl-1.76.1/images/*',
+ 'docbook-xsl-1.76.1/images/callouts/*',
+ 'docbook-xsl-1.76.1/images/colorsvg/*',
+ 'docbook-xsl-1.76.1/javahelp/*',
+ 'docbook-xsl-1.76.1/lib/*',
+ 'docbook-xsl-1.76.1/manpages/*',
+ 'docbook-xsl-1.76.1/params/*',
+ 'docbook-xsl-1.76.1/profiling/*',
+ 'docbook-xsl-1.76.1/roundtrip/*',
+ 'docbook-xsl-1.76.1/slides/browser/*',
+ 'docbook-xsl-1.76.1/slides/fo/*',
+ 'docbook-xsl-1.76.1/slides/graphics/*',
+ 'docbook-xsl-1.76.1/slides/graphics/active/*',
+ 'docbook-xsl-1.76.1/slides/graphics/inactive/*',
+ 'docbook-xsl-1.76.1/slides/graphics/toc/*',
+ 'docbook-xsl-1.76.1/slides/html/*',
+ 'docbook-xsl-1.76.1/slides/htmlhelp/*',
+ 'docbook-xsl-1.76.1/slides/keynote/*',
+ 'docbook-xsl-1.76.1/slides/keynote/xsltsl/*',
+ 'docbook-xsl-1.76.1/slides/svg/*',
+ 'docbook-xsl-1.76.1/slides/xhtml/*',
+ 'docbook-xsl-1.76.1/template/*',
+ 'docbook-xsl-1.76.1/tests/*',
+ 'docbook-xsl-1.76.1/tools/bin/*',
+ 'docbook-xsl-1.76.1/tools/make/*',
+ 'docbook-xsl-1.76.1/webhelp/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/css/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/images/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/theme-redmond/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/theme-redmond/images/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/images/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/content/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/content/search/*',
+ 'docbook-xsl-1.76.1/webhelp/docs/content/search/stemmers/*',
+ 'docbook-xsl-1.76.1/webhelp/docsrc/*',
+ 'docbook-xsl-1.76.1/webhelp/template/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/css/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/images/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/jquery/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/jquery/theme-redmond/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/jquery/theme-redmond/images/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/jquery/treeview/*',
+ 'docbook-xsl-1.76.1/webhelp/template/common/jquery/treeview/images/*',
+ 'docbook-xsl-1.76.1/webhelp/template/content/search/*',
+ 'docbook-xsl-1.76.1/webhelp/template/content/search/stemmers/*',
+ 'docbook-xsl-1.76.1/webhelp/xsl/*',
+ 'docbook-xsl-1.76.1/website/*',
+ 'docbook-xsl-1.76.1/xhtml/*',
+ 'docbook-xsl-1.76.1/xhtml-1_1/*',
+ 'utils/*']},
+ 'data_files': [('man/man1', man_pages)],
+ 'scripts': scripts,
+ 'cmdclass': {'install': install,
+ 'install_lib': install_lib,
+ 'install_data': install_data,
+ 'install_scripts': install_scripts,
+ 'build_scripts': build_scripts}
}
distutils.core.setup(**arguments)
diff --git a/test/Clang/clang_default_environment.py b/test/Clang/clang_default_environment.py
new file mode 100644
index 0000000..4ac1c68
--- /dev/null
+++ b/test/Clang/clang_default_environment.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.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang', skipping test.\n")
+
+## This will likely NOT use clang
+
+test.write('SConstruct', """
+env = Environment()
+if env['CC'] != 'clang':
+ env['CC'] = 'clang'
+env.Program('foo.c')
+""")
+
+test.write('foo.c', """\
+#include <stdio.h>
+int main(int argc, char ** argv) {
+ 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/Clang/clang_shared_library.py b/test/Clang/clang_shared_library.py
new file mode 100644
index 0000000..5e4d36f
--- /dev/null
+++ b/test/Clang/clang_shared_library.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+from SCons.Environment import Base
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang', skipping test.\n")
+
+platform = Base()['PLATFORM']
+if platform == 'posix':
+ filename = 'foo.os'
+ libraryname = 'libfoo.so'
+elif platform == 'darwin':
+ filename = 'foo.os'
+ libraryname = 'libfoo.dylib'
+elif platform == 'win32':
+ filename = 'foo.obj'
+ libraryname = 'foo.dll'
+else:
+ test.fail_test()
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang', 'link'])
+env.SharedLibrary('foo', 'foo.c')
+""")
+
+test.write('foo.c', """\
+int bar() {
+ return 42;
+}
+""")
+
+test.run()
+
+test.must_exist(test.workpath(filename))
+test.must_exist(test.workpath(libraryname))
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Clang/clang_specific_environment.py b/test/Clang/clang_specific_environment.py
new file mode 100644
index 0000000..7266a9f
--- /dev/null
+++ b/test/Clang/clang_specific_environment.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang', skipping test.\n")
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang', 'link'])
+env.Program('foo.c')
+""")
+
+test.write('foo.c', """\
+#include <stdio.h>
+int main(int argc, char ** argv) {
+ 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/Clang/clang_static_library.py b/test/Clang/clang_static_library.py
new file mode 100644
index 0000000..39e9931
--- /dev/null
+++ b/test/Clang/clang_static_library.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang', skipping test.\n")
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang', 'ar'])
+env.StaticLibrary('foo', 'foo.c')
+""")
+
+test.write('foo.c', """\
+int bar() {
+ return 42;
+}
+""")
+
+test.run()
+
+test.must_exist(test.workpath('libfoo.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/Clang/clangxx_default_environment.py b/test/Clang/clangxx_default_environment.py
new file mode 100644
index 0000000..beef1e5
--- /dev/null
+++ b/test/Clang/clangxx_default_environment.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.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang++', skipping test.\n")
+
+## This will likely NOT use clang++.
+
+test.write('SConstruct', """\
+env = Environment()
+if env['CXX'] != 'clang++':
+ env['CXX'] = 'clang++'
+env.Program('foo.cpp')
+""")
+
+test.write('foo.cpp', """\
+#include <iostream>
+int main(int argc, char ** argv) {
+ std::cout << "Hello!" << std::endl;
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!\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/Clang/clangxx_shared_library.py b/test/Clang/clangxx_shared_library.py
new file mode 100644
index 0000000..d6337ba
--- /dev/null
+++ b/test/Clang/clangxx_shared_library.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+from SCons.Environment import Base
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang++', skipping test.\n")
+
+platform = Base()['PLATFORM']
+if platform == 'posix':
+ filename = 'foo.os'
+ libraryname = 'libfoo.so'
+elif platform == 'darwin':
+ filename = 'foo.os'
+ libraryname = 'libfoo.dylib'
+elif platform == 'win32':
+ filename = 'foo.obj'
+ libraryname = 'foo.dll'
+else:
+ test.fail_test()
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang++', 'link'])
+env.SharedLibrary('foo', 'foo.cpp')
+""")
+
+test.write('foo.cpp', """\
+int bar() {
+ return 42;
+}
+""")
+
+test.run()
+
+test.must_exist(test.workpath(filename))
+test.must_exist(test.workpath(libraryname))
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Clang/clangxx_specific_environment.py b/test/Clang/clangxx_specific_environment.py
new file mode 100644
index 0000000..773fa94
--- /dev/null
+++ b/test/Clang/clangxx_specific_environment.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang++', skipping test.\n")
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang++', 'link'])
+env.Program('foo.cpp')
+""")
+
+test.write('foo.cpp', """\
+#include <iostream>
+int main(int argc, char ** argv) {
+ std::cout << "Hello!" << std::endl;
+ return 0;
+}
+""")
+
+test.run()
+
+test.run(program=test.workpath('foo'+_exe))
+
+test.fail_test(not test.stdout() == 'Hello!\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/Clang/clangxx_static_library.py b/test/Clang/clangxx_static_library.py
new file mode 100644
index 0000000..77ea58e
--- /dev/null
+++ b/test/Clang/clangxx_static_library.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_exe = TestSCons._exe
+test = TestSCons.TestSCons()
+
+if not test.where_is('clang'):
+ test.skip_test("Could not find 'clang++', skipping test.\n")
+
+test.write('SConstruct', """\
+env = Environment(tools=['clang++', 'ar'])
+env.StaticLibrary('foo', 'foo.cpp')
+""")
+
+test.write('foo.cpp', """\
+int bar() {
+ return 42;
+}
+""")
+
+test.run()
+
+test.must_exist(test.workpath('libfoo.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/Issues/2940_Ariovistus/Common/correctLinkOptions.py b/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py
index 8060add..5acd26a 100644
--- a/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py
+++ b/test/D/Issues/2940_Ariovistus/Common/correctLinkOptions.py
@@ -50,11 +50,10 @@ def testForTool(tool):
libraryname = 'libstuff.so'
filename = 'stuff.os'
elif platform == 'darwin':
+ if tool == 'dmd' or tool == 'gdc':
+ test.skip_test('Dynamic libraries not yet supported by dmd and gdc on OSX.\n')
libraryname = 'libstuff.dylib'
filename = 'stuff.os'
- # As at 2014-09-14, DMD 2.066, LDC master head, and GDC 4.9.1 do not support
- # shared libraries on OSX.
- test.skip_test('Dynamic libraries not yet supported on OSX.\n')
elif platform == 'win32':
libraryname = 'stuff.dll'
filename = 'stuff.obj'
diff --git a/test/D/SharedObjects/Common/common.py b/test/D/SharedObjects/Common/common.py
index 0322385..a46ea7e 100644
--- a/test/D/SharedObjects/Common/common.py
+++ b/test/D/SharedObjects/Common/common.py
@@ -63,9 +63,6 @@ def testForTool(tool):
elif platform == 'darwin':
filename = 'code.o'
libraryname = 'libanswer.dylib'
- # As at 2014-09-14, DMD 2.066, LDC master head, and GDC 4.9.1 do not support
- # shared libraries on OSX.
- test.skip_test('Dynamic libraries not yet supported on OSX.\n')
elif platform == 'win32':
filename = 'code.obj'
libraryname = 'answer.dll'
@@ -75,7 +72,7 @@ def testForTool(tool):
test.dir_fixture('Image')
test.write('SConstruct', open('SConstruct_template', 'r').read().format(tool))
- if tool == 'dmd':
+ if Base()['DC'] == 'gdmd':
# 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)
diff --git a/test/D/SharedObjects/Image/SConstruct_template b/test/D/SharedObjects/Image/SConstruct_template
index cae8713..d263e63 100644
--- a/test/D/SharedObjects/Image/SConstruct_template
+++ b/test/D/SharedObjects/Image/SConstruct_template
@@ -1,10 +1,7 @@
# -*- mode:python; coding:utf-8; -*-
-import os
-
environment = Environment(
- tools=['{}', 'link'])
-
-environment['ENV']['HOME'] = os.environ['HOME'] # Hack for gdmd
+ tools=['{0}', 'link']
+)
environment.SharedLibrary('answer', 'code.d')
diff --git a/test/Dir/PyPackageDir/PyPackageDir.py b/test/Dir/PyPackageDir/PyPackageDir.py
new file mode 100644
index 0000000..b215c7b
--- /dev/null
+++ b/test/Dir/PyPackageDir/PyPackageDir.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.dir_fixture('image')
+
+test.run(arguments = '.', stdout = """\
+scons: Reading SConscript files ...
+Test identification of directory for a given python package
+testmod1
+.
+submod1
+submod1/submod2
+Test parameter substitution
+submod1/submod2
+submod1/submod2
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: `.' is up to date.
+scons: done building targets.
+""")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Dir/PyPackageDir/image/SConstruct b/test/Dir/PyPackageDir/image/SConstruct
new file mode 100644
index 0000000..90d2a80
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/SConstruct
@@ -0,0 +1,29 @@
+import sys, os
+
+oldsyspath = sys.path
+dir_path = Dir('.').srcnode().abspath
+dir_path = os.path.join(dir_path, 'syspath')
+sys.path.append(dir_path)
+
+def TestPyPackageDir(env, modname):
+ packagepath = env.PyPackageDir(modname).abspath
+ # Convert from an absolute path back to a relative one for testing
+ commonprefix = os.path.commonprefix([dir_path, packagepath])
+ relpath = os.path.relpath(packagepath, commonprefix)
+ relpath = relpath.replace(os.sep, '/')
+ print(relpath)
+
+print("Test identification of directory for a given python package")
+env = Environment()
+TestPyPackageDir(env, 'testmod1')
+TestPyPackageDir(env, 'testmod2')
+TestPyPackageDir(env, 'submod1.testmod3')
+TestPyPackageDir(env, 'submod1.submod2.testmod4')
+
+print("Test parameter substitution")
+env = Environment(FOO = 'submod1.submod2.testmod4')
+TestPyPackageDir(env, '${FOO}')
+env = Environment(FOO = 'submod1.submod2', BAR = 'testmod4')
+TestPyPackageDir(env, '${FOO}.${BAR}')
+
+sys.path = oldsyspath
diff --git a/test/Dir/PyPackageDir/image/sconstest.skip b/test/Dir/PyPackageDir/image/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/sconstest.skip
diff --git a/test/Dir/PyPackageDir/image/syspath/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/sconstest.skip
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/__init__.py b/test/Dir/PyPackageDir/image/syspath/submod1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/__init__.py
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/sconstest.skip
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/__init__.py
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/sconstest.skip
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/submod2/testmod4.py
diff --git a/test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py b/test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/submod1/testmod3.py
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py b/test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/testmod1/__init__.py
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip b/test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/testmod1/sconstest.skip
diff --git a/test/Dir/PyPackageDir/image/syspath/testmod2.py b/test/Dir/PyPackageDir/image/syspath/testmod2.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Dir/PyPackageDir/image/syspath/testmod2.py
diff --git a/test/MSVC/MSVC_UWP_APP.py b/test/MSVC/MSVC_UWP_APP.py
new file mode 100644
index 0000000..c72c739
--- /dev/null
+++ b/test/MSVC/MSVC_UWP_APP.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test the ability to configure the $MSVC_UWP_APP construction variable with
+the desired effect.
+"""
+
+import TestSCons
+import SCons.Tool.MSCommon.vc as msvc
+
+def AreVCStoreLibPathsInLIBPATH(output):
+ libpath = None
+ msvc_version = None
+ lines = output.splitlines()
+ for line in lines:
+ if 'env[ENV][LIBPATH]=' in line:
+ libpath = line.split('=')[1]
+ elif 'env[MSVC_VERSION]=' in line:
+ msvc_version = line.split('=')[1]
+
+ if not libpath or not msvc_version:
+ # Couldn't find the libpath or msvc version in the output
+ return (False, False, None)
+
+ libpaths = libpath.lower().split(';')
+ (vclibstore_path_present, vclibstorerefs_path_present) = (False, False)
+ for path in libpaths:
+ # Look for the Store VC Lib paths in the LIBPATH:
+ # [VS install path]\VC\LIB\store[\arch] and
+ # [VS install path]\VC\LIB\store\references
+ # For example,
+ # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\amd64
+ # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\references
+ if r'vc\lib\store\references' in path:
+ vclibstorerefs_path_present = True
+ elif r'vc\lib\store' in path:
+ vclibstore_path_present = True
+
+ return (vclibstore_path_present, vclibstorerefs_path_present, msvc_version)
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+test.skip_if_not_msvc()
+
+test.write('SConstruct', """
+if ARGUMENTS.get('MSVC_UWP_APP'):
+ help_vars = Variables()
+ help_vars.Add(EnumVariable(
+ 'MSVC_UWP_APP',
+ 'Build for a Universal Windows Platform (UWP) Application',
+ '0',
+ allowed_values=('0', '1')))
+else:
+ help_vars = None
+env = Environment(tools=['default', 'msvc'], variables=help_vars)
+# Print the ENV LIBPATH to stdout
+print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH'))
+print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION'))
+""")
+
+installed_msvc_versions = msvc.cached_get_installed_vcs()
+# MSVC guaranteed to be at least one version on the system or else skip_if_not_msvc() function
+# would have skipped the test
+greatest_msvc_version_on_system = installed_msvc_versions[0]
+maj, min = msvc.msvc_version_to_maj_min(greatest_msvc_version_on_system)
+
+# We always use the greatest MSVC version installed on the system
+
+if maj < 14:
+ # Skip the test if MSVC version is less than VS2015
+ test.skip_test("Available MSVC doesn't support App store ")
+
+# Test setting MSVC_UWP_APP is '1' (True)
+test.run(arguments = "MSVC_UWP_APP=1")
+(vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
+test.fail_test(msvc_version != greatest_msvc_version_on_system,
+ message='MSVC_VERSION (%s) does not match expected greatest version on system (%s)' \
+ % (msvc_version, greatest_msvc_version_on_system))
+test.fail_test((vclibstore_path_present is False) or (vclibstorerefs_path_present is False),
+ message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version)
+
+# Test setting MSVC_UWP_APP is '0' (False)
+test.run(arguments = "MSVC_UWP_APP=0")
+(vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
+test.fail_test(msvc_version != greatest_msvc_version_on_system,
+ message='MSVC_VERSION (%s) does not match expected greatest version on system (%s)' \
+ % (msvc_version, greatest_msvc_version_on_system))
+test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
+ message='VC Store LIBPATHs present when MSVC_UWP_APP=0 (msvc_version=%s)' % msvc_version)
+
+# Test not setting MSVC_UWP_APP
+test.run(arguments = "")
+(vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
+test.fail_test(msvc_version != greatest_msvc_version_on_system,
+ message='MSVC_VERSION (%s) does not match expected greatest version on system (%s)' \
+ % (msvc_version, greatest_msvc_version_on_system))
+test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
+ message='VC Store LIBPATHs present when MSVC_UWP_APP not set (msvc_version=%s)' % msvc_version)
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool1.py b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool1.py
new file mode 100644
index 0000000..072daf0
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/__init__.py b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/__init__.py
new file mode 100644
index 0000000..f4ccefe
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/Toolpath_TestTool2/sconstest.skip
diff --git a/test/toolpath/nested/image/Libs/tools_example/__init__.py b/test/toolpath/nested/image/Libs/tools_example/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/__init__.py
diff --git a/test/toolpath/nested/image/Libs/tools_example/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/sconstest.skip
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_1.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_1.py
new file mode 100644
index 0000000..2a70e67
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/__init__.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/__init__.py
new file mode 100644
index 0000000..424991f
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1_2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/Toolpath_TestTool1_2/sconstest.skip
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/__init__.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/__init__.py
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/subdir1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/sconstest.skip
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_1.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_1.py
new file mode 100644
index 0000000..13d0496
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py
new file mode 100644
index 0000000..3f8fd5e
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2_2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/__init__.py b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/__init__.py
diff --git a/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/sconstest.skip b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/Libs/tools_example/subdir1/subdir2/sconstest.skip
diff --git a/test/toolpath/nested/image/SConstruct b/test/toolpath/nested/image/SConstruct
new file mode 100644
index 0000000..a7c6ceb
--- /dev/null
+++ b/test/toolpath/nested/image/SConstruct
@@ -0,0 +1,69 @@
+import sys, os
+
+toollist = ['Toolpath_TestTool1',
+ 'Toolpath_TestTool2',
+ 'subdir1.Toolpath_TestTool1_1',
+ 'subdir1.Toolpath_TestTool1_2',
+ 'subdir1.subdir2.Toolpath_TestTool2_1',
+ 'subdir1.subdir2.Toolpath_TestTool2_2',
+ ]
+
+print('Test where tools are located under site_scons/site_tools')
+env1 = Environment(tools=toollist)
+print("env1['Toolpath_TestTool1'] =", env1.get('Toolpath_TestTool1'))
+print("env1['Toolpath_TestTool2'] =", env1.get('Toolpath_TestTool2'))
+print("env1['Toolpath_TestTool1_1'] =", env1.get('Toolpath_TestTool1_1'))
+print("env1['Toolpath_TestTool1_2'] =", env1.get('Toolpath_TestTool1_2'))
+print("env1['Toolpath_TestTool2_1'] =", env1.get('Toolpath_TestTool2_1'))
+print("env1['Toolpath_TestTool2_2'] =", env1.get('Toolpath_TestTool2_2'))
+
+print('Test where toolpath is set in the env constructor')
+env2 = Environment(tools=toollist, toolpath=['Libs/tools_example'])
+print("env2['Toolpath_TestTool1'] =", env2.get('Toolpath_TestTool1'))
+print("env2['Toolpath_TestTool2'] =", env2.get('Toolpath_TestTool2'))
+print("env2['Toolpath_TestTool1_1'] =", env2.get('Toolpath_TestTool1_1'))
+print("env2['Toolpath_TestTool1_2'] =", env2.get('Toolpath_TestTool1_2'))
+print("env2['Toolpath_TestTool2_1'] =", env2.get('Toolpath_TestTool2_1'))
+print("env2['Toolpath_TestTool2_2'] =", env2.get('Toolpath_TestTool2_2'))
+
+print('Test a Clone')
+base = Environment(tools=[], toolpath=['Libs/tools_example'])
+derived = base.Clone(tools=['subdir1.Toolpath_TestTool1_1'])
+print("derived['Toolpath_TestTool1_1'] =", derived.get('Toolpath_TestTool1_1'))
+
+
+print('Test using syspath as the toolpath')
+print('Lets pretend that tools_example within Libs is actually a module installed via pip')
+oldsyspath = sys.path
+dir_path = Dir('.').srcnode().abspath
+dir_path = os.path.join(dir_path, 'Libs')
+sys.path.append(dir_path)
+
+searchpaths = []
+for item in sys.path:
+ if os.path.isdir(item): searchpaths.append(item)
+
+toollist = ['tools_example.Toolpath_TestTool1',
+ 'tools_example.Toolpath_TestTool2',
+ 'tools_example.subdir1.Toolpath_TestTool1_1',
+ 'tools_example.subdir1.Toolpath_TestTool1_2',
+ 'tools_example.subdir1.subdir2.Toolpath_TestTool2_1',
+ 'tools_example.subdir1.subdir2.Toolpath_TestTool2_2',
+ ]
+
+env3 = Environment(tools=toollist, toolpath=searchpaths)
+print("env3['Toolpath_TestTool1'] =", env3.get('Toolpath_TestTool1'))
+print("env3['Toolpath_TestTool2'] =", env3.get('Toolpath_TestTool2'))
+print("env3['Toolpath_TestTool1_1'] =", env3.get('Toolpath_TestTool1_1'))
+print("env3['Toolpath_TestTool1_2'] =", env3.get('Toolpath_TestTool1_2'))
+print("env3['Toolpath_TestTool2_1'] =", env3.get('Toolpath_TestTool2_1'))
+print("env3['Toolpath_TestTool2_2'] =", env3.get('Toolpath_TestTool2_2'))
+
+
+print('Test using PyPackageDir')
+toollist = ['Toolpath_TestTool2_1', 'Toolpath_TestTool2_2']
+env4 = Environment(tools = toollist, toolpath = [PyPackageDir('tools_example.subdir1.subdir2')])
+print("env4['Toolpath_TestTool2_1'] =", env4.get('Toolpath_TestTool2_1'))
+print("env4['Toolpath_TestTool2_2'] =", env4.get('Toolpath_TestTool2_2'))
+
+sys.path = oldsyspath
diff --git a/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool1.py b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool1.py
new file mode 100644
index 0000000..072daf0
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/__init__.py
new file mode 100644
index 0000000..f4ccefe
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/Toolpath_TestTool2/sconstest.skip
diff --git a/test/toolpath/nested/image/site_scons/site_tools/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/__init__.py
diff --git a/test/toolpath/nested/image/site_scons/site_tools/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/sconstest.skip
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_1.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_1.py
new file mode 100644
index 0000000..2a70e67
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/__init__.py
new file mode 100644
index 0000000..424991f
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool1_2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/Toolpath_TestTool1_2/sconstest.skip
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/__init__.py
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/subdir1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/sconstest.skip
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_1.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_1.py
new file mode 100644
index 0000000..13d0496
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py
new file mode 100644
index 0000000..3f8fd5e
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['Toolpath_TestTool2_2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/Toolpath_TestTool2_2/sconstest.skip
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/__init__.py b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/__init__.py
diff --git a/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/sconstest.skip b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/nested/image/site_scons/site_tools/subdir1/subdir2/sconstest.skip
diff --git a/test/toolpath/nested/nested.py b/test/toolpath/nested/nested.py
new file mode 100644
index 0000000..df2ba07
--- /dev/null
+++ b/test/toolpath/nested/nested.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.dir_fixture('image')
+
+test.run(arguments = '.', stdout = """\
+scons: Reading SConscript files ...
+Test where tools are located under site_scons/site_tools
+env1['Toolpath_TestTool1'] = 1
+env1['Toolpath_TestTool2'] = 1
+env1['Toolpath_TestTool1_1'] = 1
+env1['Toolpath_TestTool1_2'] = 1
+env1['Toolpath_TestTool2_1'] = 1
+env1['Toolpath_TestTool2_2'] = 1
+Test where toolpath is set in the env constructor
+env2['Toolpath_TestTool1'] = 1
+env2['Toolpath_TestTool2'] = 1
+env2['Toolpath_TestTool1_1'] = 1
+env2['Toolpath_TestTool1_2'] = 1
+env2['Toolpath_TestTool2_1'] = 1
+env2['Toolpath_TestTool2_2'] = 1
+Test a Clone
+derived['Toolpath_TestTool1_1'] = 1
+Test using syspath as the toolpath
+Lets pretend that tools_example within Libs is actually a module installed via pip
+env3['Toolpath_TestTool1'] = 1
+env3['Toolpath_TestTool2'] = 1
+env3['Toolpath_TestTool1_1'] = 1
+env3['Toolpath_TestTool1_2'] = 1
+env3['Toolpath_TestTool2_1'] = 1
+env3['Toolpath_TestTool2_2'] = 1
+Test using PyPackageDir
+env4['Toolpath_TestTool2_1'] = 1
+env4['Toolpath_TestTool2_2'] = 1
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: `.' is up to date.
+scons: done building targets.
+""")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/toolpath/relative_import/image/SConstruct b/test/toolpath/relative_import/image/SConstruct
new file mode 100644
index 0000000..6156929
--- /dev/null
+++ b/test/toolpath/relative_import/image/SConstruct
@@ -0,0 +1,10 @@
+env = Environment(tools=['TestTool1', 'TestTool1.TestTool1_2'], toolpath=['tools'])
+
+# Test a relative import within the root of the tools directory
+print("env['TestTool1'] =", env.get('TestTool1'))
+print("env['TestTool1_1'] =", env.get('TestTool1_1'))
+
+# Test a relative import within a sub dir
+print("env['TestTool1_2'] =", env.get('TestTool1_2'))
+print("env['TestTool1_2_1'] =", env.get('TestTool1_2_1'))
+print("env['TestTool1_2_2'] =", env.get('TestTool1_2_2'))
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_1.py b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_1.py
new file mode 100644
index 0000000..4c9a7bc
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['TestTool1_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_1.py b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_1.py
new file mode 100644
index 0000000..e65f8cd
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_1.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['TestTool1_2_1'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/__init__.py b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/__init__.py
new file mode 100644
index 0000000..463baee
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/__init__.py
@@ -0,0 +1,4 @@
+def generate(env):
+ env['TestTool1_2_2'] = 1
+def exists(env):
+ return 1
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/sconstest.skip b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/TestTool1_2_2/sconstest.skip
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/__init__.py b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/__init__.py
new file mode 100644
index 0000000..8bd698f
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/__init__.py
@@ -0,0 +1,11 @@
+from . import TestTool1_2_1
+from . import TestTool1_2_2
+
+def generate(env):
+ env['TestTool1_2'] = 1
+ TestTool1_2_1.generate(env)
+ TestTool1_2_2.generate(env)
+def exists(env):
+ TestTool1_2_1.exists(env)
+ TestTool1_2_2.exists(env)
+ return 1
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/sconstest.skip b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/TestTool1_2/sconstest.skip
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/__init__.py b/test/toolpath/relative_import/image/tools/TestTool1/__init__.py
new file mode 100644
index 0000000..d5510d2
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/__init__.py
@@ -0,0 +1,9 @@
+from . import TestTool1_1
+
+def generate(env):
+ env['TestTool1'] = 1
+ # Include another tool within the same directory
+ TestTool1_1.generate(env)
+def exists(env):
+ TestTool1_1.exists(env)
+ return 1
diff --git a/test/toolpath/relative_import/image/tools/TestTool1/sconstest.skip b/test/toolpath/relative_import/image/tools/TestTool1/sconstest.skip
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/toolpath/relative_import/image/tools/TestTool1/sconstest.skip
diff --git a/test/toolpath/relative_import/relative_import.py b/test/toolpath/relative_import/relative_import.py
new file mode 100644
index 0000000..8fa2f62
--- /dev/null
+++ b/test/toolpath/relative_import/relative_import.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.dir_fixture('image')
+
+test.run(arguments = '.', stdout = """\
+scons: Reading SConscript files ...
+env['TestTool1'] = 1
+env['TestTool1_1'] = 1
+env['TestTool1_2'] = 1
+env['TestTool1_2_1'] = 1
+env['TestTool1_2_2'] = 1
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: `.' is up to date.
+scons: done building targets.
+""")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: