summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W <garlicbready@googlemail.com>2017-08-14 10:20:43 (GMT)
committerRichard W <garlicbready@googlemail.com>2017-08-14 10:20:43 (GMT)
commit8bfb071d974edae91cde09bd64f4a2b9673e1364 (patch)
tree16fccf1096e559ed4c3f01dd2840766c64636c5a
parenta3acca060be98abf584ad0a5033bde05ecebd412 (diff)
parent90f842616029050abffdabec078fe9a1f1b1d1a9 (diff)
downloadSCons-8bfb071d974edae91cde09bd64f4a2b9673e1364.zip
SCons-8bfb071d974edae91cde09bd64f4a2b9673e1364.tar.gz
SCons-8bfb071d974edae91cde09bd64f4a2b9673e1364.tar.bz2
Merged scons/scons into default
-rw-r--r--SConstruct110
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--src/CHANGES.txt78
-rw-r--r--src/engine/SCons/ActionTests.py6
-rw-r--r--src/engine/SCons/Environment.py4
-rw-r--r--src/engine/SCons/EnvironmentValues.py97
-rw-r--r--src/engine/SCons/EnvironmentValuesTest.py16
-rw-r--r--src/engine/SCons/Subst.py29
-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.py62
-rw-r--r--src/engine/SCons/Tool/MSCommon/vs.py11
-rw-r--r--src/engine/SCons/Tool/__init__.py8
-rw-r--r--src/engine/SCons/Tool/gxx.py4
15 files changed, 340 insertions, 125 deletions
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/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/src/CHANGES.txt b/src/CHANGES.txt
index a82a978..dd92ce1 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -11,17 +11,6 @@ NOTE: This is a major release. You should expect that some targets may rebuild
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 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 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 William Blevins:
- Updated D language scanner support to latest: 2.071.1. (PR #1924)
https://dlang.org/spec/module.html accessed 11 August 2016
@@ -46,6 +35,10 @@ may cause rebuilds. In no case should rebuilds not happen.
- 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
metaclass on PyPy); wrap most-used open() calls in 'with' statements to
@@ -62,6 +55,7 @@ may cause rebuilds. In no case should rebuilds not happen.
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
@@ -70,6 +64,13 @@ may cause rebuilds. In no case should rebuilds not happen.
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).
@@ -88,6 +89,14 @@ may cause rebuilds. In no case should rebuilds not happen.
- 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)
@@ -97,6 +106,9 @@ may cause rebuilds. In no case should rebuilds not happen.
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
@@ -333,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
@@ -376,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/ActionTests.py b/src/engine/SCons/ActionTests.py
index 9d856c9..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
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 480a1d6..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)
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/Subst.py b/src/engine/SCons/Subst.py
index 9aa4bbc..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.
@@ -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 4126314..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' : [
@@ -222,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.
@@ -240,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:
@@ -281,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)
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 1ab43e7..6408f8b 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -1172,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/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':