From 8fca5898da15fe1b3f4f87fc35bed34c236e74cb Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 11 Apr 2022 09:29:41 -0400
Subject: Suppress warning for missing MSVC compiler for initial call to
msvc_setup_env with undefined MSVC_VERSION (default tools).
---
SCons/Tool/MSCommon/vc.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index fe31cb3..3373301 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -714,7 +714,9 @@ def get_installed_vcs(env=None):
def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
global __INSTALLED_VCS_RUN
+ global __MSVC_SETUP_ENV_DEFAULT
__INSTALLED_VCS_RUN = None
+ __MSVC_SETUP_ENV_DEFAULT = None
# Running these batch files isn't cheap: most of the time spent in
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
@@ -920,14 +922,18 @@ def msvc_find_valid_batch_script(env, version):
return d
+__MSVC_SETUP_ENV_DEFAULT = None
def msvc_setup_env(env):
+ global __MSVC_SETUP_ENV_DEFAULT
debug('called')
version = get_default_version(env)
if version is None:
- warn_msg = "No version of Visual Studio compiler found - C/C++ " \
- "compilers most likely not set correctly"
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ if __MSVC_SETUP_ENV_DEFAULT:
+ warn_msg = "No version of Visual Studio compiler found - C/C++ " \
+ "compilers most likely not set correctly"
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ __MSVC_SETUP_ENV_DEFAULT = True
return None
# XXX: we set-up both MSVS version for backward
--
cgit v0.12
From f338fee76045f94e78f25f15fea1d4bf33786d6e Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 12 Apr 2022 10:20:49 -0400
Subject: Raise MSVCVersionNotFound exception instead of returning an
empty/undefined dictionary when attempting to find a valid msvc batch script.
Raise an MSVCVersionNotFound exception when the default msvc version is
requested and there are no msvc versions installed. Suppress raising an
MSVCVersionNotFound exception during default msvc tool initialization. Add
additional tests.
---
SCons/Tool/MSCommon/vc.py | 36 ++++++++++---
test/MSVC/msvc_badversion.py | 59 ++++++++++++++++++++++
test/MSVC/no_msvc.py | 26 ++++++++--
test/fixture/no_msvc/no_msvcs_sconstruct.py | 1 -
test/fixture/no_msvc/no_msvcs_sconstruct_tools.py | 14 +++++
.../fixture/no_msvc/no_msvcs_sconstruct_version.py | 14 +++++
6 files changed, 138 insertions(+), 12 deletions(-)
create mode 100644 test/MSVC/msvc_badversion.py
create mode 100644 test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
create mode 100644 test/fixture/no_msvc/no_msvcs_sconstruct_version.py
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 3373301..d9a6e50 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -79,6 +79,9 @@ class BatchFileExecutionError(VisualCException):
class MSVCScriptNotFound(VisualCException):
pass
+class MSVCVersionNotFound(VisualCException):
+ pass
+
# Dict to 'canonalize' the arch
_ARCH_TO_CANONICAL = {
"amd64" : "amd64",
@@ -853,6 +856,7 @@ def msvc_find_valid_batch_script(env, version):
debug("host_platform: %s, try_target_archs: %s", host_platform, try_target_archs)
d = None
+ version_installed = False
for tp in try_target_archs:
# Set to current arch.
env['TARGET_ARCH'] = tp
@@ -869,14 +873,11 @@ def msvc_find_valid_batch_script(env, version):
try:
(vc_script, use_arg, sdk_script) = find_batch_file(env, version, host_platform, tp)
debug('vc_script:%s sdk_script:%s', vc_script, sdk_script)
+ version_installed = True
except VisualCException as e:
msg = str(e)
debug('Caught exception while looking for batch file (%s)', msg)
- warn_msg = "VC version %s not installed. " + \
- "C/C++ compilers are most likely not set correctly.\n" + \
- " Installed versions are: %s"
- warn_msg = warn_msg % (version, get_installed_vcs(env))
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ version_installed = False
continue
# Try to use the located batch file for this host/target platform combo
@@ -919,6 +920,25 @@ def msvc_find_valid_batch_script(env, version):
# To it's initial value
if not d:
env['TARGET_ARCH']=req_target_platform
+ installed_vcs = get_installed_vcs(env)
+ if version_installed:
+ err_msg = "MSVC version {} working host/target script was not found.\n" \
+ " Host = {}, Target = {}\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(
+ version, host_platform, target_platform
+ )
+ elif version and installed_vcs:
+ err_msg = "MSVC version {} was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(version, installed_vcs)
+ elif version:
+ err_msg = "MSVC version {} was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(version)
+ else:
+ err_msg = "No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly"
+ raise MSVCVersionNotFound(err_msg)
return d
@@ -930,9 +950,9 @@ def msvc_setup_env(env):
version = get_default_version(env)
if version is None:
if __MSVC_SETUP_ENV_DEFAULT:
- warn_msg = "No version of Visual Studio compiler found - C/C++ " \
- "compilers most likely not set correctly"
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ err_msg = "No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly"
+ raise MSVCVersionNotFound(err_msg)
__MSVC_SETUP_ENV_DEFAULT = True
return None
diff --git a/test/MSVC/msvc_badversion.py b/test/MSVC/msvc_badversion.py
new file mode 100644
index 0000000..7af8ca5
--- /dev/null
+++ b/test/MSVC/msvc_badversion.py
@@ -0,0 +1,59 @@
+#!/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 scons with an invalid MSVC version when at least one MSVC is present.
+"""
+
+import sys
+
+import TestSCons
+import SCons.Tool.MSCommon.vc as msvc
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+ test.skip_test("Not win32 platform. Skipping test\n")
+
+test.skip_if_not_msvc()
+
+installed_msvc_versions = msvc.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
+
+test.write('SConstruct', """\
+env = Environment(MSVC_VERSION='12.9')
+""")
+
+test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/MSVC/no_msvc.py b/test/MSVC/no_msvc.py
index d1161c6..b6442e8 100644
--- a/test/MSVC/no_msvc.py
+++ b/test/MSVC/no_msvc.py
@@ -43,9 +43,29 @@ test.run(arguments='-Q -s', stdout='')
# test no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct.py', 'SConstruct')
+test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
+
+# test msvc version number request with no msvc's
+test.file_fixture('no_msvc/no_msvcs_sconstruct_version.py', 'SConstruct')
+test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
+
+# test that MSVCVersionNotFound is not raised for default msvc tools
+# when a non-msvc tool list is used
+test.subdir('site_scons', ['site_scons', 'site_tools'])
+
+test.write(['site_scons', 'site_tools', 'myignoredefaultmsvctool.py'], """
+import SCons.Tool
+def generate(env):
+ env['MYIGNOREDEFAULTMSVCTOOL']='myignoredefaultmsvctool'
+def exists(env):
+ return 1
+""")
+
+test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct')
+test.run(arguments='-Q -s')
+
+test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct')
test.run(arguments='-Q -s')
-if 'MSVC_VERSION=None' not in test.stdout():
- test.fail_test()
+test.pass_test()
-test.pass_test()
\ No newline at end of file
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct.py b/test/fixture/no_msvc/no_msvcs_sconstruct.py
index 18366d8..590142b 100644
--- a/test/fixture/no_msvc/no_msvcs_sconstruct.py
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct.py
@@ -12,4 +12,3 @@ SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
env = SCons.Environment.Environment()
-print('MSVC_VERSION='+str(env.get('MSVC_VERSION')))
\ No newline at end of file
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py b/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
new file mode 100644
index 0000000..ca9b699
--- /dev/null
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
@@ -0,0 +1,14 @@
+import SCons
+import SCons.Tool.MSCommon
+
+def DummyVsWhere(msvc_version, env):
+ # not testing versions with vswhere, so return none
+ return None
+
+for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR:
+ SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')]
+
+SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
+
+env = SCons.Environment.Environment(tools=['MYIGNOREDEFAULTMSVCTOOL'])
+
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct_version.py b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
new file mode 100644
index 0000000..81d47cf
--- /dev/null
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
@@ -0,0 +1,14 @@
+import SCons
+import SCons.Tool.MSCommon
+
+def DummyVsWhere(msvc_version, env):
+ # not testing versions with vswhere, so return none
+ return None
+
+for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR:
+ SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR[key]=[(SCons.Util.HKEY_LOCAL_MACHINE, r'')]
+
+SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
+
+env = SCons.Environment.Environment(MSVC_VERSION='14.3')
+
--
cgit v0.12
From b19e130873dbf44d4e3edb0d0cc47df12f99b865 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 24 Apr 2022 06:12:26 -0400
Subject: Rework exception message construction when a specified msvc version
is not found. Remove exception for default msvc version and adjust test
accordingly.
---
SCons/Tool/MSCommon/vc.py | 43 ++++++++++++++++++++++---------------------
test/MSVC/no_msvc.py | 2 +-
2 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index d9a6e50..cac1744 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -717,9 +717,7 @@ def get_installed_vcs(env=None):
def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
global __INSTALLED_VCS_RUN
- global __MSVC_SETUP_ENV_DEFAULT
__INSTALLED_VCS_RUN = None
- __MSVC_SETUP_ENV_DEFAULT = None
# Running these batch files isn't cheap: most of the time spent in
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
@@ -920,40 +918,43 @@ def msvc_find_valid_batch_script(env, version):
# To it's initial value
if not d:
env['TARGET_ARCH']=req_target_platform
- installed_vcs = get_installed_vcs(env)
+
if version_installed:
err_msg = "MSVC version {} working host/target script was not found.\n" \
" Host = {}, Target = {}\n" \
" Visual Studio C/C++ compilers may not be set correctly".format(
version, host_platform, target_platform
)
- elif version and installed_vcs:
- err_msg = "MSVC version {} was not found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly.\n" \
- " Installed versions are: {}".format(version, installed_vcs)
- elif version:
- err_msg = "MSVC version {} was not found.\n" \
- " No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(version)
else:
- err_msg = "No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly"
+ installed_vcs = get_installed_vcs(env)
+ if version is not None:
+ if not installed_vcs:
+ err_msg = "MSVC version {} was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(version)
+ else:
+ err_msg = "MSVC version {} was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(version, installed_vcs)
+ else:
+ # should never get here due to early exit in msvc_setup_env
+ if not installed_vcs:
+ err_msg = "MSVC default version was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly"
+ else:
+ # should be impossible: version is None and len(installed_vcs) > 0
+ err_msg = "MSVC default version was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(installed_vcs)
raise MSVCVersionNotFound(err_msg)
return d
-__MSVC_SETUP_ENV_DEFAULT = None
-
def msvc_setup_env(env):
- global __MSVC_SETUP_ENV_DEFAULT
debug('called')
version = get_default_version(env)
if version is None:
- if __MSVC_SETUP_ENV_DEFAULT:
- err_msg = "No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly"
- raise MSVCVersionNotFound(err_msg)
- __MSVC_SETUP_ENV_DEFAULT = True
return None
# XXX: we set-up both MSVS version for backward
diff --git a/test/MSVC/no_msvc.py b/test/MSVC/no_msvc.py
index b6442e8..683951e 100644
--- a/test/MSVC/no_msvc.py
+++ b/test/MSVC/no_msvc.py
@@ -43,7 +43,7 @@ test.run(arguments='-Q -s', stdout='')
# test no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct.py', 'SConstruct')
-test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
+test.run(arguments='-Q -s', stdout='')
# test msvc version number request with no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct_version.py', 'SConstruct')
--
cgit v0.12
From 6f68a4fc1646be9ec4b1b6c5e8fbda031d239a0b Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 24 Apr 2022 07:19:26 -0400
Subject: Simplify msvc version not found exception messages by removing
impossible combinations. Update exception message formatting.
---
SCons/Tool/MSCommon/vc.py | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index cac1744..0b25ed5 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -920,33 +920,21 @@ def msvc_find_valid_batch_script(env, version):
env['TARGET_ARCH']=req_target_platform
if version_installed:
- err_msg = "MSVC version {} working host/target script was not found.\n" \
- " Host = {}, Target = {}\n" \
+ err_msg = "MSVC version '{}' working host/target script was not found.\n" \
+ " Host = '{}', Target = '{}'\n" \
" Visual Studio C/C++ compilers may not be set correctly".format(
version, host_platform, target_platform
)
else:
installed_vcs = get_installed_vcs(env)
- if version is not None:
- if not installed_vcs:
- err_msg = "MSVC version {} was not found.\n" \
- " No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(version)
- else:
- err_msg = "MSVC version {} was not found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly.\n" \
- " Installed versions are: {}".format(version, installed_vcs)
+ if installed_vcs:
+ err_msg = "MSVC version '{}' was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(version, installed_vcs)
else:
- # should never get here due to early exit in msvc_setup_env
- if not installed_vcs:
- err_msg = "MSVC default version was not found.\n" \
- " No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly"
- else:
- # should be impossible: version is None and len(installed_vcs) > 0
- err_msg = "MSVC default version was not found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly.\n" \
- " Installed versions are: {}".format(installed_vcs)
+ err_msg = "MSVC version '{}' was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(version)
raise MSVCVersionNotFound(err_msg)
return d
--
cgit v0.12
From 35d0a4621711902e9d8ee1ddb625fc782dff5de3 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 26 Apr 2022 12:39:54 -0400
Subject: Replace msvc_exists in tools exists functions for msvc tools with
msvc_setup_env_tool that also registers the tool name. The new function may
indicate that the tool should be included even when no instances of msvc are
installed. This is necessary for some error checking. Add a tool name
argument to msvc_setup_env_once as well. Add default msvc version detection.
Add a global and environment local policy variable for handling warnings
and/or exceptions: error, warn, ignore. By default warnings are produced.
Update tests accordingly.
---
SCons/Tool/MSCommon/__init__.py | 4 +-
SCons/Tool/MSCommon/vc.py | 312 ++++++++++++++++++++-
SCons/Tool/midl.py | 8 +-
SCons/Tool/mslib.py | 8 +-
SCons/Tool/mslink.py | 8 +-
SCons/Tool/msvc.py | 8 +-
SCons/Tool/msvs.py | 8 +-
test/MSVC/msvc_badversion.py | 14 +
test/MSVC/no_msvc.py | 8 +-
test/fixture/no_msvc/no_msvcs_sconstruct.py | 1 +
.../fixture/no_msvc/no_msvcs_sconstruct_version.py | 2 +
11 files changed, 349 insertions(+), 32 deletions(-)
diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py
index 50eed73..9d8a8ff 100644
--- a/SCons/Tool/MSCommon/__init__.py
+++ b/SCons/Tool/MSCommon/__init__.py
@@ -34,10 +34,12 @@ from SCons.Tool.MSCommon.sdk import mssdk_exists, mssdk_setup_env
from SCons.Tool.MSCommon.vc import (
msvc_exists,
- msvc_setup_env,
+ msvc_setup_env_tool,
msvc_setup_env_once,
msvc_version_to_maj_min,
msvc_find_vswhere,
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
)
from SCons.Tool.MSCommon.vs import (
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 0b25ed5..c100663 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -45,6 +45,7 @@ import os
import platform
from string import digits as string_digits
from subprocess import PIPE
+import re
import SCons.Util
import SCons.Warnings
@@ -82,6 +83,27 @@ class MSVCScriptNotFound(VisualCException):
class MSVCVersionNotFound(VisualCException):
pass
+# MSVC_NOTFOUND_POLICY:
+# error: raise exception
+# warn: issue warning and continue
+# ignore: continue
+_MSVC_NOTFOUND_POLICY_DEFAULT = False
+_MSVC_NOTFOUND_POLICY = _MSVC_NOTFOUND_POLICY_DEFAULT
+
+_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC = []
+_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT = {}
+
+for value, symbol_list in [
+ (True, ['Error', 'Exception']),
+ (False, ['Warn', 'Warning']),
+ (None, ['Ignore', 'Suppress']),
+]:
+ for symbol in symbol_list:
+ _MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC.append(symbol.lower())
+ _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol] = value
+ _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol.lower()] = value
+ _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol.upper()] = value
+
# Dict to 'canonalize' the arch
_ARCH_TO_CANONICAL = {
"amd64" : "amd64",
@@ -718,6 +740,7 @@ def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
global __INSTALLED_VCS_RUN
__INSTALLED_VCS_RUN = None
+ _MSVCSetupEnvDefault.reset()
# Running these batch files isn't cheap: most of the time spent in
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
@@ -762,6 +785,248 @@ def script_env(script, args=None):
return cache_data
+def _msvc_notfound_policy_lookup(symbol):
+
+ try:
+ notfound_policy = _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol]
+ except KeyError:
+ err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
+ " Valid values are: {}".format(
+ repr(symbol),
+ ', '.join([repr(s) for s in _MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC])
+ )
+ raise ValueError(err_msg)
+
+ return notfound_policy
+
+def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
+ global _MSVC_NOTFOUND_POLICY
+
+ if MSVC_NOTFOUND_POLICY is not None:
+ _MSVC_NOTFOUND_POLICY = _msvc_notfound_policy_lookup(MSVC_NOTFOUND_POLICY)
+
+ return _MSVC_NOTFOUND_POLICY
+
+def get_msvc_notfound_policy():
+ return _MSVC_NOTFOUND_POLICY
+
+def _msvc_notfound_policy_handler(env, msg):
+
+ if env and 'MSVC_NOTFOUND_POLICY' in env:
+ # use environment setting
+ notfound_policy = _msvc_notfound_policy_lookup(env['MSVC_NOTFOUND_POLICY'])
+ else:
+ # use active global setting
+ notfound_policy = _MSVC_NOTFOUND_POLICY
+
+ if notfound_policy is None:
+ debug('notfound policy: ignore')
+ elif notfound_policy:
+ debug('notfound policy: exception')
+ raise MSVCVersionNotFound(msg)
+ else:
+ debug('notfound policy: warning')
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+
+class _MSVCSetupEnvDefault:
+
+ # Determine if and/or when an error/warning should be issued when there
+ # are no versions of msvc installed. If there is at least one version of
+ # msvc installed, these routines do (almost) nothing.
+
+ # Notes:
+ # * When msvc is the default compiler because there are no compilers
+ # installed, a build may fail due to the cl.exe command not being
+ # recognized. Currently, there is no easy way to detect during
+ # msvc initialization if the default environment will be used later
+ # to build a program and/or library. There is no error/warning
+ # as there are legitimate SCons uses that do not require a c compiler.
+ # * As implemented, the default is that a warning is issued. This can
+ # be changed globally via the function set_msvc_notfound_policy and/or
+ # through the environment via the MSVC_NOTFOUND_POLICY variable.
+
+ separator = r';'
+
+ need_init = True
+
+ @classmethod
+ def reset(cls):
+ cls.n_setup = 0 # number of calls to msvc_setup_env_once
+ cls.default_ismsvc = False # is msvc the default compiler
+ cls.default_tools_re_list = [] # list of default tools regular expressions
+ cls.msvc_tools_init = set() # tools registered via msvc_exists
+ cls.msvc_tools = None # tools registered via msvc_setup_env_once
+ cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
+ cls.msvc_nodefault = False # is there a default version of msvc
+ cls.need_init = False # clear initialization indicator
+
+ @classmethod
+ def _initialize(cls, env):
+ if cls.need_init:
+ cls.reset()
+ vcs = get_installed_vcs(env)
+ cls.msvc_installed = len(vcs) > 0
+ debug('msvc default:initialize:msvc_installed=%s', cls.msvc_installed)
+
+ @classmethod
+ def register_tool(cls, env, tool):
+ if cls.need_init:
+ cls._initialize(env)
+ if cls.msvc_installed:
+ return None
+ if not tool:
+ return None
+ if cls.n_setup == 0:
+ if tool not in cls.msvc_tools_init:
+ cls.msvc_tools_init.add(tool)
+ debug('msvc default:register tool:tool=%s msvc_tools_init=%s', tool, cls.msvc_tools_init)
+ return None
+ if tool not in cls.msvc_tools:
+ cls.msvc_tools.add(tool)
+ debug('msvc default:register tool:tool=%s msvc_tools=%s', tool, cls.msvc_tools)
+
+ @classmethod
+ def register_setup(cls, env):
+ if cls.need_init:
+ cls._initialize(env)
+ cls.n_setup += 1
+ if not cls.msvc_installed:
+ cls.msvc_tools = set(cls.msvc_tools_init)
+ if cls.n_setup == 1:
+ tool_list = env.get('TOOLS', None)
+ if tool_list and tool_list[0] == 'default':
+ if len(tool_list) > 1 and tool_list[1] in cls.msvc_tools:
+ # msvc tools are the default compiler
+ cls.default_ismsvc = True
+ cls.msvc_nodefault = False
+ debug(
+ 'msvc default:register setup:n=%d msvc_installed=%s default_ismsvc=%s',
+ cls.n_setup, cls.msvc_installed, cls.default_ismsvc
+ )
+
+ @classmethod
+ def set_nodefault(cls):
+ # default msvc version, msvc not installed
+ cls.msvc_nodefault = True
+ debug('msvc default:set nodefault:msvc_nodefault=%s', cls.msvc_nodefault)
+
+ @classmethod
+ def register_iserror(cls, env, tool):
+
+ cls.register_tool(env, tool)
+
+ if cls.msvc_installed:
+ # msvc installed
+ return None
+
+ if not cls.msvc_nodefault:
+ # msvc version specified
+ return None
+
+ tool_list = env.get('TOOLS', None)
+ if not tool_list:
+ # tool list is empty
+ return None
+
+ debug(
+ 'msvc default:register iserror:n=%s default_ismsvc=%s msvc_tools=%s tool_list=%s',
+ cls.n_setup, cls.default_ismsvc, cls.msvc_tools, tool_list
+ )
+
+ if not cls.default_ismsvc:
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * msvc is not the default compiler
+
+ # construct tools set
+ tools_set = set(tool_list)
+
+ else:
+
+ if cls.n_setup == 1:
+ # first setup and msvc is default compiler:
+ # build default tools regex for current tool state
+ tools = cls.separator.join(tool_list)
+ tools_nchar = len(tools)
+ debug('msvc default:register iserror:add regex nchar=%d, tools=%s', tools_nchar, tools)
+ re_default_tools = re.compile(re.escape(tools))
+ cls.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
+ # early exit: no error for default environment when msvc is not installed
+ return None
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * environment tools list is not empty
+ # * default tools regex list constructed
+ # * msvc tools set constructed
+ #
+ # Algorithm using tools string and sets:
+ # * convert environment tools list to a string
+ # * iteratively remove default tools sequences via regex
+ # substition list built from longest sequence (first)
+ # to shortest sequence (last)
+ # * build environment tools set with remaining tools
+ # * compute intersection of environment tools and msvc tools sets
+ # * if the intersection is:
+ # empty - no error: default tools and/or no additional msvc tools
+ # not empty - error: user specified one or more msvc tool(s)
+ #
+ # This will not produce an error or warning when there are no
+ # msvc installed instances nor any other recognized compilers
+ # and the default environment is needed for a build. The msvc
+ # compiler is forcibly added to the environment tools list when
+ # there are no compilers installed on win32. In this case, cl.exe
+ # will not be found on the path resulting in a failed build.
+
+ # construct tools string
+ tools = cls.separator.join(tool_list)
+ tools_nchar = len(tools)
+
+ debug('msvc default:register iserror:nchar=%d tools=%s', tools_nchar, tools)
+
+ # iteratively remove default tool sequences (longest to shortest)
+ re_nchar_min, re_tools_min = cls.default_tools_re_list[-1]
+ if tools_nchar >= re_nchar_min and re_tools_min.search(tools):
+ # minimum characters satisfied and minimum pattern exists
+ for re_nchar, re_default_tool in cls.default_tools_re_list:
+ if tools_nchar < re_nchar:
+ # not enough characters for pattern
+ continue
+ tools = re_default_tool.sub('', tools).strip(cls.separator)
+ tools_nchar = len(tools)
+ debug('msvc default:register iserror:nchar=%d tools=%s', tools_nchar, tools)
+ if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
+ # less than minimum characters or minimum pattern does not exist
+ break
+
+ # construct non-default list(s) tools set
+ tools_set = {msvc_tool for msvc_tool in tools.split(cls.separator) if msvc_tool}
+
+ debug('msvc default:register iserror:tools=%s', tools_set)
+ if not tools_set:
+ return None
+
+ # compute intersection of remaining tools set and msvc tools set
+ tools_found = cls.msvc_tools.intersection(tools_set)
+ debug('msvc default:register iserror:tools_exist=%s', tools_found)
+ if not tools_found:
+ return None
+
+ # construct in same order as tools list
+ tools_found_list = []
+ seen_tool = set()
+ for tool in tool_list:
+ if tool not in seen_tool:
+ seen_tool.add(tool)
+ if tool in tools_found:
+ tools_found_list.append(tool)
+
+ # return tool list in order presented
+ return tools_found_list
+
def get_default_version(env):
msvc_version = env.get('MSVC_VERSION')
msvs_version = env.get('MSVS_VERSION')
@@ -796,16 +1061,24 @@ def get_default_version(env):
return msvc_version
-def msvc_setup_env_once(env):
+def msvc_setup_env_once(env, tool=None):
try:
has_run = env["MSVC_SETUP_RUN"]
except KeyError:
has_run = False
if not has_run:
+ _MSVCSetupEnvDefault.register_setup(env)
msvc_setup_env(env)
env["MSVC_SETUP_RUN"] = True
+ req_tools = _MSVCSetupEnvDefault.register_iserror(env, tool)
+ if req_tools:
+ msg = "No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Requested tool(s) are: {}".format(req_tools)
+ _msvc_notfound_policy_handler(env, msg)
+
def msvc_find_valid_batch_script(env, version):
"""Find and execute appropriate batch script to set up build env.
@@ -920,22 +1193,23 @@ def msvc_find_valid_batch_script(env, version):
env['TARGET_ARCH']=req_target_platform
if version_installed:
- err_msg = "MSVC version '{}' working host/target script was not found.\n" \
- " Host = '{}', Target = '{}'\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(
- version, host_platform, target_platform
- )
+ msg = "MSVC version '{}' working host/target script was not found.\n" \
+ " Host = '{}', Target = '{}'\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(
+ version, host_platform, target_platform
+ )
else:
installed_vcs = get_installed_vcs(env)
if installed_vcs:
- err_msg = "MSVC version '{}' was not found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly.\n" \
- " Installed versions are: {}".format(version, installed_vcs)
+ msg = "MSVC version '{}' was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(version, installed_vcs)
else:
- err_msg = "MSVC version '{}' was not found.\n" \
- " No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(version)
- raise MSVCVersionNotFound(err_msg)
+ msg = "MSVC version '{}' was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(version)
+
+ _msvc_notfound_policy_handler(env, msg)
return d
@@ -943,6 +1217,7 @@ def msvc_setup_env(env):
debug('called')
version = get_default_version(env)
if version is None:
+ _MSVCSetupEnvDefault.set_nodefault()
return None
# XXX: we set-up both MSVS version for backward
@@ -991,3 +1266,14 @@ def msvc_exists(env=None, version=None):
if version is None:
return len(vcs) > 0
return version in vcs
+
+def msvc_setup_env_tool(env=None, version=None, tool=None):
+ _MSVCSetupEnvDefault.register_tool(env, tool)
+ if msvc_exists(env, version):
+ return True
+ if env:
+ for key in ('MSVC_VERSION', 'MSVS_VERSION'):
+ if key in env:
+ return True
+ return False
+
diff --git a/SCons/Tool/midl.py b/SCons/Tool/midl.py
index 2757c34..22cdd85 100644
--- a/SCons/Tool/midl.py
+++ b/SCons/Tool/midl.py
@@ -33,13 +33,17 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
+
import SCons.Action
import SCons.Builder
import SCons.Defaults
import SCons.Scanner.IDL
import SCons.Util
-from .MSCommon import msvc_exists
+from .MSCommon import msvc_setup_env_tool
+
+tool_name = os.path.splitext(os.path.basename(__file__))[0]
def midl_emitter(target, source, env):
"""Produces a list of outputs from the MIDL compiler"""
@@ -79,7 +83,7 @@ def generate(env):
env['BUILDERS']['TypeLibrary'] = midl_builder
def exists(env):
- return msvc_exists(env)
+ return msvc_setup_env_tool(env, tool=tool_name)
# Local Variables:
# tab-width:4
diff --git a/SCons/Tool/mslib.py b/SCons/Tool/mslib.py
index 354f5cf..cbeaa7f 100644
--- a/SCons/Tool/mslib.py
+++ b/SCons/Tool/mslib.py
@@ -41,14 +41,16 @@ import SCons.Tool.msvs
import SCons.Tool.msvc
import SCons.Util
-from .MSCommon import msvc_exists, msvc_setup_env_once
+from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once
+
+tool_name = os.path.splitext(os.path.basename(__file__))[0]
def generate(env):
"""Add Builders and construction variables for lib to an Environment."""
SCons.Tool.createStaticLibBuilder(env)
# Set-up ms tools paths
- msvc_setup_env_once(env)
+ msvc_setup_env_once(env, tool=tool_name)
env['AR'] = 'lib'
env['ARFLAGS'] = SCons.Util.CLVar('/nologo')
@@ -64,7 +66,7 @@ def generate(env):
def exists(env):
- return msvc_exists(env)
+ return msvc_setup_env_tool(env, tool=tool_name)
# Local Variables:
# tab-width:4
diff --git a/SCons/Tool/mslink.py b/SCons/Tool/mslink.py
index 3dac7f0..1376020 100644
--- a/SCons/Tool/mslink.py
+++ b/SCons/Tool/mslink.py
@@ -43,9 +43,11 @@ import SCons.Tool.msvc
import SCons.Tool.msvs
import SCons.Util
-from .MSCommon import msvc_setup_env_once, msvc_exists
+from .MSCommon import msvc_setup_env_once, msvc_setup_env_tool
from .MSCommon.common import get_pch_node
+tool_name = os.path.splitext(os.path.basename(__file__))[0]
+
def pdbGenerator(env, target, source, for_signature):
try:
return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG']
@@ -307,7 +309,7 @@ def generate(env):
env['_MANIFEST_SOURCES'] = None # _windowsManifestSources
# Set-up ms tools paths
- msvc_setup_env_once(env)
+ msvc_setup_env_once(env, tool=tool_name)
# Loadable modules are on Windows the same as shared libraries, but they
# are subject to different build parameters (LDMODULE* variables).
@@ -330,7 +332,7 @@ def generate(env):
env['TEMPFILEARGJOIN'] = os.linesep
def exists(env):
- return msvc_exists(env)
+ return msvc_setup_env_tool(env, tool=tool_name)
# Local Variables:
# tab-width:4
diff --git a/SCons/Tool/msvc.py b/SCons/Tool/msvc.py
index f2cd418..ee876ac 100644
--- a/SCons/Tool/msvc.py
+++ b/SCons/Tool/msvc.py
@@ -44,9 +44,11 @@ import SCons.Util
import SCons.Warnings
import SCons.Scanner.RC
-from .MSCommon import msvc_exists, msvc_setup_env_once, msvc_version_to_maj_min, msvc_find_vswhere
+from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once, msvc_version_to_maj_min, msvc_find_vswhere
from .MSCommon.common import get_pch_node
+tool_name = os.path.splitext(os.path.basename(__file__))[0]
+
CSuffixes = ['.c', '.C']
CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
@@ -293,7 +295,7 @@ def generate(env):
env['VSWHERE'] = env.get('VSWHERE', msvc_find_vswhere())
# Set-up ms tools paths
- msvc_setup_env_once(env)
+ msvc_setup_env_once(env, tool=tool_name)
env['CFILESUFFIX'] = '.c'
env['CXXFILESUFFIX'] = '.cc'
@@ -319,7 +321,7 @@ def generate(env):
def exists(env):
- return msvc_exists(env)
+ return msvc_setup_env_tool(env, tool=tool_name)
# Local Variables:
# tab-width:4
diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py
index 887cb59..2eae8ee 100644
--- a/SCons/Tool/msvs.py
+++ b/SCons/Tool/msvs.py
@@ -45,7 +45,9 @@ import SCons.Util
import SCons.Warnings
from SCons.Defaults import processDefines
from SCons.compat import PICKLE_PROTOCOL
-from .MSCommon import msvc_exists, msvc_setup_env_once
+from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once
+
+tool_name = os.path.splitext(os.path.basename(__file__))[0]
##############################################################################
# Below here are the classes and functions for generation of
@@ -2077,7 +2079,7 @@ def generate(env):
env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"'
# Set-up ms tools paths for default version
- msvc_setup_env_once(env)
+ msvc_setup_env_once(env, tool=tool_name)
if 'MSVS_VERSION' in env:
version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
@@ -2107,7 +2109,7 @@ def generate(env):
env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
def exists(env):
- return msvc_exists(env)
+ return msvc_setup_env_tool(env, tool=tool_name)
# Local Variables:
# tab-width:4
diff --git a/test/MSVC/msvc_badversion.py b/test/MSVC/msvc_badversion.py
index 7af8ca5..ce419a8 100644
--- a/test/MSVC/msvc_badversion.py
+++ b/test/MSVC/msvc_badversion.py
@@ -47,7 +47,21 @@ installed_msvc_versions = msvc.get_installed_vcs()
test.write('SConstruct', """\
env = Environment(MSVC_VERSION='12.9')
""")
+test.run(arguments='-Q -s', stdout='')
+test.write('SConstruct', """\
+env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='ignore')
+""")
+test.run(arguments='-Q -s', stdout='')
+
+test.write('SConstruct', """\
+env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='warning')
+""")
+test.run(arguments='-Q -s', stdout='')
+
+test.write('SConstruct', """\
+env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='error')
+""")
test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
test.pass_test()
diff --git a/test/MSVC/no_msvc.py b/test/MSVC/no_msvc.py
index 683951e..4ab7dd8 100644
--- a/test/MSVC/no_msvc.py
+++ b/test/MSVC/no_msvc.py
@@ -43,7 +43,10 @@ test.run(arguments='-Q -s', stdout='')
# test no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct.py', 'SConstruct')
-test.run(arguments='-Q -s', stdout='')
+test.run(arguments='-Q -s')
+
+if 'MSVC_VERSION=None' not in test.stdout():
+ test.fail_test()
# test msvc version number request with no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct_version.py', 'SConstruct')
@@ -64,8 +67,5 @@ def exists(env):
test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct')
test.run(arguments='-Q -s')
-test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct')
-test.run(arguments='-Q -s')
-
test.pass_test()
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct.py b/test/fixture/no_msvc/no_msvcs_sconstruct.py
index 590142b..18366d8 100644
--- a/test/fixture/no_msvc/no_msvcs_sconstruct.py
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct.py
@@ -12,3 +12,4 @@ SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
env = SCons.Environment.Environment()
+print('MSVC_VERSION='+str(env.get('MSVC_VERSION')))
\ No newline at end of file
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct_version.py b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
index 81d47cf..f5cabf7 100644
--- a/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
@@ -10,5 +10,7 @@ for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR:
SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
+SCons.Tool.MSCommon.set_msvc_notfound_policy('error')
+
env = SCons.Environment.Environment(MSVC_VERSION='14.3')
--
cgit v0.12
From 51aadabc68d29c0f5ef2c782c3573092e2606ec0 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Fri, 29 Apr 2022 12:38:35 -0400
Subject: Return previous policy when setting msvc notfound policy
---
SCons/Tool/MSCommon/vc.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index c100663..57e44ee 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -802,10 +802,12 @@ def _msvc_notfound_policy_lookup(symbol):
def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
global _MSVC_NOTFOUND_POLICY
+ prev_policy = _MSVC_NOTFOUND_POLICY
+
if MSVC_NOTFOUND_POLICY is not None:
_MSVC_NOTFOUND_POLICY = _msvc_notfound_policy_lookup(MSVC_NOTFOUND_POLICY)
- return _MSVC_NOTFOUND_POLICY
+ return prev_policy
def get_msvc_notfound_policy():
return _MSVC_NOTFOUND_POLICY
--
cgit v0.12
From 7572fe5e0a721c7e85d0d3681c8f50bfcb09b944 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 2 May 2022 09:29:54 -0400
Subject: Fix set/get notfound policy to return policy symbol instead of
internal policy, fix initialization state, rework debug statements.
---
SCons/Tool/MSCommon/vc.py | 90 +++++++++++++++++++++++++++++++----------------
1 file changed, 59 insertions(+), 31 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 57e44ee..4c417f2 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -90,14 +90,16 @@ class MSVCVersionNotFound(VisualCException):
_MSVC_NOTFOUND_POLICY_DEFAULT = False
_MSVC_NOTFOUND_POLICY = _MSVC_NOTFOUND_POLICY_DEFAULT
+_MSVC_NOTFOUND_POLICY_REVERSE_DICT = {}
_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC = []
_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT = {}
for value, symbol_list in [
- (True, ['Error', 'Exception']),
- (False, ['Warn', 'Warning']),
- (None, ['Ignore', 'Suppress']),
+ (True, ['Error', 'Exception']),
+ (False, ['Warning', 'Warn']),
+ (None, ['Ignore', 'Suppress']),
]:
+ _MSVC_NOTFOUND_POLICY_REVERSE_DICT[value] = symbol_list[0].lower()
for symbol in symbol_list:
_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC.append(symbol.lower())
_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol] = value
@@ -802,15 +804,19 @@ def _msvc_notfound_policy_lookup(symbol):
def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
global _MSVC_NOTFOUND_POLICY
- prev_policy = _MSVC_NOTFOUND_POLICY
+ prev_policy = _MSVC_NOTFOUND_POLICY_REVERSE_DICT[_MSVC_NOTFOUND_POLICY]
- if MSVC_NOTFOUND_POLICY is not None:
- _MSVC_NOTFOUND_POLICY = _msvc_notfound_policy_lookup(MSVC_NOTFOUND_POLICY)
+ policy = MSVC_NOTFOUND_POLICY
+ if policy is not None:
+ _MSVC_NOTFOUND_POLICY = _msvc_notfound_policy_lookup(policy)
+ debug('prev_policy=%s, policy=%s, internal_policy=%s', repr(prev_policy), repr(policy), _MSVC_NOTFOUND_POLICY)
return prev_policy
def get_msvc_notfound_policy():
- return _MSVC_NOTFOUND_POLICY
+ policy = _MSVC_NOTFOUND_POLICY_REVERSE_DICT[_MSVC_NOTFOUND_POLICY]
+ debug('policy=%s, internal_policy=%s', repr(policy), _MSVC_NOTFOUND_POLICY)
+ return policy
def _msvc_notfound_policy_handler(env, msg):
@@ -821,13 +827,14 @@ def _msvc_notfound_policy_handler(env, msg):
# use active global setting
notfound_policy = _MSVC_NOTFOUND_POLICY
+ debug('policy=%s, internal_policy=%s', _MSVC_NOTFOUND_POLICY_REVERSE_DICT[notfound_policy], repr(notfound_policy))
+
if notfound_policy is None:
- debug('notfound policy: ignore')
+ # ignore
+ pass
elif notfound_policy:
- debug('notfound policy: exception')
raise MSVCVersionNotFound(msg)
else:
- debug('notfound policy: warning')
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
class _MSVCSetupEnvDefault:
@@ -853,6 +860,7 @@ class _MSVCSetupEnvDefault:
@classmethod
def reset(cls):
+ debug('msvc default:init')
cls.n_setup = 0 # number of calls to msvc_setup_env_once
cls.default_ismsvc = False # is msvc the default compiler
cls.default_tools_re_list = [] # list of default tools regular expressions
@@ -860,18 +868,20 @@ class _MSVCSetupEnvDefault:
cls.msvc_tools = None # tools registered via msvc_setup_env_once
cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
cls.msvc_nodefault = False # is there a default version of msvc
- cls.need_init = False # clear initialization indicator
+ cls.need_init = True # reset initialization indicator
@classmethod
def _initialize(cls, env):
if cls.need_init:
cls.reset()
+ cls.need_init = False
vcs = get_installed_vcs(env)
cls.msvc_installed = len(vcs) > 0
- debug('msvc default:initialize:msvc_installed=%s', cls.msvc_installed)
+ debug('msvc default:msvc_installed=%s', cls.msvc_installed)
@classmethod
def register_tool(cls, env, tool):
+ debug('msvc default:tool=%s', tool)
if cls.need_init:
cls._initialize(env)
if cls.msvc_installed:
@@ -881,14 +891,15 @@ class _MSVCSetupEnvDefault:
if cls.n_setup == 0:
if tool not in cls.msvc_tools_init:
cls.msvc_tools_init.add(tool)
- debug('msvc default:register tool:tool=%s msvc_tools_init=%s', tool, cls.msvc_tools_init)
+ debug('msvc default:tool=%s, msvc_tools_init=%s', tool, cls.msvc_tools_init)
return None
if tool not in cls.msvc_tools:
cls.msvc_tools.add(tool)
- debug('msvc default:register tool:tool=%s msvc_tools=%s', tool, cls.msvc_tools)
+ debug('msvc default:tool=%s, msvc_tools=%s', tool, cls.msvc_tools)
@classmethod
def register_setup(cls, env):
+ debug('msvc default')
if cls.need_init:
cls._initialize(env)
cls.n_setup += 1
@@ -902,7 +913,7 @@ class _MSVCSetupEnvDefault:
cls.default_ismsvc = True
cls.msvc_nodefault = False
debug(
- 'msvc default:register setup:n=%d msvc_installed=%s default_ismsvc=%s',
+ 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
cls.n_setup, cls.msvc_installed, cls.default_ismsvc
)
@@ -910,7 +921,7 @@ class _MSVCSetupEnvDefault:
def set_nodefault(cls):
# default msvc version, msvc not installed
cls.msvc_nodefault = True
- debug('msvc default:set nodefault:msvc_nodefault=%s', cls.msvc_nodefault)
+ debug('msvc default:msvc_nodefault=%s', cls.msvc_nodefault)
@classmethod
def register_iserror(cls, env, tool):
@@ -931,7 +942,7 @@ class _MSVCSetupEnvDefault:
return None
debug(
- 'msvc default:register iserror:n=%s default_ismsvc=%s msvc_tools=%s tool_list=%s',
+ 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
cls.n_setup, cls.default_ismsvc, cls.msvc_tools, tool_list
)
@@ -952,7 +963,7 @@ class _MSVCSetupEnvDefault:
# build default tools regex for current tool state
tools = cls.separator.join(tool_list)
tools_nchar = len(tools)
- debug('msvc default:register iserror:add regex nchar=%d, tools=%s', tools_nchar, tools)
+ debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar, tools)
re_default_tools = re.compile(re.escape(tools))
cls.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
# early exit: no error for default environment when msvc is not installed
@@ -987,7 +998,7 @@ class _MSVCSetupEnvDefault:
tools = cls.separator.join(tool_list)
tools_nchar = len(tools)
- debug('msvc default:register iserror:nchar=%d tools=%s', tools_nchar, tools)
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
# iteratively remove default tool sequences (longest to shortest)
re_nchar_min, re_tools_min = cls.default_tools_re_list[-1]
@@ -999,7 +1010,7 @@ class _MSVCSetupEnvDefault:
continue
tools = re_default_tool.sub('', tools).strip(cls.separator)
tools_nchar = len(tools)
- debug('msvc default:register iserror:nchar=%d tools=%s', tools_nchar, tools)
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
# less than minimum characters or minimum pattern does not exist
break
@@ -1007,13 +1018,13 @@ class _MSVCSetupEnvDefault:
# construct non-default list(s) tools set
tools_set = {msvc_tool for msvc_tool in tools.split(cls.separator) if msvc_tool}
- debug('msvc default:register iserror:tools=%s', tools_set)
+ debug('msvc default:tools=%s', tools_set)
if not tools_set:
return None
# compute intersection of remaining tools set and msvc tools set
tools_found = cls.msvc_tools.intersection(tools_set)
- debug('msvc default:register iserror:tools_exist=%s', tools_found)
+ debug('msvc default:tools_exist=%s', tools_found)
if not tools_found:
return None
@@ -1070,6 +1081,7 @@ def msvc_setup_env_once(env, tool=None):
has_run = False
if not has_run:
+ debug('tool=%s', repr(tool))
_MSVCSetupEnvDefault.register_setup(env)
msvc_setup_env(env)
env["MSVC_SETUP_RUN"] = True
@@ -1264,18 +1276,34 @@ def msvc_setup_env(env):
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
def msvc_exists(env=None, version=None):
+ debug('version=%s', repr(version))
vcs = get_installed_vcs(env)
if version is None:
- return len(vcs) > 0
- return version in vcs
+ rval = len(vcs) > 0
+ else:
+ rval = version in vcs
+ debug('version=%s, return=%s', repr(version), rval)
+ return rval
-def msvc_setup_env_tool(env=None, version=None, tool=None):
- _MSVCSetupEnvDefault.register_tool(env, tool)
- if msvc_exists(env, version):
- return True
+def msvc_setup_env_user(env=None):
+ rval = False
if env:
- for key in ('MSVC_VERSION', 'MSVS_VERSION'):
+ for key in ('MSVC_VERSION', 'MSVS_VERSION', 'MSVC_USE_SCRIPT'):
if key in env:
- return True
- return False
+ rval = True
+ debug('key=%s, return=%s', repr(key), rval)
+ return rval
+ debug('return=%s', rval)
+ return rval
+
+def msvc_setup_env_tool(env=None, version=None, tool=None):
+ debug('tool=%s, version=%s', repr(tool), repr(version))
+ _MSVCSetupEnvDefault.register_tool(env, tool)
+ rval = False
+ if not rval and msvc_exists(env, version):
+ rval = True
+ if not rval and msvc_setup_env_user(env):
+ rval = True
+ debug('tool=%s, version=%s, return=%s', repr(tool), repr(version), rval)
+ return rval
--
cgit v0.12
From 6d7bf1ec0efac43c2158ed21653a8070fba91f35 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 2 May 2022 11:29:41 -0400
Subject: Rename internal notfound policy dictionary.
---
SCons/Tool/MSCommon/vc.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 4c417f2..ec81eaf 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -90,7 +90,7 @@ class MSVCVersionNotFound(VisualCException):
_MSVC_NOTFOUND_POLICY_DEFAULT = False
_MSVC_NOTFOUND_POLICY = _MSVC_NOTFOUND_POLICY_DEFAULT
-_MSVC_NOTFOUND_POLICY_REVERSE_DICT = {}
+_MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL = {}
_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC = []
_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT = {}
@@ -99,7 +99,7 @@ for value, symbol_list in [
(False, ['Warning', 'Warn']),
(None, ['Ignore', 'Suppress']),
]:
- _MSVC_NOTFOUND_POLICY_REVERSE_DICT[value] = symbol_list[0].lower()
+ _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[value] = symbol_list[0].lower()
for symbol in symbol_list:
_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC.append(symbol.lower())
_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol] = value
@@ -804,7 +804,7 @@ def _msvc_notfound_policy_lookup(symbol):
def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
global _MSVC_NOTFOUND_POLICY
- prev_policy = _MSVC_NOTFOUND_POLICY_REVERSE_DICT[_MSVC_NOTFOUND_POLICY]
+ prev_policy = _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[_MSVC_NOTFOUND_POLICY]
policy = MSVC_NOTFOUND_POLICY
if policy is not None:
@@ -814,7 +814,7 @@ def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
return prev_policy
def get_msvc_notfound_policy():
- policy = _MSVC_NOTFOUND_POLICY_REVERSE_DICT[_MSVC_NOTFOUND_POLICY]
+ policy = _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[_MSVC_NOTFOUND_POLICY]
debug('policy=%s, internal_policy=%s', repr(policy), _MSVC_NOTFOUND_POLICY)
return policy
@@ -827,7 +827,7 @@ def _msvc_notfound_policy_handler(env, msg):
# use active global setting
notfound_policy = _MSVC_NOTFOUND_POLICY
- debug('policy=%s, internal_policy=%s', _MSVC_NOTFOUND_POLICY_REVERSE_DICT[notfound_policy], repr(notfound_policy))
+ debug('policy=%s, internal_policy=%s', _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[notfound_policy], repr(notfound_policy))
if notfound_policy is None:
# ignore
--
cgit v0.12
From ba3dcaab98cf8c5156c7d5f80589a2b57162d02b Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Fri, 6 May 2022 09:19:24 -0500
Subject: improved ninja default targets and for ninja file as only target when
generating.
---
CHANGES.txt | 3 +
RELEASE.txt | 4 +
SCons/Tool/ninja/Globals.py | 1 +
SCons/Tool/ninja/NinjaState.py | 93 +++++++++++++++-------
SCons/Tool/ninja/__init__.py | 22 ++++-
SCons/Tool/ninja/ninja_daemon_build.py | 9 ++-
SCons/Tool/ninja/ninja_scons_daemon.py | 29 ++++---
test/ninja/default_targets.py | 83 +++++++++++++++++++
test/ninja/force_scons_callback.py | 2 +-
.../sconstruct_default_targets | 14 ++++
10 files changed, 215 insertions(+), 45 deletions(-)
create mode 100644 test/ninja/default_targets.py
create mode 100644 test/ninja/ninja_test_sconscripts/sconstruct_default_targets
diff --git a/CHANGES.txt b/CHANGES.txt
index 42d20d7..eee3fd2 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -80,6 +80,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected
format. Compiler tools will also configure the variable automatically.
+ - Made ninja tool force the ninja file as the only target. Also improved the default
+ targets setup and made sure there is always a default target for
+ the ninja file, which excludes targets that start and stop the daemon.
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index 6bb1546..3f8a11e 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -49,6 +49,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
output format written to stdout to include more information about the source for each
message of MSVC initialization debugging output. A single space was added before the
message for all debugging output records written to stdout and to files.
+- Made ninja tool force the ninja file as the only target. Also improved the default
+ targets setup and made sure there is always a default target for
+ the ninja file, which excludes targets that start and stop the daemon.
+
FIXES
-----
diff --git a/SCons/Tool/ninja/Globals.py b/SCons/Tool/ninja/Globals.py
index 4d1d38b..d84cae6 100644
--- a/SCons/Tool/ninja/Globals.py
+++ b/SCons/Tool/ninja/Globals.py
@@ -29,6 +29,7 @@ NINJA_CUSTOM_HANDLERS = "__NINJA_CUSTOM_HANDLERS"
NINJA_BUILD = "NINJA_BUILD"
NINJA_WHEREIS_MEMO = {}
NINJA_STAT_MEMO = {}
+NINJA_DEFAULT_TARGETS = []
__NINJA_RULE_MAPPING = {}
# These are the types that get_command can do something with
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index 63ea3a1..5f8d5c7 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -29,6 +29,7 @@ import signal
import tempfile
import shutil
import sys
+import time
from os.path import splitext
from tempfile import NamedTemporaryFile
import ninja
@@ -39,7 +40,7 @@ from SCons.Script import COMMAND_LINE_TARGETS
from SCons.Util import is_List
from SCons.Errors import InternalError
from .Globals import COMMAND_TYPES, NINJA_RULES, NINJA_POOLS, \
- NINJA_CUSTOM_HANDLERS
+ NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
from .Rules import _install_action_function, _mkdir_action_function, _lib_symlink_action_function, _copy_action_function
from .Utils import get_path, alias_to_ninja_build, generate_depfile, ninja_noop, get_order_only, \
get_outputs, get_inputs, get_dependencies, get_rule, get_command_env, to_escaped_list
@@ -68,7 +69,7 @@ class NinjaState:
# couldn't find it, just give the bin name and hope
# its in the path later
self.ninja_bin_path = ninja_bin
-
+ self.ninja_syntax = ninja_syntax
self.writer_class = ninja_syntax.Writer
self.__generated = False
self.translator = SConsToNinjaTranslator(env)
@@ -77,11 +78,6 @@ class NinjaState:
# List of generated builds that will be written at a later stage
self.builds = dict()
- # List of targets for which we have generated a build. This
- # allows us to take multiple Alias nodes as sources and to not
- # fail to build if they have overlapping targets.
- self.built = set()
-
# SCons sets this variable to a function which knows how to do
# shell quoting on whatever platform it's run on. Here we use it
# to make the SCONS_INVOCATION variable properly quoted for things
@@ -96,6 +92,11 @@ class NinjaState:
python_bin = ninja_syntax.escape(scons_escape(sys.executable))
self.variables = {
"COPY": "cmd.exe /c 1>NUL copy" if sys.platform == "win32" else "cp",
+ 'PORT': scons_daemon_port,
+ 'NINJA_DIR_PATH': env.get('NINJA_DIR').abspath,
+ 'PYTHON_BIN': sys.executable,
+ 'NINJA_TOOL_DIR': pathlib.Path(__file__).parent,
+ 'NINJA_SCONS_DAEMON_KEEP_ALIVE': str(env.get('NINJA_SCONS_DAEMON_KEEP_ALIVE')),
"SCONS_INVOCATION": '{} {} --disable-ninja __NINJA_NO=1 $out'.format(
python_bin,
" ".join(
@@ -209,7 +210,7 @@ class NinjaState:
"restat": 1,
},
"TEMPLATE": {
- "command": f"{sys.executable} {pathlib.Path(__file__).parent / 'ninja_daemon_build.py'} {scons_daemon_port} {get_path(env.get('NINJA_DIR'))} $out",
+ "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_daemon_build.py $PORT $NINJA_DIR_PATH $out",
"description": "Defer to SCons to build $out",
"pool": "local_pool",
"restat": 1
@@ -238,7 +239,7 @@ class NinjaState:
},
"SCONS_DAEMON": {
- "command": f"{sys.executable} {pathlib.Path(__file__).parent / 'ninja_run_daemon.py'} {scons_daemon_port} {env.get('NINJA_DIR').abspath} {str(env.get('NINJA_SCONS_DAEMON_KEEP_ALIVE'))} $SCONS_INVOCATION",
+ "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_run_daemon.py $PORT $NINJA_DIR_PATH $NINJA_SCONS_DAEMON_KEEP_ALIVE $SCONS_INVOCATION",
"description": "Starting scons daemon...",
"pool": "local_pool",
# restat
@@ -317,7 +318,6 @@ class NinjaState:
else:
raise InternalError("Node {} added to ninja build state more than once".format(node_string))
self.builds[node_string] = build
- self.built.update(build["outputs"])
return True
# TODO: rely on SCons to tell us what is generated source
@@ -361,8 +361,7 @@ class NinjaState:
self.rules[rule]["depfile"] = "$out.d"
else:
raise Exception(f"Unknown 'NINJA_DEPFILE_PARSE_FORMAT'={self.env['NINJA_DEPFILE_PARSE_FORMAT']}, use 'mvsc', 'gcc', or 'clang'.")
-
-
+
for key, rule in self.env.get(NINJA_RULES, {}).items():
# make a non response file rule for users custom response file rules.
if rule.get('rspfile') is not None:
@@ -374,7 +373,6 @@ class NinjaState:
else:
self.rules.update({key: rule})
- self.rules.update(self.env.get(NINJA_RULES, {}))
self.pools.update(self.env.get(NINJA_POOLS, {}))
content = io.StringIO()
@@ -451,10 +449,20 @@ class NinjaState:
template_builders = []
scons_compiledb = False
+ if SCons.Script._Get_Default_Targets == SCons.Script._Set_Default_Targets_Has_Not_Been_Called:
+ all_targets = set()
+ else:
+ all_targets = None
+
for build in [self.builds[key] for key in sorted(self.builds.keys())]:
if "compile_commands.json" in build["outputs"]:
scons_compiledb = True
+ # this is for the no command line targets, no SCons default case. We want this default
+ # to just be all real files in the build.
+ if all_targets is not None and build['rule'] != 'phony':
+ all_targets = all_targets | set(build["outputs"])
+
if build["rule"] == "TEMPLATE":
template_builders.append(build)
continue
@@ -604,6 +612,22 @@ class NinjaState:
)
+ if all_targets is None:
+ # Look in SCons's list of DEFAULT_TARGETS, find the ones that
+ # we generated a ninja build rule for.
+ all_targets = [str(node) for node in NINJA_DEFAULT_TARGETS]
+ else:
+ all_targets = list(all_targets)
+
+ if len(all_targets) == 0:
+ all_targets = ["phony_default"]
+ ninja.build(
+ outputs=all_targets,
+ rule="phony",
+ )
+
+ ninja.default([self.ninja_syntax.escape_path(path) for path in sorted(all_targets)])
+
daemon_dir = pathlib.Path(tempfile.gettempdir()) / ('scons_daemon_' + str(hashlib.md5(str(get_path(self.env["NINJA_DIR"])).encode()).hexdigest()))
pidfile = None
if os.path.exists(scons_daemon_dirty):
@@ -619,24 +643,37 @@ class NinjaState:
except OSError:
pass
+ # wait for the server process to fully killed
+ try:
+ import psutil
+ while True:
+ if pid not in [proc.pid for proc in psutil.process_iter()]:
+ break
+ else:
+ time.sleep(0.1)
+ except ImportError:
+ # if psutil is not installed we can do this the hard way
+ while True:
+ if sys.platform == 'win32':
+ import ctypes
+ PROCESS_QUERY_INFORMATION = 0x1000
+ processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, 0,pid)
+ if processHandle == 0:
+ break
+ else:
+ ctypes.windll.kernel32.CloseHandle(processHandle)
+ time.sleep(0.1)
+ else:
+ try:
+ os.kill(pid, 0)
+ except OSError:
+ break
+ else:
+ time.sleep(0.1)
+
if os.path.exists(scons_daemon_dirty):
os.unlink(scons_daemon_dirty)
-
- # Look in SCons's list of DEFAULT_TARGETS, find the ones that
- # we generated a ninja build rule for.
- scons_default_targets = [
- get_path(tgt)
- for tgt in SCons.Script.DEFAULT_TARGETS
- if get_path(tgt) in self.built
- ]
-
- # If we found an overlap between SCons's list of default
- # targets and the targets we created ninja builds for then use
- # those as ninja's default as well.
- if scons_default_targets:
- ninja.default(" ".join(scons_default_targets))
-
with NamedTemporaryFile(delete=False, mode='w') as temp_ninja_file:
temp_ninja_file.write(content.getvalue())
shutil.move(temp_ninja_file.name, ninja_file_path)
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index 526db8a..4429217 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -34,7 +34,7 @@ import SCons
import SCons.Tool.ninja.Globals
from SCons.Script import GetOption
-from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS
+from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
from .Methods import register_custom_handler, register_custom_rule_mapping, register_custom_rule, register_custom_pool, \
set_build_node_callback, get_generic_shell_command, CheckNinjaCompdbExpand, get_command, \
gen_get_response_file_command
@@ -118,6 +118,7 @@ def ninja_builder(env, target, source):
# leaving warnings and other output, seems a bit
# prone to failure with such a simple check
erase_previous = output.startswith('[')
+ sys.stdout.write("\n")
def exists(env):
@@ -200,7 +201,7 @@ def generate(env):
ninja_file = env.Ninja()
env['NINJA_FILE'] = ninja_file[0]
env.AlwaysBuild(ninja_file)
- env.Alias("$NINJA_ALIAS_NAME", ninja_file)
+ SCons.Script.BUILD_TARGETS = SCons.Script.TargetList(env.Alias("$NINJA_ALIAS_NAME", ninja_file))
else:
if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]:
SCons.Warnings.SConsWarning("Generating multiple ninja files not supported, set ninja file name before tool initialization.")
@@ -445,6 +446,23 @@ def generate(env):
# date-ness.
SCons.Script.Main.BuildTask.needs_execute = lambda x: True
+
+ def ninja_Set_Default_Targets(env, tlist):
+ """
+ Record the default targets if they were ever set by the user. Ninja
+ will need to write the default targets and make sure not to include
+ the scons daemon shutdown target.
+ """
+ SCons.Script._Get_Default_Targets = SCons.Script._Set_Default_Targets_Has_Been_Called
+ SCons.Script.DEFAULT_TARGETS = ninja_file
+ for t in tlist:
+ if isinstance(t, SCons.Node.Node):
+ NINJA_DEFAULT_TARGETS.append(t)
+ else:
+ nodes = env.arg2nodes(t, env.fs.Entry)
+ NINJA_DEFAULT_TARGETS.extend(nodes)
+ SCons.Script._Set_Default_Targets = ninja_Set_Default_Targets
+
# We will eventually need to overwrite TempFileMunge to make it
# handle persistent tempfiles or get an upstreamed change to add
# some configurability to it's behavior in regards to tempfiles.
diff --git a/SCons/Tool/ninja/ninja_daemon_build.py b/SCons/Tool/ninja/ninja_daemon_build.py
index f34935b..62749b0 100644
--- a/SCons/Tool/ninja/ninja_daemon_build.py
+++ b/SCons/Tool/ninja/ninja_daemon_build.py
@@ -39,6 +39,7 @@ import pathlib
import tempfile
import hashlib
import traceback
+import socket
ninja_builddir = pathlib.Path(sys.argv[2])
daemon_dir = pathlib.Path(tempfile.gettempdir()) / (
@@ -65,8 +66,8 @@ while True:
while not response:
try:
response = conn.getresponse()
- except (http.client.RemoteDisconnected, http.client.ResponseNotReady):
- time.sleep(0.01)
+ except (http.client.RemoteDisconnected, http.client.ResponseNotReady, socket.timeout):
+ time.sleep(0.1)
except http.client.HTTPException:
logging.debug(f"Error: {traceback.format_exc()}")
exit(1)
@@ -79,6 +80,10 @@ while True:
logging.debug(f"Request Done: {sys.argv[3]}")
exit(0)
+ except ConnectionRefusedError:
+ logging.debug(f"Server refused connection to build {sys.argv[3]}, maybe it was too busy, tring again: {traceback.format_exc()}")
+ time.sleep(0.1)
+
except Exception:
logging.debug(f"Failed to send command: {traceback.format_exc()}")
exit(1)
diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py
index f900343..a50a478 100644
--- a/SCons/Tool/ninja/ninja_scons_daemon.py
+++ b/SCons/Tool/ninja/ninja_scons_daemon.py
@@ -50,6 +50,7 @@ from timeit import default_timer as timer
import traceback
import tempfile
import hashlib
+import signal
port = int(sys.argv[1])
ninja_builddir = pathlib.Path(sys.argv[2])
@@ -134,6 +135,15 @@ building_cv = Condition()
error_cv = Condition()
thread_error = False
+httpd = None
+daemon_needs_to_shutdown = False
+
+def sigint_func(signum, frame):
+ global httpd, daemon_needs_to_shutdown
+ daemon_needs_to_shutdown = True
+
+
+signal.signal(signal.SIGINT, sigint_func)
def daemon_thread_func():
@@ -213,6 +223,8 @@ def daemon_thread_func():
finished_building += [building_node]
daemon_ready = False
+ if daemon_needs_to_shutdown:
+ break
time.sleep(0.01)
except Exception:
thread_error = True
@@ -283,6 +295,7 @@ def server_thread_func():
def log_message(self, format, *args):
return
+ socketserver.TCPServer.allow_reuse_address = True
httpd = socketserver.TCPServer(("127.0.0.1", port), S)
httpd.serve_forever()
@@ -291,31 +304,23 @@ server_thread = threading.Thread(target=server_thread_func)
server_thread.daemon = True
server_thread.start()
-while timer() - keep_alive_timer < daemon_keep_alive and not thread_error:
+while timer() - keep_alive_timer < daemon_keep_alive and not thread_error and not daemon_needs_to_shutdown:
time.sleep(1)
if thread_error:
daemon_log(f"Shutting server on port {port} down because thread error.")
+elif daemon_needs_to_shutdown:
+ daemon_log("Server shutting down upon request.")
else:
daemon_log(
f"Shutting server on port {port} down because timed out: {daemon_keep_alive}"
)
-
-# if there are errors, don't immediately shut down the daemon
-# the process which started the server is attempt to connect to
-# the daemon before allowing jobs to start being sent. If the daemon
-# shuts down too fast, the launch script will think it has not
-# started yet and sit and wait. If the launch script is able to connect
-# and then the connection is dropped, it will immediately exit with fail.
-time.sleep(5)
-
+httpd.shutdown()
if os.path.exists(ninja_builddir / "scons_daemon_dirty"):
os.unlink(ninja_builddir / "scons_daemon_dirty")
if os.path.exists(daemon_dir / "pidfile"):
os.unlink(daemon_dir / "pidfile")
-httpd.shutdown()
-server_thread.join()
# Local Variables:
diff --git a/test/ninja/default_targets.py b/test/ninja/default_targets.py
new file mode 100644
index 0000000..dc7c7c1
--- /dev/null
+++ b/test/ninja/default_targets.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# Copyright The SCons Foundation
+#
+# 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.
+#
+
+import os
+
+import TestSCons
+from TestCmd import IS_WINDOWS
+
+test = TestSCons.TestSCons()
+
+try:
+ import ninja
+except ImportError:
+ test.skip_test("Could not find module in python")
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+ninja_bin = os.path.abspath(os.path.join(
+ ninja.__file__,
+ os.pardir,
+ 'data',
+ 'bin',
+ 'ninja' + _exe))
+
+test.dir_fixture('ninja-fixture')
+
+test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct')
+
+# generate simple build
+test.run(stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_not_exist([test.workpath('out1.txt')])
+test.must_exist([test.workpath('out2.txt')])
+
+# clean build and ninja files
+test.run(arguments='-c', stdout=None)
+test.must_contain_all_lines(test.stdout(), [
+ 'Removed out2.txt',
+ 'Removed build.ninja'])
+
+# only generate the ninja file
+test.run(arguments='--disable-execute-ninja', stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_not_exist(test.workpath('out1.txt'))
+test.must_not_exist(test.workpath('out2.txt'))
+
+# run ninja independently
+program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
+test.run(program=program, stdout=None)
+test.must_not_exist([test.workpath('out1.txt')])
+test.must_exist(test.workpath('out2.txt'))
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/ninja/force_scons_callback.py b/test/ninja/force_scons_callback.py
index c99ed58..e0da0dd 100644
--- a/test/ninja/force_scons_callback.py
+++ b/test/ninja/force_scons_callback.py
@@ -80,7 +80,7 @@ test.must_match("out2.txt", "test2.cpp" + os.linesep)
# only generate the ninja file with specific NINJA_SCONS_DAEMON_PORT
test.run(arguments="PORT=9999 --disable-execute-ninja", stdout=None)
# Verify that port # propagates to call to ninja_run_daemon.py
-test.must_contain(test.workpath("build.ninja"), "ninja_run_daemon.py 9999")
+test.must_contain(test.workpath("build.ninja"), "PORT = 9999")
test.pass_test()
diff --git a/test/ninja/ninja_test_sconscripts/sconstruct_default_targets b/test/ninja/ninja_test_sconscripts/sconstruct_default_targets
new file mode 100644
index 0000000..8963270
--- /dev/null
+++ b/test/ninja/ninja_test_sconscripts/sconstruct_default_targets
@@ -0,0 +1,14 @@
+import SCons
+
+SetOption('experimental','ninja')
+DefaultEnvironment(tools=[])
+
+env = Environment(tools=[])
+
+env.Tool('ninja')
+
+env.Command('out1.txt', 'foo.c', 'echo test > $TARGET' )
+out2_node = env.Command('out2.txt', 'foo.c', 'echo test > $TARGET', NINJA_FORCE_SCONS_BUILD=True)
+alias = env.Alias('def', out2_node)
+
+env.Default(alias)
--
cgit v0.12
From 75b79e01089b5b835fd30fb5777044459144dc89 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 10 May 2022 10:42:40 -0500
Subject: added target propagation for ninja execution
---
CHANGES.txt | 5 ++
RELEASE.txt | 8 ++-
SCons/Tool/ninja/Globals.py | 1 +
SCons/Tool/ninja/Utils.py | 3 +
SCons/Tool/ninja/__init__.py | 23 ++++++--
SCons/Tool/ninja/ninja_run_daemon.py | 1 +
SCons/Tool/ninja/ninja_scons_daemon.py | 101 ++++++++++++++++++++++-----------
test/ninja/command_line_targets.py | 95 +++++++++++++++++++++++++++++++
8 files changed, 196 insertions(+), 41 deletions(-)
create mode 100644 test/ninja/command_line_targets.py
diff --git a/CHANGES.txt b/CHANGES.txt
index eee3fd2..a40bd1c 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -83,6 +83,11 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Made ninja tool force the ninja file as the only target. Also improved the default
targets setup and made sure there is always a default target for
the ninja file, which excludes targets that start and stop the daemon.
+ - Update ninja tool so targets passed to SCons are propgated to ninja when scons
+ automatically executes ninja.
+ - Small refactor of scons daemons using a shared StateInfo class for communication
+ between the scons interactive thread and the http server thread. Added error handling
+ for scons interactive failing to startup.
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index 3f8a11e..7c10e27 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -52,8 +52,9 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
- Made ninja tool force the ninja file as the only target. Also improved the default
targets setup and made sure there is always a default target for
the ninja file, which excludes targets that start and stop the daemon.
-
-
+- Update ninja tool so targets passed to SCons are propgated to ninja when scons
+ automatically executes ninja.
+
FIXES
-----
@@ -104,6 +105,9 @@ IMPROVEMENTS
and msvc batch file determination when configuring the build environment. Simplify the msvc
code by eliminating special case handling primarily due to the differences between the full
versions and express versions of visual studio.
+- Small refactor of scons daemons using a shared StateInfo class for communication
+ between the scons interactive thread and the http server thread. Added error handling
+ for scons interactive failing to startup.
PACKAGING
---------
diff --git a/SCons/Tool/ninja/Globals.py b/SCons/Tool/ninja/Globals.py
index d84cae6..6b079ef 100644
--- a/SCons/Tool/ninja/Globals.py
+++ b/SCons/Tool/ninja/Globals.py
@@ -30,6 +30,7 @@ NINJA_BUILD = "NINJA_BUILD"
NINJA_WHEREIS_MEMO = {}
NINJA_STAT_MEMO = {}
NINJA_DEFAULT_TARGETS = []
+NINJA_CMDLINE_TARGETS = []
__NINJA_RULE_MAPPING = {}
# These are the types that get_command can do something with
diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py
index 888218d..c5f7ee4 100644
--- a/SCons/Tool/ninja/Utils.py
+++ b/SCons/Tool/ninja/Utils.py
@@ -29,6 +29,9 @@ from SCons.Action import get_default_ENV, _string_from_cmd_list
from SCons.Script import AddOption
from SCons.Util import is_List, flatten_sequence
+class NinjaExperimentalWarning(SCons.Warnings.WarningOnByDefault):
+ pass
+
def ninja_add_command_line_options():
"""
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index 4429217..bf6345d 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -31,16 +31,17 @@ import subprocess
import sys
import SCons
+import SCons.Script
import SCons.Tool.ninja.Globals
from SCons.Script import GetOption
-from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
+from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS, NINJA_CMDLINE_TARGETS
from .Methods import register_custom_handler, register_custom_rule_mapping, register_custom_rule, register_custom_pool, \
set_build_node_callback, get_generic_shell_command, CheckNinjaCompdbExpand, get_command, \
gen_get_response_file_command
from .Overrides import ninja_hack_linkcom, ninja_hack_arcom, NinjaNoResponseFiles, ninja_always_serial, AlwaysExecAction
from .Utils import ninja_add_command_line_options, \
- ninja_noop, ninja_print_conf_log, ninja_csig, ninja_contents, ninja_stat, ninja_whereis
+ ninja_noop, ninja_print_conf_log, ninja_csig, ninja_contents, ninja_stat, ninja_whereis, NinjaExperimentalWarning
try:
import ninja
@@ -84,7 +85,10 @@ def ninja_builder(env, target, source):
else:
cmd = [NINJA_STATE.ninja_bin_path, '-f', generated_build_ninja]
- if not env.get("NINJA_DISABLE_AUTO_RUN"):
+ if str(env.get("NINJA_DISABLE_AUTO_RUN")).lower() not in ['1', 'true']:
+ num_jobs = env.get('NINJA_MAX_JOBS', env.GetOption("num_jobs"))
+ cmd += ['-j' + str(num_jobs)] + NINJA_CMDLINE_TARGETS
+ print(f"ninja will be run with command line targets: {' '.join(NINJA_CMDLINE_TARGETS)}")
print("Executing:", str(' '.join(cmd)))
# execute the ninja build at the end of SCons, trying to
@@ -165,7 +169,7 @@ def ninja_emitter(target, source, env):
def generate(env):
"""Generate the NINJA builders."""
- global NINJA_STATE
+ global NINJA_STATE, NINJA_CMDLINE_TARGETS
if 'ninja' not in GetOption('experimental'):
return
@@ -201,6 +205,13 @@ def generate(env):
ninja_file = env.Ninja()
env['NINJA_FILE'] = ninja_file[0]
env.AlwaysBuild(ninja_file)
+
+ # We need to force SCons to only build the ninja target when ninja tool is loaded.
+ # The ninja tool is going to 'rip the guts out' of scons and make it basically unable
+ # to do anything in terms of building, so any targets besides the ninja target will
+ # end up doing nothing besides causing confusion. We save the targets however, so that
+ # SCons and invoke ninja to build them in lieu of the user.
+ NINJA_CMDLINE_TARGETS = SCons.Script.BUILD_TARGETS
SCons.Script.BUILD_TARGETS = SCons.Script.TargetList(env.Alias("$NINJA_ALIAS_NAME", ninja_file))
else:
if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]:
@@ -306,8 +317,8 @@ def generate(env):
if GetOption('disable_ninja'):
return env
- SCons.Warnings.SConsWarning("Initializing ninja tool... this feature is experimental. SCons internals and all environments will be affected.")
-
+ print("Initializing ninja tool... this feature is experimental. SCons internals and all environments will be affected.")
+ print(f"SCons running in ninja mode. {env['NINJA_FILE']} will be generated.")
# This is the point of no return, anything after this comment
# makes changes to SCons that are irreversible and incompatible
# with a normal SCons build. We return early if __NINJA_NO=1 has
diff --git a/SCons/Tool/ninja/ninja_run_daemon.py b/SCons/Tool/ninja/ninja_run_daemon.py
index e78b549..3ed9264 100644
--- a/SCons/Tool/ninja/ninja_run_daemon.py
+++ b/SCons/Tool/ninja/ninja_run_daemon.py
@@ -114,6 +114,7 @@ if not os.path.exists(ninja_builddir / "scons_daemon_dirty"):
msg = response.read()
status = response.status
if status != 200:
+ print("ERROR: SCons daemon failed to start:")
print(msg.decode("utf-8"))
exit(1)
logging.debug("Server Responded it was ready!")
diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py
index a50a478..1bf3979 100644
--- a/SCons/Tool/ninja/ninja_scons_daemon.py
+++ b/SCons/Tool/ninja/ninja_scons_daemon.py
@@ -128,28 +128,30 @@ input_q = queue.Queue()
output_q = queue.Queue()
error_q = queue.Queue()
-finished_building = []
-error_nodes = []
-
building_cv = Condition()
error_cv = Condition()
-thread_error = False
-httpd = None
-daemon_needs_to_shutdown = False
+class StateInfo:
+ def __init__(self) -> None:
+ self.thread_error = False
+ self.finished_building = []
+ self.error_nodes = []
+ self.startup_failed = False
+ self.startup_output = ''
+ self.daemon_needs_to_shutdown = False
+ self.httpd = None
-def sigint_func(signum, frame):
- global httpd, daemon_needs_to_shutdown
- daemon_needs_to_shutdown = True
+shared_state = StateInfo()
+def sigint_func(signum, frame):
+ global shared_state
+ shared_state.daemon_needs_to_shutdown = True
signal.signal(signal.SIGINT, sigint_func)
def daemon_thread_func():
- global thread_error
- global finished_building
- global error_nodes
+ global shared_state
try:
args_list = args + ["--interactive"]
daemon_log(f"Starting daemon with args: {' '.join(args_list)}")
@@ -167,16 +169,22 @@ def daemon_thread_func():
daemon_ready = False
building_node = None
+ startup_complete = False
+ # While scons interactive process is stil running...
while p.poll() is None:
+ # while there is scons output to process
while True:
try:
line = output_q.get(block=False, timeout=0.01)
except queue.Empty:
+ # breaks out of the output processing loop
break
else:
daemon_log("output: " + line.strip())
+ if not startup_complete:
+ shared_state.startup_output += line
if "scons: building terminated because of errors." in line:
error_output = ""
@@ -185,13 +193,16 @@ def daemon_thread_func():
error_output += error_q.get(block=False, timeout=0.01)
except queue.Empty:
break
- error_nodes += [{"node": building_node, "error": error_output}]
+ shared_state.error_nodes += [{"node": building_node, "error": error_output}]
daemon_ready = True
building_node = None
with building_cv:
building_cv.notify()
elif line == "scons>>>":
+ shared_state.startup_output = ''
+ startup_complete = True
+
with error_q.mutex:
error_q.queue.clear()
daemon_ready = True
@@ -199,6 +210,7 @@ def daemon_thread_func():
building_cv.notify()
building_node = None
+ # while there is input to process...
while daemon_ready and not input_q.empty():
try:
@@ -209,7 +221,7 @@ def daemon_thread_func():
p.stdin.write("exit\n".encode("utf-8"))
p.stdin.flush()
with building_cv:
- finished_building += [building_node]
+ shared_state.finished_building += [building_node]
daemon_ready = False
raise
@@ -220,14 +232,21 @@ def daemon_thread_func():
p.stdin.write(input_command.encode("utf-8"))
p.stdin.flush()
with building_cv:
- finished_building += [building_node]
+ shared_state.finished_building += [building_node]
daemon_ready = False
- if daemon_needs_to_shutdown:
+ if shared_state.daemon_needs_to_shutdown:
break
time.sleep(0.01)
+
+ # our scons process is done, make sure we are shutting down in this case
+ if not shared_state.daemon_needs_to_shutdown:
+ if not startup_complete:
+ shared_state.startup_failed = True
+ shared_state.daemon_needs_to_shutdown = True
+
except Exception:
- thread_error = True
+ shared_state.thread_error = True
daemon_log("SERVER ERROR: " + traceback.format_exc())
raise
@@ -241,18 +260,20 @@ logging.debug(
)
keep_alive_timer = timer()
-httpd = None
-
def server_thread_func():
+ global shared_state
class S(http.server.BaseHTTPRequestHandler):
def do_GET(self):
- global thread_error
+ global shared_state
global keep_alive_timer
- global error_nodes
-
try:
gets = parse_qs(urlparse(self.path).query)
+
+ # process a request from ninja for a node for scons to build.
+ # Currently this is a serial process because scons interactive is serial
+ # is it was originally meant for a real human user to be providing input
+ # parallel input was never implemented.
build = gets.get("build")
if build:
keep_alive_timer = timer()
@@ -261,12 +282,12 @@ def server_thread_func():
input_q.put(build[0])
def pred():
- return build[0] in finished_building
+ return build[0] in shared_state.finished_building
with building_cv:
building_cv.wait_for(pred)
- for error_node in error_nodes:
+ for error_node in shared_state.error_nodes:
if error_node["node"] == build[0]:
self.send_response(500)
self.send_header("Content-type", "text/html")
@@ -279,6 +300,19 @@ def server_thread_func():
self.end_headers()
return
+ # this message is used in server startup, to make sure the server launched
+ # successfully. If SCons interactive got to a input prompt (scons>>>), then
+ # the server is ready to start processing commands. Otherwise the server will
+ # send an error response back to ninja and shut itself down.
+ ready = gets.get("ready")
+ if ready:
+ if shared_state.startup_failed:
+ self.send_response(500)
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+ self.wfile.write(shared_state.startup_output.encode())
+ return
+
exitbuild = gets.get("exit")
if exitbuild:
input_q.put("exit")
@@ -288,7 +322,7 @@ def server_thread_func():
self.end_headers()
except Exception:
- thread_error = True
+ shared_state.thread_error = True
daemon_log("SERVER ERROR: " + traceback.format_exc())
raise
@@ -296,33 +330,34 @@ def server_thread_func():
return
socketserver.TCPServer.allow_reuse_address = True
- httpd = socketserver.TCPServer(("127.0.0.1", port), S)
- httpd.serve_forever()
+ shared_state.httpd = socketserver.TCPServer(("127.0.0.1", port), S)
+ shared_state.httpd.serve_forever()
server_thread = threading.Thread(target=server_thread_func)
server_thread.daemon = True
server_thread.start()
-while timer() - keep_alive_timer < daemon_keep_alive and not thread_error and not daemon_needs_to_shutdown:
+while (
+ timer() - keep_alive_timer < daemon_keep_alive
+ and not shared_state.thread_error
+ and not shared_state.daemon_needs_to_shutdown):
time.sleep(1)
-if thread_error:
+if shared_state.thread_error:
daemon_log(f"Shutting server on port {port} down because thread error.")
-elif daemon_needs_to_shutdown:
+elif shared_state.daemon_needs_to_shutdown:
daemon_log("Server shutting down upon request.")
else:
daemon_log(
f"Shutting server on port {port} down because timed out: {daemon_keep_alive}"
)
-httpd.shutdown()
+shared_state.httpd.shutdown()
if os.path.exists(ninja_builddir / "scons_daemon_dirty"):
os.unlink(ninja_builddir / "scons_daemon_dirty")
if os.path.exists(daemon_dir / "pidfile"):
os.unlink(daemon_dir / "pidfile")
-
-
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/test/ninja/command_line_targets.py b/test/ninja/command_line_targets.py
new file mode 100644
index 0000000..ad61846
--- /dev/null
+++ b/test/ninja/command_line_targets.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+#
+# Copyright The SCons Foundation
+#
+# 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.
+#
+
+import os
+
+import TestSCons
+from TestCmd import IS_WINDOWS
+
+test = TestSCons.TestSCons()
+
+try:
+ import ninja
+except ImportError:
+ test.skip_test("Could not find module in python")
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+ninja_bin = os.path.abspath(os.path.join(
+ ninja.__file__,
+ os.pardir,
+ 'data',
+ 'bin',
+ 'ninja' + _exe))
+
+test.dir_fixture('ninja-fixture')
+
+test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct')
+
+# generate simple build
+test.run(arguments=['out1.txt'], stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt')
+test.must_exist([test.workpath('out1.txt')])
+test.must_not_exist([test.workpath('out2.txt')])
+
+# clean build and ninja files
+test.run(arguments='-c', stdout=None)
+test.must_contain_all_lines(test.stdout(), [
+ 'Removed out1.txt',
+ 'Removed build.ninja'])
+
+# generate simple build
+test.run(arguments=['out2.txt'], stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_contain_all(test.stdout(), 'build.ninja -j1 out2.txt')
+test.must_not_exist([test.workpath('out1.txt')])
+test.must_exist([test.workpath('out2.txt')])
+
+# clean build and ninja files
+test.run(arguments='-c', stdout=None)
+test.must_contain_all_lines(test.stdout(), [
+ 'Removed out2.txt',
+ 'Removed build.ninja'])
+
+test.run(arguments=['out1.txt', 'out2.txt'], stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt out2.txt')
+test.must_exist([test.workpath('out1.txt')])
+test.must_exist([test.workpath('out2.txt')])
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
--
cgit v0.12
From 880109b6e0bef087b93fef93fda0178bd7defed4 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 10 May 2022 11:56:14 -0500
Subject: fix sider issues
---
SCons/Tool/ninja/__init__.py | 2 +-
SCons/Tool/ninja/ninja_scons_daemon.py | 7 +++----
test/ninja/command_line_targets.py | 1 -
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index bf6345d..04a7abb 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -211,7 +211,7 @@ def generate(env):
# to do anything in terms of building, so any targets besides the ninja target will
# end up doing nothing besides causing confusion. We save the targets however, so that
# SCons and invoke ninja to build them in lieu of the user.
- NINJA_CMDLINE_TARGETS = SCons.Script.BUILD_TARGETS
+ NINJA_CMDLINE_TARGETS = SCons.Script.BUILD_TARGETS
SCons.Script.BUILD_TARGETS = SCons.Script.TargetList(env.Alias("$NINJA_ALIAS_NAME", ninja_file))
else:
if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]:
diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py
index 1bf3979..c4a1d11 100644
--- a/SCons/Tool/ninja/ninja_scons_daemon.py
+++ b/SCons/Tool/ninja/ninja_scons_daemon.py
@@ -338,10 +338,9 @@ server_thread = threading.Thread(target=server_thread_func)
server_thread.daemon = True
server_thread.start()
-while (
- timer() - keep_alive_timer < daemon_keep_alive
- and not shared_state.thread_error
- and not shared_state.daemon_needs_to_shutdown):
+while (timer() - keep_alive_timer < daemon_keep_alive
+ and not shared_state.thread_error
+ and not shared_state.daemon_needs_to_shutdown):
time.sleep(1)
if shared_state.thread_error:
diff --git a/test/ninja/command_line_targets.py b/test/ninja/command_line_targets.py
index ad61846..9fa77ea 100644
--- a/test/ninja/command_line_targets.py
+++ b/test/ninja/command_line_targets.py
@@ -25,7 +25,6 @@
import os
import TestSCons
-from TestCmd import IS_WINDOWS
test = TestSCons.TestSCons()
--
cgit v0.12
From 50df0c523b69b1ec832e1b39f6fd16fcd139f36e Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Wed, 11 May 2022 23:15:18 -0500
Subject: add another exception which should be handled by retry
---
SCons/Tool/ninja/ninja_run_daemon.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/SCons/Tool/ninja/ninja_run_daemon.py b/SCons/Tool/ninja/ninja_run_daemon.py
index 297bcf4..08029a2 100644
--- a/SCons/Tool/ninja/ninja_run_daemon.py
+++ b/SCons/Tool/ninja/ninja_run_daemon.py
@@ -46,6 +46,7 @@ import logging
import time
import http.client
import traceback
+import socket
ninja_builddir = pathlib.Path(sys.argv[2])
daemon_dir = pathlib.Path(tempfile.gettempdir()) / (
@@ -108,7 +109,7 @@ if not os.path.exists(ninja_builddir / "scons_daemon_dirty"):
try:
response = conn.getresponse()
- except (http.client.RemoteDisconnected, http.client.ResponseNotReady):
+ except (http.client.RemoteDisconnected, http.client.ResponseNotReady, socket.timeout):
time.sleep(0.01)
except http.client.HTTPException:
log_error(f"Error: {traceback.format_exc()}")
--
cgit v0.12
From cc81a44b0095ad2e9df68e20aa9d3e4ce6f4dff9 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 15 May 2022 16:08:38 -0400
Subject: Hard-code tool name instead of deriving from file name
---
SCons/Tool/midl.py | 2 +-
SCons/Tool/mslib.py | 2 +-
SCons/Tool/mslink.py | 2 +-
SCons/Tool/msvc.py | 2 +-
SCons/Tool/msvs.py | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/SCons/Tool/midl.py b/SCons/Tool/midl.py
index 22cdd85..72d7696 100644
--- a/SCons/Tool/midl.py
+++ b/SCons/Tool/midl.py
@@ -43,7 +43,7 @@ import SCons.Util
from .MSCommon import msvc_setup_env_tool
-tool_name = os.path.splitext(os.path.basename(__file__))[0]
+tool_name = 'midl'
def midl_emitter(target, source, env):
"""Produces a list of outputs from the MIDL compiler"""
diff --git a/SCons/Tool/mslib.py b/SCons/Tool/mslib.py
index cbeaa7f..be4088b 100644
--- a/SCons/Tool/mslib.py
+++ b/SCons/Tool/mslib.py
@@ -43,7 +43,7 @@ import SCons.Util
from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once
-tool_name = os.path.splitext(os.path.basename(__file__))[0]
+tool_name = 'mslib'
def generate(env):
"""Add Builders and construction variables for lib to an Environment."""
diff --git a/SCons/Tool/mslink.py b/SCons/Tool/mslink.py
index 1376020..2a90e17 100644
--- a/SCons/Tool/mslink.py
+++ b/SCons/Tool/mslink.py
@@ -46,7 +46,7 @@ import SCons.Util
from .MSCommon import msvc_setup_env_once, msvc_setup_env_tool
from .MSCommon.common import get_pch_node
-tool_name = os.path.splitext(os.path.basename(__file__))[0]
+tool_name = 'mslink'
def pdbGenerator(env, target, source, for_signature):
try:
diff --git a/SCons/Tool/msvc.py b/SCons/Tool/msvc.py
index ae47fdd..191d2cc 100644
--- a/SCons/Tool/msvc.py
+++ b/SCons/Tool/msvc.py
@@ -47,7 +47,7 @@ import SCons.Scanner.RC
from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once, msvc_version_to_maj_min, msvc_find_vswhere
from .MSCommon.common import get_pch_node
-tool_name = os.path.splitext(os.path.basename(__file__))[0]
+tool_name = 'msvc'
CSuffixes = ['.c', '.C']
CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py
index 2eae8ee..86df1ef 100644
--- a/SCons/Tool/msvs.py
+++ b/SCons/Tool/msvs.py
@@ -47,7 +47,7 @@ from SCons.Defaults import processDefines
from SCons.compat import PICKLE_PROTOCOL
from .MSCommon import msvc_setup_env_tool, msvc_setup_env_once
-tool_name = os.path.splitext(os.path.basename(__file__))[0]
+tool_name = 'msvs'
##############################################################################
# Below here are the classes and functions for generation of
--
cgit v0.12
From a90c14216220dcdf1112da7c3aff52b795c3b8a1 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 15 May 2022 16:12:46 -0400
Subject: Update test script header with template/test.py header
---
test/MSVC/msvc_badversion.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/test/MSVC/msvc_badversion.py b/test/MSVC/msvc_badversion.py
index ce419a8..a36bd2b 100644
--- a/test/MSVC/msvc_badversion.py
+++ b/test/MSVC/msvc_badversion.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# 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 scons with an invalid MSVC version when at least one MSVC is present.
--
cgit v0.12
From 053f220e789a42e104faa29b467fb224fc1468e5 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 15 May 2022 20:29:20 -0400
Subject: Fix tool name in test fixture
---
test/fixture/no_msvc/no_msvcs_sconstruct_tools.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py b/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
index ca9b699..9aa924b 100644
--- a/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct_tools.py
@@ -10,5 +10,5 @@ for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR:
SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
-env = SCons.Environment.Environment(tools=['MYIGNOREDEFAULTMSVCTOOL'])
+env = SCons.Environment.Environment(tools=['myignoredefaultmsvctool'])
--
cgit v0.12
From 85159b73248da753504440d0fc39e868096ce770 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 15 May 2022 20:56:04 -0400
Subject: Remove unnecessary import
---
SCons/Tool/midl.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/SCons/Tool/midl.py b/SCons/Tool/midl.py
index 72d7696..3def928 100644
--- a/SCons/Tool/midl.py
+++ b/SCons/Tool/midl.py
@@ -33,8 +33,6 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import os
-
import SCons.Action
import SCons.Builder
import SCons.Defaults
--
cgit v0.12
From a506af6e1eb8bede7cc4e227e7887d39001bb53e Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 17 May 2022 19:06:49 -0400
Subject: Raise exception for unexpected cache file format
---
SCons/Tool/MSCommon/common.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py
index f542e02..577ec48 100644
--- a/SCons/Tool/MSCommon/common.py
+++ b/SCons/Tool/MSCommon/common.py
@@ -110,7 +110,15 @@ def read_script_env_cache():
# json to the cache dictionary. Reconstruct the cache key
# tuple from the key list written to json.
envcache_list = json.load(f)
- envcache = {tuple(d['key']): d['data'] for d in envcache_list}
+ if isinstance(envcache_list, list):
+ envcache = {tuple(d['key']): d['data'] for d in envcache_list}
+ else:
+ raise TypeError(
+ 'SCONS_CACHE_MSVC_CONFIG cache file read error: expected type {}, found type {}.\n' \
+ ' Remove cache file {} and try again'.format(
+ repr('list'), repr(type(envcache_list).__name__), repr(CONFIG_CACHE)
+ )
+ )
except FileNotFoundError:
# don't fail if no cache file, just proceed without it
pass
--
cgit v0.12
From 2efe7d108823f528bdfc162ea9aae572914ae383 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Wed, 18 May 2022 16:10:03 -0700
Subject: [ci skip] fix sider complaint. Reformat. Update file header to
current standard
---
SCons/Tool/midl.py | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/SCons/Tool/midl.py b/SCons/Tool/midl.py
index 72d7696..c25ce69 100644
--- a/SCons/Tool/midl.py
+++ b/SCons/Tool/midl.py
@@ -1,15 +1,6 @@
-"""SCons.Tool.midl
-
-Tool-specific initialization for midl (Microsoft IDL compiler).
-
-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.
-
-"""
-
+# MIT License
#
-# __COPYRIGHT__
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -29,11 +20,16 @@ selection method.
# 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__"
+"""SCons.Tool.midl
-import os
+Tool-specific initialization for midl (Microsoft IDL compiler).
+
+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.
+
+"""
import SCons.Action
import SCons.Builder
@@ -45,6 +41,7 @@ from .MSCommon import msvc_setup_env_tool
tool_name = 'midl'
+
def midl_emitter(target, source, env):
"""Produces a list of outputs from the MIDL compiler"""
base, _ = SCons.Util.splitext(str(target[0]))
@@ -62,26 +59,29 @@ def midl_emitter(target, source, env):
dlldata = base + '_data.c'
targets.append(dlldata)
- return (targets, source)
+ return targets, source
+
idl_scanner = SCons.Scanner.IDL.IDLScan()
midl_action = SCons.Action.Action('$MIDLCOM', '$MIDLCOMSTR')
-midl_builder = SCons.Builder.Builder(action = midl_action,
- src_suffix = '.idl',
+midl_builder = SCons.Builder.Builder(action=midl_action,
+ src_suffix='.idl',
suffix='.tlb',
- emitter = midl_emitter,
- source_scanner = idl_scanner)
+ emitter=midl_emitter,
+ source_scanner=idl_scanner)
+
def generate(env):
"""Add Builders and construction variables for midl to an Environment."""
- env['MIDL'] = 'MIDL.EXE'
- env['MIDLFLAGS'] = SCons.Util.CLVar('/nologo')
- env['MIDLCOM'] = '$MIDL $MIDLFLAGS /tlb ${TARGETS[0]} /h ${TARGETS[1]} /iid ${TARGETS[2]} /proxy ${TARGETS[3]} /dlldata ${TARGETS[4]} $SOURCE 2> NUL'
+ env['MIDL'] = 'MIDL.EXE'
+ env['MIDLFLAGS'] = SCons.Util.CLVar('/nologo')
+ env['MIDLCOM'] = '$MIDL $MIDLFLAGS /tlb ${TARGETS[0]} /h ${TARGETS[1]} /iid ${TARGETS[2]} /proxy ${TARGETS[3]} /dlldata ${TARGETS[4]} $SOURCE 2> NUL'
env['BUILDERS']['TypeLibrary'] = midl_builder
+
def exists(env):
return msvc_setup_env_tool(env, tool=tool_name)
--
cgit v0.12
From 0e51fe4467417350bc969c498698999b6f3b946e Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 19 May 2022 08:46:16 -0400
Subject: Change notfound policy parallel variables to namedtuple.
Rework debug statement contents and formatting for notfound policy. Make comment for internal class a docstring per request.
---
SCons/Tool/MSCommon/vc.py | 117 +++++++++++++++++++++++++++-------------------
1 file changed, 69 insertions(+), 48 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 2dd28de..33faca2 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -91,28 +91,36 @@ class MSVCUseSettingsError(VisualCException):
class MSVCVersionNotFound(VisualCException):
pass
-# MSVC_NOTFOUND_POLICY:
-# error: raise exception
-# warn: issue warning and continue
-# ignore: continue
-_MSVC_NOTFOUND_POLICY_DEFAULT = False
-_MSVC_NOTFOUND_POLICY = _MSVC_NOTFOUND_POLICY_DEFAULT
-
-_MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL = {}
-_MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC = []
-_MSVC_NOTFOUND_POLICY_SYMBOLS_DICT = {}
-
-for value, symbol_list in [
+# MSVC_NOTFOUND_POLICY definition:
+# error: raise exception
+# warning: issue warning and continue
+# ignore: continue
+
+_MSVC_NOTFOUND_POLICY_DEFINITION = namedtuple('MSVCNotFoundPolicyDefinition', [
+ 'value',
+ 'symbol',
+])
+
+_MSVC_NOTFOUND_POLICY_INTERNAL = {}
+_MSVC_NOTFOUND_POLICY_EXTERNAL = {}
+
+for policy_value, policy_symbol_list in [
(True, ['Error', 'Exception']),
(False, ['Warning', 'Warn']),
(None, ['Ignore', 'Suppress']),
]:
- _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[value] = symbol_list[0].lower()
- for symbol in symbol_list:
- _MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC.append(symbol.lower())
- _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol] = value
- _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol.lower()] = value
- _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol.upper()] = value
+
+ policy_symbol = policy_symbol_list[0].lower()
+ policy_def = _MSVC_NOTFOUND_POLICY_DEFINITION(policy_value, policy_symbol)
+
+ _MSVC_NOTFOUND_POLICY_INTERNAL[policy_symbol] = policy_def
+
+ for policy_symbol in policy_symbol_list:
+ _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
+ _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
+ _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
+
+_MSVC_NOTFOUND_POLICY_DEF = _MSVC_NOTFOUND_POLICY_INTERNAL['warning']
# Dict to 'canonalize' the arch
_ARCH_TO_CANONICAL = {
@@ -1050,69 +1058,82 @@ def script_env(script, args=None):
def _msvc_notfound_policy_lookup(symbol):
try:
- notfound_policy = _MSVC_NOTFOUND_POLICY_SYMBOLS_DICT[symbol]
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_EXTERNAL[symbol]
except KeyError:
err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
" Valid values are: {}".format(
repr(symbol),
- ', '.join([repr(s) for s in _MSVC_NOTFOUND_POLICY_SYMBOLS_PUBLIC])
+ ', '.join([repr(s) for s in _MSVC_NOTFOUND_POLICY_EXTERNAL.keys()])
)
raise ValueError(err_msg)
- return notfound_policy
+ return notfound_policy_def
def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
- global _MSVC_NOTFOUND_POLICY
+ global _MSVC_NOTFOUND_POLICY_DEF
- prev_policy = _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[_MSVC_NOTFOUND_POLICY]
+ prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
policy = MSVC_NOTFOUND_POLICY
if policy is not None:
- _MSVC_NOTFOUND_POLICY = _msvc_notfound_policy_lookup(policy)
+ _MSVC_NOTFOUND_POLICY_DEF = _msvc_notfound_policy_lookup(policy)
+
+ debug(
+ 'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ repr(prev_policy), repr(policy),
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
- debug('prev_policy=%s, policy=%s, internal_policy=%s', repr(prev_policy), repr(policy), _MSVC_NOTFOUND_POLICY)
return prev_policy
def get_msvc_notfound_policy():
- policy = _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[_MSVC_NOTFOUND_POLICY]
- debug('policy=%s, internal_policy=%s', repr(policy), _MSVC_NOTFOUND_POLICY)
- return policy
+ debug(
+ 'policy.symbol=%s, policy.value=%s',
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
+ return _MSVC_NOTFOUND_POLICY_DEF.symbol
def _msvc_notfound_policy_handler(env, msg):
if env and 'MSVC_NOTFOUND_POLICY' in env:
# use environment setting
- notfound_policy = _msvc_notfound_policy_lookup(env['MSVC_NOTFOUND_POLICY'])
+ notfound_policy_def = _msvc_notfound_policy_lookup(env['MSVC_NOTFOUND_POLICY'])
+ notfound_policy_src = 'environment'
else:
# use active global setting
- notfound_policy = _MSVC_NOTFOUND_POLICY
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+ notfound_policy_src = 'default'
- debug('policy=%s, internal_policy=%s', _MSVC_NOTFOUND_POLICY_INTERNAL_SYMBOL[notfound_policy], repr(notfound_policy))
+ debug(
+ 'source=%s, policy.symbol=%s, policy.value=%s',
+ notfound_policy_src, repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
+ )
- if notfound_policy is None:
+ if notfound_policy_def.value is None:
# ignore
pass
- elif notfound_policy:
+ elif notfound_policy_def.value:
raise MSVCVersionNotFound(msg)
else:
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
class _MSVCSetupEnvDefault:
-
- # Determine if and/or when an error/warning should be issued when there
- # are no versions of msvc installed. If there is at least one version of
- # msvc installed, these routines do (almost) nothing.
-
- # Notes:
- # * When msvc is the default compiler because there are no compilers
- # installed, a build may fail due to the cl.exe command not being
- # recognized. Currently, there is no easy way to detect during
- # msvc initialization if the default environment will be used later
- # to build a program and/or library. There is no error/warning
- # as there are legitimate SCons uses that do not require a c compiler.
- # * As implemented, the default is that a warning is issued. This can
- # be changed globally via the function set_msvc_notfound_policy and/or
- # through the environment via the MSVC_NOTFOUND_POLICY variable.
+ """
+ Determine if and/or when an error/warning should be issued when there
+ are no versions of msvc installed. If there is at least one version of
+ msvc installed, these routines do (almost) nothing.
+
+ Notes:
+ * When msvc is the default compiler because there are no compilers
+ installed, a build may fail due to the cl.exe command not being
+ recognized. Currently, there is no easy way to detect during
+ msvc initialization if the default environment will be used later
+ to build a program and/or library. There is no error/warning
+ as there are legitimate SCons uses that do not require a c compiler.
+ * As implemented, the default is that a warning is issued. This can
+ be changed globally via the function set_msvc_notfound_policy and/or
+ through the environment via the MSVC_NOTFOUND_POLICY variable.
+ """
separator = r';'
--
cgit v0.12
From 479b123c6177fca85990b0d6890d9737a49016e2 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 19 May 2022 10:25:42 -0400
Subject: Treat environment notfound policy set to None the same as if
undefined (default global setting)
---
SCons/Tool/MSCommon/vc.py | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 33faca2..32d0e61 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1096,17 +1096,24 @@ def get_msvc_notfound_policy():
def _msvc_notfound_policy_handler(env, msg):
if env and 'MSVC_NOTFOUND_POLICY' in env:
- # use environment setting
- notfound_policy_def = _msvc_notfound_policy_lookup(env['MSVC_NOTFOUND_POLICY'])
+ # environment setting
notfound_policy_src = 'environment'
+ policy = env['MSVC_NOTFOUND_POLICY']
+ if policy is not None:
+ # user policy request
+ notfound_policy_def = _msvc_notfound_policy_lookup(policy)
+ else:
+ # active global setting
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
else:
- # use active global setting
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+ # active global setting
notfound_policy_src = 'default'
+ policy = None
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
debug(
- 'source=%s, policy.symbol=%s, policy.value=%s',
- notfound_policy_src, repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
+ 'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ notfound_policy_src, repr(policy), repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
)
if notfound_policy_def.value is None:
--
cgit v0.12
From 64a652ee2aa8714322c1d07f0d2fc3056d610212 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 19 May 2022 16:46:03 -0400
Subject: Issue warning for incompatible cache format and continue; file
possibly overwritten.
---
SCons/Tool/MSCommon/common.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py
index 577ec48..c9f07f5 100644
--- a/SCons/Tool/MSCommon/common.py
+++ b/SCons/Tool/MSCommon/common.py
@@ -35,6 +35,10 @@ from contextlib import suppress
from pathlib import Path
import SCons.Util
+import SCons.Warnings
+
+class MSVCCacheInvalidWarning(SCons.Warnings.WarningOnByDefault):
+ pass
# SCONS_MSCOMMON_DEBUG is internal-use so undocumented:
# set to '-' to print to console, else set to filename to log to
@@ -113,12 +117,12 @@ def read_script_env_cache():
if isinstance(envcache_list, list):
envcache = {tuple(d['key']): d['data'] for d in envcache_list}
else:
- raise TypeError(
- 'SCONS_CACHE_MSVC_CONFIG cache file read error: expected type {}, found type {}.\n' \
- ' Remove cache file {} and try again'.format(
- repr('list'), repr(type(envcache_list).__name__), repr(CONFIG_CACHE)
- )
+ # don't fail if incompatible format, just proceed without it
+ warn_msg = "Incompatible format for msvc cache file {}: file may be overwritten.".format(
+ repr(CONFIG_CACHE)
)
+ SCons.Warnings.warn(MSVCCacheInvalidWarning, warn_msg)
+ debug(warn_msg)
except FileNotFoundError:
# don't fail if no cache file, just proceed without it
pass
--
cgit v0.12
From 6848757227a6b9e605be699d6f0b28445b3deede Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sat, 21 May 2022 11:08:03 -0400
Subject: Update CHANGES.txt and RELEASE.txt. [ci skip]
---
CHANGES.txt | 19 +++++++++++++++++++
RELEASE.txt | 19 +++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/CHANGES.txt b/CHANGES.txt
index 17121f4..3978b5b 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -48,6 +48,25 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
require delayed expansion to be enabled which is currently not supported and is
typically not enabled by default on the host system. The batch files may also require
environment variables that are not included by default in the msvc environment.
+ - Suppress issuing a warning when there are no installed Visual Studio instances for the default
+ tools configuration (issue #2813). When msvc is the default compiler because there are no
+ compilers installed, a build may fail due to the cl.exe command not being recognized. At
+ present, there is no easy way to detect during msvc initialization if the default environment
+ will be used later to build a program and/or library. There is no error/warning issued for the
+ default tools as there are legitimate SCons uses that do not require a c compiler.
+ - Added a global policy setting and an environment policy variable for specifying the action to
+ be taken when an msvc request cannot be satisfied. The available options are "error",
+ "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be
+ set and retrieved via the functions set_msvc_notfound_policy and get_msvc_notfound_policy,
+ respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment
+ policy variable introduced is MSVC_NOTFOUND_POLICY. When defined, the environment policy
+ variable overrides the global policy setting for a given environment. When the active policy
+ is "error" or "exception", an MSVCVersionNotFound exception is raised. When the active policy
+ is "warning" or "warn", a VisualCMissingWarning warning is issued and the constructed
+ environment is likely incomplete. When the active policy is "ignore" or "suppress", no action
+ is taken and the constructed environment is likely incomplete. As implemented, the default
+ global policy is "warning". The ability to set the global policy via an SCons command-line
+ option may be added in a future enhancement.
From William Deegan:
- Fix check for unsupported Python version. It was broken. Also now the error message
diff --git a/RELEASE.txt b/RELEASE.txt
index 1a00d02..94bedaf 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -21,6 +21,19 @@ NEW FUNCTIONALITY
be used in the shell command of some Action.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
+- Added a global policy setting and an environment policy variable for specifying the action to
+ be taken when an msvc request cannot be satisfied. The available options are "error",
+ "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be
+ set and retrieved via the functions set_msvc_notfound_policy and get_msvc_notfound_policy,
+ respectively. These two methods may be imported from SCons.Tool.MSCommon. The environment
+ policy variable introduced is MSVC_NOTFOUND_POLICY. When defined, the environment policy
+ variable overrides the global policy setting for a given environment. When the active policy
+ is "error" or "exception", an MSVCVersionNotFound exception is raised. When the active policy
+ is "warning" or "warn", a VisualCMissingWarning warning is issued and the constructed
+ environment is likely incomplete. When the active policy is "ignore" or "suppress", no action
+ is taken and the constructed environment is likely incomplete. As implemented, the default
+ global policy is "warning". The ability to set the global policy via an SCons command-line
+ option may be added in a future enhancement.
DEPRECATED FUNCTIONALITY
@@ -120,6 +133,12 @@ FIXES
- The system environment variable names imported for MSVC 7.0 and 6.0 were updated to be
consistent with the variables names defined by their respective installers. This fixes an
error caused when bypassing MSVC detection by specifying the MSVC 7.0 batch file directly.
+- Suppress issuing a warning when there are no installed Visual Studio instances for the default
+ tools configuration (issue #2813). When msvc is the default compiler because there are no
+ compilers installed, a build may fail due to the cl.exe command not being recognized. At
+ present, there is no easy way to detect during msvc initialization if the default environment
+ will be used later to build a program and/or library. There is no error/warning issued for the
+ default tools as there are legitimate SCons uses that do not require a c compiler.
IMPROVEMENTS
------------
--
cgit v0.12
From 2e80fc1c2796a705b9049aba686de8e35bb878cd Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Mon, 23 May 2022 22:55:33 -0500
Subject: Updated SHELL_ENV_GENERATOR to be list of functions now called
SHELL_ENV_GENERATORS
---
CHANGES.txt | 5 +++-
RELEASE.txt | 3 +++
SCons/Action.py | 22 +++++++++++++---
SCons/Action.xml | 35 +++++++++++++++++++------
SCons/Tool/ninja/Methods.py | 4 +--
SCons/Tool/ninja/NinjaState.py | 11 +++++++-
SCons/Tool/ninja/Utils.py | 4 +--
test/Actions/subst_shell_env-fixture/SConstruct | 24 ++++++++++++-----
test/Actions/subst_shell_env.py | 4 +--
9 files changed, 87 insertions(+), 25 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 519ced9..60e934f 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -99,9 +99,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected
format. Compiler tools will also configure the variable automatically.
- - Added SHELL_ENV_GENERATOR construction variables. This variable allows the user to Define
+ - Added SHELL_ENV_GENERATOR construction variable. This variable allows the user to Define
a function which will be called to generate or alter the execution environment which will
be used in the shell command of some Action.
+ - Updated SHELL_ENV_GENERATOR construction variable to SHELL_ENV_GENERATORS. This variable
+ is now an iterable which will contain functions which each are called and each can customize
+ the execution environment.
- Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
- Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry
to connect to the server during start up.
diff --git a/RELEASE.txt b/RELEASE.txt
index 5bfee35..38fbbd7 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -19,6 +19,9 @@ NEW FUNCTIONALITY
- Added SHELL_ENV_GENERATOR construction variables. This variable allows the user to Define
a function which will be called to generate or alter the execution environment which will
be used in the shell command of some Action.
+- Updated SHELL_ENV_GENERATOR construction variable to SHELL_ENV_GENERATORS. This variable
+ is now an iterable which will contain functions which each are called and each can customize
+ the execution environment.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
diff --git a/SCons/Action.py b/SCons/Action.py
index 0849178..4dd0543 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -732,7 +732,7 @@ def _string_from_cmd_list(cmd_list):
default_ENV = None
-def get_default_ENV(env, target=None, source=None):
+def get_default_ENV(env):
"""
A fiddlin' little function that has an 'import SCons.Environment' which
can't be moved to the top level without creating an import loop. Since
@@ -755,6 +755,23 @@ def get_default_ENV(env, target=None, source=None):
return default_ENV
+def _resolve_shell_env(env, target, source):
+ ENV = get_default_ENV(env)
+ shell_gen = env.get('SHELL_ENV_GENERATORS')
+ if shell_gen is not None:
+ ENV = ENV.copy()
+ try:
+ shell_gens = iter(shell_gen)
+ except:
+ raise SCons.Errors.UserError("SHELL_ENV_GENERATORS must be iteratable.")
+ else:
+ for generator in shell_gens:
+ ENV = generator(env, target, source, ENV)
+ if not isinstance(ENV, dict):
+ raise SCons.Errors.UserError("SHELL_ENV_GENERATORS function: {generator} must return a dict.")
+ return ENV
+
+
def _subproc(scons_env, cmd, error='ignore', **kw):
"""Wrapper for subprocess which pulls from construction env.
@@ -924,10 +941,9 @@ class CommandAction(_ActionAction):
escape = env.get('ESCAPE', lambda x: x)
- ENV = env.get('SHELL_ENV_GENERATOR', get_default_ENV)(env, target, source)
+ ENV = _resolve_shell_env(env, target, source)
# Ensure that the ENV values are all strings:
-
for key, value in ENV.items():
if not is_String(value):
if is_List(value):
diff --git a/SCons/Action.xml b/SCons/Action.xml
index 2c18d55..8994adb 100644
--- a/SCons/Action.xml
+++ b/SCons/Action.xml
@@ -200,18 +200,32 @@ in which the command should be executed.
-
+
-A function to generate or alter the environment dictionary which will be used
-when executing the &cv-link-SPAWN; function. This primarily give the
-user a chance to customize the execution environment for particular Actions.
-It must return a dictionary containing the environment variables as
-keys and the values as values.
+Must be an iterable containing functions where each function generates or
+alters the environment dictionary which will be used
+when executing the &cv-link-SPAWN; function. The functions will initially
+be passed a reference of the current execution environment (e.g. env['ENV']),
+and each called while iterating the list. Each function must return a dictionary
+which will then be passed to the next function iterated. The return dictionary
+should contain keys which represent the environment variables and their respective
+values.
+
+This primary purpose of this construction variable is to give the user the ability
+to substitute execution environment variables based on env, targets, and sources.
+If desired, the user can completly customize the execution environment for particular
+targets.
-def custom_shell_env(env, target, source):
+def custom_shell_env(env, target, source, shell_env):
+ # customize shell_env if desired
+ if str(target[0]) == 'special_target'is:
+ shell_env['SPECIAL_VAR'] = env.subst('SOME_VAR', target=target, source=source)
+ return shell_env
+
+env["SHELL_ENV_GENERATORS"] = [custom_shell_env]
@@ -223,10 +237,15 @@ execution environment can be derived from.
target
The list of targets associated with this action.
-
+ source
The list of sources associated with this action.
+
+ shell_env
+The current shell_env after iterating other SHELL_ENV_GENERATORS functions. This can be compared
+to the passed env['ENV'] to detect any changes.
+
diff --git a/SCons/Tool/ninja/Methods.py b/SCons/Tool/ninja/Methods.py
index 2be576f..c0afab8 100644
--- a/SCons/Tool/ninja/Methods.py
+++ b/SCons/Tool/ninja/Methods.py
@@ -81,7 +81,7 @@ def get_generic_shell_command(env, node, action, targets, sources, executor=None
"GENERATED_CMD",
{
"cmd": generate_command(env, node, action, targets, sources, executor=executor),
- "env": get_command_env(env),
+ "env": get_command_env(env, targets, sources),
},
# Since this function is a rule mapping provider, it must return a list of dependencies,
# and usually this would be the path to a tool, such as a compiler, used for this rule.
@@ -266,7 +266,7 @@ def gen_get_response_file_command(env, rule, tool, tool_is_dynamic=False, custom
variables = {"rspc": rsp_content, rule: cmd}
if use_command_env:
- variables["env"] = get_command_env(env)
+ variables["env"] = get_command_env(env, targets, sources)
for key, value in custom_env.items():
variables["env"] += env.subst(
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index 63ea3a1..ac10b5e 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -809,6 +809,15 @@ class SConsToNinjaTranslator:
# Remove all preceding and proceeding whitespace
cmdline = cmdline.strip()
+ env = node.env if node.env else self.env
+ executor = node.get_executor()
+ if executor is not None:
+ targets = executor.get_all_targets()
+ else:
+ if hasattr(node, "target_peers"):
+ targets = node.target_peers
+ else:
+ targets = [node]
# Make sure we didn't generate an empty cmdline
if cmdline:
@@ -817,7 +826,7 @@ class SConsToNinjaTranslator:
"rule": get_rule(node, "GENERATED_CMD"),
"variables": {
"cmd": cmdline,
- "env": get_command_env(node.env if node.env else self.env),
+ "env": get_command_env(env, targets, node.sources),
},
"implicit": dependencies,
}
diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py
index 888218d..2bd2263 100644
--- a/SCons/Tool/ninja/Utils.py
+++ b/SCons/Tool/ninja/Utils.py
@@ -259,7 +259,7 @@ def ninja_noop(*_args, **_kwargs):
return None
-def get_command_env(env):
+def get_command_env(env, target, source):
"""
Return a string that sets the environment for any environment variables that
differ between the OS environment and the SCons command ENV.
@@ -275,7 +275,7 @@ def get_command_env(env):
# os.environ or differ from it. We assume if it's a new or
# differing key from the process environment then it's
# important to pass down to commands in the Ninja file.
- ENV = get_default_ENV(env)
+ ENV = SCons.Action._resolve_shell_env(env, target, source)
scons_specified_env = {
key: value
for key, value in ENV.items()
diff --git a/test/Actions/subst_shell_env-fixture/SConstruct b/test/Actions/subst_shell_env-fixture/SConstruct
index 6e48add..5ba822e 100644
--- a/test/Actions/subst_shell_env-fixture/SConstruct
+++ b/test/Actions/subst_shell_env-fixture/SConstruct
@@ -1,24 +1,36 @@
import sys
-def custom_environment_expansion(env, target, source):
- ENV = env['ENV'].copy()
- ENV['EXPANDED_SHELL_VAR'] = env.subst(env['ENV']['EXPANDED_SHELL_VAR'], target=target, source=source)
+def custom_environment_expansion1(env, target, source, shell_env):
+ ENV = shell_env.copy()
+ ENV['EXPANDED_SHELL_VAR1'] = env.subst(env['ENV']['EXPANDED_SHELL_VAR1'], target=target, source=source)
+ return ENV
+
+def custom_environment_expansion2(env, target, source, shell_env):
+ ENV = shell_env.copy()
+ ENV['EXPANDED_SHELL_VAR2'] = env.subst(env['ENV']['EXPANDED_SHELL_VAR2'], target=target, source=source)
return ENV
def expand_this_generator(env, target, source, for_signature):
return "I_got_expanded_to_" + str(target[0])
+def expand_that_generator(env, target, source, for_signature):
+ return str(target[0]) + "_is_from_expansion"
+
env = Environment(tools=['textfile'])
-env['SHELL_ENV_GENERATOR'] = custom_environment_expansion
+env['SHELL_ENV_GENERATORS'] = [custom_environment_expansion1, custom_environment_expansion2]
env['EXPAND_THIS'] = expand_this_generator
-env['ENV']['EXPANDED_SHELL_VAR'] = "$EXPAND_THIS"
+env['EXPAND_THAT'] = expand_that_generator
+
+env['ENV']['EXPANDED_SHELL_VAR1'] = "$EXPAND_THIS"
+env['ENV']['EXPANDED_SHELL_VAR2'] = "$EXPAND_THAT"
env['ENV']['NON_EXPANDED_SHELL_VAR'] = "$EXPAND_THIS"
env.Textfile('expand_script.py', [
'import os',
- 'print(os.environ["EXPANDED_SHELL_VAR"])',
+ 'print(os.environ["EXPANDED_SHELL_VAR1"])',
+ 'print(os.environ["EXPANDED_SHELL_VAR2"])',
'print(os.environ["NON_EXPANDED_SHELL_VAR"])',
])
env.Command('out.txt', 'expand_script.py', fr'{sys.executable} $SOURCE > $TARGET')
diff --git a/test/Actions/subst_shell_env.py b/test/Actions/subst_shell_env.py
index 9f5c5db..d26f0ae 100644
--- a/test/Actions/subst_shell_env.py
+++ b/test/Actions/subst_shell_env.py
@@ -36,8 +36,8 @@ test = TestSCons.TestSCons()
test.dir_fixture('subst_shell_env-fixture')
test.run(arguments = ['-Q'])
-test.must_match('out.txt', f"I_got_expanded_to_out.txt{os.linesep}$EXPAND_THIS{os.linesep}")
-test.must_match('out2.txt', f"I_got_expanded_to_out2.txt{os.linesep}$EXPAND_THIS{os.linesep}")
+test.must_match('out.txt', f"I_got_expanded_to_out.txt{os.linesep}out.txt_is_from_expansion{os.linesep}$EXPAND_THIS{os.linesep}")
+test.must_match('out2.txt', f"I_got_expanded_to_out2.txt{os.linesep}out2.txt_is_from_expansion{os.linesep}$EXPAND_THIS{os.linesep}")
test.pass_test()
--
cgit v0.12
From c02b362bcb03bb74bfba8fb26636397f357a8cfa Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Mon, 23 May 2022 23:11:50 -0500
Subject: fix sider complaint
---
SCons/Action.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/SCons/Action.py b/SCons/Action.py
index 4dd0543..7de8454 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -108,6 +108,7 @@ import subprocess
from subprocess import DEVNULL
import inspect
from collections import OrderedDict
+from typing import Type
import SCons.Debug
from SCons.Debug import logInstanceCreation
@@ -762,7 +763,7 @@ def _resolve_shell_env(env, target, source):
ENV = ENV.copy()
try:
shell_gens = iter(shell_gen)
- except:
+ except TypeError:
raise SCons.Errors.UserError("SHELL_ENV_GENERATORS must be iteratable.")
else:
for generator in shell_gens:
--
cgit v0.12
From cc5a1aa155a3bb95a0f573e01e5cf09fe7f30e90 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Mon, 23 May 2022 23:14:04 -0500
Subject: removed auto type
---
SCons/Action.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/SCons/Action.py b/SCons/Action.py
index 7de8454..172e74e 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -108,7 +108,6 @@ import subprocess
from subprocess import DEVNULL
import inspect
from collections import OrderedDict
-from typing import Type
import SCons.Debug
from SCons.Debug import logInstanceCreation
--
cgit v0.12
From 4b9a5534225b93fc7038c8d801bb6652699bb97c Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Mon, 23 May 2022 23:15:37 -0500
Subject: move ENV copy to more optimal location
---
SCons/Action.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Action.py b/SCons/Action.py
index 172e74e..38570ce 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -759,12 +759,12 @@ def _resolve_shell_env(env, target, source):
ENV = get_default_ENV(env)
shell_gen = env.get('SHELL_ENV_GENERATORS')
if shell_gen is not None:
- ENV = ENV.copy()
try:
shell_gens = iter(shell_gen)
except TypeError:
raise SCons.Errors.UserError("SHELL_ENV_GENERATORS must be iteratable.")
else:
+ ENV = ENV.copy()
for generator in shell_gens:
ENV = generator(env, target, source, ENV)
if not isinstance(ENV, dict):
--
cgit v0.12
From cdb1d2163a927981e9dab9f977094537e7b0d959 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Sun, 15 May 2022 09:44:59 -0600
Subject: Try to improve variantdir docs [skip appveyor]
Reorder some bits, add some explantaions, include example of
passing different environments to subsidiary SConscript.
Signed-off-by: Mats Wichmann
---
SCons/Environment.xml | 64 ++++++++++++++++++++++-----------------------
SCons/Script/SConscript.xml | 56 ++++++++++++++++++---------------------
2 files changed, 57 insertions(+), 63 deletions(-)
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index 3a6df97..79289c3 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -3416,42 +3416,35 @@ env.UpdateValue(target = Value(output), source = Value(input))
-Sets up an alternate build location.
-When building in the variant_dir,
-&SCons; backfills as needed with files from src_dir
-to create a complete build directory.
+Sets up a mapping to define a variant build directory
+variant_dir,
+which must be in or underneath the project top directory.
+src_dir may not be underneath
+variant_dir.
+A &f-VariantDir; mapping is global, even if called using the
+the &f-env-VariantDir; form.
&f-VariantDir;
can be called multiple times with the same
src_dir
-to set up multiple builds with different options
-(variants).
-
-
-
-The
-variant
-location must be in or underneath the project top directory,
-and src_dir
-may not be underneath
-variant_dir.
+to set up multiple variant builds with different options.
+When files in variant_dir are referenced,
+&SCons; backfills as needed with files from src_dir
+to create a complete build directory.
By default, &SCons;
-physically duplicates the source files and SConscript files
-as needed into the variant tree.
-Thus, a build performed in the variant tree is guaranteed to be identical
-to a build performed in the source tree even if
+physically duplicates the source files, SConscript files,
+and directory structure as needed into the variant directory.
+Thus, a build performed in the variant directory is guaranteed to be identical
+to a build performed in the source directory even if
intermediate source files are generated during the build,
or if preprocessors or other scanners search for included files
-relative to the source file,
+using paths relative to the source file,
or if individual compilers or other invoked tools are hard-coded
to put derived files in the same directory as source files.
Only the files &SCons; calculates are needed for the build are
duplicated into variant_dir.
-
-
-
If possible on the platform,
the duplication is performed by linking rather than copying.
This behavior is affected by the
@@ -3470,38 +3463,43 @@ to invoke Builders using the path names of source files in
src_dir
and the path names of derived files within
variant_dir.
-This is more efficient than
-duplicate=True,
+This is more efficient than duplicating,
and is safe for most builds;
-revert to True
+revert to duplicate=True
if it causes problems.
&f-VariantDir;
works most naturally with used with a subsidiary SConscript file.
-The subsidiary SConscript file is called as if it
-were in
+The subsidiary SConscript file must be called as if it were in
variant_dir,
regardless of the value of
duplicate.
+When calling an SConscript file,
+you can pass an appropriately set up environment
+using the exports keyword
+argument so the SConscript can pick up the right settings
+for that variant build.
This is how you tell
&scons;
-which variant of a source tree to build:
+which variant of a source directory to build:
+env1 = Environment(...settings for variant1...)
+env2 = Environment(...settings for variant2...)
+
# run src/SConscript in two variant directories
VariantDir('build/variant1', 'src')
-SConscript('build/variant1/SConscript')
+SConscript('build/variant1/SConscript', exports={"env": env1})
VariantDir('build/variant2', 'src')
-SConscript('build/variant2/SConscript')
+SConscript('build/variant2/SConscript', exports={"env": env2})
See also the
-&f-link-SConscript;
-function, described above,
+&f-link-SConscript; function
for another way to specify a variant directory
in conjunction with calling a subsidiary SConscript file.
diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml
index 3c5b907..0710ea5 100644
--- a/SCons/Script/SConscript.xml
+++ b/SCons/Script/SConscript.xml
@@ -368,7 +368,7 @@ Return('val1 val2')
-Execute one or more subsidiary SConscript (configuration) files.
+Executes one or more subsidiary SConscript (configuration) files.
There are two ways to call the
&f-SConscript; function.
@@ -395,8 +395,8 @@ config = SConscript('MyConfig.py')
The second way to call
&f-SConscript;
-is to specify a list of (sub)directory names
-as a
+is to specify a list of directory names
+using the
dirs=subdirs
keyword argument.
In this case,
@@ -448,38 +448,24 @@ SConscript(dirs=['one', 'two', 'three'], exports='shared_info')
If the optional
variant_dir
argument is present, it causes an effect equivalent to the
-&f-link-VariantDir; function.
+&f-link-VariantDir; function,
+but in effect only during the execution of the SConscript file.
The variant_dir
-argument is interpreted relative to the directory of the calling
-SConscript file.
-The optional
-duplicate argument is
-interpreted as for &f-link-VariantDir;.
-If variant_dir
-is omitted, the duplicate argument is ignored.
-See the description of
-&f-link-VariantDir;
-below for additional details and restrictions.
-
-
-
-If
-variant_dir
-is present,
-the source directory is the directory in which the
-SConscript
-file resides and the
-SConscript
+argument is interpreted relative to the directory of the
+calling SConscript file.
+The source directory is the directory in which the
+called SConscript
+file resides and the SConscript
file is evaluated as if it were in the
variant_dir
-directory:
+directory. Thus:
SConscript('src/SConscript', variant_dir='build')
-is equivalent to
+is equivalent to:
@@ -488,9 +474,8 @@ SConscript('build/SConscript')
-This later paradigm is often used when the sources are
-in the same directory as the
-&SConstruct;:
+If the sources are in the same directory as the
+&SConstruct;,
@@ -498,7 +483,7 @@ SConscript('SConscript', variant_dir='build')
-is equivalent to
+is equivalent to:
@@ -507,6 +492,17 @@ SConscript('build/SConscript')
+The optional
+duplicate argument is
+interpreted as for &f-link-VariantDir;.
+If the variant_dir argument
+is omitted, the duplicate argument is ignored.
+See the description of
+&f-link-VariantDir;
+for additional details and restrictions.
+
+
+
-(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist])
-
+(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist])
+
@@ -374,31 +374,27 @@ There are two ways to call the
-The first calling style
-is to explicitly specify one or more
-scripts
-as the first argument.
+The first calling style is to supply
+one or more SConscript file names
+as the first (positional) argument.
A single script may be specified as a string;
-multiple scripts must be specified as a list
+multiple scripts must be specified as a list of strings
(either explicitly or as created by
a function like
&f-link-Split;).
Examples:
-SConscript('SConscript') # run SConscript in the current directory
+SConscript('SConscript') # run SConscript in the current directory
SConscript('src/SConscript') # run SConscript in the src directory
SConscript(['src/SConscript', 'doc/SConscript'])
config = SConscript('MyConfig.py')
-The second way to call
-&f-SConscript;
-is to specify a list of directory names
-using the
-dirs=subdirs
-keyword argument.
+The other calling style is to omit the positional argument naming
+scripts and instead specify a list of directory names using the
+dirs keyword argument.
In this case,
&scons;
will
@@ -408,14 +404,13 @@ in each of the specified directories.
You may specify a name other than
&SConscript;
by supplying an optional
-name=script
-keyword argument.
+name keyword argument.
The first three examples below have the same effect
as the first three examples above:
-SConscript(dirs='.') # run SConscript in the current directory
-SConscript(dirs='src') # run SConscript in the src directory
+SConscript(dirs='.') # run SConscript in the current directory
+SConscript(dirs='src') # run SConscript in the src directory
SConscript(dirs=['src', 'doc'])
SConscript(dirs=['sub1', 'sub2'], name='MySConscript')
@@ -423,8 +418,12 @@ SConscript(dirs=['sub1', 'sub2'], name='MySConscript')
The optional
exports
-argument provides a string or list of strings representing
+keyword argument provides a string or list of strings representing
variable names, or a dictionary of named values, to export.
+For the first calling style only, a second positional argument
+will be interpreted as exports; the
+second calling style must use the keyword argument form
+for exports.
These variables are locally exported only to the called
SConscript file(s)
and do not affect the global pool of variables managed by the
@@ -585,11 +584,11 @@ SConscript('src/SConscript', variant_dir='build/ppc', duplicate=0)
&f-SConscript; returns the values of any variables
-named by the executed SConscript(s) in arguments
-to the &f-link-Return; function (see above for details).
+named by the executed SConscript file(s) in arguments
+to the &f-link-Return; function.
If a single &f-SConscript; call causes multiple scripts to
be executed, the return value is a tuple containing
-the returns of all of the scripts. If an executed
+the returns of each of the scripts. If an executed
script does not explicitly call &Return;, it returns
None.
--
cgit v0.12
From 45e9eec5a86adcd815a9bebfba536a44c7f9a756 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Tue, 17 May 2022 09:01:11 -0600
Subject: Fix grammar error ("the the") [ci skip]
Signed-off-by: Mats Wichmann
---
SCons/Environment.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index 3700a44..346fc75 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -3421,7 +3421,7 @@ Sets up a mapping to define a variant build directory in
src_dir may not be underneath
variant_dir.
A &f-VariantDir; mapping is global, even if called using the
-the &f-env-VariantDir; form.
+&f-env-VariantDir; form.
&f-VariantDir;
can be called multiple times with the same
src_dir
--
cgit v0.12
From b14c20e353712291e0321c0fa1e7557bf385ea04 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Mon, 23 May 2022 08:18:51 -0600
Subject: Further tweak of VariantDir doc [skip appveyor]
Signed-off-by: Mats Wichmann
---
SCons/Environment.xml | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index 346fc75..294562d 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -3482,14 +3482,11 @@ The subsidiary SConscript file must be called as if it were in
variant_dir,
regardless of the value of
duplicate.
-When calling an SConscript file,
-you can pass an appropriately set up environment
-using the exports keyword
-argument so the SConscript can pick up the right settings
-for that variant build.
-This is how you tell
-&scons;
-which variant of a source directory to build:
+When calling an SConscript file, you can use the
+exports keyword argument
+to pass parameters (individually or as an appropriately set up environment)
+so the SConscript can pick up the right settings for that variant build.
+The SConscript must &f-link-Import; these to use them. Example:
@@ -3511,7 +3508,7 @@ in conjunction with calling a subsidiary SConscript file.
-Examples:
+More examples:
--
cgit v0.12
From cf2641d678eb6142f5f00e686f8e4d46959267ee Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Wed, 25 May 2022 13:31:38 -0600
Subject: Typo fix [ci skip]
Signed-off-by: Mats Wichmann
---
SCons/Environment.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index 294562d..5c4326c 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -318,7 +318,7 @@ Added methods propagate through &f-env-Clone; calls.
-Examples:
+More examples:
@@ -3477,7 +3477,7 @@ if it causes problems.
&f-VariantDir;
-works most naturally with used with a subsidiary SConscript file.
+works most naturally when used with a subsidiary SConscript file.
The subsidiary SConscript file must be called as if it were in
variant_dir,
regardless of the value of
--
cgit v0.12
From a4daaa6d49f7f5972e8d7d083d492068b1a5d362 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Thu, 26 May 2022 06:41:09 -0600
Subject: SConscript doc tweaks per #4150 review comments [skip appveyor]
Signed-off-by: Mats Wichmann
---
SCons/Script/SConscript.xml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml
index 17c9236..eb52acc 100644
--- a/SCons/Script/SConscript.xml
+++ b/SCons/Script/SConscript.xml
@@ -404,7 +404,8 @@ in each of the specified directories.
You may specify a name other than
&SConscript;
by supplying an optional
-name keyword argument.
+name=scriptname
+keyword argument.
The first three examples below have the same effect
as the first three examples above:
@@ -448,7 +449,7 @@ If the optional
variant_dir
argument is present, it causes an effect equivalent to the
&f-link-VariantDir; function,
-but in effect only during the execution of the SConscript file.
+but in effect only within the scope of the &f-SConscript; call.
The variant_dir
argument is interpreted relative to the directory of the
calling SConscript file.
--
cgit v0.12
From 9f6cfbdd5dc35a9711e5c5ab5ef3414b4a05e0ef Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Thu, 26 May 2022 22:58:55 -0500
Subject: collapsed related CHANGES comments
---
CHANGES.txt | 9 +++------
RELEASE.txt | 9 +++------
2 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 60e934f..d5aba9f 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -99,12 +99,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected
format. Compiler tools will also configure the variable automatically.
- - Added SHELL_ENV_GENERATOR construction variable. This variable allows the user to Define
- a function which will be called to generate or alter the execution environment which will
- be used in the shell command of some Action.
- - Updated SHELL_ENV_GENERATOR construction variable to SHELL_ENV_GENERATORS. This variable
- is now an iterable which will contain functions which each are called and each can customize
- the execution environment.
+ - Added SHELL_ENV_GENERATORS construction variable. This variable
+ is an iterable which will contain functions in which each are called and each can allow
+ the user a method to customize the execution environment.
- Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
- Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry
to connect to the server during start up.
diff --git a/RELEASE.txt b/RELEASE.txt
index 38fbbd7..195e325 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -16,12 +16,9 @@ NEW FUNCTIONALITY
- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT.
- Added Configure.CheckMember() checker to check if struct/class has the specified member.
-- Added SHELL_ENV_GENERATOR construction variables. This variable allows the user to Define
- a function which will be called to generate or alter the execution environment which will
- be used in the shell command of some Action.
-- Updated SHELL_ENV_GENERATOR construction variable to SHELL_ENV_GENERATORS. This variable
- is now an iterable which will contain functions which each are called and each can customize
- the execution environment.
+- Added SHELL_ENV_GENERATORS construction variable. This variable
+ is an iterable which will contain functions in which each are called and each can allow
+ the user a method to customize the execution environment.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
--
cgit v0.12
From f262fbd6bacf1c0d7f26d747d853b9ce909f4442 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Thu, 26 May 2022 23:03:13 -0500
Subject: fix missing f string
---
SCons/Action.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Action.py b/SCons/Action.py
index 38570ce..e29c4e9 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -768,7 +768,7 @@ def _resolve_shell_env(env, target, source):
for generator in shell_gens:
ENV = generator(env, target, source, ENV)
if not isinstance(ENV, dict):
- raise SCons.Errors.UserError("SHELL_ENV_GENERATORS function: {generator} must return a dict.")
+ raise SCons.Errors.UserError(f"SHELL_ENV_GENERATORS function: {generator} must return a dict.")
return ENV
--
cgit v0.12
From 150197f2273fa639aa4815a68f9bcd38d3068a8d Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Mon, 30 May 2022 12:28:57 -0600
Subject: Fix some Py 3.11 depr warns in tests
A couple of unittest methods that a few SCons tests use have
been marked deprecated in Python 3.11, with replacements provided.
Partial fix for #4162, do not close just off this PR.
Signed-off-by: Mats Wichmann
---
CHANGES.txt | 2 ++
SCons/Scanner/ScannerTests.py | 4 +++-
SCons/Tool/ToolTests.py | 4 +++-
SCons/Tool/msvsTests.py | 4 +++-
SCons/cppTests.py | 4 +++-
testing/framework/TestCmdTests.py | 6 ++++--
testing/framework/TestCommonTests.py | 6 ++++--
7 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 9a6a26f..7d3eadb 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -93,6 +93,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
"dict" (avoid redefining builtin)
- Fix an old use-before-set bug in tex tool (issue #2888)
- Fix a test harness exception returning stderr if a wait_for timed out.
+ - Modernize a few tests that use now-deprecated unittest.getTestCaseNames
+ and unittest.makeSuite - Python itself suggests the replacements.
From Zhichang Yu:
- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT.
diff --git a/SCons/Scanner/ScannerTests.py b/SCons/Scanner/ScannerTests.py
index 68332a0..b9cb209 100644
--- a/SCons/Scanner/ScannerTests.py
+++ b/SCons/Scanner/ScannerTests.py
@@ -621,7 +621,9 @@ def suite():
ClassicCPPTestCase,
]
for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ names = loader.getTestCaseNames(tclass)
suite.addTests(list(map(tclass, names)))
return suite
diff --git a/SCons/Tool/ToolTests.py b/SCons/Tool/ToolTests.py
index 7cff7c8..9338c2d 100644
--- a/SCons/Tool/ToolTests.py
+++ b/SCons/Tool/ToolTests.py
@@ -116,7 +116,9 @@ class ToolTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.makeSuite(ToolTestCase, 'test_')
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ suite = loader.loadTestsFromTestCase(ToolTestCase)
TestUnit.run(suite)
# Local Variables:
diff --git a/SCons/Tool/msvsTests.py b/SCons/Tool/msvsTests.py
index 4cbaf0e..c4d2e98 100644
--- a/SCons/Tool/msvsTests.py
+++ b/SCons/Tool/msvsTests.py
@@ -982,7 +982,9 @@ if __name__ == "__main__":
if k in os.environ:
del os.environ[k]
- suite = unittest.makeSuite(test_class, 'test_')
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ suite = loader.loadTestsFromTestCase(test_class)
if not TestUnit.cli.get_runner()().run(suite).wasSuccessful():
exit_val = 1
finally:
diff --git a/SCons/cppTests.py b/SCons/cppTests.py
index a9aef9d..f20c302 100644
--- a/SCons/cppTests.py
+++ b/SCons/cppTests.py
@@ -876,7 +876,9 @@ if __name__ == '__main__':
fileTestCase,
]
for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ names = loader.getTestCaseNames(tclass)
try:
names = sorted(set(names))
except NameError:
diff --git a/testing/framework/TestCmdTests.py b/testing/framework/TestCmdTests.py
index 212c59a..3b29091 100644
--- a/testing/framework/TestCmdTests.py
+++ b/testing/framework/TestCmdTests.py
@@ -3389,8 +3389,10 @@ if __name__ == "__main__":
])
suite = unittest.TestSuite()
for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests([ tclass(n) for n in names ])
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ names = loader.getTestCaseNames(tclass)
+ suite.addTests([tclass(n) for n in names])
if not unittest.TextTestRunner().run(suite).wasSuccessful():
sys.exit(1)
diff --git a/testing/framework/TestCommonTests.py b/testing/framework/TestCommonTests.py
index 03a5508..dff7a50 100644
--- a/testing/framework/TestCommonTests.py
+++ b/testing/framework/TestCommonTests.py
@@ -2429,8 +2429,10 @@ if __name__ == "__main__":
]
suite = unittest.TestSuite()
for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests([ tclass(n) for n in names ])
+ loader = unittest.TestLoader()
+ loader.testMethodPrefix = 'test_'
+ names = loader.getTestCaseNames(tclass)
+ suite.addTests([tclass(n) for n in names])
if not unittest.TextTestRunner().run(suite).wasSuccessful():
sys.exit(1)
--
cgit v0.12
From c7272c7367f1c3f819645d996c6d93449cf14f5b Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Fri, 13 May 2022 08:18:22 -0600
Subject: Normalize use of test.sleep()
Some tests used time.sleep while others used the harness's test.sleep,
the ones that are done for file timestamp delay management now all use
test.sleep - with a consistent comment, so it's easier to spot.
There are still tests that use time.sleep with smaller intervals that
were left alone.
Affected tests were reformatted, in the spirit of gradually improving
tests that you otherwise touch...
Signed-off-by: Mats Wichmann
---
test/CacheDir/timestamp-match.py | 25 ++--
test/CacheDir/timestamp-newer.py | 24 ++--
test/Copy-Action.py | 70 +++++-----
test/Decider/MD5-timestamp-Repository.py | 20 +--
test/Decider/MD5-timestamp.py | 21 +--
test/Decider/timestamp.py | 23 +---
test/Dir/source.py | 85 +++++++------
test/Libs/LIBPATH.py | 71 +++++------
test/PharLap.py | 19 ++-
test/Program.py | 87 ++++++-------
test/Repository/no-SConsignFile.py | 14 +-
test/Repository/variants.py | 212 +++++++++++++++----------------
test/Touch.py | 35 +++--
test/chained-build.py | 62 +++++----
test/sconsign/script/Signatures.py | 26 ++--
test/sconsign/script/dblite.py | 45 +++----
16 files changed, 378 insertions(+), 461 deletions(-)
diff --git a/test/CacheDir/timestamp-match.py b/test/CacheDir/timestamp-match.py
index 4b64137..fd9c659 100644
--- a/test/CacheDir/timestamp-match.py
+++ b/test/CacheDir/timestamp-match.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that CAcheDir() works when using 'timestamp-match' decisions.
@@ -41,21 +40,15 @@ Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
test.write('file.in', "file.in\n")
-test.run(arguments = '--cache-show --debug=explain .')
-
+test.run(arguments='--cache-show --debug=explain .')
test.must_match('file.out', "file.in\n")
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.sleep()
-
+test.sleep() # delay for timestamps
test.touch('file.in')
-
-test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+test.not_up_to_date(options='--cache-show --debug=explain', arguments='.')
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
test.pass_test()
diff --git a/test/CacheDir/timestamp-newer.py b/test/CacheDir/timestamp-newer.py
index 618f467..567078e 100644
--- a/test/CacheDir/timestamp-newer.py
+++ b/test/CacheDir/timestamp-newer.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that CAcheDir() works when using 'timestamp-newer' decisions.
@@ -41,21 +40,16 @@ Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
test.write('file.in', "file.in\n")
-test.run(arguments = '--cache-show --debug=explain .')
-
+test.run(arguments='--cache-show --debug=explain .')
test.must_match('file.out', "file.in\n")
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.sleep()
-
+test.sleep() # delay for timestamps
test.touch('file.in')
-test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
-
-test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+test.not_up_to_date(options='--cache-show --debug=explain', arguments='.')
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
+test.up_to_date(options='--cache-show --debug=explain', arguments='.')
test.pass_test()
diff --git a/test/Copy-Action.py b/test/Copy-Action.py
index 4bfa0da..2179744 100644
--- a/test/Copy-Action.py
+++ b/test/Copy-Action.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that the Copy() Action works, and preserves file modification
@@ -37,29 +36,32 @@ import TestSCons
test = TestSCons.TestSCons()
-test.write('SConstruct', """
+test.write('SConstruct', """\
Execute(Copy('f1.out', 'f1.in'))
Execute(Copy(File('d2.out'), 'd2.in'))
Execute(Copy('d3.out', File('f3.in')))
+
def cat(env, source, target):
target = str(target[0])
with open(target, "w") as f:
for src in source:
with open(str(src), "r") as ifp:
f.write(ifp.read())
+
Cat = Action(cat)
env = Environment()
-env.Command('bar.out', 'bar.in', [Cat,
- Copy("f4.out", "f4.in"),
- Copy("d5.out", "d5.in"),
- Copy("d6.out", "f6.in")])
-env = Environment(OUTPUT = 'f7.out', INPUT = 'f7.in')
+env.Command(
+ 'bar.out',
+ 'bar.in',
+ [Cat, Copy("f4.out", "f4.in"), Copy("d5.out", "d5.in"), Copy("d6.out", "f6.in")],
+)
+env = Environment(OUTPUT='f7.out', INPUT='f7.in')
env.Command('f8.out', 'f8.in', [Copy('$OUTPUT', '$INPUT'), Cat])
env.Command('f9.out', 'f9.in', [Cat, Copy('${TARGET}-Copy', '$SOURCE')])
-env.CopyTo( 'd4', 'f10.in' )
-env.CopyAs( 'd4/f11.out', 'f11.in')
-env.CopyAs( 'd4/f12.out', 'd5/f12.in')
+env.CopyTo('d4', 'f10.in')
+env.CopyAs('d4/f11.out', 'f11.in')
+env.CopyAs('d4/f12.out', 'd5/f12.in')
env.Command('f 13.out', 'f 13.in', Copy('$TARGET', '$SOURCE'))
""")
@@ -87,19 +89,20 @@ test.write('f 13.in', "f 13.in\n")
os.chmod('f1.in', 0o646)
os.chmod('f4.in', 0o644)
-test.sleep()
+test.sleep() # delay for timestamps
d4_f10_in = os.path.join('d4', 'f10.in')
d4_f11_out = os.path.join('d4', 'f11.out')
d4_f12_out = os.path.join('d4', 'f12.out')
d5_f12_in = os.path.join('d5', 'f12.in')
-expect = test.wrap_stdout(read_str = """\
+expect = test.wrap_stdout(
+ read_str="""\
Copy("f1.out", "f1.in")
Copy("d2.out", "d2.in")
Copy("d3.out", "f3.in")
""",
- build_str = """\
+ build_str="""\
cat(["bar.out"], ["bar.in"])
Copy("f4.out", "f4.in")
Copy("d5.out", "d5.in")
@@ -112,9 +115,10 @@ Copy("f7.out", "f7.in")
cat(["f8.out"], ["f8.in"])
cat(["f9.out"], ["f9.in"])
Copy("f9.out-Copy", "f9.in")
-""" % locals())
+""" % locals(),
+)
-test.run(options = '-n', arguments = '.', stdout = expect)
+test.run(options='-n', arguments='.', stdout=expect)
test.must_not_exist('f1.out')
test.must_not_exist('d2.out')
@@ -162,23 +166,21 @@ def must_be_same(f1, f2):
for value in ['ST_MODE', 'ST_MTIME']:
v = getattr(stat, value)
if s1[v] != s2[v]:
- msg = '%s[%s] %s != %s[%s] %s\n' % \
- (repr(f1), value, s1[v],
- repr(f2), value, s2[v],)
+ msg = f"{f1!r}[{value}] {s1[v1]} != {f2!r}[{value}] {s2[v]}\n"
sys.stderr.write(msg)
- errors = errors + 1
-
-must_be_same('f1.out', 'f1.in')
-must_be_same(['d2.out', 'file'], ['d2.in', 'file'])
-must_be_same(['d3.out', 'f3.in'], 'f3.in')
-must_be_same('f4.out', 'f4.in')
-must_be_same(['d5.out', 'file'], ['d5.in', 'file'])
-must_be_same(['d6.out', 'f6.in'], 'f6.in')
-must_be_same('f7.out', 'f7.in')
-must_be_same(['d4', 'f10.in'], 'f10.in')
-must_be_same(['d4', 'f11.out'], 'f11.in')
-must_be_same(['d4', 'f12.out'], ['d5', 'f12.in'])
-must_be_same('f 13.out', 'f 13.in')
+ errors += 1
+
+must_be_same('f1.out', 'f1.in')
+must_be_same(['d2.out', 'file'], ['d2.in', 'file'])
+must_be_same(['d3.out', 'f3.in'], 'f3.in')
+must_be_same('f4.out', 'f4.in')
+must_be_same(['d5.out', 'file'], ['d5.in', 'file'])
+must_be_same(['d6.out', 'f6.in'], 'f6.in')
+must_be_same('f7.out', 'f7.in')
+must_be_same(['d4', 'f10.in'], 'f10.in')
+must_be_same(['d4', 'f11.out'], 'f11.in')
+must_be_same(['d4', 'f12.out'], ['d5', 'f12.in'])
+must_be_same('f 13.out', 'f 13.in')
if errors:
test.fail_test()
diff --git a/test/Decider/MD5-timestamp-Repository.py b/test/Decider/MD5-timestamp-Repository.py
index 1826f68..201bdfe 100644
--- a/test/Decider/MD5-timestamp-Repository.py
+++ b/test/Decider/MD5-timestamp-Repository.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify behavior of the MD5-timestamp Decider() setting when combined with Repository() usage
@@ -38,13 +37,11 @@ test = TestSCons.TestSCons()
test.subdir('Repository', 'work')
repository = test.workpath('Repository')
-
test.write(['Repository','content1.in'], "content1.in 1\n")
test.write(['Repository','content2.in'], "content2.in 1\n")
test.write(['Repository','content3.in'], "content3.in 1\n")
# test.writable('Repository', 0)
-
test.write(['work','SConstruct'], """\
Repository(r'%s')
DefaultEnvironment(tools=[])
@@ -53,18 +50,14 @@ m.Decider('MD5-timestamp')
m.Command('content1.out', 'content1.in', Copy('$TARGET', '$SOURCE'))
m.Command('content2.out', 'content2.in', Copy('$TARGET', '$SOURCE'))
m.Command('content3.out', 'content3.in', Copy('$TARGET', '$SOURCE'))
-"""%repository)
+""" % repository)
test.run(chdir='work',arguments='.')
-
test.up_to_date(chdir='work',arguments='.')
-test.sleep()
-
+test.sleep() # delay for timestamps
test.write(['Repository','content1.in'], "content1.in 2\n")
-
test.touch(['Repository','content2.in'])
-
time_content = os.stat(os.path.join(repository,'content3.in'))[stat.ST_MTIME]
test.write(['Repository','content3.in'], "content3.in 2\n")
test.touch(['Repository','content3.in'], time_content)
@@ -76,10 +69,9 @@ test.touch(['Repository','content3.in'], time_content)
expect = test.wrap_stdout("""\
Copy("content1.out", "%s")
-"""%os.path.join(repository,'content1.in'))
+""" % os.path.join(repository, 'content1.in'))
test.run(chdir='work', arguments='.', stdout=expect)
-
test.up_to_date(chdir='work', arguments='.')
test.pass_test()
diff --git a/test/Decider/MD5-timestamp.py b/test/Decider/MD5-timestamp.py
index 6fcdb42..3815639 100644
--- a/test/Decider/MD5-timestamp.py
+++ b/test/Decider/MD5-timestamp.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify behavior of the MD5-timestamp Decider() setting.
@@ -49,15 +48,10 @@ test.write('content2.in', "content2.in 1\n")
test.write('content3.in', "content3.in 1\n")
test.run(arguments = '.')
-
test.up_to_date(arguments = '.')
-
-
-test.sleep()
-
+test.sleep() # delay for timestamps
test.write('content1.in', "content1.in 2\n")
-
test.touch('content2.in')
time_content = os.stat('content3.in')[stat.ST_MTIME]
@@ -73,11 +67,8 @@ expect = test.wrap_stdout("""\
Copy("content1.out", "content1.in")
""")
-test.run(arguments = '.', stdout=expect)
-
-test.up_to_date(arguments = '.')
-
-
+test.run(arguments='.', stdout=expect)
+test.up_to_date(arguments='.')
test.pass_test()
diff --git a/test/Decider/timestamp.py b/test/Decider/timestamp.py
index e528d77..d713a62 100644
--- a/test/Decider/timestamp.py
+++ b/test/Decider/timestamp.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify various interactions of the timestamp-match and timestamp-newer
@@ -54,27 +53,21 @@ test.write('newer1.in', "newer1.in\n")
test.write('newer2.in', "newer2.in\n")
test.run(arguments = '.')
-
test.up_to_date(arguments = '.')
time_match = os.stat('match2.out')[stat.ST_MTIME]
time_newer = os.stat('newer2.out')[stat.ST_MTIME]
-
-
# Now make all the source files newer than (different timestamps from)
# the last time the targets were built, and touch the target files
# of match1.out and newer1.out to see the different effects.
-
-test.sleep()
-
+test.sleep() # delay for timestamps
test.touch('match1.in')
test.touch('newer1.in')
test.touch('match2.in')
test.touch('newer2.in')
-test.sleep()
-
+test.sleep() # delay for timestamps
test.touch('match1.out')
test.touch('newer1.out')
@@ -90,7 +83,7 @@ Copy("match2.out", "match2.in")
Copy("newer2.out", "newer2.in")
""")
-test.run(arguments = '.', stdout=expect)
+test.run(arguments='.', stdout=expect)
# Now, for the somewhat pathological case, reset the match2.out and
# newer2.out timestamps to the older timestamp when the targets were
@@ -107,9 +100,7 @@ expect = test.wrap_stdout("""\
Copy("newer2.out", "newer2.in")
""")
-test.run(arguments = '.', stdout=expect)
-
-
+test.run(arguments='.', stdout=expect)
test.pass_test()
diff --git a/test/Dir/source.py b/test/Dir/source.py
index c35d169..a0ba987 100644
--- a/test/Dir/source.py
+++ b/test/Dir/source.py
@@ -42,15 +42,16 @@ test.subdir('tstamp', [ 'tstamp', 'subdir' ],
test.write('SConstruct', """\
DefaultEnvironment(tools=[])
+
def writeTarget(target, source, env):
- f=open(str(target[0]), 'w')
+ f = open(str(target[0]), 'w')
f.write("stuff\\n")
f.close()
return 0
-test_bld_dir = Builder(action=writeTarget,
- source_factory=Dir,
- source_scanner=DirScanner)
+test_bld_dir = Builder(
+ action=writeTarget, source_factory=Dir, source_scanner=DirScanner
+)
test_bld_file = Builder(action=writeTarget)
env = Environment(tools=[])
env['BUILDERS']['TestDir'] = test_bld_dir
@@ -61,34 +62,36 @@ env_tstamp.Decider('timestamp-newer')
env_tstamp.TestFile(source='junk.txt', target='tstamp/junk.out')
env_tstamp.TestDir(source='tstamp', target='tstamp.out')
env_tstamp.Command('cmd-tstamp-noscan.out', 'cmd-tstamp', writeTarget)
-env_tstamp.Command('cmd-tstamp.out', 'cmd-tstamp', writeTarget,
- source_scanner=DirScanner)
+env_tstamp.Command(
+ 'cmd-tstamp.out', 'cmd-tstamp', writeTarget, source_scanner=DirScanner
+)
env_content = env.Clone()
env_content.Decider('content')
env_content.TestFile(source='junk.txt', target='content/junk.out')
env_content.TestDir(source='content', target='content.out')
env_content.Command('cmd-content-noscan.out', 'cmd-content', writeTarget)
-env_content.Command('cmd-content.out', 'cmd-content', writeTarget,
- source_scanner=DirScanner)
+env_content.Command(
+ 'cmd-content.out', 'cmd-content', writeTarget, source_scanner=DirScanner
+)
""")
-test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'tstamp', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n')
-test.write([ 'tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n')
-test.write([ 'content', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'content', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'content', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'cmd-tstamp', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'cmd-tstamp', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'cmd-content', '#hash.txt' ], '#hash.txt 1\n')
-test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'cmd-content', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
+test.write(['tstamp', 'foo.txt'], 'foo.txt 1\n')
+test.write(['tstamp', '#hash.txt'], 'hash.txt 1\n')
+test.write(['tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n')
+test.write(['tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n')
+test.write(['content', 'foo.txt'], 'foo.txt 1\n')
+test.write(['content', '#hash.txt'], 'hash.txt 1\n')
+test.write(['content', 'subdir', 'bar.txt'], 'bar.txt 1\n')
+test.write(['content', 'subdir', '#hash.txt'], 'hash.txt 1\n')
+test.write(['cmd-tstamp', 'foo.txt'], 'foo.txt 1\n')
+test.write(['cmd-tstamp', '#hash.txt'], 'hash.txt 1\n')
+test.write(['cmd-tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n')
+test.write(['cmd-tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n')
+test.write(['cmd-content', 'foo.txt'], 'foo.txt 1\n')
+test.write(['cmd-content', '#hash.txt'], '#hash.txt 1\n')
+test.write(['cmd-content', 'subdir', 'bar.txt'], 'bar.txt 1\n')
+test.write(['cmd-content', 'subdir', '#hash.txt'], 'hash.txt 1\n')
test.write('junk.txt', 'junk.txt\n')
test.run(arguments=".", stderr=None)
@@ -106,61 +109,61 @@ test.up_to_date(arguments='cmd-content.out')
test.up_to_date(arguments='cmd-tstamp-noscan.out')
test.up_to_date(arguments='cmd-content-noscan.out')
-test.sleep()
+test.sleep() # delay for timestamps
-test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 2\n')
+test.write(['tstamp', 'foo.txt'], 'foo.txt 2\n')
test.not_up_to_date(arguments='tstamp.out')
-test.write([ 'tstamp', 'new.txt' ], 'new.txt\n')
+test.write(['tstamp', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='tstamp.out')
-test.write([ 'content', 'foo.txt' ], 'foo.txt 2\n')
+test.write(['content', 'foo.txt'], 'foo.txt 2\n')
test.not_up_to_date(arguments='content.out')
-test.write([ 'content', 'new.txt' ], 'new.txt\n')
+test.write(['content', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='content.out')
-test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 2\n')
+test.write(['cmd-tstamp', 'foo.txt'], 'foo.txt 2\n')
test.not_up_to_date(arguments='cmd-tstamp.out')
test.up_to_date(arguments='cmd-tstamp-noscan.out')
-test.write([ 'cmd-tstamp', 'new.txt' ], 'new.txt\n')
+test.write(['cmd-tstamp', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='cmd-tstamp.out')
test.up_to_date(arguments='cmd-tstamp-noscan.out')
-test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 2\n')
+test.write(['cmd-content', 'foo.txt'], 'foo.txt 2\n')
test.not_up_to_date(arguments='cmd-content.out')
test.up_to_date(arguments='cmd-content-noscan.out')
-test.write([ 'cmd-content', 'new.txt' ], 'new.txt\n')
+test.write(['cmd-content', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='cmd-content.out')
test.up_to_date(arguments='cmd-content-noscan.out')
-test.write([ 'tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.write(['tstamp', 'subdir', 'bar.txt'], 'bar.txt 2\n')
test.not_up_to_date(arguments='tstamp.out')
-test.write([ 'tstamp', 'subdir', 'new.txt' ], 'new.txt\n')
+test.write(['tstamp', 'subdir', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='tstamp.out')
-test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.write(['content', 'subdir', 'bar.txt'], 'bar.txt 2\n')
test.not_up_to_date(arguments='content.out')
-test.write([ 'content', 'subdir', 'new.txt' ], 'new.txt\n')
+test.write(['content', 'subdir', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='content.out')
-test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.write(['cmd-tstamp', 'subdir', 'bar.txt'], 'bar.txt 2\n')
test.not_up_to_date(arguments='cmd-tstamp.out')
test.up_to_date(arguments='cmd-tstamp-noscan.out')
-test.write([ 'cmd-tstamp', 'subdir', 'new.txt' ], 'new.txt\n')
+test.write(['cmd-tstamp', 'subdir', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='cmd-tstamp.out')
test.up_to_date(arguments='cmd-tstamp-noscan.out')
-test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.write(['cmd-content', 'subdir', 'bar.txt'], 'bar.txt 2\n')
test.not_up_to_date(arguments='cmd-content.out')
test.up_to_date(arguments='cmd-content-noscan.out')
-test.write([ 'cmd-content', 'subdir', 'new.txt' ], 'new.txt\n')
+test.write(['cmd-content', 'subdir', 'new.txt'], 'new.txt\n')
test.not_up_to_date(arguments='cmd-content.out')
test.up_to_date(arguments='cmd-content-noscan.out')
diff --git a/test/Libs/LIBPATH.py b/test/Libs/LIBPATH.py
index b5a1b54..d663e56 100644
--- a/test/Libs/LIBPATH.py
+++ b/test/Libs/LIBPATH.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,7 @@
# 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 time
@@ -40,20 +40,17 @@ test.subdir('lib1', 'lib2')
prog1 = test.workpath('prog') + _exe
prog2 = test.workpath(dll_ + 'shlib') + _dll
-test.write('SConstruct', """
-env1 = Environment(LIBS = [ 'foo1' ],
- LIBPATH = [ '$FOO' ],
- FOO='./lib1')
+test.write('SConstruct', """\
+env1 = Environment(LIBS=['foo1'], LIBPATH=['$FOO'], FOO='./lib1')
f1 = env1.SharedObject('f1', 'f1.c')
-env1.Program(target = 'prog', source = 'prog.c')
-env1.Library(target = './lib1/foo1', source = f1)
+env1.Program(target='prog', source='prog.c')
+env1.Library(target='./lib1/foo1', source=f1)
-env2 = Environment(LIBS = 'foo2',
- LIBPATH = '.')
-env2.SharedLibrary(target = 'shlib', source = 'shlib.c', no_import_lib = 1)
-env2.Library(target = 'foo2', source = f1)
+env2 = Environment(LIBS='foo2', LIBPATH='.')
+env2.SharedLibrary(target='shlib', source='shlib.c', no_import_lib=1)
+env2.Library(target='foo2', source=f1)
""")
test.write('f1.c', r"""
@@ -99,8 +96,8 @@ test.run(program = prog1,
oldtime1 = os.path.getmtime(prog1)
oldtime2 = os.path.getmtime(prog2)
-time.sleep(2)
-test.run(arguments = '.')
+test.sleep() # delay for timestamps
+test.run(arguments='.')
test.fail_test(oldtime1 != os.path.getmtime(prog1))
test.fail_test(oldtime2 != os.path.getmtime(prog2))
@@ -115,30 +112,25 @@ f1(void)
}
""")
-test.run(arguments = '.',
- stderr=TestSCons.noisy_ar,
- match=TestSCons.match_re_dotall)
-test.run(program = prog1,
- stdout = "f1.c 1\nprog.c\n")
+test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall)
+test.run(program=prog1, stdout="f1.c 1\nprog.c\n")
test.fail_test(oldtime2 == os.path.getmtime(prog2))
#test.up_to_date(arguments = '.')
# Change LIBPATH and make sure we don't rebuild because of it.
-test.write('SConstruct', """
-env1 = Environment(LIBS = [ 'foo1' ],
- LIBPATH = [ './lib1', './lib2' ])
+test.write('SConstruct', """\
+env1 = Environment(LIBS=['foo1'], LIBPATH=['./lib1', './lib2'])
f1 = env1.SharedObject('f1', 'f1.c')
-env1.Program(target = 'prog', source = 'prog.c')
-env1.Library(target = './lib1/foo1', source = f1)
+env1.Program(target='prog', source='prog.c')
+env1.Library(target='./lib1/foo1', source=f1)
-env2 = Environment(LIBS = 'foo2',
- LIBPATH = Split('. ./lib2'))
-env2.SharedLibrary(target = 'shlib', source = 'shlib.c', no_import_lib = 1)
-env2.Library(target = 'foo2', source = f1)
+env2 = Environment(LIBS='foo2', LIBPATH=Split('. ./lib2'))
+env2.SharedLibrary(target='shlib', source='shlib.c', no_import_lib=1)
+env2.Library(target='foo2', source=f1)
""")
-test.up_to_date(arguments = '.', stderr=None)
+test.up_to_date(arguments='.', stderr=None)
test.write('f1.c', r"""
#include
@@ -150,27 +142,22 @@ f1(void)
}
""")
-test.run(arguments = '.',
- stderr=TestSCons.noisy_ar,
- match=TestSCons.match_re_dotall)
-test.run(program = prog1,
- stdout = "f1.c 2\nprog.c\n")
+test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall)
+test.run(program=prog1, stdout="f1.c 2\nprog.c\n")
-test.up_to_date(arguments = '.')
+test.up_to_date(arguments='.')
# We need at least one file for some implementations of the Library
# builder, notably the SGI one.
test.write('empty.c', 'int a=0;\n')
# Check that a null-string LIBPATH doesn't blow up.
-test.write('SConstruct', """
-env = Environment(LIBPATH = '')
-env.Library('foo', source = 'empty.c')
+test.write('SConstruct', """\
+env = Environment(LIBPATH='')
+env.Library('foo', source='empty.c')
""")
-test.run(arguments = '.',
- stderr=TestSCons.noisy_ar,
- match=TestSCons.match_re_dotall)
+test.run(arguments='.', stderr=TestSCons.noisy_ar, match=TestSCons.match_re_dotall)
test.pass_test()
diff --git a/test/PharLap.py b/test/PharLap.py
index 8e56f21..0a54151 100644
--- a/test/PharLap.py
+++ b/test/PharLap.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import sys
@@ -284,10 +283,10 @@ test.write([ "baz", "bar.lnk"],"""
@asm.emb
""")
-test.write("SConstruct", """
-env=Environment(tools = [ 'linkloc', '386asm' ],
- ASFLAGS='-twocase -cvsym',
- LINKFLAGS='@foo.lnk')
+test.write("SConstruct", """\
+env = Environment(
+ tools=['linkloc', '386asm'], ASFLAGS='-twocase -cvsym', LINKFLAGS='@foo.lnk'
+)
env.Program(target='minasm', source='minasm.asm')
""")
@@ -304,8 +303,8 @@ test.write([ "baz", "bar.lnk"],"""
""")
oldtime = os.path.getmtime(test.workpath('minasm.exe'))
-time.sleep(2) # Give the time stamp time to change
-test.run(arguments = '.')
+test.sleep() # delay for timestamps
+test.run(arguments='.')
test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))
test.pass_test()
diff --git a/test/Program.py b/test/Program.py
index 15fd0c3..640787f 100644
--- a/test/Program.py
+++ b/test/Program.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# 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 time
@@ -40,13 +39,13 @@ foo4 = test.workpath('foo4' + _exe)
foo5 = test.workpath('foo5' + _exe)
foo_args = 'foo1%s foo2%s foo3%s foo4%s foo5%s' % (_exe, _exe, _exe, _exe, _exe)
-test.write('SConstruct', """
+test.write('SConstruct', """\
env = Environment()
-env.Program(target = 'foo1', source = 'f1.c')
-env.Program(target = 'foo2', source = Split('f2a.c f2b.c f2c.c'))
+env.Program(target='foo1', source='f1.c')
+env.Program(target='foo2', source=Split('f2a.c f2b.c f2c.c'))
f3a = File('f3a.c')
f3b = File('f3b.c')
-Program(target = 'foo3', source = [f3a, [f3b, 'f3c.c']])
+Program(target='foo3', source=[f3a, [f3b, 'f3c.c']])
env.Program('foo4', 'f4.c')
env.Program('foo5.c')
""")
@@ -156,15 +155,14 @@ main(int argc, char *argv[])
}
""")
-test.run(arguments = '.')
+test.run(arguments='.')
-test.run(program = foo1, stdout = "f1.c\n")
-test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n")
-test.run(program = foo3, stdout = "f3a.c\nf3b.c\nf3c.c\n")
-test.run(program = foo4, stdout = "f4.c\n")
-test.run(program = foo5, stdout = "foo5.c\n")
-
-test.up_to_date(arguments = '.')
+test.run(program=foo1, stdout="f1.c\n")
+test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
+test.run(program=foo3, stdout="f3a.c\nf3b.c\nf3c.c\n")
+test.run(program=foo4, stdout="f4.c\n")
+test.run(program=foo5, stdout="foo5.c\n")
+test.up_to_date(arguments='.')
test.write('f1.c', r"""
#include
@@ -211,15 +209,14 @@ main(int argc, char *argv[])
}
""")
-test.run(arguments = '.')
-
-test.run(program = foo1, stdout = "f1.c X\n")
-test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n")
-test.run(program = foo3, stdout = "f3a.c\nf3b.c X\nf3c.c\n")
-test.run(program = foo4, stdout = "f4.c X\n")
-test.run(program = foo5, stdout = "foo5.c X\n")
+test.run(arguments='.')
-test.up_to_date(arguments = '.')
+test.run(program=foo1, stdout="f1.c X\n")
+test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
+test.run(program=foo3, stdout="f3a.c\nf3b.c X\nf3c.c\n")
+test.run(program=foo4, stdout="f4.c X\n")
+test.run(program=foo5, stdout="foo5.c X\n")
+test.up_to_date(arguments='.')
# make sure the programs didn't get rebuilt, because nothing changed:
oldtime1 = os.path.getmtime(foo1)
@@ -228,10 +225,8 @@ oldtime3 = os.path.getmtime(foo3)
oldtime4 = os.path.getmtime(foo4)
oldtime5 = os.path.getmtime(foo5)
-time.sleep(2) # introduce a small delay, to make the test valid
-
-test.run(arguments = foo_args)
-
+test.sleep() # delay for timestamps
+test.run(arguments=foo_args)
test.fail_test(oldtime1 != os.path.getmtime(foo1))
test.fail_test(oldtime2 != os.path.getmtime(foo2))
test.fail_test(oldtime3 != os.path.getmtime(foo3))
@@ -284,15 +279,14 @@ main(int argc, char *argv[])
}
""")
-test.run(arguments = foo_args)
-
-test.run(program = foo1, stdout = "f1.c Y\n")
-test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n")
-test.run(program = foo3, stdout = "f3a.c\nf3b.c Y\nf3c.c\n")
-test.run(program = foo4, stdout = "f4.c Y\n")
-test.run(program = foo5, stdout = "foo5.c Y\n")
+test.run(arguments=foo_args)
-test.up_to_date(arguments = foo_args)
+test.run(program=foo1, stdout="f1.c Y\n")
+test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
+test.run(program=foo3, stdout="f3a.c\nf3b.c Y\nf3c.c\n")
+test.run(program=foo4, stdout="f4.c Y\n")
+test.run(program=foo5, stdout="foo5.c Y\n")
+test.up_to_date(arguments=foo_args)
test.write('f1.c', r"""
#include
@@ -340,15 +334,14 @@ main(int argc, char *argv[])
}
""")
-test.run(arguments = foo_args)
-
-test.run(program = foo1, stdout = "f1.c Z\n")
-test.run(program = foo2, stdout = "f2a.c\nf2b.c\nf2c.c\n")
-test.run(program = foo3, stdout = "f3a.c\nf3b.c Z\nf3c.c\n")
-test.run(program = foo4, stdout = "f4.c Z\n")
-test.run(program = foo5, stdout = "foo5.c Z\n")
+test.run(arguments=foo_args)
-test.up_to_date(arguments = foo_args)
+test.run(program=foo1, stdout="f1.c Z\n")
+test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
+test.run(program=foo3, stdout="f3a.c\nf3b.c Z\nf3c.c\n")
+test.run(program=foo4, stdout="f4.c Z\n")
+test.run(program=foo5, stdout="foo5.c Z\n")
+test.up_to_date(arguments=foo_args)
# make sure the programs didn't get rebuilt, because nothing changed:
oldtime1 = os.path.getmtime(foo1)
@@ -357,10 +350,8 @@ oldtime3 = os.path.getmtime(foo3)
oldtime4 = os.path.getmtime(foo4)
oldtime5 = os.path.getmtime(foo5)
-time.sleep(2) # introduce a small delay, to make the test valid
-
-test.run(arguments = foo_args)
-
+test.sleep() # delay for timestamps
+test.run(arguments=foo_args)
test.fail_test(not (oldtime1 == os.path.getmtime(foo1)))
test.fail_test(not (oldtime2 == os.path.getmtime(foo2)))
test.fail_test(not (oldtime3 == os.path.getmtime(foo3)))
diff --git a/test/Repository/no-SConsignFile.py b/test/Repository/no-SConsignFile.py
index d7f570c..6b5b3e2 100644
--- a/test/Repository/no-SConsignFile.py
+++ b/test/Repository/no-SConsignFile.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Test that using Repository() works even when the Repository has no
@@ -63,13 +62,10 @@ test.write(['src', 'foo.h'], """\
# Make sure it's past the max_drift time,
# so the source file signatures get saved.
-test.sleep(2)
+test.sleep() # delay for timestamps
test.run(chdir='build', arguments='.')
-
-test.run(program=test.workpath('build', 'foo'),
- stdout="src/foo.h\nsrc/foo.c\n")
-
+test.run(program=test.workpath('build', 'foo'), stdout="src/foo.h\nsrc/foo.c\n")
test.up_to_date(chdir='build', arguments='.')
test.pass_test()
diff --git a/test/Repository/variants.py b/test/Repository/variants.py
index c95e853..a07d7a0 100644
--- a/test/Repository/variants.py
+++ b/test/Repository/variants.py
@@ -31,20 +31,22 @@ from TestSCons import TestSCons, _exe, _obj
test = TestSCons()
-test.subdir('repository',
- ['repository', 'src1'],
- ['repository', 'src2'],
- ['repository', 'src2', 'include'],
- ['repository', 'src2', 'xxx'],
- ['repository', 'build2'],
- ['repository', 'build2', 'foo'],
- ['repository', 'build2', 'bar'],
- 'work1',
- ['work1', 'src1'],
- 'work2',
- ['work2', 'src2'],
- ['work2', 'src2', 'include'],
- ['work2', 'src2', 'xxx'])
+test.subdir(
+ 'repository',
+ ['repository', 'src1'],
+ ['repository', 'src2'],
+ ['repository', 'src2', 'include'],
+ ['repository', 'src2', 'xxx'],
+ ['repository', 'build2'],
+ ['repository', 'build2', 'foo'],
+ ['repository', 'build2', 'bar'],
+ 'work1',
+ ['work1', 'src1'],
+ 'work2',
+ ['work2', 'src2'],
+ ['work2', 'src2', 'include'],
+ ['work2', 'src2', 'xxx'],
+)
aaa_obj = 'aaa' + _obj
bbb_obj = 'bbb' + _obj
@@ -56,14 +58,18 @@ repository_build1_foo_xxx = test.workpath('repository', 'build1', 'foo', 'xxx')
work1_build1_foo_xxx = test.workpath('work1', 'build1', 'foo', 'xxx')
work1_build1_bar_xxx = test.workpath('work1', 'build1', 'bar', 'xxx')
-repository_build2_foo_src2_xxx_xxx = test.workpath('repository', 'build2',
- 'foo', 'src2', 'xxx', 'xxx')
-repository_build2_bar_src2_xxx_xxx = test.workpath('repository', 'build2',
- 'bar', 'src2', 'xxx', 'xxx')
-work2_build2_foo_src2_xxx_xxx = test.workpath('work2', 'build2',
- 'foo', 'src2', 'xxx', 'xxx')
-work2_build2_bar_src2_xxx_xxx = test.workpath('work2', 'build2',
- 'bar', 'src2', 'xxx', 'xxx')
+repository_build2_foo_src2_xxx_xxx = test.workpath(
+ 'repository', 'build2', 'foo', 'src2', 'xxx', 'xxx'
+)
+repository_build2_bar_src2_xxx_xxx = test.workpath(
+ 'repository', 'build2', 'bar', 'src2', 'xxx', 'xxx'
+)
+work2_build2_foo_src2_xxx_xxx = test.workpath(
+ 'work2', 'build2', 'foo', 'src2', 'xxx', 'xxx'
+)
+work2_build2_bar_src2_xxx_xxx = test.workpath(
+ 'work2', 'build2', 'bar', 'src2', 'xxx', 'xxx'
+)
opts = "-Y " + test.workpath('repository')
@@ -73,12 +79,13 @@ OS = ARGUMENTS.get('OS', '')
build1_os = "#build1/" + OS
default = Environment()
ccflags = {
- '' : '',
- 'foo' : '-DFOO',
- 'bar' : '-DBAR',
+ '': '',
+ 'foo': '-DFOO',
+ 'bar': '-DBAR',
}
-env1 = Environment(CCFLAGS = default.subst('$CCFLAGS %s' % ccflags[OS]),
- CPPPATH = build1_os)
+env1 = Environment(
+ CCFLAGS=default.subst('$CCFLAGS %s' % ccflags[OS]), CPPPATH=build1_os
+)
VariantDir(build1_os, 'src1')
SConscript(build1_os + '/SConscript', "env1")
@@ -95,8 +102,9 @@ test.write(['repository', 'build2', 'foo', 'SConscript'], r"""
VariantDir('src2', '#src2')
default = Environment()
-env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DFOO'),
- CPPPATH = ['#src2/xxx', '#src2/include'])
+env2 = Environment(
+ CCFLAGS=default.subst('$CCFLAGS -DFOO'), CPPPATH=['#src2/xxx', '#src2/include']
+)
SConscript('src2/xxx/SConscript', "env2")
""")
@@ -105,8 +113,9 @@ test.write(['repository', 'build2', 'bar', 'SConscript'], r"""
VariantDir('src2', '#src2')
default = Environment()
-env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DBAR'),
- CPPPATH = ['#src2/xxx', '#src2/include'])
+env2 = Environment(
+ CCFLAGS=default.subst('$CCFLAGS -DBAR'), CPPPATH=['#src2/xxx', '#src2/include']
+)
SConscript('src2/xxx/SConscript', "env2")
""")
@@ -216,12 +225,9 @@ repository/src1/bbb.c: REPOSITORY_FOO
repository/src1/main.c: REPOSITORY_FOO
""")
-database_name=test.get_sconsignname()
-
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+database_name = test.get_sconsignname()
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
@@ -237,10 +243,8 @@ repository/src2/xxx/include.h: BAR
repository/src2/xxx/main.c: BAR
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
@@ -251,15 +255,10 @@ test.writable('repository', 0)
#
test.up_to_date(chdir='work1', options=opts + " OS=foo", arguments='build1')
-test.fail_test(os.path.exists(
- test.workpath('work1', 'build1', 'foo', aaa_obj)))
-test.fail_test(os.path.exists(
- test.workpath('work1', 'build1', 'foo', bbb_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work1', 'build1', 'foo', main_obj)))
-
-test.fail_test(os.path.exists(
- test.workpath('work1', 'build1', 'foo', xxx_exe)))
+test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', aaa_obj)))
+test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', bbb_obj)))
+test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', main_obj)))
+test.fail_test(os.path.exists(test.workpath('work1', 'build1', 'foo', xxx_exe)))
#
test.run(chdir='work1', options=opts, arguments='OS=bar .')
@@ -271,18 +270,13 @@ repository/src1/bbb.c: REPOSITORY_BAR
repository/src1/main.c: REPOSITORY_BAR
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-
test.up_to_date(chdir='work1', options=opts + " OS=bar", arguments='build1')
-# Ensure file time stamps will be newer.
-time.sleep(2)
-
+test.sleep() # delay for timestamps
test.write(['work1', 'src1', 'iii.h'], r"""
#ifdef FOO
#define STRING "WORK_FOO"
@@ -302,13 +296,10 @@ repository/src1/bbb.c: WORK_BAR
repository/src1/main.c: WORK_BAR
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-
test.up_to_date(chdir='work1', options=opts + " OS=bar", arguments='build1')
#
@@ -320,38 +311,39 @@ repository/src1/bbb.c: WORK_FOO
repository/src1/main.c: WORK_FOO
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-
test.up_to_date(chdir='work1', options=opts + " OS=foo", arguments='build1')
-
-#
test.up_to_date(chdir='work2', options=opts, arguments='build2')
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'foo', 'src2', 'xxx', aaa_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'foo', 'src2', 'xxx', bbb_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'foo', 'src2', 'xxx', main_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'foo', 'src2', 'xxx', xxx_exe)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'bar', 'src2', 'xxx', aaa_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'bar', 'src2', 'xxx', bbb_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'bar', 'src2', 'xxx', main_obj)))
-test.fail_test(os.path.exists(test.workpath(
- 'work2', 'build2', 'bar', 'src2', 'xxx', xxx_exe)))
-
-# Ensure file time stamps will be newer.
-time.sleep(2)
-
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', aaa_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', bbb_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', main_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'foo', 'src2', 'xxx', xxx_exe))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', aaa_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', bbb_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', main_obj))
+)
+test.fail_test(
+ os.path.exists(test.workpath('work2', 'build2', 'bar', 'src2', 'xxx', xxx_exe))
+)
+
+test.sleep() # delay for timestamps
test.write(['work2', 'src2', 'include', 'my_string.h'], r"""
#ifdef FOO
#define INCLUDE_OS "FOO"
@@ -362,7 +354,6 @@ test.write(['work2', 'src2', 'include', 'my_string.h'], r"""
#define INCLUDE_STRING "work2/src2/include/my_string.h: %s\n"
""")
-#
test.run(chdir='work2', options=opts, arguments='build2')
test.run(program=work2_build2_foo_src2_xxx_xxx, stdout="""\
@@ -377,16 +368,12 @@ repository/src2/xxx/include.h: BAR
repository/src2/xxx/main.c: BAR
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-# Ensure file time stamps will be newer.
-time.sleep(2)
-
+test.sleep() # delay for timestamps
test.write(['work2', 'src2', 'xxx', 'include.h'], r"""
#include
#ifdef FOO
@@ -412,38 +399,37 @@ work2/src2/xxx/include.h: BAR
repository/src2/xxx/main.c: BAR
""")
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-#
test.unlink(['work2', 'src2', 'include', 'my_string.h'])
-
test.run(chdir='work2', options=opts, arguments='build2')
-test.run(program=work2_build2_foo_src2_xxx_xxx, stdout="""\
+test.run(
+ program=work2_build2_foo_src2_xxx_xxx,
+ stdout="""\
repository/src2/include/my_string.h: FOO
work2/src2/xxx/include.h: FOO
repository/src2/xxx/main.c: FOO
-""")
+""",
+)
-test.run(program=work2_build2_bar_src2_xxx_xxx, stdout="""\
+test.run(
+ program=work2_build2_bar_src2_xxx_xxx,
+ stdout="""\
repository/src2/include/my_string.h: BAR
work2/src2/xxx/include.h: BAR
repository/src2/xxx/main.c: BAR
-""")
+""",
+)
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src1', database_name)))
-test.fail_test(os.path.exists(
- test.workpath('repository', 'src2', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src1', database_name)))
+test.fail_test(os.path.exists(test.workpath('repository', 'src2', database_name)))
test.fail_test(os.path.exists(test.workpath('work1', 'src1', database_name)))
test.fail_test(os.path.exists(test.workpath('work2', 'src2', database_name)))
-#
test.pass_test()
# Local Variables:
diff --git a/test/Touch.py b/test/Touch.py
index 431cd6c..3538c7d 100644
--- a/test/Touch.py
+++ b/test/Touch.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that the Touch() Action works.
@@ -34,30 +33,29 @@ import TestSCons
test = TestSCons.TestSCons()
-test.write('SConstruct', """
+test.write('SConstruct', """\
Execute(Touch('f1'))
Execute(Touch(File('f1-File')))
+
def cat(env, source, target):
target = str(target[0])
with open(target, "wb") as f:
for src in source:
with open(str(src), "rb") as ifp:
f.write(ifp.read())
+
Cat = Action(cat)
env = Environment()
env.Command('f2.out', 'f2.in', [Cat, Touch("f3")])
env = Environment(FILE='f4')
env.Command('f5.out', 'f5.in', [Touch("$FILE"), Cat])
-env.Command('f6.out', 'f6.in', [Cat,
- Touch("Touch-$SOURCE"),
- Touch("$TARGET-Touch")])
+env.Command('f6.out', 'f6.in', [Cat, Touch("Touch-$SOURCE"), Touch("$TARGET-Touch")])
# Make sure Touch works with a list of arguments
env = Environment()
-env.Command('f7.out', 'f7.in', [Cat,
- Touch(["Touch-$SOURCE",
- "$TARGET-Touch",
- File("f8")])])
+env.Command(
+ 'f7.out', 'f7.in', [Cat, Touch(["Touch-$SOURCE", "$TARGET-Touch", File("f8")])]
+)
""")
test.write('f1', "f1\n")
@@ -70,11 +68,12 @@ test.write('f7.in', "f7.in\n")
old_f1_time = os.path.getmtime(test.workpath('f1'))
old_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
-expect = test.wrap_stdout(read_str = """\
+expect = test.wrap_stdout(
+ read_str="""\
Touch("f1")
Touch("f1-File")
""",
- build_str = """\
+ build_str="""\
cat(["f2.out"], ["f2.in"])
Touch("f3")
Touch("f4")
@@ -84,11 +83,11 @@ Touch("Touch-f6.in")
Touch("f6.out-Touch")
cat(["f7.out"], ["f7.in"])
Touch(["Touch-f7.in", "f7.out-Touch", "f8"])
-""")
-test.run(options = '-n', arguments = '.', stdout = expect)
-
-test.sleep(2)
+""",
+)
+test.run(options='-n', arguments='.', stdout=expect)
+test.sleep() # delay for timestamps
new_f1_time = os.path.getmtime(test.workpath('f1'))
test.fail_test(old_f1_time != new_f1_time)
new_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
diff --git a/test/chained-build.py b/test/chained-build.py
index 871a593..10d0b46 100644
--- a/test/chained-build.py
+++ b/test/chained-build.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# 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
@@ -58,23 +57,20 @@ test.write(['w1', 'SConstruct1'], SConstruct1_contents)
test.write(['w1', 'SConstruct2'], SConstruct2_contents)
test.write(['w1', 'foo.in'], "foo.in 1")
-test.run(chdir='w1',
- arguments="--max-drift=0 -f SConstruct1 foo.mid",
- stdout = test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'))
-
-test.run(chdir='w1',
- arguments="--max-drift=0 -f SConstruct2 foo.out",
- stdout = test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'))
-
-test.up_to_date(chdir='w1',
- options="--max-drift=0 -f SConstruct1",
- arguments="foo.mid")
-
-test.up_to_date(chdir='w1',
- options="--max-drift=0 -f SConstruct2",
- arguments="foo.out")
-
-test.sleep() # make sure foo.in rewrite has new mod-time
+test.run(
+ chdir='w1',
+ arguments="--max-drift=0 -f SConstruct1 foo.mid",
+ stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'),
+)
+test.run(
+ chdir='w1',
+ arguments="--max-drift=0 -f SConstruct2 foo.out",
+ stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'),
+)
+test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct1", arguments="foo.mid")
+test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct2", arguments="foo.out")
+
+test.sleep() # delay for timestamps
test.write(['w1', 'foo.in'], "foo.in 2")
# Because we're using --max-drift=0, we use the cached csig value
@@ -86,17 +82,19 @@ test.up_to_date(chdir='w1',
# Now try with --max-drift disabled. The build of foo.out should still
# be considered up-to-date, but the build of foo.mid now detects the
# change and rebuilds, too, which then causes a rebuild of foo.out.
-test.up_to_date(chdir='w1',
- options="--max-drift=-1 -f SConstruct2",
- arguments="foo.out")
-
-test.run(chdir='w1',
- arguments="--max-drift=-1 -f SConstruct1 foo.mid",
- stdout = test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'))
-
-test.run(chdir='w1',
- arguments="--max-drift=-1 -f SConstruct2 foo.out",
- stdout = test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'))
+test.up_to_date(
+ chdir='w1', options="--max-drift=-1 -f SConstruct2", arguments="foo.out"
+)
+test.run(
+ chdir='w1',
+ arguments="--max-drift=-1 -f SConstruct1 foo.mid",
+ stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'),
+)
+test.run(
+ chdir='w1',
+ arguments="--max-drift=-1 -f SConstruct2 foo.out",
+ stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'),
+)
test.pass_test()
diff --git a/test/sconsign/script/Signatures.py b/test/sconsign/script/Signatures.py
index ef8bac0..2225f83 100644
--- a/test/sconsign/script/Signatures.py
+++ b/test/sconsign/script/Signatures.py
@@ -44,8 +44,8 @@ if NEED_HELPER:
# in the expected output because paths in the .sconsign files are
# canonicalized to use / as the separator.
-sub1_hello_c = 'sub1/hello.c'
-sub1_hello_obj = 'sub1/hello.obj'
+sub1_hello_c = 'sub1/hello.c'
+sub1_hello_obj = 'sub1/hello.obj'
test.subdir('sub1', 'sub2')
@@ -135,7 +135,7 @@ env2.Program('sub2/hello.c')
""",
)
# TODO in the above, we would normally want to run a python program
-# using "our python" like this:
+# using "our Python" like this:
# CCCOM=[[r'{_python_}', r'{fake_cc_py}', 'sub2', '$TARGET', '$SOURCE']],
# LINKCOM=[[r'{_python_}', r'{fake_link_py}', '$TARGET', '$SOURCE']],
# however we're looking at dependencies with sconsign, so that breaks things.
@@ -160,17 +160,16 @@ test.write(['sub2', 'inc2.h'], r"""\
#define STRING2 "inc2.h"
""")
-test.sleep()
-
+test.sleep() # delay for timestamps
test.run(arguments = '. --max-drift=1')
sig_re = r'[0-9a-fA-F]{32,64}'
date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d'
-
database_name = test.get_sconsignname()
-test.run_sconsign(arguments = f"-e hello.exe -e hello.obj sub1/{database_name}",
- stdout = r"""hello.exe: %(sig_re)s \d+ \d+
+test.run_sconsign(
+ arguments=f"-e hello.exe -e hello.obj sub1/{database_name}",
+ stdout=r"""hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
fake_link\.py: None \d+ \d+
%(sig_re)s \[.*\]
@@ -178,10 +177,12 @@ hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: None \d+ \d+
fake_cc\.py: None \d+ \d+
%(sig_re)s \[.*\]
-""" % locals())
+""" % locals(),
+)
-test.run_sconsign(arguments = f"-e hello.exe -e hello.obj -r sub1/{database_name}",
- stdout = r"""hello.exe: %(sig_re)s '%(date_re)s' \d+
+test.run_sconsign(
+ arguments=f"-e hello.exe -e hello.obj -r sub1/{database_name}",
+ stdout=r"""hello.exe: %(sig_re)s '%(date_re)s' \d+
%(sub1_hello_obj)s: %(sig_re)s '%(date_re)s' \d+
fake_link\.py: None '%(date_re)s' \d+
%(sig_re)s \[.*\]
@@ -189,7 +190,8 @@ hello.obj: %(sig_re)s '%(date_re)s' \d+
%(sub1_hello_c)s: None '%(date_re)s' \d+
fake_cc\.py: None '%(date_re)s' \d+
%(sig_re)s \[.*\]
-""" % locals())
+""" % locals(),
+)
test.pass_test()
diff --git a/test/sconsign/script/dblite.py b/test/sconsign/script/dblite.py
index 1fcf8c0..24d8403 100644
--- a/test/sconsign/script/dblite.py
+++ b/test/sconsign/script/dblite.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
-# __COPYRIGHT__
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
Verify that various ways of getting at a an sconsign file written with
@@ -97,17 +96,11 @@ main(int argc, char *argv[])
}
""")
-test.write(['sub2', 'inc1.h'], r"""\
-#define STRING1 "inc1.h"
-""")
-
-test.write(['sub2', 'inc2.h'], r"""\
-#define STRING2 "inc2.h"
-""")
-
-test.sleep()
+test.write(['sub2', 'inc1.h'], r'#define STRING1 "inc1.h"')
+test.write(['sub2', 'inc2.h'], r'#define STRING2 "inc2.h"')
-test.run(arguments = '. --max-drift=1')
+test.sleep() # delay for timestamps
+test.run(arguments='. --max-drift=1')
sig_re = r'[0-9a-fA-F]{32,64}'
date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d'
@@ -146,23 +139,23 @@ hello%(_obj)s: %(sig_re)s '%(date_re)s' \d+
common_flags = '-e hello%(_exe)s -e hello%(_obj)s -d sub1' % locals()
-test.run_sconsign(arguments = "%s my_sconsign" % common_flags,
- stdout = expect)
+test.run_sconsign(arguments="%s my_sconsign" % common_flags, stdout=expect)
-test.run_sconsign(arguments = "%s my_sconsign.dblite" % common_flags,
- stdout = expect)
+test.run_sconsign(arguments="%s my_sconsign.dblite" % common_flags, stdout=expect)
-test.run_sconsign(arguments = "%s -f dblite my_sconsign" % common_flags,
- stdout = expect)
+test.run_sconsign(arguments="%s -f dblite my_sconsign" % common_flags, stdout=expect)
-test.run_sconsign(arguments = "%s -f dblite my_sconsign.dblite" % common_flags,
- stdout = expect)
+test.run_sconsign(
+ arguments="%s -f dblite my_sconsign.dblite" % common_flags, stdout=expect
+)
-test.run_sconsign(arguments = "%s -r -f dblite my_sconsign" % common_flags,
- stdout = expect_r)
+test.run_sconsign(
+ arguments="%s -r -f dblite my_sconsign" % common_flags, stdout=expect_r
+)
-test.run_sconsign(arguments = "%s -r -f dblite my_sconsign.dblite" % common_flags,
- stdout = expect_r)
+test.run_sconsign(
+ arguments="%s -r -f dblite my_sconsign.dblite" % common_flags, stdout=expect_r
+)
test.pass_test()
--
cgit v0.12
From 53e33adc2a7cbd7d68020350060f73ea5977f002 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Tue, 31 May 2022 09:11:42 -0600
Subject: Fix sider-detected typo in test change
Signed-off-by: Mats Wichmann
---
test/Copy-Action.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/Copy-Action.py b/test/Copy-Action.py
index 2179744..e135a9f 100644
--- a/test/Copy-Action.py
+++ b/test/Copy-Action.py
@@ -166,7 +166,7 @@ def must_be_same(f1, f2):
for value in ['ST_MODE', 'ST_MTIME']:
v = getattr(stat, value)
if s1[v] != s2[v]:
- msg = f"{f1!r}[{value}] {s1[v1]} != {f2!r}[{value}] {s2[v]}\n"
+ msg = f"{f1!r}[{value}] {s1[v]} != {f2!r}[{value}] {s2[v]}\n"
sys.stderr.write(msg)
errors += 1
--
cgit v0.12
From c9c678683a3944b0500a8ce68c80d7c5d48c9230 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Wed, 1 Jun 2022 14:28:03 -0700
Subject: Updated CHANGES/RELEASE to be a bit simpler. Fixed typo in docs for
SHELL_ENV_GENERATORS.
---
CHANGES.txt | 9 ++++++---
RELEASE.txt | 9 ++++++---
SCons/Action.py | 10 ++++++++--
SCons/Action.xml | 8 ++++----
test/Actions/subst_shell_env.py | 2 +-
5 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d5aba9f..84ec06b 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -99,9 +99,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected
format. Compiler tools will also configure the variable automatically.
- - Added SHELL_ENV_GENERATORS construction variable. This variable
- is an iterable which will contain functions in which each are called and each can allow
- the user a method to customize the execution environment.
+ - Added SHELL_ENV_GENERATORS construction variable. This variable should be set to a list
+ (or an iterable) which contains functions to be called in order
+ when constructing the execution environment (Generally this is the shell environment
+ variables). This allows the user to customize how (for example) PATH is constructed.
+ Note that these are called for every build command run by SCons. It could have considerable
+ performance impact if not used carefully.
- Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
- Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry
to connect to the server during start up.
diff --git a/RELEASE.txt b/RELEASE.txt
index 195e325..e7fa31c 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -16,9 +16,12 @@ NEW FUNCTIONALITY
- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT.
- Added Configure.CheckMember() checker to check if struct/class has the specified member.
-- Added SHELL_ENV_GENERATORS construction variable. This variable
- is an iterable which will contain functions in which each are called and each can allow
- the user a method to customize the execution environment.
+- Added SHELL_ENV_GENERATORS construction variable. This variable should be set to a list
+ (or an iterable) which contains functions to be called in order
+ when constructing the execution environment (Generally this is the shell environment
+ variables). This allows the user to customize how (for example) PATH is constructed.
+ Note that these are called for every build command run by SCons. It could have considerable
+ performance impact if not used carefully.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
diff --git a/SCons/Action.py b/SCons/Action.py
index e29c4e9..6e67c7f 100644
--- a/SCons/Action.py
+++ b/SCons/Action.py
@@ -756,9 +756,15 @@ def get_default_ENV(env):
def _resolve_shell_env(env, target, source):
+ """
+ First get default environment.
+ Then if SHELL_ENV_GENERATORS is set and is iterable,
+ call each callable in that list to allow it to alter
+ the created execution environment.
+ """
ENV = get_default_ENV(env)
- shell_gen = env.get('SHELL_ENV_GENERATORS')
- if shell_gen is not None:
+ shell_gen = env.get('SHELL_ENV_GENERATORS')
+ if shell_gen:
try:
shell_gens = iter(shell_gen)
except TypeError:
diff --git a/SCons/Action.xml b/SCons/Action.xml
index 8994adb..1346db2 100644
--- a/SCons/Action.xml
+++ b/SCons/Action.xml
@@ -203,7 +203,7 @@ in which the command should be executed.
-Must be an iterable containing functions where each function generates or
+Must be a list (or an iterable) containing functions where each function generates or
alters the environment dictionary which will be used
when executing the &cv-link-SPAWN; function. The functions will initially
be passed a reference of the current execution environment (e.g. env['ENV']),
@@ -214,14 +214,14 @@ values.
This primary purpose of this construction variable is to give the user the ability
to substitute execution environment variables based on env, targets, and sources.
-If desired, the user can completly customize the execution environment for particular
+If desired, the user can completely customize the execution environment for particular
targets.
def custom_shell_env(env, target, source, shell_env):
- # customize shell_env if desired
- if str(target[0]) == 'special_target'is:
+ """customize shell_env if desired"""
+ if str(target[0]) == 'special_target':
shell_env['SPECIAL_VAR'] = env.subst('SOME_VAR', target=target, source=source)
return shell_env
diff --git a/test/Actions/subst_shell_env.py b/test/Actions/subst_shell_env.py
index d26f0ae..02ba640 100644
--- a/test/Actions/subst_shell_env.py
+++ b/test/Actions/subst_shell_env.py
@@ -25,7 +25,7 @@
"""
Verify that shell environment variables can be expanded per target/source
-when exectuting actions on the command line.
+when executing actions on the command line.
"""
import os
--
cgit v0.12
From 00dd82bf9a1f0b3332449a0add3a5f3d5c78c8c2 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Thu, 2 Jun 2022 10:25:48 -0700
Subject: Move logic which waits for a process to die into SCons.Util
wait_for_process_to_die(pid)
---
SCons/Tool/ninja/NinjaState.py | 29 ++---------------------------
SCons/Util.py | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index 5f8d5c7..770da07 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -37,7 +37,7 @@ import hashlib
import SCons
from SCons.Script import COMMAND_LINE_TARGETS
-from SCons.Util import is_List
+from SCons.Util import is_List, wait_for_process_to_die
from SCons.Errors import InternalError
from .Globals import COMMAND_TYPES, NINJA_RULES, NINJA_POOLS, \
NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
@@ -644,32 +644,7 @@ class NinjaState:
pass
# wait for the server process to fully killed
- try:
- import psutil
- while True:
- if pid not in [proc.pid for proc in psutil.process_iter()]:
- break
- else:
- time.sleep(0.1)
- except ImportError:
- # if psutil is not installed we can do this the hard way
- while True:
- if sys.platform == 'win32':
- import ctypes
- PROCESS_QUERY_INFORMATION = 0x1000
- processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, 0,pid)
- if processHandle == 0:
- break
- else:
- ctypes.windll.kernel32.CloseHandle(processHandle)
- time.sleep(0.1)
- else:
- try:
- os.kill(pid, 0)
- except OSError:
- break
- else:
- time.sleep(0.1)
+ wait_for_process_to_die(pid)
if os.path.exists(scons_daemon_dirty):
os.unlink(scons_daemon_dirty)
diff --git a/SCons/Util.py b/SCons/Util.py
index 093ca41..0fe42c8 100644
--- a/SCons/Util.py
+++ b/SCons/Util.py
@@ -29,6 +29,7 @@ import os
import pprint
import re
import sys
+import time
from collections import UserDict, UserList, UserString, OrderedDict
from collections.abc import MappingView
from contextlib import suppress
@@ -2123,6 +2124,40 @@ def print_time():
from SCons.Script.Main import print_time
return print_time
+
+def wait_for_process_to_die(pid):
+ """
+ Wait for specified process to die, or alternatively kill it
+ NOTE: This function operates best with psutil pypi package
+ """
+ # wait for the process to fully killed
+ try:
+ import psutil
+ while True:
+ if pid not in [proc.pid for proc in psutil.process_iter()]:
+ break
+ else:
+ time.sleep(0.1)
+ except ImportError:
+ # if psutil is not installed we can do this the hard way
+ while True:
+ if sys.platform == 'win32':
+ import ctypes
+ PROCESS_QUERY_INFORMATION = 0x1000
+ processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, 0,pid)
+ if processHandle == 0:
+ break
+ else:
+ ctypes.windll.kernel32.CloseHandle(processHandle)
+ time.sleep(0.1)
+ else:
+ try:
+ os.kill(pid, 0)
+ except OSError:
+ break
+ else:
+ time.sleep(0.1)
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
--
cgit v0.12
From a2dffb888472f55fad92e539d24b929b292fcb07 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Thu, 2 Jun 2022 11:27:25 -0700
Subject: Updated CHANGES/RELEASE contents
---
CHANGES.txt | 18 +++++++++---------
RELEASE.txt | 13 ++++++++-----
2 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d21aa60..08fdd34 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -81,8 +81,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
only used for ninja)
- Ninja: Fix issue where Configure files weren't being properly processed when build run
via ninja.
- - Added ninja mingw support and improved ninja CommandGeneratorAction support.
- - Update ninja file generation to only create response files for build commands
+ - Ninja: Added ninja mingw support and improved ninja CommandGeneratorAction support.
+ - Ninja: Update ninja file generation to only create response files for build commands
which exceed MAXLINELENGTH
- Ninja: Added NINJA_GENERATED_SOURCE_ALIAS_NAME which allows user to specify an
Alias() which the ninja tool can use to determine which files are generated sources.
@@ -93,16 +93,16 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
required by other build targets. Code contributed by MongoDB
The downstream commit is here:
https://github.com/mongodb/mongo/commit/2fef432fa6e7cf3fd4f22ba3b193222c2887f14f
- - Added special case for ninja scons daemon to work in win32 python3.6 environments.
+ - Ninja: Added special case for ninja scons daemon to work in win32 python3.6 environments.
This particular environment does a bad job managing popen standard file handles, so
some special workarounds are needed.
- - Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
+ - Ninja:Added user configurable setting of ninja depfile format via NINJA_DEPFILE_PARSE_FORMAT.
Now setting NINJA_DEPFILE_PARSE_FORMAT to [msvc,gcc,clang] can force the ninja expected
format. Compiler tools will also configure the variable automatically.
- - Made ninja tool force the ninja file as the only target. Also improved the default
- targets setup and made sure there is always a default target for
+ - Ninja: Made ninja tool force the ninja file as the only target.
+ - Ninja: Improved the default targets setup and made sure there is always a default target for
the ninja file, which excludes targets that start and stop the daemon.
- - Update ninja tool so targets passed to SCons are propgated to ninja when scons
+ - Ninja: Update ninja tool so targets passed to SCons are propagated to ninja when scons
automatically executes ninja.
- Small refactor of scons daemons using a shared StateInfo class for communication
between the scons interactive thread and the http server thread. Added error handling
@@ -110,8 +110,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Added SHELL_ENV_GENERATOR construction variables. This variable allows the user to Define
a function which will be called to generate or alter the execution environment which will
be used in the shell command of some Action.
- - Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
- - Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry
+ - Ninja: Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
+ - Ninja: Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry
to connect to the server during start up.
From Mats Wichmann:
diff --git a/RELEASE.txt b/RELEASE.txt
index ce2b8e5..832698d 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -58,17 +58,17 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
".scons_msvc_cache" so there should be no transition problem if using the
default; if using a custom cache file name, the cache should still be
manually removed if there are problems to transition to the new style.
-- Update ninja file generation to only create response files for build commands
+- Ninja: Update ninja file generation to only create response files for build commands
which exceed MAXLINELENGTH
- Update the debug output written to stdout for MSVC initialization which is enabled
by setting SCONS_MSCOMMON_DEBUG=- to use the logging module. Also changed the debug
output format written to stdout to include more information about the source for each
message of MSVC initialization debugging output. A single space was added before the
message for all debugging output records written to stdout and to files.
-- Made ninja tool force the ninja file as the only target. Also improved the default
+- Ninja: Made ninja tool force the ninja file as the only target. Also improved the default
targets setup and made sure there is always a default target for
the ninja file, which excludes targets that start and stop the daemon.
-- Update ninja tool so targets passed to SCons are propgated to ninja when scons
+- Ninja: Update ninja tool so targets passed to SCons are propgated to ninja when scons
automatically executes ninja.
- Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool.
- The build argument (i.e., x86) is no longer passed to the MSVC 6.0 to 7.1 batch
@@ -138,7 +138,7 @@ IMPROVEMENTS
- Verify that a user specified msvc script (via MSVC_USE_SCRIPT) exists and raise an
exception immediately when the user specified msvc script does not exist.
- Add cache-debug messages for push failures.
-- Added ninja mingw support and improved ninja CommandGeneratorAction support.
+- Ninja: Added ninja mingw support and improved ninja CommandGeneratorAction support.
- Command-line help is now sensitive to the size of the terminal window: the
width of the help text will scale for terminals other than 80 chars wide.
- Refactor the msvc code so that the same data structures are used during initial msvc detection
@@ -148,7 +148,10 @@ IMPROVEMENTS
- Small refactor of scons daemons using a shared StateInfo class for communication
between the scons interactive thread and the http server thread. Added error handling
for scons interactive failing to startup.
-- Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
+- Ninja: Updated ninja scons daemon scripts to output errors to stderr as well as the daemon log.
+- Ninja: Ensure that all targets set as default via Default() in SConstruct/SConscripts are
+ default targets in the generated ninja.build file.
+
PACKAGING
---------
--
cgit v0.12
From b5ebe82c9867ad9da154e57c70d1f63f2d98d3a1 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Thu, 2 Jun 2022 12:11:10 -0700
Subject: Updated ninja docs in users guilde.
---
SCons/Util.py | 2 +-
doc/user/external.xml | 54 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/SCons/Util.py b/SCons/Util.py
index 0fe42c8..0eeef2a 100644
--- a/SCons/Util.py
+++ b/SCons/Util.py
@@ -2138,7 +2138,7 @@ def wait_for_process_to_die(pid):
break
else:
time.sleep(0.1)
- except ImportError:
+ except ImportError:
# if psutil is not installed we can do this the hard way
while True:
if sys.platform == 'win32':
diff --git a/doc/user/external.xml b/doc/user/external.xml
index b483196..e15f998 100644
--- a/doc/user/external.xml
+++ b/doc/user/external.xml
@@ -303,25 +303,45 @@
Ninja Build Generator
-
-
-
+
+
This is an experimental new feature.
It is subject to change and/or removal without a depreciation cycle.
-
+
+
+
+
+ Loading the &t-link-ninja; tool into SCons will make significant changes
+ in SCons' normal functioning.
+
+
+
- To enable this feature you'll need to use one of the following:
+ SCons will no longer execute any commands directly and will only create the build.ninja and
+ run ninja.
-
-
-# On the command line
---experimental=ninja
+
+
+
+ Any targets specified on the command line will be passed along to &ninja;
+
+
+
+
+
+ To enable this feature you'll need to use one of the following:
+
+
+
+# On the command line --experimental=ninja
# Or in your SConstruct
SetOption('experimental', 'ninja')
-
-
+
+
+
+
Ninja is a small build system that tries to be fast
@@ -366,8 +386,10 @@ conda install -c conda-forge ninja
It is not expected that the &b-link-Ninja; builder will work for all builds at this point. It is still under active
- development. If you find that your build doesn't work with &ninja; please bring this to the users mailing list
- or #scons-help channel on our Discord server.
+ development. If you find that your build doesn't work with &ninja; please bring this to the users mailing list
+ or
+ #scons-help
+ channel on our Discord server.
@@ -377,6 +399,12 @@ conda install -c conda-forge ninja
implement those actions via shell commands in the &ninja; build file.
+
+ When ninja runs the generated &ninja; build file, ninja will launch &scons; as a daemon and feed commands
+ to that &scons; process which &ninja; is unable to build directly. This daemon will stay alive until
+ explicitly killed or it times out. The timeout is set by &cv-link-NINJA_SCONS_DAEMON_KEEP_ALIVE; .
+
+
See:
--
cgit v0.12
From a3d7d83d64a711b8b1738091c7eb6eebe4666716 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Thu, 2 Jun 2022 13:42:36 -0700
Subject: Fix sider complaints
---
SCons/Tool/ninja/NinjaState.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index 770da07..8f7e04b 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -29,7 +29,6 @@ import signal
import tempfile
import shutil
import sys
-import time
from os.path import splitext
from tempfile import NamedTemporaryFile
import ninja
@@ -37,7 +36,7 @@ import hashlib
import SCons
from SCons.Script import COMMAND_LINE_TARGETS
-from SCons.Util import is_List, wait_for_process_to_die
+from SCons.Util import wait_for_process_to_die
from SCons.Errors import InternalError
from .Globals import COMMAND_TYPES, NINJA_RULES, NINJA_POOLS, \
NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
--
cgit v0.12
From b511d618966ff82b2200824123793301039cf579 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Fri, 3 Jun 2022 10:30:20 -0700
Subject: [ci skip] Add note to handle processes not dying properly by raising
exception and handling in calling function
---
SCons/Tool/ninja/NinjaState.py | 2 ++
SCons/Util.py | 1 +
2 files changed, 3 insertions(+)
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index c9cacce..c168c7f 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -643,6 +643,8 @@ class NinjaState:
pass
# wait for the server process to fully killed
+ # TODO: update wait_for_process_to_die() to handle timeout and then catch exception
+ # here and do something smart.
wait_for_process_to_die(pid)
if os.path.exists(scons_daemon_dirty):
diff --git a/SCons/Util.py b/SCons/Util.py
index 0eeef2a..49a3a0f 100644
--- a/SCons/Util.py
+++ b/SCons/Util.py
@@ -2129,6 +2129,7 @@ def wait_for_process_to_die(pid):
"""
Wait for specified process to die, or alternatively kill it
NOTE: This function operates best with psutil pypi package
+ TODO: Add timeout which raises exception
"""
# wait for the process to fully killed
try:
--
cgit v0.12
From ae46e4569da500e0a9270fda61dd983384f68a3a Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Fri, 3 Jun 2022 10:53:50 -0700
Subject: [ci skip] Added blurb about ninja restarting the scons daemon if it
detects need to regenerate the build.ninja
---
doc/user/external.xml | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/doc/user/external.xml b/doc/user/external.xml
index e15f998..0eab32e 100644
--- a/doc/user/external.xml
+++ b/doc/user/external.xml
@@ -400,9 +400,14 @@ conda install -c conda-forge ninja
- When ninja runs the generated &ninja; build file, ninja will launch &scons; as a daemon and feed commands
+ When &ninja; runs the generated &ninja; build file, &ninja; will launch &scons; as a daemon and feed commands
to that &scons; process which &ninja; is unable to build directly. This daemon will stay alive until
- explicitly killed or it times out. The timeout is set by &cv-link-NINJA_SCONS_DAEMON_KEEP_ALIVE; .
+ explicitly killed, or it times out. The timeout is set by &cv-link-NINJA_SCONS_DAEMON_KEEP_ALIVE; .
+
+
+
+ The daemon will be restarted if any &SConscript; file(s) change or the build changes in a way that &ninja; determines
+ it needs to regenerate the build.ninja file
See:
--
cgit v0.12
From 48d31b80ce66afba4b495c1dcad44d9d38d2c242 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Fri, 3 Jun 2022 14:22:21 -0700
Subject: If no newline at end of message supplied to skip_test(), then we
write one to stdout after the original message
---
testing/framework/TestCommon.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/testing/framework/TestCommon.py b/testing/framework/TestCommon.py
index 1999f74..e8045ca 100644
--- a/testing/framework/TestCommon.py
+++ b/testing/framework/TestCommon.py
@@ -782,6 +782,8 @@ class TestCommon(TestCmd):
"""
if message:
sys.stdout.write(message)
+ if not message.endswith('\n'):
+ sys.stdout.write('\n')
sys.stdout.flush()
pass_skips = os.environ.get('TESTCOMMON_PASS_SKIPS')
if pass_skips in [None, 0, '0']:
--
cgit v0.12
From 23a35cec7896e567ff81a8afaab99ab87ed92b8b Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Sat, 4 Jun 2022 07:24:05 -0600
Subject: Update ActionTests for Python 3.11
Required all new bytecode strings.
Some reformatting done (this is not a full formatting run).
Partial fix for #4162, do not close only for this PR.
Signed-off-by: Mats Wichmann
---
SCons/ActionTests.py | 344 +++++++++++++++++++++++++++------------------------
1 file changed, 185 insertions(+), 159 deletions(-)
diff --git a/SCons/ActionTests.py b/SCons/ActionTests.py
index 29ed4a7..0a7f25b 100644
--- a/SCons/ActionTests.py
+++ b/SCons/ActionTests.py
@@ -71,16 +71,16 @@ with open(sys.argv[1], 'w') as f:
if 'ACTPY_PIPE' in os.environ:
if 'PIPE_STDOUT_FILE' in os.environ:
- with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f:
- stdout_msg = f.read()
+ with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f:
+ stdout_msg = f.read()
else:
- stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
- sys.stdout.write( stdout_msg )
+ stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
+ sys.stdout.write(stdout_msg)
if 'PIPE_STDERR_FILE' in os.environ:
- with open(os.environ['PIPE_STDERR_FILE'], 'r') as f:
- stderr_msg = f.read()
+ with open(os.environ['PIPE_STDERR_FILE'], 'r') as f:
+ stderr_msg = f.read()
else:
- stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
+ stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
sys.stderr.write(stderr_msg)
sys.exit(0)
""")
@@ -113,8 +113,9 @@ class CmdStringHolder:
return self.literal
def escape(self, escape_func):
- """Escape the string with the supplied function. The
- function is expected to take an arbitrary string, then
+ """Escape the string with the supplied function.
+
+ The function is expected to take an arbitrary string, then
return it with all special characters escaped and ready
for passing to the command interpreter.
@@ -251,8 +252,8 @@ def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
def test_positional_args(pos_callback, cmd, **kw):
- """Test that Action() returns the expected type and that positional args work.
- """
+ """Test that Action returns the expected type and positional args work."""
+
act = SCons.Action.Action(cmd, **kw)
pos_callback(act)
assert act.varlist == (), act.varlist
@@ -293,7 +294,7 @@ def test_positional_args(pos_callback, cmd, **kw):
test_varlist(pos_callback, none, cmd, None, **kw)
- """Test handling of bad cmdstrfunc arguments """
+ # Test handling of bad cmdstrfunc arguments
try:
a = SCons.Action.Action(cmd, [], **kw)
except SCons.Errors.UserError as e:
@@ -310,8 +311,7 @@ class ActionTestCase(unittest.TestCase):
"""Test the Action() factory function"""
def test_FunctionAction(self):
- """Test the Action() factory's creation of FunctionAction objects
- """
+ """Test the Action() factory's creation of FunctionAction objects."""
def foo():
pass
@@ -325,8 +325,7 @@ class ActionTestCase(unittest.TestCase):
test_positional_args(func_action, [foo])
def test_CommandAction(self):
- """Test the Action() factory's creation of CommandAction objects
- """
+ """Test the Action() factory's creation of CommandAction objects."""
def cmd_action(a):
assert isinstance(a, SCons.Action.CommandAction), a
@@ -343,8 +342,8 @@ class ActionTestCase(unittest.TestCase):
test_positional_args(line_action, [["explicit", "command", "line"]])
def test_ListAction(self):
- """Test the Action() factory's creation of ListAction objects
- """
+ """Test the Action() factory's creation of ListAction objects."""
+
a1 = SCons.Action.Action(["x", "y", "z", ["a", "b", "c"]])
assert isinstance(a1, SCons.Action.ListAction), a1
assert a1.varlist == (), a1.varlist
@@ -401,8 +400,7 @@ class ActionTestCase(unittest.TestCase):
assert a5.list[1].strfunction == foo, a5.list[1].strfunction
def test_CommandGeneratorAction(self):
- """Test the Action() factory's creation of CommandGeneratorAction objects
- """
+ """Test the Action factory's creation of CommandGeneratorAction objects."""
def foo(): pass
@@ -413,8 +411,7 @@ class ActionTestCase(unittest.TestCase):
test_positional_args(gen_action, foo, generator=1)
def test_LazyCmdGeneratorAction(self):
- """Test the Action() factory's creation of lazy CommandGeneratorAction objects
- """
+ """Test the Action factory's creation of lazy CommandGeneratorAction objects."""
def lazy_action(a):
assert isinstance(a, SCons.Action.LazyAction), a
@@ -425,8 +422,8 @@ class ActionTestCase(unittest.TestCase):
test_positional_args(lazy_action, "${FOO}")
def test_no_action(self):
- """Test when the Action() factory can't create an action object
- """
+ """Test when the Action() factory can't create an action object."""
+
try:
a5 = SCons.Action.Action(1)
except TypeError:
@@ -435,8 +432,8 @@ class ActionTestCase(unittest.TestCase):
assert 0, "Should have thrown a TypeError creating Action from an int."
def test_reentrance(self):
- """Test the Action() factory when the action is already an Action object
- """
+ """Test the Action factory when the action is already an Action object."""
+
a1 = SCons.Action.Action("foo")
a2 = SCons.Action.Action(a1)
assert a2 is a1, a2
@@ -445,8 +442,7 @@ class ActionTestCase(unittest.TestCase):
class _ActionActionTestCase(unittest.TestCase):
def test__init__(self):
- """Test creation of _ActionAction objects
- """
+ """Test creation of _ActionAction objects."""
def func1():
pass
@@ -519,8 +515,7 @@ class _ActionActionTestCase(unittest.TestCase):
assert a.varlist is t, a.varlist
def test_dup_keywords(self):
- """Test handling of both cmdstr and strfunction arguments
- """
+ """Test handling of both cmdstr and strfunction arguments."""
def func():
pass
@@ -535,8 +530,8 @@ class _ActionActionTestCase(unittest.TestCase):
raise Exception("did not catch expected UserError")
def test___cmp__(self):
- """Test Action comparison
- """
+ """Test Action comparison."""
+
a1 = SCons.Action.Action("x")
a2 = SCons.Action.Action("x")
assert a1 == a2
@@ -545,8 +540,8 @@ class _ActionActionTestCase(unittest.TestCase):
assert a2 != a3
def test_print_cmd_lines(self):
- """Test the print_cmd_lines() method
- """
+ """Test the print_cmd_lines() method."""
+
save_stdout = sys.stdout
try:
@@ -565,8 +560,8 @@ class _ActionActionTestCase(unittest.TestCase):
sys.stdout = save_stdout
def test___call__(self):
- """Test calling an Action
- """
+ """Test calling an Action."""
+
save_stdout = sys.stdout
save_print_actions = SCons.Action.print_actions
@@ -753,8 +748,8 @@ class _ActionActionTestCase(unittest.TestCase):
SCons.Action.execute_actions = save_execute_actions
def test_presub_lines(self):
- """Test the presub_lines() method
- """
+ """Test the presub_lines() method."""
+
env = Environment()
a = SCons.Action.Action("x")
s = a.presub_lines(env)
@@ -875,8 +870,8 @@ class _ActionActionTestCase(unittest.TestCase):
class CommandActionTestCase(unittest.TestCase):
def test___init__(self):
- """Test creation of a command Action
- """
+ """Test creation of a command Action."""
+
a = SCons.Action.CommandAction(["xyzzy"])
assert a.cmd_list == ["xyzzy"], a.cmd_list
assert a.cmdstr is _null, a.cmdstr
@@ -886,8 +881,8 @@ class CommandActionTestCase(unittest.TestCase):
assert a.cmdstr == "cadabra", a.cmdstr
def test___str__(self):
- """Test fetching the pre-substitution string for command Actions
- """
+ """Test fetching the pre-substitution string for command Actions."""
+
env = Environment()
act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
s = str(act)
@@ -900,8 +895,7 @@ class CommandActionTestCase(unittest.TestCase):
assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
def test_genstring(self):
- """Test the genstring() method for command Actions
- """
+ """Test the genstring() method for command Actions."""
env = Environment()
t1 = DummyNode('t1')
@@ -938,8 +932,7 @@ class CommandActionTestCase(unittest.TestCase):
assert s == expect, s
def test_strfunction(self):
- """Test fetching the string representation of command Actions
- """
+ """Test fetching the string representation of command Actions."""
env = Environment()
t1 = DummyNode('t1')
@@ -1090,9 +1083,8 @@ class CommandActionTestCase(unittest.TestCase):
assert s == "foo bar", s
def test_execute(self):
- """Test execution of command Actions
+ """Test execution of command Actions."""
- """
try:
env = self.env
except AttributeError:
@@ -1247,8 +1239,7 @@ class CommandActionTestCase(unittest.TestCase):
assert r == 0, r
def test_set_handler(self):
- """Test setting the command handler...
- """
+ """Test setting the command handler..."""
class Test:
def __init__(self):
@@ -1299,8 +1290,7 @@ class CommandActionTestCase(unittest.TestCase):
assert t.executed == ['**xyzzy**'], t.executed
def test_get_contents(self):
- """Test fetching the contents of a command Action
- """
+ """Test fetching the contents of a command Action."""
def CmdGen(target, source, env, for_signature):
assert for_signature
@@ -1373,6 +1363,7 @@ class CommandActionTestCase(unittest.TestCase):
def test_get_implicit_deps(self):
"""Test getting the implicit dependencies of a command Action."""
+
class SpecialEnvironment(Environment):
def WhereIs(self, prog):
return prog
@@ -1413,11 +1404,11 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def factory(self, act, **kw):
"""Pass any keywords as a dict"""
+
return SCons.Action.CommandGeneratorAction(act, kw)
def test___init__(self):
- """Test creation of a command generator Action
- """
+ """Test creation of a command generator Action."""
def f(target, source, env):
pass
@@ -1426,8 +1417,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
assert a.generator == f
def test___str__(self):
- """Test the pre-substitution strings for command generator Actions
- """
+ """Test the pre-substitution strings for command generator Actions."""
def f(target, source, env, for_signature, self=self):
# See if "env" is really a construction environment (or
@@ -1444,8 +1434,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
assert s == 'FOO', s
def test_genstring(self):
- """Test the command generator Action genstring() method
- """
+ """Test the command generator Action genstring() method."""
def f(target, source, env, for_signature, self=self):
dummy = env['dummy']
@@ -1459,8 +1448,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
def test_execute(self):
- """Test executing a command generator Action
- """
+ """Test executing a command generator Action."""
def f(target, source, env, for_signature, self=self):
dummy = env['dummy']
@@ -1519,8 +1507,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
assert self.rfile_called
def test_get_contents(self):
- """Test fetching the contents of a command generator Action
- """
+ """Test fetching the contents of a command generator Action."""
def f(target, source, env, for_signature):
foo = env['foo']
@@ -1540,8 +1527,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
assert c == b"guux FFF BBB test", c
def test_get_contents_of_function_action(self):
- """Test contents of a CommandGeneratorAction-generated FunctionAction
- """
+ """Test contents of a CommandGeneratorAction-generated FunctionAction."""
def LocalFunc():
pass
@@ -1554,6 +1540,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
(3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
}
meth_matches = [
@@ -1571,12 +1558,12 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
a = self.factory(f_global)
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr(
+ assert c == func_matches[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr(
func_matches[sys.version_info[:2]])
a = self.factory(f_local)
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr(
+ assert c == func_matches[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr(
func_matches[sys.version_info[:2]])
def f_global2(target, source, env, for_signature):
@@ -1599,8 +1586,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
class FunctionActionTestCase(unittest.TestCase):
def test___init__(self):
- """Test creation of a function Action
- """
+ """Test creation of a function Action."""
def func1():
pass
@@ -1623,8 +1609,7 @@ class FunctionActionTestCase(unittest.TestCase):
assert a.strfunction == func3, a.strfunction
def test___str__(self):
- """Test the __str__() method for function Actions
- """
+ """Test the __str__() method for function Actions."""
def func1():
pass
@@ -1642,8 +1627,8 @@ class FunctionActionTestCase(unittest.TestCase):
assert s == "class1(target, source, env)", s
def test_execute(self):
- """Test executing a function Action
- """
+ """Test executing a function Action."""
+
self.inc = 0
def f(target, source, env):
@@ -1721,8 +1706,7 @@ class FunctionActionTestCase(unittest.TestCase):
assert self.string_it
def test_get_contents(self):
- """Test fetching the contents of a function Action
- """
+ """Test fetching the contents of a function Action."""
def LocalFunc():
pass
@@ -1734,6 +1718,7 @@ class FunctionActionTestCase(unittest.TestCase):
(3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
}
@@ -1744,6 +1729,7 @@ class FunctionActionTestCase(unittest.TestCase):
(3, 8): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 9): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 10): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 11): bytearray(b'1, 1, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
}
def factory(act, **kw):
@@ -1751,20 +1737,23 @@ class FunctionActionTestCase(unittest.TestCase):
a = factory(GlobalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- 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 == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]])
a = factory(LocalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- 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 == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]])
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 == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- func_matches[sys.version_info[:2]])
+ assert (
+ c == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\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'))
@@ -1775,8 +1764,9 @@ class FunctionActionTestCase(unittest.TestCase):
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 == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\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)
@@ -1796,12 +1786,12 @@ class FunctionActionTestCase(unittest.TestCase):
lc = LocalClass()
a = factory(lc.LocalMethod)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c == meth_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- meth_matches[sys.version_info[:2]])
+ assert (
+ c == meth_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\nExpected one of \n" + repr(meth_matches[sys.version_info[:2]])
def test_strfunction(self):
- """Test the FunctionAction.strfunction() method
- """
+ """Test the FunctionAction.strfunction() method."""
def func():
pass
@@ -1825,8 +1815,7 @@ class FunctionActionTestCase(unittest.TestCase):
class ListActionTestCase(unittest.TestCase):
def test___init__(self):
- """Test creation of a list of subsidiary Actions
- """
+ """Test creation of a list of subsidiary Actions."""
def func():
pass
@@ -1838,8 +1827,7 @@ class ListActionTestCase(unittest.TestCase):
assert a.list[2].list[0].cmd_list == 'y'
def test___str__(self):
- """Test the __str__() method for a list of subsidiary Actions
- """
+ """Test the __str__() method for a list of subsidiary Actions."""
def f(target, source, env):
pass
@@ -1852,8 +1840,7 @@ class ListActionTestCase(unittest.TestCase):
assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
def test_genstring(self):
- """Test the genstring() method for a list of subsidiary Actions
- """
+ """Test the genstring() method for a list of subsidiary Actions."""
def f(target, source, env):
pass
@@ -1867,8 +1854,7 @@ class ListActionTestCase(unittest.TestCase):
assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
def test_execute(self):
- """Test executing a list of subsidiary Actions
- """
+ """Test executing a list of subsidiary Actions."""
self.inc = 0
def f(target, source, env):
@@ -1904,8 +1890,8 @@ class ListActionTestCase(unittest.TestCase):
assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
def test_get_contents(self):
- """Test fetching the contents of a list of subsidiary Actions
- """
+ """Test fetching the contents of a list of subsidiary Actions."""
+
self.foo = 0
def gen(target, source, env, for_signature):
@@ -1923,8 +1909,8 @@ class ListActionTestCase(unittest.TestCase):
class LazyActionTestCase(unittest.TestCase):
def test___init__(self):
- """Test creation of a lazy-evaluation Action
- """
+ """Test creation of a lazy-evaluation Action."""
+
# Environment variable references should create a special type
# of LazyAction that lazily evaluates the variable for whether
# it's a string or something else before doing anything.
@@ -1937,8 +1923,7 @@ class LazyActionTestCase(unittest.TestCase):
assert a10.var == 'FOO', a10.var
def test_genstring(self):
- """Test the lazy-evaluation Action genstring() method
- """
+ """Test the lazy-evaluation Action genstring() method."""
def f(target, source, env):
pass
@@ -1952,8 +1937,7 @@ class LazyActionTestCase(unittest.TestCase):
assert s == 'xxx', s
def test_execute(self):
- """Test executing a lazy-evaluation Action
- """
+ """Test executing a lazy-evaluation Action."""
def f(target, source, env):
s = env['s']
@@ -1969,16 +1953,15 @@ class LazyActionTestCase(unittest.TestCase):
assert c == "act.py: 'lazy'\n", c
def test_get_contents(self):
- """Test fetching the contents of a lazy-evaluation Action
- """
+ """Test fetching the contents of a lazy-evaluation Action."""
+
a = SCons.Action.Action("${FOO}")
env = Environment(FOO=[["This", "is", "a", "test"]])
c = a.get_contents(target=[], source=[], env=env)
assert c == b"This is a test", c
def test_get_contents_of_function_action(self):
- """Test fetching the contents of a lazy-evaluation FunctionAction
- """
+ """Test fetching the contents of a lazy-evaluation FunctionAction."""
def LocalFunc():
pass
@@ -1990,6 +1973,7 @@ class LazyActionTestCase(unittest.TestCase):
(3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 9): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
(3, 10): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
}
meth_matches = [
@@ -2005,21 +1989,24 @@ 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 == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- func_matches[sys.version_info[:2]])
+ assert (
+ c == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\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 == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- func_matches[sys.version_info[:2]])
+ assert (
+ c == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\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'
env = Environment(FOO=factory(GlobalFunc, varlist=['XYZ']))
c = a.get_contents(target=[], source=[], env=env)
- 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 == func_matches[sys.version_info[:2]]
+ ), f"Got\n{c!r}\nExpected one of \n" + repr(func_matches[sys.version_info[:2]])
env['XYZ'] = 'foo'
c = a.get_contents(target=[], source=[], env=env)
@@ -2029,6 +2016,7 @@ class LazyActionTestCase(unittest.TestCase):
class ActionCallerTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of an ActionCaller"""
+
ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO': 4, 'BAR': 5})
assert ac.parent == 1, ac.parent
assert ac.args == [2, 3], ac.args
@@ -2050,20 +2038,24 @@ class ActionCallerTestCase(unittest.TestCase):
(3, 8): b'd\x00S\x00',
(3, 9): b'd\x00S\x00',
(3, 10): b'd\x00S\x00',
-
+ (3, 11): b'\x97\x00d\x00S\x00',
}
af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], (
+ f"Got\n{c!r}\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 == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], (
+ f"Got\n{c!r}\nExpected one of \n"
+ + repr(matches[sys.version_info[:2]])
+ )
class LocalActFunc:
def __call__(self):
@@ -2072,14 +2064,18 @@ class ActionCallerTestCase(unittest.TestCase):
af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], (
+ f"Got\n{c!r}\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 == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
- matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], (
+ f"Got\n{c!r}\nExpected one of \n"
+ + repr(matches[sys.version_info[:2]])
+ )
matches = [
b"",
@@ -2089,13 +2085,12 @@ class ActionCallerTestCase(unittest.TestCase):
af = SCons.Action.ActionFactory(str, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == "" or \
- c == "" or \
- c == "", repr(c)
+ assert c in ("", "", ""), repr(c)
# ^^ class str for python3
def test___call__(self):
"""Test calling an ActionCaller"""
+
actfunc_args = []
def actfunc(a1, a2, a3, args=actfunc_args):
@@ -2123,6 +2118,7 @@ class ActionCallerTestCase(unittest.TestCase):
def test_strfunction(self):
"""Test calling the ActionCaller strfunction() method"""
+
strfunc_args = []
def actfunc(a1, a2, a3, a4):
@@ -2159,6 +2155,7 @@ class ActionFactoryTestCase(unittest.TestCase):
def test___call__(self):
"""Test calling whatever's returned from an ActionFactory"""
+
actfunc_args = []
strfunc_args = []
@@ -2175,12 +2172,12 @@ class ActionFactoryTestCase(unittest.TestCase):
class ActionCompareTestCase(unittest.TestCase):
-
def test_1_solo_name(self):
"""Test Lazy Cmd Generator Action get_name alone.
Basically ensures we can locate the builder, comparing it to
itself along the way."""
+
bar = SCons.Builder.Builder(action={})
env = Environment(BUILDERS={'BAR': bar})
name = bar.get_name(env)
@@ -2191,12 +2188,12 @@ class ActionCompareTestCase(unittest.TestCase):
Ensure that we can compare builders (and thereby actions) to
each other safely."""
+
foo = SCons.Builder.Builder(action='$FOO', suffix='.foo')
bar = SCons.Builder.Builder(action={})
assert foo != bar
assert foo.action != bar.action
- env = Environment(BUILDERS={'FOO': foo,
- 'BAR': bar})
+ env = Environment(BUILDERS={'FOO': foo, 'BAR': bar})
name = foo.get_name(env)
assert name == 'FOO', name
name = bar.get_name(env)
@@ -2214,10 +2211,7 @@ class ActionCompareTestCase(unittest.TestCase):
bar = SCons.Builder.Builder(action={}, suffix={None: '.bar'})
bar.add_action('.cow', "$MOO")
dog = SCons.Builder.Builder(suffix='.bar')
-
- env = Environment(BUILDERS={'FOO': foo,
- 'BAR': bar,
- 'DOG': dog})
+ env = Environment(BUILDERS={'FOO': foo, 'BAR': bar, 'DOG': dog})
assert foo.get_name(env) == 'FOO', foo.get_name(env)
assert bar.get_name(env) == 'BAR', bar.get_name(env)
@@ -2236,7 +2230,6 @@ class TestClass:
class ObjectContentsTestCase(unittest.TestCase):
-
def test_function_contents(self):
"""Test that Action._function_contents works"""
@@ -2244,20 +2237,25 @@ class ObjectContentsTestCase(unittest.TestCase):
"""A test function"""
return a
- # Since the python bytecode has per version differences, we need different expected results per version
+ # Since the python bytecode has per version differences,
+ # we need different expected results per version
expected = {
(3, 5): (bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()')),
(3, 6): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')),
(3, 7): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')),
(3, 8): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')),
(3, 9): (bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')),
- (3, 10): (bytearray(b'3, 3, 0, 0,(N.),(),(|\x00S\x00),(),()'),
- bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()')) # 3.10.1, 3.10.2
+ (3, 10): (
+ bytearray(b'3, 3, 0, 0,(N.),(),(|\x00S\x00),(),()'),
+ bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
+ ), # 3.10.1, 3.10.2
+ (3, 11): bytearray(b'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'),
}
c = SCons.Action._function_contents(func1)
- assert c in expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(
- expected[sys.version_info[:2]])
+ assert c in expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr(
+ expected[sys.version_info[:2]]
+ )
def test_object_contents(self):
"""Test that Action._object_contents works"""
@@ -2268,24 +2266,34 @@ class ObjectContentsTestCase(unittest.TestCase):
# c = SCons.Action._object_instance_content(o)
- # Since the python bytecode has per version differences, we need different expected results per version
+ # Since the python bytecode has per version differences,
+ # we need different expected results per version
expected = {
(3, 5): bytearray(
- b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"
+ ),
(3, 7): bytearray(
- b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"
+ ),
(3, 8): bytearray(
- b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"
+ ),
(3, 9): bytearray(
- b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"
+ ),
(3, 10): bytearray(
- b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"),
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{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}}}"
+ ),
+ (3, 11): bytearray(
+ b"{TestClass:__main__}[[[(, ()), [(, (,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x97\x00d\x01|\x00_\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02|\x00_\x01\x00\x00\x00\x00\x00\x00\x00\x00d\x00S\x00),(),(),2, 2, 0, 0,(),(),(\x97\x00d\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]])
+ assert c == expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr(
+ expected[sys.version_info[:2]]
+ )
def test_code_contents(self):
"""Test that Action._code_contents works"""
@@ -2295,25 +2303,43 @@ class ObjectContentsTestCase(unittest.TestCase):
# Since the python bytecode has per version differences, we need different expected results per version
expected = {
- (3, 5): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'),
- (3, 6): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
- (3, 7): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
- (3, 8): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
- (3, 9): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
- (3, 10): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
+ (3, 5): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'
+ ),
+ (3, 6): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
+ ),
+ (3, 7): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
+ ),
+ (3, 8): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
+ ),
+ (3, 9): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
+ ),
+ (3, 10): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
+ ),
+ (3, 11): bytearray(
+ b'0, 0, 0, 0,(Hello, World!),(print),(\x97\x00\x02\x00e\x00d\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x01S\x00)'),
}
- assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(expected[
- sys.version_info[:2]])
+ assert c == expected[sys.version_info[:2]], f"Got\n{c!r}\nExpected\n" + repr(
+ expected[sys.version_info[:2]]
+ )
def test_uncaught_exception_bubbles(self):
"""Test that _subproc bubbles uncaught exceptions"""
+
try:
- pobj = SCons.Action._subproc(Environment(),
- None,
- stdin='devnull',
- stderr='devnull',
- stdout=subprocess.PIPE)
+ pobj = SCons.Action._subproc(
+ Environment(),
+ None,
+ stdin='devnull',
+ stderr='devnull',
+ stdout=subprocess.PIPE,
+ )
pobj.wait()
except EnvironmentError:
pass
--
cgit v0.12
From eed3b5845a6a1258cd979d39b3f47b7133053552 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Sun, 5 Jun 2022 18:23:01 -0700
Subject: Added test for invalid env['MSVC_NOTFOUND_POLICY'] value
---
test/MSVC/msvc_badversion.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/test/MSVC/msvc_badversion.py b/test/MSVC/msvc_badversion.py
index a36bd2b..65dc789 100644
--- a/test/MSVC/msvc_badversion.py
+++ b/test/MSVC/msvc_badversion.py
@@ -44,25 +44,35 @@ installed_msvc_versions = msvc.get_installed_vcs()
# skip_if_not_msvc() function would have skipped the test
test.write('SConstruct', """\
+DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9')
""")
test.run(arguments='-Q -s', stdout='')
test.write('SConstruct', """\
+DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='ignore')
""")
test.run(arguments='-Q -s', stdout='')
test.write('SConstruct', """\
+DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='warning')
""")
test.run(arguments='-Q -s', stdout='')
test.write('SConstruct', """\
+DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='error')
""")
test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)
+test.write('SConstruct', """\
+env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='bad_value')
+""")
+test.run(arguments='-Q -s', status=2, stderr=r"^.* Value specified for MSVC_NOTFOUND_POLICY.+", match=TestSCons.match_re_dotall)
+
+
test.pass_test()
# Local Variables:
--
cgit v0.12
From de86183d3307c32b7b917e8b2dc989921b632ec7 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Sun, 5 Jun 2022 18:29:46 -0700
Subject: Add Blurb for MSVC_NOTFOUND_POLICY
---
SCons/Tool/msvc.xml | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 4a45d26..59a285e 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -74,6 +74,7 @@ Sets construction variables for the Microsoft Visual C/C++ compiler.
PCHPCHSTOPPDB
+MSVC_NOTFOUND_POLICY
@@ -578,5 +579,28 @@ and also before &f-link-env-Tool; is called to ininitialize any of those tools:
+
+
+
+Specify how to handle missing MSVC.
+
+
+
+ The MSVC_NOTFOUND_POLICY specifies how &scons; should handle when there is no installed
+ MSVC or if a specific version is requested, that version is not available.
+
+
+
+Valid values for MSVC_NOTFOUND_POLICY are listed here. Note that each group below is equivalent.
+
+
+'error', 'Error', 'ERROR', 'exception', 'Exception', 'EXCEPTION'
+'warning', 'Warning', 'WARNING', 'warn', 'Warn', 'WARN'
+'suppress', 'Suppress', 'SUPPRESS'
+
+
+
+
+
--
cgit v0.12
From 294629587a8cadfa1b6e409d2a4751a7be4880bf Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 6 Jun 2022 09:55:50 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 44 +++++++++++++++++++++++++++++++++++---------
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 59a285e..84c0e90 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -582,22 +582,48 @@ and also before &f-link-env-Tool; is called to ininitialize any of those tools:
-Specify how to handle missing MSVC.
+Specify the &scons; action to take when an msvc installation is not found.
- The MSVC_NOTFOUND_POLICY specifies how &scons; should handle when there is no installed
- MSVC or if a specific version is requested, that version is not available.
+ The MSVC_NOTFOUND_POLICY specifies the action &scons; should take when there are no
+ msvc versions installed or when the requested msvc version is not installed.
-Valid values for MSVC_NOTFOUND_POLICY are listed here. Note that each group below is equivalent.
+The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; action taken are:
-
-'error', 'Error', 'ERROR', 'exception', 'Exception', 'EXCEPTION'
-'warning', 'Warning', 'WARNING', 'warn', 'Warn', 'WARN'
-'suppress', 'Suppress', 'SUPPRESS'
-
+
+
+
+
+'error', 'Error', 'ERROR', 'exception', 'Exception', 'EXCEPTION'
+
+
+Raise an exception when there are no msvc versions installed or when the requested msvc version is not installed.
+
+
+
+
+
+'warning', 'Warning', 'WARNING', 'warn', 'Warn', 'WARN'
+
+
+Issue a warning when there are no msvc versions installed or when the requested msvc version is not installed.
+
+
+
+
+
+'ignore', 'Ignore', 'IGNORE', 'suppress', 'Suppress', 'SUPPRESS'
+
+
+Take no action and continue when there are no msvc versions installed or when the requested msvc version is not installed. Depending on usage, this could result in build failure(s).
+
+
+
+
+
--
cgit v0.12
From 69d6b9acceeda73780592d1b8e09b3aa4f2c3813 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 6 Jun 2022 10:11:51 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 84c0e90..bb484c5 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -582,11 +582,11 @@ and also before &f-link-env-Tool; is called to ininitialize any of those tools:
-Specify the &scons; action to take when an msvc installation is not found.
+Specify the action taken when the Microsoft Visual C/C++ compiler is not found.
- The MSVC_NOTFOUND_POLICY specifies the action &scons; should take when there are no
+ The MSVC_NOTFOUND_POLICY specifies the &scons; action taken when there are no
msvc versions installed or when the requested msvc version is not installed.
--
cgit v0.12
From e7c4d5bb062d979da2a27560db7a658cdef9c262 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 6 Jun 2022 11:56:37 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index bb484c5..187f3b5 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -597,7 +597,7 @@ The valid values for MSVC_NOTFOUND_POLICY and the corresponding &
-'error', 'Error', 'ERROR', 'exception', 'Exception', 'EXCEPTION'
+'Error' or 'Exception'
Raise an exception when there are no msvc versions installed or when the requested msvc version is not installed.
@@ -606,25 +606,36 @@ Raise an exception when there are no msvc versions installed or when the request
-'warning', 'Warning', 'WARNING', 'warn', 'Warn', 'WARN'
+'Warning' or 'Warn'
-Issue a warning when there are no msvc versions installed or when the requested msvc version is not installed.
+Issue a warning and continue when there are no msvc versions installed or when the requested msvc version is not installed.
+Depending on usage, this could result in build failure(s).
-'ignore', 'Ignore', 'IGNORE', 'suppress', 'Suppress', 'SUPPRESS'
+'Ignore' or 'Suppress'
-Take no action and continue when there are no msvc versions installed or when the requested msvc version is not installed. Depending on usage, this could result in build failure(s).
+Take no action and continue when there are no msvc versions installed or when the requested msvc version is not installed.
+Depending on usage, this could result in build failure(s).
+
+Note: in addition to the camel case values shown above, lower case and upper case values are accepted as well.
+
+
+
+The default scons action taken when there are no msvc versions installed or when the requested msvc version is
+not installed is to issue a warning and continue. This may change in the future.
+
+
--
cgit v0.12
From 1d3e0e3b0edd4b723d868434c49997215da45fc1 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 6 Jun 2022 13:00:20 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 187f3b5..59b8944 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -582,16 +582,16 @@ and also before &f-link-env-Tool; is called to ininitialize any of those tools:
-Specify the action taken when the Microsoft Visual C/C++ compiler is not found.
+Specify the scons behavior when the Microsoft Visual C/C++ compiler is not detected.
- The MSVC_NOTFOUND_POLICY specifies the &scons; action taken when there are no
- msvc versions installed or when the requested msvc version is not installed.
+ The MSVC_NOTFOUND_POLICY specifies the &scons; behavior when no msvc versions are detected or
+ when the requested msvc version is not detected.
-The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; action taken are:
+The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; behavior are:
@@ -600,7 +600,7 @@ The valid values for MSVC_NOTFOUND_POLICY and the corresponding &
'Error' or 'Exception'
-Raise an exception when there are no msvc versions installed or when the requested msvc version is not installed.
+Raise an exception when no msvc versions are detected or when the requested msvc version is not detected.
@@ -609,7 +609,7 @@ Raise an exception when there are no msvc versions installed or when the request
'Warning' or 'Warn'
-Issue a warning and continue when there are no msvc versions installed or when the requested msvc version is not installed.
+Issue a warning and continue when no msvc versions are detected or when the requested msvc version is not detected.
Depending on usage, this could result in build failure(s).
@@ -619,7 +619,7 @@ Depending on usage, this could result in build failure(s).
'Ignore' or 'Suppress'
-Take no action and continue when there are no msvc versions installed or when the requested msvc version is not installed.
+Take no action and continue when no msvc versions are detected or when the requested msvc version is not detected.
Depending on usage, this could result in build failure(s).
@@ -632,8 +632,8 @@ Note: in addition to the camel case values shown above, lower case and upper cas
-The default scons action taken when there are no msvc versions installed or when the requested msvc version is
-not installed is to issue a warning and continue. This may change in the future.
+The default scons behavior when no msvc versions are detected or when the requested msvc version is not detected
+is to issue a warning and continue. This may change in the future.
--
cgit v0.12
From bd3cc3b1f0218643a6c8b610bc1328e169f45c6c Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Mon, 6 Jun 2022 16:11:28 -0500
Subject: Updated lex emitter to respect escaped spaces when climbing out of a
the SCosncript dir
---
CHANGES.txt | 1 +
RELEASE.txt | 1 +
SCons/Tool/lex.py | 2 +-
test/LEX/lex_headerfile.py | 44 ++++++++++++++++++++++
test/LEX/lex_headerfile/spaced path/SConstruct | 2 +
test/LEX/lex_headerfile/spaced path/src/SConscript | 10 +++++
test/LEX/lex_headerfile/spaced path/src/lexer.l | 1 +
test/LEX/lex_headerfile/spaced path/src/lexer2.l | 1 +
8 files changed, 61 insertions(+), 1 deletion(-)
create mode 100644 test/LEX/lex_headerfile.py
create mode 100644 test/LEX/lex_headerfile/spaced path/SConstruct
create mode 100644 test/LEX/lex_headerfile/spaced path/src/SConscript
create mode 100644 test/LEX/lex_headerfile/spaced path/src/lexer.l
create mode 100644 test/LEX/lex_headerfile/spaced path/src/lexer2.l
diff --git a/CHANGES.txt b/CHANGES.txt
index 03692d6..efea669 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -116,6 +116,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
+ - Updated lex emitter to respect escaped spaces when climbing out of a the SCosncript dir
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index cfa8afc..a393a36 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -134,6 +134,7 @@ FIXES
- The system environment variable names imported for MSVC 7.0 and 6.0 were updated to be
consistent with the variables names defined by their respective installers. This fixes an
error caused when bypassing MSVC detection by specifying the MSVC 7.0 batch file directly.
+- Updated lex emitter to respect escaped spaces when climbing out of a the SCosncript dir
IMPROVEMENTS
------------
diff --git a/SCons/Tool/lex.py b/SCons/Tool/lex.py
index d8d8de4..c33d0fa 100644
--- a/SCons/Tool/lex.py
+++ b/SCons/Tool/lex.py
@@ -58,7 +58,7 @@ def lexEmitter(target, source, env):
# Different options that are used to trigger the creation of extra files.
fileGenOptions = ["--header-file=", "--tables-file="]
- lexflags = env.subst("$LEXFLAGS", target=target, source=source)
+ lexflags = env.subst_list("$LEXFLAGS", target=target, source=source)
for option in SCons.Util.CLVar(lexflags):
for fileGenOption in fileGenOptions:
l = len(fileGenOption)
diff --git a/test/LEX/lex_headerfile.py b/test/LEX/lex_headerfile.py
new file mode 100644
index 0000000..c2e2e8b
--- /dev/null
+++ b/test/LEX/lex_headerfile.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Test the headerfile option for lex tool.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.dir_fixture('lex_headerfile')
+
+test.run(chdir='spaced path', arguments='.')
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/LEX/lex_headerfile/spaced path/SConstruct b/test/LEX/lex_headerfile/spaced path/SConstruct
new file mode 100644
index 0000000..aa4aca0
--- /dev/null
+++ b/test/LEX/lex_headerfile/spaced path/SConstruct
@@ -0,0 +1,2 @@
+DefaultEnvironment(tools=[])
+SConscript("src/SConscript")
\ No newline at end of file
diff --git a/test/LEX/lex_headerfile/spaced path/src/SConscript b/test/LEX/lex_headerfile/spaced path/src/SConscript
new file mode 100644
index 0000000..a3f4bfd
--- /dev/null
+++ b/test/LEX/lex_headerfile/spaced path/src/SConscript
@@ -0,0 +1,10 @@
+env = Environment(tools=['lex'])
+
+def make_header_path(env, target, source, for_signature):
+ return target[1]
+
+env.Replace(LEX_HEADER_FILE_GEN=make_header_path)
+env.Append(LEXFLAGS=['--header-file=$LEX_HEADER_FILE_GEN'])
+
+env.CFile(target=['#gen_src/lexer.c', '#gen_src/lexer.l.h'], source='lexer.l')
+env.CFile(target=['#gen_src/lexer2.c', '#gen_src/lexer2.l.h'], source='lexer2.l')
\ No newline at end of file
diff --git a/test/LEX/lex_headerfile/spaced path/src/lexer.l b/test/LEX/lex_headerfile/spaced path/src/lexer.l
new file mode 100644
index 0000000..66b82a4
--- /dev/null
+++ b/test/LEX/lex_headerfile/spaced path/src/lexer.l
@@ -0,0 +1 @@
+%%
\ No newline at end of file
diff --git a/test/LEX/lex_headerfile/spaced path/src/lexer2.l b/test/LEX/lex_headerfile/spaced path/src/lexer2.l
new file mode 100644
index 0000000..66b82a4
--- /dev/null
+++ b/test/LEX/lex_headerfile/spaced path/src/lexer2.l
@@ -0,0 +1 @@
+%%
\ No newline at end of file
--
cgit v0.12
From 0ed5eea9af9358a0bfbeefa42507775947fe2d5f Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 12:30:50 -0500
Subject: Added option to allow scons to determine if it should skip ninja
regeneration.
---
CHANGES.txt | 2 +
RELEASE.txt | 2 +
SCons/Script/SConsOptions.py | 3 +-
SCons/Tool/ninja/NinjaState.py | 119 ++++++++++++++-------
SCons/Tool/ninja/Utils.py | 25 ++++-
SCons/Tool/ninja/__init__.py | 11 +-
test/ninja/ninja_file_deterministic.py | 105 ++++++++++++++++++
.../sconstruct_ninja_determinism | 20 ++++
8 files changed, 241 insertions(+), 46 deletions(-)
create mode 100644 test/ninja/ninja_file_deterministic.py
create mode 100644 test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism
diff --git a/CHANGES.txt b/CHANGES.txt
index 03692d6..4541168 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -116,6 +116,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
+ - Ninja: added option to skip ninja regeneration if scons can determine the ninja file does
+ not need to be regenerated.
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index cfa8afc..0dae549 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -88,6 +88,8 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
require delayed expansion to be enabled which is currently not supported and is
typically not enabled by default on the host system. The batch files may also require
environment variables that are not included by default in the msvc environment.
+- Ninja: added option to skip ninja regeneration if scons can determine the ninja file does
+ not need to be regenerated.
FIXES
-----
diff --git a/SCons/Script/SConsOptions.py b/SCons/Script/SConsOptions.py
index e2631fb..0210b79 100644
--- a/SCons/Script/SConsOptions.py
+++ b/SCons/Script/SConsOptions.py
@@ -151,7 +151,8 @@ class SConsValues(optparse.Values):
# Requested setable flag in : https://github.com/SCons/scons/issues/3983
# From experimental ninja
'disable_execute_ninja',
- 'disable_ninja'
+ 'disable_ninja',
+ 'skip_ninja_regen'
]
def set_option(self, name, value):
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index c168c7f..c75c966 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -29,6 +29,8 @@ import signal
import tempfile
import shutil
import sys
+import random
+import filecmp
from os.path import splitext
from tempfile import NamedTemporaryFile
import ninja
@@ -42,7 +44,7 @@ from .Globals import COMMAND_TYPES, NINJA_RULES, NINJA_POOLS, \
NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS
from .Rules import _install_action_function, _mkdir_action_function, _lib_symlink_action_function, _copy_action_function
from .Utils import get_path, alias_to_ninja_build, generate_depfile, ninja_noop, get_order_only, \
- get_outputs, get_inputs, get_dependencies, get_rule, get_command_env, to_escaped_list
+ get_outputs, get_inputs, get_dependencies, get_rule, get_command_env, to_escaped_list, ninja_sorted_build
from .Methods import get_command
@@ -82,7 +84,26 @@ class NinjaState:
# to make the SCONS_INVOCATION variable properly quoted for things
# like CCFLAGS
scons_escape = env.get("ESCAPE", lambda x: x)
- scons_daemon_port = int(env.get('NINJA_SCONS_DAEMON_PORT',-1))
+
+ # The daemon port should be the same across runs, unless explicitly set
+ # or if the portfile is deleted. This ensures the ninja file is deterministic
+ # across regen's if nothings changed. The construction var should take preference,
+ # then portfile is next, and then otherwise create a new random port to persist in
+ # use.
+ scons_daemon_port = None
+ os.makedirs(get_path(self.env.get("NINJA_DIR")), exist_ok=True)
+ scons_daemon_port_file = str(pathlib.Path(get_path(self.env.get("NINJA_DIR"))) / "scons_daemon_portfile")
+
+ if env.get('NINJA_SCONS_DAEMON_PORT') is not None:
+ scons_daemon_port = int(env.get('NINJA_SCONS_DAEMON_PORT'))
+ elif os.path.exists(scons_daemon_port_file):
+ with open(scons_daemon_port_file) as f:
+ scons_daemon_port = int(f.read())
+ else:
+ scons_daemon_port = random.randint(10000, 60000)
+
+ with open(scons_daemon_port_file, 'w') as f:
+ f.write(str(scons_daemon_port))
# if SCons was invoked from python, we expect the first arg to be the scons.py
# script, otherwise scons was invoked from the scons script
@@ -381,13 +402,13 @@ class NinjaState:
ninja.variable("builddir", get_path(self.env.Dir(self.env['NINJA_DIR']).path))
- for pool_name, size in self.pools.items():
+ for pool_name, size in sorted(self.pools.items()):
ninja.pool(pool_name, min(self.env.get('NINJA_MAX_JOBS', size), size))
- for var, val in self.variables.items():
+ for var, val in sorted(self.variables.items()):
ninja.variable(var, val)
- for rule, kwargs in self.rules.items():
+ for rule, kwargs in sorted(self.rules.items()):
if self.env.get('NINJA_MAX_JOBS') is not None and 'pool' not in kwargs:
kwargs['pool'] = 'local_pool'
ninja.rule(rule, **kwargs)
@@ -529,8 +550,9 @@ class NinjaState:
)
if remaining_outputs:
- ninja.build(
- outputs=sorted(remaining_outputs), rule="phony", implicit=first_output,
+ ninja_sorted_build(
+ ninja,
+ outputs=remaining_outputs, rule="phony", implicit=first_output,
)
build["outputs"] = first_output
@@ -548,12 +570,18 @@ class NinjaState:
if "inputs" in build:
build["inputs"].sort()
- ninja.build(**build)
+ ninja_sorted_build(
+ ninja,
+ **build
+ )
scons_daemon_dirty = str(pathlib.Path(get_path(self.env.get("NINJA_DIR"))) / "scons_daemon_dirty")
for template_builder in template_builders:
template_builder["implicit"] += [scons_daemon_dirty]
- ninja.build(**template_builder)
+ ninja_sorted_build(
+ ninja,
+ **template_builder
+ )
# We have to glob the SCons files here to teach the ninja file
# how to regenerate itself. We'll never see ourselves in the
@@ -563,17 +591,19 @@ class NinjaState:
ninja_file_path = self.env.File(self.ninja_file).path
regenerate_deps = to_escaped_list(self.env, self.env['NINJA_REGENERATE_DEPS'])
- ninja.build(
- ninja_file_path,
+ ninja_sorted_build(
+ ninja,
+ outputs=ninja_file_path,
rule="REGENERATE",
implicit=regenerate_deps,
variables={
- "self": ninja_file_path,
+ "self": ninja_file_path
}
)
- ninja.build(
- regenerate_deps,
+ ninja_sorted_build(
+ ninja,
+ outputs=regenerate_deps,
rule="phony",
variables={
"self": ninja_file_path,
@@ -584,8 +614,9 @@ class NinjaState:
# If we ever change the name/s of the rules that include
# compile commands (i.e. something like CC) we will need to
# update this build to reflect that complete list.
- ninja.build(
- "compile_commands.json",
+ ninja_sorted_build(
+ ninja,
+ outputs="compile_commands.json",
rule="CMD",
pool="console",
implicit=[str(self.ninja_file)],
@@ -601,12 +632,14 @@ class NinjaState:
},
)
- ninja.build(
- "compiledb", rule="phony", implicit=["compile_commands.json"],
+ ninja_sorted_build(
+ ninja,
+ outputs="compiledb", rule="phony", implicit=["compile_commands.json"],
)
- ninja.build(
- ["run_ninja_scons_daemon_phony", scons_daemon_dirty],
+ ninja_sorted_build(
+ ninja,
+ outputs=["run_ninja_scons_daemon_phony", scons_daemon_dirty],
rule="SCONS_DAEMON",
)
@@ -620,39 +653,45 @@ class NinjaState:
if len(all_targets) == 0:
all_targets = ["phony_default"]
- ninja.build(
+ ninja_sorted_build(
+ ninja,
outputs=all_targets,
rule="phony",
)
ninja.default([self.ninja_syntax.escape_path(path) for path in sorted(all_targets)])
- daemon_dir = pathlib.Path(tempfile.gettempdir()) / ('scons_daemon_' + str(hashlib.md5(str(get_path(self.env["NINJA_DIR"])).encode()).hexdigest()))
- pidfile = None
- if os.path.exists(scons_daemon_dirty):
- pidfile = scons_daemon_dirty
- elif os.path.exists(daemon_dir / 'pidfile'):
- pidfile = daemon_dir / 'pidfile'
-
- if pidfile:
- with open(pidfile) as f:
- pid = int(f.readline())
- try:
- os.kill(pid, signal.SIGINT)
- except OSError:
- pass
+ with NamedTemporaryFile(delete=False, mode='w') as temp_ninja_file:
+ temp_ninja_file.write(content.getvalue())
+
+ if self.env.GetOption('skip_ninja_regen') and os.path.exists(ninja_file_path) and filecmp.cmp(temp_ninja_file.name, ninja_file_path):
+ os.unlink(temp_ninja_file.name)
+ else:
+
+ daemon_dir = pathlib.Path(tempfile.gettempdir()) / ('scons_daemon_' + str(hashlib.md5(str(get_path(self.env["NINJA_DIR"])).encode()).hexdigest()))
+ pidfile = None
+ if os.path.exists(scons_daemon_dirty):
+ pidfile = scons_daemon_dirty
+ elif os.path.exists(daemon_dir / 'pidfile'):
+ pidfile = daemon_dir / 'pidfile'
+
+ if pidfile:
+ with open(pidfile) as f:
+ pid = int(f.readline())
+ try:
+ os.kill(pid, signal.SIGINT)
+ except OSError:
+ pass
# wait for the server process to fully killed
# TODO: update wait_for_process_to_die() to handle timeout and then catch exception
# here and do something smart.
wait_for_process_to_die(pid)
- if os.path.exists(scons_daemon_dirty):
- os.unlink(scons_daemon_dirty)
+ if os.path.exists(scons_daemon_dirty):
+ os.unlink(scons_daemon_dirty)
- with NamedTemporaryFile(delete=False, mode='w') as temp_ninja_file:
- temp_ninja_file.write(content.getvalue())
- shutil.move(temp_ninja_file.name, ninja_file_path)
+ shutil.move(temp_ninja_file.name, ninja_file_path)
self.__generated = True
diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py
index b2c3cd3..dec6d2c 100644
--- a/SCons/Tool/ninja/Utils.py
+++ b/SCons/Tool/ninja/Utils.py
@@ -23,6 +23,7 @@
import os
import shutil
from os.path import join as joinpath
+from collections import OrderedDict
import SCons
from SCons.Action import get_default_ENV, _string_from_cmd_list
@@ -52,6 +53,15 @@ def ninja_add_command_line_options():
help='Disable ninja generation and build with scons even if tool is loaded. '+
'Also used by ninja to build targets which only scons can build.')
+ AddOption('--skip-ninja-regen',
+ dest='skip_ninja_regen',
+ metavar='BOOL',
+ action="store_true",
+ default=False,
+ help='Allow scons to skip regeneration of the ninja file and restarting of the daemon. ' +
+ 'Care should be taken in cases where Glob is in use or generated files are used in ' +
+ 'command lines.')
+
def is_valid_dependent_node(node):
"""
@@ -126,7 +136,7 @@ def get_dependencies(node, skip_sources=False):
get_path(src_file(child))
for child in filter_ninja_nodes(node.children())
if child not in node.sources
- ]
+ ]
return [get_path(src_file(child)) for child in filter_ninja_nodes(node.children())]
@@ -261,6 +271,19 @@ def ninja_noop(*_args, **_kwargs):
"""
return None
+def ninja_recursive_sorted_dict(build):
+ sorted_dict = OrderedDict()
+ for key, val in sorted(build.items()):
+ if isinstance(val, dict):
+ sorted_dict[key] = ninja_recursive_sorted_dict(val)
+ else:
+ sorted_dict[key] = val
+ return sorted_dict
+
+
+def ninja_sorted_build(ninja, **build):
+ sorted_dict = ninja_recursive_sorted_dict(build)
+ ninja.build(**sorted_dict)
def get_command_env(env, target, source):
"""
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index 04a7abb..ad75978 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -26,7 +26,7 @@
import importlib
import os
-import random
+import traceback
import subprocess
import sys
@@ -66,8 +66,12 @@ def ninja_builder(env, target, source):
print("Generating:", str(target[0]))
generated_build_ninja = target[0].get_abspath()
- NINJA_STATE.generate()
-
+ try:
+ NINJA_STATE.generate()
+ except Exception as e:
+ raise SCons.Errors.BuildError(
+ errstr=f"ERROR: an excetion occurred while generating the ninja file:\n{traceback.format_exc()}",
+ node=target)
if env["PLATFORM"] == "win32":
# TODO: Is this necessary as you set env variable in the ninja build file per target?
# this is not great, its doesn't consider specific
@@ -194,7 +198,6 @@ def generate(env):
env["NINJA_ALIAS_NAME"] = env.get("NINJA_ALIAS_NAME", "generate-ninja")
env['NINJA_DIR'] = env.Dir(env.get("NINJA_DIR", '#/.ninja'))
env["NINJA_SCONS_DAEMON_KEEP_ALIVE"] = env.get("NINJA_SCONS_DAEMON_KEEP_ALIVE", 180000)
- env["NINJA_SCONS_DAEMON_PORT"] = env.get('NINJA_SCONS_DAEMON_PORT', random.randint(10000, 60000))
if GetOption("disable_ninja"):
env.SConsignFile(os.path.join(str(env['NINJA_DIR']),'.ninja.sconsign'))
diff --git a/test/ninja/ninja_file_deterministic.py b/test/ninja/ninja_file_deterministic.py
new file mode 100644
index 0000000..2ac5e1a
--- /dev/null
+++ b/test/ninja/ninja_file_deterministic.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Copyright The SCons Foundation
+#
+# 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.
+#
+
+import os
+import shutil
+import filecmp
+
+import TestSCons
+from TestCmd import IS_WINDOWS
+
+test = TestSCons.TestSCons()
+
+try:
+ import ninja
+except ImportError:
+ test.skip_test("Could not find module in python")
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+ninja_bin = os.path.abspath(os.path.join(
+ ninja.BIN_DIR,
+ 'ninja' + _exe))
+
+test.dir_fixture('ninja-fixture')
+
+test.file_fixture('ninja_test_sconscripts/sconstruct_ninja_determinism', 'SConstruct')
+
+# generate simple build
+test.run(stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig'))
+
+# generate same build again
+test.run(stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja', 'ninja: no work to do.'])
+test.must_contain_all(test.stdout(), 'Executing:')
+test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+
+# make sure the ninja file was deterministic
+if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')):
+ test.fail_test()
+
+# clean build and ninja files
+os.unlink(test.workpath('build.ninja.orig'))
+test.run(arguments='-c', stdout=None)
+
+# only generate the ninja file
+test.run(arguments='--disable-execute-ninja', stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_not_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+
+# run ninja independently
+program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
+test.run(program=program, stdout=None)
+test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig'))
+
+# only generate the ninja file again
+test.run(arguments='--disable-execute-ninja', stdout=None)
+test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
+test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+
+# run ninja independently again
+program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
+test.run(program=program, stdout=None)
+test.must_contain_all_lines(test.stdout(), ['ninja: no work to do.'])
+test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
+
+# make sure the ninja file was deterministic
+if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')):
+ test.fail_test()
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism b/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism
new file mode 100644
index 0000000..6bd7c26
--- /dev/null
+++ b/test/ninja/ninja_test_sconscripts/sconstruct_ninja_determinism
@@ -0,0 +1,20 @@
+import SCons
+import random
+SetOption('experimental','ninja')
+SetOption('skip_ninja_regen', True)
+DefaultEnvironment(tools=[])
+
+env = Environment(tools=[])
+
+env.Tool('ninja')
+
+# make the dependency list vary in order. Ninja tool should sort them to be deterministic.
+for i in range(1, 10):
+ node = env.Command(f'out{i}.txt', 'foo.c', 'echo test > $TARGET')
+ deps = list(range(1, i))
+ random.shuffle(deps)
+ for j in deps:
+ if j == i:
+ continue
+ env.Depends(node, f'out{j}.txt')
+
--
cgit v0.12
From 60b6724b28a909f63fa99f970bc39111f039024d Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 12:35:08 -0500
Subject: improve help text slightly
---
SCons/Tool/ninja/Utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py
index dec6d2c..583301e 100644
--- a/SCons/Tool/ninja/Utils.py
+++ b/SCons/Tool/ninja/Utils.py
@@ -59,7 +59,7 @@ def ninja_add_command_line_options():
action="store_true",
default=False,
help='Allow scons to skip regeneration of the ninja file and restarting of the daemon. ' +
- 'Care should be taken in cases where Glob is in use or generated files are used in ' +
+ 'Care should be taken in cases where Glob is in use or SCons generated files are used in ' +
'command lines.')
--
cgit v0.12
From 97a265e6da13a6a3827c599c23271b60aadef176 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 14:23:10 -0500
Subject: Added new alias 'shutdown-ninja-scons-daemon' to allow ninja to
shutdown the daemon
---
CHANGES.txt | 2 +
RELEASE.txt | 2 +
SCons/Tool/ninja/NinjaState.py | 11 +++++
SCons/Tool/ninja/__init__.py | 1 +
SCons/Tool/ninja/ninja_daemon_build.py | 14 +++++-
SCons/Tool/ninja/ninja_scons_daemon.py | 5 ++-
test/ninja/shutdown_scons_daemon.py | 79 ++++++++++++++++++++++++++++++++++
testing/framework/TestCmd.py | 32 ++++++++++++++
8 files changed, 144 insertions(+), 2 deletions(-)
create mode 100644 test/ninja/shutdown_scons_daemon.py
diff --git a/CHANGES.txt b/CHANGES.txt
index 03692d6..9db19a8 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -116,6 +116,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
+ -Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon.
+ Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs.
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index cfa8afc..811d957 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -24,6 +24,8 @@ NEW FUNCTIONALITY
performance impact if not used carefully.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
+- Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon.
+ Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs.
DEPRECATED FUNCTIONALITY
diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py
index c168c7f..553d8cc 100644
--- a/SCons/Tool/ninja/NinjaState.py
+++ b/SCons/Tool/ninja/NinjaState.py
@@ -214,6 +214,12 @@ class NinjaState:
"pool": "local_pool",
"restat": 1
},
+ "EXIT_SCONS_DAEMON": {
+ "command": "$PYTHON_BIN $NINJA_TOOL_DIR/ninja_daemon_build.py $PORT $NINJA_DIR_PATH --exit",
+ "description": "Shutting down ninja scons daemon server",
+ "pool": "local_pool",
+ "restat": 1
+ },
"SCONS": {
"command": "$SCONS_INVOCATION $out",
"description": "$SCONS_INVOCATION $out",
@@ -610,6 +616,11 @@ class NinjaState:
rule="SCONS_DAEMON",
)
+ ninja.build(
+ "shutdown_ninja_scons_daemon_phony",
+ rule="EXIT_SCONS_DAEMON",
+ )
+
if all_targets is None:
# Look in SCons's list of DEFAULT_TARGETS, find the ones that
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index 04a7abb..6f474ca 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -495,3 +495,4 @@ def generate(env):
env.Alias('run-ninja-scons-daemon', 'run_ninja_scons_daemon_phony')
+ env.Alias('shutdown-ninja-scons-daemon', 'shutdown_ninja_scons_daemon_phony')
\ No newline at end of file
diff --git a/SCons/Tool/ninja/ninja_daemon_build.py b/SCons/Tool/ninja/ninja_daemon_build.py
index 48156f5..63eb136 100644
--- a/SCons/Tool/ninja/ninja_daemon_build.py
+++ b/SCons/Tool/ninja/ninja_daemon_build.py
@@ -60,11 +60,22 @@ def log_error(msg):
while True:
try:
+ if not os.path.exists(daemon_dir / "pidfile"):
+ if sys.argv[3] != '--exit':
+ logging.debug(f"ERROR: Server pid not found {daemon_dir / 'pidfile'} for request {sys.argv[3]}")
+ exit(1)
+ else:
+ logging.debug(f"WARNING: Unecessary request to shutfown server, its already shutdown.")
+ exit(0)
+
logging.debug(f"Sending request: {sys.argv[3]}")
conn = http.client.HTTPConnection(
"127.0.0.1", port=int(sys.argv[1]), timeout=60
)
- conn.request("GET", "/?build=" + sys.argv[3])
+ if sys.argv[3] == '--exit':
+ conn.request("GET", "/?exit=1")
+ else:
+ conn.request("GET", "/?build=" + sys.argv[3])
response = None
while not response:
@@ -81,6 +92,7 @@ while True:
if status != 200:
log_error(msg.decode("utf-8"))
exit(1)
+
logging.debug(f"Request Done: {sys.argv[3]}")
exit(0)
diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py
index c4a1d11..35a7789 100644
--- a/SCons/Tool/ninja/ninja_scons_daemon.py
+++ b/SCons/Tool/ninja/ninja_scons_daemon.py
@@ -168,6 +168,7 @@ def daemon_thread_func():
te.start()
daemon_ready = False
+
building_node = None
startup_complete = False
@@ -218,12 +219,14 @@ def daemon_thread_func():
except queue.Empty:
break
if "exit" in building_node:
+ daemon_log("input: " + "exit")
p.stdin.write("exit\n".encode("utf-8"))
p.stdin.flush()
with building_cv:
shared_state.finished_building += [building_node]
daemon_ready = False
- raise
+ daemon_needs_to_shutdown = True
+ break
else:
input_command = "build " + building_node + "\n"
diff --git a/test/ninja/shutdown_scons_daemon.py b/test/ninja/shutdown_scons_daemon.py
new file mode 100644
index 0000000..fffbadb
--- /dev/null
+++ b/test/ninja/shutdown_scons_daemon.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# Copyright The SCons Foundation
+#
+# 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.
+#
+
+import os
+import psutil
+from timeit import default_timer as timer
+
+import TestSCons
+from TestCmd import IS_WINDOWS
+
+test = TestSCons.TestSCons()
+
+try:
+ import ninja
+except ImportError:
+ test.skip_test("Could not find module in python")
+
+_python_ = TestSCons._python_
+_exe = TestSCons._exe
+
+ninja_bin = os.path.abspath(
+ os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe)
+)
+
+test.dir_fixture("ninja-fixture")
+
+test.file_fixture(
+ "ninja_test_sconscripts/sconstruct_force_scons_callback", "SConstruct"
+)
+
+test.run(stdout=None)
+pid = None
+test.must_exist(test.workpath('.ninja/scons_daemon_dirty'))
+with open(test.workpath('.ninja/scons_daemon_dirty')) as f:
+ pid = int(f.read())
+ if pid not in [proc.pid for proc in psutil.process_iter()]:
+ test.fail_test(message="daemon not running!")
+
+program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin
+test.run(program=program, arguments='shutdown-ninja-scons-daemon', stdout=None)
+
+wait_time = 10
+start_time = timer()
+while True:
+ if wait_time > (timer() - start_time):
+ if pid not in [proc.pid for proc in psutil.process_iter()]:
+ break
+ else:
+ test.fail_test(message=f"daemon still not shutdown after {wait_time} seconds.")
+
+test.must_not_exist(test.workpath('.ninja/scons_daemon_dirty'))
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py
index 5759121..34acb4d 100644
--- a/testing/framework/TestCmd.py
+++ b/testing/framework/TestCmd.py
@@ -299,9 +299,12 @@ __version__ = "1.3"
import atexit
import difflib
import errno
+import hashlib
import os
import re
+import psutil
import shutil
+import signal
import stat
import subprocess
import sys
@@ -310,6 +313,7 @@ import threading
import time
import traceback
from collections import UserList, UserString
+from pathlib import Path
from subprocess import PIPE, STDOUT
from typing import Optional
@@ -382,6 +386,31 @@ def _caller(tblist, skip):
atfrom = "\tfrom"
return string
+def clean_up_ninja_daemon(self, result_type):
+ if self:
+ for path in Path(self.workdir).rglob('.ninja'):
+ daemon_dir = Path(tempfile.gettempdir()) / (
+ "scons_daemon_" + str(hashlib.md5(str(path.resolve()).encode()).hexdigest())
+ )
+ pidfiles = [daemon_dir / 'pidfile', path / 'scons_daemon_dirty']
+ for pidfile in pidfiles:
+ if pidfile.exists():
+ with open(daemon_dir / 'pidfile') as f:
+ try:
+ pid = int(f.read())
+ os.kill(pid, signal.SIGINT)
+ except OSError:
+ pass
+
+ while True:
+ if pid not in [proc.pid for proc in psutil.process_iter()]:
+ break
+ else:
+ time.sleep(0.1)
+
+ if not self._preserve[result_type]:
+ if daemon_dir.exists():
+ shutil.rmtree(daemon_dir)
def fail_test(self=None, condition=True, function=None, skip=0, message=None):
"""Causes a test to exit with a fail.
@@ -402,6 +431,7 @@ def fail_test(self=None, condition=True, function=None, skip=0, message=None):
return
if function is not None:
function()
+ clean_up_ninja_daemon(self, 'fail_test')
of = ""
desc = ""
sep = " "
@@ -447,6 +477,7 @@ def no_result(self=None, condition=True, function=None, skip=0):
return
if function is not None:
function()
+ clean_up_ninja_daemon(self, 'no_result')
of = ""
desc = ""
sep = " "
@@ -483,6 +514,7 @@ def pass_test(self=None, condition=True, function=None):
return
if function is not None:
function()
+ clean_up_ninja_daemon(self, 'pass_test')
sys.stderr.write("PASSED\n")
sys.exit(0)
--
cgit v0.12
From b1ede4ce01b6163086c748f509c51616b9dec051 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 14:28:15 -0500
Subject: fixed sider complaint
---
SCons/Tool/ninja/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index ad75978..7c32676 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -68,7 +68,7 @@ def ninja_builder(env, target, source):
generated_build_ninja = target[0].get_abspath()
try:
NINJA_STATE.generate()
- except Exception as e:
+ except Exception:
raise SCons.Errors.BuildError(
errstr=f"ERROR: an excetion occurred while generating the ninja file:\n{traceback.format_exc()}",
node=target)
--
cgit v0.12
From e3b2dd31e326a0d5b948fa35eae0cb1eefbbebf4 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 14:34:28 -0500
Subject: install psutil for testing and fix sider complaints
---
.github/workflows/experimental_tests.yml | 2 +-
.github/workflows/runtest.yml | 2 +-
SCons/Tool/ninja/ninja_daemon_build.py | 2 +-
SCons/Tool/ninja/ninja_scons_daemon.py | 2 +-
testing/framework/TestCmd.py | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/experimental_tests.yml b/.github/workflows/experimental_tests.yml
index 3672144..92fc134 100644
--- a/.github/workflows/experimental_tests.yml
+++ b/.github/workflows/experimental_tests.yml
@@ -44,7 +44,7 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install ninja
- # if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+ if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi
# sudo apt-get update
- name: Test experimental packages ${{ matrix.os }}
run: |
diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml
index cfc585e..f37111b 100644
--- a/.github/workflows/runtest.yml
+++ b/.github/workflows/runtest.yml
@@ -38,7 +38,7 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install ninja
- # if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+ if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi
# sudo apt-get update
- name: runtest ${{ matrix.os }}
run: |
diff --git a/SCons/Tool/ninja/ninja_daemon_build.py b/SCons/Tool/ninja/ninja_daemon_build.py
index 63eb136..c21ea0b 100644
--- a/SCons/Tool/ninja/ninja_daemon_build.py
+++ b/SCons/Tool/ninja/ninja_daemon_build.py
@@ -65,7 +65,7 @@ while True:
logging.debug(f"ERROR: Server pid not found {daemon_dir / 'pidfile'} for request {sys.argv[3]}")
exit(1)
else:
- logging.debug(f"WARNING: Unecessary request to shutfown server, its already shutdown.")
+ logging.debug("WARNING: Unnecessary request to shutfown server, its already shutdown.")
exit(0)
logging.debug(f"Sending request: {sys.argv[3]}")
diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py
index 35a7789..6802af2 100644
--- a/SCons/Tool/ninja/ninja_scons_daemon.py
+++ b/SCons/Tool/ninja/ninja_scons_daemon.py
@@ -225,7 +225,7 @@ def daemon_thread_func():
with building_cv:
shared_state.finished_building += [building_node]
daemon_ready = False
- daemon_needs_to_shutdown = True
+ shared_state.daemon_needs_to_shutdown = True
break
else:
diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py
index 34acb4d..2d3428c 100644
--- a/testing/framework/TestCmd.py
+++ b/testing/framework/TestCmd.py
@@ -399,7 +399,7 @@ def clean_up_ninja_daemon(self, result_type):
try:
pid = int(f.read())
os.kill(pid, signal.SIGINT)
- except OSError:
+ except OSError:
pass
while True:
--
cgit v0.12
From a20c08c1309486f0f51ecd8cf34ba521da0718f0 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 14:36:39 -0500
Subject: fix formatting in changes.txt
---
CHANGES.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 9db19a8..a4ef7b2 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -116,7 +116,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
- -Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon.
+ - Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon.
Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs.
From Mats Wichmann:
--
cgit v0.12
From 719ad105165e942ee39f42749ee48d06e7567c90 Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 15:05:42 -0500
Subject: Added command line variable to pass ninja args through scons.
---
CHANGES.txt | 2 ++
RELEASE.txt | 1 +
SCons/Tool/ninja/__init__.py | 12 +++++++++++-
SCons/Tool/ninja/ninja.xml | 11 ++++++++++-
test/ninja/generate_and_build.py | 3 ++-
5 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 03692d6..90e2d4e 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -116,6 +116,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
+ - Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args.
+
From Mats Wichmann:
- Tweak the way default site_scons paths on Windows are expressed to
diff --git a/RELEASE.txt b/RELEASE.txt
index cfa8afc..699e51e 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -24,6 +24,7 @@ NEW FUNCTIONALITY
performance impact if not used carefully.
- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
+- Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args.
DEPRECATED FUNCTIONALITY
diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py
index 04a7abb..27a2957 100644
--- a/SCons/Tool/ninja/__init__.py
+++ b/SCons/Tool/ninja/__init__.py
@@ -33,6 +33,7 @@ import sys
import SCons
import SCons.Script
import SCons.Tool.ninja.Globals
+from SCons.Script import Variables
from SCons.Script import GetOption
from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFAULT_TARGETS, NINJA_CMDLINE_TARGETS
@@ -87,7 +88,7 @@ def ninja_builder(env, target, source):
if str(env.get("NINJA_DISABLE_AUTO_RUN")).lower() not in ['1', 'true']:
num_jobs = env.get('NINJA_MAX_JOBS', env.GetOption("num_jobs"))
- cmd += ['-j' + str(num_jobs)] + NINJA_CMDLINE_TARGETS
+ cmd += ['-j' + str(num_jobs)] + env.get('NINJA_CMD_ARGS', '').split() + NINJA_CMDLINE_TARGETS
print(f"ninja will be run with command line targets: {' '.join(NINJA_CMDLINE_TARGETS)}")
print("Executing:", str(' '.join(cmd)))
@@ -185,6 +186,15 @@ def generate(env):
env["NINJA_DISABLE_AUTO_RUN"] = env.get("NINJA_DISABLE_AUTO_RUN", GetOption('disable_execute_ninja'))
env["NINJA_FILE_NAME"] = env.get("NINJA_FILE_NAME", "build.ninja")
+ if env.get("NINJA_CMD_ARGS") is not None:
+ env["NINJA_CMD_ARGS"] = env.get("NINJA_CMD_ARGS")
+ else:
+ vars = Variables()
+ vars.Add("NINJA_CMD_ARGS")
+ var_env = env.Clone()
+ vars.Update(var_env)
+ env["NINJA_CMD_ARGS"] = var_env.get("NINJA_CMD_ARGS", '')
+
# Add the Ninja builder.
always_exec_ninja_action = AlwaysExecAction(ninja_builder, {})
ninja_builder_obj = SCons.Builder.Builder(action=always_exec_ninja_action,
diff --git a/SCons/Tool/ninja/ninja.xml b/SCons/Tool/ninja/ninja.xml
index 6b247d0..0929684 100644
--- a/SCons/Tool/ninja/ninja.xml
+++ b/SCons/Tool/ninja/ninja.xml
@@ -77,7 +77,7 @@ See its __doc__ string for a discussion of the format.
IMPLICIT_COMMAND_DEPENDENCIESNINJA_SCONS_DAEMON_KEEP_ALIVENINJA_SCONS_DAEMON_PORT
-
+ NINJA_CMD_ARGS
@@ -395,5 +395,14 @@ python -m pip install ninja
+
+
+
+ A string which will pass arguments through SCons to the ninja command when scons executes ninja.
+ Has no effect if &cv-NINJA_DISABLE_AUTO_RUN; is set.
+
+
+
+
diff --git a/test/ninja/generate_and_build.py b/test/ninja/generate_and_build.py
index 91be108..83b7387 100644
--- a/test/ninja/generate_and_build.py
+++ b/test/ninja/generate_and_build.py
@@ -49,10 +49,11 @@ test.dir_fixture('ninja-fixture')
test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build', 'SConstruct')
# generate simple build
-test.run(stdout=None)
+test.run(stdout=None, arguments='NINJA_CMD_ARGS=-v')
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
+test.must_contain_all(test.stdout(), ' -j1 -v')
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")
# clean build and ninja files
--
cgit v0.12
From fc6a0e35e7bc1c25aa0359a2391e31ce4ab2dd1f Mon Sep 17 00:00:00 2001
From: Daniel Moody
Date: Tue, 7 Jun 2022 15:10:39 -0500
Subject: fix psutil install
---
.github/workflows/experimental_tests.yml | 3 +--
.github/workflows/runtest.yml | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/experimental_tests.yml b/.github/workflows/experimental_tests.yml
index 92fc134..52078d5 100644
--- a/.github/workflows/experimental_tests.yml
+++ b/.github/workflows/experimental_tests.yml
@@ -43,8 +43,7 @@ jobs:
- name: Install dependencies including ninja ${{ matrix.os }}
run: |
python -m pip install --upgrade pip setuptools wheel
- python -m pip install ninja
- if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi
+ python -m pip install ninja psutil
# sudo apt-get update
- name: Test experimental packages ${{ matrix.os }}
run: |
diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml
index f37111b..dd18013 100644
--- a/.github/workflows/runtest.yml
+++ b/.github/workflows/runtest.yml
@@ -37,8 +37,7 @@ jobs:
- name: Install dependencies including ninja ${{ matrix.os }}
run: |
python -m pip install --upgrade pip setuptools wheel
- python -m pip install ninja
- if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi
+ python -m pip install ninja psutil
# sudo apt-get update
- name: runtest ${{ matrix.os }}
run: |
--
cgit v0.12
From e30a6efe2cbf887a501b2a18be854ea0346e299d Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 8 Jun 2022 12:29:04 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 59b8944..d99bcef 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -632,10 +632,28 @@ Note: in addition to the camel case values shown above, lower case and upper cas
-The default scons behavior when no msvc versions are detected or when the requested msvc version is not detected
-is to issue a warning and continue. This may change in the future.
+The MSVC_NOTFOUND_POLICY is enforced if any of the following conditions are satisfied:
+
+&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified), and the default tools list contains one or more of the msvc tools.
+&cv-MSVC_VERSION; is specified, the default tools list is explicitly specified (e.g., tools=['default']), and the default tools list contains one or more of the msvc tools.
+A non-default tools list is specified that contains one or more of the msvc tools (e.g., tools=['msvc', 'mslink']).
+
+
+The MSVC_NOTFOUND_POLICY is ignored if any of the following conditions are satisfied:
+
+&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified).
+&cv-MSVC_VERSION; is not specified and the default tools list is explicitly specified (e.g., tools=['default']).
+A non-default tool list is specified that does not contain any of the msvc tools (e.g., tools=['mingw']).
+
+
+
+
+When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue subject to the enforcement conditions listed above. The default &scons; behavior may change in the future.
+
+
+
--
cgit v0.12
From be45d8d5f77d15bbca6cee1108f2d7dbfe5ef79b Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 8 Jun 2022 12:44:27 -0400
Subject: Add preliminary docstrings for set_msvc_notfound_policy and
get_msvc_notfound_policy
---
SCons/Tool/MSCommon/vc.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 32d0e61..f0c286a 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1070,6 +1070,19 @@ def _msvc_notfound_policy_lookup(symbol):
return notfound_policy_def
def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
+ """ Set the default policy when MSVC is not found.
+
+ Args:
+ MSVC_NOTFOUND_POLICY:
+ string representing the policy behavior
+ when MSVC is not found or None
+
+ Returns:
+ The previous policy is returned when the MSVC_NOTFOUND_POLICY argument
+ is not None. The active policy is returned when the MSVC_NOTFOUND_POLICY
+ argument is None.
+
+ """
global _MSVC_NOTFOUND_POLICY_DEF
prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
@@ -1087,6 +1100,7 @@ def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
return prev_policy
def get_msvc_notfound_policy():
+ """Return the active policy when MSVC is not found."""
debug(
'policy.symbol=%s, policy.value=%s',
repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
--
cgit v0.12
From 609b79f538dc025a2b2d4dfd4d8814f96481949e Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 8 Jun 2022 14:12:59 -0400
Subject: Update MSVC_NOTFOUND_POLICY documentation
---
SCons/Tool/msvc.xml | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index d99bcef..e8df128 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -632,25 +632,40 @@ Note: in addition to the camel case values shown above, lower case and upper cas
-The MSVC_NOTFOUND_POLICY is enforced if any of the following conditions are satisfied:
+The MSVC_NOTFOUND_POLICY is applied when any of the following conditions are satisfied:
-&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified), and the default tools list contains one or more of the msvc tools.
-&cv-MSVC_VERSION; is specified, the default tools list is explicitly specified (e.g., tools=['default']), and the default tools list contains one or more of the msvc tools.
-A non-default tools list is specified that contains one or more of the msvc tools (e.g., tools=['msvc', 'mslink']).
+
+&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified),
+and the default tools list contains one or more of the msvc tools.
+
+
+&cv-MSVC_VERSION; is specified, the default tools list is explicitly specified (e.g., tools=['default']),
+and the default tools list contains one or more of the msvc tools.
+
+
+A non-default tools list is specified that contains one or more of the msvc tools (e.g., tools=['msvc', 'mslink']).
+
-The MSVC_NOTFOUND_POLICY is ignored if any of the following conditions are satisfied:
+The MSVC_NOTFOUND_POLICY is ignored when any of the following conditions are satisfied:
-&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified).
-&cv-MSVC_VERSION; is not specified and the default tools list is explicitly specified (e.g., tools=['default']).
-A non-default tool list is specified that does not contain any of the msvc tools (e.g., tools=['mingw']).
+
+&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified).
+
+
+&cv-MSVC_VERSION; is not specified and the default tools list is explicitly specified (e.g., tools=['default']).
+
+
+A non-default tool list is specified that does not contain any of the msvc tools (e.g., tools=['mingw']).
+
-When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue subject to the enforcement conditions listed above. The default &scons; behavior may change in the future.
+When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue
+subject to the conditions listed above. The default &scons; behavior may change in the future.
--
cgit v0.12
From 3d9345e2d086f3b39a419452c9b74f763698dd04 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Thu, 9 Jun 2022 09:03:58 -0600
Subject: doc: FORTRANCOM doesn't include cpp vars [skip appveyor]
FORTRANCOM and SHFORTRANCOM don't add the C preprocessor variables
by default, the docs suggest they do. The PP variants, which run
through the preprocessor, do add these. Adjust docs.
Fixes #2128
Signed-off-by: Mats Wichmann
---
SCons/Tool/fortran.xml | 43 ++++++++++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/SCons/Tool/fortran.xml b/SCons/Tool/fortran.xml
index a4f0cec..4f0517b 100644
--- a/SCons/Tool/fortran.xml
+++ b/SCons/Tool/fortran.xml
@@ -1,6 +1,6 @@
+
- # On the command line
- --experimental=ninja
+# On the command line
+--experimental=ninja
- # Or in your SConstruct
- SetOption('experimental', 'ninja')
+# Or in your SConstruct
+SetOption('experimental', 'ninja')
This functionality is subject to change and/or removal without deprecation cycle.
-
- To use this tool you must install pypi's ninja
- package.
- This can be done via
- pip install ninja
+ To use this tool you need to install the &Python; &ninja; package,
+ as the tool by default depends on being able to do an
+ import of the package
+
+ This can be done via:
+
+python -m pip install ninja
+
diff --git a/doc/generated/functions.gen b/doc/generated/functions.gen
index c982b96..a2d9acd 100644
--- a/doc/generated/functions.gen
+++ b/doc/generated/functions.gen
@@ -63,7 +63,7 @@ Added methods propagate through &f-env-Clone; calls.
-Examples:
+More examples:
@@ -472,7 +472,7 @@ and/or suffix,
so the contents are treated as a list of strings, that is,
adding a string will result in a separate string entry,
not a combined string. For &cv-CPPDEFINES; as well as
-for &cv-link-LIBS;, and the various *PATH
+for &cv-link-LIBS;, and the various *PATH;
variables, &SCons; will supply the compiler-specific
syntax (e.g. adding a -D or /D
prefix for &cv-CPPDEFINES;), so this syntax should be omitted when
@@ -550,7 +550,7 @@ do not make sense and a &Python; exception will be raised.
When using &f-env-Append; to modify &consvars;
which are path specifications (conventionally,
-the names of such end in PATH),
+the names of such end in PATH),
it is recommended to add the values as a list of strings,
even if there is only a single string to add.
The same goes for adding library names to &cv-LIBS;.
@@ -570,26 +570,26 @@ See also &f-link-env-AppendUnique;,
env.AppendENVPath(name, newpath, [envname, sep, delete_existing=False])
-Append new path elements to the given path in the
-specified external environment (&cv-link-ENV; by default).
-This will only add
-any particular path once (leaving the last one it encounters and
-ignoring the rest, to preserve path order),
-and to help assure this,
-will normalize all paths (using
-os.path.normpath
+Append path elements specified by newpath
+to the given search path string or list name
+in mapping envname in the &consenv;.
+Supplying envname is optional:
+the default is the execution environment &cv-link-ENV;.
+Optional sep is used as the search path separator,
+the default is the platform's separator (os.pathsep).
+A path element will only appear once.
+Any duplicates in newpath are dropped,
+keeping the last appearing (to preserve path order).
+If delete_existing
+is False (the default)
+any addition duplicating an existing path element is ignored;
+if delete_existing
+is True the existing value will
+be dropped and the path element will be added at the end.
+To help maintain uniqueness all paths are normalized (using
+os.path.normpath
and
-os.path.normcase).
-This can also handle the
-case where the given old path variable is a list instead of a
-string, in which case a list will be returned instead of a string.
-
-
-
-If
-delete_existing
-is False, then adding a path that already exists
-will not move it to the end; it will stay where it is in the list.
+os.path.normcase).
@@ -608,6 +608,11 @@ print('after:', env['ENV']['INCLUDE'])
before: /foo:/biz
after: /biz:/foo/bar:/foo
+
+
+See also &f-link-env-PrependENVPath;.
+
+
@@ -718,7 +723,7 @@ is being used and
&scons;
finds a derived file that needs to be rebuilt,
it will first look in the cache to see if a
-file with matching build signature exists
+file with matching &buildsig; exists
(indicating the input file(s) and build action(s)
were identical to those for the current target),
and if so, will retrieve the file from the cache.
@@ -730,7 +735,7 @@ If the derived file is not present in the cache,
&scons;
will build it and
then place a copy of the built file in the cache,
-identified by its build signature, for future use.
+identified by its &buildsig;, for future use.
@@ -787,6 +792,13 @@ method can be used to disable caching of specific files. This can be
useful if inputs and/or outputs of some tool are impossible to
predict or prohibitively large.
+
+
+Note that (at this time) &SCons; provides no facilities
+for managing the derived-file cache. It is up to the developer
+to arrange for cache pruning, expiry, etc. if needed.
+
+
@@ -1194,7 +1206,7 @@ was built.
This can be consulted to match various
file characteristics
such as the timestamp,
-size, or content signature.
+size, or &contentsig;.
@@ -1390,10 +1402,11 @@ Find an executable from one or more choices:
progs may be a string or a list of strings.
Returns the first value from progs
that was found, or None.
-Executable is searched by checking the paths specified
-by env['ENV']['PATH'].
+Executable is searched by checking the paths in the execution environment
+(env['ENV']['PATH']).
On Windows systems, additionally applies the filename suffixes found in
-env['ENV']['PATHEXT']
+the execution environment
+(env['ENV']['PATHEXT'])
but will not include any such extension in the return value.
&f-env-Detect; is a wrapper around &f-link-env-WhereIs;.
@@ -2640,12 +2653,8 @@ not as separate arguments to
-By default,
-duplicate values are eliminated;
-you can, however, specify
-unique=False
-to allow duplicate
-values to be added.
+If unique is true (the default),
+duplicate values are not stored.
When eliminating duplicate values,
any &consvars; that end with
the string
@@ -2653,6 +2662,8 @@ the string
keep the left-most unique value.
All other &consvars; keep
the right-most unique value.
+If unique is false,
+values are added even if they are duplicates.
@@ -2669,9 +2680,13 @@ env.MergeFlags(['!pkg-config gtk+-2.0 --cflags', '-O3'])
# Combine an optimization flag with the flags returned from running pkg-config
# twice and merge the result into the construction variables.
-env.MergeFlags(['-O3',
- '!pkg-config gtk+-2.0 --cflags --libs',
- '!pkg-config libpng12 --cflags --libs'])
+env.MergeFlags(
+ [
+ '-O3',
+ '!pkg-config gtk+-2.0 --cflags --libs',
+ '!pkg-config libpng12 --cflags --libs',
+ ]
+)
@@ -2773,15 +2788,13 @@ NoClean(env.Program('hello', 'hello.c'))
env.ParseConfig(command, [function, unique])
Updates the current &consenv; with the values extracted
-from the output from running external command,
-by calling a helper function function
-which understands
-the output of command.
+from the output of running external command,
+by passing it to a helper function.
command may be a string
or a list of strings representing the command and
its arguments.
If function
-is not given,
+is omitted or None,
&f-link-env-MergeFlags; is used.
By default,
duplicate values are not
@@ -2792,33 +2805,32 @@ to allow duplicate values to be added.
-If &f-env-MergeFlags; is used,
-it expects a response in the style of a
-*-config
-command typical of the POSIX programming environment
-(for example,
-gtk-config)
-and adds the options
-to the appropriate construction variables.
-Interpreted options
-and the construction variables they affect
-are as specified for the
-&f-link-env-ParseFlags;
-method (which
-&f-env-MergeFlags; calls).
-See that method's description
-for a table of options and corresponding construction variables.
+command is executed using the
+SCons execution environment (that is, the &consvar;
+&cv-link-ENV; in the current &consenv;).
+If command needs additional information
+to operate properly, that needs to be set in the execution environment.
+For example, pkg-config
+may need a custom value set in the PKG_CONFIG_PATH
+environment variable.
-If &f-env-MergeFlags; cannot interpret the results of
+&f-env-MergeFlags; needs to understand
+the output produced by command
+in order to distribute it to appropriate &consvars;.
+&f-env-MergeFlags; uses a separate function to
+do that processing -
+see &f-link-env-ParseFlags; for the details, including a
+a table of options and corresponding construction variables.
+To provide alternative processing of the output of
command,
you can suppply a custom
-function to do so.
-function
-must accept three arguments:
-the &consenv; to modify, the string returned
-by running command,
+function,
+which must accept three arguments:
+the &consenv; to modify,
+a string argument containing the output from running
+command,
and the optional
unique flag.
@@ -2828,8 +2840,7 @@ and the optional
ParseDepends(filename, [must_exist, only_one])env.ParseDepends(filename, [must_exist, only_one])
-Parses the contents of the specified
-filename
+Parses the contents of filename
as a list of dependencies in the style of
&Make;
or
@@ -2840,27 +2851,21 @@ and explicitly establishes all of the listed dependencies.
By default,
it is not an error
-if the specified
-filename
+if filename
does not exist.
The optional
must_exist
-argument may be set to a non-zero
-value to have
-scons
-throw an exception and
-generate an error if the file does not exist,
+argument may be set to True
+to have &SCons;
+raise an exception if the file does not exist,
or is otherwise inaccessible.
The optional
only_one
-argument may be set to a non-zero
-value to have
-scons
-thrown an exception and
-generate an error
+argument may be set to True
+to have &SCons; raise an exception
if the file contains dependency
information for more than one target.
This can provide a small sanity check
@@ -2876,7 +2881,6 @@ file.
-The
filename
and all of the files listed therein
will be interpreted relative to
@@ -2892,10 +2896,10 @@ function.
env.ParseFlags(flags, ...)
Parses one or more strings containing
-typical command-line flags for GCC tool chains
+typical command-line flags for GCC-style tool chains
and returns a dictionary with the flag values
separated into the appropriate SCons construction variables.
-This is intended as a companion to the
+Intended as a companion to the
&f-link-env-MergeFlags;
method, but allows for the values in the returned dictionary
to be modified, if necessary,
@@ -2910,11 +2914,20 @@ directly unless you want to manipulate the values.)
If the first character in any string is
-an exclamation mark (!),
+an exclamation mark (!),
the rest of the string is executed as a command,
and the output from the command is
parsed as GCC tool chain command-line flags
and added to the resulting dictionary.
+This can be used to call a *-config
+command typical of the POSIX programming environment
+(for example,
+pkg-config).
+Note that such a comamnd is executed using the
+SCons execution environment;
+if the command needs additional information,
+that information needs to be explcitly provided.
+See &f-link-ParseConfig; for more details.
@@ -3051,30 +3064,28 @@ and &f-link-env-PrependUnique;.
- env.PrependENVPath(name, newpath, [envname, sep, delete_existing])
+ env.PrependENVPath(name, newpath, [envname, sep, delete_existing=True])
-Prepend new path elements to the given path in the
-specified external environment (&cv-link-ENV; by default).
-This will only add
-any particular path once (leaving the first one it encounters and
-ignoring the rest, to preserve path order),
-and to help assure this,
-will normalize all paths (using
+Prepend path elements specified by newpath
+to the given search path string or list name
+in mapping envname in the &consenv;.
+Supplying envname is optional:
+the default is the execution environment &cv-link-ENV;.
+Optional sep is used as the search path separator,
+the default is the platform's separator (os.pathsep).
+A path element will only appear once.
+Any duplicates in newpath are dropped,
+keeping the first appearing (to preserve path order).
+If delete_existing
+is False
+any addition duplicating an existing path element is ignored;
+if delete_existing
+is True (the default) the existing value will
+be dropped and the path element will be inserted at the beginning.
+To help maintain uniqueness all paths are normalized (using
os.path.normpath
and
os.path.normcase).
-This can also handle the
-case where the given old path variable is a list instead of a
-string, in which case a list will be returned instead of a string.
-
-
-
-If
-delete_existing
-is False,
-then adding a path that already exists
-will not move it to the beginning;
-it will stay where it is in the list.
@@ -3094,6 +3105,11 @@ print('after:', env['ENV']['INCLUDE'])
before: /biz:/foo
after: /foo/bar:/foo:/biz
+
+
+See also &f-link-env-AppendENVPath;.
+
+
@@ -3103,7 +3119,7 @@ Prepend values to &consvars; in the current &consenv;,
maintaining uniqueness.
Works like &f-link-env-Append; (see for details),
except that values are added to the front,
-rather than the end, of any existing value of the the &consvar;,
+rather than the end, of any existing value of the &consvar;,
and values already present in the &consvar;
will not be added again.
If delete_existing
@@ -3461,40 +3477,36 @@ for a complete explanation of the arguments and behavior.
SConscript(scripts, [exports, variant_dir, duplicate, must_exist])env.SConscript(scripts, [exports, variant_dir, duplicate, must_exist])
- SConscript(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist])
- env.SConscript(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist])
+ SConscript(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist])
+ env.SConscript(dirs=subdirs, [name=scriptname, exports, variant_dir, duplicate, must_exist])
-Execute one or more subsidiary SConscript (configuration) files.
+Executes one or more subsidiary SConscript (configuration) files.
There are two ways to call the
&f-SConscript; function.
-The first calling style
-is to explicitly specify one or more
-scripts
-as the first argument.
+The first calling style is to supply
+one or more SConscript file names
+as the first (positional) argument.
A single script may be specified as a string;
-multiple scripts must be specified as a list
+multiple scripts must be specified as a list of strings
(either explicitly or as created by
a function like
&f-link-Split;).
Examples:
-SConscript('SConscript') # run SConscript in the current directory
+SConscript('SConscript') # run SConscript in the current directory
SConscript('src/SConscript') # run SConscript in the src directory
SConscript(['src/SConscript', 'doc/SConscript'])
config = SConscript('MyConfig.py')
-The second way to call
-&f-SConscript;
-is to specify a list of (sub)directory names
-as a
-dirs=subdirs
-keyword argument.
+The other calling style is to omit the positional argument naming
+scripts and instead specify a list of directory names using the
+dirs keyword argument.
In this case,
&scons;
will
@@ -3504,14 +3516,14 @@ in each of the specified directories.
You may specify a name other than
&SConscript;
by supplying an optional
-name=script
+name=scriptname
keyword argument.
The first three examples below have the same effect
as the first three examples above:
-SConscript(dirs='.') # run SConscript in the current directory
-SConscript(dirs='src') # run SConscript in the src directory
+SConscript(dirs='.') # run SConscript in the current directory
+SConscript(dirs='src') # run SConscript in the src directory
SConscript(dirs=['src', 'doc'])
SConscript(dirs=['sub1', 'sub2'], name='MySConscript')
@@ -3519,8 +3531,12 @@ SConscript(dirs=['sub1', 'sub2'], name='MySConscript')
The optional
exports
-argument provides a string or list of strings representing
+keyword argument provides a string or list of strings representing
variable names, or a dictionary of named values, to export.
+For the first calling style only, a second positional argument
+will be interpreted as exports; the
+second calling style must use the keyword argument form
+for exports.
These variables are locally exported only to the called
SConscript file(s)
and do not affect the global pool of variables managed by the
@@ -3544,38 +3560,24 @@ SConscript(dirs=['one', 'two', 'three'], exports='shared_info')
If the optional
variant_dir
argument is present, it causes an effect equivalent to the
-&f-link-VariantDir; function.
+&f-link-VariantDir; function,
+but in effect only within the scope of the &f-SConscript; call.
The variant_dir
-argument is interpreted relative to the directory of the calling
-SConscript file.
-The optional
-duplicate argument is
-interpreted as for &f-link-VariantDir;.
-If variant_dir
-is omitted, the duplicate argument is ignored.
-See the description of
-&f-link-VariantDir;
-below for additional details and restrictions.
-
-
-
-If
-variant_dir
-is present,
-the source directory is the directory in which the
-SConscript
-file resides and the
-SConscript
+argument is interpreted relative to the directory of the
+calling SConscript file.
+The source directory is the directory in which the
+called SConscript
+file resides and the SConscript
file is evaluated as if it were in the
variant_dir
-directory:
+directory. Thus:
SConscript('src/SConscript', variant_dir='build')
-is equivalent to
+is equivalent to:
@@ -3584,9 +3586,8 @@ SConscript('build/SConscript')
-This later paradigm is often used when the sources are
-in the same directory as the
-&SConstruct;:
+If the sources are in the same directory as the
+&SConstruct;,
@@ -3594,7 +3595,7 @@ SConscript('SConscript', variant_dir='build')
-is equivalent to
+is equivalent to:
@@ -3603,6 +3604,17 @@ SConscript('build/SConscript')
+The optional
+duplicate argument is
+interpreted as for &f-link-VariantDir;.
+If the variant_dir argument
+is omitted, the duplicate argument is ignored.
+See the description of
+&f-link-VariantDir;
+for additional details and restrictions.
+
+
+
$__LDMODULEVERSIONFLAGS">
-$__NINJA_NO">
$__SHLIBVERSIONFLAGS">
$APPLELINK_COMPATIBILITY_VERSION">
$_APPLELINK_COMPATIBILITY_VERSION">
@@ -38,6 +37,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$CC">
$CCCOM">
$CCCOMSTR">
+$CCDEPFLAGS">
$CCFLAGS">
$CCPCHFLAGS">
$CCPDBFLAGS">
@@ -320,7 +320,10 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MSSDK_DIR">
$MSSDK_VERSION">
$MSVC_BATCH">
+$MSVC_NOTFOUND_POLICY">
$MSVC_USE_SCRIPT">
+$MSVC_USE_SCRIPT_ARGS">
+$MSVC_USE_SETTINGS">
$MSVC_UWP_APP">
$MSVC_VERSION">
$MSVS">
@@ -351,17 +354,22 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MWCW_VERSIONS">
$NAME">
$NINJA_ALIAS_NAME">
+$NINJA_CMD_ARGS">
$NINJA_COMPDB_EXPAND">
+$NINJA_DEPFILE_PARSE_FORMAT">
$NINJA_DIR">
$NINJA_DISABLE_AUTO_RUN">
$NINJA_ENV_VAR_CACHE">
$NINJA_FILE_NAME">
$NINJA_FORCE_SCONS_BUILD">
+$NINJA_GENERATED_SOURCE_ALIAS_NAME">
$NINJA_GENERATED_SOURCE_SUFFIXES">
$NINJA_MSVC_DEPS_PREFIX">
$NINJA_POOL">
$NINJA_REGENERATE_DEPS">
$_NINJA_REGENERATE_DEPS_FUNC">
+$NINJA_SCONS_DAEMON_KEEP_ALIVE">
+$NINJA_SCONS_DAEMON_PORT">
$NINJA_SYNTAX">
$no_import_lib">
$OBJPREFIX">
@@ -480,6 +488,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$SHDLINKCOM">
$SHDLINKFLAGS">
$SHELL">
+$SHELL_ENV_GENERATORS">
$SHF03">
$SHF03COM">
$SHF03COMSTR">
@@ -664,7 +673,6 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
-->
$__LDMODULEVERSIONFLAGS">
-$__NINJA_NO">
$__SHLIBVERSIONFLAGS">
$APPLELINK_COMPATIBILITY_VERSION">
$_APPLELINK_COMPATIBILITY_VERSION">
@@ -693,6 +701,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$CC">
$CCCOM">
$CCCOMSTR">
+$CCDEPFLAGS">
$CCFLAGS">
$CCPCHFLAGS">
$CCPDBFLAGS">
@@ -975,7 +984,10 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MSSDK_DIR">
$MSSDK_VERSION">
$MSVC_BATCH">
+$MSVC_NOTFOUND_POLICY">
$MSVC_USE_SCRIPT">
+$MSVC_USE_SCRIPT_ARGS">
+$MSVC_USE_SETTINGS">
$MSVC_UWP_APP">
$MSVC_VERSION">
$MSVS">
@@ -1006,17 +1018,22 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MWCW_VERSIONS">
$NAME">
$NINJA_ALIAS_NAME">
+$NINJA_CMD_ARGS">
$NINJA_COMPDB_EXPAND">
+$NINJA_DEPFILE_PARSE_FORMAT">
$NINJA_DIR">
$NINJA_DISABLE_AUTO_RUN">
$NINJA_ENV_VAR_CACHE">
$NINJA_FILE_NAME">
$NINJA_FORCE_SCONS_BUILD">
+$NINJA_GENERATED_SOURCE_ALIAS_NAME">
$NINJA_GENERATED_SOURCE_SUFFIXES">
$NINJA_MSVC_DEPS_PREFIX">
$NINJA_POOL">
$NINJA_REGENERATE_DEPS">
$_NINJA_REGENERATE_DEPS_FUNC">
+$NINJA_SCONS_DAEMON_KEEP_ALIVE">
+$NINJA_SCONS_DAEMON_PORT">
$NINJA_SYNTAX">
$no_import_lib">
$OBJPREFIX">
@@ -1135,6 +1152,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$SHDLINKCOM">
$SHDLINKFLAGS">
$SHELL">
+$SHELL_ENV_GENERATORS">
$SHF03">
$SHF03COM">
$SHF03COMSTR">
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index a98f4e8..4578d1c 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -5207,7 +5207,7 @@ the dependency graph related to their sources.
An alias is checked for up to date by checking if
its sources are up to date.
An alias is built by making sure its sources have been built,
-and if any building took place,
+and if any building took place,
applying any Actions that are defined as part of the alias.
@@ -7470,7 +7470,7 @@ There are, however, a few portability
issues waiting to trap the unwary.
-.C file suffix
+.C File Suffix&scons; handles the upper-case
.C
@@ -7490,50 +7490,125 @@ suffix as a C source file.
-Fortran file suffixes
+Fortran File Suffixes
-&scons; handles upper-case
-Fortran file suffixes differently
-depending on the capabilities of
-the underlying system.
-On a case-sensitive system
-such as Linux or UNIX,
-&scons; treats a file with a
-.F
-as a Fortran source file
-that is to be first run through
-the standard C preprocessor,
-while the lower-case version is not.
-This matches the convention of gfortran,
-which may also be followed by other Fortran compilers.
-This also applies to other naming variants,
+
+There are several ways source file suffixes impact the
+behavior of &SCons; when working with Fortran language code
+(not all are system-specific, but they are included here
+for completeness).
+
+
+
+As the Fortran language has evolved through multiple
+standards editions, projects might have a need to handle
+files from different language generations differently.
+To this end, &SCons; dispatches to a different compiler
+dialect setup (expressed as a set of &consvars;)
+depending on the file suffix.
+By default, all of these setups start out the same,
+but individual &consvars; can be modified as needed to tune a given dialect.
+Each of these dialacts has a tool specification module
+whose documentation describes the &consvars; associated
+with that dialect: .f
+(as well as .for and .ftn)
+in &t-link-fortran;; (&consvars; start with FORTRAN)
+.f77 in &t-link-f77;;
+(&consvars; start with F77)
+.f90 in &t-link-f90;;
+(&consvars; start with F90)
+.f95 in &t-link-f95;;
+(&consvars; start with F95)
+.f03 in &t-link-f03;;
+(&consvars; start with F03)
+.f08 in &t-link-f08;
+(&consvars; start with F08).
+
+
+
+While &SCons; recognizes multiple internal dialects
+based on filename suffixes,
+the convention of various available Fortran compilers is
+to assign an actual meaning to only two of these suffixes:
+.f
+(as well as .for and .ftn)
+refers to the fixed-format source
+code that was the only available option in FORTRAN 77 and earlier,
+and .f90 refers to free-format source code
+which became available as of the Fortran 90 standard.
+Some compilers recognize suffixes which correspond to Fortran
+specifications later then F90 as equivalent to
+.f90 for this purpose,
+while some do not - check the documentation for your compiler.
+An occasionally suggested policy suggestion is to use only
+.f and .f90
+as Fortran filename suffixes.
+The fixed/free form determination can usually be controlled
+explicitly with compiler flags
+(e.g. for gfortran),
+overriding any assumption that may be made based on the source file suffix.
+
+
+
+The source file suffix does not imply conformance
+with the similarly-named Fortran standard - a suffix of
+.f08 does not mean you are compiling
+specifically for Fortran 2008. Normally, compilers
+provide command-line options for making this selection
+(e.g. for gfortran).
+
+
+
+For dialects from F90 on (including the generic FORTRAN dialect),
+a suffix of .mod is recognized for Fortran modules.
+These files are a side effect of compiling a Fortran
+source file containing module declarations,
+and must be available when other code which declares
+that it uses the module is processed.
+&SCons; does not currently have integrated support for submodules,
+introduced in the Fortran 2008 standard -
+the invoked compiler will produce results,
+but &SCons; will not recognize
+.smod files as tracked objects.
+
+
+
+On a case-sensitive system such as Linux or UNIX,
+a file with a an upper-cased suffix from the set
+.F,
.FOR,
.FTN,
.F90,
.F95,
.F03 and
-.F08;
-files suffixed with
+.F08
+is treated as a Fortran source file
+which shall first be run through
+the standard C preprocessor.
+The lower-cased versions of these suffixes do not
+trigger this behavior.
+On systems which do not distinguish between uppper
+and lower case in filenames,
+this behavior is not available,
+but files suffixed with either
.FPP
-and .fpp
-are both run through the preprocessor,
-as indicated by the pp
-part of the name.
-On a case-insensitive system
-such as Windows,
-&scons; treats a file with a
-.F
-suffix as a Fortran source file that should
-not
-be run through the C preprocessor.
+or .fpp
+are always passed to the preprocessor first.
+This matches the convention of gfortran
+from the GNU Compiler Collection,
+and also followed by certain other Fortran compilers.
+For these two suffixes,
+the generic FORTRAN dialect will be selected.
+
+
-Run through the C preprocessor
-here means that a different set of &consvars; will
-be applied in constructed commands, for example
+&SCons; itself does not invoke the preprocessor,
+that is handled by the compiler,
+but it adds &consvars; which are applicable to the preprocessor run.
+You can see this difference by examining
&cv-link-FORTRANPPCOM; and &cv-link-FORTRANPPCOMSTR;
-instead of
-&cv-link-FORTRANCOM; and &cv-link-FORTRANCOMSTR;.
-See the Fortran-related &consvars; for more details.
+which are used instead of
+&cv-link-FORTRANCOM; and &cv-link-FORTRANCOMSTR; for that dialect.
@@ -7542,10 +7617,10 @@ See the Fortran-related &consvars; for more details.
Cygwin supplies a set of tools and utilities
that let users work on a
-Windows system using a more POSIX-like environment.
-The Cygwin tools, including Cygwin Python,
+Windows system using a POSIX-like environment.
+The Cygwin tools, including Cygwin &Python;,
do this, in part,
-by sharing an ability to interpret UNIX-like path names.
+by sharing an ability to interpret POSIX-style path names.
For example, the Cygwin tools
will internally translate a Cygwin path name
like /cygdrive/c/mydir
@@ -7553,11 +7628,11 @@ to an equivalent Windows pathname
of C:/mydir (equivalent to C:\mydir).
-Versions of Python
+Versions of &Python;
that are built for native Windows execution,
such as the python.org and ActiveState versions,
-do not have the Cygwin path name semantics.
-This means that using a native Windows version of Python
+do not understand the Cygwin path name semantics.
+This means that using a native Windows version of &Python;
to build compiled programs using Cygwin tools
(such as &gcc;, &bison; and &flex;)
may yield unpredictable results.
@@ -7567,14 +7642,22 @@ but it requires careful attention to the use of path names
in your SConscript files.In practice, users can sidestep
-the issue by adopting the following rules:
+the issue by adopting the following guidelines:
When using Cygwin's &gcc; for compiling,
-use the Cygwin-supplied Python interpreter
+use the Cygwin-supplied &Python; interpreter
to run &scons;;
when using Microsoft Visual C/C++
-(or some other Windows compiler)
-use the python.org or Microsoft Store or ActiveState version of Python
-to run &scons;.
+(or some other "native" Windows compiler)
+use the python.org, Microsoft Store, ActiveState or other
+native version of &Python; to run &scons;.
+
+
+
+This discussion largely applies to the msys2 environment
+as well (with the use of the mingw compiler toolchain),
+in particular the recommendation to use the msys2 version of
+&Python; if running &scons; from inside an msys2 shell.
+
@@ -7584,7 +7667,7 @@ to run &scons;.scons.bat batch file,
there are (at least) two ramifications.
Note this is no longer the default - &scons; installed
-via Python's pip installer
+via &Python;''s pip installer
will have an scons.exe which does
not have these limitations:
@@ -7624,7 +7707,7 @@ directory must be in your PATH
environment variable or the
['ENV']['PATH'] &consvar; for &scons;
to detect and use the MinGW tools. When running under the native Windows
-Python interpreter, &scons; will prefer the MinGW tools over the Cygwin
+Python; interpreter, &scons; will prefer the MinGW tools over the Cygwin
tools, if they are both installed, regardless of the order of the bin
directories in the PATH variable.
If you have both MSVC and MinGW
--
cgit v0.12
From 5187917d8a99b86e965ddeb676b0f8fe6c670318 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 16 Jun 2022 11:41:17 -0400
Subject: Add SDK version support and validate all arguments.
---
SCons/Tool/MSCommon/vc.py | 1637 ++++++++++++++++++++++++++++-----------------
1 file changed, 1010 insertions(+), 627 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 0c9fcee..c44c698 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -101,6 +101,17 @@ class BatchFileExecutionWarning(SCons.Warnings.WarningOnByDefault):
class _Const:
+ BOOLEAN_KEYS = {}
+ BOOLEAN_SYMBOLS = {}
+
+ for bool, symbol_list in [
+ (False, (0, '0', False, 'False', 'FALSE', 'false', 'No', 'NO', 'no', None, '')),
+ (True, (1, '1', True, 'True', 'TRUE', 'true', 'Yes', 'YES', 'yes', )),
+ ]:
+ BOOLEAN_KEYS[bool] = symbol_list
+ for symbol in symbol_list:
+ BOOLEAN_SYMBOLS[symbol] = bool
+
MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
'vc_runtime',
'vc_runtime_numeric',
@@ -1197,7 +1208,8 @@ def reset_installed_vcs():
global __INSTALLED_VCS_RUN
__INSTALLED_VCS_RUN = None
_MSVCSetupEnvDefault.reset()
- _MSVCScriptArguments.reset()
+ _WindowsSDK.reset()
+ _ScriptArguments.reset()
# Running these batch files isn't cheap: most of the time spent in
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
@@ -1622,287 +1634,543 @@ def msvc_setup_env_once(env, tool=None):
" Requested tool(s) are: {}".format(req_tools)
_msvc_notfound_policy_handler(env, msg)
-class _MSVCScriptArguments:
-
- # Force -vcvars_ver argument for default toolset
- MSVC_TOOLSET_DEFAULT_VCVARSVER = False
+def msvc_find_valid_batch_script(env, version):
+ """Find and execute appropriate batch script to set up build env.
- # MSVC batch file arguments:
- #
- # VS2022: UWP, SDK, TOOLSET, SPECTRE
- # VS2019: UWP, SDK, TOOLSET, SPECTRE
- # VS2017: UWP, SDK, TOOLSET, SPECTRE
- # VS2015: UWP, SDK
- #
- # MSVC_SCRIPT_ARGS: VS2015+
- #
- # MSVC_UWP_APP: VS2015+
- # MSVC_SDK_VERSION: VS2015+
- # MSVC_TOOLSET_VERSION: VS2017+
- # MSVC_SPECTRE_LIBS: VS2017+
+ The MSVC build environment depends heavily on having the shell
+ environment set. SCons does not inherit that, and does not count
+ on that being set up correctly anyway, so it tries to find the right
+ MSVC batch script, or the right arguments to the generic batch script
+ vcvarsall.bat, and run that, so we have a valid environment to build in.
+ There are dragons here: the batch scripts don't fail (see comments
+ elsewhere), they just leave you with a bad setup, so try hard to
+ get it right.
+ """
- @enum.unique
- class SortOrder(enum.IntEnum):
- ARCH = 0 # arch
- UWP = 1 # MSVC_UWP_APP
- SDK = 2 # MSVC_SDK_VERSION
- TOOLSET = 3 # MSVC_TOOLSET_VERSION
- SPECTRE = 4 # MSVC_SPECTRE_LIBS
- USER = 5 # MSVC_SCRIPT_ARGS
+ # Find the host, target, and all candidate (host, target) platform combinations:
+ platforms = get_host_target(env, version)
+ debug("host_platform %s, target_platform %s host_target_list %s", *platforms)
+ host_platform, target_platform, host_target_list = platforms
- VS2019 = _Const.MSVS_VERSION_INTERNAL['2019']
- VS2017 = _Const.MSVS_VERSION_INTERNAL['2017']
- VS2015 = _Const.MSVS_VERSION_INTERNAL['2015']
+ d = None
+ version_installed = False
+ for host_arch, target_arch, in host_target_list:
+ # Set to current arch.
+ env['TARGET_ARCH'] = target_arch
+ arg = ''
- MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
- 'version', # fully qualified msvc version (e.g., '14.1Exp')
- 'vs_def',
- ])
+ # Try to locate a batch file for this host/target platform combo
+ try:
+ (vc_script, arg, vc_dir, sdk_script) = find_batch_file(env, version, host_arch, target_arch)
+ debug('vc_script:%s vc_script_arg:%s sdk_script:%s', vc_script, arg, sdk_script)
+ version_installed = True
+ except VisualCException as e:
+ msg = str(e)
+ debug('Caught exception while looking for batch file (%s)', msg)
+ version_installed = False
+ continue
- @classmethod
- def _msvc_version(cls, version):
+ # Try to use the located batch file for this host/target platform combo
+ debug('use_script 2 %s, args:%s', repr(vc_script), arg)
+ found = None
+ if vc_script:
+ arg = _ScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
+ try:
+ d = script_env(vc_script, args=arg)
+ found = vc_script
+ except BatchFileExecutionError as e:
+ debug('use_script 3: failed running VC script %s: %s: Error:%s', repr(vc_script), arg, e)
+ vc_script=None
+ continue
+ if not vc_script and sdk_script:
+ debug('use_script 4: trying sdk script: %s', sdk_script)
+ try:
+ d = script_env(sdk_script)
+ found = sdk_script
+ except BatchFileExecutionError as e:
+ debug('use_script 5: failed running SDK script %s: Error:%s', repr(sdk_script), e)
+ continue
+ elif not vc_script and not sdk_script:
+ debug('use_script 6: Neither VC script nor SDK script found')
+ continue
- verstr = get_msvc_version_numeric(version)
- vs_def = _Const.MSVC_VERSION_INTERNAL[verstr]
+ debug("Found a working script/target: %s/%s", repr(found), arg)
+ break # We've found a working target_platform, so stop looking
- version_args = cls.MSVC_VERSION_ARGS_DEFINITION(
- version = version,
- vs_def = vs_def,
- )
+ # If we cannot find a viable installed compiler, reset the TARGET_ARCH
+ # To it's initial value
+ if not d:
+ env['TARGET_ARCH'] = target_platform
- return version_args
+ if version_installed:
+ msg = "MSVC version '{}' working host/target script was not found.\n" \
+ " Host = '{}', Target = '{}'\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(
+ version, host_platform, target_platform
+ )
+ else:
+ installed_vcs = get_installed_vcs(env)
+ if installed_vcs:
+ msg = "MSVC version '{}' was not found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly.\n" \
+ " Installed versions are: {}".format(version, installed_vcs)
+ else:
+ msg = "MSVC version '{}' was not found.\n" \
+ " No versions of the MSVC compiler were found.\n" \
+ " Visual Studio C/C++ compilers may not be set correctly".format(version)
- @classmethod
- def _msvc_script_argument_uwp(cls, env, msvc, arglist):
+ _msvc_notfound_policy_handler(env, msg)
- uwp_app = env['MSVC_UWP_APP']
- debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
+ return d
- if not uwp_app:
- return None
+_undefined = None
- if uwp_app not in (True, '1'):
- return None
+def get_use_script_use_settings(env):
+ global _undefined
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(uwp_app), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
+ if _undefined is None:
+ _undefined = object()
- # VS2017+ rewrites uwp => store for 14.0 toolset
- uwp_arg = msvc.vs_def.vc_uwp
+ # use_script use_settings return values action
+ # value ignored (value, None) use script or bypass detection
+ # undefined value not None (False, value) use dictionary
+ # undefined undefined/None (True, None) msvc detection
- # uwp may not be installed
- argpair = (cls.SortOrder.UWP, uwp_arg)
- arglist.append(argpair)
+ # None (documentation) or evaluates False (code): bypass detection
+ # need to distinguish between undefined and None
+ use_script = env.get('MSVC_USE_SCRIPT', _undefined)
- return uwp_arg
+ if use_script != _undefined:
+ # use_script defined, use_settings ignored (not type checked)
+ return (use_script, None)
- # TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
- re_sdk_version_10 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
+ # undefined or None: use_settings ignored
+ use_settings = env.get('MSVC_USE_SETTINGS', None)
- @classmethod
- def _msvc_script_argument_sdk_constraints(cls, msvc, sdk_version):
+ if use_settings is not None:
+ # use script undefined, use_settings defined and not None (type checked)
+ return (False, use_settings)
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc_version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(sdk_version), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
+ # use script undefined, use_settings undefined or None
+ return (True, None)
- # TODO: check sdk against vs_def/vc_buildtools_def
+def msvc_setup_env(env):
+ debug('called')
+ version = get_default_version(env)
+ if version is None:
+ if not msvc_setup_env_user(env):
+ _MSVCSetupEnvDefault.set_nodefault()
+ return None
- if sdk_version == '8.1':
- debug('valid: sdk_version=%s', repr(sdk_version))
- return None
+ # XXX: we set-up both MSVS version for backward
+ # compatibility with the msvs tool
+ env['MSVC_VERSION'] = version
+ env['MSVS_VERSION'] = version
+ env['MSVS'] = {}
- if cls.re_sdk_version_10.match(sdk_version):
- debug('valid: sdk_version=%s', repr(sdk_version))
- return None
+ use_script, use_settings = get_use_script_use_settings(env)
+ if SCons.Util.is_String(use_script):
+ use_script = use_script.strip()
+ if not os.path.exists(use_script):
+ raise MSVCScriptNotFound('Script specified by MSVC_USE_SCRIPT not found: "{}"'.format(use_script))
+ args = env.subst('$MSVC_USE_SCRIPT_ARGS')
+ debug('use_script 1 %s %s', repr(use_script), repr(args))
+ d = script_env(use_script, args)
+ elif use_script:
+ d = msvc_find_valid_batch_script(env,version)
+ debug('use_script 2 %s', d)
+ if not d:
+ return d
+ elif use_settings is not None:
+ if not SCons.Util.is_Dict(use_settings):
+ error_msg = 'MSVC_USE_SETTINGS type error: expected a dictionary, found {}'.format(type(use_settings).__name__)
+ raise MSVCUseSettingsError(error_msg)
+ d = use_settings
+ debug('use_settings %s', d)
+ else:
+ debug('MSVC_USE_SCRIPT set to False')
+ warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
+ "set correctly."
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ return None
- debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
- err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
- return err_msg
+ for k, v in d.items():
+ env.PrependENVPath(k, v, delete_existing=True)
+ debug("env['ENV']['%s'] = %s", k, env['ENV'][k])
- @classmethod
- def _msvc_script_argument_sdk(cls, env, msvc, is_uwp, arglist):
+ # final check to issue a warning if the compiler is not present
+ if not find_program_path(env, 'cl'):
+ debug("did not find %s", _CL_EXE_NAME)
+ if CONFIG_CACHE:
+ propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE)
+ else:
+ propose = "It may need to be installed separately with Visual Studio."
+ warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose)
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
- sdk_version = env['MSVC_SDK_VERSION']
- debug(
- 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, uwp=%s',
- repr(msvc.version), repr(sdk_version), repr(is_uwp)
- )
+def msvc_exists(env=None, version=None):
+ debug('version=%s', repr(version))
+ vcs = get_installed_vcs(env)
+ if version is None:
+ rval = len(vcs) > 0
+ else:
+ rval = version in vcs
+ debug('version=%s, return=%s', repr(version), rval)
+ return rval
- if not sdk_version:
- return None
+def msvc_setup_env_user(env=None):
+ rval = False
+ if env:
- err_msg = cls._msvc_script_argument_sdk_constraints(msvc, sdk_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
+ # Intent is to use msvc tools:
+ # MSVC_VERSION or MSVS_VERSION: defined and is True
+ # MSVC_USE_SCRIPT: defined and (is string or is False)
+ # MSVC_USE_SETTINGS: defined and is not None
- # sdk folder may not exist
- argpair = (cls.SortOrder.SDK, sdk_version)
- arglist.append(argpair)
+ # defined and is True
+ for key in ['MSVC_VERSION', 'MSVS_VERSION']:
+ if key in env and env[key]:
+ rval = True
+ debug('key=%s, return=%s', repr(key), rval)
+ return rval
- return sdk_version
+ # defined and (is string or is False)
+ for key in ['MSVC_USE_SCRIPT']:
+ if key in env and (SCons.Util.is_String(env[key]) or not env[key]):
+ rval = True
+ debug('key=%s, return=%s', repr(key), rval)
+ return rval
- @classmethod
- def _msvc_read_toolset_file(cls, msvc, filename):
- toolset_version = None
+ # defined and is not None
+ for key in ['MSVC_USE_SETTINGS']:
+ if key in env and env[key] is not None:
+ rval = True
+ debug('key=%s, return=%s', repr(key), rval)
+ return rval
+
+ debug('return=%s', rval)
+ return rval
+
+def msvc_setup_env_tool(env=None, version=None, tool=None):
+ debug('tool=%s, version=%s', repr(tool), repr(version))
+ _MSVCSetupEnvDefault.register_tool(env, tool)
+ rval = False
+ if not rval and msvc_exists(env, version):
+ rval = True
+ if not rval and msvc_setup_env_user(env):
+ rval = True
+ debug('tool=%s, version=%s, return=%s', repr(tool), repr(version), rval)
+ return rval
+
+class _Util:
+
+ @staticmethod
+ def listdir_dirs(p):
+ dirs = []
+ for dir_name in os.listdir(p):
+ dir_path = os.path.join(p, dir_name)
+ if os.path.isdir(dir_path):
+ dirs.append((dir_name, dir_path))
+ return dirs
+
+ @staticmethod
+ def process_path(p):
+ if p:
+ p = os.path.normpath(p)
+ p = os.path.realpath(p)
+ p = os.path.normcase(p)
+ return p
+
+class _Registry:
+
+ def read_value(hkey, subkey_valname):
try:
- with open(filename) as f:
- toolset_version = f.readlines()[0].strip()
- debug(
- 'msvc_version=%s, filename=%s, toolset_version=%s',
- repr(msvc.version), repr(filename), repr(toolset_version)
- )
+ rval = common.read_reg(subkey_valname, hkroot=hkey)
except OSError:
- debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
except IndexError:
- debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
- return toolset_version
+ debug('IndexError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
+ debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
+ return rval
@classmethod
- def _msvc_read_toolset_folders(cls, msvc, vc_dir):
+ def registry_query_path(cls, key, val, suffix):
+ extval = val + '\\' + suffix if suffix else val
+ qpath = cls.read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = _Util.process_path(qpath)
+ else:
+ qpath = None
+ return (qpath, key, val, extval)
+
+ REG_SOFTWARE_MICROSOFT = [
+ (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Microsoft'),
+ (SCons.Util.HKEY_CURRENT_USER, r'Software\Wow6432Node\Microsoft'), # SDK queries
+ (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Microsoft'),
+ (SCons.Util.HKEY_CURRENT_USER, r'Software\Microsoft'),
+ ]
- toolsets_sxs = {}
- toolsets_full = []
+ @classmethod
+ def microsoft_query_paths(cls, suffix, usrval=None):
+ paths = []
+ records = []
+ for key, val in cls.REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ qpath = cls.read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = _Util.process_path(qpath)
+ if qpath not in paths:
+ paths.append(qpath)
+ records.append((qpath, key, val, extval, usrval))
+ return records
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
- sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
- for sxs_toolset in sxs_toolsets:
- filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
- filepath = os.path.join(build_dir, sxs_toolset, filename)
- debug('sxs toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_version = cls._msvc_read_toolset_file(msvc, filepath)
- if not toolset_version:
- continue
- toolsets_sxs[sxs_toolset] = toolset_version
- debug(
- 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
- repr(msvc.version), repr(sxs_toolset), toolset_version
- )
+ @classmethod
+ def microsoft_query_keys(cls, suffix, usrval=None):
+ records = []
+ for key, val in cls.REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ rval = cls.read_value(key, extval)
+ if rval:
+ records.append((key, val, extval, usrval))
+ return records
- toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
- toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
- for toolset_version in toolsets:
- binpath = os.path.join(toolset_dir, toolset_version, "bin")
- debug('toolset: check binpath=%s', repr(binpath))
- if os.path.exists(binpath):
- toolsets_full.append(toolset_version)
- debug(
- 'toolset: msvc_version=%s, toolset_version=%s',
- repr(msvc.version), repr(toolset_version)
- )
+ @classmethod
+ def microsoft_sdks(cls, version):
+ return '\\'.join([r'Microsoft SDKs\Windows', 'v' + version, r'InstallationFolder'])
- toolsets_full.sort(reverse=True)
- debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
+ @classmethod
+ def sdk_query_paths(cls, version):
+ q = cls.microsoft_sdks(version)
+ return cls.microsoft_query_paths(q)
- return toolsets_sxs, toolsets_full
+ @classmethod
+ def windows_kits(cls, version):
+ return r'Windows Kits\Installed Roots\KitsRoot' + version
@classmethod
- def _msvc_read_toolset_default(cls, msvc, vc_dir):
+ def windows_kit_query_paths(cls, version):
+ q = cls.windows_kits(version)
+ return cls.microsoft_query_paths(q)
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+class _WindowsSDK:
- # VS2019+
- filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
- filepath = os.path.join(build_dir, filename)
+ sdk_map_cache = {}
+ sdk_cache = {}
- debug('default toolset: check file=%s', repr(filepath))
- toolset_buildtools = None
- if os.path.exists(filepath):
- toolset_buildtools = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_buildtools:
- return toolset_buildtools
+ @classmethod
+ def reset(cls):
+ cls.sdk_map_cache = {}
+ cls.sdk_cache = {}
- # VS2017+
- filename = "Microsoft.VCToolsVersion.default.txt"
- filepath = os.path.join(build_dir, filename)
+ @classmethod
+ def _new_sdk_map(cls):
+ sdk_map = {
+ 'desktop': [],
+ 'uwp': [],
+ }
+ return sdk_map
- debug('default toolset: check file=%s', repr(filepath))
- toolset_default = None
- if os.path.exists(filepath):
- toolset_default = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_default:
- return toolset_default
+ @classmethod
+ def _sdk_10_layout(cls, version):
- return None
+ folder_prefix = version + '.'
+
+ sdk_map = cls._new_sdk_map()
+
+ sdk_roots = _Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ if not os.path.exists(sdk_root):
+ continue
+
+ sdk_include_path = os.path.join(sdk_root, 'include')
+ if not os.path.exists(sdk_include_path):
+ continue
+
+ for version_nbr, version_nbr_path in _Util.listdir_dirs(sdk_include_path):
+
+ if not version_nbr.startswith(folder_prefix):
+ continue
+
+ sdk_inc_path = _Util.process_path(os.path.join(version_nbr_path, 'um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
@classmethod
- def _reset_toolsets(cls):
- debug('reset: toolset cache')
- cls._toolset_version_cache = {}
- cls._toolset_default_cache = {}
+ def _sdk_81_layout(cls, version):
- _toolset_version_cache = {}
- _toolset_default_cache = {}
+ version_nbr = version
+
+ sdk_map = cls._new_sdk_map()
+
+ sdk_roots = _Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ sdk_targets = []
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ # msvc does not check for existence of root or other files
+
+ sdk_inc_path = _Util.process_path(os.path.join(sdk_root, r'include\um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
@classmethod
- def _msvc_version_toolsets(cls, msvc, vc_dir):
+ def _sdk_10(cls, key, reg_version):
+ if key in cls.sdk_map_cache:
+ sdk_map = cls.sdk_map_cache[key]
+ else:
+ sdk_map = cls._sdk_10_layout(reg_version)
+ cls.sdk_map_cache[key] = sdk_map
+ return sdk_map
- if msvc.version in cls._toolset_version_cache:
- toolsets_sxs, toolsets_full = cls._toolset_version_cache[msvc.version]
+ @classmethod
+ def _sdk_81(cls, key, reg_version):
+ if key in cls.sdk_map_cache:
+ sdk_map = cls.sdk_map_cache[key]
else:
- toolsets_sxs, toolsets_full = cls._msvc_read_toolset_folders(msvc, vc_dir)
- cls._toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
+ sdk_map = cls._sdk_81_layout(reg_version)
+ cls.sdk_map_cache[key] = sdk_map
+ return sdk_map
- return toolsets_sxs, toolsets_full
+ @classmethod
+ def _combine_sdk_map_list(cls, sdk_map_list):
+ combined_sdk_map = cls._new_sdk_map()
+ for sdk_map in sdk_map_list:
+ for key, val in sdk_map.items():
+ combined_sdk_map[key].extend(val)
+ return combined_sdk_map
+
+ sdk_dispatch_map = None
@classmethod
- def _msvc_default_toolset(cls, msvc, vc_dir):
+ def _version_list_sdk_map(cls, version_list):
- if msvc.version in cls._toolset_default_cache:
- toolset_default = cls._toolset_default_cache[msvc.version]
- else:
- toolset_default = cls._msvc_read_toolset_default(msvc, vc_dir)
- cls._toolset_default_cache[msvc.version] = toolset_default
+ if not cls.sdk_dispatch_map:
+ cls.sdk_dispatch_map = {
+ '10.0': (cls._sdk_10, '10.0'),
+ '8.1': (cls._sdk_81, '8.1'),
+ }
- return toolset_default
+ sdk_map_list = []
+ for version in version_list:
+ func, reg_version = cls.sdk_dispatch_map[version]
+ sdk_map = func(version, reg_version)
+ sdk_map_list.append(sdk_map)
+
+ combined_sdk_map = cls._combine_sdk_map_list(sdk_map_list)
+ return combined_sdk_map
@classmethod
- def _msvc_version_toolset_vcvars(cls, msvc, vc_dir, toolset_version):
+ def _sdk_map(cls, version_list):
+ key = tuple(version_list)
+ if key in cls.sdk_cache:
+ sdk_map = cls.sdk_cache[key]
+ else:
+ version_numlist = [float(v) for v in version_list]
+ version_numlist.sort(reverse=True)
+ key = tuple([str(v) for v in version_numlist])
+ sdk_map = cls._version_list_sdk_map(key)
+ cls.sdk_cache[key] = sdk_map
+ return sdk_map
- if toolset_version == '14.0':
- return toolset_version
+ @classmethod
+ def _get_sdk_version_list(cls, version_list, platform):
+ sdk_map = cls._sdk_map(version_list)
+ sdk_list = sdk_map.get(platform, [])
+ return sdk_list
- toolsets_sxs, toolsets_full = cls._msvc_version_toolsets(msvc, vc_dir)
+def get_sdk_versions(MSVC_VERSION=None, MSVC_UWP_APP=False):
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric == cls.VS2019.vc_buildtools_def.vc_version_numeric:
- # necessary to detect toolset not found
- if toolset_version == '14.28.16.8':
- new_toolset_version = '14.28'
- # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
- # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
- # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
+ sdk_versions = []
- if toolset_version in toolsets_sxs:
- toolset_vcvars = toolsets_sxs[toolset_version]
- return toolset_vcvars
+ if not MSVC_VERSION:
+ vcs = get_installed_vcs()
+ if not vcs:
+ return sdk_versions
+ MSVC_VERSION = vcs[0]
- for toolset_full in toolsets_full:
- if toolset_full.startswith(toolset_version):
- toolset_vcvars = toolset_full
- return toolset_vcvars
+ verstr = get_msvc_version_numeric(MSVC_VERSION)
+ vs_def = _Const.MSVC_VERSION_EXTERNAL.get(verstr, None)
+ if not vs_def:
+ return sdk_versions
- return None
+ is_uwp = True if MSVC_UWP_APP in _Const.BOOLEAN_KEYS[True] else False
+ platform = 'uwp' if is_uwp else 'desktop'
+ sdk_list = _WindowsSDK._get_sdk_version_list(vs_def.vc_sdk_versions, platform)
+
+ sdk_versions.extend(sdk_list)
+ return sdk_versions
+
+class _ScriptArguments:
+
+ # TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
+ re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
+ re_sdk_version_81 = re.compile(r'^8[.]1$')
+
+ re_sdk_dispatch_map = {
+ '10.0': re_sdk_version_100,
+ '8.1': re_sdk_version_81,
+ }
# capture msvc version
re_toolset_version = re.compile(r'^(?P[1-9][0-9]?[.][0-9])[0-9.]*$', re.IGNORECASE)
@@ -1920,223 +2188,210 @@ class _MSVCScriptArguments:
# valid SxS formats will be matched with re_toolset_full: match 3 '.' format
re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
- @classmethod
- def _msvc_script_argument_toolset_constraints(cls, msvc, toolset_version):
+ # MSVC_SCRIPT_ARGS
+ re_vcvars_uwp = re.compile(r'(?:(?(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
+ re_vcvars_sdk = re.compile(r'(?:(?(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
+ re_vcvars_toolset = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_ver[=](?P\S*))(?:(?!\S)|$)', re.IGNORECASE)
+ re_vcvars_spectre = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P\S*))(?:(?!\S)|$)',re.IGNORECASE)
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(toolset_version), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
- )
- return err_msg
+ # Force default sdk argument
+ MSVC_FORCE_DEFAULT_SDK = False
- m = cls.re_toolset_version.match(toolset_version)
- if not m:
- debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
- err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
- repr(toolset_version)
- )
- return err_msg
+ # Force default toolset argument
+ MSVC_FORCE_DEFAULT_TOOLSET = False
- toolset_ver = m.group('version')
- toolset_vernum = float(toolset_ver)
+ # MSVC batch file arguments:
+ #
+ # VS2022: UWP, SDK, TOOLSET, SPECTRE
+ # VS2019: UWP, SDK, TOOLSET, SPECTRE
+ # VS2017: UWP, SDK, TOOLSET, SPECTRE
+ # VS2015: UWP, SDK
+ #
+ # MSVC_SCRIPT_ARGS: VS2015+
+ #
+ # MSVC_UWP_APP: VS2015+
+ # MSVC_SDK_VERSION: VS2015+
+ # MSVC_TOOLSET_VERSION: VS2017+
+ # MSVC_SPECTRE_LIBS: VS2017+
- if toolset_vernum < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: %s < %s VS2015',
- repr(toolset_vernum), repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
- repr(toolset_version), repr(toolset_ver), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
+ @enum.unique
+ class SortOrder(enum.IntEnum):
+ ARCH = 0 # arch
+ UWP = 1 # MSVC_UWP_APP
+ SDK = 2 # MSVC_SDK_VERSION
+ TOOLSET = 3 # MSVC_TOOLSET_VERSION
+ SPECTRE = 4 # MSVC_SPECTRE_LIBS
+ USER = 5 # MSVC_SCRIPT_ARGS
- if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: toolset %s > %s msvc',
- repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
- repr(toolset_version), repr(toolset_ver), repr(msvc.version)
- )
- return err_msg
+ VS2019 = _Const.MSVS_VERSION_INTERNAL['2019']
+ VS2017 = _Const.MSVS_VERSION_INTERNAL['2017']
+ VS2015 = _Const.MSVS_VERSION_INTERNAL['2015']
- if toolset_vernum == cls.VS2015.vc_buildtools_def.vc_version_numeric:
- # tooset = 14.0
- if cls.re_toolset_full.match(toolset_version):
- if not cls.re_toolset_140.match(toolset_version):
- debug(
- 'invalid: toolset version 14.0 constraint: %s != 14.0',
- repr(toolset_version)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
- repr(toolset_version), repr(toolset_version)
- )
- return err_msg
- return None
+ MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
+ 'version', # fully qualified msvc version (e.g., '14.1Exp')
+ 'vs_def',
+ ])
- if cls.re_toolset_full.match(toolset_version):
- debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
- return None
+ @classmethod
+ def _msvc_version(cls, version):
- if cls.re_toolset_sxs.match(toolset_version):
- debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
- return None
+ verstr = get_msvc_version_numeric(version)
+ vs_def = _Const.MSVC_VERSION_INTERNAL[verstr]
- debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
- err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
- return err_msg
+ version_args = cls.MSVC_VERSION_ARGS_DEFINITION(
+ version = version,
+ vs_def = vs_def,
+ )
+
+ return version_args
@classmethod
- def _msvc_script_argument_toolset(cls, env, msvc, vc_dir, arglist):
+ def _msvc_script_argument_uwp(cls, env, msvc, arglist):
- toolset_version = env['MSVC_TOOLSET_VERSION']
- debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
+ uwp_app = env['MSVC_UWP_APP']
+ debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
- if not toolset_version:
+ if not uwp_app:
return None
- err_msg = cls._msvc_script_argument_toolset_constraints(msvc, toolset_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
+ if uwp_app not in _Const.BOOLEAN_KEYS[True]:
+ return None
- if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
- new_toolset_version = '14.0'
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
)
- toolset_version = new_toolset_version
-
- toolset_vcvars = cls._msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
- debug(
- 'toolset: toolset_version=%s, toolset_vcvars=%s',
- repr(toolset_version), repr(toolset_vcvars)
- )
-
- if not toolset_vcvars:
- err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
- repr(toolset_version), repr(msvc.version)
+ err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(uwp_app), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
)
raise MSVCArgumentError(err_msg)
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
+ # VS2017+ rewrites uwp => store for 14.0 toolset
+ uwp_arg = msvc.vs_def.vc_uwp
+
+ # uwp may not be installed
+ argpair = (cls.SortOrder.UWP, uwp_arg)
arglist.append(argpair)
- return toolset_vcvars
+ return uwp_arg
@classmethod
- def _msvc_script_default_toolset(cls, env, msvc, vc_dir, arglist):
+ def _user_script_argument_uwp(cls, env, uwp, user_argstr):
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
+ matches = [m for m in cls.re_vcvars_uwp.finditer(user_argstr)]
+ if not matches:
return None
- toolset_default = cls._msvc_default_toolset(msvc, vc_dir)
- if not toolset_default:
+ if len(matches) > 1:
+ debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not uwp:
return None
- debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
+ env_argstr = env.get('MSVC_UWP_APP','')
+ debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
- arglist.append(argpair)
+ err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
- return toolset_default
+ raise MSVCArgumentError(err_msg)
@classmethod
- def _msvc_script_argument_spectre(cls, env, msvc, arglist):
-
- spectre_libs = env['MSVC_SPECTRE_LIBS']
- debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
-
- if not spectre_libs:
- return None
-
- if spectre_libs not in (True, '1'):
- return None
+ def _msvc_script_argument_sdk_constraints(cls, msvc, sdk_version):
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
+ 'invalid: msvc_version constraint: %s < %s VS2015',
repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
+ repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
)
- err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(spectre_libs), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
+ err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(sdk_version), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
)
- raise MSVCArgumentError(err_msg)
-
- spectre_arg = 'spectre'
+ return err_msg
- # spectre libs may not be installed
- argpair = (cls.SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
- arglist.append(argpair)
+ for msvc_sdk_version in msvc.vs_def.vc_sdk_versions:
+ re_sdk_version = cls.re_sdk_dispatch_map[msvc_sdk_version]
+ if re_sdk_version.match(sdk_version):
+ debug('valid: sdk_version=%s', repr(sdk_version))
+ return None
- return spectre_arg
+ debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
+ err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
+ return err_msg
@classmethod
- def _msvc_script_argument_user(cls, env, msvc, arglist):
+ def _msvc_script_argument_sdk(cls, env, msvc, platform, arglist):
- # subst None -> empty string
- script_args = env.subst('$MSVC_SCRIPT_ARGS')
- debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
+ sdk_version = env['MSVC_SDK_VERSION']
+ debug(
+ 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform=%s',
+ repr(msvc.version), repr(sdk_version), repr(platform)
+ )
- if not script_args:
+ if not sdk_version:
return None
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(script_args), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
+ err_msg = cls._msvc_script_argument_sdk_constraints(msvc, sdk_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform)
+
+ if sdk_version not in sdk_list:
+ err_msg = "MSVC_SDK_VERSION {} not found for platform {}".format(
+ repr(sdk_version), repr(platform)
)
raise MSVCArgumentError(err_msg)
- # user arguments are not validated
- argpair = (cls.SortOrder.USER, script_args)
+ # sdk folder may not exist
+ argpair = (cls.SortOrder.SDK, sdk_version)
arglist.append(argpair)
- return script_args
-
- re_vcvars_uwp = re.compile(r'(?:\s|^)(?P(?:uwp|store))(?:\s|$)',re.IGNORECASE)
- re_vcvars_sdk = re.compile(r'(?:\s|^)(?P(?:[1-9][0-9]*[.]\S*))(?:\s|$)',re.IGNORECASE)
- re_vcvars_spectre = re.compile(r'(?:\s|^)(?P(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P\S*))(?:\s|$)',re.IGNORECASE)
- re_vcvars_toolset = re.compile(r'(?:\s|^)(?P(?:[-]{1,2}|[/])vcvars_ver[=](?P\S*))(?:\s|$)', re.IGNORECASE)
+ return sdk_version
@classmethod
- def _user_script_argument_uwp(cls, env, uwp, user_argstr):
+ def _msvc_script_default_sdk(cls, env, msvc, platform, arglist):
- if not uwp:
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
return None
- m = cls.re_vcvars_uwp.search(user_argstr)
- if not m:
+ sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform)
+ if not len(sdk_list):
return None
- env_argstr = env.get('MSVC_UWP_APP','')
- debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+ sdk_default = sdk_list[0]
- err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
+ debug(
+ 'MSVC_VERSION=%s, sdk_default=%s, platform=%s',
+ repr(msvc.version), repr(sdk_default), repr(platform)
)
- raise MSVCArgumentError(err_msg)
+ argpair = (cls.SortOrder.SDK, sdk_default)
+ arglist.append(argpair)
+
+ return sdk_default
@classmethod
def _user_script_argument_sdk(cls, env, sdk_version, user_argstr):
- if not sdk_version:
+ matches = [m for m in cls.re_vcvars_sdk.finditer(user_argstr)]
+ if not matches:
return None
- m = cls.re_vcvars_sdk.search(user_argstr)
- if not m:
- return None
+ if len(matches) > 1:
+ debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not sdk_version:
+ user_sdk = matches[0].group('sdk')
+ return user_sdk
env_argstr = env.get('MSVC_SDK_VERSION','')
debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
@@ -2148,33 +2403,374 @@ class _MSVCScriptArguments:
raise MSVCArgumentError(err_msg)
@classmethod
- def _user_script_argument_toolset(cls, env, toolset_version, user_argstr):
+ def _msvc_read_toolset_file(cls, msvc, filename):
+ toolset_version = None
+ try:
+ with open(filename) as f:
+ toolset_version = f.readlines()[0].strip()
+ debug(
+ 'msvc_version=%s, filename=%s, toolset_version=%s',
+ repr(msvc.version), repr(filename), repr(toolset_version)
+ )
+ except OSError:
+ debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ except IndexError:
+ debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ return toolset_version
- m = cls.re_vcvars_toolset.search(user_argstr)
- if not m:
- return None
+ @classmethod
+ def _msvc_read_toolset_folders(cls, msvc, vc_dir):
- if not toolset_version:
- user_toolset = m.group('toolset')
- return user_toolset
+ toolsets_sxs = {}
+ toolsets_full = []
- env_argstr = env.get('MSVC_TOOLSET_VERSION','')
- debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+ sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
+ for sxs_toolset in sxs_toolsets:
+ filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
+ filepath = os.path.join(build_dir, sxs_toolset, filename)
+ debug('sxs toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_version = cls._msvc_read_toolset_file(msvc, filepath)
+ if not toolset_version:
+ continue
+ toolsets_sxs[sxs_toolset] = toolset_version
+ debug(
+ 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(sxs_toolset), toolset_version
+ )
- err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
+ toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
+ toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
+ for toolset_version in toolsets:
+ binpath = os.path.join(toolset_dir, toolset_version, "bin")
+ debug('toolset: check binpath=%s', repr(binpath))
+ if os.path.exists(binpath):
+ toolsets_full.append(toolset_version)
+ debug(
+ 'toolset: msvc_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(toolset_version)
+ )
- raise MSVCArgumentError(err_msg)
+ toolsets_full.sort(reverse=True)
+ debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
+
+ return toolsets_sxs, toolsets_full
+
+ @classmethod
+ def _msvc_read_toolset_default(cls, msvc, vc_dir):
+
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+
+ # VS2019+
+ filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ toolset_buildtools = None
+ if os.path.exists(filepath):
+ toolset_buildtools = cls._msvc_read_toolset_file(msvc, filepath)
+ if toolset_buildtools:
+ return toolset_buildtools
+
+ # VS2017+
+ filename = "Microsoft.VCToolsVersion.default.txt"
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ toolset_default = None
+ if os.path.exists(filepath):
+ toolset_default = cls._msvc_read_toolset_file(msvc, filepath)
+ if toolset_default:
+ return toolset_default
+
+ return None
+
+ @classmethod
+ def _reset_toolsets(cls):
+ debug('reset: toolset cache')
+ cls._toolset_version_cache = {}
+ cls._toolset_default_cache = {}
+
+ _toolset_version_cache = {}
+ _toolset_default_cache = {}
+
+ @classmethod
+ def _msvc_version_toolsets(cls, msvc, vc_dir):
+
+ if msvc.version in cls._toolset_version_cache:
+ toolsets_sxs, toolsets_full = cls._toolset_version_cache[msvc.version]
+ else:
+ toolsets_sxs, toolsets_full = cls._msvc_read_toolset_folders(msvc, vc_dir)
+ cls._toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
+
+ return toolsets_sxs, toolsets_full
+
+ @classmethod
+ def _msvc_default_toolset(cls, msvc, vc_dir):
+
+ if msvc.version in cls._toolset_default_cache:
+ toolset_default = cls._toolset_default_cache[msvc.version]
+ else:
+ toolset_default = cls._msvc_read_toolset_default(msvc, vc_dir)
+ cls._toolset_default_cache[msvc.version] = toolset_default
+
+ return toolset_default
+
+ @classmethod
+ def _msvc_version_toolset_vcvars(cls, msvc, vc_dir, toolset_version):
+
+ if toolset_version == '14.0':
+ return toolset_version
+
+ toolsets_sxs, toolsets_full = cls._msvc_version_toolsets(msvc, vc_dir)
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric == cls.VS2019.vc_buildtools_def.vc_version_numeric:
+ # necessary to detect toolset not found
+ if toolset_version == '14.28.16.8':
+ new_toolset_version = '14.28'
+ # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
+ # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
+ # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ if toolset_version in toolsets_sxs:
+ toolset_vcvars = toolsets_sxs[toolset_version]
+ return toolset_vcvars
+
+ for toolset_full in toolsets_full:
+ if toolset_full.startswith(toolset_version):
+ toolset_vcvars = toolset_full
+ return toolset_vcvars
+
+ return None
+
+ @classmethod
+ def _msvc_script_argument_toolset_constraints(cls, msvc, toolset_version):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(toolset_version), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ m = cls.re_toolset_version.match(toolset_version)
+ if not m:
+ debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
+ err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
+ repr(toolset_version)
+ )
+ return err_msg
+
+ toolset_ver = m.group('version')
+ toolset_vernum = float(toolset_ver)
+
+ if toolset_vernum < cls.VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: %s < %s VS2015',
+ repr(toolset_vernum), repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
+ repr(toolset_version), repr(toolset_ver), repr(cls.VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: toolset %s > %s msvc',
+ repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
+ repr(toolset_version), repr(toolset_ver), repr(msvc.version)
+ )
+ return err_msg
+
+ if toolset_vernum == cls.VS2015.vc_buildtools_def.vc_version_numeric:
+ # tooset = 14.0
+ if cls.re_toolset_full.match(toolset_version):
+ if not cls.re_toolset_140.match(toolset_version):
+ debug(
+ 'invalid: toolset version 14.0 constraint: %s != 14.0',
+ repr(toolset_version)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
+ repr(toolset_version), repr(toolset_version)
+ )
+ return err_msg
+ return None
+
+ if cls.re_toolset_full.match(toolset_version):
+ debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
+ return None
+
+ if cls.re_toolset_sxs.match(toolset_version):
+ debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
+ return None
+
+ debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
+ err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
+ return err_msg
+
+ @classmethod
+ def _msvc_script_argument_toolset(cls, env, msvc, vc_dir, arglist):
+
+ toolset_version = env['MSVC_TOOLSET_VERSION']
+ debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
+
+ if not toolset_version:
+ return None
+
+ err_msg = cls._msvc_script_argument_toolset_constraints(msvc, toolset_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
+ new_toolset_version = '14.0'
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ toolset_vcvars = cls._msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
+ debug(
+ 'toolset: toolset_version=%s, toolset_vcvars=%s',
+ repr(toolset_version), repr(toolset_vcvars)
+ )
+
+ if not toolset_vcvars:
+ err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
+ repr(toolset_version), repr(msvc.version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
+ arglist.append(argpair)
+
+ return toolset_vcvars
+
+ @classmethod
+ def _msvc_script_default_toolset(cls, env, msvc, vc_dir, arglist):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
+ return None
+
+ toolset_default = cls._msvc_default_toolset(msvc, vc_dir)
+ if not toolset_default:
+ return None
+
+ debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
+
+ argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
+ arglist.append(argpair)
+
+ return toolset_default
+
+ @classmethod
+ def _user_script_argument_toolset(cls, env, toolset_version, user_argstr):
+
+ matches = [m for m in cls.re_vcvars_toolset.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not toolset_version:
+ user_toolset = matches[0].group('toolset')
+ return user_toolset
+
+ env_argstr = env.get('MSVC_TOOLSET_VERSION','')
+ debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+ @classmethod
+ def _msvc_script_argument_spectre(cls, env, msvc, arglist):
+
+ spectre_libs = env['MSVC_SPECTRE_LIBS']
+ debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
+
+ if not spectre_libs:
+ return None
+
+ if spectre_libs not in (True, '1'):
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(spectre_libs), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ spectre_arg = 'spectre'
+
+ # spectre libs may not be installed
+ argpair = (cls.SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
+ arglist.append(argpair)
+
+ return spectre_arg
+
+ @classmethod
+ def _msvc_script_argument_user(cls, env, msvc, arglist):
+
+ # subst None -> empty string
+ script_args = env.subst('$MSVC_SCRIPT_ARGS')
+ debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
+
+ if not script_args:
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(script_args), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ # user arguments are not validated
+ argpair = (cls.SortOrder.USER, script_args)
+ arglist.append(argpair)
+
+ return script_args
@classmethod
def _user_script_argument_spectre(cls, env, spectre, user_argstr):
- if not spectre:
+ matches = [m for m in cls.re_vcvars_spectre.finditer(user_argstr)]
+ if not matches:
return None
- m = cls.re_vcvars_spectre.search(user_argstr)
- if not m:
+ if len(matches) > 1:
+ debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not spectre:
return None
env_argstr = env.get('MSVC_SPECTRE_LIBS','')
@@ -2189,55 +2785,70 @@ class _MSVCScriptArguments:
@classmethod
def msvc_script_arguments(cls, env, version, vc_dir, arg):
- msvc = cls._msvc_version(version)
-
- argstr = ''
arglist = []
+ msvc = cls._msvc_version(version)
+
if arg:
argpair = (cls.SortOrder.ARCH, arg)
arglist.append(argpair)
- user_argstr = None
- user_toolset = None
-
- uwp = None
- sdk_version = None
- toolset_version = None
- spectre = None
-
if 'MSVC_SCRIPT_ARGS' in env:
user_argstr = cls._msvc_script_argument_user(env, msvc, arglist)
+ else:
+ user_argstr = None
if 'MSVC_UWP_APP' in env:
uwp = cls._msvc_script_argument_uwp(env, msvc, arglist)
- if uwp and user_argstr:
- cls._user_script_argument_uwp(env, uwp, user_argstr)
+ else:
+ uwp = None
+
+ if user_argstr:
+ cls._user_script_argument_uwp(env, uwp, user_argstr)
+
+ platform = 'uwp' if uwp else 'desktop'
if 'MSVC_SDK_VERSION' in env:
- is_uwp = True if uwp else False
- sdk_version = cls._msvc_script_argument_sdk(env, msvc, is_uwp, arglist)
- if sdk_version and user_argstr:
- cls._user_script_argument_sdk(env, sdk_version, user_argstr)
+ sdk_version = cls._msvc_script_argument_sdk(env, msvc, platform, arglist)
+ else:
+ sdk_version = None
+
+ if user_argstr:
+ user_sdk = cls._user_script_argument_sdk(env, sdk_version, user_argstr)
+ else:
+ user_sdk = None
+
+ if cls.MSVC_FORCE_DEFAULT_SDK:
+ if not sdk_version and not user_sdk:
+ sdk_version = cls._msvc_script_default_sdk(env, msvc, platform, arglist)
if 'MSVC_TOOLSET_VERSION' in env:
toolset_version = cls._msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
+ else:
+ toolset_version = None
if user_argstr:
user_toolset = cls._user_script_argument_toolset(env, toolset_version, user_argstr)
+ else:
+ user_toolset = None
- if cls.MSVC_TOOLSET_DEFAULT_VCVARSVER:
+ if cls.MSVC_FORCE_DEFAULT_TOOLSET:
if not toolset_version and not user_toolset:
toolset_version = cls._msvc_script_default_toolset(env, msvc, vc_dir, arglist)
if 'MSVC_SPECTRE_LIBS' in env:
spectre = cls._msvc_script_argument_spectre(env, msvc, arglist)
- if spectre and user_argstr:
- cls._user_script_argument_spectre(env, spectre, user_argstr)
+ else:
+ spectre = None
+
+ if user_argstr:
+ cls._user_script_argument_spectre(env, spectre, user_argstr)
if arglist:
arglist.sort()
argstr = ' '.join([argpair[-1] for argpair in arglist]).strip()
+ else:
+ argstr = ''
debug('arguments: %s', repr(argstr))
return argstr
@@ -2247,231 +2858,3 @@ class _MSVCScriptArguments:
debug('reset')
cls._reset_toolsets()
-def msvc_find_valid_batch_script(env, version):
- """Find and execute appropriate batch script to set up build env.
-
- The MSVC build environment depends heavily on having the shell
- environment set. SCons does not inherit that, and does not count
- on that being set up correctly anyway, so it tries to find the right
- MSVC batch script, or the right arguments to the generic batch script
- vcvarsall.bat, and run that, so we have a valid environment to build in.
- There are dragons here: the batch scripts don't fail (see comments
- elsewhere), they just leave you with a bad setup, so try hard to
- get it right.
- """
-
- # Find the host, target, and all candidate (host, target) platform combinations:
- platforms = get_host_target(env, version)
- debug("host_platform %s, target_platform %s host_target_list %s", *platforms)
- host_platform, target_platform, host_target_list = platforms
-
- d = None
- version_installed = False
- for host_arch, target_arch, in host_target_list:
- # Set to current arch.
- env['TARGET_ARCH'] = target_arch
- arg = ''
-
- # Try to locate a batch file for this host/target platform combo
- try:
- (vc_script, arg, vc_dir, sdk_script) = find_batch_file(env, version, host_arch, target_arch)
- debug('vc_script:%s vc_script_arg:%s sdk_script:%s', vc_script, arg, sdk_script)
- version_installed = True
- except VisualCException as e:
- msg = str(e)
- debug('Caught exception while looking for batch file (%s)', msg)
- version_installed = False
- continue
-
- # Try to use the located batch file for this host/target platform combo
- debug('use_script 2 %s, args:%s', repr(vc_script), arg)
- found = None
- if vc_script:
- arg = _MSVCScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
- try:
- d = script_env(vc_script, args=arg)
- found = vc_script
- except BatchFileExecutionError as e:
- debug('use_script 3: failed running VC script %s: %s: Error:%s', repr(vc_script), arg, e)
- vc_script=None
- continue
- if not vc_script and sdk_script:
- debug('use_script 4: trying sdk script: %s', sdk_script)
- try:
- d = script_env(sdk_script)
- found = sdk_script
- except BatchFileExecutionError as e:
- debug('use_script 5: failed running SDK script %s: Error:%s', repr(sdk_script), e)
- continue
- elif not vc_script and not sdk_script:
- debug('use_script 6: Neither VC script nor SDK script found')
- continue
-
- debug("Found a working script/target: %s/%s", repr(found), arg)
- break # We've found a working target_platform, so stop looking
-
- # If we cannot find a viable installed compiler, reset the TARGET_ARCH
- # To it's initial value
- if not d:
- env['TARGET_ARCH'] = target_platform
-
- if version_installed:
- msg = "MSVC version '{}' working host/target script was not found.\n" \
- " Host = '{}', Target = '{}'\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(
- version, host_platform, target_platform
- )
- else:
- installed_vcs = get_installed_vcs(env)
- if installed_vcs:
- msg = "MSVC version '{}' was not found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly.\n" \
- " Installed versions are: {}".format(version, installed_vcs)
- else:
- msg = "MSVC version '{}' was not found.\n" \
- " No versions of the MSVC compiler were found.\n" \
- " Visual Studio C/C++ compilers may not be set correctly".format(version)
-
- _msvc_notfound_policy_handler(env, msg)
-
- return d
-
-_undefined = None
-
-def get_use_script_use_settings(env):
- global _undefined
-
- if _undefined is None:
- _undefined = object()
-
- # use_script use_settings return values action
- # value ignored (value, None) use script or bypass detection
- # undefined value not None (False, value) use dictionary
- # undefined undefined/None (True, None) msvc detection
-
- # None (documentation) or evaluates False (code): bypass detection
- # need to distinguish between undefined and None
- use_script = env.get('MSVC_USE_SCRIPT', _undefined)
-
- if use_script != _undefined:
- # use_script defined, use_settings ignored (not type checked)
- return (use_script, None)
-
- # undefined or None: use_settings ignored
- use_settings = env.get('MSVC_USE_SETTINGS', None)
-
- if use_settings is not None:
- # use script undefined, use_settings defined and not None (type checked)
- return (False, use_settings)
-
- # use script undefined, use_settings undefined or None
- return (True, None)
-
-def msvc_setup_env(env):
- debug('called')
- version = get_default_version(env)
- if version is None:
- if not msvc_setup_env_user(env):
- _MSVCSetupEnvDefault.set_nodefault()
- return None
-
- # XXX: we set-up both MSVS version for backward
- # compatibility with the msvs tool
- env['MSVC_VERSION'] = version
- env['MSVS_VERSION'] = version
- env['MSVS'] = {}
-
- use_script, use_settings = get_use_script_use_settings(env)
- if SCons.Util.is_String(use_script):
- use_script = use_script.strip()
- if not os.path.exists(use_script):
- raise MSVCScriptNotFound('Script specified by MSVC_USE_SCRIPT not found: "{}"'.format(use_script))
- args = env.subst('$MSVC_USE_SCRIPT_ARGS')
- debug('use_script 1 %s %s', repr(use_script), repr(args))
- d = script_env(use_script, args)
- elif use_script:
- d = msvc_find_valid_batch_script(env,version)
- debug('use_script 2 %s', d)
- if not d:
- return d
- elif use_settings is not None:
- if not SCons.Util.is_Dict(use_settings):
- error_msg = 'MSVC_USE_SETTINGS type error: expected a dictionary, found {}'.format(type(use_settings).__name__)
- raise MSVCUseSettingsError(error_msg)
- d = use_settings
- debug('use_settings %s', d)
- else:
- debug('MSVC_USE_SCRIPT set to False')
- warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
- "set correctly."
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
- return None
-
- for k, v in d.items():
- env.PrependENVPath(k, v, delete_existing=True)
- debug("env['ENV']['%s'] = %s", k, env['ENV'][k])
-
- # final check to issue a warning if the compiler is not present
- if not find_program_path(env, 'cl'):
- debug("did not find %s", _CL_EXE_NAME)
- if CONFIG_CACHE:
- propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE)
- else:
- propose = "It may need to be installed separately with Visual Studio."
- warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose)
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
-
-def msvc_exists(env=None, version=None):
- debug('version=%s', repr(version))
- vcs = get_installed_vcs(env)
- if version is None:
- rval = len(vcs) > 0
- else:
- rval = version in vcs
- debug('version=%s, return=%s', repr(version), rval)
- return rval
-
-def msvc_setup_env_user(env=None):
- rval = False
- if env:
-
- # Intent is to use msvc tools:
- # MSVC_VERSION or MSVS_VERSION: defined and is True
- # MSVC_USE_SCRIPT: defined and (is string or is False)
- # MSVC_USE_SETTINGS: defined and is not None
-
- # defined and is True
- for key in ['MSVC_VERSION', 'MSVS_VERSION']:
- if key in env and env[key]:
- rval = True
- debug('key=%s, return=%s', repr(key), rval)
- return rval
-
- # defined and (is string or is False)
- for key in ['MSVC_USE_SCRIPT']:
- if key in env and (SCons.Util.is_String(env[key]) or not env[key]):
- rval = True
- debug('key=%s, return=%s', repr(key), rval)
- return rval
-
- # defined and is not None
- for key in ['MSVC_USE_SETTINGS']:
- if key in env and env[key] is not None:
- rval = True
- debug('key=%s, return=%s', repr(key), rval)
- return rval
-
- debug('return=%s', rval)
- return rval
-
-def msvc_setup_env_tool(env=None, version=None, tool=None):
- debug('tool=%s, version=%s', repr(tool), repr(version))
- _MSVCSetupEnvDefault.register_tool(env, tool)
- rval = False
- if not rval and msvc_exists(env, version):
- rval = True
- if not rval and msvc_setup_env_user(env):
- rval = True
- debug('tool=%s, version=%s, return=%s', repr(tool), repr(version), rval)
- return rval
-
--
cgit v0.12
From 33bef70b9ccaac0106d5e7f0c37211d224b6a585 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 16 Jun 2022 12:43:22 -0400
Subject: Rename msvc batch platform (uwp/store/desktop) to platform_type.
---
SCons/Tool/MSCommon/vc.py | 50 +++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 26 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index c44c698..acffc7c 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -106,7 +106,7 @@ class _Const:
for bool, symbol_list in [
(False, (0, '0', False, 'False', 'FALSE', 'false', 'No', 'NO', 'no', None, '')),
- (True, (1, '1', True, 'True', 'TRUE', 'true', 'Yes', 'YES', 'yes', )),
+ (True, (1, '1', True, 'True', 'TRUE', 'true', 'Yes', 'YES', 'yes')),
]:
BOOLEAN_KEYS[bool] = symbol_list
for symbol in symbol_list:
@@ -2007,7 +2007,7 @@ class _WindowsSDK:
if not os.path.exists(sdk_inc_path):
continue
- for platform, sdk_inc_file in [
+ for platform_type, sdk_inc_file in [
('desktop', 'winsdkver.h'),
('uwp', 'windows.h'),
]:
@@ -2015,12 +2015,12 @@ class _WindowsSDK:
if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
continue
- key = (version_nbr, platform)
+ key = (version_nbr, platform_type)
if key in sdk_version_platform_seen:
continue
sdk_version_platform_seen.add(key)
- sdk_map[platform].append(version_nbr)
+ sdk_map[platform_type].append(version_nbr)
for key, val in sdk_map.items():
val.sort(reverse=True)
@@ -2039,8 +2039,6 @@ class _WindowsSDK:
sdk_version_platform_seen = set()
sdk_roots_seen = set()
- sdk_targets = []
-
for sdk_t in sdk_roots:
sdk_root = sdk_t[0]
@@ -2054,7 +2052,7 @@ class _WindowsSDK:
if not os.path.exists(sdk_inc_path):
continue
- for platform, sdk_inc_file in [
+ for platform_type, sdk_inc_file in [
('desktop', 'winsdkver.h'),
('uwp', 'windows.h'),
]:
@@ -2062,12 +2060,12 @@ class _WindowsSDK:
if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
continue
- key = (version_nbr, platform)
+ key = (version_nbr, platform_type)
if key in sdk_version_platform_seen:
continue
sdk_version_platform_seen.add(key)
- sdk_map[platform].append(version_nbr)
+ sdk_map[platform_type].append(version_nbr)
for key, val in sdk_map.items():
val.sort(reverse=True)
@@ -2134,9 +2132,9 @@ class _WindowsSDK:
return sdk_map
@classmethod
- def _get_sdk_version_list(cls, version_list, platform):
+ def _get_sdk_version_list(cls, version_list, platform_type):
sdk_map = cls._sdk_map(version_list)
- sdk_list = sdk_map.get(platform, [])
+ sdk_list = sdk_map.get(platform_type, [])
return sdk_list
def get_sdk_versions(MSVC_VERSION=None, MSVC_UWP_APP=False):
@@ -2155,8 +2153,8 @@ def get_sdk_versions(MSVC_VERSION=None, MSVC_UWP_APP=False):
return sdk_versions
is_uwp = True if MSVC_UWP_APP in _Const.BOOLEAN_KEYS[True] else False
- platform = 'uwp' if is_uwp else 'desktop'
- sdk_list = _WindowsSDK._get_sdk_version_list(vs_def.vc_sdk_versions, platform)
+ platform_type = 'uwp' if is_uwp else 'desktop'
+ sdk_list = _WindowsSDK._get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
sdk_versions.extend(sdk_list)
return sdk_versions
@@ -2326,12 +2324,12 @@ class _ScriptArguments:
return err_msg
@classmethod
- def _msvc_script_argument_sdk(cls, env, msvc, platform, arglist):
+ def _msvc_script_argument_sdk(cls, env, msvc, platform_type, arglist):
sdk_version = env['MSVC_SDK_VERSION']
debug(
- 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform=%s',
- repr(msvc.version), repr(sdk_version), repr(platform)
+ 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_version), repr(platform_type)
)
if not sdk_version:
@@ -2341,11 +2339,11 @@ class _ScriptArguments:
if err_msg:
raise MSVCArgumentError(err_msg)
- sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform)
+ sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
if sdk_version not in sdk_list:
- err_msg = "MSVC_SDK_VERSION {} not found for platform {}".format(
- repr(sdk_version), repr(platform)
+ err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
+ repr(sdk_version), repr(platform_type)
)
raise MSVCArgumentError(err_msg)
@@ -2356,20 +2354,20 @@ class _ScriptArguments:
return sdk_version
@classmethod
- def _msvc_script_default_sdk(cls, env, msvc, platform, arglist):
+ def _msvc_script_default_sdk(cls, env, msvc, platform_type, arglist):
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
return None
- sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform)
+ sdk_list = _WindowsSDK._get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
if not len(sdk_list):
return None
sdk_default = sdk_list[0]
debug(
- 'MSVC_VERSION=%s, sdk_default=%s, platform=%s',
- repr(msvc.version), repr(sdk_default), repr(platform)
+ 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_default), repr(platform_type)
)
argpair = (cls.SortOrder.SDK, sdk_default)
@@ -2806,10 +2804,10 @@ class _ScriptArguments:
if user_argstr:
cls._user_script_argument_uwp(env, uwp, user_argstr)
- platform = 'uwp' if uwp else 'desktop'
+ platform_type = 'uwp' if uwp else 'desktop'
if 'MSVC_SDK_VERSION' in env:
- sdk_version = cls._msvc_script_argument_sdk(env, msvc, platform, arglist)
+ sdk_version = cls._msvc_script_argument_sdk(env, msvc, platform_type, arglist)
else:
sdk_version = None
@@ -2820,7 +2818,7 @@ class _ScriptArguments:
if cls.MSVC_FORCE_DEFAULT_SDK:
if not sdk_version and not user_sdk:
- sdk_version = cls._msvc_script_default_sdk(env, msvc, platform, arglist)
+ sdk_version = cls._msvc_script_default_sdk(env, msvc, platform_type, arglist)
if 'MSVC_TOOLSET_VERSION' in env:
toolset_version = cls._msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
--
cgit v0.12
From 716f93a5207d8e7c941f3ff38ef2b3b0c923c479 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 16 Jun 2022 13:04:52 -0400
Subject: Update comments
---
SCons/Tool/MSCommon/vc.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index acffc7c..e29fba4 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -2269,7 +2269,7 @@ class _ScriptArguments:
# VS2017+ rewrites uwp => store for 14.0 toolset
uwp_arg = msvc.vs_def.vc_uwp
- # uwp may not be installed
+ # store/uwp may not be fully installed
argpair = (cls.SortOrder.UWP, uwp_arg)
arglist.append(argpair)
@@ -2347,7 +2347,6 @@ class _ScriptArguments:
)
raise MSVCArgumentError(err_msg)
- # sdk folder may not exist
argpair = (cls.SortOrder.SDK, sdk_version)
arglist.append(argpair)
--
cgit v0.12
From e2033e5f52002d404383c97e3a6a010efef174c8 Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Thu, 9 Jun 2022 11:30:47 -0600
Subject: Fortran vairants now include FORTRANCOMMONFLAGS
The documentation suggested $FORTRANFLAGS was included in the build
lines for all variants, but it was not. Turns out the test suite
quite explicitly checks that FORTRANFLAGS doesn't leak through to other
variants, so instead define a new FORTRANCOMMONFLAGS to serve the purpose
of a flag that applies to all variants.
Assorted cleanup. And f-strings.
Fixes #2257
Signed-off-by: Mats Wichmann
---
CHANGES.txt | 6 ++
RELEASE.txt | 2 +
SCons/Tool/FortranCommon.py | 178 ++++++++++++++++----------------
SCons/Tool/f03.xml | 5 +-
SCons/Tool/f08.xml | 5 +-
SCons/Tool/f77.xml | 7 +-
SCons/Tool/f90.xml | 5 +-
SCons/Tool/f95.xml | 5 +-
SCons/Tool/fortran.xml | 13 ++-
SCons/Tool/g77.py | 2 -
SCons/Tool/g77.xml | 5 +-
SCons/Tool/gfortran.py | 18 ++--
SCons/Tool/gfortran.xml | 19 +---
SCons/Tool/ifl.py | 21 ++--
SCons/Tool/ifort.py | 13 +--
test/Fortran/F77PATH.py | 78 ++++++--------
test/Fortran/F90PATH.py | 66 +++++-------
test/Fortran/FORTRANCOMMONFLAGS.py | 132 +++++++++++++++++++++++
test/Fortran/FORTRANFILESUFFIXES2.py | 43 ++++----
test/Fortran/FORTRANPATH.py | 54 +++++-----
test/Fortran/fixture/myfortran.py | 17 +--
test/Fortran/fixture/myfortran_flags.py | 17 +--
22 files changed, 406 insertions(+), 305 deletions(-)
create mode 100644 test/Fortran/FORTRANCOMMONFLAGS.py
diff --git a/CHANGES.txt b/CHANGES.txt
index 28785e1..d221603 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -194,6 +194,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
to add a path to the execution environment if it was discovered in
default_paths. Previously, the routine, called by many tool modules,
never altered the execution environment, leaving it to the tools.
+ - A new construction variable FORTRANCOMMONFLAGS is added which is
+ applied to all Fortran dialects, in case someone needs to set some
+ flags globally. FORTRANFLAGS looked like it was intended for that,
+ but was not applied to other dialects, and e2e tests explicitly checked
+ that FORTRANFLAGS did not propagate outside the FORTRAN dialect,
+ so the conclusion is that behavior is intentional (issue #2257)
From Zhichang Yu:
- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT.
diff --git a/RELEASE.txt b/RELEASE.txt
index abecf39..4f42e8c 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -43,6 +43,8 @@ NEW FUNCTIONALITY
is taken and the constructed environment is likely incomplete. As implemented, the default
global policy is "warning". The ability to set the global policy via an SCons command-line
option may be added in a future enhancement.
+- Fortran: a new construction variable FORTRANCOMMONFLAGS is added which is
+ applied to all Fortran dialects, to enable global (all-dialect) settings.
DEPRECATED FUNCTIONALITY
diff --git a/SCons/Tool/FortranCommon.py b/SCons/Tool/FortranCommon.py
index cad16b6..f889383 100644
--- a/SCons/Tool/FortranCommon.py
+++ b/SCons/Tool/FortranCommon.py
@@ -21,43 +21,48 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""
-
-Stuff for processing Fortran, common to all fortran dialects.
-
-"""
+"""Routines for setting up Fortran, common to all dialects."""
import re
import os.path
+from typing import Tuple
-import SCons.Action
import SCons.Scanner.Fortran
import SCons.Tool
import SCons.Util
+from SCons.Action import Action
+
+def isfortran(env, source) -> bool:
+ """Returns True if source has any fortran files in it.
-def isfortran(env, source):
- """Return 1 if any of code in source has fortran files in it, 0
- otherwise."""
+ Only checks based on filename suffixes, does not examine code.
+ """
try:
fsuffixes = env['FORTRANSUFFIXES']
except KeyError:
# If no FORTRANSUFFIXES, no fortran tool, so there is no need to look
# for fortran sources.
- return 0
+ return False
if not source:
# Source might be None for unusual cases like SConf.
- return 0
+ return False
for s in source:
if s.sources:
ext = os.path.splitext(str(s.sources[0]))[1]
if ext in fsuffixes:
- return 1
- return 0
+ return True
+ return False
-def _fortranEmitter(target, source, env):
+def _fortranEmitter(target, source, env) -> Tuple:
+ """Common code for Fortran emitter.
+
+ Called by both the static and shared object emitters,
+ mainly to account for generated module files.
+ """
+
node = source[0].rfile()
if not node.exists() and not node.is_derived():
print("Could not locate " + str(node.name))
@@ -78,21 +83,29 @@ def _fortranEmitter(target, source, env):
return (target, source)
-def FortranEmitter(target, source, env):
+def FortranEmitter(target, source, env) -> Tuple:
import SCons.Defaults
target, source = _fortranEmitter(target, source, env)
return SCons.Defaults.StaticObjectEmitter(target, source, env)
-def ShFortranEmitter(target, source, env):
+def ShFortranEmitter(target, source, env) -> Tuple:
import SCons.Defaults
target, source = _fortranEmitter(target, source, env)
return SCons.Defaults.SharedObjectEmitter(target, source, env)
-def ComputeFortranSuffixes(suffixes, ppsuffixes):
- """suffixes are fortran source files, and ppsuffixes the ones to be
- pre-processed. Both should be sequences, not strings."""
+def ComputeFortranSuffixes(suffixes, ppsuffixes) -> None:
+ """Update the suffix lists to reflect the platform requirements.
+
+ If upper-cased suffixes can be distinguished from lower, those are
+ added to *ppsuffixes*. If not, they are added to *suffixes*.
+
+ Args:
+ suffixes (list): indicate regular Fortran source files
+ ppsuffixes (list): indicate Fortran source files that should be
+ be run through the pre-processor
+ """
assert len(suffixes) > 0
s = suffixes[0]
sup = s.upper()
@@ -102,31 +115,34 @@ def ComputeFortranSuffixes(suffixes, ppsuffixes):
else:
suffixes.extend(upper_suffixes)
-
-def CreateDialectActions(dialect):
+def CreateDialectActions(dialect) -> Tuple[Action, Action, Action, Action]:
"""Create dialect specific actions."""
- CompAction = SCons.Action.Action('$%sCOM ' % dialect, '$%sCOMSTR' % dialect)
- CompPPAction = SCons.Action.Action('$%sPPCOM ' % dialect, '$%sPPCOMSTR' % dialect)
- ShCompAction = SCons.Action.Action('$SH%sCOM ' % dialect, '$SH%sCOMSTR' % dialect)
- ShCompPPAction = SCons.Action.Action('$SH%sPPCOM ' % dialect, '$SH%sPPCOMSTR' % dialect)
-
+ CompAction = Action(f'${dialect}COM ', cmdstr=f'${dialect}COMSTR')
+ CompPPAction = Action(f'${dialect}PPCOM ', cmdstr=f'${dialect}PPCOMSTR')
+ ShCompAction = Action(f'$SH{dialect}COM ', cmdstr=f'$SH{dialect}COMSTR')
+ ShCompPPAction = Action(f'$SH{dialect}PPCOM ', cmdstr=f'$SH{dialect}PPCOMSTR')
return CompAction, CompPPAction, ShCompAction, ShCompPPAction
-def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_module=False):
- """Add dialect specific construction variables."""
- ComputeFortranSuffixes(suffixes, ppsuffixes)
+def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_mods=False) -> None:
+ """Add dialect specific construction variables.
- fscan = SCons.Scanner.Fortran.FortranScan("%sPATH" % dialect)
+ Args:
+ dialect (str): dialect name
+ suffixes (list): suffixes associated with this dialect
+ ppsuffixes (list): suffixes using cpp associated with this dialect
+ support_mods (bool): whether this dialect supports modules
+ """
+ ComputeFortranSuffixes(suffixes, ppsuffixes)
+ fscan = SCons.Scanner.Fortran.FortranScan(f"{dialect}PATH")
for suffix in suffixes + ppsuffixes:
SCons.Tool.SourceFileScanner.add_scanner(suffix, fscan)
- env.AppendUnique(FORTRANSUFFIXES = suffixes + ppsuffixes)
+ env.AppendUnique(FORTRANSUFFIXES=suffixes + ppsuffixes)
compaction, compppaction, shcompaction, shcompppaction = \
CreateDialectActions(dialect)
-
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
for suffix in suffixes:
@@ -141,64 +157,60 @@ def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_module=False):
static_obj.add_emitter(suffix, FortranEmitter)
shared_obj.add_emitter(suffix, ShFortranEmitter)
- if '%sFLAGS' % dialect not in env:
- env['%sFLAGS' % dialect] = SCons.Util.CLVar('')
-
- if 'SH%sFLAGS' % dialect not in env:
- env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect)
+ if f'{dialect}FLAGS' not in env:
+ env[f'{dialect}FLAGS'] = SCons.Util.CLVar('')
+ if f'SH{dialect}FLAGS' not in env:
+ env[f'SH{dialect}FLAGS'] = SCons.Util.CLVar(f'${dialect}FLAGS')
# If a tool does not define fortran prefix/suffix for include path, use C ones
- if 'INC%sPREFIX' % dialect not in env:
- env['INC%sPREFIX' % dialect] = '$INCPREFIX'
-
- if 'INC%sSUFFIX' % dialect not in env:
- env['INC%sSUFFIX' % dialect] = '$INCSUFFIX'
-
- env['_%sINCFLAGS' % dialect] = '${_concat(INC%sPREFIX, %sPATH, INC%sSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}' % (dialect, dialect, dialect)
-
- if support_module:
- env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
- env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
- env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
- env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
+ if f'INC{dialect}PREFIX' not in env:
+ env[f'INC{dialect}PREFIX'] = '$INCPREFIX'
+ if f'INC{dialect}SUFFIX' not in env:
+ env[f'INC{dialect}SUFFIX'] = '$INCSUFFIX'
+
+ env[f'_{dialect}INCFLAGS'] = f'${{_concat(INC{dialect}PREFIX, {dialect}PATH, INC{dialect}SUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}}'
+
+ if support_mods:
+ env[f'{dialect}COM'] = f'${dialect} -o $TARGET -c $FORTRANCOMMONFLAGS ${dialect}FLAGS $_{dialect}INCFLAGS $_FORTRANMODFLAG $SOURCES #XXX{dialect}'
+ env[f'{dialect}PPCOM'] = f'${dialect} -o $TARGET -c $FORTRANCOMMONFLAGS ${dialect}FLAGS $CPPFLAGS $_CPPDEFFLAGS $_{dialect}INCFLAGS $_FORTRANMODFLAG $SOURCES #XXXPP{dialect}'
+ env[f'SH{dialect}COM'] = f'$SH{dialect} -o $TARGET -c $FORTRANCOMMONFLAGS $SH{dialect}FLAGS $_{dialect}INCFLAGS $_FORTRANMODFLAG $SOURCES #XXX{dialect}'
+ env[f'SH{dialect}PPCOM'] = f'$SH{dialect} -o $TARGET -c $FORTRANCOMMONFLAGS $SH{dialect}FLAGS $CPPFLAGS $_CPPDEFFLAGS $_{dialect}INCFLAGS $_FORTRANMODFLAG $SOURCES #XXXPP{dialect}'
else:
- env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
- env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
- env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
- env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
+ env[f'{dialect}COM'] = f'${dialect} -o $TARGET -c $FORTRANCOMMONFLAGS ${dialect}FLAGS $_{dialect}INCFLAGS $SOURCES #XXX{dialect}'
+ env[f'{dialect}PPCOM'] = f'${dialect} -o $TARGET -c $FORTRANCOMMONFLAGS ${dialect}FLAGS $CPPFLAGS $_CPPDEFFLAGS $_{dialect}INCFLAGS $SOURCES #XXXPP{dialect}'
+ env[f'SH{dialect}COM'] = f'$SH{dialect} -o $TARGET -c $FORTRANCOMMONFLAGS $SH{dialect}FLAGS $_{dialect}INCFLAGS $SOURCES #XXX{dialect}'
+ env[f'SH{dialect}PPCOM'] = f'$SH{dialect} -o $TARGET -c $FORTRANCOMMONFLAGS $SH{dialect}FLAGS $CPPFLAGS $_CPPDEFFLAGS $_{dialect}INCFLAGS $SOURCES #XXXPP{dialect}'
+
-def add_fortran_to_env(env):
- """Add Builders and construction variables for Fortran to an Environment."""
+def add_fortran_to_env(env) -> None:
+ """Add Builders and construction variables for Fortran/generic."""
try:
FortranSuffixes = env['FORTRANFILESUFFIXES']
except KeyError:
FortranSuffixes = ['.f', '.for', '.ftn']
- #print("Adding %s to fortran suffixes" % FortranSuffixes)
try:
FortranPPSuffixes = env['FORTRANPPFILESUFFIXES']
except KeyError:
FortranPPSuffixes = ['.fpp', '.FPP']
- DialectAddToEnv(env, "FORTRAN", FortranSuffixes,
- FortranPPSuffixes, support_module=True)
+ DialectAddToEnv(env, "FORTRAN", FortranSuffixes, FortranPPSuffixes, support_mods=True)
+ # Module support
env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX
env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX
-
env['FORTRANMODDIR'] = '' # where the compiler should place .mod files
env['FORTRANMODDIRPREFIX'] = '' # some prefix to $FORTRANMODDIR - similar to $INCPREFIX
env['FORTRANMODDIRSUFFIX'] = '' # some suffix to $FORTRANMODDIR - similar to $INCSUFFIX
env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
-def add_f77_to_env(env):
- """Add Builders and construction variables for f77 to an Environment."""
+def add_f77_to_env(env) -> None:
+ """Add Builders and construction variables for f77 dialect."""
try:
F77Suffixes = env['F77FILESUFFIXES']
except KeyError:
F77Suffixes = ['.f77']
- #print("Adding %s to f77 suffixes" % F77Suffixes)
try:
F77PPSuffixes = env['F77PPFILESUFFIXES']
except KeyError:
@@ -206,59 +218,50 @@ def add_f77_to_env(env):
DialectAddToEnv(env, "F77", F77Suffixes, F77PPSuffixes)
-def add_f90_to_env(env):
- """Add Builders and construction variables for f90 to an Environment."""
+def add_f90_to_env(env) -> None:
+ """Add Builders and construction variables for f90 dialect."""
try:
F90Suffixes = env['F90FILESUFFIXES']
except KeyError:
F90Suffixes = ['.f90']
- #print("Adding %s to f90 suffixes" % F90Suffixes)
try:
F90PPSuffixes = env['F90PPFILESUFFIXES']
except KeyError:
F90PPSuffixes = []
- DialectAddToEnv(env, "F90", F90Suffixes, F90PPSuffixes,
- support_module=True)
-
+ DialectAddToEnv(env, "F90", F90Suffixes, F90PPSuffixes, support_mods=True)
-def add_f95_to_env(env):
- """Add Builders and construction variables for f95 to an Environment."""
+def add_f95_to_env(env) -> None:
+ """Add Builders and construction variables for f95 dialect."""
try:
F95Suffixes = env['F95FILESUFFIXES']
except KeyError:
F95Suffixes = ['.f95']
- #print("Adding %s to f95 suffixes" % F95Suffixes)
try:
F95PPSuffixes = env['F95PPFILESUFFIXES']
except KeyError:
F95PPSuffixes = []
- DialectAddToEnv(env, "F95", F95Suffixes, F95PPSuffixes,
- support_module=True)
-
+ DialectAddToEnv(env, "F95", F95Suffixes, F95PPSuffixes, support_mods=True)
-def add_f03_to_env(env):
- """Add Builders and construction variables for f03 to an Environment."""
+def add_f03_to_env(env) -> None:
+ """Add Builders and construction variables for f03 dialect."""
try:
F03Suffixes = env['F03FILESUFFIXES']
except KeyError:
F03Suffixes = ['.f03']
- #print("Adding %s to f95 suffixes" % F95Suffixes)
try:
F03PPSuffixes = env['F03PPFILESUFFIXES']
except KeyError:
F03PPSuffixes = []
- DialectAddToEnv(env, "F03", F03Suffixes, F03PPSuffixes,
- support_module=True)
+ DialectAddToEnv(env, "F03", F03Suffixes, F03PPSuffixes, support_mods=True)
-
-def add_f08_to_env(env):
- """Add Builders and construction variables for f08 to an Environment."""
+def add_f08_to_env(env) -> None:
+ """Add Builders and construction variables for f08 dialect."""
try:
F08Suffixes = env['F08FILESUFFIXES']
except KeyError:
@@ -269,13 +272,10 @@ def add_f08_to_env(env):
except KeyError:
F08PPSuffixes = []
- DialectAddToEnv(env, "F08", F08Suffixes, F08PPSuffixes,
- support_module=True)
-
+ DialectAddToEnv(env, "F08", F08Suffixes, F08PPSuffixes, support_mods=True)
-def add_all_to_env(env):
- """Add builders and construction variables for all supported fortran
- dialects."""
+def add_all_to_env(env) -> None:
+ """Add builders and construction variables for all supported dialects."""
add_fortran_to_env(env)
add_f77_to_env(env)
add_f90_to_env(env)
diff --git a/SCons/Tool/f03.xml b/SCons/Tool/f03.xml
index fc14ace..c989385 100644
--- a/SCons/Tool/f03.xml
+++ b/SCons/Tool/f03.xml
@@ -1,6 +1,6 @@
@@ -5585,38 +5605,37 @@ and the list of sources for this builder.
def e(target, source, env):
- return (target + ['foo.foo'], source + ['foo.src'])
+ return target + ['foo.foo'], source + ['foo.src']
# Simple association of an emitter function with a Builder.
-b = Builder("my_build < $TARGET > $SOURCE",
- emitter = e)
+b = Builder("my_build < $TARGET > $SOURCE", emitter=e)
def e2(target, source, env):
- return (target + ['bar.foo'], source + ['bar.src'])
+ return target + ['bar.foo'], source + ['bar.src']
# Simple association of a list of emitter functions with a Builder.
-b = Builder("my_build < $TARGET > $SOURCE",
- emitter = [e, e2])
+b = Builder("my_build < $TARGET > $SOURCE", emitter=[e, e2])
-# Calling an emitter function through a &consvar;.
+# Calling an emitter function through a construction variable.
env = Environment(MY_EMITTER=e)
-b = Builder("my_build < $TARGET > $SOURCE",
- emitter='$MY_EMITTER')
+b = Builder("my_build < $TARGET > $SOURCE", emitter='$MY_EMITTER')
-# Calling a list of emitter functions through a &consvar;.
+# Calling a list of emitter functions through a construction variable.
env = Environment(EMITTER_LIST=[e, e2])
-b = Builder("my_build < $TARGET > $SOURCE",
- emitter='$EMITTER_LIST')
+b = Builder("my_build < $TARGET > $SOURCE", emitter='$EMITTER_LIST')
# Associating multiple emitters with different file
# suffixes using a dictionary.
def e_suf1(target, source, env):
- return (target + ['another_target_file'], source)
+ return target + ['another_target_file'], source
+
def e_suf2(target, source, env):
- return (target, source + ['another_source_file'])
-b = Builder("my_build < $TARGET > $SOURCE",
- emitter={'.suf1' : e_suf1,
- '.suf2' : e_suf2})
+ return target, source + ['another_source_file']
+
+b = Builder(
+ action="my_build < $TARGET > $SOURCE",
+ emitter={'.suf1': e_suf1, '.suf2': e_suf2}
+)
--
cgit v0.12
From 869c75679492039a5dcb1f66fd9a78d59a4340da Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Mon, 20 Jun 2022 08:58:35 -0600
Subject: A few more tweaks in Builder Methods intro [skip appveyor]
Signed-off-by: Mats Wichmann
---
doc/man/scons.xml | 50 ++++++++++++++++++++++++--------------------------
1 file changed, 24 insertions(+), 26 deletions(-)
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index 8e64290..2e7784c 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -2675,7 +2675,7 @@ and a same-named environment method
that splits a single string
into a list, using
strings of white-space characters as the delimiter
-(similar to the Python string split
+(similar to the &Python; string split
method, but succeeds even if the input isn't a string).
@@ -2697,7 +2697,7 @@ env.Program('bar', source='bar.c foo.c'.split())
Sources and targets can be specified as a a scalar or as a list,
either of strings or nodes (more on nodes below).
When specifying path strings,
-Python follows the POSIX pathname convention:
+&Python; follows the POSIX pathname convention:
if a string begins with the operating system pathname separator
(on Windows both the slash and backslash separator are accepted,
and any leading drive specifier is ignored for
@@ -2806,7 +2806,7 @@ env.Program('build/prog', ['f1.c', 'f2.c'], srcdir='src')
The optional
parse_flags
-keyword argument causes behavior similarly to the
+keyword argument causes behavior similarl to the
&f-link-env-MergeFlags; method, where the argument value is
broken into individual settings and merged into the appropriate &consvars;.
@@ -2861,15 +2861,13 @@ env.Command('sub/dir/foo.out', 'sub/dir/foo.in', "cp foo.in foo.out", chdir=True
not
automatically modify
its expansion of
-&consvars; like
-$TARGET
-and
-$SOURCE
+&consvars; like &cv-link-TARGET;
+and &cv-link-SOURCE;
when using the chdir
keyword argument--that is,
the expanded file names
will still be relative to
-the top-level directory where &SConstruct; was found,
+the top-level directory where the &SConstruct; was found,
and consequently incorrect
relative to the chdir directory.
If you use the chdir keyword argument,
@@ -2880,7 +2878,7 @@ expansions like
and
${SOURCE.file}
to use just the filename portion of the
-targets and source.
+target and source.
Keyword arguments that are not specifically
recognized are treated as &consvar;
@@ -2911,7 +2909,7 @@ env.SharedLibrary(
and &cv-link-LIBSUFFIXES;
&consvars; must be set if you want &scons; to search automatically
for dependencies on the non-standard library names;
-see the descriptions below of these variables for more information.
+see the descriptions of these variables for more information.
Although the builder methods defined by
&scons;
@@ -2930,11 +2928,11 @@ SharedLibrary('word', 'word.cpp')
has determined are appropriate for the local system.Builder methods that can be called without an explicit
-environment (indicated in the listing of builders without
-a leading env.)
-may be called from custom Python modules that you
+environment (indicated in the listing of builders below
+without a leading env.)
+may be called from custom &Python; modules that you
import into an SConscript file by adding the following
-to the Python module:
+to the &Python; module:
from SCons.Script import *
@@ -2942,17 +2940,17 @@ from SCons.Script import *
A builder may add additional targets
-(and, in fact, sources) beyond those requested,
+beyond those requested
if an attached Emitter chooses to do so
-(see and, as an example,
-&cv-link-PROGEMITTER;, for more information).
+(see for more information.
+&cv-link-PROGEMITTER; is an example).
For example, the GNU linker takes a command-line argument
,
which causes it to produce a linker map file in addition
to the executable file actually being linked.
If the &b-link-Program; builder's emitter is configured
to add this mapfile if the option is set,
-two targets will be returned when you only asked for one.
+then two targets will be returned when you only asked for one.
@@ -3000,7 +2998,7 @@ contain elements which are themselves lists, such as
bar_obj_list
returned by the &b-link-StaticObject; call.
If you need to manipulate a list of lists returned by builders
-directly in Python code,
+directly in &Python; code,
you can either build a new list by hand:
@@ -3025,19 +3023,19 @@ for obj in objects:
Since builder calls return
-a list-like object, not an actual Python list,
-it is not appropriate to use the Python add
+a list-like object, not an actual &Python; list,
+it is not appropriate to use the &Python; add
operator (+ or +=)
-to append builder results to a Python list.
+to append builder results to a &Python; list.
Because the list and the object are different types,
-Python will not update the original list in place,
+&Python; will not update the original list in place,
but will instead create a new NodeList object
containing the concatenation of the list
elements and the builder results.
-This will cause problems for any other Python variables
+This will cause problems for any other &Python; variables
in your SCons configuration
that still hold on to a reference to the original list.
-Instead, use the Python list
+Instead, use the &Python; list
extend
method to make sure the list is updated in-place.
Example:
@@ -3055,7 +3053,7 @@ object_files.extend(Object('bar.c'))
The path name for a Node's file may be used
-by passing the Node to Python's builtin
+by passing the Node to &Python;'s builtin
str
function:
--
cgit v0.12
From 94b23f77472aabaabc372b0facb26c4f384413c5 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 12:11:24 -0400
Subject: Rename _Const to _Config. Rework msvc sdk version function. Minor
cleanup.
---
SCons/Tool/MSCommon/__init__.py | 1 +
SCons/Tool/MSCommon/vc.py | 68 ++++++++++++++++++++++-------------------
2 files changed, 37 insertions(+), 32 deletions(-)
diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py
index 9d8a8ff..de78f84 100644
--- a/SCons/Tool/MSCommon/__init__.py
+++ b/SCons/Tool/MSCommon/__init__.py
@@ -40,6 +40,7 @@ from SCons.Tool.MSCommon.vc import (
msvc_find_vswhere,
set_msvc_notfound_policy,
get_msvc_notfound_policy,
+ get_msvc_sdk_versions,
)
from SCons.Tool.MSCommon.vs import (
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index e193d91..3abd606 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -132,7 +132,7 @@ class _Dispatcher:
func = getattr(classref, method)
func()
-class _Const:
+class _Config:
BOOLEAN_SYMBOLS = {}
BOOLEAN_EXTERNAL = {}
@@ -1255,6 +1255,12 @@ def reset_installed_vcs():
__INSTALLED_VCS_RUN = None
_Dispatcher.reset()
+def get_default_installed_msvc(env=None):
+ vcs = get_installed_vcs(env)
+ msvc_version = vcs[0] if vcs else None
+ debug('msvc_version=%s', repr(msvc_version))
+ return msvc_version
+
# Running these batch files isn't cheap: most of the time spent in
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
# in multiple environments, for example:
@@ -1648,13 +1654,11 @@ def get_default_version(env):
return msvs_version
if not msvc_version:
- installed_vcs = get_installed_vcs(env)
- debug('installed_vcs:%s', installed_vcs)
- if not installed_vcs:
+ msvc_version = get_default_installed_msvc(env)
+ if not msvc_version:
#SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
debug('No installed VCs')
return None
- msvc_version = installed_vcs[0]
debug('using default installed MSVC version %s', repr(msvc_version))
else:
debug('using specified MSVC version %s', repr(msvc_version))
@@ -1769,13 +1773,9 @@ def msvc_find_valid_batch_script(env, version):
return d
-_undefined = None
+_UNDEFINED = object()
def get_use_script_use_settings(env):
- global _undefined
-
- if _undefined is None:
- _undefined = object()
# use_script use_settings return values action
# value ignored (value, None) use script or bypass detection
@@ -1784,9 +1784,9 @@ def get_use_script_use_settings(env):
# None (documentation) or evaluates False (code): bypass detection
# need to distinguish between undefined and None
- use_script = env.get('MSVC_USE_SCRIPT', _undefined)
+ use_script = env.get('MSVC_USE_SCRIPT', _UNDEFINED)
- if use_script != _undefined:
+ if use_script != _UNDEFINED:
# use_script defined, use_settings ignored (not type checked)
return (use_script, None)
@@ -1908,6 +1908,21 @@ def msvc_setup_env_tool(env=None, version=None, tool=None):
debug('tool=%s, version=%s, return=%s', repr(tool), repr(version), rval)
return rval
+def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
+ debug('msvc_version=%s, msvc_uwp_app=%s', repr(msvc_version), repr(msvc_uwp_app))
+
+ rval = []
+
+ if not msvc_version:
+ msvc_version = get_default_installed_msvc()
+
+ if not msvc_version:
+ debug('no msvc versions detected')
+ return rval
+
+ rval = MSVC.WinSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
+ return rval
+
class _Util:
@staticmethod
@@ -2158,7 +2173,7 @@ class _WindowsSDK:
def _verify_sdk_dispatch_map(cls):
debug('%s verify sdk_dispatch_map', cls.__name__)
cls._init_sdk_dispatch_map()
- for sdk_version in _Const.MSVC_SDK_VERSIONS:
+ for sdk_version in _Config.MSVC_SDK_VERSIONS:
if sdk_version in cls.sdk_dispatch_map:
continue
err_msg = 'sdk version {} not in {}.sdk_dispatch_map'.format(sdk_version, cls.__name__)
@@ -2205,20 +2220,13 @@ class _WindowsSDK:
sdk_versions = []
- if not msvc_version:
- vcs = get_installed_vcs()
- if not vcs:
- debug('no msvc versions detected')
- return sdk_versions
- msvc_version = vcs[0]
-
verstr = get_msvc_version_numeric(msvc_version)
- vs_def = _Const.MSVC_VERSION_EXTERNAL.get(verstr, None)
+ vs_def = _Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
if not vs_def:
debug('vs_def is not defined')
return sdk_versions
- is_uwp = True if msvc_uwp_app in _Const.BOOLEAN_SYMBOLS[True] else False
+ is_uwp = True if msvc_uwp_app in _Config.BOOLEAN_SYMBOLS[True] else False
platform_type = 'uwp' if is_uwp else 'desktop'
sdk_list = _WindowsSDK.get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
@@ -2239,10 +2247,6 @@ class _WindowsSDK:
_Dispatcher.register(_WindowsSDK)
-def get_sdk_versions(MSVC_VERSION=None, MSVC_UWP_APP=False):
- debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(MSVC_VERSION), repr(MSVC_UWP_APP))
- return _WindowsSDK.get_msvc_sdk_version_list(msvc_version=MSVC_VERSION, msvc_uwp_app=MSVC_UWP_APP)
-
class _ScriptArguments:
# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
@@ -2257,7 +2261,7 @@ class _ScriptArguments:
@classmethod
def _verify_re_sdk_dispatch_map(cls):
debug('%s verify re_sdk_dispatch_map', cls.__name__)
- for sdk_version in _Const.MSVC_SDK_VERSIONS:
+ for sdk_version in _Config.MSVC_SDK_VERSIONS:
if sdk_version in cls.re_sdk_dispatch_map:
continue
err_msg = 'sdk version {} not in {}.re_sdk_dispatch_map'.format(sdk_version, cls.__name__)
@@ -2315,9 +2319,9 @@ class _ScriptArguments:
SPECTRE = 4 # MSVC_SPECTRE_LIBS
USER = 5 # MSVC_SCRIPT_ARGS
- VS2019 = _Const.MSVS_VERSION_INTERNAL['2019']
- VS2017 = _Const.MSVS_VERSION_INTERNAL['2017']
- VS2015 = _Const.MSVS_VERSION_INTERNAL['2015']
+ VS2019 = _Config.MSVS_VERSION_INTERNAL['2019']
+ VS2017 = _Config.MSVS_VERSION_INTERNAL['2017']
+ VS2015 = _Config.MSVS_VERSION_INTERNAL['2015']
MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
'version', # fully qualified msvc version (e.g., '14.1Exp')
@@ -2328,7 +2332,7 @@ class _ScriptArguments:
def _msvc_version(cls, version):
verstr = get_msvc_version_numeric(version)
- vs_def = _Const.MSVC_VERSION_INTERNAL[verstr]
+ vs_def = _Config.MSVC_VERSION_INTERNAL[verstr]
version_args = cls.MSVC_VERSION_ARGS_DEFINITION(
version = version,
@@ -2346,7 +2350,7 @@ class _ScriptArguments:
if not uwp_app:
return None
- if uwp_app not in _Const.BOOLEAN_SYMBOLS[True]:
+ if uwp_app not in _Config.BOOLEAN_SYMBOLS[True]:
return None
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
--
cgit v0.12
From dbd301878f8f7bb004658b25a62d57b48ee4c8a3 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 12:19:39 -0400
Subject: Fix windows SDK reference
---
SCons/Tool/MSCommon/vc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 3abd606..ab05323 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1920,7 +1920,7 @@ def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
debug('no msvc versions detected')
return rval
- rval = MSVC.WinSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
+ rval = _WindowsSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
return rval
class _Util:
--
cgit v0.12
From 010c2ad46c32827b7ed8082ec11b83404a039faa Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 16:53:31 -0400
Subject: Refactor recent portions of vc.py into MSVC module
---
SCons/Tool/MSCommon/MSVC/Config.py | 284 +++++
SCons/Tool/MSCommon/MSVC/Dispatcher.py | 62 +
SCons/Tool/MSCommon/MSVC/Exceptions.py | 39 +
SCons/Tool/MSCommon/MSVC/NotFound.py | 132 +++
SCons/Tool/MSCommon/MSVC/Registry.py | 110 ++
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 733 ++++++++++++
SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py | 235 ++++
SCons/Tool/MSCommon/MSVC/Util.py | 55 +
SCons/Tool/MSCommon/MSVC/WinSDK.py | 250 ++++
SCons/Tool/MSCommon/MSVC/__init__.py | 50 +
SCons/Tool/MSCommon/__init__.py | 7 +-
SCons/Tool/MSCommon/vc.py | 1638 +--------------------------
12 files changed, 1968 insertions(+), 1627 deletions(-)
create mode 100644 SCons/Tool/MSCommon/MSVC/Config.py
create mode 100644 SCons/Tool/MSCommon/MSVC/Dispatcher.py
create mode 100644 SCons/Tool/MSCommon/MSVC/Exceptions.py
create mode 100644 SCons/Tool/MSCommon/MSVC/NotFound.py
create mode 100644 SCons/Tool/MSCommon/MSVC/Registry.py
create mode 100644 SCons/Tool/MSCommon/MSVC/ScriptArguments.py
create mode 100644 SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
create mode 100644 SCons/Tool/MSCommon/MSVC/Util.py
create mode 100644 SCons/Tool/MSCommon/MSVC/WinSDK.py
create mode 100644 SCons/Tool/MSCommon/MSVC/__init__.py
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
new file mode 100644
index 0000000..476dcb3
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -0,0 +1,284 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Constants and initialized data structures for Microsoft Visual C/C++.
+"""
+
+from collections import (
+ namedtuple,
+)
+
+from . import Dispatcher
+
+Dispatcher.register_modulename(__name__)
+
+UNDEFINED = object()
+
+BOOLEAN_SYMBOLS = {}
+BOOLEAN_EXTERNAL = {}
+
+for bool, symbol_list, symbol_case_list in [
+ (False, (False, 0, '0', None, ''), ('False', 'No', 'F', 'N')),
+ (True, (True, 1, '1'), ('True', 'Yes', 'T', 'Y')),
+]:
+ BOOLEAN_SYMBOLS[bool] = list(symbol_list)
+ for symbol in symbol_case_list:
+ BOOLEAN_SYMBOLS[bool].extend([symbol, symbol.lower(), symbol.upper()])
+
+ for symbol in BOOLEAN_SYMBOLS[bool]:
+ BOOLEAN_EXTERNAL[symbol] = bool
+
+MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
+ 'vc_runtime',
+ 'vc_runtime_numeric',
+ 'vc_runtime_alias_list',
+ 'vc_runtime_vsdef_list',
+])
+
+MSVC_RUNTIME_DEFINITION_LIST = []
+
+MSVC_RUNTIME_INTERNAL = {}
+MSVC_RUNTIME_EXTERNAL = {}
+
+for vc_runtime, vc_runtime_numeric, vc_runtime_alias_list in [
+ ('140', 140, ['ucrt']),
+ ('120', 120, ['msvcr120']),
+ ('110', 110, ['msvcr110']),
+ ('100', 100, ['msvcr100']),
+ ('90', 90, ['msvcr90']),
+ ('80', 80, ['msvcr80']),
+ ('71', 71, ['msvcr71']),
+ ('70', 70, ['msvcr70']),
+ ('60', 60, ['msvcrt']),
+]:
+ vc_runtime_def = MSVC_RUNTIME_DEFINITION(
+ vc_runtime = vc_runtime,
+ vc_runtime_numeric = vc_runtime_numeric,
+ vc_runtime_alias_list = vc_runtime_alias_list,
+ vc_runtime_vsdef_list = [],
+ )
+
+ MSVC_RUNTIME_DEFINITION_LIST.append(vc_runtime_def)
+
+ MSVC_RUNTIME_INTERNAL[vc_runtime] = vc_runtime_def
+ MSVC_RUNTIME_EXTERNAL[vc_runtime] = vc_runtime_def
+
+ for vc_runtime_alias in vc_runtime_alias_list:
+ MSVC_RUNTIME_EXTERNAL[vc_runtime_alias] = vc_runtime_def
+
+MSVC_BUILDTOOLS_DEFINITION = namedtuple('MSVCBuildtools', [
+ 'vc_buildtools',
+ 'vc_buildtools_numeric',
+ 'vc_version',
+ 'vc_version_numeric',
+ 'cl_version',
+ 'cl_version_numeric',
+ 'vc_runtime_def',
+])
+
+MSVC_BUILDTOOLS_DEFINITION_LIST = []
+
+MSVC_BUILDTOOLS_INTERNAL = {}
+MSVC_BUILDTOOLS_EXTERNAL = {}
+
+VC_VERSION_MAP = {}
+
+for vc_buildtools, vc_version, cl_version, vc_runtime in [
+ ('v143', '14.3', '19.3', '140'),
+ ('v142', '14.2', '19.2', '140'),
+ ('v141', '14.1', '19.1', '140'),
+ ('v140', '14.0', '19.0', '140'),
+ ('v120', '12.0', '18.0', '120'),
+ ('v110', '11.0', '17.0', '110'),
+ ('v100', '10.0', '16.0', '100'),
+ ('v90', '9.0', '15.0', '90'),
+ ('v80', '8.0', '14.0', '80'),
+ ('v71', '7.1', '13.1', '71'),
+ ('v70', '7.0', '13.0', '70'),
+ ('v60', '6.0', '12.0', '60'),
+]:
+
+ vc_runtime_def = MSVC_RUNTIME_INTERNAL[vc_runtime]
+
+ vc_buildtools_def = MSVC_BUILDTOOLS_DEFINITION(
+ vc_buildtools = vc_buildtools,
+ vc_buildtools_numeric = int(vc_buildtools[1:]),
+ vc_version = vc_version,
+ vc_version_numeric = float(vc_version),
+ cl_version = cl_version,
+ cl_version_numeric = float(cl_version),
+ vc_runtime_def = vc_runtime_def,
+ )
+
+ MSVC_BUILDTOOLS_DEFINITION_LIST.append(vc_buildtools_def)
+
+ MSVC_BUILDTOOLS_INTERNAL[vc_buildtools] = vc_buildtools_def
+ MSVC_BUILDTOOLS_EXTERNAL[vc_buildtools] = vc_buildtools_def
+ MSVC_BUILDTOOLS_EXTERNAL[vc_version] = vc_buildtools_def
+
+ VC_VERSION_MAP[vc_version] = vc_buildtools_def
+
+MSVS_VERSION_INTERNAL = {}
+MSVS_VERSION_EXTERNAL = {}
+
+MSVC_VERSION_INTERNAL = {}
+MSVC_VERSION_EXTERNAL = {}
+
+MSVS_VERSION_MAJOR_MAP = {}
+
+CL_VERSION_MAP = {}
+
+MSVC_SDK_VERSIONS = set()
+
+VISUALSTUDIO_DEFINITION = namedtuple('VisualStudioDefinition', [
+ 'vs_product',
+ 'vs_product_alias_list',
+ 'vs_version',
+ 'vs_version_major',
+ 'vs_envvar',
+ 'vs_express',
+ 'vs_lookup',
+ 'vc_sdk_versions',
+ 'vc_ucrt_versions',
+ 'vc_uwp',
+ 'vc_buildtools_def',
+ 'vc_buildtools_all',
+])
+
+VISUALSTUDIO_DEFINITION_LIST = []
+
+VS_PRODUCT_ALIAS = {
+ '1998': ['6']
+}
+
+# vs_envvar: VisualStudioVersion defined in environment for MSVS 2012 and later
+# MSVS 2010 and earlier cl_version -> vs_def is a 1:1 mapping
+# SDK attached to product or buildtools?
+for vs_product, vs_version, vs_envvar, vs_express, vs_lookup, vc_sdk, vc_ucrt, vc_uwp, vc_buildtools_all in [
+ ('2022', '17.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v143', 'v142', 'v141', 'v140']),
+ ('2019', '16.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v142', 'v141', 'v140']),
+ ('2017', '15.0', True, True, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v141', 'v140']),
+ ('2015', '14.0', True, True, 'registry', ['10.0', '8.1'], ['10'], 'store', ['v140']),
+ ('2013', '12.0', True, True, 'registry', None, None, None, ['v120']),
+ ('2012', '11.0', True, True, 'registry', None, None, None, ['v110']),
+ ('2010', '10.0', False, True, 'registry', None, None, None, ['v100']),
+ ('2008', '9.0', False, True, 'registry', None, None, None, ['v90']),
+ ('2005', '8.0', False, True, 'registry', None, None, None, ['v80']),
+ ('2003', '7.1', False, False, 'registry', None, None, None, ['v71']),
+ ('2002', '7.0', False, False, 'registry', None, None, None, ['v70']),
+ ('1998', '6.0', False, False, 'registry', None, None, None, ['v60']),
+]:
+
+ vs_version_major = vs_version.split('.')[0]
+
+ vc_buildtools_def = MSVC_BUILDTOOLS_INTERNAL[vc_buildtools_all[0]]
+
+ vs_def = VISUALSTUDIO_DEFINITION(
+ vs_product = vs_product,
+ vs_product_alias_list = [],
+ vs_version = vs_version,
+ vs_version_major = vs_version_major,
+ vs_envvar = vs_envvar,
+ vs_express = vs_express,
+ vs_lookup = vs_lookup,
+ vc_sdk_versions = vc_sdk,
+ vc_ucrt_versions = vc_ucrt,
+ vc_uwp = vc_uwp,
+ vc_buildtools_def = vc_buildtools_def,
+ vc_buildtools_all = vc_buildtools_all,
+ )
+
+ VISUALSTUDIO_DEFINITION_LIST.append(vs_def)
+
+ vc_buildtools_def.vc_runtime_def.vc_runtime_vsdef_list.append(vs_def)
+
+ MSVS_VERSION_INTERNAL[vs_product] = vs_def
+ MSVS_VERSION_EXTERNAL[vs_product] = vs_def
+ MSVS_VERSION_EXTERNAL[vs_version] = vs_def
+
+ MSVC_VERSION_INTERNAL[vc_buildtools_def.vc_version] = vs_def
+ MSVC_VERSION_EXTERNAL[vs_product] = vs_def
+ MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_version] = vs_def
+ MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_buildtools] = vs_def
+
+ if vs_product in VS_PRODUCT_ALIAS:
+ for vs_product_alias in VS_PRODUCT_ALIAS[vs_product]:
+ vs_def.vs_product_alias_list.append(vs_product_alias)
+ MSVS_VERSION_EXTERNAL[vs_product_alias] = vs_def
+ MSVC_VERSION_EXTERNAL[vs_product_alias] = vs_def
+
+ MSVS_VERSION_MAJOR_MAP[vs_version_major] = vs_def
+
+ CL_VERSION_MAP[vc_buildtools_def.cl_version] = vs_def
+
+ if not vc_sdk:
+ continue
+
+ MSVC_SDK_VERSIONS.update(vc_sdk)
+
+# convert string version set to string version list ranked in descending order
+MSVC_SDK_VERSIONS = [str(f) for f in sorted([float(s) for s in MSVC_SDK_VERSIONS], reverse=True)]
+
+MSVS_VERSION_LEGACY = {}
+MSVC_VERSION_LEGACY = {}
+
+for vdict in (MSVS_VERSION_EXTERNAL, MSVC_VERSION_INTERNAL):
+ for key, vs_def in vdict.items():
+ if key not in MSVS_VERSION_LEGACY:
+ MSVS_VERSION_LEGACY[key] = vs_def
+ MSVC_VERSION_LEGACY[key] = vs_def
+
+# MSVC_NOTFOUND_POLICY definition:
+# error: raise exception
+# warning: issue warning and continue
+# ignore: continue
+
+MSVC_NOTFOUND_POLICY_DEFINITION = namedtuple('MSVCNotFoundPolicyDefinition', [
+ 'value',
+ 'symbol',
+])
+
+MSVC_NOTFOUND_DEFINITION_LIST = []
+
+MSVC_NOTFOUND_POLICY_INTERNAL = {}
+MSVC_NOTFOUND_POLICY_EXTERNAL = {}
+
+for policy_value, policy_symbol_list in [
+ (True, ['Error', 'Exception']),
+ (False, ['Warning', 'Warn']),
+ (None, ['Ignore', 'Suppress']),
+]:
+
+ policy_symbol = policy_symbol_list[0].lower()
+ policy_def = MSVC_NOTFOUND_POLICY_DEFINITION(policy_value, policy_symbol)
+
+ MSVC_NOTFOUND_DEFINITION_LIST.append(vs_def)
+
+ MSVC_NOTFOUND_POLICY_INTERNAL[policy_symbol] = policy_def
+
+ for policy_symbol in policy_symbol_list:
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
+
diff --git a/SCons/Tool/MSCommon/MSVC/Dispatcher.py b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
new file mode 100644
index 0000000..ebcd704
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
@@ -0,0 +1,62 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Internal method dispatcher for Microsoft Visual C/C++.
+"""
+
+import sys
+
+from ..common import (
+ debug,
+)
+
+_refs = []
+
+def register_class(ref):
+ _refs.append(ref)
+
+def register_modulename(modname):
+ module = sys.modules[modname]
+ _refs.append(module)
+
+def reset():
+ debug('')
+ for ref in _refs:
+ for method in ['reset', '_reset']:
+ if not hasattr(ref, method) or not callable(getattr(ref, method, None)):
+ continue
+ debug('call %s.%s()', ref.__name__, method)
+ func = getattr(ref, method)
+ func()
+
+def verify():
+ debug('')
+ for ref in _refs:
+ for method in ['verify', '_verify']:
+ if not hasattr(ref, method) or not callable(getattr(ref, method, None)):
+ continue
+ debug('call %s.%s()', ref.__name__, method)
+ func = getattr(ref, method)
+ func()
+
diff --git a/SCons/Tool/MSCommon/MSVC/Exceptions.py b/SCons/Tool/MSCommon/MSVC/Exceptions.py
new file mode 100644
index 0000000..7a61ec5
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Exceptions.py
@@ -0,0 +1,39 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Exceptions for Microsoft Visual C/C++.
+"""
+
+class VisualCException(Exception):
+ pass
+
+class MSVCVersionNotFound(VisualCException):
+ pass
+
+class MSVCInternalError(VisualCException):
+ pass
+
+class MSVCArgumentError(VisualCException):
+ pass
+
diff --git a/SCons/Tool/MSCommon/MSVC/NotFound.py b/SCons/Tool/MSCommon/MSVC/NotFound.py
new file mode 100644
index 0000000..7abe5ad
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/NotFound.py
@@ -0,0 +1,132 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Microsoft Visual C/C++ not found policy.
+
+Notes:
+ * As implemented, the default is that a warning is issued. This can
+ be changed globally via the function set_msvc_notfound_policy and/or
+ through the environment via the MSVC_NOTFOUND_POLICY variable.
+"""
+
+import SCons.Warnings
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Config
+
+from .Exceptions import (
+ MSVCVersionNotFound,
+)
+
+Dispatcher.register_modulename(__name__)
+
+_MSVC_NOTFOUND_POLICY_DEF = Config.MSVC_NOTFOUND_POLICY_INTERNAL['warning']
+
+def _msvc_notfound_policy_lookup(symbol):
+
+ try:
+ notfound_policy_def = Config.MSVC_NOTFOUND_POLICY_EXTERNAL[symbol]
+ except KeyError:
+ err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
+ " Valid values are: {}".format(
+ repr(symbol),
+ ', '.join([repr(s) for s in Config.MSVC_NOTFOUND_POLICY_EXTERNAL.keys()])
+ )
+ raise ValueError(err_msg)
+
+ return notfound_policy_def
+
+def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
+ """ Set the default policy when MSVC is not found.
+
+ Args:
+ MSVC_NOTFOUND_POLICY:
+ string representing the policy behavior
+ when MSVC is not found or None
+
+ Returns:
+ The previous policy is returned when the MSVC_NOTFOUND_POLICY argument
+ is not None. The active policy is returned when the MSVC_NOTFOUND_POLICY
+ argument is None.
+
+ """
+ global _MSVC_NOTFOUND_POLICY_DEF
+
+ prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
+
+ policy = MSVC_NOTFOUND_POLICY
+ if policy is not None:
+ _MSVC_NOTFOUND_POLICY_DEF = _msvc_notfound_policy_lookup(policy)
+
+ debug(
+ 'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ repr(prev_policy), repr(policy),
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
+
+ return prev_policy
+
+def get_msvc_notfound_policy():
+ """Return the active policy when MSVC is not found."""
+ debug(
+ 'policy.symbol=%s, policy.value=%s',
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
+ return _MSVC_NOTFOUND_POLICY_DEF.symbol
+
+def policy_handler(env, msg):
+
+ if env and 'MSVC_NOTFOUND_POLICY' in env:
+ # environment setting
+ notfound_policy_src = 'environment'
+ policy = env['MSVC_NOTFOUND_POLICY']
+ if policy is not None:
+ # user policy request
+ notfound_policy_def = _msvc_notfound_policy_lookup(policy)
+ else:
+ # active global setting
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+ else:
+ # active global setting
+ notfound_policy_src = 'default'
+ policy = None
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+
+ debug(
+ 'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ notfound_policy_src, repr(policy), repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
+ )
+
+ if notfound_policy_def.value is None:
+ # ignore
+ pass
+ elif notfound_policy_def.value:
+ raise MSVCVersionNotFound(msg)
+ else:
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
new file mode 100644
index 0000000..848b125
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -0,0 +1,110 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Windows registry functions for Microsoft Visual C/C++.
+"""
+
+import os
+
+from SCons.Util import (
+ HKEY_LOCAL_MACHINE,
+ HKEY_CURRENT_USER,
+ HKEY_LOCAL_MACHINE,
+ HKEY_CURRENT_USER,
+)
+
+from .. common import (
+ debug,
+ read_reg,
+)
+
+from . import Dispatcher
+from . import Util
+
+Dispatcher.register_modulename(__name__)
+
+def read_value(hkey, subkey_valname):
+ try:
+ rval = read_reg(subkey_valname, hkroot=hkey)
+ except OSError:
+ debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
+ except IndexError:
+ debug('IndexError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
+ debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
+ return rval
+
+def registry_query_path(key, val, suffix):
+ extval = val + '\\' + suffix if suffix else val
+ qpath = read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = Util.process_path(qpath)
+ else:
+ qpath = None
+ return (qpath, key, val, extval)
+
+REG_SOFTWARE_MICROSOFT = [
+ (HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Microsoft'),
+ (HKEY_CURRENT_USER, r'Software\Wow6432Node\Microsoft'), # SDK queries
+ (HKEY_LOCAL_MACHINE, r'Software\Microsoft'),
+ (HKEY_CURRENT_USER, r'Software\Microsoft'),
+]
+
+def microsoft_query_paths(suffix, usrval=None):
+ paths = []
+ records = []
+ for key, val in REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ qpath = read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = Util.process_path(qpath)
+ if qpath not in paths:
+ paths.append(qpath)
+ records.append((qpath, key, val, extval, usrval))
+ return records
+
+def microsoft_query_keys(suffix, usrval=None):
+ records = []
+ for key, val in REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ rval = read_value(key, extval)
+ if rval:
+ records.append((key, val, extval, usrval))
+ return records
+
+def microsoft_sdks(version):
+ return '\\'.join([r'Microsoft SDKs\Windows', 'v' + version, r'InstallationFolder'])
+
+def sdk_query_paths(version):
+ q = microsoft_sdks(version)
+ return microsoft_query_paths(q)
+
+def windows_kits(version):
+ return r'Windows Kits\Installed Roots\KitsRoot' + version
+
+def windows_kit_query_paths(version):
+ q = windows_kits(version)
+ return microsoft_query_paths(q)
+
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
new file mode 100644
index 0000000..324f8be
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -0,0 +1,733 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Batch file argument functions for Microsoft Visual C/C++.
+"""
+
+import os
+import re
+import enum
+
+from collections import (
+ namedtuple,
+)
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Util
+from . import Config
+from . import WinSDK
+
+from .Exceptions import (
+ MSVCInternalError,
+ MSVCArgumentError,
+)
+
+Dispatcher.register_modulename(__name__)
+
+# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
+re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
+re_sdk_version_81 = re.compile(r'^8[.]1$')
+
+re_sdk_dispatch_map = {
+ '10.0': re_sdk_version_100,
+ '8.1': re_sdk_version_81,
+}
+
+def _verify_re_sdk_dispatch_map():
+ debug('')
+ for sdk_version in Config.MSVC_SDK_VERSIONS:
+ if sdk_version in re_sdk_dispatch_map:
+ continue
+ err_msg = 'sdk version {} not in re_sdk_dispatch_map'.format(sdk_version)
+ raise MSVCInternalError(err_msg)
+ return None
+
+# capture msvc version
+re_toolset_version = re.compile(r'^(?P[1-9][0-9]?[.][0-9])[0-9.]*$', re.IGNORECASE)
+
+re_toolset_full = re.compile(r'''^(?:
+ (?:[1-9][0-9][.][0-9]{1,2})| # XX.Y - XX.YY
+ (?:[1-9][0-9][.][0-9]{2}[.][0-9]{1,5}) # XX.YY.Z - XX.YY.ZZZZZ
+)$''', re.VERBOSE)
+
+re_toolset_140 = re.compile(r'''^(?:
+ (?:14[.]0{1,2})| # 14.0 - 14.00
+ (?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
+)$''', re.VERBOSE)
+
+# valid SxS formats will be matched with re_toolset_full: match 3 '.' format
+re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
+
+# MSVC_SCRIPT_ARGS
+re_vcvars_uwp = re.compile(r'(?:(?(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
+re_vcvars_sdk = re.compile(r'(?:(?(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
+re_vcvars_toolset = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_ver[=](?P\S*))(?:(?!\S)|$)', re.IGNORECASE)
+re_vcvars_spectre = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P\S*))(?:(?!\S)|$)',re.IGNORECASE)
+
+# Force default sdk argument
+MSVC_FORCE_DEFAULT_SDK = False
+
+# Force default toolset argument
+MSVC_FORCE_DEFAULT_TOOLSET = False
+
+# MSVC batch file arguments:
+#
+# VS2022: UWP, SDK, TOOLSET, SPECTRE
+# VS2019: UWP, SDK, TOOLSET, SPECTRE
+# VS2017: UWP, SDK, TOOLSET, SPECTRE
+# VS2015: UWP, SDK
+#
+# MSVC_SCRIPT_ARGS: VS2015+
+#
+# MSVC_UWP_APP: VS2015+
+# MSVC_SDK_VERSION: VS2015+
+# MSVC_TOOLSET_VERSION: VS2017+
+# MSVC_SPECTRE_LIBS: VS2017+
+
+@enum.unique
+class SortOrder(enum.IntEnum):
+ ARCH = 0 # arch
+ UWP = 1 # MSVC_UWP_APP
+ SDK = 2 # MSVC_SDK_VERSION
+ TOOLSET = 3 # MSVC_TOOLSET_VERSION
+ SPECTRE = 4 # MSVC_SPECTRE_LIBS
+ USER = 5 # MSVC_SCRIPT_ARGS
+
+VS2019 = Config.MSVS_VERSION_INTERNAL['2019']
+VS2017 = Config.MSVS_VERSION_INTERNAL['2017']
+VS2015 = Config.MSVS_VERSION_INTERNAL['2015']
+
+MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
+ 'version', # fully qualified msvc version (e.g., '14.1Exp')
+ 'vs_def',
+])
+
+def _msvc_version(version):
+
+ verstr = Util.get_version_prefix(version)
+ vs_def = Config.MSVC_VERSION_INTERNAL[verstr]
+
+ version_args = MSVC_VERSION_ARGS_DEFINITION(
+ version = version,
+ vs_def = vs_def,
+ )
+
+ return version_args
+
+def _msvc_script_argument_uwp(env, msvc, arglist):
+
+ uwp_app = env['MSVC_UWP_APP']
+ debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
+
+ if not uwp_app:
+ return None
+
+ if uwp_app not in Config.BOOLEAN_SYMBOLS[True]:
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(uwp_app), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ # VS2017+ rewrites uwp => store for 14.0 toolset
+ uwp_arg = msvc.vs_def.vc_uwp
+
+ # store/uwp may not be fully installed
+ argpair = (SortOrder.UWP, uwp_arg)
+ arglist.append(argpair)
+
+ return uwp_arg
+
+def _user_script_argument_uwp(env, uwp, user_argstr):
+
+ matches = [m for m in re_vcvars_uwp.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not uwp:
+ return None
+
+ env_argstr = env.get('MSVC_UWP_APP','')
+ debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_script_argument_sdk_constraints(msvc, sdk_version):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc_version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(sdk_version), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ for msvc_sdk_version in msvc.vs_def.vc_sdk_versions:
+ re_sdk_version = re_sdk_dispatch_map[msvc_sdk_version]
+ if re_sdk_version.match(sdk_version):
+ debug('valid: sdk_version=%s', repr(sdk_version))
+ return None
+
+ debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
+ err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
+ return err_msg
+
+def _msvc_script_argument_sdk(env, msvc, platform_type, arglist):
+
+ sdk_version = env['MSVC_SDK_VERSION']
+ debug(
+ 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_version), repr(platform_type)
+ )
+
+ if not sdk_version:
+ return None
+
+ err_msg = _msvc_script_argument_sdk_constraints(msvc, sdk_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+
+ if sdk_version not in sdk_list:
+ err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
+ repr(sdk_version), repr(platform_type)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ argpair = (SortOrder.SDK, sdk_version)
+ arglist.append(argpair)
+
+ return sdk_version
+
+def _msvc_script_default_sdk(env, msvc, platform_type, arglist):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ return None
+
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+ if not len(sdk_list):
+ return None
+
+ sdk_default = sdk_list[0]
+
+ debug(
+ 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_default), repr(platform_type)
+ )
+
+ argpair = (SortOrder.SDK, sdk_default)
+ arglist.append(argpair)
+
+ return sdk_default
+
+def _user_script_argument_sdk(env, sdk_version, user_argstr):
+
+ matches = [m for m in re_vcvars_sdk.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not sdk_version:
+ user_sdk = matches[0].group('sdk')
+ return user_sdk
+
+ env_argstr = env.get('MSVC_SDK_VERSION','')
+ debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_read_toolset_file(msvc, filename):
+ toolset_version = None
+ try:
+ with open(filename) as f:
+ toolset_version = f.readlines()[0].strip()
+ debug(
+ 'msvc_version=%s, filename=%s, toolset_version=%s',
+ repr(msvc.version), repr(filename), repr(toolset_version)
+ )
+ except OSError:
+ debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ except IndexError:
+ debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ return toolset_version
+
+def _msvc_read_toolset_folders(msvc, vc_dir):
+
+ toolsets_sxs = {}
+ toolsets_full = []
+
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+ sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
+ for sxs_toolset in sxs_toolsets:
+ filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
+ filepath = os.path.join(build_dir, sxs_toolset, filename)
+ debug('sxs toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_version = _msvc_read_toolset_file(msvc, filepath)
+ if not toolset_version:
+ continue
+ toolsets_sxs[sxs_toolset] = toolset_version
+ debug(
+ 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(sxs_toolset), toolset_version
+ )
+
+ toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
+ toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
+ for toolset_version in toolsets:
+ binpath = os.path.join(toolset_dir, toolset_version, "bin")
+ debug('toolset: check binpath=%s', repr(binpath))
+ if os.path.exists(binpath):
+ toolsets_full.append(toolset_version)
+ debug(
+ 'toolset: msvc_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(toolset_version)
+ )
+
+ toolsets_full.sort(reverse=True)
+ debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
+
+ return toolsets_sxs, toolsets_full
+
+def _msvc_read_toolset_default(msvc, vc_dir):
+
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+
+ # VS2019+
+ filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_buildtools = _msvc_read_toolset_file(msvc, filepath)
+ if toolset_buildtools:
+ return toolset_buildtools
+
+ # VS2017+
+ filename = "Microsoft.VCToolsVersion.default.txt"
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_default = _msvc_read_toolset_file(msvc, filepath)
+ if toolset_default:
+ return toolset_default
+
+ return None
+
+_toolset_version_cache = {}
+_toolset_default_cache = {}
+
+def _reset_toolset_cache():
+ debug('reset: toolset cache')
+ _toolset_version_cache = {}
+ _toolset_default_cache = {}
+
+def _msvc_version_toolsets(msvc, vc_dir):
+
+ if msvc.version in _toolset_version_cache:
+ toolsets_sxs, toolsets_full = _toolset_version_cache[msvc.version]
+ else:
+ toolsets_sxs, toolsets_full = _msvc_read_toolset_folders(msvc, vc_dir)
+ _toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
+
+ return toolsets_sxs, toolsets_full
+
+def _msvc_default_toolset(msvc, vc_dir):
+
+ if msvc.version in _toolset_default_cache:
+ toolset_default = _toolset_default_cache[msvc.version]
+ else:
+ toolset_default = _msvc_read_toolset_default(msvc, vc_dir)
+ _toolset_default_cache[msvc.version] = toolset_default
+
+ return toolset_default
+
+def _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version):
+
+ if toolset_version == '14.0':
+ return toolset_version
+
+ toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric == VS2019.vc_buildtools_def.vc_version_numeric:
+ # necessary to detect toolset not found
+ if toolset_version == '14.28.16.8':
+ new_toolset_version = '14.28'
+ # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
+ # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
+ # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ if toolset_version in toolsets_sxs:
+ toolset_vcvars = toolsets_sxs[toolset_version]
+ return toolset_vcvars
+
+ for toolset_full in toolsets_full:
+ if toolset_full.startswith(toolset_version):
+ toolset_vcvars = toolset_full
+ return toolset_vcvars
+
+ return None
+
+def _msvc_script_argument_toolset_constraints(msvc, toolset_version):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(toolset_version), repr(msvc.version), repr(VS2017.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ m = re_toolset_version.match(toolset_version)
+ if not m:
+ debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
+ err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
+ repr(toolset_version)
+ )
+ return err_msg
+
+ toolset_ver = m.group('version')
+ toolset_vernum = float(toolset_ver)
+
+ if toolset_vernum < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: %s < %s VS2015',
+ repr(toolset_vernum), repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
+ repr(toolset_version), repr(toolset_ver), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: toolset %s > %s msvc',
+ repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
+ repr(toolset_version), repr(toolset_ver), repr(msvc.version)
+ )
+ return err_msg
+
+ if toolset_vernum == VS2015.vc_buildtools_def.vc_version_numeric:
+ # tooset = 14.0
+ if re_toolset_full.match(toolset_version):
+ if not re_toolset_140.match(toolset_version):
+ debug(
+ 'invalid: toolset version 14.0 constraint: %s != 14.0',
+ repr(toolset_version)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
+ repr(toolset_version), repr(toolset_version)
+ )
+ return err_msg
+ return None
+
+ if re_toolset_full.match(toolset_version):
+ debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
+ return None
+
+ if re_toolset_sxs.match(toolset_version):
+ debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
+ return None
+
+ debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
+ err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
+ return err_msg
+
+def _msvc_script_argument_toolset(env, msvc, vc_dir, arglist):
+
+ toolset_version = env['MSVC_TOOLSET_VERSION']
+ debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
+
+ if not toolset_version:
+ return None
+
+ err_msg = _msvc_script_argument_toolset_constraints(msvc, toolset_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
+ new_toolset_version = '14.0'
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ toolset_vcvars = _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
+ debug(
+ 'toolset: toolset_version=%s, toolset_vcvars=%s',
+ repr(toolset_version), repr(toolset_vcvars)
+ )
+
+ if not toolset_vcvars:
+ err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
+ repr(toolset_version), repr(msvc.version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
+ arglist.append(argpair)
+
+ return toolset_vcvars
+
+def _msvc_script_default_toolset(env, msvc, vc_dir, arglist):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ return None
+
+ toolset_default = _msvc_default_toolset(msvc, vc_dir)
+ if not toolset_default:
+ return None
+
+ debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
+
+ argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
+ arglist.append(argpair)
+
+ return toolset_default
+
+def _user_script_argument_toolset(env, toolset_version, user_argstr):
+
+ matches = [m for m in re_vcvars_toolset.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not toolset_version:
+ user_toolset = matches[0].group('toolset')
+ return user_toolset
+
+ env_argstr = env.get('MSVC_TOOLSET_VERSION','')
+ debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_script_argument_spectre(env, msvc, arglist):
+
+ spectre_libs = env['MSVC_SPECTRE_LIBS']
+ debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
+
+ if not spectre_libs:
+ return None
+
+ if spectre_libs not in (True, '1'):
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(spectre_libs), repr(msvc.version), repr(VS2017.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ spectre_arg = 'spectre'
+
+ # spectre libs may not be installed
+ argpair = (SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
+ arglist.append(argpair)
+
+ return spectre_arg
+
+def _msvc_script_argument_user(env, msvc, arglist):
+
+ # subst None -> empty string
+ script_args = env.subst('$MSVC_SCRIPT_ARGS')
+ debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
+
+ if not script_args:
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(script_args), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ # user arguments are not validated
+ argpair = (SortOrder.USER, script_args)
+ arglist.append(argpair)
+
+ return script_args
+
+def _user_script_argument_spectre(env, spectre, user_argstr):
+
+ matches = [m for m in re_vcvars_spectre.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not spectre:
+ return None
+
+ env_argstr = env.get('MSVC_SPECTRE_LIBS','')
+ debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def msvc_script_arguments(env, version, vc_dir, arg):
+
+ arglist = []
+
+ msvc = _msvc_version(version)
+
+ if arg:
+ argpair = (SortOrder.ARCH, arg)
+ arglist.append(argpair)
+
+ if 'MSVC_SCRIPT_ARGS' in env:
+ user_argstr = _msvc_script_argument_user(env, msvc, arglist)
+ else:
+ user_argstr = None
+
+ if 'MSVC_UWP_APP' in env:
+ uwp = _msvc_script_argument_uwp(env, msvc, arglist)
+ else:
+ uwp = None
+
+ if user_argstr:
+ _user_script_argument_uwp(env, uwp, user_argstr)
+
+ platform_type = 'uwp' if uwp else 'desktop'
+
+ if 'MSVC_SDK_VERSION' in env:
+ sdk_version = _msvc_script_argument_sdk(env, msvc, platform_type, arglist)
+ else:
+ sdk_version = None
+
+ if user_argstr:
+ user_sdk = _user_script_argument_sdk(env, sdk_version, user_argstr)
+ else:
+ user_sdk = None
+
+ if MSVC_FORCE_DEFAULT_SDK:
+ if not sdk_version and not user_sdk:
+ sdk_version = _msvc_script_default_sdk(env, msvc, platform_type, arglist)
+
+ if 'MSVC_TOOLSET_VERSION' in env:
+ toolset_version = _msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
+ else:
+ toolset_version = None
+
+ if user_argstr:
+ user_toolset = _user_script_argument_toolset(env, toolset_version, user_argstr)
+ else:
+ user_toolset = None
+
+ if MSVC_FORCE_DEFAULT_TOOLSET:
+ if not toolset_version and not user_toolset:
+ toolset_version = _msvc_script_default_toolset(env, msvc, vc_dir, arglist)
+
+ if 'MSVC_SPECTRE_LIBS' in env:
+ spectre = _msvc_script_argument_spectre(env, msvc, arglist)
+ else:
+ spectre = None
+
+ if user_argstr:
+ _user_script_argument_spectre(env, spectre, user_argstr)
+
+ if arglist:
+ arglist.sort()
+ argstr = ' '.join([argpair[-1] for argpair in arglist]).strip()
+ else:
+ argstr = ''
+
+ debug('arguments: %s', repr(argstr))
+ return argstr
+
+def reset():
+ debug('')
+ _reset_toolset_cache()
+
+def verify():
+ debug('')
+ _verify_re_sdk_dispatch_map()
+
diff --git a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
new file mode 100644
index 0000000..8a79007
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
@@ -0,0 +1,235 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Determine if and/or when an error/warning should be issued when there
+are no versions of msvc installed. If there is at least one version of
+msvc installed, these routines do (almost) nothing.
+
+Notes:
+ * When msvc is the default compiler because there are no compilers
+ installed, a build may fail due to the cl.exe command not being
+ recognized. Currently, there is no easy way to detect during
+ msvc initialization if the default environment will be used later
+ to build a program and/or library. There is no error/warning
+ as there are legitimate SCons uses that do not require a c compiler.
+ * An error is indicated by returning a non-empty tool list from the
+ function register_iserror.
+"""
+
+import re
+
+from .. common import (
+ debug,
+)
+
+from . import Dispatcher
+
+Dispatcher.register_modulename(__name__)
+
+class _Data:
+
+ separator = r';'
+
+ need_init = True
+
+ @classmethod
+ def reset(cls):
+ debug('msvc default:init')
+ cls.n_setup = 0 # number of calls to msvc_setup_env_once
+ cls.default_ismsvc = False # is msvc the default compiler
+ cls.default_tools_re_list = [] # list of default tools regular expressions
+ cls.msvc_tools_init = set() # tools registered via msvc_exists
+ cls.msvc_tools = None # tools registered via msvc_setup_env_once
+ cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
+ cls.msvc_nodefault = False # is there a default version of msvc
+ cls.need_init = True # reset initialization indicator
+
+def _initialize(env, msvc_exists_func):
+ if _Data.need_init:
+ _Data.reset()
+ _Data.need_init = False
+ _Data.msvc_installed = msvc_exists_func(env)
+ debug('msvc default:msvc_installed=%s', _Data.msvc_installed)
+
+def register_tool(env, tool, msvc_exists_func):
+ debug('msvc default:tool=%s', tool)
+ if _Data.need_init:
+ _initialize(env, msvc_exists_func)
+ if _Data.msvc_installed:
+ return None
+ if not tool:
+ return None
+ if _Data.n_setup == 0:
+ if tool not in _Data.msvc_tools_init:
+ _Data.msvc_tools_init.add(tool)
+ debug('msvc default:tool=%s, msvc_tools_init=%s', tool, _Data.msvc_tools_init)
+ return None
+ if tool not in _Data.msvc_tools:
+ _Data.msvc_tools.add(tool)
+ debug('msvc default:tool=%s, msvc_tools=%s', tool, _Data.msvc_tools)
+
+def register_setup(env, msvc_exists_func):
+ debug('msvc default')
+ if _Data.need_init:
+ _initialize(env, msvc_exists_func)
+ _Data.n_setup += 1
+ if not _Data.msvc_installed:
+ _Data.msvc_tools = set(_Data.msvc_tools_init)
+ if _Data.n_setup == 1:
+ tool_list = env.get('TOOLS', None)
+ if tool_list and tool_list[0] == 'default':
+ if len(tool_list) > 1 and tool_list[1] in _Data.msvc_tools:
+ # msvc tools are the default compiler
+ _Data.default_ismsvc = True
+ _Data.msvc_nodefault = False
+ debug(
+ 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
+ _Data.n_setup, _Data.msvc_installed, _Data.default_ismsvc
+ )
+
+def set_nodefault():
+ # default msvc version, msvc not installed
+ _Data.msvc_nodefault = True
+ debug('msvc default:msvc_nodefault=%s', _Data.msvc_nodefault)
+
+def register_iserror(env, tool, msvc_exists_func):
+
+ register_tool(env, tool, msvc_exists_func)
+
+ if _Data.msvc_installed:
+ # msvc installed
+ return None
+
+ if not _Data.msvc_nodefault:
+ # msvc version specified
+ return None
+
+ tool_list = env.get('TOOLS', None)
+ if not tool_list:
+ # tool list is empty
+ return None
+
+ debug(
+ 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
+ _Data.n_setup, _Data.default_ismsvc, _Data.msvc_tools, tool_list
+ )
+
+ if not _Data.default_ismsvc:
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * msvc is not the default compiler
+
+ # construct tools set
+ tools_set = set(tool_list)
+
+ else:
+
+ if _Data.n_setup == 1:
+ # first setup and msvc is default compiler:
+ # build default tools regex for current tool state
+ tools = _Data.separator.join(tool_list)
+ tools_nchar = len(tools)
+ debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar, tools)
+ re_default_tools = re.compile(re.escape(tools))
+ _Data.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
+ # early exit: no error for default environment when msvc is not installed
+ return None
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * environment tools list is not empty
+ # * default tools regex list constructed
+ # * msvc tools set constructed
+ #
+ # Algorithm using tools string and sets:
+ # * convert environment tools list to a string
+ # * iteratively remove default tools sequences via regex
+ # substition list built from longest sequence (first)
+ # to shortest sequence (last)
+ # * build environment tools set with remaining tools
+ # * compute intersection of environment tools and msvc tools sets
+ # * if the intersection is:
+ # empty - no error: default tools and/or no additional msvc tools
+ # not empty - error: user specified one or more msvc tool(s)
+ #
+ # This will not produce an error or warning when there are no
+ # msvc installed instances nor any other recognized compilers
+ # and the default environment is needed for a build. The msvc
+ # compiler is forcibly added to the environment tools list when
+ # there are no compilers installed on win32. In this case, cl.exe
+ # will not be found on the path resulting in a failed build.
+
+ # construct tools string
+ tools = _Data.separator.join(tool_list)
+ tools_nchar = len(tools)
+
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
+
+ # iteratively remove default tool sequences (longest to shortest)
+ re_nchar_min, re_tools_min = _Data.default_tools_re_list[-1]
+ if tools_nchar >= re_nchar_min and re_tools_min.search(tools):
+ # minimum characters satisfied and minimum pattern exists
+ for re_nchar, re_default_tool in _Data.default_tools_re_list:
+ if tools_nchar < re_nchar:
+ # not enough characters for pattern
+ continue
+ tools = re_default_tool.sub('', tools).strip(_Data.separator)
+ tools_nchar = len(tools)
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
+ if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
+ # less than minimum characters or minimum pattern does not exist
+ break
+
+ # construct non-default list(s) tools set
+ tools_set = {msvc_tool for msvc_tool in tools.split(_Data.separator) if msvc_tool}
+
+ debug('msvc default:tools=%s', tools_set)
+ if not tools_set:
+ return None
+
+ # compute intersection of remaining tools set and msvc tools set
+ tools_found = _Data.msvc_tools.intersection(tools_set)
+ debug('msvc default:tools_exist=%s', tools_found)
+ if not tools_found:
+ return None
+
+ # construct in same order as tools list
+ tools_found_list = []
+ seen_tool = set()
+ for tool in tool_list:
+ if tool not in seen_tool:
+ seen_tool.add(tool)
+ if tool in tools_found:
+ tools_found_list.append(tool)
+
+ # return tool list in order presented
+ return tools_found_list
+
+def reset():
+ debug('')
+ _Data.reset()
+
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
new file mode 100644
index 0000000..15abdcd
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -0,0 +1,55 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Helper functions for Microsoft Visual C/C++.
+"""
+
+import os
+import re
+
+def listdir_dirs(p):
+ dirs = []
+ for dir_name in os.listdir(p):
+ dir_path = os.path.join(p, dir_name)
+ if os.path.isdir(dir_path):
+ dirs.append((dir_name, dir_path))
+ return dirs
+
+def process_path(p):
+ if p:
+ p = os.path.normpath(p)
+ p = os.path.realpath(p)
+ p = os.path.normcase(p)
+ return p
+
+re_version_prefix = re.compile(r'^(?P[0-9.]+).*')
+
+def get_version_prefix(version):
+ m = re_version_prefix.match(version)
+ if m:
+ rval = m.group('version')
+ else:
+ rval = ''
+ return rval
+
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
new file mode 100644
index 0000000..e95c72e
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -0,0 +1,250 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Windows SDK functions for Microsoft Visual C/C++.
+"""
+
+import os
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Util
+from . import Config
+from . import Registry
+
+from .Exceptions import (
+ MSVCInternalError,
+)
+
+Dispatcher.register_modulename(__name__)
+
+def _new_sdk_map():
+ sdk_map = {
+ 'desktop': [],
+ 'uwp': [],
+ }
+ return sdk_map
+
+def _sdk_10_layout(version):
+
+ folder_prefix = version + '.'
+
+ sdk_map = _new_sdk_map()
+
+ sdk_roots = Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ if not os.path.exists(sdk_root):
+ continue
+
+ sdk_include_path = os.path.join(sdk_root, 'include')
+ if not os.path.exists(sdk_include_path):
+ continue
+
+ for version_nbr, version_nbr_path in Util.listdir_dirs(sdk_include_path):
+
+ if not version_nbr.startswith(folder_prefix):
+ continue
+
+ sdk_inc_path = Util.process_path(os.path.join(version_nbr_path, 'um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform_type, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform_type)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform_type].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
+
+def _sdk_81_layout(version):
+
+ version_nbr = version
+
+ sdk_map = _new_sdk_map()
+
+ sdk_roots = Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ # msvc does not check for existence of root or other files
+
+ sdk_inc_path = Util.process_path(os.path.join(sdk_root, r'include\um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform_type, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform_type)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform_type].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
+
+_sdk_map_cache = {}
+_sdk_cache = {}
+
+def _reset_sdk_cache():
+ debug('')
+ _sdk_map_cache = {}
+ _sdk_cache = {}
+
+def _sdk_10(key, reg_version):
+ if key in _sdk_map_cache:
+ sdk_map = _sdk_map_cache[key]
+ else:
+ sdk_map = _sdk_10_layout(reg_version)
+ _sdk_map_cache[key] = sdk_map
+ return sdk_map
+
+def _sdk_81(key, reg_version):
+ if key in _sdk_map_cache:
+ sdk_map = _sdk_map_cache[key]
+ else:
+ sdk_map = _sdk_81_layout(reg_version)
+ _sdk_map_cache[key] = sdk_map
+ return sdk_map
+
+def _combine_sdk_map_list(sdk_map_list):
+ combined_sdk_map = _new_sdk_map()
+ for sdk_map in sdk_map_list:
+ for key, val in sdk_map.items():
+ combined_sdk_map[key].extend(val)
+ return combined_sdk_map
+
+_sdk_dispatch_map = {
+ '10.0': (_sdk_10, '10.0'),
+ '8.1': (_sdk_81, '8.1'),
+}
+
+def _verify_sdk_dispatch_map():
+ debug('')
+ for sdk_version in Config.MSVC_SDK_VERSIONS:
+ if sdk_version in _sdk_dispatch_map:
+ continue
+ err_msg = 'sdk version {} not in sdk_dispatch_map'.format(sdk_version)
+ raise MSVCInternalError(err_msg)
+ return None
+
+def _version_list_sdk_map(version_list):
+
+ sdk_map_list = []
+ for version in version_list:
+ func, reg_version = _sdk_dispatch_map[version]
+ sdk_map = func(version, reg_version)
+ sdk_map_list.append(sdk_map)
+
+ combined_sdk_map = _combine_sdk_map_list(sdk_map_list)
+ return combined_sdk_map
+
+def _sdk_map(version_list):
+ key = tuple(version_list)
+ if key in _sdk_cache:
+ sdk_map = _sdk_cache[key]
+ else:
+ version_numlist = [float(v) for v in version_list]
+ version_numlist.sort(reverse=True)
+ key = tuple([str(v) for v in version_numlist])
+ sdk_map = _version_list_sdk_map(key)
+ _sdk_cache[key] = sdk_map
+ return sdk_map
+
+def get_sdk_version_list(version_list, platform_type):
+ sdk_map = _sdk_map(version_list)
+ sdk_list = sdk_map.get(platform_type, [])
+ return sdk_list
+
+def get_msvc_sdk_version_list(msvc_version, msvc_uwp_app=False):
+ debug('msvc_version=%s, msvc_uwp_app=%s', repr(msvc_version), repr(msvc_uwp_app))
+
+ sdk_versions = []
+
+ verstr = Util.get_version_prefix(msvc_version)
+ vs_def = Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
+ if not vs_def:
+ debug('vs_def is not defined')
+ return sdk_versions
+
+ is_uwp = True if msvc_uwp_app in Config.BOOLEAN_SYMBOLS[True] else False
+ platform_type = 'uwp' if is_uwp else 'desktop'
+ sdk_list = get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
+
+ sdk_versions.extend(sdk_list)
+ debug('sdk_versions=%s', repr(sdk_versions))
+
+ return sdk_versions
+
+def reset():
+ debug('')
+ _reset_sdk_cache()
+
+def verify():
+ debug('')
+ _verify_sdk_dispatch_map()
+
diff --git a/SCons/Tool/MSCommon/MSVC/__init__.py b/SCons/Tool/MSCommon/MSVC/__init__.py
new file mode 100644
index 0000000..afd993f
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/__init__.py
@@ -0,0 +1,50 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# 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.
+
+"""
+Functions for Microsoft Visual C/C++.
+"""
+
+from . import Exceptions
+from . import Util
+
+from . import Dispatcher as _Dispatcher
+
+from . import Config
+from . import Registry
+from . import SetupEnvDefault
+from . import NotFound
+from . import WinSDK
+from . import ScriptArguments
+
+from .NotFound import (
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+)
+
+def reset():
+ _Dispatcher.reset()
+
+#reset() # testing
+_Dispatcher.verify()
+
diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py
index de78f84..9f35e94 100644
--- a/SCons/Tool/MSCommon/__init__.py
+++ b/SCons/Tool/MSCommon/__init__.py
@@ -32,14 +32,17 @@ import SCons.Util
from SCons.Tool.MSCommon.sdk import mssdk_exists, mssdk_setup_env
+from SCons.Tool.MSCommon.MSVC import (
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+)
+
from SCons.Tool.MSCommon.vc import (
msvc_exists,
msvc_setup_env_tool,
msvc_setup_env_once,
msvc_version_to_maj_min,
msvc_find_vswhere,
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
get_msvc_sdk_versions,
)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index ab05323..5a27f44 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -51,7 +51,6 @@ from collections import (
namedtuple,
OrderedDict,
)
-import enum
import SCons.Util
import SCons.Warnings
@@ -61,9 +60,10 @@ from . import common
from .common import CONFIG_CACHE, debug
from .sdk import get_installed_sdks
-
-class VisualCException(Exception):
- pass
+from . import MSVC
+from .MSVC.Exceptions import (
+ VisualCException
+)
class UnsupportedVersion(VisualCException):
pass
@@ -89,296 +89,10 @@ class MSVCScriptNotFound(VisualCException):
class MSVCUseSettingsError(VisualCException):
pass
-class MSVCVersionNotFound(VisualCException):
- pass
-
-class MSVCArgumentError(VisualCException):
- pass
-
-class MSVCInternalError(VisualCException):
- pass
-
class BatchFileExecutionWarning(SCons.Warnings.WarningOnByDefault):
pass
-class _Dispatcher:
-
- classrefs = []
-
- @classmethod
- def register(cls, classref):
- cls.classrefs.append(classref)
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- for classref in cls.classrefs:
- for method in ['reset', '_reset']:
- if not hasattr(classref, method) or not callable(getattr(classref, method, None)):
- continue
- debug('call %s.%s()', classref.__name__, method)
- func = getattr(classref, method)
- func()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- for classref in cls.classrefs:
- for method in ['verify', '_verify']:
- if not hasattr(classref, method) or not callable(getattr(classref, method, None)):
- continue
- debug('call %s.%s()', classref.__name__, method)
- func = getattr(classref, method)
- func()
-
-class _Config:
-
- BOOLEAN_SYMBOLS = {}
- BOOLEAN_EXTERNAL = {}
-
- for bool, symbol_list, symbol_case_list in [
- (False, (False, 0, '0', None, ''), ('False', 'No', 'F', 'N')),
- (True, (True, 1, '1'), ('True', 'Yes', 'T', 'Y')),
- ]:
- BOOLEAN_SYMBOLS[bool] = list(symbol_list)
- for symbol in symbol_case_list:
- BOOLEAN_SYMBOLS[bool].extend([symbol, symbol.lower(), symbol.upper()])
-
- for symbol in BOOLEAN_SYMBOLS[bool]:
- BOOLEAN_EXTERNAL[symbol] = bool
-
- MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
- 'vc_runtime',
- 'vc_runtime_numeric',
- 'vc_runtime_alias_list',
- 'vc_runtime_vsdef_list',
- ])
-
- MSVC_RUNTIME_DEFINITION_LIST = []
-
- MSVC_RUNTIME_INTERNAL = {}
- MSVC_RUNTIME_EXTERNAL = {}
-
- for vc_runtime, vc_runtime_numeric, vc_runtime_alias_list in [
- ('140', 140, ['ucrt']),
- ('120', 120, ['msvcr120']),
- ('110', 110, ['msvcr110']),
- ('100', 100, ['msvcr100']),
- ('90', 90, ['msvcr90']),
- ('80', 80, ['msvcr80']),
- ('71', 71, ['msvcr71']),
- ('70', 70, ['msvcr70']),
- ('60', 60, ['msvcrt']),
- ]:
- vc_runtime_def = MSVC_RUNTIME_DEFINITION(
- vc_runtime = vc_runtime,
- vc_runtime_numeric = vc_runtime_numeric,
- vc_runtime_alias_list = vc_runtime_alias_list,
- vc_runtime_vsdef_list = [],
- )
-
- MSVC_RUNTIME_DEFINITION_LIST.append(vc_runtime_def)
-
- MSVC_RUNTIME_INTERNAL[vc_runtime] = vc_runtime_def
- MSVC_RUNTIME_EXTERNAL[vc_runtime] = vc_runtime_def
-
- for vc_runtime_alias in vc_runtime_alias_list:
- MSVC_RUNTIME_EXTERNAL[vc_runtime_alias] = vc_runtime_def
-
- MSVC_BUILDTOOLS_DEFINITION = namedtuple('MSVCBuildtools', [
- 'vc_buildtools',
- 'vc_buildtools_numeric',
- 'vc_version',
- 'vc_version_numeric',
- 'cl_version',
- 'cl_version_numeric',
- 'vc_runtime_def',
- ])
-
- MSVC_BUILDTOOLS_DEFINITION_LIST = []
-
- MSVC_BUILDTOOLS_INTERNAL = {}
- MSVC_BUILDTOOLS_EXTERNAL = {}
-
- VC_VERSION_MAP = {}
-
- for vc_buildtools, vc_version, cl_version, vc_runtime in [
- ('v143', '14.3', '19.3', '140'),
- ('v142', '14.2', '19.2', '140'),
- ('v141', '14.1', '19.1', '140'),
- ('v140', '14.0', '19.0', '140'),
- ('v120', '12.0', '18.0', '120'),
- ('v110', '11.0', '17.0', '110'),
- ('v100', '10.0', '16.0', '100'),
- ('v90', '9.0', '15.0', '90'),
- ('v80', '8.0', '14.0', '80'),
- ('v71', '7.1', '13.1', '71'),
- ('v70', '7.0', '13.0', '70'),
- ('v60', '6.0', '12.0', '60'),
- ]:
-
- vc_runtime_def = MSVC_RUNTIME_INTERNAL[vc_runtime]
-
- vc_buildtools_def = MSVC_BUILDTOOLS_DEFINITION(
- vc_buildtools = vc_buildtools,
- vc_buildtools_numeric = int(vc_buildtools[1:]),
- vc_version = vc_version,
- vc_version_numeric = float(vc_version),
- cl_version = cl_version,
- cl_version_numeric = float(cl_version),
- vc_runtime_def = vc_runtime_def,
- )
-
- MSVC_BUILDTOOLS_DEFINITION_LIST.append(vc_buildtools_def)
-
- MSVC_BUILDTOOLS_INTERNAL[vc_buildtools] = vc_buildtools_def
- MSVC_BUILDTOOLS_EXTERNAL[vc_buildtools] = vc_buildtools_def
- MSVC_BUILDTOOLS_EXTERNAL[vc_version] = vc_buildtools_def
-
- VC_VERSION_MAP[vc_version] = vc_buildtools_def
-
- MSVS_VERSION_INTERNAL = {}
- MSVS_VERSION_EXTERNAL = {}
-
- MSVC_VERSION_INTERNAL = {}
- MSVC_VERSION_EXTERNAL = {}
-
- MSVS_VERSION_MAJOR_MAP = {}
-
- CL_VERSION_MAP = {}
-
- MSVC_SDK_VERSIONS = set()
-
- VISUALSTUDIO_DEFINITION = namedtuple('VisualStudioDefinition', [
- 'vs_product',
- 'vs_product_alias_list',
- 'vs_version',
- 'vs_version_major',
- 'vs_envvar',
- 'vs_express',
- 'vs_lookup',
- 'vc_sdk_versions',
- 'vc_ucrt_versions',
- 'vc_uwp',
- 'vc_buildtools_def',
- 'vc_buildtools_all',
- ])
-
- VISUALSTUDIO_DEFINITION_LIST = []
-
- VS_PRODUCT_ALIAS = {
- '1998': ['6']
- }
-
- # vs_envvar: VisualStudioVersion defined in environment for MSVS 2012 and later
- # MSVS 2010 and earlier cl_version -> vs_def is a 1:1 mapping
- # SDK attached to product or buildtools?
- for vs_product, vs_version, vs_envvar, vs_express, vs_lookup, vc_sdk, vc_ucrt, vc_uwp, vc_buildtools_all in [
- ('2022', '17.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v143', 'v142', 'v141', 'v140']),
- ('2019', '16.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v142', 'v141', 'v140']),
- ('2017', '15.0', True, True, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v141', 'v140']),
- ('2015', '14.0', True, True, 'registry', ['10.0', '8.1'], ['10'], 'store', ['v140']),
- ('2013', '12.0', True, True, 'registry', None, None, None, ['v120']),
- ('2012', '11.0', True, True, 'registry', None, None, None, ['v110']),
- ('2010', '10.0', False, True, 'registry', None, None, None, ['v100']),
- ('2008', '9.0', False, True, 'registry', None, None, None, ['v90']),
- ('2005', '8.0', False, True, 'registry', None, None, None, ['v80']),
- ('2003', '7.1', False, False, 'registry', None, None, None, ['v71']),
- ('2002', '7.0', False, False, 'registry', None, None, None, ['v70']),
- ('1998', '6.0', False, False, 'registry', None, None, None, ['v60']),
- ]:
-
- vs_version_major = vs_version.split('.')[0]
-
- vc_buildtools_def = MSVC_BUILDTOOLS_INTERNAL[vc_buildtools_all[0]]
-
- vs_def = VISUALSTUDIO_DEFINITION(
- vs_product = vs_product,
- vs_product_alias_list = [],
- vs_version = vs_version,
- vs_version_major = vs_version_major,
- vs_envvar = vs_envvar,
- vs_express = vs_express,
- vs_lookup = vs_lookup,
- vc_sdk_versions = vc_sdk,
- vc_ucrt_versions = vc_ucrt,
- vc_uwp = vc_uwp,
- vc_buildtools_def = vc_buildtools_def,
- vc_buildtools_all = vc_buildtools_all,
- )
-
- VISUALSTUDIO_DEFINITION_LIST.append(vs_def)
-
- vc_buildtools_def.vc_runtime_def.vc_runtime_vsdef_list.append(vs_def)
-
- MSVS_VERSION_INTERNAL[vs_product] = vs_def
- MSVS_VERSION_EXTERNAL[vs_product] = vs_def
- MSVS_VERSION_EXTERNAL[vs_version] = vs_def
-
- MSVC_VERSION_INTERNAL[vc_buildtools_def.vc_version] = vs_def
- MSVC_VERSION_EXTERNAL[vs_product] = vs_def
- MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_version] = vs_def
- MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_buildtools] = vs_def
-
- if vs_product in VS_PRODUCT_ALIAS:
- for vs_product_alias in VS_PRODUCT_ALIAS[vs_product]:
- vs_def.vs_product_alias_list.append(vs_product_alias)
- MSVS_VERSION_EXTERNAL[vs_product_alias] = vs_def
- MSVC_VERSION_EXTERNAL[vs_product_alias] = vs_def
-
- MSVS_VERSION_MAJOR_MAP[vs_version_major] = vs_def
-
- CL_VERSION_MAP[vc_buildtools_def.cl_version] = vs_def
-
- if not vc_sdk:
- continue
-
- MSVC_SDK_VERSIONS.update(vc_sdk)
-
- # convert string version set to string version list ranked in descending order
- MSVC_SDK_VERSIONS = [str(f) for f in sorted([float(s) for s in MSVC_SDK_VERSIONS], reverse=True)]
-
- MSVS_VERSION_LEGACY = {}
- MSVC_VERSION_LEGACY = {}
-
- for vdict in (MSVS_VERSION_EXTERNAL, MSVC_VERSION_INTERNAL):
- for key, vs_def in vdict.items():
- if key not in MSVS_VERSION_LEGACY:
- MSVS_VERSION_LEGACY[key] = vs_def
- MSVC_VERSION_LEGACY[key] = vs_def
-
-# MSVC_NOTFOUND_POLICY definition:
-# error: raise exception
-# warning: issue warning and continue
-# ignore: continue
-
-_MSVC_NOTFOUND_POLICY_DEFINITION = namedtuple('MSVCNotFoundPolicyDefinition', [
- 'value',
- 'symbol',
-])
-
-_MSVC_NOTFOUND_POLICY_INTERNAL = {}
-_MSVC_NOTFOUND_POLICY_EXTERNAL = {}
-
-for policy_value, policy_symbol_list in [
- (True, ['Error', 'Exception']),
- (False, ['Warning', 'Warn']),
- (None, ['Ignore', 'Suppress']),
-]:
-
- policy_symbol = policy_symbol_list[0].lower()
- policy_def = _MSVC_NOTFOUND_POLICY_DEFINITION(policy_value, policy_symbol)
-
- _MSVC_NOTFOUND_POLICY_INTERNAL[policy_symbol] = policy_def
-
- for policy_symbol in policy_symbol_list:
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
-
-_MSVC_NOTFOUND_POLICY_DEF = _MSVC_NOTFOUND_POLICY_INTERNAL['warning']
-
# Dict to 'canonalize' the arch
_ARCH_TO_CANONICAL = {
"amd64" : "amd64",
@@ -1253,7 +967,7 @@ def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
global __INSTALLED_VCS_RUN
__INSTALLED_VCS_RUN = None
- _Dispatcher.reset()
+ MSVC.reset()
def get_default_installed_msvc(env=None):
vcs = get_installed_vcs(env)
@@ -1344,295 +1058,6 @@ def script_env(script, args=None):
return cache_data
-def _msvc_notfound_policy_lookup(symbol):
-
- try:
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_EXTERNAL[symbol]
- except KeyError:
- err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
- " Valid values are: {}".format(
- repr(symbol),
- ', '.join([repr(s) for s in _MSVC_NOTFOUND_POLICY_EXTERNAL.keys()])
- )
- raise ValueError(err_msg)
-
- return notfound_policy_def
-
-def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
- """ Set the default policy when MSVC is not found.
-
- Args:
- MSVC_NOTFOUND_POLICY:
- string representing the policy behavior
- when MSVC is not found or None
-
- Returns:
- The previous policy is returned when the MSVC_NOTFOUND_POLICY argument
- is not None. The active policy is returned when the MSVC_NOTFOUND_POLICY
- argument is None.
-
- """
- global _MSVC_NOTFOUND_POLICY_DEF
-
- prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
-
- policy = MSVC_NOTFOUND_POLICY
- if policy is not None:
- _MSVC_NOTFOUND_POLICY_DEF = _msvc_notfound_policy_lookup(policy)
-
- debug(
- 'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
- repr(prev_policy), repr(policy),
- repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
- )
-
- return prev_policy
-
-def get_msvc_notfound_policy():
- """Return the active policy when MSVC is not found."""
- debug(
- 'policy.symbol=%s, policy.value=%s',
- repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
- )
- return _MSVC_NOTFOUND_POLICY_DEF.symbol
-
-def _msvc_notfound_policy_handler(env, msg):
-
- if env and 'MSVC_NOTFOUND_POLICY' in env:
- # environment setting
- notfound_policy_src = 'environment'
- policy = env['MSVC_NOTFOUND_POLICY']
- if policy is not None:
- # user policy request
- notfound_policy_def = _msvc_notfound_policy_lookup(policy)
- else:
- # active global setting
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
- else:
- # active global setting
- notfound_policy_src = 'default'
- policy = None
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
-
- debug(
- 'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
- notfound_policy_src, repr(policy), repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
- )
-
- if notfound_policy_def.value is None:
- # ignore
- pass
- elif notfound_policy_def.value:
- raise MSVCVersionNotFound(msg)
- else:
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
-
-class _MSVCSetupEnvDefault:
- """
- Determine if and/or when an error/warning should be issued when there
- are no versions of msvc installed. If there is at least one version of
- msvc installed, these routines do (almost) nothing.
-
- Notes:
- * When msvc is the default compiler because there are no compilers
- installed, a build may fail due to the cl.exe command not being
- recognized. Currently, there is no easy way to detect during
- msvc initialization if the default environment will be used later
- to build a program and/or library. There is no error/warning
- as there are legitimate SCons uses that do not require a c compiler.
- * As implemented, the default is that a warning is issued. This can
- be changed globally via the function set_msvc_notfound_policy and/or
- through the environment via the MSVC_NOTFOUND_POLICY variable.
- """
-
- separator = r';'
-
- need_init = True
-
- @classmethod
- def reset(cls):
- debug('msvc default:init')
- cls.n_setup = 0 # number of calls to msvc_setup_env_once
- cls.default_ismsvc = False # is msvc the default compiler
- cls.default_tools_re_list = [] # list of default tools regular expressions
- cls.msvc_tools_init = set() # tools registered via msvc_exists
- cls.msvc_tools = None # tools registered via msvc_setup_env_once
- cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
- cls.msvc_nodefault = False # is there a default version of msvc
- cls.need_init = True # reset initialization indicator
-
- @classmethod
- def _initialize(cls, env):
- if cls.need_init:
- cls.reset()
- cls.need_init = False
- vcs = get_installed_vcs(env)
- cls.msvc_installed = len(vcs) > 0
- debug('msvc default:msvc_installed=%s', cls.msvc_installed)
-
- @classmethod
- def register_tool(cls, env, tool):
- debug('msvc default:tool=%s', tool)
- if cls.need_init:
- cls._initialize(env)
- if cls.msvc_installed:
- return None
- if not tool:
- return None
- if cls.n_setup == 0:
- if tool not in cls.msvc_tools_init:
- cls.msvc_tools_init.add(tool)
- debug('msvc default:tool=%s, msvc_tools_init=%s', tool, cls.msvc_tools_init)
- return None
- if tool not in cls.msvc_tools:
- cls.msvc_tools.add(tool)
- debug('msvc default:tool=%s, msvc_tools=%s', tool, cls.msvc_tools)
-
- @classmethod
- def register_setup(cls, env):
- debug('msvc default')
- if cls.need_init:
- cls._initialize(env)
- cls.n_setup += 1
- if not cls.msvc_installed:
- cls.msvc_tools = set(cls.msvc_tools_init)
- if cls.n_setup == 1:
- tool_list = env.get('TOOLS', None)
- if tool_list and tool_list[0] == 'default':
- if len(tool_list) > 1 and tool_list[1] in cls.msvc_tools:
- # msvc tools are the default compiler
- cls.default_ismsvc = True
- cls.msvc_nodefault = False
- debug(
- 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
- cls.n_setup, cls.msvc_installed, cls.default_ismsvc
- )
-
- @classmethod
- def set_nodefault(cls):
- # default msvc version, msvc not installed
- cls.msvc_nodefault = True
- debug('msvc default:msvc_nodefault=%s', cls.msvc_nodefault)
-
- @classmethod
- def register_iserror(cls, env, tool):
-
- cls.register_tool(env, tool)
-
- if cls.msvc_installed:
- # msvc installed
- return None
-
- if not cls.msvc_nodefault:
- # msvc version specified
- return None
-
- tool_list = env.get('TOOLS', None)
- if not tool_list:
- # tool list is empty
- return None
-
- debug(
- 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
- cls.n_setup, cls.default_ismsvc, cls.msvc_tools, tool_list
- )
-
- if not cls.default_ismsvc:
-
- # Summary:
- # * msvc is not installed
- # * msvc version not specified (default)
- # * msvc is not the default compiler
-
- # construct tools set
- tools_set = set(tool_list)
-
- else:
-
- if cls.n_setup == 1:
- # first setup and msvc is default compiler:
- # build default tools regex for current tool state
- tools = cls.separator.join(tool_list)
- tools_nchar = len(tools)
- debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar, tools)
- re_default_tools = re.compile(re.escape(tools))
- cls.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
- # early exit: no error for default environment when msvc is not installed
- return None
-
- # Summary:
- # * msvc is not installed
- # * msvc version not specified (default)
- # * environment tools list is not empty
- # * default tools regex list constructed
- # * msvc tools set constructed
- #
- # Algorithm using tools string and sets:
- # * convert environment tools list to a string
- # * iteratively remove default tools sequences via regex
- # substition list built from longest sequence (first)
- # to shortest sequence (last)
- # * build environment tools set with remaining tools
- # * compute intersection of environment tools and msvc tools sets
- # * if the intersection is:
- # empty - no error: default tools and/or no additional msvc tools
- # not empty - error: user specified one or more msvc tool(s)
- #
- # This will not produce an error or warning when there are no
- # msvc installed instances nor any other recognized compilers
- # and the default environment is needed for a build. The msvc
- # compiler is forcibly added to the environment tools list when
- # there are no compilers installed on win32. In this case, cl.exe
- # will not be found on the path resulting in a failed build.
-
- # construct tools string
- tools = cls.separator.join(tool_list)
- tools_nchar = len(tools)
-
- debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
-
- # iteratively remove default tool sequences (longest to shortest)
- re_nchar_min, re_tools_min = cls.default_tools_re_list[-1]
- if tools_nchar >= re_nchar_min and re_tools_min.search(tools):
- # minimum characters satisfied and minimum pattern exists
- for re_nchar, re_default_tool in cls.default_tools_re_list:
- if tools_nchar < re_nchar:
- # not enough characters for pattern
- continue
- tools = re_default_tool.sub('', tools).strip(cls.separator)
- tools_nchar = len(tools)
- debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
- if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
- # less than minimum characters or minimum pattern does not exist
- break
-
- # construct non-default list(s) tools set
- tools_set = {msvc_tool for msvc_tool in tools.split(cls.separator) if msvc_tool}
-
- debug('msvc default:tools=%s', tools_set)
- if not tools_set:
- return None
-
- # compute intersection of remaining tools set and msvc tools set
- tools_found = cls.msvc_tools.intersection(tools_set)
- debug('msvc default:tools_exist=%s', tools_found)
- if not tools_found:
- return None
-
- # construct in same order as tools list
- tools_found_list = []
- seen_tool = set()
- for tool in tool_list:
- if tool not in seen_tool:
- seen_tool.add(tool)
- if tool in tools_found:
- tools_found_list.append(tool)
-
- # return tool list in order presented
- return tools_found_list
-
-_Dispatcher.register(_MSVCSetupEnvDefault)
-
def get_default_version(env):
msvc_version = env.get('MSVC_VERSION')
msvs_version = env.get('MSVS_VERSION')
@@ -1673,16 +1098,16 @@ def msvc_setup_env_once(env, tool=None):
if not has_run:
debug('tool=%s', repr(tool))
- _MSVCSetupEnvDefault.register_setup(env)
+ MSVC.SetupEnvDefault.register_setup(env, msvc_exists)
msvc_setup_env(env)
env["MSVC_SETUP_RUN"] = True
- req_tools = _MSVCSetupEnvDefault.register_iserror(env, tool)
+ req_tools = MSVC.SetupEnvDefault.register_iserror(env, tool, msvc_exists)
if req_tools:
msg = "No versions of the MSVC compiler were found.\n" \
" Visual Studio C/C++ compilers may not be set correctly.\n" \
" Requested tool(s) are: {}".format(req_tools)
- _msvc_notfound_policy_handler(env, msg)
+ MSVC.Notfound.policy_handler(env, msg)
def msvc_find_valid_batch_script(env, version):
"""Find and execute appropriate batch script to set up build env.
@@ -1724,7 +1149,7 @@ def msvc_find_valid_batch_script(env, version):
debug('use_script 2 %s, args:%s', repr(vc_script), arg)
found = None
if vc_script:
- arg = _ScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
+ arg = MSVC.ScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
try:
d = script_env(vc_script, args=arg)
found = vc_script
@@ -1769,7 +1194,7 @@ def msvc_find_valid_batch_script(env, version):
" No versions of the MSVC compiler were found.\n" \
" Visual Studio C/C++ compilers may not be set correctly".format(version)
- _msvc_notfound_policy_handler(env, msg)
+ MSVC.NotFound.policy_handler(env, msg)
return d
@@ -1805,7 +1230,7 @@ def msvc_setup_env(env):
version = get_default_version(env)
if version is None:
if not msvc_setup_env_user(env):
- _MSVCSetupEnvDefault.set_nodefault()
+ MSVC.SetupEnvDefault.set_nodefault()
return None
# XXX: we set-up both MSVS version for backward
@@ -1899,7 +1324,7 @@ def msvc_setup_env_user(env=None):
def msvc_setup_env_tool(env=None, version=None, tool=None):
debug('tool=%s, version=%s', repr(tool), repr(version))
- _MSVCSetupEnvDefault.register_tool(env, tool)
+ MSVC.SetupEnvDefault.register_tool(env, tool, msvc_exists)
rval = False
if not rval and msvc_exists(env, version):
rval = True
@@ -1920,1043 +1345,6 @@ def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
debug('no msvc versions detected')
return rval
- rval = _WindowsSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
+ rval = MSVC.WinSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
return rval
-class _Util:
-
- @staticmethod
- def listdir_dirs(p):
- dirs = []
- for dir_name in os.listdir(p):
- dir_path = os.path.join(p, dir_name)
- if os.path.isdir(dir_path):
- dirs.append((dir_name, dir_path))
- return dirs
-
- @staticmethod
- def process_path(p):
- if p:
- p = os.path.normpath(p)
- p = os.path.realpath(p)
- p = os.path.normcase(p)
- return p
-
-class _Registry:
-
- def read_value(hkey, subkey_valname):
- try:
- rval = common.read_reg(subkey_valname, hkroot=hkey)
- except OSError:
- debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
- return None
- except IndexError:
- debug('IndexError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
- return None
- debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
- return rval
-
- @classmethod
- def registry_query_path(cls, key, val, suffix):
- extval = val + '\\' + suffix if suffix else val
- qpath = cls.read_value(key, extval)
- if qpath and os.path.exists(qpath):
- qpath = _Util.process_path(qpath)
- else:
- qpath = None
- return (qpath, key, val, extval)
-
- REG_SOFTWARE_MICROSOFT = [
- (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Microsoft'),
- (SCons.Util.HKEY_CURRENT_USER, r'Software\Wow6432Node\Microsoft'), # SDK queries
- (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Microsoft'),
- (SCons.Util.HKEY_CURRENT_USER, r'Software\Microsoft'),
- ]
-
- @classmethod
- def microsoft_query_paths(cls, suffix, usrval=None):
- paths = []
- records = []
- for key, val in cls.REG_SOFTWARE_MICROSOFT:
- extval = val + '\\' + suffix if suffix else val
- qpath = cls.read_value(key, extval)
- if qpath and os.path.exists(qpath):
- qpath = _Util.process_path(qpath)
- if qpath not in paths:
- paths.append(qpath)
- records.append((qpath, key, val, extval, usrval))
- return records
-
- @classmethod
- def microsoft_query_keys(cls, suffix, usrval=None):
- records = []
- for key, val in cls.REG_SOFTWARE_MICROSOFT:
- extval = val + '\\' + suffix if suffix else val
- rval = cls.read_value(key, extval)
- if rval:
- records.append((key, val, extval, usrval))
- return records
-
- @classmethod
- def microsoft_sdks(cls, version):
- return '\\'.join([r'Microsoft SDKs\Windows', 'v' + version, r'InstallationFolder'])
-
- @classmethod
- def sdk_query_paths(cls, version):
- q = cls.microsoft_sdks(version)
- return cls.microsoft_query_paths(q)
-
- @classmethod
- def windows_kits(cls, version):
- return r'Windows Kits\Installed Roots\KitsRoot' + version
-
- @classmethod
- def windows_kit_query_paths(cls, version):
- q = cls.windows_kits(version)
- return cls.microsoft_query_paths(q)
-
-class _WindowsSDK:
-
- @classmethod
- def _new_sdk_map(cls):
- sdk_map = {
- 'desktop': [],
- 'uwp': [],
- }
- return sdk_map
-
- @classmethod
- def _sdk_10_layout(cls, version):
-
- folder_prefix = version + '.'
-
- sdk_map = cls._new_sdk_map()
-
- sdk_roots = _Registry.sdk_query_paths(version)
-
- sdk_version_platform_seen = set()
- sdk_roots_seen = set()
-
- for sdk_t in sdk_roots:
-
- sdk_root = sdk_t[0]
- if sdk_root in sdk_roots_seen:
- continue
- sdk_roots_seen.add(sdk_root)
-
- if not os.path.exists(sdk_root):
- continue
-
- sdk_include_path = os.path.join(sdk_root, 'include')
- if not os.path.exists(sdk_include_path):
- continue
-
- for version_nbr, version_nbr_path in _Util.listdir_dirs(sdk_include_path):
-
- if not version_nbr.startswith(folder_prefix):
- continue
-
- sdk_inc_path = _Util.process_path(os.path.join(version_nbr_path, 'um'))
- if not os.path.exists(sdk_inc_path):
- continue
-
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
- ]:
-
- if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
- continue
-
- key = (version_nbr, platform_type)
- if key in sdk_version_platform_seen:
- continue
- sdk_version_platform_seen.add(key)
-
- sdk_map[platform_type].append(version_nbr)
-
- for key, val in sdk_map.items():
- val.sort(reverse=True)
-
- return sdk_map
-
- @classmethod
- def _sdk_81_layout(cls, version):
-
- version_nbr = version
-
- sdk_map = cls._new_sdk_map()
-
- sdk_roots = _Registry.sdk_query_paths(version)
-
- sdk_version_platform_seen = set()
- sdk_roots_seen = set()
-
- for sdk_t in sdk_roots:
-
- sdk_root = sdk_t[0]
- if sdk_root in sdk_roots_seen:
- continue
- sdk_roots_seen.add(sdk_root)
-
- # msvc does not check for existence of root or other files
-
- sdk_inc_path = _Util.process_path(os.path.join(sdk_root, r'include\um'))
- if not os.path.exists(sdk_inc_path):
- continue
-
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
- ]:
-
- if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
- continue
-
- key = (version_nbr, platform_type)
- if key in sdk_version_platform_seen:
- continue
- sdk_version_platform_seen.add(key)
-
- sdk_map[platform_type].append(version_nbr)
-
- for key, val in sdk_map.items():
- val.sort(reverse=True)
-
- return sdk_map
-
- sdk_map_cache = {}
- sdk_cache = {}
-
- @classmethod
- def _reset_sdk_cache(cls):
- debug('reset %s: sdk cache', cls.__name__)
- cls._sdk_map_cache = {}
- cls._sdk_cache = {}
-
- @classmethod
- def _sdk_10(cls, key, reg_version):
- if key in cls.sdk_map_cache:
- sdk_map = cls.sdk_map_cache[key]
- else:
- sdk_map = cls._sdk_10_layout(reg_version)
- cls.sdk_map_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def _sdk_81(cls, key, reg_version):
- if key in cls.sdk_map_cache:
- sdk_map = cls.sdk_map_cache[key]
- else:
- sdk_map = cls._sdk_81_layout(reg_version)
- cls.sdk_map_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def _combine_sdk_map_list(cls, sdk_map_list):
- combined_sdk_map = cls._new_sdk_map()
- for sdk_map in sdk_map_list:
- for key, val in sdk_map.items():
- combined_sdk_map[key].extend(val)
- return combined_sdk_map
-
- sdk_dispatch_map = None
-
- @classmethod
- def _init_sdk_dispatch_map(cls):
- cls.sdk_dispatch_map = {
- '10.0': (cls._sdk_10, '10.0'),
- '8.1': (cls._sdk_81, '8.1'),
- }
-
- @classmethod
- def _verify_sdk_dispatch_map(cls):
- debug('%s verify sdk_dispatch_map', cls.__name__)
- cls._init_sdk_dispatch_map()
- for sdk_version in _Config.MSVC_SDK_VERSIONS:
- if sdk_version in cls.sdk_dispatch_map:
- continue
- err_msg = 'sdk version {} not in {}.sdk_dispatch_map'.format(sdk_version, cls.__name__)
- raise MSVCInternalError(err_msg)
- return None
-
- @classmethod
- def _version_list_sdk_map(cls, version_list):
-
- if not cls.sdk_dispatch_map:
- cls._init_sdk_dispatch_map()
-
- sdk_map_list = []
- for version in version_list:
- func, reg_version = cls.sdk_dispatch_map[version]
- sdk_map = func(version, reg_version)
- sdk_map_list.append(sdk_map)
-
- combined_sdk_map = cls._combine_sdk_map_list(sdk_map_list)
- return combined_sdk_map
-
- @classmethod
- def _sdk_map(cls, version_list):
- key = tuple(version_list)
- if key in cls.sdk_cache:
- sdk_map = cls.sdk_cache[key]
- else:
- version_numlist = [float(v) for v in version_list]
- version_numlist.sort(reverse=True)
- key = tuple([str(v) for v in version_numlist])
- sdk_map = cls._version_list_sdk_map(key)
- cls.sdk_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def get_sdk_version_list(cls, version_list, platform_type):
- sdk_map = cls._sdk_map(version_list)
- sdk_list = sdk_map.get(platform_type, [])
- return sdk_list
-
- @classmethod
- def get_msvc_sdk_version_list(cls, msvc_version=None, msvc_uwp_app=False):
- debug('msvc_version=%s, msvc_uwp_app=%s', repr(msvc_version), repr(msvc_uwp_app))
-
- sdk_versions = []
-
- verstr = get_msvc_version_numeric(msvc_version)
- vs_def = _Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
- if not vs_def:
- debug('vs_def is not defined')
- return sdk_versions
-
- is_uwp = True if msvc_uwp_app in _Config.BOOLEAN_SYMBOLS[True] else False
- platform_type = 'uwp' if is_uwp else 'desktop'
- sdk_list = _WindowsSDK.get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
-
- sdk_versions.extend(sdk_list)
- debug('sdk_versions=%s', repr(sdk_versions))
-
- return sdk_versions
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- cls._reset_sdk_cache()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- cls._verify_sdk_dispatch_map()
-
-_Dispatcher.register(_WindowsSDK)
-
-class _ScriptArguments:
-
- # TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
- re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
- re_sdk_version_81 = re.compile(r'^8[.]1$')
-
- re_sdk_dispatch_map = {
- '10.0': re_sdk_version_100,
- '8.1': re_sdk_version_81,
- }
-
- @classmethod
- def _verify_re_sdk_dispatch_map(cls):
- debug('%s verify re_sdk_dispatch_map', cls.__name__)
- for sdk_version in _Config.MSVC_SDK_VERSIONS:
- if sdk_version in cls.re_sdk_dispatch_map:
- continue
- err_msg = 'sdk version {} not in {}.re_sdk_dispatch_map'.format(sdk_version, cls.__name__)
- raise MSVCInternalError(err_msg)
- return None
-
- # capture msvc version
- re_toolset_version = re.compile(r'^(?P[1-9][0-9]?[.][0-9])[0-9.]*$', re.IGNORECASE)
-
- re_toolset_full = re.compile(r'''^(?:
- (?:[1-9][0-9][.][0-9]{1,2})| # XX.Y - XX.YY
- (?:[1-9][0-9][.][0-9]{2}[.][0-9]{1,5}) # XX.YY.Z - XX.YY.ZZZZZ
- )$''', re.VERBOSE)
-
- re_toolset_140 = re.compile(r'''^(?:
- (?:14[.]0{1,2})| # 14.0 - 14.00
- (?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
- )$''', re.VERBOSE)
-
- # valid SxS formats will be matched with re_toolset_full: match 3 '.' format
- re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
-
- # MSVC_SCRIPT_ARGS
- re_vcvars_uwp = re.compile(r'(?:(?(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
- re_vcvars_sdk = re.compile(r'(?:(?(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
- re_vcvars_toolset = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_ver[=](?P\S*))(?:(?!\S)|$)', re.IGNORECASE)
- re_vcvars_spectre = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P\S*))(?:(?!\S)|$)',re.IGNORECASE)
-
- # Force default sdk argument
- MSVC_FORCE_DEFAULT_SDK = False
-
- # Force default toolset argument
- MSVC_FORCE_DEFAULT_TOOLSET = False
-
- # MSVC batch file arguments:
- #
- # VS2022: UWP, SDK, TOOLSET, SPECTRE
- # VS2019: UWP, SDK, TOOLSET, SPECTRE
- # VS2017: UWP, SDK, TOOLSET, SPECTRE
- # VS2015: UWP, SDK
- #
- # MSVC_SCRIPT_ARGS: VS2015+
- #
- # MSVC_UWP_APP: VS2015+
- # MSVC_SDK_VERSION: VS2015+
- # MSVC_TOOLSET_VERSION: VS2017+
- # MSVC_SPECTRE_LIBS: VS2017+
-
- @enum.unique
- class SortOrder(enum.IntEnum):
- ARCH = 0 # arch
- UWP = 1 # MSVC_UWP_APP
- SDK = 2 # MSVC_SDK_VERSION
- TOOLSET = 3 # MSVC_TOOLSET_VERSION
- SPECTRE = 4 # MSVC_SPECTRE_LIBS
- USER = 5 # MSVC_SCRIPT_ARGS
-
- VS2019 = _Config.MSVS_VERSION_INTERNAL['2019']
- VS2017 = _Config.MSVS_VERSION_INTERNAL['2017']
- VS2015 = _Config.MSVS_VERSION_INTERNAL['2015']
-
- MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
- 'version', # fully qualified msvc version (e.g., '14.1Exp')
- 'vs_def',
- ])
-
- @classmethod
- def _msvc_version(cls, version):
-
- verstr = get_msvc_version_numeric(version)
- vs_def = _Config.MSVC_VERSION_INTERNAL[verstr]
-
- version_args = cls.MSVC_VERSION_ARGS_DEFINITION(
- version = version,
- vs_def = vs_def,
- )
-
- return version_args
-
- @classmethod
- def _msvc_script_argument_uwp(cls, env, msvc, arglist):
-
- uwp_app = env['MSVC_UWP_APP']
- debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
-
- if not uwp_app:
- return None
-
- if uwp_app not in _Config.BOOLEAN_SYMBOLS[True]:
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(uwp_app), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- # VS2017+ rewrites uwp => store for 14.0 toolset
- uwp_arg = msvc.vs_def.vc_uwp
-
- # store/uwp may not be fully installed
- argpair = (cls.SortOrder.UWP, uwp_arg)
- arglist.append(argpair)
-
- return uwp_arg
-
- @classmethod
- def _user_script_argument_uwp(cls, env, uwp, user_argstr):
-
- matches = [m for m in cls.re_vcvars_uwp.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not uwp:
- return None
-
- env_argstr = env.get('MSVC_UWP_APP','')
- debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_script_argument_sdk_constraints(cls, msvc, sdk_version):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc_version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(sdk_version), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- for msvc_sdk_version in msvc.vs_def.vc_sdk_versions:
- re_sdk_version = cls.re_sdk_dispatch_map[msvc_sdk_version]
- if re_sdk_version.match(sdk_version):
- debug('valid: sdk_version=%s', repr(sdk_version))
- return None
-
- debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
- err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
- return err_msg
-
- @classmethod
- def _msvc_script_argument_sdk(cls, env, msvc, platform_type, arglist):
-
- sdk_version = env['MSVC_SDK_VERSION']
- debug(
- 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_version), repr(platform_type)
- )
-
- if not sdk_version:
- return None
-
- err_msg = cls._msvc_script_argument_sdk_constraints(msvc, sdk_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
-
- sdk_list = _WindowsSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
-
- if sdk_version not in sdk_list:
- err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
- repr(sdk_version), repr(platform_type)
- )
- raise MSVCArgumentError(err_msg)
-
- argpair = (cls.SortOrder.SDK, sdk_version)
- arglist.append(argpair)
-
- return sdk_version
-
- @classmethod
- def _msvc_script_default_sdk(cls, env, msvc, platform_type, arglist):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- return None
-
- sdk_list = _WindowsSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
- if not len(sdk_list):
- return None
-
- sdk_default = sdk_list[0]
-
- debug(
- 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_default), repr(platform_type)
- )
-
- argpair = (cls.SortOrder.SDK, sdk_default)
- arglist.append(argpair)
-
- return sdk_default
-
- @classmethod
- def _user_script_argument_sdk(cls, env, sdk_version, user_argstr):
-
- matches = [m for m in cls.re_vcvars_sdk.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not sdk_version:
- user_sdk = matches[0].group('sdk')
- return user_sdk
-
- env_argstr = env.get('MSVC_SDK_VERSION','')
- debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_read_toolset_file(cls, msvc, filename):
- toolset_version = None
- try:
- with open(filename) as f:
- toolset_version = f.readlines()[0].strip()
- debug(
- 'msvc_version=%s, filename=%s, toolset_version=%s',
- repr(msvc.version), repr(filename), repr(toolset_version)
- )
- except OSError:
- debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
- except IndexError:
- debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
- return toolset_version
-
- @classmethod
- def _msvc_read_toolset_folders(cls, msvc, vc_dir):
-
- toolsets_sxs = {}
- toolsets_full = []
-
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
- sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
- for sxs_toolset in sxs_toolsets:
- filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
- filepath = os.path.join(build_dir, sxs_toolset, filename)
- debug('sxs toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_version = cls._msvc_read_toolset_file(msvc, filepath)
- if not toolset_version:
- continue
- toolsets_sxs[sxs_toolset] = toolset_version
- debug(
- 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
- repr(msvc.version), repr(sxs_toolset), toolset_version
- )
-
- toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
- toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
- for toolset_version in toolsets:
- binpath = os.path.join(toolset_dir, toolset_version, "bin")
- debug('toolset: check binpath=%s', repr(binpath))
- if os.path.exists(binpath):
- toolsets_full.append(toolset_version)
- debug(
- 'toolset: msvc_version=%s, toolset_version=%s',
- repr(msvc.version), repr(toolset_version)
- )
-
- toolsets_full.sort(reverse=True)
- debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
-
- return toolsets_sxs, toolsets_full
-
- @classmethod
- def _msvc_read_toolset_default(cls, msvc, vc_dir):
-
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
-
- # VS2019+
- filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
- filepath = os.path.join(build_dir, filename)
-
- debug('default toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_buildtools = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_buildtools:
- return toolset_buildtools
-
- # VS2017+
- filename = "Microsoft.VCToolsVersion.default.txt"
- filepath = os.path.join(build_dir, filename)
-
- debug('default toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_default = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_default:
- return toolset_default
-
- return None
-
- _toolset_version_cache = {}
- _toolset_default_cache = {}
-
- @classmethod
- def _reset_toolset_cache(cls):
- debug('reset %s: toolset cache', cls.__name__)
- cls._toolset_version_cache = {}
- cls._toolset_default_cache = {}
-
- @classmethod
- def _msvc_version_toolsets(cls, msvc, vc_dir):
-
- if msvc.version in cls._toolset_version_cache:
- toolsets_sxs, toolsets_full = cls._toolset_version_cache[msvc.version]
- else:
- toolsets_sxs, toolsets_full = cls._msvc_read_toolset_folders(msvc, vc_dir)
- cls._toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
-
- return toolsets_sxs, toolsets_full
-
- @classmethod
- def _msvc_default_toolset(cls, msvc, vc_dir):
-
- if msvc.version in cls._toolset_default_cache:
- toolset_default = cls._toolset_default_cache[msvc.version]
- else:
- toolset_default = cls._msvc_read_toolset_default(msvc, vc_dir)
- cls._toolset_default_cache[msvc.version] = toolset_default
-
- return toolset_default
-
- @classmethod
- def _msvc_version_toolset_vcvars(cls, msvc, vc_dir, toolset_version):
-
- if toolset_version == '14.0':
- return toolset_version
-
- toolsets_sxs, toolsets_full = cls._msvc_version_toolsets(msvc, vc_dir)
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric == cls.VS2019.vc_buildtools_def.vc_version_numeric:
- # necessary to detect toolset not found
- if toolset_version == '14.28.16.8':
- new_toolset_version = '14.28'
- # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
- # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
- # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
-
- if toolset_version in toolsets_sxs:
- toolset_vcvars = toolsets_sxs[toolset_version]
- return toolset_vcvars
-
- for toolset_full in toolsets_full:
- if toolset_full.startswith(toolset_version):
- toolset_vcvars = toolset_full
- return toolset_vcvars
-
- return None
-
- @classmethod
- def _msvc_script_argument_toolset_constraints(cls, msvc, toolset_version):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(toolset_version), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- m = cls.re_toolset_version.match(toolset_version)
- if not m:
- debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
- err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
- repr(toolset_version)
- )
- return err_msg
-
- toolset_ver = m.group('version')
- toolset_vernum = float(toolset_ver)
-
- if toolset_vernum < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: %s < %s VS2015',
- repr(toolset_vernum), repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
- repr(toolset_version), repr(toolset_ver), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: toolset %s > %s msvc',
- repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
- repr(toolset_version), repr(toolset_ver), repr(msvc.version)
- )
- return err_msg
-
- if toolset_vernum == cls.VS2015.vc_buildtools_def.vc_version_numeric:
- # tooset = 14.0
- if cls.re_toolset_full.match(toolset_version):
- if not cls.re_toolset_140.match(toolset_version):
- debug(
- 'invalid: toolset version 14.0 constraint: %s != 14.0',
- repr(toolset_version)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
- repr(toolset_version), repr(toolset_version)
- )
- return err_msg
- return None
-
- if cls.re_toolset_full.match(toolset_version):
- debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
- return None
-
- if cls.re_toolset_sxs.match(toolset_version):
- debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
- return None
-
- debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
- err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
- return err_msg
-
- @classmethod
- def _msvc_script_argument_toolset(cls, env, msvc, vc_dir, arglist):
-
- toolset_version = env['MSVC_TOOLSET_VERSION']
- debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
-
- if not toolset_version:
- return None
-
- err_msg = cls._msvc_script_argument_toolset_constraints(msvc, toolset_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
-
- if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
- new_toolset_version = '14.0'
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
-
- toolset_vcvars = cls._msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
- debug(
- 'toolset: toolset_version=%s, toolset_vcvars=%s',
- repr(toolset_version), repr(toolset_vcvars)
- )
-
- if not toolset_vcvars:
- err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
- repr(toolset_version), repr(msvc.version)
- )
- raise MSVCArgumentError(err_msg)
-
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
- arglist.append(argpair)
-
- return toolset_vcvars
-
- @classmethod
- def _msvc_script_default_toolset(cls, env, msvc, vc_dir, arglist):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- return None
-
- toolset_default = cls._msvc_default_toolset(msvc, vc_dir)
- if not toolset_default:
- return None
-
- debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
-
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
- arglist.append(argpair)
-
- return toolset_default
-
- @classmethod
- def _user_script_argument_toolset(cls, env, toolset_version, user_argstr):
-
- matches = [m for m in cls.re_vcvars_toolset.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not toolset_version:
- user_toolset = matches[0].group('toolset')
- return user_toolset
-
- env_argstr = env.get('MSVC_TOOLSET_VERSION','')
- debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_script_argument_spectre(cls, env, msvc, arglist):
-
- spectre_libs = env['MSVC_SPECTRE_LIBS']
- debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
-
- if not spectre_libs:
- return None
-
- if spectre_libs not in (True, '1'):
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(spectre_libs), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- spectre_arg = 'spectre'
-
- # spectre libs may not be installed
- argpair = (cls.SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
- arglist.append(argpair)
-
- return spectre_arg
-
- @classmethod
- def _msvc_script_argument_user(cls, env, msvc, arglist):
-
- # subst None -> empty string
- script_args = env.subst('$MSVC_SCRIPT_ARGS')
- debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
-
- if not script_args:
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(script_args), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- # user arguments are not validated
- argpair = (cls.SortOrder.USER, script_args)
- arglist.append(argpair)
-
- return script_args
-
- @classmethod
- def _user_script_argument_spectre(cls, env, spectre, user_argstr):
-
- matches = [m for m in cls.re_vcvars_spectre.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not spectre:
- return None
-
- env_argstr = env.get('MSVC_SPECTRE_LIBS','')
- debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def msvc_script_arguments(cls, env, version, vc_dir, arg):
-
- arglist = []
-
- msvc = cls._msvc_version(version)
-
- if arg:
- argpair = (cls.SortOrder.ARCH, arg)
- arglist.append(argpair)
-
- if 'MSVC_SCRIPT_ARGS' in env:
- user_argstr = cls._msvc_script_argument_user(env, msvc, arglist)
- else:
- user_argstr = None
-
- if 'MSVC_UWP_APP' in env:
- uwp = cls._msvc_script_argument_uwp(env, msvc, arglist)
- else:
- uwp = None
-
- if user_argstr:
- cls._user_script_argument_uwp(env, uwp, user_argstr)
-
- platform_type = 'uwp' if uwp else 'desktop'
-
- if 'MSVC_SDK_VERSION' in env:
- sdk_version = cls._msvc_script_argument_sdk(env, msvc, platform_type, arglist)
- else:
- sdk_version = None
-
- if user_argstr:
- user_sdk = cls._user_script_argument_sdk(env, sdk_version, user_argstr)
- else:
- user_sdk = None
-
- if cls.MSVC_FORCE_DEFAULT_SDK:
- if not sdk_version and not user_sdk:
- sdk_version = cls._msvc_script_default_sdk(env, msvc, platform_type, arglist)
-
- if 'MSVC_TOOLSET_VERSION' in env:
- toolset_version = cls._msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
- else:
- toolset_version = None
-
- if user_argstr:
- user_toolset = cls._user_script_argument_toolset(env, toolset_version, user_argstr)
- else:
- user_toolset = None
-
- if cls.MSVC_FORCE_DEFAULT_TOOLSET:
- if not toolset_version and not user_toolset:
- toolset_version = cls._msvc_script_default_toolset(env, msvc, vc_dir, arglist)
-
- if 'MSVC_SPECTRE_LIBS' in env:
- spectre = cls._msvc_script_argument_spectre(env, msvc, arglist)
- else:
- spectre = None
-
- if user_argstr:
- cls._user_script_argument_spectre(env, spectre, user_argstr)
-
- if arglist:
- arglist.sort()
- argstr = ' '.join([argpair[-1] for argpair in arglist]).strip()
- else:
- argstr = ''
-
- debug('arguments: %s', repr(argstr))
- return argstr
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- cls._reset_toolset_cache()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- cls._verify_re_sdk_dispatch_map()
-
-_Dispatcher.register(_ScriptArguments)
-
-# internal consistency check
-_Dispatcher.verify()
--
cgit v0.12
From 14ee60c050d577704004ba8ade7e5347e356f9e9 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 17:08:34 -0400
Subject: Fix typo in module name
---
SCons/Tool/MSCommon/vc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 5a27f44..2e5d542 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1107,7 +1107,7 @@ def msvc_setup_env_once(env, tool=None):
msg = "No versions of the MSVC compiler were found.\n" \
" Visual Studio C/C++ compilers may not be set correctly.\n" \
" Requested tool(s) are: {}".format(req_tools)
- MSVC.Notfound.policy_handler(env, msg)
+ MSVC.NotFound.policy_handler(env, msg)
def msvc_find_valid_batch_script(env, version):
"""Find and execute appropriate batch script to set up build env.
--
cgit v0.12
From 9619adbcf75cf9f6c851e577f49d92b021012de3 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 17:50:03 -0400
Subject: Cleanup MSCommon/vc imports and move Dispatcher imports and
registration
---
SCons/Tool/MSCommon/MSVC/Config.py | 2 +-
SCons/Tool/MSCommon/MSVC/Dispatcher.py | 1 +
SCons/Tool/MSCommon/MSVC/NotFound.py | 3 ++-
SCons/Tool/MSCommon/MSVC/Registry.py | 3 ++-
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 3 ++-
SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py | 2 +-
SCons/Tool/MSCommon/MSVC/WinSDK.py | 3 ++-
SCons/Tool/MSCommon/MSVC/__init__.py | 7 +------
SCons/Tool/MSCommon/__init__.py | 6 ------
SCons/Tool/MSCommon/vc.py | 6 ++++++
10 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
index 476dcb3..8f3a2cc 100644
--- a/SCons/Tool/MSCommon/MSVC/Config.py
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -30,9 +30,9 @@ from collections import (
)
from . import Dispatcher
-
Dispatcher.register_modulename(__name__)
+
UNDEFINED = object()
BOOLEAN_SYMBOLS = {}
diff --git a/SCons/Tool/MSCommon/MSVC/Dispatcher.py b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
index ebcd704..0b216ca 100644
--- a/SCons/Tool/MSCommon/MSVC/Dispatcher.py
+++ b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
@@ -31,6 +31,7 @@ from ..common import (
debug,
)
+
_refs = []
def register_class(ref):
diff --git a/SCons/Tool/MSCommon/MSVC/NotFound.py b/SCons/Tool/MSCommon/MSVC/NotFound.py
index 7abe5ad..6ade285 100644
--- a/SCons/Tool/MSCommon/MSVC/NotFound.py
+++ b/SCons/Tool/MSCommon/MSVC/NotFound.py
@@ -36,15 +36,16 @@ from ..common import (
debug,
)
-from . import Dispatcher
from . import Config
from .Exceptions import (
MSVCVersionNotFound,
)
+from . import Dispatcher
Dispatcher.register_modulename(__name__)
+
_MSVC_NOTFOUND_POLICY_DEF = Config.MSVC_NOTFOUND_POLICY_INTERNAL['warning']
def _msvc_notfound_policy_lookup(symbol):
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
index 848b125..f9a5eb2 100644
--- a/SCons/Tool/MSCommon/MSVC/Registry.py
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -39,11 +39,12 @@ from .. common import (
read_reg,
)
-from . import Dispatcher
from . import Util
+from . import Dispatcher
Dispatcher.register_modulename(__name__)
+
def read_value(hkey, subkey_valname):
try:
rval = read_reg(subkey_valname, hkroot=hkey)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 324f8be..1b02396 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -37,7 +37,6 @@ from ..common import (
debug,
)
-from . import Dispatcher
from . import Util
from . import Config
from . import WinSDK
@@ -47,8 +46,10 @@ from .Exceptions import (
MSVCArgumentError,
)
+from . import Dispatcher
Dispatcher.register_modulename(__name__)
+
# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
re_sdk_version_81 = re.compile(r'^8[.]1$')
diff --git a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
index 8a79007..8b9faa9 100644
--- a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
+++ b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
@@ -44,9 +44,9 @@ from .. common import (
)
from . import Dispatcher
-
Dispatcher.register_modulename(__name__)
+
class _Data:
separator = r';'
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
index e95c72e..bd8d9b0 100644
--- a/SCons/Tool/MSCommon/MSVC/WinSDK.py
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -31,7 +31,6 @@ from ..common import (
debug,
)
-from . import Dispatcher
from . import Util
from . import Config
from . import Registry
@@ -40,8 +39,10 @@ from .Exceptions import (
MSVCInternalError,
)
+from . import Dispatcher
Dispatcher.register_modulename(__name__)
+
def _new_sdk_map():
sdk_map = {
'desktop': [],
diff --git a/SCons/Tool/MSCommon/MSVC/__init__.py b/SCons/Tool/MSCommon/MSVC/__init__.py
index afd993f..1341415 100644
--- a/SCons/Tool/MSCommon/MSVC/__init__.py
+++ b/SCons/Tool/MSCommon/MSVC/__init__.py
@@ -28,8 +28,6 @@ Functions for Microsoft Visual C/C++.
from . import Exceptions
from . import Util
-from . import Dispatcher as _Dispatcher
-
from . import Config
from . import Registry
from . import SetupEnvDefault
@@ -37,10 +35,7 @@ from . import NotFound
from . import WinSDK
from . import ScriptArguments
-from .NotFound import (
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
-)
+from . import Dispatcher as _Dispatcher
def reset():
_Dispatcher.reset()
diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py
index 9f35e94..7900a87 100644
--- a/SCons/Tool/MSCommon/__init__.py
+++ b/SCons/Tool/MSCommon/__init__.py
@@ -32,18 +32,12 @@ import SCons.Util
from SCons.Tool.MSCommon.sdk import mssdk_exists, mssdk_setup_env
-from SCons.Tool.MSCommon.MSVC import (
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
-)
-
from SCons.Tool.MSCommon.vc import (
msvc_exists,
msvc_setup_env_tool,
msvc_setup_env_once,
msvc_version_to_maj_min,
msvc_find_vswhere,
- get_msvc_sdk_versions,
)
from SCons.Tool.MSCommon.vs import (
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 2e5d542..a2e8e42 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -61,10 +61,16 @@ from .common import CONFIG_CACHE, debug
from .sdk import get_installed_sdks
from . import MSVC
+
from .MSVC.Exceptions import (
VisualCException
)
+from .MSVC.NotFound import (
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+)
+
class UnsupportedVersion(VisualCException):
pass
--
cgit v0.12
From a7c56cebc24fd5aaa2dd05a1751412120c946835 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 18:36:54 -0400
Subject: Fix msvc notfound policy module path for test
---
test/fixture/no_msvc/no_msvcs_sconstruct_version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/fixture/no_msvc/no_msvcs_sconstruct_version.py b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
index f5cabf7..4c76d44 100644
--- a/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
+++ b/test/fixture/no_msvc/no_msvcs_sconstruct_version.py
@@ -10,7 +10,7 @@ for key in SCons.Tool.MSCommon.vc._VCVER_TO_PRODUCT_DIR:
SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
-SCons.Tool.MSCommon.set_msvc_notfound_policy('error')
+SCons.Tool.MSCommon.vc.set_msvc_notfound_policy('error')
env = SCons.Environment.Environment(MSVC_VERSION='14.3')
--
cgit v0.12
From f6a7b846bba8477ca8221edd2b76dc3d1d842439 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 20 Jun 2022 21:48:57 -0400
Subject: Add global for cache reset (classmethod to module omission) and
remove duplicate import
---
SCons/Tool/MSCommon/MSVC/Registry.py | 2 --
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 2 ++
SCons/Tool/MSCommon/MSVC/WinSDK.py | 2 ++
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
index f9a5eb2..492f3d0 100644
--- a/SCons/Tool/MSCommon/MSVC/Registry.py
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -30,8 +30,6 @@ import os
from SCons.Util import (
HKEY_LOCAL_MACHINE,
HKEY_CURRENT_USER,
- HKEY_LOCAL_MACHINE,
- HKEY_CURRENT_USER,
)
from .. common import (
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 1b02396..d0fc6ef 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -373,6 +373,8 @@ _toolset_version_cache = {}
_toolset_default_cache = {}
def _reset_toolset_cache():
+ global _toolset_version_cache
+ global _toolset_default_cache
debug('reset: toolset cache')
_toolset_version_cache = {}
_toolset_default_cache = {}
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
index bd8d9b0..8338c27 100644
--- a/SCons/Tool/MSCommon/MSVC/WinSDK.py
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -152,6 +152,8 @@ _sdk_map_cache = {}
_sdk_cache = {}
def _reset_sdk_cache():
+ global _sdk_map_cache
+ global _sdk_cache
debug('')
_sdk_map_cache = {}
_sdk_cache = {}
--
cgit v0.12
From dd328cff200935a7f570396f06b93a3da82278d7 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 08:06:01 -0400
Subject: Suppress sider imported but unused for namespace. Restrict
MSVC_UWP_APP boolean symbols accepted.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 13 ++++++++-----
SCons/Tool/MSCommon/MSVC/__init__.py | 16 ++++++++--------
SCons/Tool/MSCommon/vc.py | 4 ++--
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index d0fc6ef..a64d9f4 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -50,6 +50,9 @@ from . import Dispatcher
Dispatcher.register_modulename(__name__)
+# MSVC_UWP_APP argument: boolean True
+_UWP_ARGUMENT_BOOLEAN_TRUE = (True, '1')
+
# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
re_sdk_version_81 = re.compile(r'^8[.]1$')
@@ -91,10 +94,10 @@ re_vcvars_toolset = re.compile(r'(?:(?(?:[-]{1,2}|[/])vc
re_vcvars_spectre = re.compile(r'(?:(?(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P\S*))(?:(?!\S)|$)',re.IGNORECASE)
# Force default sdk argument
-MSVC_FORCE_DEFAULT_SDK = False
+_MSVC_FORCE_DEFAULT_SDK = False
# Force default toolset argument
-MSVC_FORCE_DEFAULT_TOOLSET = False
+_MSVC_FORCE_DEFAULT_TOOLSET = False
# MSVC batch file arguments:
#
@@ -148,7 +151,7 @@ def _msvc_script_argument_uwp(env, msvc, arglist):
if not uwp_app:
return None
- if uwp_app not in Config.BOOLEAN_SYMBOLS[True]:
+ if uwp_app not in _UWP_ARGUMENT_BOOLEAN_TRUE:
return None
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
@@ -691,7 +694,7 @@ def msvc_script_arguments(env, version, vc_dir, arg):
else:
user_sdk = None
- if MSVC_FORCE_DEFAULT_SDK:
+ if _MSVC_FORCE_DEFAULT_SDK:
if not sdk_version and not user_sdk:
sdk_version = _msvc_script_default_sdk(env, msvc, platform_type, arglist)
@@ -705,7 +708,7 @@ def msvc_script_arguments(env, version, vc_dir, arg):
else:
user_toolset = None
- if MSVC_FORCE_DEFAULT_TOOLSET:
+ if _MSVC_FORCE_DEFAULT_TOOLSET:
if not toolset_version and not user_toolset:
toolset_version = _msvc_script_default_toolset(env, msvc, vc_dir, arglist)
diff --git a/SCons/Tool/MSCommon/MSVC/__init__.py b/SCons/Tool/MSCommon/MSVC/__init__.py
index 1341415..c07e849 100644
--- a/SCons/Tool/MSCommon/MSVC/__init__.py
+++ b/SCons/Tool/MSCommon/MSVC/__init__.py
@@ -25,15 +25,15 @@
Functions for Microsoft Visual C/C++.
"""
-from . import Exceptions
-from . import Util
+from . import Exceptions # noqa: F401
+from . import Util # noqa: F401
-from . import Config
-from . import Registry
-from . import SetupEnvDefault
-from . import NotFound
-from . import WinSDK
-from . import ScriptArguments
+from . import Config # noqa: F401
+from . import Registry # noqa: F401
+from . import SetupEnvDefault # noqa: F401
+from . import NotFound # noqa: F401
+from . import WinSDK # noqa: F401
+from . import ScriptArguments # noqa: F401
from . import Dispatcher as _Dispatcher
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index a2e8e42..2f1ec11 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -67,8 +67,8 @@ from .MSVC.Exceptions import (
)
from .MSVC.NotFound import (
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
+ set_msvc_notfound_policy, # noqa: F401
+ get_msvc_notfound_policy, # noqa: F401
)
class UnsupportedVersion(VisualCException):
--
cgit v0.12
From 5dd220bf7d625771acc7f7ca476275795029b560 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 08:59:21 -0400
Subject: Add internal, undocumented SCONS_CACHE_MSVC_FORCE_DEFAULTS
environment variable to force default SDK and toolset arguments.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index a64d9f4..8bef3f5 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -34,6 +34,7 @@ from collections import (
)
from ..common import (
+ CONFIG_CACHE,
debug,
)
@@ -50,6 +51,13 @@ from . import Dispatcher
Dispatcher.register_modulename(__name__)
+# Force default SDK and toolset arguments in cache
+_SCONS_CACHE_MSVC_FORCE_DEFAULTS = False
+if CONFIG_CACHE:
+ # SCONS_CACHE_MSVC_FORCE_DEFAULTS is internal and not documented.
+ if os.environ.get('SCONS_CACHE_MSVC_FORCE_DEFAULTS') in Config.BOOLEAN_SYMBOLS[True]:
+ _SCONS_CACHE_MSVC_FORCE_DEFAULTS = True
+
# MSVC_UWP_APP argument: boolean True
_UWP_ARGUMENT_BOOLEAN_TRUE = (True, '1')
@@ -99,6 +107,20 @@ _MSVC_FORCE_DEFAULT_SDK = False
# Force default toolset argument
_MSVC_FORCE_DEFAULT_TOOLSET = False
+def _msvc_force_default_sdk(force=True):
+ global _MSVC_FORCE_DEFAULT_SDK
+ _MSVC_FORCE_DEFAULT_SDK = force
+ debug('_MSVC_FORCE_DEFAULT_SDK=%s', repr(force))
+
+def _msvc_force_default_toolset(force=True):
+ global _MSVC_FORCE_DEFAULT_TOOLSET
+ _MSVC_FORCE_DEFAULT_TOOLSET = force
+ debug('_MSVC_FORCE_DEFAULT_TOOLSET=%s', repr(force))
+
+if _SCONS_CACHE_MSVC_FORCE_DEFAULTS:
+ _msvc_force_default_sdk(True)
+ _msvc_force_default_toolset(True)
+
# MSVC batch file arguments:
#
# VS2022: UWP, SDK, TOOLSET, SPECTRE
--
cgit v0.12
From ac9b54756cedd01c36bfbf1bca7d59f92fd08f15 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 10:08:53 -0400
Subject: Consider MSVC_TOOLSET_VERSION specification intent to use msvc tools.
Update boolean symbols accepted for uwp and spectre.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 9 +++++----
SCons/Tool/MSCommon/vc.py | 16 ++++++++++++----
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 8bef3f5..2a94650 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -58,8 +58,9 @@ if CONFIG_CACHE:
if os.environ.get('SCONS_CACHE_MSVC_FORCE_DEFAULTS') in Config.BOOLEAN_SYMBOLS[True]:
_SCONS_CACHE_MSVC_FORCE_DEFAULTS = True
-# MSVC_UWP_APP argument: boolean True
-_UWP_ARGUMENT_BOOLEAN_TRUE = (True, '1')
+# Script argument: boolean True
+_ARGUMENT_BOOLEAN_TRUE_LEGACY = (True, '1') # MSVC_UWP_APP
+_ARGUMENT_BOOLEAN_TRUE = (True,)
# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
@@ -173,7 +174,7 @@ def _msvc_script_argument_uwp(env, msvc, arglist):
if not uwp_app:
return None
- if uwp_app not in _UWP_ARGUMENT_BOOLEAN_TRUE:
+ if uwp_app not in _ARGUMENT_BOOLEAN_TRUE_LEGACY:
return None
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
@@ -610,7 +611,7 @@ def _msvc_script_argument_spectre(env, msvc, arglist):
if not spectre_libs:
return None
- if spectre_libs not in (True, '1'):
+ if spectre_libs not in _ARGUMENT_BOOLEAN_TRUE:
return None
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 2f1ec11..dc97e2f 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1300,12 +1300,20 @@ def msvc_setup_env_user(env=None):
if env:
# Intent is to use msvc tools:
- # MSVC_VERSION or MSVS_VERSION: defined and is True
- # MSVC_USE_SCRIPT: defined and (is string or is False)
- # MSVC_USE_SETTINGS: defined and is not None
+ # MSVC_VERSION: defined and evaluates True
+ # MSVS_VERSION: defined and evaluates True
+ # MSVC_TOOLSET_VERSION: defined and evaluates True
+ # MSVC_USE_SCRIPT: defined and (is string or evaluates False)
+ # MSVC_USE_SETTINGS: defined and is not None
+
+ # Arguments possibly present but not considered:
+ # MSVC_SDK_VERSION
+ # MSVC_UWP_APP
+ # MSVC_SPECTRE_LIBS
+ # MSVC_SCRIPT_ARGS
# defined and is True
- for key in ['MSVC_VERSION', 'MSVS_VERSION']:
+ for key in ['MSVC_VERSION', 'MSVS_VERSION', 'MSVC_TOOLSET_VERSION']:
if key in env and env[key]:
rval = True
debug('key=%s, return=%s', repr(key), rval)
--
cgit v0.12
From 377e8152bbd9cc4556318283c845dd66defe2d8c Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 10:11:29 -0400
Subject: Comment out BatchFileExecutionWarning definition and invocation.
---
SCons/Tool/MSCommon/vc.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index dc97e2f..7b6034e 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -95,8 +95,8 @@ class MSVCScriptNotFound(VisualCException):
class MSVCUseSettingsError(VisualCException):
pass
-class BatchFileExecutionWarning(SCons.Warnings.WarningOnByDefault):
- pass
+#class BatchFileExecutionWarning(SCons.Warnings.WarningOnByDefault):
+# pass
# Dict to 'canonalize' the arch
@@ -1055,7 +1055,7 @@ def script_env(script, args=None):
# detected errors, cl.exe on path
debug('script=%s args=%s errors=%s', repr(script), repr(args), script_errmsg)
# This may be a bad idea (scons environment != vs cmdline environment)
- SCons.Warnings.warn(BatchFileExecutionWarning, script_errmsg)
+ #SCons.Warnings.warn(BatchFileExecutionWarning, script_errmsg)
# TODO: errlog/errstr should be added to cache and warning moved to call site
# once we updated cache, give a chance to write out if user wanted
--
cgit v0.12
From 016e7f7bdc6b901916da08a361b5cca8c24ee600 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 10:26:36 -0400
Subject: Update flake8 F401 placement
---
SCons/Tool/MSCommon/vc.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 7b6034e..f34e9e0 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -67,9 +67,9 @@ from .MSVC.Exceptions import (
)
from .MSVC.NotFound import (
- set_msvc_notfound_policy, # noqa: F401
- get_msvc_notfound_policy, # noqa: F401
-)
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+) # noqa: F401
class UnsupportedVersion(VisualCException):
pass
--
cgit v0.12
From 56bd50d3a15cbe3c82e84bf703a3f4bf1e5615d5 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 10:32:31 -0400
Subject: Add comment and import one-by-one for msvc notfound policy and flake8
F401
---
SCons/Tool/MSCommon/vc.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index f34e9e0..56f21e8 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -66,10 +66,9 @@ from .MSVC.Exceptions import (
VisualCException
)
-from .MSVC.NotFound import (
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
-) # noqa: F401
+# msvc test(s) expect avaiable via vc
+from .MSVC.NotFound import set_msvc_notfound_policy # noqa: F401
+from .MSVC.NotFound import get_msvc_notfound_policy # noqa: F401
class UnsupportedVersion(VisualCException):
pass
--
cgit v0.12
From ad7a59d1621d4154aeb51ba402f77aa18d65e21d Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 10:38:05 -0400
Subject: Fix sider issue
---
SCons/Tool/MSCommon/vc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 56f21e8..5130727 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -66,7 +66,7 @@ from .MSVC.Exceptions import (
VisualCException
)
-# msvc test(s) expect avaiable via vc
+# msvc test(s) expect notfound policy available via vc
from .MSVC.NotFound import set_msvc_notfound_policy # noqa: F401
from .MSVC.NotFound import get_msvc_notfound_policy # noqa: F401
--
cgit v0.12
From a5938cce33f77237e45ad86a3f43e58f65ba74d3 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 11:22:29 -0400
Subject: Move SCONS_CACHE_MSVC_FORCE_DEFAULTS environment variable query to
MSCommon and set boolean if active.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 18 +++++++-----------
SCons/Tool/MSCommon/common.py | 5 +++++
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 2a94650..aa96946 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -34,7 +34,7 @@ from collections import (
)
from ..common import (
- CONFIG_CACHE,
+ CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS,
debug,
)
@@ -51,13 +51,6 @@ from . import Dispatcher
Dispatcher.register_modulename(__name__)
-# Force default SDK and toolset arguments in cache
-_SCONS_CACHE_MSVC_FORCE_DEFAULTS = False
-if CONFIG_CACHE:
- # SCONS_CACHE_MSVC_FORCE_DEFAULTS is internal and not documented.
- if os.environ.get('SCONS_CACHE_MSVC_FORCE_DEFAULTS') in Config.BOOLEAN_SYMBOLS[True]:
- _SCONS_CACHE_MSVC_FORCE_DEFAULTS = True
-
# Script argument: boolean True
_ARGUMENT_BOOLEAN_TRUE_LEGACY = (True, '1') # MSVC_UWP_APP
_ARGUMENT_BOOLEAN_TRUE = (True,)
@@ -118,9 +111,12 @@ def _msvc_force_default_toolset(force=True):
_MSVC_FORCE_DEFAULT_TOOLSET = force
debug('_MSVC_FORCE_DEFAULT_TOOLSET=%s', repr(force))
-if _SCONS_CACHE_MSVC_FORCE_DEFAULTS:
- _msvc_force_default_sdk(True)
- _msvc_force_default_toolset(True)
+def msvc_force_default_arguments(force=True):
+ _msvc_force_default_sdk(force)
+ _msvc_force_default_toolset(force)
+
+if CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS:
+ msvc_force_default_arguments(force=True)
# MSVC batch file arguments:
#
diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py
index c9f07f5..da8fd55 100644
--- a/SCons/Tool/MSCommon/common.py
+++ b/SCons/Tool/MSCommon/common.py
@@ -102,6 +102,11 @@ CONFIG_CACHE = os.environ.get('SCONS_CACHE_MSVC_CONFIG')
if CONFIG_CACHE in ('1', 'true', 'True'):
CONFIG_CACHE = os.path.join(os.path.expanduser('~'), 'scons_msvc_cache.json')
+# SCONS_CACHE_MSVC_FORCE_DEFAULTS is internal-use so undocumented.
+CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS = False
+if CONFIG_CACHE:
+ if os.environ.get('SCONS_CACHE_MSVC_FORCE_DEFAULTS') in ('1', 'true', 'True'):
+ CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS = True
def read_script_env_cache():
""" fetch cached msvc env vars if requested, else return empty dict """
--
cgit v0.12
From 52e349c07058d6b7b2b5eb46ae6371427bee9849 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 12:37:03 -0400
Subject: Remove debug messages that by default are noisy.
---
SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py | 2 --
SCons/Tool/MSCommon/vc.py | 7 ++-----
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
index 8b9faa9..e1c05bc 100644
--- a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
+++ b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
@@ -73,7 +73,6 @@ def _initialize(env, msvc_exists_func):
debug('msvc default:msvc_installed=%s', _Data.msvc_installed)
def register_tool(env, tool, msvc_exists_func):
- debug('msvc default:tool=%s', tool)
if _Data.need_init:
_initialize(env, msvc_exists_func)
if _Data.msvc_installed:
@@ -90,7 +89,6 @@ def register_tool(env, tool, msvc_exists_func):
debug('msvc default:tool=%s, msvc_tools=%s', tool, _Data.msvc_tools)
def register_setup(env, msvc_exists_func):
- debug('msvc default')
if _Data.need_init:
_initialize(env, msvc_exists_func)
_Data.n_setup += 1
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 5130727..7ea3583 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1102,7 +1102,6 @@ def msvc_setup_env_once(env, tool=None):
has_run = False
if not has_run:
- debug('tool=%s', repr(tool))
MSVC.SetupEnvDefault.register_setup(env, msvc_exists)
msvc_setup_env(env)
env["MSVC_SETUP_RUN"] = True
@@ -1285,13 +1284,13 @@ def msvc_setup_env(env):
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
def msvc_exists(env=None, version=None):
- debug('version=%s', repr(version))
vcs = get_installed_vcs(env)
if version is None:
rval = len(vcs) > 0
else:
rval = version in vcs
- debug('version=%s, return=%s', repr(version), rval)
+ if not rval:
+ debug('version=%s, return=%s', repr(version), rval)
return rval
def msvc_setup_env_user(env=None):
@@ -1336,14 +1335,12 @@ def msvc_setup_env_user(env=None):
return rval
def msvc_setup_env_tool(env=None, version=None, tool=None):
- debug('tool=%s, version=%s', repr(tool), repr(version))
MSVC.SetupEnvDefault.register_tool(env, tool, msvc_exists)
rval = False
if not rval and msvc_exists(env, version):
rval = True
if not rval and msvc_setup_env_user(env):
rval = True
- debug('tool=%s, version=%s, return=%s', repr(tool), repr(version), rval)
return rval
def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
--
cgit v0.12
From 7683a2f958287ceee257b0449eed767b0dd275e5 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 21 Jun 2022 12:46:14 -0400
Subject: Remove MSVC_TOOLSET_VERSION from intent to use msvc tools (attached
to default version or specific version).
---
SCons/Tool/MSCommon/vc.py | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 7ea3583..675b8d0 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1304,14 +1304,8 @@ def msvc_setup_env_user(env=None):
# MSVC_USE_SCRIPT: defined and (is string or evaluates False)
# MSVC_USE_SETTINGS: defined and is not None
- # Arguments possibly present but not considered:
- # MSVC_SDK_VERSION
- # MSVC_UWP_APP
- # MSVC_SPECTRE_LIBS
- # MSVC_SCRIPT_ARGS
-
# defined and is True
- for key in ['MSVC_VERSION', 'MSVS_VERSION', 'MSVC_TOOLSET_VERSION']:
+ for key in ['MSVC_VERSION', 'MSVS_VERSION']:
if key in env and env[key]:
rval = True
debug('key=%s, return=%s', repr(key), rval)
--
cgit v0.12
From 98cf01fd1434463a7af5b3fe5375a9772882dcd2 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 22 Jun 2022 16:53:53 -0400
Subject: Reorder function declarations
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 46 ++++++++++++++---------------
1 file changed, 23 insertions(+), 23 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index aa96946..e56dd4a 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -629,6 +629,29 @@ def _msvc_script_argument_spectre(env, msvc, arglist):
return spectre_arg
+def _user_script_argument_spectre(env, spectre, user_argstr):
+
+ matches = [m for m in re_vcvars_spectre.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not spectre:
+ return None
+
+ env_argstr = env.get('MSVC_SPECTRE_LIBS','')
+ debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
def _msvc_script_argument_user(env, msvc, arglist):
# subst None -> empty string
@@ -655,29 +678,6 @@ def _msvc_script_argument_user(env, msvc, arglist):
return script_args
-def _user_script_argument_spectre(env, spectre, user_argstr):
-
- matches = [m for m in re_vcvars_spectre.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not spectre:
- return None
-
- env_argstr = env.get('MSVC_SPECTRE_LIBS','')
- debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
def msvc_script_arguments(env, version, vc_dir, arg):
arglist = []
--
cgit v0.12
From 1de714ae3085d9fd07cb8837f523037885271aa8 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 23 Jun 2022 18:58:38 -0400
Subject: Construction variable documentation additions and modifications.
---
SCons/Tool/msvc.xml | 553 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 542 insertions(+), 11 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index e8df128..6663aab 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -481,9 +481,24 @@ env = Environment(MSVC_VERSION='8.0', MSVC_USE_SETTINGS=msvc_use_settings)
-Note: the dictionary content requirements are based on the internal msvc implementation and
-therefore may change at any time. The burden is on the user to ensure the dictionary contents
-are minimally sufficient to ensure successful builds.
+Important usage details:
+
+
+
+MSVC_USE_SETTINGS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The dictionary content requirements are based on the internal msvc implementation and
+therefore may change at any time.
+
+The burden is on the user to ensure the dictionary contents are minimally sufficient to
+ensure successful builds.
+
+
+
@@ -510,21 +525,65 @@ are minimally sufficient to ensure successful builds.
-Build libraries for a Universal Windows Platform (UWP) Application.
+Build with the Universal Windows Platform (UWP) application Visual C++ libraries.
-If &cv-MSVC_UWP_APP; is set, the Visual C++ environment will be set up to point
+The valid values for MSVC_UWP_APP are True,
+'1', False, '0',
+or None.
+
+
+
+When MSVC_UWP_APP is enabled (i.e., True or
+'1'), the Visual C++ environment will be set up to point
to the Windows Store compatible libraries and Visual C++ 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 or later.
-This variable must be passed as an argument to the Environment()
-constructor; setting it later has no effect.
+
+
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+
+
+MSVC_UWP_APP is enabled and a UWP argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via MSVC_UWP_APP
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
-Valid values are '1' or '0'
+Example - A Visual Studio 2022 build for the Universal Windows Platform:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_UWP_APP=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_UWP_APP must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The existence of the UWP libraries is not verified when MSVC_UWP_APP is enabled
+which could result in build failures.
+
+The burden is on the user to ensure the requisite UWP libraries are installed.
+
+
+
@@ -582,7 +641,7 @@ and also before &f-link-env-Tool; is called to ininitialize any of those tools:
-Specify the scons behavior when the Microsoft Visual C/C++ compiler is not detected.
+Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not detected.
@@ -590,7 +649,7 @@ Specify the scons behavior when the Microsoft Visual C/C++ compiler is not detec
when the requested msvc version is not detected.
-
+
The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; behavior are:
@@ -664,13 +723,485 @@ A non-default tool list is specified that does not contain any of the msvc tools
+Important usage details:
+
+
+
+MSVC_NOTFOUND_POLICY must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+
+
When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue
subject to the conditions listed above. The default &scons; behavior may change in the future.
+
+
+
+
+
+
+Pass user-defined arguments to the Visual C++ batch file determined via autodetection.
+
+
+
+MSVC_SCRIPT_ARGS is available for msvc batch file arguments that do not have first-class support
+via construction variables or when there is an issue with the appropriate construction variable validation.
+When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;)
+rather than MSVC_SCRIPT_ARGS arguments.
+
+
+
+The valid values for MSVC_SCRIPT_ARGS are: None, a string,
+or a list of strings.
+
+
+
+The MSVC_SCRIPT_ARGS value is converted to a scalar string (i.e., "flattened").
+The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined
+via autodetection subject to the validation conditions listed below.
+
+
+
+MSVC_SCRIPT_ARGS is ignored when the value is None and when the
+result from argument conversion is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SCRIPT_ARGS is specified for Visual Studio 2013 and earlier.
+
+
+
+Multiple SDK version arguments (e.g., '10.0.20348.0') are specified
+in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument
+(e.g., '10.0.20348.0') is specified in MSVC_SCRIPT_ARGS.
+Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and MSVC_SCRIPT_ARGS
+are not allowed.
+
+
+
+Multiple toolset version arguments (e.g., '-vcvars_ver=14.29')
+are specified in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument
+(e.g., '-vcvars_ver=14.29') is specified in MSVC_SCRIPT_ARGS.
+Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and
+MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre')
+are specified in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument
+(e.g., '-vcvars_spectre_libs=spectre') is specified in
+MSVC_SCRIPT_ARGS. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
+and MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+Multiple UWP arguments (e.g., uwp or store) are specified
+in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or
+store) is specified in MSVC_SCRIPT_ARGS. Multiple UWP declarations
+via &cv-link-MSVC_UWP_APP; and MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+
+
+
+Example 1 - A Visual Studio 2022 build with an SDK version and a toolset version
+specified with a string argument:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS='10.0.20348.0 -vcvars_ver=14.29.30133')
+
+
+
+
+Example 2 - A Visual Studio 2022 build with an SDK version and a toolset version
+specified with a list argument:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['10.0.20348.0', '-vcvars_ver=14.29.30133'])
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SCRIPT_ARGS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+Other than checking for multiple declarations as described above, MSVC_SCRIPT_ARGS arguments
+are not validated.
+
+
+
+
+Erroneous, inconsistent, and/or version incompatible MSVC_SCRIPT_ARGS arguments are likely
+to result in build failures for reasons that are not readily apparent and may be difficult to diagnose.
+
+The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent
+and compatible with the version of msvc selected.
+
+
+
+
+
+
+
+Build with a specific version of the Microsoft Software Development Kit (SDK).
+
+
+
+The valid values for MSVC_SDK_VERSION are: None
+or a string containing the requested SDK version (e.g., '10.0.20348.0').
+
+
+
+MSVC_SDK_VERSION is ignored when the value is None and when
+the value is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SDK_VERSION is specified for Visual Studio 2013 and earlier.
+
+
+
+MSVC_SDK_VERSION is specified and an SDK version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via MSVC_SDK_VERSION
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+The MSVC_SDK_VERSION specified does not match any of the supported formats:
+
+
+'10.0.XXXXX.Y' [SDK 10.0]
+
+
+'8.1' [SDK 8.1]
+
+
+
+
+
+The system folder for the corresponding MSVC_SDK_VERSION version is not found.
+The requested SDK version does not appear to be installed.
+
+
+
+The MSVC_SDK_VERSION version does not appear to support the requested platform
+type (i.e., UWP or Desktop). The requested SDK version
+platform type components do not appear to be installed.
+
+
+
+
+
+
+Example 1 - A Visual Studio 2022 build with a specific Windows SDK version:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0')
+
+
+
+
+Example 2 - A Visual Studio 2022 build with a specific SDK version for the Universal Windows Platform:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0', MSVC_UWP_APP=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SDK_VERSION must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+Should a SDK 10.0 version be installed that does not follow the naming scheme above, the
+SDK version will need to be specified via &cv-link-MSVC_SCRIPT_ARGS; until the version number
+validation format can be extended.
+
+
+
+
+Should an exception be raised indicating that the SDK version is not found, verify that
+the requested SDK version is installed with the necessary platform type components.
+
+
+
+There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
+when using the v141 build tools and the target architecture is ARM64.
+Should build failures arise with this combination of settings, MSVC_SDK_VERSION may be
+employed to specify a different SDK version for the build.
+
+
+
+
+
+
+
+
+
+
+
+Build with a specific Visual C++ toolset version.
+
+
+
+Specifying MSVC_TOOLSET_VERSION does not affect the autodetection and selection
+of msvc instances. The MSVC_TOOLSET_VERSION is applied after
+an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION;
+is not specified.
+
+
+
+The valid values for MSVC_TOOLSET_VERSION are: None
+or a string containing the requested toolset version (e.g., '14.29').
+
+
+
+MSVC_TOOLSET_VERSION is ignored when the value is None and when
+the value is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_TOOLSET_VERSION is specified for Visual Studio 2015 and earlier.
+
+
+
+MSVC_TOOLSET_VERSION is specified and a toolset version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via MSVC_TOOLSET_VERSION
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+
+The MSVC_TOOLSET_VERSION specified does not match any of the supported formats:
+
+
+
+
+
+'XX.Y'
+
+
+
+'XX.YY'
+
+
+
+'XX.YY.ZZZZZ'
+
+
+
+'XX.YY.Z' to 'XX.YY.ZZZZ'
+
+[&scons; extension not directly supported by the msvc batch files and may be removed in the future]
+
+
+
+
+'XX.YY.ZZ.N' [SxS format]
+
+
+
+'XX.YY.ZZ.NN' [SxS format]
+
+
+
+
+
+
+
+The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
+is for Visual Studio 2013 and earlier (e.g., '12.0').
+
+
+
+The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
+is greater than the msvc version selected (e.g., '99.0').
+
+
+
+A system folder for the corresponding MSVC_TOOLSET_VERSION version is not found.
+The requested toolset version does not appear to be installed.
+
+
+
+
+
+
+Toolset selection details:
+
+
+
+SxS version numbers are not always in three dot format (e.g., 'XX.YY.ZZ.NN') as shown above.
+
+In Visual Studio 2022 for example, 14.16 is an SxS toolset version that is directly
+mapped to toolset version 14.16.27023.
+
+
+
+When MSVC_TOOLSET_VERSION is not an SxS version number or a full toolset version number:
+the first toolset version, ranked in descending order, that matches the MSVC_TOOLSET_VERSION
+prefix is selected.
+
+
+
+When MSVC_TOOLSET_VERSION is specified using the major msvc version prefix
+(i.e., 'XX.Y') and the major msvc version is that of the latest release of
+Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version.
+
+In the latest release of Visual Studio, the default Visual C++ toolset version is not necessarily the
+toolset with the largest version number.
+
+
+
+
+
+
+Example environment constructor invocations with toolset version specifications:
+
+Environment(MSVC_TOOLSET_VERSION='14.2')
+Environment(MSVC_TOOLSET_VERSION='14.29')
+Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
+Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
+
+
+
+
+Important usage details:
+
+
+
+MSVC_TOOLSET_VERSION must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The existence of the toolset host architecture and target architecture folders are not verified
+when MSVC_TOOLSET_VERSION is specified which could result in build failures.
+
+The burden is on the user to ensure the requisite toolset target architecture build tools are installed.
+
+
+
+
+
+
+
+
+
+
+
+Build with the spectre-mitigated Visual C++ libraries.
+
+
+
+The valid values for MSVC_SPECTRE_LIBS are: True,
+False, or None.
+
+
+
+When MSVC_SPECTRE_LIBS is enabled (i.e., True),
+the Visual C++ environment will include the paths to the spectre-mitigated implementations
+of the Microsoft Visual C++ libraries.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SPECTRE_LIBS is enabled for Visual Studio 2015 and earlier.
+
+
+
+MSVC_SPECTRE_LIBS is enabled and a spectre library argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via MSVC_SPECTRE_LIBS
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+
+
+
+Example - A Visual Studio 2022 build with spectre mitigated Visual C++ libraries:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SPECTRE_LIBS=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SPECTRE_LIBS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+Additional compiler switches (e.g., /Qspectre) are necessary for including
+spectre mitigations when building user artifacts. Refer to the Visual Studio documentation for
+details.
+
+
+
+
+The existence of the spectre mitigations libraries is not verified when MSVC_SPECTRE_LIBS
+is enabled which could result in build failures.
+
+The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
+
+
+
+
+
+
+
--
cgit v0.12
From f99f7cab7bc3af5ef18e3189f531572df4558fe4 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Thu, 23 Jun 2022 18:59:01 -0400
Subject: Construction variable documentation additions and modifications.
---
doc/generated/variables.gen | 558 +++++++++++++++++++++++++++++++++++++++++++-
doc/generated/variables.mod | 8 +
2 files changed, 555 insertions(+), 11 deletions(-)
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 996e35a..f1b3fff 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -4686,7 +4686,7 @@ will be compiled separately.
MSVC_NOTFOUND_POLICY
-Specify the scons behavior when the Microsoft Visual C/C++ compiler is not detected.
+Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not detected.
@@ -4694,7 +4694,7 @@ Specify the scons behavior when the Microsoft Visual C/C++ compiler is not detec
when the requested msvc version is not detected.
-
+
The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; behavior are:
@@ -4768,10 +4768,487 @@ A non-default tool list is specified that does not contain any of the msvc tools
+Important usage details:
+
+
+
+MSVC_NOTFOUND_POLICY must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+
+
When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue
subject to the conditions listed above. The default &scons; behavior may change in the future.
+
+
+
+
+ MSVC_SCRIPT_ARGS
+
+
+Pass user-defined arguments to the Visual C++ batch file determined via autodetection.
+
+
+
+MSVC_SCRIPT_ARGS is available for msvc batch file arguments that do not have first-class support
+via construction variables or when there is an issue with the appropriate construction variable validation.
+When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;)
+rather than MSVC_SCRIPT_ARGS arguments.
+
+
+
+The valid values for MSVC_SCRIPT_ARGS are: None, a string,
+or a list of strings.
+
+
+
+The MSVC_SCRIPT_ARGS value is converted to a scalar string (i.e., "flattened").
+The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined
+via autodetection subject to the validation conditions listed below.
+
+
+
+MSVC_SCRIPT_ARGS is ignored when the value is None and when the
+result from argument conversion is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SCRIPT_ARGS is specified for Visual Studio 2013 and earlier.
+
+
+
+Multiple SDK version arguments (e.g., '10.0.20348.0') are specified
+in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument
+(e.g., '10.0.20348.0') is specified in MSVC_SCRIPT_ARGS.
+Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and MSVC_SCRIPT_ARGS
+are not allowed.
+
+
+
+Multiple toolset version arguments (e.g., '-vcvars_ver=14.29')
+are specified in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument
+(e.g., '-vcvars_ver=14.29') is specified in MSVC_SCRIPT_ARGS.
+Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and
+MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre')
+are specified in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument
+(e.g., '-vcvars_spectre_libs=spectre') is specified in
+MSVC_SCRIPT_ARGS. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
+and MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+Multiple UWP arguments (e.g., uwp or store) are specified
+in MSVC_SCRIPT_ARGS.
+
+
+
+&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or
+store) is specified in MSVC_SCRIPT_ARGS. Multiple UWP declarations
+via &cv-link-MSVC_UWP_APP; and MSVC_SCRIPT_ARGS are not allowed.
+
+
+
+
+
+
+Example 1 - A Visual Studio 2022 build with an SDK version and a toolset version
+specified with a string argument:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS='10.0.20348.0 -vcvars_ver=14.29.30133')
+
+
+
+
+Example 2 - A Visual Studio 2022 build with an SDK version and a toolset version
+specified with a list argument:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SCRIPT_ARGS=['10.0.20348.0', '-vcvars_ver=14.29.30133'])
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SCRIPT_ARGS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+Other than checking for multiple declarations as described above, MSVC_SCRIPT_ARGS arguments
+are not validated.
+
+
+
+
+Erroneous, inconsistent, and/or version incompatible MSVC_SCRIPT_ARGS arguments are likely
+to result in build failures for reasons that are not readily apparent and may be difficult to diagnose.
+
+The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent
+and compatible with the version of msvc selected.
+
+
+
+
+
+
+
+
+
+ MSVC_SDK_VERSION
+
+
+Build with a specific version of the Microsoft Software Development Kit (SDK).
+
+
+
+The valid values for MSVC_SDK_VERSION are: None
+or a string containing the requested SDK version (e.g., '10.0.20348.0').
+
+
+
+MSVC_SDK_VERSION is ignored when the value is None and when
+the value is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SDK_VERSION is specified for Visual Studio 2013 and earlier.
+
+
+
+MSVC_SDK_VERSION is specified and an SDK version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via MSVC_SDK_VERSION
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+The MSVC_SDK_VERSION specified does not match any of the supported formats:
+
+
+'10.0.XXXXX.Y' [SDK 10.0]
+
+
+'8.1' [SDK 8.1]
+
+
+
+
+
+The system folder for the corresponding MSVC_SDK_VERSION version is not found.
+The requested SDK version does not appear to be installed.
+
+
+
+The MSVC_SDK_VERSION version does not appear to support the requested platform
+type (i.e., UWP or Desktop). The requested SDK version
+platform type components do not appear to be installed.
+
+
+
+
+
+
+Example 1 - A Visual Studio 2022 build with a specific Windows SDK version:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0')
+
+
+
+
+Example 2 - A Visual Studio 2022 build with a specific SDK version for the Universal Windows Platform:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SDK_VERSION='10.0.20348.0', MSVC_UWP_APP=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SDK_VERSION must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+Should a SDK 10.0 version be installed that does not follow the naming scheme above, the
+SDK version will need to be specified via &cv-link-MSVC_SCRIPT_ARGS; until the version number
+validation format can be extended.
+
+
+
+
+Should an exception be raised indicating that the SDK version is not found, verify that
+the requested SDK version is installed with the necessary platform type components.
+
+
+
+There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
+when using the v141 build tools and the target architecture is ARM64.
+Should build failures arise with this combination of settings, MSVC_SDK_VERSION may be
+employed to specify a different SDK version for the build.
+
+
+
+
+
+
+
+
+
+ MSVC_SPECTRE_LIBS
+
+
+Build with the spectre-mitigated Visual C++ libraries.
+
+
+
+The valid values for MSVC_SPECTRE_LIBS are: True,
+False, or None.
+
+
+
+When MSVC_SPECTRE_LIBS is enabled (i.e., True),
+the Visual C++ environment will include the paths to the spectre-mitigated implementations
+of the Microsoft Visual C++ libraries.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_SPECTRE_LIBS is enabled for Visual Studio 2015 and earlier.
+
+
+
+MSVC_SPECTRE_LIBS is enabled and a spectre library argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via MSVC_SPECTRE_LIBS
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+
+
+
+Example - A Visual Studio 2022 build with spectre mitigated Visual C++ libraries:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_SPECTRE_LIBS=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_SPECTRE_LIBS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+Additional compiler switches (e.g., /Qspectre) are necessary for including
+spectre mitigations when building user artifacts. Refer to the Visual Studio documentation for
+details.
+
+
+
+
+The existence of the spectre mitigations libraries is not verified when MSVC_SPECTRE_LIBS
+is enabled which could result in build failures.
+
+The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
+
+
+
+
+
+
+
+
+
+ MSVC_TOOLSET_VERSION
+
+
+Build with a specific Visual C++ toolset version.
+
+
+
+Specifying MSVC_TOOLSET_VERSION does not affect the autodetection and selection
+of msvc instances. The MSVC_TOOLSET_VERSION is applied after
+an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION;
+is not specified.
+
+
+
+The valid values for MSVC_TOOLSET_VERSION are: None
+or a string containing the requested toolset version (e.g., '14.29').
+
+
+
+MSVC_TOOLSET_VERSION is ignored when the value is None and when
+the value is an empty string. The validation conditions below do not apply.
+
+
+
+An exception is raised when any of the following conditions are satisfied:
+
+
+
+MSVC_TOOLSET_VERSION is specified for Visual Studio 2015 and earlier.
+
+
+
+MSVC_TOOLSET_VERSION is specified and a toolset version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via MSVC_TOOLSET_VERSION
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+
+The MSVC_TOOLSET_VERSION specified does not match any of the supported formats:
+
+
+
+
+
+'XX.Y'
+
+
+
+'XX.YY'
+
+
+
+'XX.YY.ZZZZZ'
+
+
+
+'XX.YY.Z' to 'XX.YY.ZZZZ'
+
+[&scons; extension not directly supported by the msvc batch files and may be removed in the future]
+
+
+
+
+'XX.YY.ZZ.N' [SxS format]
+
+
+
+'XX.YY.ZZ.NN' [SxS format]
+
+
+
+
+
+
+
+The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
+is for Visual Studio 2013 and earlier (e.g., '12.0').
+
+
+
+The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
+is greater than the msvc version selected (e.g., '99.0').
+
+
+
+A system folder for the corresponding MSVC_TOOLSET_VERSION version is not found.
+The requested toolset version does not appear to be installed.
+
+
+
+
+
+
+Toolset selection details:
+
+
+
+SxS version numbers are not always in three dot format (e.g., 'XX.YY.ZZ.NN') as shown above.
+
+In Visual Studio 2022 for example, 14.16 is an SxS toolset version that is directly
+mapped to toolset version 14.16.27023.
+
+
+
+When MSVC_TOOLSET_VERSION is not an SxS version number or a full toolset version number:
+the first toolset version, ranked in descending order, that matches the MSVC_TOOLSET_VERSION
+prefix is selected.
+
+
+
+When MSVC_TOOLSET_VERSION is specified using the major msvc version prefix
+(i.e., 'XX.Y') and the major msvc version is that of the latest release of
+Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version.
+
+In the latest release of Visual Studio, the default Visual C++ toolset version is not necessarily the
+toolset with the largest version number.
+
+
+
+
+
+
+Example environment constructor invocations with toolset version specifications:
+
+Environment(MSVC_TOOLSET_VERSION='14.2')
+Environment(MSVC_TOOLSET_VERSION='14.29')
+Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
+Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
+
+
+
+
+Important usage details:
+
+
+
+MSVC_TOOLSET_VERSION must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The existence of the toolset host architecture and target architecture folders are not verified
+when MSVC_TOOLSET_VERSION is specified which could result in build failures.
+
+The burden is on the user to ensure the requisite toolset target architecture build tools are installed.
+
+
+
+
@@ -4879,9 +5356,24 @@ env = Environment(MSVC_VERSION='8.0', MSVC_USE_SETTINGS=msvc_use_settings)
-Note: the dictionary content requirements are based on the internal msvc implementation and
-therefore may change at any time. The burden is on the user to ensure the dictionary contents
-are minimally sufficient to ensure successful builds.
+Important usage details:
+
+
+
+MSVC_USE_SETTINGS must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The dictionary content requirements are based on the internal msvc implementation and
+therefore may change at any time.
+
+The burden is on the user to ensure the dictionary contents are minimally sufficient to
+ensure successful builds.
+
+
+
@@ -4891,21 +5383,65 @@ are minimally sufficient to ensure successful builds.
MSVC_UWP_APP
-Build libraries for a Universal Windows Platform (UWP) Application.
+Build with the Universal Windows Platform (UWP) application Visual C++ libraries.
+
+
+
+The valid values for MSVC_UWP_APP are True,
+'1', False, '0',
+or None.
-If &cv-MSVC_UWP_APP; is set, the Visual C++ environment will be set up to point
+When MSVC_UWP_APP is enabled (i.e., True or
+'1'), the Visual C++ environment will be set up to point
to the Windows Store compatible libraries and Visual C++ 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 or later.
-This variable must be passed as an argument to the Environment()
-constructor; setting it later has no effect.
+
+
-Valid values are '1' or '0'
+An exception is raised when any of the following conditions are satisfied:
+
+
+MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+
+
+MSVC_UWP_APP is enabled and a UWP argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via MSVC_UWP_APP
+and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+
+
+
+
+Example - A Visual Studio 2022 build for the Universal Windows Platform:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_UWP_APP=True)
+
+
+
+
+Important usage details:
+
+
+
+MSVC_UWP_APP must be passed as an argument to the Environment() constructor;
+setting it later has no effect.
+
+
+
+
+The existence of the UWP libraries is not verified when MSVC_UWP_APP is enabled
+which could result in build failures.
+
+The burden is on the user to ensure the requisite UWP libraries are installed.
+
+
+
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index c5cd0cd..d3d29f2 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -321,6 +321,10 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MSSDK_VERSION">
$MSVC_BATCH">
$MSVC_NOTFOUND_POLICY">
+$MSVC_SCRIPT_ARGS">
+$MSVC_SDK_VERSION">
+$MSVC_SPECTRE_LIBS">
+$MSVC_TOOLSET_VERSION">
$MSVC_USE_SCRIPT">
$MSVC_USE_SCRIPT_ARGS">
$MSVC_USE_SETTINGS">
@@ -985,6 +989,10 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$MSSDK_VERSION">
$MSVC_BATCH">
$MSVC_NOTFOUND_POLICY">
+$MSVC_SCRIPT_ARGS">
+$MSVC_SDK_VERSION">
+$MSVC_SPECTRE_LIBS">
+$MSVC_TOOLSET_VERSION">
$MSVC_USE_SCRIPT">
$MSVC_USE_SCRIPT_ARGS">
$MSVC_USE_SETTINGS">
--
cgit v0.12
From 623cdba27514874cd1af6e09911153885574113d Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Fri, 24 Jun 2022 19:21:22 -0400
Subject: Documentation updates [ci skip]
---
SCons/Tool/msvc.xml | 199 ++++++++++++++++++++++++++------------------
doc/generated/variables.gen | 199 ++++++++++++++++++++++++++------------------
2 files changed, 234 insertions(+), 164 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 6663aab..de82db0 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -349,8 +349,15 @@ Sets the preferred version of Microsoft Visual C/C++ to use.
If &cv-MSVC_VERSION; is not set, SCons will (by default) select the
latest version of Visual C/C++ installed on your system. If the
specified version isn't installed, tool initialization will fail.
-This variable must be passed as an argument to the &f-link-Environment;
-constructor; setting it later has no effect.
+
+
+
+&cv-MSVC_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_VERSION; must be set before the first msvc tool is
+loaded into the environment.
@@ -410,7 +417,7 @@ is, if you are sure everything is set correctly already and
you don't want &SCons; to change anything.
-&cv-MSVC_USE_SCRIPT; overrides &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;.
+&cv-MSVC_USE_SCRIPT; ignores &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;.
@@ -485,8 +492,12 @@ Important usage details:
-MSVC_USE_SETTINGS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_USE_SETTINGS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_USE_SETTINGS; must be set before the first msvc tool is
+loaded into the environment.
@@ -529,13 +540,13 @@ Build with the Universal Windows Platform (UWP) application Visual C++ libraries
-The valid values for MSVC_UWP_APP are True,
+The valid values for &cv-MSVC_UWP_APP; are: True,
'1', False, '0',
or None.
-When MSVC_UWP_APP is enabled (i.e., True or
+When &cv-MSVC_UWP_APP; is enabled (i.e., True or
'1'), the Visual C++ environment will be set up to point
to the Windows Store compatible libraries and Visual C++ runtimes. In doing so,
any libraries that are built will be able to be used in a UWP App and published
@@ -549,11 +560,11 @@ constructor; setting it later has no effect. -->
An exception is raised when any of the following conditions are satisfied:
-MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+&cv-MSVC_UWP_APP; is enabled for Visual Studio 2013 and earlier.
-MSVC_UWP_APP is enabled and a UWP argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via MSVC_UWP_APP
+&cv-MSVC_UWP_APP; is enabled and a UWP argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via &cv-MSVC_UWP_APP;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
@@ -571,13 +582,17 @@ Important usage details:
-MSVC_UWP_APP must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_UWP_APP; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_UWP_APP; must be set before the first msvc tool is
+loaded into the environment.
-The existence of the UWP libraries is not verified when MSVC_UWP_APP is enabled
+The existence of the UWP libraries is not verified when &cv-MSVC_UWP_APP; is enabled
which could result in build failures.
The burden is on the user to ensure the requisite UWP libraries are installed.
@@ -645,12 +660,12 @@ Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not det
- The MSVC_NOTFOUND_POLICY specifies the &scons; behavior when no msvc versions are detected or
+ The &cv-MSVC_NOTFOUND_POLICY; specifies the &scons; behavior when no msvc versions are detected or
when the requested msvc version is not detected.
-The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; behavior are:
+The valid values for &cv-MSVC_NOTFOUND_POLICY; and the corresponding &scons; behavior are:
@@ -691,7 +706,7 @@ Note: in addition to the camel case values shown above, lower case and upper cas
-The MSVC_NOTFOUND_POLICY is applied when any of the following conditions are satisfied:
+The &cv-MSVC_NOTFOUND_POLICY; is applied when any of the following conditions are satisfied:
&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified),
@@ -708,7 +723,7 @@ A non-default tools list is specified that contains one or more of the msvc tool
-The MSVC_NOTFOUND_POLICY is ignored when any of the following conditions are satisfied:
+The &cv-MSVC_NOTFOUND_POLICY; is ignored when any of the following conditions are satisfied:
&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified).
@@ -727,15 +742,19 @@ Important usage details:
-MSVC_NOTFOUND_POLICY must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_NOTFOUND_POLICY; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_NOTFOUND_POLICY; must be set before the first msvc tool is
+loaded into the environment.
-When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue
+When &cv-MSVC_NOTFOUND_POLICY; is not specified, the default &scons; behavior is to issue a warning and continue
subject to the conditions listed above. The default &scons; behavior may change in the future.
@@ -749,25 +768,25 @@ Pass user-defined arguments to the Visual C++ batch file determined via autodete
-MSVC_SCRIPT_ARGS is available for msvc batch file arguments that do not have first-class support
+&cv-MSVC_SCRIPT_ARGS; is available for msvc batch file arguments that do not have first-class support
via construction variables or when there is an issue with the appropriate construction variable validation.
When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;)
-rather than MSVC_SCRIPT_ARGS arguments.
+rather than &cv-MSVC_SCRIPT_ARGS; arguments.
-The valid values for MSVC_SCRIPT_ARGS are: None, a string,
+The valid values for &cv-MSVC_SCRIPT_ARGS; are: None, a string,
or a list of strings.
-The MSVC_SCRIPT_ARGS value is converted to a scalar string (i.e., "flattened").
+The &cv-MSVC_SCRIPT_ARGS; value is converted to a scalar string (i.e., "flattened").
The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined
via autodetection subject to the validation conditions listed below.
-MSVC_SCRIPT_ARGS is ignored when the value is None and when the
+&cv-MSVC_SCRIPT_ARGS; is ignored when the value is None and when the
result from argument conversion is an empty string. The validation conditions below do not apply.
@@ -776,54 +795,54 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SCRIPT_ARGS is specified for Visual Studio 2013 and earlier.
+&cv-MSVC_SCRIPT_ARGS; is specified for Visual Studio 2013 and earlier.
Multiple SDK version arguments (e.g., '10.0.20348.0') are specified
-in MSVC_SCRIPT_ARGS.
+in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument
-(e.g., '10.0.20348.0') is specified in MSVC_SCRIPT_ARGS.
-Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and MSVC_SCRIPT_ARGS
+(e.g., '10.0.20348.0') is specified in &cv-MSVC_SCRIPT_ARGS;.
+Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and &cv-MSVC_SCRIPT_ARGS;
are not allowed.
Multiple toolset version arguments (e.g., '-vcvars_ver=14.29')
-are specified in MSVC_SCRIPT_ARGS.
+are specified in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument
-(e.g., '-vcvars_ver=14.29') is specified in MSVC_SCRIPT_ARGS.
+(e.g., '-vcvars_ver=14.29') is specified in &cv-MSVC_SCRIPT_ARGS;.
Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and
-MSVC_SCRIPT_ARGS are not allowed.
+&cv-MSVC_SCRIPT_ARGS; are not allowed.
Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre')
-are specified in MSVC_SCRIPT_ARGS.
+are specified in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument
(e.g., '-vcvars_spectre_libs=spectre') is specified in
-MSVC_SCRIPT_ARGS. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
-and MSVC_SCRIPT_ARGS are not allowed.
+&cv-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
+and &cv-MSVC_SCRIPT_ARGS; are not allowed.
Multiple UWP arguments (e.g., uwp or store) are specified
-in MSVC_SCRIPT_ARGS.
+in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or
-store) is specified in MSVC_SCRIPT_ARGS. Multiple UWP declarations
-via &cv-link-MSVC_UWP_APP; and MSVC_SCRIPT_ARGS are not allowed.
+store) is specified in &cv-MSVC_SCRIPT_ARGS;. Multiple UWP declarations
+via &cv-link-MSVC_UWP_APP; and &cv-MSVC_SCRIPT_ARGS; are not allowed.
@@ -850,18 +869,22 @@ Important usage details:
-MSVC_SCRIPT_ARGS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SCRIPT_ARGS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SCRIPT_ARGS; must be set before the first msvc tool is
+loaded into the environment.
-Other than checking for multiple declarations as described above, MSVC_SCRIPT_ARGS arguments
+Other than checking for multiple declarations as described above, &cv-MSVC_SCRIPT_ARGS; arguments
are not validated.
-Erroneous, inconsistent, and/or version incompatible MSVC_SCRIPT_ARGS arguments are likely
+Erroneous, inconsistent, and/or version incompatible &cv-MSVC_SCRIPT_ARGS; arguments are likely
to result in build failures for reasons that are not readily apparent and may be difficult to diagnose.
The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent
@@ -881,12 +904,12 @@ Build with a specific version of the Microsoft Software Development Kit (SDK).
-The valid values for MSVC_SDK_VERSION are: None
-or a string containing the requested SDK version (e.g., '10.0.20348.0').
+The valid values for &cv-MSVC_SDK_VERSION; are: None
+or a string containing the requested SDK version (e.g., '10.0.20348.0').
-MSVC_SDK_VERSION is ignored when the value is None and when
+&cv-MSVC_SDK_VERSION; is ignored when the value is None and when
the value is an empty string. The validation conditions below do not apply.
@@ -895,17 +918,17 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SDK_VERSION is specified for Visual Studio 2013 and earlier.
+&cv-MSVC_SDK_VERSION; is specified for Visual Studio 2013 and earlier.
-MSVC_SDK_VERSION is specified and an SDK version argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via MSVC_SDK_VERSION
+&cv-MSVC_SDK_VERSION; is specified and an SDK version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via &cv-MSVC_SDK_VERSION;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
-The MSVC_SDK_VERSION specified does not match any of the supported formats:
+The &cv-MSVC_SDK_VERSION; specified does not match any of the supported formats:
'10.0.XXXXX.Y' [SDK 10.0]
@@ -917,12 +940,12 @@ The MSVC_SDK_VERSION specified does not match any of the supporte
-The system folder for the corresponding MSVC_SDK_VERSION version is not found.
+The system folder for the corresponding &cv-MSVC_SDK_VERSION; version is not found.
The requested SDK version does not appear to be installed.
-The MSVC_SDK_VERSION version does not appear to support the requested platform
+The &cv-MSVC_SDK_VERSION; version does not appear to support the requested platform
type (i.e., UWP or Desktop). The requested SDK version
platform type components do not appear to be installed.
@@ -949,8 +972,12 @@ Important usage details:
-MSVC_SDK_VERSION must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SDK_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SDK_VERSION; must be set before the first msvc tool is
+loaded into the environment.
@@ -969,7 +996,7 @@ the requested SDK version is installed with the necessary platform type componen
There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
when using the v141 build tools and the target architecture is ARM64.
-Should build failures arise with this combination of settings, MSVC_SDK_VERSION may be
+Should build failures arise with this combination of settings, &cv-MSVC_SDK_VERSION; may be
employed to specify a different SDK version for the build.
@@ -986,19 +1013,19 @@ Build with a specific Visual C++ toolset version.
-Specifying MSVC_TOOLSET_VERSION does not affect the autodetection and selection
-of msvc instances. The MSVC_TOOLSET_VERSION is applied after
+Specifying &cv-MSVC_TOOLSET_VERSION; does not affect the autodetection and selection
+of msvc instances. The &cv-MSVC_TOOLSET_VERSION; is applied after
an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION;
is not specified.
-The valid values for MSVC_TOOLSET_VERSION are: None
-or a string containing the requested toolset version (e.g., '14.29').
+The valid values for &cv-MSVC_TOOLSET_VERSION; are: None
+or a string containing the requested toolset version (e.g., '14.29').
-MSVC_TOOLSET_VERSION is ignored when the value is None and when
+&cv-MSVC_TOOLSET_VERSION; is ignored when the value is None and when
the value is an empty string. The validation conditions below do not apply.
@@ -1007,18 +1034,18 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_TOOLSET_VERSION is specified for Visual Studio 2015 and earlier.
+&cv-MSVC_TOOLSET_VERSION; is specified for Visual Studio 2015 and earlier.
-MSVC_TOOLSET_VERSION is specified and a toolset version argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via MSVC_TOOLSET_VERSION
+&cv-MSVC_TOOLSET_VERSION; is specified and a toolset version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via &cv-MSVC_TOOLSET_VERSION;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
-The MSVC_TOOLSET_VERSION specified does not match any of the supported formats:
+The &cv-MSVC_TOOLSET_VERSION; specified does not match any of the supported formats:
@@ -1055,17 +1082,17 @@ The MSVC_TOOLSET_VERSION specified does not match any of the supp
-The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
-is for Visual Studio 2013 and earlier (e.g., '12.0').
+The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified
+is for Visual Studio 2013 and earlier (e.g., '12.0').
-The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
-is greater than the msvc version selected (e.g., '99.0').
+The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified
+is greater than the msvc version selected (e.g., '99.0').
-A system folder for the corresponding MSVC_TOOLSET_VERSION version is not found.
+A system folder for the corresponding &cv-MSVC_TOOLSET_VERSION; version is not found.
The requested toolset version does not appear to be installed.
@@ -1084,13 +1111,13 @@ mapped to toolset version 14.16.27023.
-When MSVC_TOOLSET_VERSION is not an SxS version number or a full toolset version number:
-the first toolset version, ranked in descending order, that matches the MSVC_TOOLSET_VERSION
+When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number:
+the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION;
prefix is selected.
-When MSVC_TOOLSET_VERSION is specified using the major msvc version prefix
+When &cv-MSVC_TOOLSET_VERSION; is specified using the major msvc version prefix
(i.e., 'XX.Y') and the major msvc version is that of the latest release of
Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version.
@@ -1116,14 +1143,18 @@ Important usage details:
-MSVC_TOOLSET_VERSION must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_TOOLSET_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_TOOLSET_VERSION; must be set before the first msvc tool is
+loaded into the environment.
The existence of the toolset host architecture and target architecture folders are not verified
-when MSVC_TOOLSET_VERSION is specified which could result in build failures.
+when &cv-MSVC_TOOLSET_VERSION; is specified which could result in build failures.
The burden is on the user to ensure the requisite toolset target architecture build tools are installed.
@@ -1141,12 +1172,12 @@ Build with the spectre-mitigated Visual C++ libraries.
-The valid values for MSVC_SPECTRE_LIBS are: True,
+The valid values for &cv-MSVC_SPECTRE_LIBS; are: True,
False, or None.
-When MSVC_SPECTRE_LIBS is enabled (i.e., True),
+When &cv-MSVC_SPECTRE_LIBS; is enabled (i.e., True),
the Visual C++ environment will include the paths to the spectre-mitigated implementations
of the Microsoft Visual C++ libraries.
@@ -1156,12 +1187,12 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SPECTRE_LIBS is enabled for Visual Studio 2015 and earlier.
+&cv-MSVC_SPECTRE_LIBS; is enabled for Visual Studio 2015 and earlier.
-MSVC_SPECTRE_LIBS is enabled and a spectre library argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via MSVC_SPECTRE_LIBS
+&cv-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-MSVC_SPECTRE_LIBS;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
@@ -1180,8 +1211,12 @@ Important usage details:
-MSVC_SPECTRE_LIBS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SPECTRE_LIBS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SPECTRE_LIBS; must be set before the first msvc tool is
+loaded into the environment.
@@ -1192,7 +1227,7 @@ details.
-The existence of the spectre mitigations libraries is not verified when MSVC_SPECTRE_LIBS
+The existence of the spectre mitigations libraries is not verified when &cv-MSVC_SPECTRE_LIBS;
is enabled which could result in build failures.
The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index f1b3fff..a0c2dc4 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -4690,12 +4690,12 @@ Specify the &scons; behavior when the Microsoft Visual C/C++ compiler is not det
- The MSVC_NOTFOUND_POLICY specifies the &scons; behavior when no msvc versions are detected or
+ The &cv-MSVC_NOTFOUND_POLICY; specifies the &scons; behavior when no msvc versions are detected or
when the requested msvc version is not detected.
-The valid values for MSVC_NOTFOUND_POLICY and the corresponding &scons; behavior are:
+The valid values for &cv-MSVC_NOTFOUND_POLICY; and the corresponding &scons; behavior are:
@@ -4736,7 +4736,7 @@ Note: in addition to the camel case values shown above, lower case and upper cas
-The MSVC_NOTFOUND_POLICY is applied when any of the following conditions are satisfied:
+The &cv-MSVC_NOTFOUND_POLICY; is applied when any of the following conditions are satisfied:
&cv-MSVC_VERSION; is specified, the default tools list is implicitly defined (i.e., the tools list is not specified),
@@ -4753,7 +4753,7 @@ A non-default tools list is specified that contains one or more of the msvc tool
-The MSVC_NOTFOUND_POLICY is ignored when any of the following conditions are satisfied:
+The &cv-MSVC_NOTFOUND_POLICY; is ignored when any of the following conditions are satisfied:
&cv-MSVC_VERSION; is not specified and the default tools list is implicitly defined (i.e., the tools list is not specified).
@@ -4772,15 +4772,19 @@ Important usage details:
-MSVC_NOTFOUND_POLICY must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_NOTFOUND_POLICY; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_NOTFOUND_POLICY; must be set before the first msvc tool is
+loaded into the environment.
-When MSVC_NOTFOUND_POLICY is not specified, the default &scons; behavior is to issue a warning and continue
+When &cv-MSVC_NOTFOUND_POLICY; is not specified, the default &scons; behavior is to issue a warning and continue
subject to the conditions listed above. The default &scons; behavior may change in the future.
@@ -4795,25 +4799,25 @@ Pass user-defined arguments to the Visual C++ batch file determined via autodete
-MSVC_SCRIPT_ARGS is available for msvc batch file arguments that do not have first-class support
+&cv-MSVC_SCRIPT_ARGS; is available for msvc batch file arguments that do not have first-class support
via construction variables or when there is an issue with the appropriate construction variable validation.
When available, it is recommended to use the appropriate construction variables (e.g., &cv-link-MSVC_TOOLSET_VERSION;)
-rather than MSVC_SCRIPT_ARGS arguments.
+rather than &cv-MSVC_SCRIPT_ARGS; arguments.
-The valid values for MSVC_SCRIPT_ARGS are: None, a string,
+The valid values for &cv-MSVC_SCRIPT_ARGS; are: None, a string,
or a list of strings.
-The MSVC_SCRIPT_ARGS value is converted to a scalar string (i.e., "flattened").
+The &cv-MSVC_SCRIPT_ARGS; value is converted to a scalar string (i.e., "flattened").
The resulting scalar string, if not empty, is passed as an argument to the msvc batch file determined
via autodetection subject to the validation conditions listed below.
-MSVC_SCRIPT_ARGS is ignored when the value is None and when the
+&cv-MSVC_SCRIPT_ARGS; is ignored when the value is None and when the
result from argument conversion is an empty string. The validation conditions below do not apply.
@@ -4822,54 +4826,54 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SCRIPT_ARGS is specified for Visual Studio 2013 and earlier.
+&cv-MSVC_SCRIPT_ARGS; is specified for Visual Studio 2013 and earlier.
Multiple SDK version arguments (e.g., '10.0.20348.0') are specified
-in MSVC_SCRIPT_ARGS.
+in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_SDK_VERSION; is specified and an SDK version argument
-(e.g., '10.0.20348.0') is specified in MSVC_SCRIPT_ARGS.
-Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and MSVC_SCRIPT_ARGS
+(e.g., '10.0.20348.0') is specified in &cv-MSVC_SCRIPT_ARGS;.
+Multiple SDK version declarations via &cv-link-MSVC_SDK_VERSION; and &cv-MSVC_SCRIPT_ARGS;
are not allowed.
Multiple toolset version arguments (e.g., '-vcvars_ver=14.29')
-are specified in MSVC_SCRIPT_ARGS.
+are specified in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_TOOLSET_VERSION; is specified and a toolset version argument
-(e.g., '-vcvars_ver=14.29') is specified in MSVC_SCRIPT_ARGS.
+(e.g., '-vcvars_ver=14.29') is specified in &cv-MSVC_SCRIPT_ARGS;.
Multiple toolset version declarations via &cv-link-MSVC_TOOLSET_VERSION; and
-MSVC_SCRIPT_ARGS are not allowed.
+&cv-MSVC_SCRIPT_ARGS; are not allowed.
Multiple spectre library arguments (e.g., '-vcvars_spectre_libs=spectre')
-are specified in MSVC_SCRIPT_ARGS.
+are specified in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument
(e.g., '-vcvars_spectre_libs=spectre') is specified in
-MSVC_SCRIPT_ARGS. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
-and MSVC_SCRIPT_ARGS are not allowed.
+&cv-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-link-MSVC_SPECTRE_LIBS;
+and &cv-MSVC_SCRIPT_ARGS; are not allowed.
Multiple UWP arguments (e.g., uwp or store) are specified
-in MSVC_SCRIPT_ARGS.
+in &cv-MSVC_SCRIPT_ARGS;.
&cv-link-MSVC_UWP_APP; is enabled and a UWP argument (e.g., uwp or
-store) is specified in MSVC_SCRIPT_ARGS. Multiple UWP declarations
-via &cv-link-MSVC_UWP_APP; and MSVC_SCRIPT_ARGS are not allowed.
+store) is specified in &cv-MSVC_SCRIPT_ARGS;. Multiple UWP declarations
+via &cv-link-MSVC_UWP_APP; and &cv-MSVC_SCRIPT_ARGS; are not allowed.
@@ -4896,18 +4900,22 @@ Important usage details:
-MSVC_SCRIPT_ARGS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SCRIPT_ARGS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SCRIPT_ARGS; must be set before the first msvc tool is
+loaded into the environment.
-Other than checking for multiple declarations as described above, MSVC_SCRIPT_ARGS arguments
+Other than checking for multiple declarations as described above, &cv-MSVC_SCRIPT_ARGS; arguments
are not validated.
-Erroneous, inconsistent, and/or version incompatible MSVC_SCRIPT_ARGS arguments are likely
+Erroneous, inconsistent, and/or version incompatible &cv-MSVC_SCRIPT_ARGS; arguments are likely
to result in build failures for reasons that are not readily apparent and may be difficult to diagnose.
The burden is on the user to ensure that the arguments provided to the msvc batch file are valid, consistent
@@ -4928,12 +4936,12 @@ Build with a specific version of the Microsoft Software Development Kit (SDK).
-The valid values for MSVC_SDK_VERSION are: None
-or a string containing the requested SDK version (e.g., '10.0.20348.0').
+The valid values for &cv-MSVC_SDK_VERSION; are: None
+or a string containing the requested SDK version (e.g., '10.0.20348.0').
-MSVC_SDK_VERSION is ignored when the value is None and when
+&cv-MSVC_SDK_VERSION; is ignored when the value is None and when
the value is an empty string. The validation conditions below do not apply.
@@ -4942,17 +4950,17 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SDK_VERSION is specified for Visual Studio 2013 and earlier.
+&cv-MSVC_SDK_VERSION; is specified for Visual Studio 2013 and earlier.
-MSVC_SDK_VERSION is specified and an SDK version argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via MSVC_SDK_VERSION
+&cv-MSVC_SDK_VERSION; is specified and an SDK version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple SDK version declarations via &cv-MSVC_SDK_VERSION;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
-The MSVC_SDK_VERSION specified does not match any of the supported formats:
+The &cv-MSVC_SDK_VERSION; specified does not match any of the supported formats:
'10.0.XXXXX.Y' [SDK 10.0]
@@ -4964,12 +4972,12 @@ The MSVC_SDK_VERSION specified does not match any of the supporte
-The system folder for the corresponding MSVC_SDK_VERSION version is not found.
+The system folder for the corresponding &cv-MSVC_SDK_VERSION; version is not found.
The requested SDK version does not appear to be installed.
-The MSVC_SDK_VERSION version does not appear to support the requested platform
+The &cv-MSVC_SDK_VERSION; version does not appear to support the requested platform
type (i.e., UWP or Desktop). The requested SDK version
platform type components do not appear to be installed.
@@ -4996,8 +5004,12 @@ Important usage details:
-MSVC_SDK_VERSION must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SDK_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SDK_VERSION; must be set before the first msvc tool is
+loaded into the environment.
@@ -5016,7 +5028,7 @@ the requested SDK version is installed with the necessary platform type componen
There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
when using the v141 build tools and the target architecture is ARM64.
-Should build failures arise with this combination of settings, MSVC_SDK_VERSION may be
+Should build failures arise with this combination of settings, &cv-MSVC_SDK_VERSION; may be
employed to specify a different SDK version for the build.
@@ -5034,12 +5046,12 @@ Build with the spectre-mitigated Visual C++ libraries.
-The valid values for MSVC_SPECTRE_LIBS are: True,
+The valid values for &cv-MSVC_SPECTRE_LIBS; are: True,
False, or None.
-When MSVC_SPECTRE_LIBS is enabled (i.e., True),
+When &cv-MSVC_SPECTRE_LIBS; is enabled (i.e., True),
the Visual C++ environment will include the paths to the spectre-mitigated implementations
of the Microsoft Visual C++ libraries.
@@ -5049,12 +5061,12 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_SPECTRE_LIBS is enabled for Visual Studio 2015 and earlier.
+&cv-MSVC_SPECTRE_LIBS; is enabled for Visual Studio 2015 and earlier.
-MSVC_SPECTRE_LIBS is enabled and a spectre library argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via MSVC_SPECTRE_LIBS
+&cv-MSVC_SPECTRE_LIBS; is enabled and a spectre library argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple spectre library declarations via &cv-MSVC_SPECTRE_LIBS;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
@@ -5073,8 +5085,12 @@ Important usage details:
-MSVC_SPECTRE_LIBS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_SPECTRE_LIBS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_SPECTRE_LIBS; must be set before the first msvc tool is
+loaded into the environment.
@@ -5085,7 +5101,7 @@ details.
-The existence of the spectre mitigations libraries is not verified when MSVC_SPECTRE_LIBS
+The existence of the spectre mitigations libraries is not verified when &cv-MSVC_SPECTRE_LIBS;
is enabled which could result in build failures.
The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
@@ -5105,19 +5121,19 @@ Build with a specific Visual C++ toolset version.
-Specifying MSVC_TOOLSET_VERSION does not affect the autodetection and selection
-of msvc instances. The MSVC_TOOLSET_VERSION is applied after
+Specifying &cv-MSVC_TOOLSET_VERSION; does not affect the autodetection and selection
+of msvc instances. The &cv-MSVC_TOOLSET_VERSION; is applied after
an msvc instance is selected. This could be the default version of msvc if &cv-link-MSVC_VERSION;
is not specified.
-The valid values for MSVC_TOOLSET_VERSION are: None
-or a string containing the requested toolset version (e.g., '14.29').
+The valid values for &cv-MSVC_TOOLSET_VERSION; are: None
+or a string containing the requested toolset version (e.g., '14.29').
-MSVC_TOOLSET_VERSION is ignored when the value is None and when
+&cv-MSVC_TOOLSET_VERSION; is ignored when the value is None and when
the value is an empty string. The validation conditions below do not apply.
@@ -5126,18 +5142,18 @@ An exception is raised when any of the following conditions are satisfied:
-MSVC_TOOLSET_VERSION is specified for Visual Studio 2015 and earlier.
+&cv-MSVC_TOOLSET_VERSION; is specified for Visual Studio 2015 and earlier.
-MSVC_TOOLSET_VERSION is specified and a toolset version argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via MSVC_TOOLSET_VERSION
+&cv-MSVC_TOOLSET_VERSION; is specified and a toolset version argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple toolset version declarations via &cv-MSVC_TOOLSET_VERSION;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
-The MSVC_TOOLSET_VERSION specified does not match any of the supported formats:
+The &cv-MSVC_TOOLSET_VERSION; specified does not match any of the supported formats:
@@ -5174,17 +5190,17 @@ The MSVC_TOOLSET_VERSION specified does not match any of the supp
-The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
-is for Visual Studio 2013 and earlier (e.g., '12.0').
+The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified
+is for Visual Studio 2013 and earlier (e.g., '12.0').
-The major msvc version prefix (i.e., 'XX.Y') of the MSVC_TOOLSET_VERSION specified
-is greater than the msvc version selected (e.g., '99.0').
+The major msvc version prefix (i.e., 'XX.Y') of the &cv-MSVC_TOOLSET_VERSION; specified
+is greater than the msvc version selected (e.g., '99.0').
-A system folder for the corresponding MSVC_TOOLSET_VERSION version is not found.
+A system folder for the corresponding &cv-MSVC_TOOLSET_VERSION; version is not found.
The requested toolset version does not appear to be installed.
@@ -5203,13 +5219,13 @@ mapped to toolset version 14.16.27023.
-When MSVC_TOOLSET_VERSION is not an SxS version number or a full toolset version number:
-the first toolset version, ranked in descending order, that matches the MSVC_TOOLSET_VERSION
+When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number:
+the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION;
prefix is selected.
-When MSVC_TOOLSET_VERSION is specified using the major msvc version prefix
+When &cv-MSVC_TOOLSET_VERSION; is specified using the major msvc version prefix
(i.e., 'XX.Y') and the major msvc version is that of the latest release of
Visual Studio, the selected toolset version may not be the same as the default Visual C++ toolset version.
@@ -5235,14 +5251,18 @@ Important usage details:
-MSVC_TOOLSET_VERSION must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_TOOLSET_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_TOOLSET_VERSION; must be set before the first msvc tool is
+loaded into the environment.
The existence of the toolset host architecture and target architecture folders are not verified
-when MSVC_TOOLSET_VERSION is specified which could result in build failures.
+when &cv-MSVC_TOOLSET_VERSION; is specified which could result in build failures.
The burden is on the user to ensure the requisite toolset target architecture build tools are installed.
@@ -5283,7 +5303,7 @@ is, if you are sure everything is set correctly already and
you don't want &SCons; to change anything.
-&cv-MSVC_USE_SCRIPT; overrides &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;.
+&cv-MSVC_USE_SCRIPT; ignores &cv-link-MSVC_VERSION; and &cv-link-TARGET_ARCH;.
@@ -5360,8 +5380,12 @@ Important usage details:
-MSVC_USE_SETTINGS must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_USE_SETTINGS; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_USE_SETTINGS; must be set before the first msvc tool is
+loaded into the environment.
@@ -5387,13 +5411,13 @@ Build with the Universal Windows Platform (UWP) application Visual C++ libraries
-The valid values for MSVC_UWP_APP are True,
+The valid values for &cv-MSVC_UWP_APP; are: True,
'1', False, '0',
or None.
-When MSVC_UWP_APP is enabled (i.e., True or
+When &cv-MSVC_UWP_APP; is enabled (i.e., True or
'1'), the Visual C++ environment will be set up to point
to the Windows Store compatible libraries and Visual C++ runtimes. In doing so,
any libraries that are built will be able to be used in a UWP App and published
@@ -5407,11 +5431,11 @@ constructor; setting it later has no effect. -->
An exception is raised when any of the following conditions are satisfied:
-MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+&cv-MSVC_UWP_APP; is enabled for Visual Studio 2013 and earlier.
-MSVC_UWP_APP is enabled and a UWP argument is specified in
-&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via MSVC_UWP_APP
+&cv-MSVC_UWP_APP; is enabled and a UWP argument is specified in
+&cv-link-MSVC_SCRIPT_ARGS;. Multiple UWP declarations via &cv-MSVC_UWP_APP;
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
@@ -5429,13 +5453,17 @@ Important usage details:
-MSVC_UWP_APP must be passed as an argument to the Environment() constructor;
-setting it later has no effect.
+&cv-MSVC_UWP_APP; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_UWP_APP; must be set before the first msvc tool is
+loaded into the environment.
-The existence of the UWP libraries is not verified when MSVC_UWP_APP is enabled
+The existence of the UWP libraries is not verified when &cv-MSVC_UWP_APP; is enabled
which could result in build failures.
The burden is on the user to ensure the requisite UWP libraries are installed.
@@ -5458,8 +5486,15 @@ Sets the preferred version of Microsoft Visual C/C++ to use.
If &cv-MSVC_VERSION; is not set, SCons will (by default) select the
latest version of Visual C/C++ installed on your system. If the
specified version isn't installed, tool initialization will fail.
-This variable must be passed as an argument to the &f-link-Environment;
-constructor; setting it later has no effect.
+
+
+
+&cv-MSVC_VERSION; must be passed as an argument to the &f-link-Environment;
+constructor when an msvc tool (e.g., &t-link-msvc;, &t-link-msvs;, etc.) is
+loaded via the default tools list or via a tools list passed to the
+&f-link-Environment; constructor.
+Otherwise, &cv-MSVC_VERSION; must be set before the first msvc tool is
+loaded into the environment.
--
cgit v0.12
From 56d8f264280d47bafa19ce982641191bfca5cad2 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Sat, 25 Jun 2022 10:56:42 -0400
Subject: updated blurb in CHANGES.txt and RELEASE.txt to indicate more
specifically what's fixed. Address a few lint issues in the lex.py file
---
CHANGES.txt | 5 ++---
RELEASE.txt | 5 +++--
SCons/Tool/lex.py | 13 ++++++++-----
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index c986c1e..87766c3 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -135,9 +135,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
to connect to the server during start up.
- - Updated lex emitter to respect escaped spaces when climbing out of a the SConscript dir.
- Previously if the build/source directories absolute path included a space the lex emitter
- would fail to use the correct paths.
+ - lex: Fixed an issue with the lex tool where file arguments specified to either "--header-file="
+ or "--tables-file=" which included a space in the path to the file would be processed incorrectly
- Ninja: added option "--skip-ninja-regen" to enable skipping regeneration of the ninja file
if scons can determine the ninja file doesnot need to be regenerated, which will also
skip restarting the scons daemon. Note this option is could result in incorrect rebuilds
diff --git a/RELEASE.txt b/RELEASE.txt
index da580b8..fce184f 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -111,9 +111,9 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
if scons can determine the ninja file doesnot need to be regenerated, which will also
skip restarting the scons daemon. Note this option is could result in incorrect rebuilds
if scons Glob or scons generated files are used in ninja build target's command lines.
+
FIXES
-----
-
- Fix a number of Python ResourceWarnings which are issued when running SCons and/or it's tests
with python 3.9 (or higher)
- Ninja: Fix issue where Configure files weren't being properly processed when build run
@@ -156,7 +156,8 @@ FIXES
- The system environment variable names imported for MSVC 7.0 and 6.0 were updated to be
consistent with the variables names defined by their respective installers. This fixes an
error caused when bypassing MSVC detection by specifying the MSVC 7.0 batch file directly.
-- Updated lex emitter to respect escaped spaces when climbing out of a the SConscript dir
+- lex: Fixed an issue with the lex tool where file arguments specified to either "--header-file="
+ or "--tables-file=" which included a space in the path to the file would be processed incorrectly
- Suppress issuing a warning when there are no installed Visual Studio instances for the default
tools configuration (issue #2813). When msvc is the default compiler because there are no
compilers installed, a build may fail due to the cl.exe command not being recognized. At
diff --git a/SCons/Tool/lex.py b/SCons/Tool/lex.py
index c33d0fa..96f9bcb 100644
--- a/SCons/Tool/lex.py
+++ b/SCons/Tool/lex.py
@@ -46,6 +46,7 @@ if sys.platform == 'win32':
else:
BINS = ["flex", "lex"]
+
def lexEmitter(target, source, env):
sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0]))
@@ -56,18 +57,19 @@ def lexEmitter(target, source, env):
# files generated by flex.
# Different options that are used to trigger the creation of extra files.
- fileGenOptions = ["--header-file=", "--tables-file="]
+ file_gen_options = ["--header-file=", "--tables-file="]
lexflags = env.subst_list("$LEXFLAGS", target=target, source=source)
for option in SCons.Util.CLVar(lexflags):
- for fileGenOption in fileGenOptions:
+ for fileGenOption in file_gen_options:
l = len(fileGenOption)
if option[:l] == fileGenOption:
# A file generating option is present, so add the
# file name to the target list.
- fileName = option[l:].strip()
- target.append(fileName)
- return (target, source)
+ file_name = option[l:].strip()
+ target.append(file_name)
+ return target, source
+
def get_lex_path(env, append_paths=False):
"""
@@ -128,6 +130,7 @@ def generate(env):
env["LEX"] = env.Detect(BINS)
env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
+
def exists(env):
if sys.platform == 'win32':
return get_lex_path(env)
--
cgit v0.12
From 9b7ba04890c6a88b49ff282659199183dda996f9 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Sat, 25 Jun 2022 14:06:38 -0400
Subject: Minor edits. Link to Action Objects instead of just referencing it,
and removed extraneous '(see)'
---
SCons/Environment.xml | 2 +-
doc/man/scons.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index 23fba62..485fe39 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -1646,7 +1646,7 @@ and then executed.
Any additional arguments to &f-Execute;
are passed on to the &f-link-Action; factory function
which actually creates the Action object
-(see the manpage section "Action Objects"
+(see the manpage section Action Objects
for a description). Example:
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index 8545cb7..ef96d28 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -6076,7 +6076,7 @@ keyword arguments may not both be supplied in a single call to &f-Action;
Printing of action strings is affected by the setting of
-&cv-link-PRINT_CMD_LINE_FUNC; (see).
+&cv-link-PRINT_CMD_LINE_FUNC;.
Examples:
--
cgit v0.12
From 773f267b2ec42b4e629d01bab51f69d49d1605c8 Mon Sep 17 00:00:00 2001
From: William Deegan
Date: Sat, 25 Jun 2022 15:31:38 -0400
Subject: minor edits plus adding a warning about using chdir
---
doc/man/scons.xml | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index 2e7784c..19f5eb1 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -2635,7 +2635,7 @@ often (though not always) by tools which determine
whether the external dependencies for the builder are satisfied,
and which perform the necessary setup
(see Tools).
-Builers are attached to a &consenv; as methods.
+Builders are attached to a &consenv; as methods.
The available builder methods are registered as
key-value pairs in the
&cv-link-BUILDERS; attribute of the &consenv;,
@@ -2694,8 +2694,8 @@ env.Program('bar', source='bar.c foo.c'.split())
-Sources and targets can be specified as a a scalar or as a list,
-either of strings or nodes (more on nodes below).
+Sources and targets can be specified as a scalar or as a list,
+composed of either strings or nodes (more on nodes below).
When specifying path strings,
&Python; follows the POSIX pathname convention:
if a string begins with the operating system pathname separator
@@ -2806,7 +2806,7 @@ env.Program('build/prog', ['f1.c', 'f2.c'], srcdir='src')
The optional
parse_flags
-keyword argument causes behavior similarl to the
+keyword argument causes behavior similar to the
&f-link-env-MergeFlags; method, where the argument value is
broken into individual settings and merged into the appropriate &consvars;.
@@ -2841,6 +2841,23 @@ and evaluates true,
then &scons; will change to the
target file's directory.
+
+
+Python only keeps one current directory
+location even if there are multiple threads.
+This means that use of the
+chdir
+argument
+will
+not
+work with the SCons
+
+option,
+because individual worker threads spawned
+by SCons interfere with each other
+when they start changing directory.
+
+
# scons will change to the "sub" subdirectory
# before executing the "cp" command.
@@ -2950,7 +2967,7 @@ which causes it to produce a linker map file in addition
to the executable file actually being linked.
If the &b-link-Program; builder's emitter is configured
to add this mapfile if the option is set,
-then two targets will be returned when you only asked for one.
+then two targets will be returned when you only provided for one.
--
cgit v0.12
From 607d719e44d58de52f261b95a6c7c8a4dfa5b225 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sat, 25 Jun 2022 19:18:59 -0400
Subject: Minor documentation update based on stress tests [ci skip]
---
SCons/Tool/msvc.xml | 10 ++++++----
doc/generated/variables.gen | 10 ++++++----
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index de82db0..ab02252 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -994,10 +994,12 @@ the requested SDK version is installed with the necessary platform type componen
-There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
-when using the v141 build tools and the target architecture is ARM64.
-Should build failures arise with this combination of settings, &cv-MSVC_SDK_VERSION; may be
-employed to specify a different SDK version for the build.
+There is a known issue with the Microsoft libraries when the target architecture is
+ARM64 and a Windows 11 SDK (version '10.0.22000.0' and later) is used
+with the v141 build tools and older v142 toolsets
+(versions '14.28.29333' and earlier). Should build failures arise with these combinations
+of settings due to unresolved symbols in the Microsoft libraries, &cv-MSVC_SDK_VERSION; may be employed to
+specify a Windows 10 SDK (e.g., '10.0.20348.0') for the build.
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index a0c2dc4..c34b70c 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -5026,10 +5026,12 @@ the requested SDK version is installed with the necessary platform type componen
-There is a known issue with the Microsoft libraries for SDK version '10.0.22000.0'
-when using the v141 build tools and the target architecture is ARM64.
-Should build failures arise with this combination of settings, &cv-MSVC_SDK_VERSION; may be
-employed to specify a different SDK version for the build.
+There is a known issue with the Microsoft libraries when the target architecture is
+ARM64 and a Windows 11 SDK (version '10.0.22000.0' and later) is used
+with the v141 build tools and older v142 toolsets
+(versions '14.28.29333' and earlier). Should build failures arise with these combinations
+of settings due to unresolved symbols in the Microsoft libraries, &cv-MSVC_SDK_VERSION; may be employed to
+specify a Windows 10 SDK (e.g., '10.0.20348.0') for the build.
--
cgit v0.12
From d98f0faf2c06cda35b3da02a245ad78a32f245a7 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 26 Jun 2022 09:12:39 -0400
Subject: Update CHANGES.txt and RELEASE.txt
---
CHANGES.txt | 23 ++++++++++++++++++++++-
RELEASE.txt | 24 +++++++++++++++++++++---
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index bea5838..c6c6732 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -31,8 +31,29 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
determination when configuring the build environment. This could lead to build failures when
only an MSVC Express instance is installed and the MSVC version is not explicitly specified
(issue #2668 and issue #2697).
- - Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
+ - Added MSVC_USE_SETTINGS construction variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
+ - Added MSVC_SDK_VERSION construction variable which allows building with a specific Microsoft
+ SDK version. This variable is used with the msvc batch file determined via autodetection subject
+ to validation constraints. Refer to the documentation for additional requirements and validation
+ details.
+ - Added MSVC_TOOLSET_VERSION construction variable which allows building with a specific toolset
+ version. This variable is used with the msvc batch file determined via autodetection subject to
+ validation constraints. This variable does not affect the autodetection and selection of msvc
+ instances. The toolset version is applied after an msvc instance is selected. This could be the
+ default version of msvc. Refer to the documentation for additional requirements and validation
+ details. Addresses issue #3265, issue #3664, and pull request #4149.
+ - Added MSVC_SPECTRE_LIBS construction variable which allows building with spectre-mitigated
+ Visual C++ libraries. This variable is used with the msvc batch file determined via autodetection
+ subject to validation constraints. Refer to the documentation for additional requirements and
+ validation details.
+ - Added MSVC_SCRIPT_ARGS construction variable which specifies command line arguments that are
+ passed to the msvc batch file determined via autodetection subject to validation constraints.
+ Refer to the documentation for additional requirements and validation details. Addresses
+ enhancement issue #4106.
+ - An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+ Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013
+ and earlier. Refer to the documentation for additional requirements and validation details.
- The imported system environment variable names for MSVC 7.0 and 6.0 have been changed to the
names set by their respective installers. Prior to this change, bypassing MSVC detection by
specifying the MSVC 7.0 batch file directly would fail due to using an erroneous environment
diff --git a/RELEASE.txt b/RELEASE.txt
index c86c1d5..b244fda 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -23,8 +23,23 @@ NEW FUNCTIONALITY
variables). This allows the user to customize how (for example) PATH is constructed.
Note that these are called for every build command run by SCons. It could have considerable
performance impact if not used carefully.
-- Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler
+- Added MSVC_USE_SETTINGS construction variable to pass a dictionary to configure the msvc compiler
system environment as an alternative to bypassing Visual Studio autodetection entirely.
+- Added MSVC_SDK_VERSION construction variable which allows building with a specific Microsoft
+ SDK version. This variable is used with the msvc batch file determined via autodetection. Refer
+ to the documentation for additional requirements and validation details.
+- Added MSVC_TOOLSET_VERSION construction variable which allows building with a specific toolset
+ version. This variable is used with the msvc batch file determined via autodetection. This
+ variable does not affect the autodetection and selection of msvc instances. The toolset version
+ is applied after an msvc instance is selected. This could be the default version of msvc. Refer
+ to the documentation for additional requirements and validation details. Addresses issue #3265,
+ issue #3664, and pull request #4149.
+- Added MSVC_SPECTRE_LIBS construction variable which allows building with spectre-mitigated
+ Visual C++ libraries. This variable is used with the msvc batch file determined via autodetection.
+ Refer to the documentation for additional requirements and validation details.
+- Added MSVC_SCRIPT_ARGS construction variable which specifies command line arguments that are
+ passed to the msvc batch file determined via autodetection. Refer to the documentation for
+ additional requirements and validation details. Addresses enhancement issue #4106.
- Ninja: Added new alias "shutdown-ninja-scons-daemon" to allow ninja to shutdown the daemon.
Also added cleanup to test framework to kill ninja scons daemons and clean ip daemon logs.
NOTE: Test for this requires python psutil module. It will be skipped if not present.
@@ -96,8 +111,8 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
automatically executes ninja.
- Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool.
- The build argument (i.e., x86) is no longer passed to the MSVC 6.0 to 7.1 batch
- files. This may improve the effectiveness of the internal msvc cache when using
- MSVC detection and when bypassing MSVC detection as the MSVC 6.0 to 7.1 batch files
+ files. This may improve the effectiveness of the internal msvc cache when using
+ MSVC detection and when bypassing MSVC detection as the MSVC 6.0 to 7.1 batch files
do not expect any arguments.
- Propagate the OS and windir environment variables from the system environment to the msvc
environment. The OS and windir environment variables are used in the MSVC 6.0 batch file
@@ -109,6 +124,9 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
require delayed expansion to be enabled which is currently not supported and is
typically not enabled by default on the host system. The batch files may also require
environment variables that are not included by default in the msvc environment.
+- An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
+ Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013
+ and earlier. Refer to the documentation for additional requirements and validation details.
- Ninja: added option "--skip-ninja-regen" to enable skipping regeneration of the ninja file
if scons can determine the ninja file doesnot need to be regenerated, which will also
skip restarting the scons daemon. Note this option is could result in incorrect rebuilds
--
cgit v0.12
From 7a38a4b6547c3776b20f4b1435773a7458a8ebd8 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 26 Jun 2022 10:54:38 -0400
Subject: Set global lxml etree XSLT maximum traversal depth. Update generated
documentation artifacts.
---
SCons/Tool/docbook/__init__.py | 12 +++++
doc/generated/functions.gen | 52 +++++++++++----------
doc/generated/tools.gen | 17 ++++---
doc/generated/variables.gen | 103 +++++++++++++++++++++++++++--------------
doc/generated/variables.mod | 2 +
5 files changed, 117 insertions(+), 69 deletions(-)
diff --git a/SCons/Tool/docbook/__init__.py b/SCons/Tool/docbook/__init__.py
index 4c3f60c..5cf5e61 100644
--- a/SCons/Tool/docbook/__init__.py
+++ b/SCons/Tool/docbook/__init__.py
@@ -66,6 +66,18 @@ re_manvolnum = re.compile(r"([^<]*)")
re_refname = re.compile(r"([^<]*)")
#
+# lxml etree XSLT global max traversal depth
+#
+
+lmxl_xslt_global_max_depth = 3100
+
+if has_lxml and lmxl_xslt_global_max_depth:
+ def __lxml_xslt_set_global_max_depth(max_depth):
+ from lxml import etree
+ etree.XSLT.set_global_max_depth(max_depth)
+ __lxml_xslt_set_global_max_depth(lmxl_xslt_global_max_depth)
+
+#
# Helper functions
#
def __extend_targets_sources(target, source):
diff --git a/doc/generated/functions.gen b/doc/generated/functions.gen
index a2d9acd..efc4c9e 100644
--- a/doc/generated/functions.gen
+++ b/doc/generated/functions.gen
@@ -1611,45 +1611,49 @@ See the manpage section "Construction Environments" for more details.
- Execute(action, [strfunction, varlist])
- env.Execute(action, [strfunction, varlist])
+ Execute(action, [actionargs ...])
+ env.Execute(action, [actionargs ...])
-Executes an Action object.
-The specified
+Executes an Action.
action
may be an Action object
-(see manpage section "Action Objects"
-for an explanation of behavior),
or it may be a command-line string,
list of commands,
or executable &Python; function,
-each of which will be converted
+each of which will first be converted
into an Action object
and then executed.
Any additional arguments to &f-Execute;
-(strfunction, varlist)
are passed on to the &f-link-Action; factory function
-which actually creates the Action object.
-The exit value of the command
-or return value of the &Python; function
-will be returned.
+which actually creates the Action object
+(see the manpage section Action Objects
+for a description). Example:
+
+
+
+Execute(Copy('file.out', 'file.in'))
+
+
+&f-Execute; performs its action immediately,
+as part of the SConscript-reading phase.
+There are no sources or targets declared in an
+&f-Execute; call, so any objects it manipulates
+will not be tracked as part of the &SCons; dependency graph.
+In the example above, neither
+file.out nor
+file.in will be tracked objects.
-Note that
+&f-Execute; returns the exit value of the command
+or return value of the &Python; function.
&scons;
-will print an error message if the executed
+prints an error message if the executed
action
-fails--that is,
-exits with or returns a non-zero value.
-&scons;
-will
+fails (exits with or returns a non-zero value),
+however it does
not,
-however,
-automatically terminate the build
-if the specified
-action
-fails.
+automatically terminate the build for such a failure.
If you want the build to stop in response to a failed
&f-Execute;
call,
@@ -1657,8 +1661,6 @@ you must explicitly check for a non-zero return value:
-Execute(Copy('file.out', 'file.in'))
-
if Execute("mkdir sub/dir/ectory"):
# The mkdir failed, don't try to build.
Exit(1)
diff --git a/doc/generated/tools.gen b/doc/generated/tools.gen
index ecc301a..35ded17 100644
--- a/doc/generated/tools.gen
+++ b/doc/generated/tools.gen
@@ -389,35 +389,35 @@ Sets construction variables for the dvips utility.
Set construction variables for generic POSIX Fortran 03 compilers.
-Sets: &cv-link-F03;, &cv-link-F03COM;, &cv-link-F03FLAGS;, &cv-link-F03PPCOM;, &cv-link-SHF03;, &cv-link-SHF03COM;, &cv-link-SHF03FLAGS;, &cv-link-SHF03PPCOM;, &cv-link-_F03INCFLAGS;.Uses: &cv-link-F03COMSTR;, &cv-link-F03PPCOMSTR;, &cv-link-SHF03COMSTR;, &cv-link-SHF03PPCOMSTR;.
+Sets: &cv-link-F03;, &cv-link-F03COM;, &cv-link-F03FLAGS;, &cv-link-F03PPCOM;, &cv-link-SHF03;, &cv-link-SHF03COM;, &cv-link-SHF03FLAGS;, &cv-link-SHF03PPCOM;, &cv-link-_F03INCFLAGS;.Uses: &cv-link-F03COMSTR;, &cv-link-F03PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF03COMSTR;, &cv-link-SHF03PPCOMSTR;.f08
Set construction variables for generic POSIX Fortran 08 compilers.
-Sets: &cv-link-F08;, &cv-link-F08COM;, &cv-link-F08FLAGS;, &cv-link-F08PPCOM;, &cv-link-SHF08;, &cv-link-SHF08COM;, &cv-link-SHF08FLAGS;, &cv-link-SHF08PPCOM;, &cv-link-_F08INCFLAGS;.Uses: &cv-link-F08COMSTR;, &cv-link-F08PPCOMSTR;, &cv-link-SHF08COMSTR;, &cv-link-SHF08PPCOMSTR;.
+Sets: &cv-link-F08;, &cv-link-F08COM;, &cv-link-F08FLAGS;, &cv-link-F08PPCOM;, &cv-link-SHF08;, &cv-link-SHF08COM;, &cv-link-SHF08FLAGS;, &cv-link-SHF08PPCOM;, &cv-link-_F08INCFLAGS;.Uses: &cv-link-F08COMSTR;, &cv-link-F08PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF08COMSTR;, &cv-link-SHF08PPCOMSTR;.f77
Set construction variables for generic POSIX Fortran 77 compilers.
-Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77FLAGS;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;, &cv-link-_F77INCFLAGS;.Uses: &cv-link-F77COMSTR;, &cv-link-F77PPCOMSTR;, &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHF77COMSTR;, &cv-link-SHF77PPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANPPCOMSTR;.
+Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77FLAGS;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANFLAGS;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;, &cv-link-_F77INCFLAGS;.Uses: &cv-link-F77COMSTR;, &cv-link-F77PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-FORTRANCOMSTR;, &cv-link-FORTRANFLAGS;, &cv-link-FORTRANPPCOMSTR;, &cv-link-SHF77COMSTR;, &cv-link-SHF77PPCOMSTR;, &cv-link-SHFORTRANCOMSTR;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOMSTR;.f90
Set construction variables for generic POSIX Fortran 90 compilers.
-Sets: &cv-link-F90;, &cv-link-F90COM;, &cv-link-F90FLAGS;, &cv-link-F90PPCOM;, &cv-link-SHF90;, &cv-link-SHF90COM;, &cv-link-SHF90FLAGS;, &cv-link-SHF90PPCOM;, &cv-link-_F90INCFLAGS;.Uses: &cv-link-F90COMSTR;, &cv-link-F90PPCOMSTR;, &cv-link-SHF90COMSTR;, &cv-link-SHF90PPCOMSTR;.
+Sets: &cv-link-F90;, &cv-link-F90COM;, &cv-link-F90FLAGS;, &cv-link-F90PPCOM;, &cv-link-SHF90;, &cv-link-SHF90COM;, &cv-link-SHF90FLAGS;, &cv-link-SHF90PPCOM;, &cv-link-_F90INCFLAGS;.Uses: &cv-link-F90COMSTR;, &cv-link-F90PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF90COMSTR;, &cv-link-SHF90PPCOMSTR;.f95
Set construction variables for generic POSIX Fortran 95 compilers.
-Sets: &cv-link-F95;, &cv-link-F95COM;, &cv-link-F95FLAGS;, &cv-link-F95PPCOM;, &cv-link-SHF95;, &cv-link-SHF95COM;, &cv-link-SHF95FLAGS;, &cv-link-SHF95PPCOM;, &cv-link-_F95INCFLAGS;.Uses: &cv-link-F95COMSTR;, &cv-link-F95PPCOMSTR;, &cv-link-SHF95COMSTR;, &cv-link-SHF95PPCOMSTR;.
+Sets: &cv-link-F95;, &cv-link-F95COM;, &cv-link-F95FLAGS;, &cv-link-F95PPCOM;, &cv-link-SHF95;, &cv-link-SHF95COM;, &cv-link-SHF95FLAGS;, &cv-link-SHF95PPCOM;, &cv-link-_F95INCFLAGS;.Uses: &cv-link-F95COMSTR;, &cv-link-F95PPCOMSTR;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-SHF95COMSTR;, &cv-link-SHF95PPCOMSTR;.fortran
@@ -437,10 +437,8 @@ Set construction variables for the &gXX; C++ compiler.
g77
Set construction variables for the &g77; Fortran compiler.
-Calls the &t-f77; Tool module
-to set variables.
-
+Sets: &cv-link-F77;, &cv-link-F77COM;, &cv-link-F77FILESUFFIXES;, &cv-link-F77PPCOM;, &cv-link-F77PPFILESUFFIXES;, &cv-link-FORTRAN;, &cv-link-FORTRANCOM;, &cv-link-FORTRANPPCOM;, &cv-link-SHF77;, &cv-link-SHF77COM;, &cv-link-SHF77FLAGS;, &cv-link-SHF77PPCOM;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANCOM;, &cv-link-SHFORTRANFLAGS;, &cv-link-SHFORTRANPPCOM;.Uses: &cv-link-F77FLAGS;, &cv-link-FORTRANCOMMONFLAGS;, &cv-link-FORTRANFLAGS;.gas
@@ -516,7 +514,8 @@ environment:
gfortran
-Sets construction variables for the GNU F95/F2003 GNU compiler.
+Sets construction variables for the GNU Fortran compiler.
+Calls the &t-link-fortran; Tool module to set variables.
Sets: &cv-link-F77;, &cv-link-F90;, &cv-link-F95;, &cv-link-FORTRAN;, &cv-link-SHF77;, &cv-link-SHF77FLAGS;, &cv-link-SHF90;, &cv-link-SHF90FLAGS;, &cv-link-SHF95;, &cv-link-SHF95FLAGS;, &cv-link-SHFORTRAN;, &cv-link-SHFORTRANFLAGS;.
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index c34b70c..32db05e 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -2682,6 +2682,17 @@ in the &cv-link-FORTRANFLAGS;,
+
+
+ FORTRANCOMMONFLAGS
+
+
+General user-specified options that are passed to the Fortran compiler.
+Similar to &cv-link-FORTRANFLAGS;,
+but this variable is applied to all dialects.
+
+
+ FORTRANCOMSTR
@@ -2709,7 +2720,8 @@ default, this is ['.f', '.for', '.ftn']FORTRANFLAGS
-General user-specified options that are passed to the Fortran compiler.
+General user-specified options for the FORTRAN dialect
+that are passed to the Fortran compiler.
Note that this variable does
not
contain
@@ -6578,44 +6590,65 @@ A Python function used to print the command lines as they are executed
or
options or their equivalents).
-The function should take four arguments:
+The function must accept four arguments:
s,
-the command being executed (a string),
target,
-the target being built (file node, list, or string name(s)),
+source and
+env.
+s
+is a string showing the command being executed,
+target,
+is the target being built (file node, list, or string name(s)),
source,
-the source(s) used (file node, list, or string name(s)), and
-env,
-the environment being used.
+is the source(s) used (file node, list, or string name(s)),
+and env
+is the environment being used.
-The function must do the printing itself. The default implementation,
-used if this variable is not set or is None, is:
+The function must do the printing itself.
+The default implementation,
+used if this variable is not set or is None,
+is to just print the string, as in:
def print_cmd_line(s, target, source, env):
- sys.stdout.write(s + "\n")
+ sys.stdout.write(s + "\n")
-Here's an example of a more interesting function:
+Here is an example of a more interesting function:
def print_cmd_line(s, target, source, env):
- sys.stdout.write("Building %s -> %s...\n" %
- (' and '.join([str(x) for x in source]),
- ' and '.join([str(x) for x in target])))
-env=Environment(PRINT_CMD_LINE_FUNC=print_cmd_line)
-env.Program('foo', 'foo.c')
+ sys.stdout.write(
+ "Building %s -> %s...\n"
+ % (
+ ' and '.join([str(x) for x in source]),
+ ' and '.join([str(x) for x in target]),
+ )
+ )
+
+env = Environment(PRINT_CMD_LINE_FUNC=print_cmd_line)
+env.Program('foo', ['foo.c', 'bar.c'])
-This just prints "Building targetname from sourcename..." instead
-of the actual commands.
-Such a function could also log the actual commands to a log file,
-for example.
+This prints:
+
+
+
+...
+scons: Building targets ...
+Building bar.c -> bar.o...
+Building foo.c -> foo.o...
+Building foo.o and bar.o -> foo...
+scons: done building targets.
+
+
+
+Another example could be a function that logs the actual commands to a file.
@@ -7587,9 +7620,9 @@ targets.
def custom_shell_env(env, target, source, shell_env):
"""customize shell_env if desired"""
if str(target[0]) == 'special_target':
- shell_env['SPECIAL_VAR'] = env.subst('SOME_VAR', target=target, source=source)
+ shell_env['SPECIAL_VAR'] = env.subst('SOME_VAR', target=target, source=source)
return shell_env
-
+
env["SHELL_ENV_GENERATORS"] = [custom_shell_env]
@@ -7663,7 +7696,7 @@ Options that are passed to the Fortran 03 compiler
to generated shared-library objects.
You only need to set &cv-link-SHF03FLAGS; if you need to define specific
user options for Fortran 03 files.
-You should normally set the &cv-link-SHFORTRANFLAGS; variable,
+You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable,
which specifies the user-specified options
passed to the default Fortran compiler
for all Fortran versions.
@@ -7751,7 +7784,7 @@ Options that are passed to the Fortran 08 compiler
to generated shared-library objects.
You only need to set &cv-link-SHF08FLAGS; if you need to define specific
user options for Fortran 08 files.
-You should normally set the &cv-link-SHFORTRANFLAGS; variable,
+You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable,
which specifies the user-specified options
passed to the default Fortran compiler
for all Fortran versions.
@@ -7839,7 +7872,7 @@ Options that are passed to the Fortran 77 compiler
to generated shared-library objects.
You only need to set &cv-link-SHF77FLAGS; if you need to define specific
user options for Fortran 77 files.
-You should normally set the &cv-link-SHFORTRANFLAGS; variable,
+You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable,
which specifies the user-specified options
passed to the default Fortran compiler
for all Fortran versions.
@@ -7927,7 +7960,7 @@ Options that are passed to the Fortran 90 compiler
to generated shared-library objects.
You only need to set &cv-link-SHF90FLAGS; if you need to define specific
user options for Fortran 90 files.
-You should normally set the &cv-link-SHFORTRANFLAGS; variable,
+You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable,
which specifies the user-specified options
passed to the default Fortran compiler
for all Fortran versions.
@@ -8015,7 +8048,7 @@ Options that are passed to the Fortran 95 compiler
to generated shared-library objects.
You only need to set &cv-link-SHF95FLAGS; if you need to define specific
user options for Fortran 95 files.
-You should normally set the &cv-link-SHFORTRANFLAGS; variable,
+You should normally set the &cv-link-FORTRANCOMMONFLAGS; variable,
which specifies the user-specified options
passed to the default Fortran compiler
for all Fortran versions.
@@ -8389,7 +8422,7 @@ which would be a symlink and point to libtest.so.0.1.2
A command interpreter function that will be called to execute command line
-strings. The function must expect the following arguments:
+strings. The function must accept five arguments:
@@ -8397,18 +8430,18 @@ def spawn(shell, escape, cmd, args, env):
-sh
-is a string naming the shell program to use.
+shell
+is a string naming the shell program to use,
escape
is a function that can be called to escape shell special characters in
-the command line.
+the command line,
cmd
-is the path to the command to be executed.
+is the path to the command to be executed,
args
-is the arguments to the command.
+holds the arguments to the command and
env
-is a dictionary of the environment variables
-in which the command should be executed.
+is a dictionary of environment variables
+defining the execution environment in which the command should be executed.
diff --git a/doc/generated/variables.mod b/doc/generated/variables.mod
index d3d29f2..cc51043 100644
--- a/doc/generated/variables.mod
+++ b/doc/generated/variables.mod
@@ -186,6 +186,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$File">
$FORTRAN">
$FORTRANCOM">
+$FORTRANCOMMONFLAGS">
$FORTRANCOMSTR">
$FORTRANFILESUFFIXES">
$FORTRANFLAGS">
@@ -854,6 +855,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
$File">
$FORTRAN">
$FORTRANCOM">
+$FORTRANCOMMONFLAGS">
$FORTRANCOMSTR">
$FORTRANFILESUFFIXES">
$FORTRANFLAGS">
--
cgit v0.12
From 20a092ffda8d2492a5745b5aa93c48c14d0d4e76 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Sun, 26 Jun 2022 12:26:12 -0400
Subject: Add blurb for additional MSVC_UWP_APP values accepted.
---
CHANGES.txt | 1 +
RELEASE.txt | 1 +
2 files changed, 2 insertions(+)
diff --git a/CHANGES.txt b/CHANGES.txt
index c6c6732..381b061 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -54,6 +54,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013
and earlier. Refer to the documentation for additional requirements and validation details.
+ MSVC_UWP_APP was extended to accept True, False, and None in addition to '1' and '0'.
- The imported system environment variable names for MSVC 7.0 and 6.0 have been changed to the
names set by their respective installers. Prior to this change, bypassing MSVC detection by
specifying the MSVC 7.0 batch file directly would fail due to using an erroneous environment
diff --git a/RELEASE.txt b/RELEASE.txt
index b244fda..12dec62 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -127,6 +127,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
- An exception is raised when MSVC_UWP_APP is enabled for Visual Studio 2013 and earlier.
Previous behavior was to silently ignore MSVC_UWP_APP when enabled for Visual Studio 2013
and earlier. Refer to the documentation for additional requirements and validation details.
+ MSVC_UWP_APP was extended to accept True, False, and None in addition to '1' and '0'.
- Ninja: added option "--skip-ninja-regen" to enable skipping regeneration of the ninja file
if scons can determine the ninja file doesnot need to be regenerated, which will also
skip restarting the scons daemon. Note this option is could result in incorrect rebuilds
--
cgit v0.12
From 2e2b4640b09a94b0aa2b2f90581295e28ba83650 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 27 Jun 2022 10:40:55 -0400
Subject: Rework SxS toolset version support and vcvars bug fix handling.
Update MSVC_TOOLSET_VERSION documentation.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 81 ++++++++++++++++++++++-------
SCons/Tool/msvc.xml | 39 +++++++++-----
doc/generated/variables.gen | 39 +++++++++-----
3 files changed, 113 insertions(+), 46 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index e56dd4a..6a4ce3e 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -86,9 +86,22 @@ re_toolset_140 = re.compile(r'''^(?:
(?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
)$''', re.VERBOSE)
-# valid SxS formats will be matched with re_toolset_full: match 3 '.' format
+# SxS toolset version: MM.mm.VV.vv format
re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
+# SxS version bugfix
+_msvc_sxs_bugfix_folder = set()
+_msvc_sxs_bugfix_version = {}
+
+for msvc_version, sxs_version, sxs_bugfix in [
+ # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
+ # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
+ # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
+ ('14.2', '14.28.16.8', '14.28')
+]:
+ _msvc_sxs_bugfix_folder.add((msvc_version, sxs_bugfix))
+ _msvc_sxs_bugfix_version[(msvc_version, sxs_version)] = sxs_bugfix
+
# MSVC_SCRIPT_ARGS
re_vcvars_uwp = re.compile(r'(?:(?(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
re_vcvars_sdk = re.compile(r'(?:(?(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
@@ -327,14 +340,42 @@ def _msvc_read_toolset_file(msvc, filename):
debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
return toolset_version
+def _msvc_sxs_toolset_folder(msvc, sxs_folder):
+
+ if re_toolset_sxs.match(sxs_folder):
+ return sxs_folder
+
+ key = (msvc.vs_def.vc_buildtools_def.vc_version, sxs_folder)
+ if key in _msvc_sxs_bugfix_folder:
+ return sxs_folder
+
+ debug('sxs folder: ignore version=%s', repr(sxs_folder))
+ return None
+
+def _msvc_sxs_toolset_version(msvc, sxs_toolset):
+
+ if not re_toolset_sxs.match(sxs_toolset):
+ return None, False
+
+ key = (msvc.vs_def.vc_buildtools_def.vc_version, sxs_toolset)
+ sxs_bugfix = _msvc_sxs_bugfix_version.get(key)
+ if not sxs_bugfix:
+ return sxs_toolset, False
+
+ debug('sxs bugfix: version=%s => version=%s', repr(sxs_toolset), repr(sxs_bugfix))
+ return sxs_bugfix, True
+
def _msvc_read_toolset_folders(msvc, vc_dir):
toolsets_sxs = {}
toolsets_full = []
build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
- sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
- for sxs_toolset in sxs_toolsets:
+ sxs_folders = [f.name for f in os.scandir(build_dir) if f.is_dir()]
+ for sxs_folder in sxs_folders:
+ sxs_toolset = _msvc_sxs_toolset_folder(msvc, sxs_folder)
+ if not sxs_toolset:
+ continue
filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
filepath = os.path.join(build_dir, sxs_toolset, filename)
debug('sxs toolset: check file=%s', repr(filepath))
@@ -428,23 +469,27 @@ def _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version):
toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric == VS2019.vc_buildtools_def.vc_version_numeric:
- # necessary to detect toolset not found
- if toolset_version == '14.28.16.8':
- new_toolset_version = '14.28'
- # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
- # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
- # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
-
- if toolset_version in toolsets_sxs:
- toolset_vcvars = toolsets_sxs[toolset_version]
+ if toolset_version in toolsets_full:
+ # full toolset version provided
+ toolset_vcvars = toolset_version
return toolset_vcvars
+ sxs_toolset, sxs_isbugfix = _msvc_sxs_toolset_version(msvc, toolset_version)
+ if sxs_toolset:
+ # SxS version provided
+ sxs_version = toolsets_sxs.get(sxs_toolset, None)
+ if sxs_version:
+ # SxS full toolset version
+ if sxs_version in toolsets_full:
+ toolset_vcvars = sxs_version
+ return toolset_vcvars
+ return None
+ # SxS version file missing
+ if not sxs_isbugfix:
+ return None
+ # SxS version bugfix: check toolset version
+ toolset_version = sxs_toolset
+
for toolset_full in toolsets_full:
if toolset_full.startswith(toolset_version):
toolset_vcvars = toolset_full
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index ab02252..11c6478 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -1106,13 +1106,6 @@ Toolset selection details:
-SxS version numbers are not always in three dot format (e.g., 'XX.YY.ZZ.NN') as shown above.
-
-In Visual Studio 2022 for example, 14.16 is an SxS toolset version that is directly
-mapped to toolset version 14.16.27023.
-
-
-
When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number:
the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION;
prefix is selected.
@@ -1131,13 +1124,31 @@ toolset with the largest version number.
-Example environment constructor invocations with toolset version specifications:
-
-Environment(MSVC_TOOLSET_VERSION='14.2')
-Environment(MSVC_TOOLSET_VERSION='14.29')
-Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
-Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
-
+Example 1 - A default Visual Studio build with a partial toolset version specified:
+
+env = Environment(MSVC_TOOLSET_VERSION='14.2')
+
+
+
+
+Example 2 - A default Visual Studio build with a partial toolset version specified:
+
+env = Environment(MSVC_TOOLSET_VERSION='14.29')
+
+
+
+
+Example 3 - A Visual Studio 2022 build with a full toolset version specified:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
+
+
+
+
+Example 4 - A Visual Studio 2022 build with an SxS toolset version specified:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
+
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index 32db05e..d5980ff 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -5226,13 +5226,6 @@ Toolset selection details:
-SxS version numbers are not always in three dot format (e.g., 'XX.YY.ZZ.NN') as shown above.
-
-In Visual Studio 2022 for example, 14.16 is an SxS toolset version that is directly
-mapped to toolset version 14.16.27023.
-
-
-
When &cv-MSVC_TOOLSET_VERSION; is not an SxS version number or a full toolset version number:
the first toolset version, ranked in descending order, that matches the &cv-MSVC_TOOLSET_VERSION;
prefix is selected.
@@ -5251,13 +5244,31 @@ toolset with the largest version number.
-Example environment constructor invocations with toolset version specifications:
-
-Environment(MSVC_TOOLSET_VERSION='14.2')
-Environment(MSVC_TOOLSET_VERSION='14.29')
-Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
-Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
-
+Example 1 - A default Visual Studio build with a partial toolset version specified:
+
+env = Environment(MSVC_TOOLSET_VERSION='14.2')
+
+
+
+
+Example 2 - A default Visual Studio build with a partial toolset version specified:
+
+env = Environment(MSVC_TOOLSET_VERSION='14.29')
+
+
+
+
+Example 3 - A Visual Studio 2022 build with a full toolset version specified:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.30133')
+
+
+
+
+Example 4 - A Visual Studio 2022 build with an SxS toolset version specified:
+
+env = Environment(MSVC_VERSION='14.3', MSVC_TOOLSET_VERSION='14.29.16.11')
+
--
cgit v0.12
From b94e801aba5a6864644a156b5260ce6d721f4fc3 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 27 Jun 2022 14:36:02 -0400
Subject: Move verify invocation to last line of vc.py. Add verify method to
Config module to check that all _VCVER versions are defined locally. Update
module docstrings for Dispatcher and MSVC init.
---
SCons/Tool/MSCommon/MSVC/Config.py | 15 +++++++++++++++
SCons/Tool/MSCommon/MSVC/Dispatcher.py | 25 ++++++++++++++++++++++---
SCons/Tool/MSCommon/MSVC/__init__.py | 14 ++++++++++++--
SCons/Tool/MSCommon/vc.py | 3 +++
4 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
index 8f3a2cc..a4cb874 100644
--- a/SCons/Tool/MSCommon/MSVC/Config.py
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -29,6 +29,12 @@ from collections import (
namedtuple,
)
+from . import Util
+
+from .Exceptions import (
+ MSVCInternalError,
+)
+
from . import Dispatcher
Dispatcher.register_modulename(__name__)
@@ -282,3 +288,12 @@ for policy_value, policy_symbol_list in [
MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
+def verify():
+ from .. import vc
+ for msvc_version in vc._VCVER:
+ vc_version = Util.get_version_prefix(msvc_version)
+ if vc_version in MSVC_VERSION_INTERNAL:
+ continue
+ err_msg = 'vc_version {} not in MSVC_VERSION_INTERNAL'.format(repr(vc_version))
+ raise MSVCInternalError(err_msg)
+
diff --git a/SCons/Tool/MSCommon/MSVC/Dispatcher.py b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
index 0b216ca..dab1e15 100644
--- a/SCons/Tool/MSCommon/MSVC/Dispatcher.py
+++ b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
@@ -23,6 +23,25 @@
"""
Internal method dispatcher for Microsoft Visual C/C++.
+
+MSVC modules can register their module (register_modulename) and individual
+classes (register_class) with the method dispatcher during initialization. MSVC
+modules tend to be registered immediately after the Dispatcher import near the
+top of the file. Methods in the MSVC modules can be invoked indirectly without
+having to hard-code the method calls effectively decoupling the upstream module
+with the downstream modules:
+
+The reset method dispatches calls to all registered objects with a reset method
+and/or a _reset method. The reset methods are used to restore data structures
+to their initial state for testing purposes. Typically, this involves clearing
+cached values.
+
+The verify method dispatches calls to all registered objects with a verify
+method and/or a _verify method. The verify methods are used to check that
+initialized data structures distributed across multiple modules are internally
+consistent. An exception is raised when a verification constraint violation
+is detected. Typically, this verifies that initialized dictionaries support
+all of the requisite keys as new versions are added.
"""
import sys
@@ -34,13 +53,13 @@ from ..common import (
_refs = []
-def register_class(ref):
- _refs.append(ref)
-
def register_modulename(modname):
module = sys.modules[modname]
_refs.append(module)
+def register_class(ref):
+ _refs.append(ref)
+
def reset():
debug('')
for ref in _refs:
diff --git a/SCons/Tool/MSCommon/MSVC/__init__.py b/SCons/Tool/MSCommon/MSVC/__init__.py
index c07e849..b0ef5dd 100644
--- a/SCons/Tool/MSCommon/MSVC/__init__.py
+++ b/SCons/Tool/MSCommon/MSVC/__init__.py
@@ -23,6 +23,16 @@
"""
Functions for Microsoft Visual C/C++.
+
+The reset method is used to restore MSVC module data structures to their
+initial state for testing purposes.
+
+The verify method is used as a sanity check that MSVC module data structures
+are internally consistent.
+
+Currently:
+* reset is invoked from reset_installed_vcs in the vc module.
+* verify is invoked from the last line in the vc module.
"""
from . import Exceptions # noqa: F401
@@ -40,6 +50,6 @@ from . import Dispatcher as _Dispatcher
def reset():
_Dispatcher.reset()
-#reset() # testing
-_Dispatcher.verify()
+def verify():
+ _Dispatcher.verify()
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 675b8d0..7c65879 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1352,3 +1352,6 @@ def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
rval = MSVC.WinSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
return rval
+# internal consistency check (should be last)
+MSVC.verify()
+
--
cgit v0.12
From 90922c1195eef8d75664d59ed8668fd8e5679390 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Mon, 27 Jun 2022 15:09:13 -0400
Subject: Add docstrings to MSVC/Util.py methods.
---
SCons/Tool/MSCommon/MSVC/Util.py | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
index 15abdcd..ba70b24 100644
--- a/SCons/Tool/MSCommon/MSVC/Util.py
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -29,6 +29,16 @@ import os
import re
def listdir_dirs(p):
+ """Get a list of qualified subdirectory paths from a windows path.
+
+ Args:
+ p: str
+ windows path
+
+ Returns:
+ List[str]: list of qualified subdirectory paths
+
+ """
dirs = []
for dir_name in os.listdir(p):
dir_path = os.path.join(p, dir_name)
@@ -37,6 +47,16 @@ def listdir_dirs(p):
return dirs
def process_path(p):
+ """Normalize a windows path.
+
+ Args:
+ p: str
+ windows path
+
+ Returns:
+ str: normalized windows path
+
+ """
if p:
p = os.path.normpath(p)
p = os.path.realpath(p)
@@ -46,6 +66,16 @@ def process_path(p):
re_version_prefix = re.compile(r'^(?P[0-9.]+).*')
def get_version_prefix(version):
+ """Get the version number prefix from a string.
+
+ Args:
+ version: str
+ version string
+
+ Returns:
+ str: the version number prefix
+
+ """
m = re_version_prefix.match(version)
if m:
rval = m.group('version')
--
cgit v0.12
From d5a2a52087c968058fff3f2cc983f75953235e1a Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:16:49 -0400
Subject: Additional validation for MSVC_SDK_VERSION and MSVC_SPECTRE_LIBS.
Adjust documentation. Add additional exceptions for SDK version not found,
toolset version not found, and spectre libraries not found. Add data
structure for platform type.
---
SCons/Tool/MSCommon/MSVC/Config.py | 27 +++
SCons/Tool/MSCommon/MSVC/Exceptions.py | 11 +-
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 262 ++++++++++++++++++++++------
SCons/Tool/MSCommon/MSVC/Util.py | 20 +++
SCons/Tool/MSCommon/MSVC/WinSDK.py | 39 +++--
SCons/Tool/msvc.xml | 17 +-
doc/generated/variables.gen | 17 +-
7 files changed, 314 insertions(+), 79 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
index a4cb874..3b71cd8 100644
--- a/SCons/Tool/MSCommon/MSVC/Config.py
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -55,6 +55,33 @@ for bool, symbol_list, symbol_case_list in [
for symbol in BOOLEAN_SYMBOLS[bool]:
BOOLEAN_EXTERNAL[symbol] = bool
+MSVC_PLATFORM_DEFINITION = namedtuple('MSVCPlatform', [
+ 'vc_platform',
+ 'is_uwp',
+])
+
+MSVC_PLATFORM_DEFINITION_LIST = []
+
+MSVC_PLATFORM_INTERNAL = {}
+MSVC_PLATFORM_EXTERNAL = {}
+
+for vc_platform, is_uwp in [
+ ('Desktop', False),
+ ('UWP', True),
+]:
+
+ vc_platform_def = MSVC_PLATFORM_DEFINITION(
+ vc_platform = vc_platform,
+ is_uwp = is_uwp,
+ )
+
+ MSVC_PLATFORM_DEFINITION_LIST.append(vc_platform_def)
+
+ MSVC_PLATFORM_INTERNAL[vc_platform] = vc_platform_def
+
+ for symbol in [vc_platform, vc_platform.lower(), vc_platform.upper()]:
+ MSVC_PLATFORM_EXTERNAL[symbol] = vc_platform_def
+
MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
'vc_runtime',
'vc_runtime_numeric',
diff --git a/SCons/Tool/MSCommon/MSVC/Exceptions.py b/SCons/Tool/MSCommon/MSVC/Exceptions.py
index 7a61ec5..015fede 100644
--- a/SCons/Tool/MSCommon/MSVC/Exceptions.py
+++ b/SCons/Tool/MSCommon/MSVC/Exceptions.py
@@ -28,10 +28,19 @@ Exceptions for Microsoft Visual C/C++.
class VisualCException(Exception):
pass
+class MSVCInternalError(VisualCException):
+ pass
+
class MSVCVersionNotFound(VisualCException):
pass
-class MSVCInternalError(VisualCException):
+class MSVCSDKVersionNotFound(VisualCException):
+ pass
+
+class MSVCToolsetVersionNotFound(VisualCException):
+ pass
+
+class MSVCSpectreLibsNotFound(VisualCException):
pass
class MSVCArgumentError(VisualCException):
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 6a4ce3e..33e13fd 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -44,6 +44,9 @@ from . import WinSDK
from .Exceptions import (
MSVCInternalError,
+ MSVCSDKVersionNotFound,
+ MSVCToolsetVersionNotFound,
+ MSVCSpectreLibsNotFound,
MSVCArgumentError,
)
@@ -131,6 +134,18 @@ def msvc_force_default_arguments(force=True):
if CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS:
msvc_force_default_arguments(force=True)
+# UWP SDK 8.1 and SDK 10:
+#
+# https://stackoverflow.com/questions/46659238/build-windows-app-compatible-for-8-1-and-10
+# VS2019 - UWP (Except for Win10Mobile)
+# VS2017 - UWP
+# VS2015 - UWP, Win8.1 StoreApp, WP8/8.1 StoreApp
+# VS2013 - Win8/8.1 StoreApp, WP8/8.1 StoreApp
+
+# SPECTRE LIBS (msvc documentation):
+# "There are no versions of Spectre-mitigated libraries for Universal Windows (UWP) apps or
+# components. App-local deployment of such libraries isn't possible."
+
# MSVC batch file arguments:
#
# VS2022: UWP, SDK, TOOLSET, SPECTRE
@@ -159,7 +174,7 @@ VS2017 = Config.MSVS_VERSION_INTERNAL['2017']
VS2015 = Config.MSVS_VERSION_INTERNAL['2015']
MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
- 'version', # fully qualified msvc version (e.g., '14.1Exp')
+ 'version', # full version (e.g., '14.1Exp', '14.32.31326')
'vs_def',
])
@@ -175,6 +190,18 @@ def _msvc_version(version):
return version_args
+def _toolset_version(version):
+
+ verstr = Util.get_msvc_version_prefix(version)
+ vs_def = Config.MSVC_VERSION_INTERNAL[verstr]
+
+ version_args = MSVC_VERSION_ARGS_DEFINITION(
+ version = version,
+ vs_def = vs_def,
+ )
+
+ return version_args
+
def _msvc_script_argument_uwp(env, msvc, arglist):
uwp_app = env['MSVC_UWP_APP']
@@ -252,12 +279,38 @@ def _msvc_script_argument_sdk_constraints(msvc, sdk_version):
err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
return err_msg
-def _msvc_script_argument_sdk(env, msvc, platform_type, arglist):
+def _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def):
+
+ if sdk_version == '8.1' and platform_def.is_uwp:
+
+ vs_def = toolset.vs_def if toolset else msvc.vs_def
+
+ if vs_def.vc_buildtools_def.vc_version_numeric > VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: uwp/store SDK 8.1 msvc_version constraint: %s > %s VS2015',
+ repr(vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ if toolset and toolset.vs_def != msvc.vs_def:
+ err_msg = "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: toolset version {} > {} VS2015".format(
+ repr(sdk_version), repr(platform_def.vc_platform),
+ repr(toolset.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ else:
+ err_msg = "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: MSVC_VERSION {} > {} VS2015".format(
+ repr(sdk_version), repr(platform_def.vc_platform),
+ repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ return None
+
+def _msvc_script_argument_sdk(env, msvc, toolset, platform_def, arglist):
sdk_version = env['MSVC_SDK_VERSION']
debug(
'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_version), repr(platform_type)
+ repr(msvc.version), repr(sdk_version), repr(platform_def.vc_platform)
)
if not sdk_version:
@@ -267,12 +320,16 @@ def _msvc_script_argument_sdk(env, msvc, platform_type, arglist):
if err_msg:
raise MSVCArgumentError(err_msg)
- sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_def)
if sdk_version not in sdk_list:
err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
- repr(sdk_version), repr(platform_type)
+ repr(sdk_version), repr(platform_def.vc_platform)
)
+ raise MSVCSDKVersionNotFound(err_msg)
+
+ err_msg = _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def)
+ if err_msg:
raise MSVCArgumentError(err_msg)
argpair = (SortOrder.SDK, sdk_version)
@@ -280,12 +337,12 @@ def _msvc_script_argument_sdk(env, msvc, platform_type, arglist):
return sdk_version
-def _msvc_script_default_sdk(env, msvc, platform_type, arglist):
+def _msvc_script_default_sdk(env, msvc, platform_def, arglist):
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
return None
- sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_def)
if not len(sdk_list):
return None
@@ -293,7 +350,7 @@ def _msvc_script_default_sdk(env, msvc, platform_type, arglist):
debug(
'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_default), repr(platform_type)
+ repr(msvc.version), repr(sdk_default), repr(platform_def.vc_platform)
)
argpair = (SortOrder.SDK, sdk_default)
@@ -597,8 +654,9 @@ def _msvc_script_argument_toolset(env, msvc, vc_dir, arglist):
err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
repr(toolset_version), repr(msvc.version)
)
- raise MSVCArgumentError(err_msg)
+ raise MSVCToolsetVersionNotFound(err_msg)
+ # toolset may not be installed for host/target
argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
arglist.append(argpair)
@@ -644,16 +702,7 @@ def _user_script_argument_toolset(env, toolset_version, user_argstr):
raise MSVCArgumentError(err_msg)
-def _msvc_script_argument_spectre(env, msvc, arglist):
-
- spectre_libs = env['MSVC_SPECTRE_LIBS']
- debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
-
- if not spectre_libs:
- return None
-
- if spectre_libs not in _ARGUMENT_BOOLEAN_TRUE:
- return None
+def _msvc_script_argument_spectre_constraints(msvc, toolset, spectre_libs, platform_def):
if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
debug(
@@ -664,11 +713,63 @@ def _msvc_script_argument_spectre(env, msvc, arglist):
err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
repr(spectre_libs), repr(msvc.version), repr(VS2017.vc_buildtools_def.vc_version)
)
+ return err_msg
+
+ if toolset:
+ if toolset.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: %s < %s VS2017',
+ repr(toolset.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: toolset version {} < {} VS2017".format(
+ repr(spectre_libs), repr(toolset.version), repr(VS2017.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+
+ if platform_def.is_uwp:
+ debug(
+ 'invalid: spectre_libs=%s and platform_type=%s',
+ repr(spectre_libs), repr(platform_def.vc_platform)
+ )
+ err_msg = "MSVC_SPECTRE_LIBS ({}) are not supported for platform type ({})".format(
+ repr(spectre_libs), repr(platform_def.vc_platform)
+ )
+ return err_msg
+
+ return None
+
+def _msvc_script_argument_spectre(env, msvc, vc_dir, toolset, platform_def, arglist):
+
+ spectre_libs = env['MSVC_SPECTRE_LIBS']
+ debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
+
+ if not spectre_libs:
+ return None
+
+ if spectre_libs not in _ARGUMENT_BOOLEAN_TRUE:
+ return None
+
+ err_msg = _msvc_script_argument_spectre_constraints(msvc, toolset, spectre_libs, platform_def)
+ if err_msg:
raise MSVCArgumentError(err_msg)
+ if toolset:
+ spectre_dir = os.path.join(vc_dir, "Tools", "MSVC", toolset.version, "lib", "spectre")
+ if not os.path.exists(spectre_dir):
+ debug(
+ 'spectre libs: msvc_version=%s, toolset_version=%s, spectre_dir=%s',
+ repr(msvc.version), repr(toolset.version), repr(spectre_dir)
+ )
+ err_msg = "Spectre libraries not found for MSVC_VERSION {} toolset version {}".format(
+ repr(msvc.version), repr(toolset.version)
+ )
+ raise MSVCSpectreLibsNotFound(err_msg)
+
spectre_arg = 'spectre'
- # spectre libs may not be installed
+ # spectre libs may not be installed for host/target
argpair = (SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
arglist.append(argpair)
@@ -723,66 +824,111 @@ def _msvc_script_argument_user(env, msvc, arglist):
return script_args
+def _msvc_process_construction_variables(env):
+
+ for cache_variable in [
+ _MSVC_FORCE_DEFAULT_TOOLSET,
+ _MSVC_FORCE_DEFAULT_SDK,
+ ]:
+ if cache_variable:
+ return True
+
+ for env_variable in [
+ 'MSVC_UWP_APP',
+ 'MSVC_TOOLSET_VERSION',
+ 'MSVC_SDK_VERSION',
+ 'MSVC_SPECTRE_LIBS',
+ ]:
+ if env.get(env_variable, None) != None:
+ return True
+
+ return False
+
def msvc_script_arguments(env, version, vc_dir, arg):
arglist = []
- msvc = _msvc_version(version)
-
if arg:
argpair = (SortOrder.ARCH, arg)
arglist.append(argpair)
+ msvc = _msvc_version(version)
+
if 'MSVC_SCRIPT_ARGS' in env:
user_argstr = _msvc_script_argument_user(env, msvc, arglist)
else:
user_argstr = None
- if 'MSVC_UWP_APP' in env:
- uwp = _msvc_script_argument_uwp(env, msvc, arglist)
- else:
- uwp = None
+ if _msvc_process_construction_variables(env):
- if user_argstr:
- _user_script_argument_uwp(env, uwp, user_argstr)
+ # MSVC_UWP_APP
- platform_type = 'uwp' if uwp else 'desktop'
+ if 'MSVC_UWP_APP' in env:
+ uwp = _msvc_script_argument_uwp(env, msvc, arglist)
+ else:
+ uwp = None
- if 'MSVC_SDK_VERSION' in env:
- sdk_version = _msvc_script_argument_sdk(env, msvc, platform_type, arglist)
- else:
- sdk_version = None
+ if user_argstr:
+ _user_script_argument_uwp(env, uwp, user_argstr)
- if user_argstr:
- user_sdk = _user_script_argument_sdk(env, sdk_version, user_argstr)
- else:
- user_sdk = None
+ is_uwp = True if uwp else False
+ platform_def = WinSDK.get_msvc_platform(is_uwp)
- if _MSVC_FORCE_DEFAULT_SDK:
- if not sdk_version and not user_sdk:
- sdk_version = _msvc_script_default_sdk(env, msvc, platform_type, arglist)
+ # MSVC_TOOLSET_VERSION
- if 'MSVC_TOOLSET_VERSION' in env:
- toolset_version = _msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
- else:
- toolset_version = None
+ if 'MSVC_TOOLSET_VERSION' in env:
+ toolset_version = _msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
+ else:
+ toolset_version = None
- if user_argstr:
- user_toolset = _user_script_argument_toolset(env, toolset_version, user_argstr)
- else:
- user_toolset = None
+ if user_argstr:
+ user_toolset = _user_script_argument_toolset(env, toolset_version, user_argstr)
+ else:
+ user_toolset = None
- if _MSVC_FORCE_DEFAULT_TOOLSET:
if not toolset_version and not user_toolset:
- toolset_version = _msvc_script_default_toolset(env, msvc, vc_dir, arglist)
-
- if 'MSVC_SPECTRE_LIBS' in env:
- spectre = _msvc_script_argument_spectre(env, msvc, arglist)
- else:
- spectre = None
-
- if user_argstr:
- _user_script_argument_spectre(env, spectre, user_argstr)
+ default_toolset = _msvc_script_default_toolset(env, msvc, vc_dir, arglist)
+ else:
+ default_toolset = None
+
+ if _MSVC_FORCE_DEFAULT_TOOLSET:
+ if default_toolset:
+ toolset_version = default_toolset
+
+ if user_toolset:
+ toolset = None
+ elif toolset_version:
+ toolset = _toolset_version(toolset_version)
+ elif default_toolset:
+ toolset = _toolset_version(default_toolset)
+ else:
+ toolset = None
+
+ # MSVC_SDK_VERSION
+
+ if 'MSVC_SDK_VERSION' in env:
+ sdk_version = _msvc_script_argument_sdk(env, msvc, toolset, platform_def, arglist)
+ else:
+ sdk_version = None
+
+ if user_argstr:
+ user_sdk = _user_script_argument_sdk(env, sdk_version, user_argstr)
+ else:
+ user_sdk = None
+
+ if _MSVC_FORCE_DEFAULT_SDK:
+ if not sdk_version and not user_sdk:
+ sdk_version = _msvc_script_default_sdk(env, msvc, platform_def, arglist)
+
+ # MSVC_SPECTRE_LIBS
+
+ if 'MSVC_SPECTRE_LIBS' in env:
+ spectre = _msvc_script_argument_spectre(env, msvc, vc_dir, toolset, platform_def, arglist)
+ else:
+ spectre = None
+
+ if user_argstr:
+ _user_script_argument_spectre(env, spectre, user_argstr)
if arglist:
arglist.sort()
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
index ba70b24..ed87f9d 100644
--- a/SCons/Tool/MSCommon/MSVC/Util.py
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -83,3 +83,23 @@ def get_version_prefix(version):
rval = ''
return rval
+re_msvc_version_prefix = re.compile(r'^(?P[1-9][0-9]?[.][0-9]).*')
+
+def get_msvc_version_prefix(version):
+ """Get the msvc version number prefix from a string.
+
+ Args:
+ version: str
+ version string
+
+ Returns:
+ str: the msvc version number prefix
+
+ """
+ m = re_msvc_version_prefix.match(version)
+ if m:
+ rval = m.group('version')
+ else:
+ rval = ''
+ return rval
+
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
index 8338c27..42526c2 100644
--- a/SCons/Tool/MSCommon/MSVC/WinSDK.py
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -43,10 +43,13 @@ from . import Dispatcher
Dispatcher.register_modulename(__name__)
+_DESKTOP = Config.MSVC_PLATFORM_INTERNAL['Desktop']
+_UWP = Config.MSVC_PLATFORM_INTERNAL['UWP']
+
def _new_sdk_map():
sdk_map = {
- 'desktop': [],
- 'uwp': [],
+ _DESKTOP.vc_platform: [],
+ _UWP.vc_platform: [],
}
return sdk_map
@@ -84,20 +87,20 @@ def _sdk_10_layout(version):
if not os.path.exists(sdk_inc_path):
continue
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
+ for vc_platform, sdk_inc_file in [
+ (_DESKTOP.vc_platform, 'winsdkver.h'),
+ (_UWP.vc_platform, 'windows.h'),
]:
if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
continue
- key = (version_nbr, platform_type)
+ key = (version_nbr, vc_platform)
if key in sdk_version_platform_seen:
continue
sdk_version_platform_seen.add(key)
- sdk_map[platform_type].append(version_nbr)
+ sdk_map[vc_platform].append(version_nbr)
for key, val in sdk_map.items():
val.sort(reverse=True)
@@ -128,20 +131,20 @@ def _sdk_81_layout(version):
if not os.path.exists(sdk_inc_path):
continue
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
+ for vc_platform, sdk_inc_file in [
+ (_DESKTOP.vc_platform, 'winsdkver.h'),
+ (_UWP.vc_platform, 'windows.h'),
]:
if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
continue
- key = (version_nbr, platform_type)
+ key = (version_nbr, vc_platform)
if key in sdk_version_platform_seen:
continue
sdk_version_platform_seen.add(key)
- sdk_map[platform_type].append(version_nbr)
+ sdk_map[vc_platform].append(version_nbr)
for key, val in sdk_map.items():
val.sort(reverse=True)
@@ -218,9 +221,13 @@ def _sdk_map(version_list):
_sdk_cache[key] = sdk_map
return sdk_map
-def get_sdk_version_list(version_list, platform_type):
+def get_msvc_platform(is_uwp=False):
+ platform_def = _UWP if is_uwp else _DESKTOP
+ return platform_def
+
+def get_sdk_version_list(version_list, platform_def):
sdk_map = _sdk_map(version_list)
- sdk_list = sdk_map.get(platform_type, [])
+ sdk_list = sdk_map.get(platform_def.vc_platform, [])
return sdk_list
def get_msvc_sdk_version_list(msvc_version, msvc_uwp_app=False):
@@ -235,8 +242,8 @@ def get_msvc_sdk_version_list(msvc_version, msvc_uwp_app=False):
return sdk_versions
is_uwp = True if msvc_uwp_app in Config.BOOLEAN_SYMBOLS[True] else False
- platform_type = 'uwp' if is_uwp else 'desktop'
- sdk_list = get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
+ platform_def = get_msvc_platform(is_uwp)
+ sdk_list = get_sdk_version_list(vs_def.vc_sdk_versions, platform_def)
sdk_versions.extend(sdk_list)
debug('sdk_versions=%s', repr(sdk_versions))
diff --git a/SCons/Tool/msvc.xml b/SCons/Tool/msvc.xml
index 11c6478..9297100 100644
--- a/SCons/Tool/msvc.xml
+++ b/SCons/Tool/msvc.xml
@@ -950,6 +950,13 @@ type (i.e., UWP or Desktop). The requeste
platform type components do not appear to be installed.
+
+The &cv-MSVC_SDK_VERSION; version is 8.1, the platform type is
+UWP, and the build tools selected are from Visual Studio 2017
+and later (i.e., &cv-link-MSVC_VERSION; must be '14.0' or &cv-link-MSVC_TOOLSET_VERSION;
+must be '14.0').
+
+
@@ -1209,6 +1216,12 @@ An exception is raised when any of the following conditions are satisfied:
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+&cv-MSVC_SPECTRE_LIBS; is enabled and the platform type is UWP. There
+are no spectre-mitigated libraries for Universal Windows Platform (UWP) applications or
+components.
+
+
@@ -1240,8 +1253,8 @@ details.
-The existence of the spectre mitigations libraries is not verified when &cv-MSVC_SPECTRE_LIBS;
-is enabled which could result in build failures.
+The existence of the spectre libraries host architecture and target architecture folders are not
+verified when &cv-MSVC_SPECTRE_LIBS; is enabled which could result in build failures.
The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen
index d5980ff..80d5b18 100644
--- a/doc/generated/variables.gen
+++ b/doc/generated/variables.gen
@@ -4994,6 +4994,13 @@ type (i.e., UWP or Desktop). The requeste
platform type components do not appear to be installed.
+
+The &cv-MSVC_SDK_VERSION; version is 8.1, the platform type is
+UWP, and the build tools selected are from Visual Studio 2017
+and later (i.e., &cv-link-MSVC_VERSION; must be '14.0' or &cv-link-MSVC_TOOLSET_VERSION;
+must be '14.0').
+
+
@@ -5084,6 +5091,12 @@ An exception is raised when any of the following conditions are satisfied:
and &cv-link-MSVC_SCRIPT_ARGS; are not allowed.
+
+&cv-MSVC_SPECTRE_LIBS; is enabled and the platform type is UWP. There
+are no spectre-mitigated libraries for Universal Windows Platform (UWP) applications or
+components.
+
+
@@ -5115,8 +5128,8 @@ details.
-The existence of the spectre mitigations libraries is not verified when &cv-MSVC_SPECTRE_LIBS;
-is enabled which could result in build failures.
+The existence of the spectre libraries host architecture and target architecture folders are not
+verified when &cv-MSVC_SPECTRE_LIBS; is enabled which could result in build failures.
The burden is on the user to ensure the requisite libraries with spectre mitigations are installed.
--
cgit v0.12
From f500d2e6d12d50feec93517c077194adc9a31306 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:26:56 -0400
Subject: Fix sider issue.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 33e13fd..556cae8 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -839,7 +839,7 @@ def _msvc_process_construction_variables(env):
'MSVC_SDK_VERSION',
'MSVC_SPECTRE_LIBS',
]:
- if env.get(env_variable, None) != None:
+ if env.get(env_variable, None) is not None:
return True
return False
--
cgit v0.12
From 8dd2c436317301067f2637829572c36499e24318 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 29 Jun 2022 06:58:30 -0400
Subject: Use msvc version prefix instead of version prefix for internal
dictionary lookup.
---
SCons/Tool/MSCommon/MSVC/Config.py | 2 +-
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 2 +-
SCons/Tool/MSCommon/MSVC/WinSDK.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
index 3b71cd8..fa7dbc1 100644
--- a/SCons/Tool/MSCommon/MSVC/Config.py
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -318,7 +318,7 @@ for policy_value, policy_symbol_list in [
def verify():
from .. import vc
for msvc_version in vc._VCVER:
- vc_version = Util.get_version_prefix(msvc_version)
+ vc_version = Util.get_msvc_version_prefix(msvc_version)
if vc_version in MSVC_VERSION_INTERNAL:
continue
err_msg = 'vc_version {} not in MSVC_VERSION_INTERNAL'.format(repr(vc_version))
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 556cae8..56a4676 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -180,7 +180,7 @@ MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
def _msvc_version(version):
- verstr = Util.get_version_prefix(version)
+ verstr = Util.get_msvc_version_prefix(version)
vs_def = Config.MSVC_VERSION_INTERNAL[verstr]
version_args = MSVC_VERSION_ARGS_DEFINITION(
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
index 42526c2..b17f850 100644
--- a/SCons/Tool/MSCommon/MSVC/WinSDK.py
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -235,7 +235,7 @@ def get_msvc_sdk_version_list(msvc_version, msvc_uwp_app=False):
sdk_versions = []
- verstr = Util.get_version_prefix(msvc_version)
+ verstr = Util.get_msvc_version_prefix(msvc_version)
vs_def = Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
if not vs_def:
debug('vs_def is not defined')
--
cgit v0.12
From a63c1cfdeffbcf7e9214702df4f93e5f015ead10 Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 29 Jun 2022 15:20:44 -0400
Subject: Add 14.0 toolset registry check as done in msvc vsvars140.bat.
---
SCons/Tool/MSCommon/MSVC/Registry.py | 3 +++
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 19 ++++++++++++++++++-
SCons/Tool/MSCommon/vc.py | 1 -
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
index 492f3d0..9ffa01e 100644
--- a/SCons/Tool/MSCommon/MSVC/Registry.py
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -107,3 +107,6 @@ def windows_kit_query_paths(version):
q = windows_kits(version)
return microsoft_query_paths(q)
+def vstudio_sxs_vc7(version):
+ return '\\'.join([r'VisualStudio\SxS\VC7', version])
+
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 56a4676..4db478a 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -40,6 +40,7 @@ from ..common import (
from . import Util
from . import Config
+from . import Registry
from . import WinSDK
from .Exceptions import (
@@ -491,13 +492,16 @@ def _msvc_read_toolset_default(msvc, vc_dir):
_toolset_version_cache = {}
_toolset_default_cache = {}
+_toolset_have140_cache = None
def _reset_toolset_cache():
global _toolset_version_cache
global _toolset_default_cache
+ global _toolset_have140_cache
debug('reset: toolset cache')
_toolset_version_cache = {}
_toolset_default_cache = {}
+ _toolset_have140_cache = None
def _msvc_version_toolsets(msvc, vc_dir):
@@ -519,10 +523,23 @@ def _msvc_default_toolset(msvc, vc_dir):
return toolset_default
+def _msvc_have140_toolset():
+ global _toolset_have140_cache
+
+ if _toolset_have140_cache is None:
+ suffix = Registry.vstudio_sxs_vc7('14.0')
+ vcinstalldirs = [record[0] for record in Registry.microsoft_query_paths(suffix)]
+ debug('vc140 toolset: paths=%s', repr(vcinstalldirs))
+ _toolset_have140_cache = True if vcinstalldirs else False
+
+ return _toolset_have140_cache
+
def _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version):
if toolset_version == '14.0':
- return toolset_version
+ if _msvc_have140_toolset():
+ return toolset_version
+ return None
toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index 7c65879..502a71f 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -1300,7 +1300,6 @@ def msvc_setup_env_user(env=None):
# Intent is to use msvc tools:
# MSVC_VERSION: defined and evaluates True
# MSVS_VERSION: defined and evaluates True
- # MSVC_TOOLSET_VERSION: defined and evaluates True
# MSVC_USE_SCRIPT: defined and (is string or evaluates False)
# MSVC_USE_SETTINGS: defined and is not None
--
cgit v0.12
From fa7f870b7768fae625396c0a0dfface959fee65f Mon Sep 17 00:00:00 2001
From: Joseph Brill <48932340+jcbrill@users.noreply.github.com>
Date: Wed, 29 Jun 2022 20:44:23 -0400
Subject: Fix Util.py docstring for listdir_dirs. Minor update to reading sxs
toolsets and toolset folders.
---
SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 64 ++++++++++++++---------------
SCons/Tool/MSCommon/MSVC/Util.py | 26 +++++++-----
2 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
index 4db478a..14c8c6c 100644
--- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -398,16 +398,16 @@ def _msvc_read_toolset_file(msvc, filename):
debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
return toolset_version
-def _msvc_sxs_toolset_folder(msvc, sxs_folder):
+def _msvc_sxs_toolset_folder(msvc, sxs_version):
- if re_toolset_sxs.match(sxs_folder):
- return sxs_folder
+ if re_toolset_sxs.match(sxs_version):
+ return sxs_version
- key = (msvc.vs_def.vc_buildtools_def.vc_version, sxs_folder)
+ key = (msvc.vs_def.vc_buildtools_def.vc_version, sxs_version)
if key in _msvc_sxs_bugfix_folder:
- return sxs_folder
+ return sxs_version
- debug('sxs folder: ignore version=%s', repr(sxs_folder))
+ debug('sxs folder: ignore version=%s', repr(sxs_version))
return None
def _msvc_sxs_toolset_version(msvc, sxs_toolset):
@@ -429,35 +429,35 @@ def _msvc_read_toolset_folders(msvc, vc_dir):
toolsets_full = []
build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
- sxs_folders = [f.name for f in os.scandir(build_dir) if f.is_dir()]
- for sxs_folder in sxs_folders:
- sxs_toolset = _msvc_sxs_toolset_folder(msvc, sxs_folder)
- if not sxs_toolset:
- continue
- filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
- filepath = os.path.join(build_dir, sxs_toolset, filename)
- debug('sxs toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_version = _msvc_read_toolset_file(msvc, filepath)
- if not toolset_version:
+ if os.path.exists(build_dir):
+ for sxs_version, sxs_path in Util.listdir_dirs(build_dir):
+ sxs_version = _msvc_sxs_toolset_folder(msvc, sxs_version)
+ if not sxs_version:
continue
- toolsets_sxs[sxs_toolset] = toolset_version
- debug(
- 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
- repr(msvc.version), repr(sxs_toolset), toolset_version
- )
+ filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_version)
+ filepath = os.path.join(sxs_path, filename)
+ debug('sxs toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_version = _msvc_read_toolset_file(msvc, filepath)
+ if not toolset_version:
+ continue
+ toolsets_sxs[sxs_version] = toolset_version
+ debug(
+ 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(sxs_version), repr(toolset_version)
+ )
toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
- toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
- for toolset_version in toolsets:
- binpath = os.path.join(toolset_dir, toolset_version, "bin")
- debug('toolset: check binpath=%s', repr(binpath))
- if os.path.exists(binpath):
- toolsets_full.append(toolset_version)
- debug(
- 'toolset: msvc_version=%s, toolset_version=%s',
- repr(msvc.version), repr(toolset_version)
- )
+ if os.path.exists(toolset_dir):
+ for toolset_version, toolset_path in Util.listdir_dirs(toolset_dir):
+ binpath = os.path.join(toolset_path, "bin")
+ debug('toolset: check binpath=%s', repr(binpath))
+ if os.path.exists(binpath):
+ toolsets_full.append(toolset_version)
+ debug(
+ 'toolset: msvc_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(toolset_version)
+ )
toolsets_full.sort(reverse=True)
debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
index ed87f9d..f1983ba 100644
--- a/SCons/Tool/MSCommon/MSVC/Util.py
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -29,14 +29,17 @@ import os
import re
def listdir_dirs(p):
- """Get a list of qualified subdirectory paths from a windows path.
+ """
+ Return a list of tuples for each subdirectory of the given directory path.
+ Each tuple is comprised of the subdirectory name and the qualified subdirectory path.
+ Assumes the given directory path exists and is a directory.
Args:
p: str
- windows path
+ directory path
Returns:
- List[str]: list of qualified subdirectory paths
+ list[tuple[str,str]]: a list of tuples
"""
dirs = []
@@ -47,14 +50,15 @@ def listdir_dirs(p):
return dirs
def process_path(p):
- """Normalize a windows path.
+ """
+ Normalize a system path
Args:
p: str
- windows path
+ system path
Returns:
- str: normalized windows path
+ str: normalized system path
"""
if p:
@@ -66,11 +70,12 @@ def process_path(p):
re_version_prefix = re.compile(r'^(?P[0-9.]+).*')
def get_version_prefix(version):
- """Get the version number prefix from a string.
+ """
+ Get the version number prefix from a string.
Args:
version: str
- version string
+ version specification
Returns:
str: the version number prefix
@@ -86,11 +91,12 @@ def get_version_prefix(version):
re_msvc_version_prefix = re.compile(r'^(?P[1-9][0-9]?[.][0-9]).*')
def get_msvc_version_prefix(version):
- """Get the msvc version number prefix from a string.
+ """
+ Get the msvc version number prefix from a string.
Args:
version: str
- version string
+ version specification
Returns:
str: the msvc version number prefix
--
cgit v0.12
From 3fc497c7775f572a32056a1c6b52ee4592c4bced Mon Sep 17 00:00:00 2001
From: Mats Wichmann
Date: Sun, 26 Jun 2022 13:07:57 -0600
Subject: Improvements to lex and yacc tools
The mocked tools mylex.py and myyacc.py now understand the file-generation
options, and generate a dummy file with predictable contents, for
checking. This allows more testing of the path through the SCons support
for these two without needing live commands.
New tests added which invoke the file-generation options, and make
sure the extra files are created, and that SCons detects and tracks
the added targets. Work is done in a subdirectory, which exposes some
existing known inconsistent behavior (the regular generated file goes
in the subdir per the LEXCOM and YACCOM generated line, while the ones
generated from commandline options go in the topdir) - but we're going
to allow that behavior to continue for backwards compat.
Same fix applied to yacc tool that PR #4168 did for lex - do subst_list()
instead of subst() to preserve spaces in paths. That fix left the lex
tool unable to pass the new test, as it could not see the individual
arguments in the FLAGS variable, which was solved by indexing into the
subst'd list so we can iterate over the args again.
Test and tool cleanup; add DefaultEnvironment calls, etc.
Note this mentions, but does not address the problem described in issue 4154.
Signed-off-by: Mats Wichmann
---
CHANGES.txt | 2 +
SCons/Tool/__init__.py | 8 +--
SCons/Tool/lex.py | 58 ++++++++++++---------
SCons/Tool/lex.xml | 35 ++++++++++++-
SCons/Tool/yacc.py | 73 +++++++++++++++-----------
SCons/Tool/yacc.xml | 70 ++++++++++++++++++++++---
doc/scons.mod | 1 -
test/LEX/FLEXFLAGS.py | 93 ++++++++++++++++++++++++++++++++++
test/LEX/LEX.py | 1 +
test/LEX/LEXCOM.py | 20 ++++----
test/LEX/LEXCOMSTR.py | 22 ++++----
test/LEX/LEXFLAGS.py | 10 ++--
test/LEX/lex_headerfile.py | 4 ++
test/LEX/live.py | 28 ++++------
test/LEX/live_mingw.py | 4 +-
test/LEX/no_lex.py | 12 ++---
test/YACC/BISONFLAGS.py | 92 +++++++++++++++++++++++++++++++++
test/YACC/YACC-fixture/myyacc.py | 12 +++--
test/YACC/YACC.py | 36 +++++++------
test/YACC/YACCCOM.py | 20 ++++----
test/YACC/YACCCOMSTR.py | 22 ++++----
test/YACC/YACCFLAGS-fixture/myyacc.py | 78 ++++++++++++++++++++++------
test/YACC/YACCFLAGS.py | 31 ++++++------
test/YACC/YACCHFILESUFFIX.py | 33 ++++++------
test/YACC/YACCHXXFILESUFFIX.py | 33 ++++++------
test/YACC/YACCVCGFILESUFFIX.py | 33 ++++++------
test/YACC/live-check-output-cleaned.py | 13 +++--
test/YACC/live.py | 21 ++++----
test/fixture/mylex.py | 31 +++++++++++-
testing/framework/TestSCons.py | 33 ++++++++----
30 files changed, 668 insertions(+), 261 deletions(-)
create mode 100644 test/LEX/FLEXFLAGS.py
create mode 100644 test/YACC/BISONFLAGS.py
diff --git a/CHANGES.txt b/CHANGES.txt
index bea5838..6188863 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -202,6 +202,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
but was not applied to other dialects, and e2e tests explicitly checked
that FORTRANFLAGS did not propagate outside the FORTRAN dialect,
so the conclusion is that behavior is intentional (issue #2257)
+ - Improvements to lex and yacc tools: better documentation of
+ extra-file options, add test for extra-file behavior.
From Zhichang Yu:
- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT.
diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py
index 8e4a22d..afc579f 100644
--- a/SCons/Tool/__init__.py
+++ b/SCons/Tool/__init__.py
@@ -36,6 +36,7 @@ tool specifications.
import sys
import os
import importlib.util
+from typing import Optional
import SCons.Builder
import SCons.Errors
@@ -829,7 +830,7 @@ def tool_list(platform, env):
return [x for x in tools if x]
-def find_program_path(env, key_program, default_paths=None, add_path=False) -> str:
+def find_program_path(env, key_program, default_paths=None, add_path=False) -> Optional[str]:
"""
Find the location of a tool using various means.
@@ -849,6 +850,8 @@ def find_program_path(env, key_program, default_paths=None, add_path=False) -> s
# Then in the OS path
path = SCons.Util.WhereIs(key_program)
if path:
+ if add_path:
+ env.AppendENVPath('PATH', os.path.dirname(path))
return path
# Finally, add the defaults and check again.
@@ -864,8 +867,7 @@ def find_program_path(env, key_program, default_paths=None, add_path=False) -> s
# leave that to the caller, unless add_path is true.
env['ENV']['PATH'] = save_path
if path and add_path:
- bin_dir = os.path.dirname(path)
- env.AppendENVPath('PATH', bin_dir)
+ env.AppendENVPath('PATH', os.path.dirname(path))
return path
diff --git a/SCons/Tool/lex.py b/SCons/Tool/lex.py
index 96f9bcb..262fe25 100644
--- a/SCons/Tool/lex.py
+++ b/SCons/Tool/lex.py
@@ -23,6 +23,9 @@
"""Tool-specific initialization for lex.
+This tool should support multiple lex implementations,
+but is in actuality biased towards GNU Flex.
+
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.
@@ -30,14 +33,17 @@ selection method.
import os.path
import sys
+from typing import Optional
import SCons.Action
import SCons.Tool
-import SCons.Util
import SCons.Warnings
from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
from SCons.Platform.win32 import CHOCO_DEFAULT_PATH
+from SCons.Util import CLVar, to_String
+
+DEFAULT_PATHS = CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS
LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR")
@@ -47,20 +53,25 @@ else:
BINS = ["flex", "lex"]
-def lexEmitter(target, source, env):
- sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0]))
+def lexEmitter(target, source, env) -> tuple:
+ """Adds extra files generated by lex program to target list."""
+ sourceBase, sourceExt = os.path.splitext(to_String(source[0]))
if sourceExt == ".lm": # If using Objective-C
target = [sourceBase + ".m"] # the extension is ".m".
- # This emitter essentially tries to add to the target all extra
- # files generated by flex.
-
- # Different options that are used to trigger the creation of extra files.
+ # With --header-file and ----tables-file, the file to write is defined
+ # by the option argument. Extract this and include in the list of targets.
+ # NOTE: a filename passed to the command this way is not modified by SCons,
+ # and so will be interpreted relative to the project top directory at
+ # execution time, while the name added to the target list will be
+ # interpreted relative to the SConscript directory - a possibile mismatch.
+ #
+ # These are GNU flex-only options.
+ # TODO: recognize --outfile also?
file_gen_options = ["--header-file=", "--tables-file="]
-
lexflags = env.subst_list("$LEXFLAGS", target=target, source=source)
- for option in SCons.Util.CLVar(lexflags):
+ for option in lexflags[0]:
for fileGenOption in file_gen_options:
l = len(fileGenOption)
if option[:l] == fileGenOption:
@@ -68,28 +79,29 @@ def lexEmitter(target, source, env):
# file name to the target list.
file_name = option[l:].strip()
target.append(file_name)
+
return target, source
-def get_lex_path(env, append_paths=False):
+def get_lex_path(env, append_paths=False) -> Optional[str]:
"""
- Find the path to the lex tool, searching several possible names
+ Returns the path to the lex tool, searching several possible names.
- Only called in the Windows case, so the default_path
- can be Windows-specific
+ Only called in the Windows case, so the `default_path` argument to
+ :func:`find_program_path` can be Windows-specific.
- :param env: current construction environment
- :param append_paths: if set, add the path to the tool to PATH
- :return: path to lex tool, if found
+ Args:
+ env: current construction environment
+ append_paths: if set, add the path to the tool to PATH
"""
for prog in BINS:
bin_path = SCons.Tool.find_program_path(
env,
prog,
- default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ default_paths=DEFAULT_PATHS,
+ add_path=append_paths,
+ )
if bin_path:
- if append_paths:
- env.AppendENVPath('PATH', os.path.dirname(bin_path))
return bin_path
SCons.Warnings.warn(
@@ -98,7 +110,7 @@ def get_lex_path(env, append_paths=False):
)
-def generate(env):
+def generate(env) -> None:
"""Add Builders and construction variables for lex to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
@@ -117,21 +129,21 @@ def generate(env):
cxx_file.add_action(".ll", LexAction)
cxx_file.add_emitter(".ll", lexEmitter)
- env["LEXFLAGS"] = SCons.Util.CLVar("")
+ env["LEXFLAGS"] = CLVar("")
if sys.platform == 'win32':
# ignore the return - we do not need the full path here
_ = get_lex_path(env, append_paths=True)
env["LEX"] = env.Detect(BINS)
if not env.get("LEXUNISTD"):
- env["LEXUNISTD"] = SCons.Util.CLVar("")
+ env["LEXUNISTD"] = CLVar("")
env["LEXCOM"] = "$LEX $LEXUNISTD $LEXFLAGS -t $SOURCES > $TARGET"
else:
env["LEX"] = env.Detect(BINS)
env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
-def exists(env):
+def exists(env) -> Optional[str]:
if sys.platform == 'win32':
return get_lex_path(env)
else:
diff --git a/SCons/Tool/lex.xml b/SCons/Tool/lex.xml
index 5afb754..8622ced 100644
--- a/SCons/Tool/lex.xml
+++ b/SCons/Tool/lex.xml
@@ -1,6 +1,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/c-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/c-hl.xml
index 1503dd1..44ab02d 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/c-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/c-hl.xml
@@ -1,101 +1,101 @@
-
-
-
-
- /**
- */
-
-
-
- ///
-
-
-
- /*
- */
-
- //
-
-
- #
- \
-
-
-
- "
- \
-
-
- '
- \
-
-
- 0x
- ul
- lu
- u
- l
-
-
-
- .
-
- e
- ul
- lu
- u
- f
- l
-
-
-
- auto
- _Bool
- break
- case
- char
- _Complex
- const
- continue
- default
- do
- double
- else
- enum
- extern
- float
- for
- goto
- if
- _Imaginary
- inline
- int
- long
- register
- restrict
- return
- short
- signed
- sizeof
- static
- struct
- switch
- typedef
- union
- unsigned
- void
- volatile
- while
-
+
+
+
+
+ /**
+ */
+
+
+
+ ///
+
+
+
+ /*
+ */
+
+ //
+
+
+ #
+ \
+
+
+
+ "
+ \
+
+
+ '
+ \
+
+
+ 0x
+ ul
+ lu
+ u
+ l
+
+
+
+ .
+
+ e
+ ul
+ lu
+ u
+ f
+ l
+
+
+
+ auto
+ _Bool
+ break
+ case
+ char
+ _Complex
+ const
+ continue
+ default
+ do
+ double
+ else
+ enum
+ extern
+ float
+ for
+ goto
+ if
+ _Imaginary
+ inline
+ int
+ long
+ register
+ restrict
+ return
+ short
+ signed
+ sizeof
+ static
+ struct
+ switch
+ typedef
+ union
+ unsigned
+ void
+ volatile
+ while
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/common.xsl b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/common.xsl
index e9b5650..1742377 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/common.xsl
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/common.xsl
@@ -1,120 +1,120 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- unprocessed xslthl style:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unprocessed xslthl style:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/cpp-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/cpp-hl.xml
index db57d5e..2213b7c 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/cpp-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/cpp-hl.xml
@@ -1,150 +1,150 @@
-
-
-
-
- /**
- */
-
-
-
- ///
-
-
-
- /*
- */
-
- //
-
-
- #
- \
-
-
-
- "
- \
-
-
- '
- \
-
-
- 0x
- ul
- lu
- u
- l
-
-
-
- .
-
- e
- ul
- lu
- u
- f
- l
-
-
-
-
- auto
- _Bool
- break
- case
- char
- _Complex
- const
- continue
- default
- do
- double
- else
- enum
- extern
- float
- for
- goto
- if
- _Imaginary
- inline
- int
- long
- register
- restrict
- return
- short
- signed
- sizeof
- static
- struct
- switch
- typedef
- union
- unsigned
- void
- volatile
- while
-
- asm
- dynamic_cast
- namespace
- reinterpret_cast
- try
- bool
- explicit
- new
- static_cast
- typeid
- catch
- false
- operator
- template
- typename
- class
- friend
- private
- this
- using
- const_cast
- inline
- public
- throw
- virtual
- delete
- mutable
- protected
- true
- wchar_t
-
+
+
+
+
+ /**
+ */
+
+
+
+ ///
+
+
+
+ /*
+ */
+
+ //
+
+
+ #
+ \
+
+
+
+ "
+ \
+
+
+ '
+ \
+
+
+ 0x
+ ul
+ lu
+ u
+ l
+
+
+
+ .
+
+ e
+ ul
+ lu
+ u
+ f
+ l
+
+
+
+
+ auto
+ _Bool
+ break
+ case
+ char
+ _Complex
+ const
+ continue
+ default
+ do
+ double
+ else
+ enum
+ extern
+ float
+ for
+ goto
+ if
+ _Imaginary
+ inline
+ int
+ long
+ register
+ restrict
+ return
+ short
+ signed
+ sizeof
+ static
+ struct
+ switch
+ typedef
+ union
+ unsigned
+ void
+ volatile
+ while
+
+ asm
+ dynamic_cast
+ namespace
+ reinterpret_cast
+ try
+ bool
+ explicit
+ new
+ static_cast
+ typeid
+ catch
+ false
+ operator
+ template
+ typename
+ class
+ friend
+ private
+ this
+ using
+ const_cast
+ inline
+ public
+ throw
+ virtual
+ delete
+ mutable
+ protected
+ true
+ wchar_t
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/csharp-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/csharp-hl.xml
index 99c2e3e..8a8a76d 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/csharp-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/csharp-hl.xml
@@ -1,187 +1,187 @@
-
-
-
-
- /**
- */
-
-
-
- ///
-
-
-
- /*
- */
-
- //
-
-
- [
- ]
- (
- )
-
-
-
- #
- \
-
-
-
-
- @"
- "
- \
-
-
-
- "
- \
-
-
- '
- \
-
-
- 0x
- ul
- lu
- u
- l
-
-
-
- .
-
- e
- ul
- lu
- u
- f
- d
- m
- l
-
-
-
- abstract
- as
- base
- bool
- break
- byte
- case
- catch
- char
- checked
- class
- const
- continue
- decimal
- default
- delegate
- do
- double
- else
- enum
- event
- explicit
- extern
- false
- finally
- fixed
- float
- for
- foreach
- goto
- if
- implicit
- in
- int
- interface
- internal
- is
- lock
- long
- namespace
- new
- null
- object
- operator
- out
- override
- params
- private
- protected
- public
- readonly
- ref
- return
- sbyte
- sealed
- short
- sizeof
- stackalloc
- static
- string
- struct
- switch
- this
- throw
- true
- try
- typeof
- uint
- ulong
- unchecked
- unsafe
- ushort
- using
- virtual
- void
- volatile
- while
-
-
-
- add
- alias
- get
- global
- partial
- remove
- set
- value
- where
- yield
-
+
+
+
+
+ /**
+ */
+
+
+
+ ///
+
+
+
+ /*
+ */
+
+ //
+
+
+ [
+ ]
+ (
+ )
+
+
+
+ #
+ \
+
+
+
+
+ @"
+ "
+ \
+
+
+
+ "
+ \
+
+
+ '
+ \
+
+
+ 0x
+ ul
+ lu
+ u
+ l
+
+
+
+ .
+
+ e
+ ul
+ lu
+ u
+ f
+ d
+ m
+ l
+
+
+
+ abstract
+ as
+ base
+ bool
+ break
+ byte
+ case
+ catch
+ char
+ checked
+ class
+ const
+ continue
+ decimal
+ default
+ delegate
+ do
+ double
+ else
+ enum
+ event
+ explicit
+ extern
+ false
+ finally
+ fixed
+ float
+ for
+ foreach
+ goto
+ if
+ implicit
+ in
+ int
+ interface
+ internal
+ is
+ lock
+ long
+ namespace
+ new
+ null
+ object
+ operator
+ out
+ override
+ params
+ private
+ protected
+ public
+ readonly
+ ref
+ return
+ sbyte
+ sealed
+ short
+ sizeof
+ stackalloc
+ static
+ string
+ struct
+ switch
+ this
+ throw
+ true
+ try
+ typeof
+ uint
+ ulong
+ unchecked
+ unsafe
+ ushort
+ using
+ virtual
+ void
+ volatile
+ while
+
+
+
+ add
+ alias
+ get
+ global
+ partial
+ remove
+ set
+ value
+ where
+ yield
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/delphi-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/delphi-hl.xml
index d5b4d1a..2a45d29 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/delphi-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/delphi-hl.xml
@@ -1,200 +1,200 @@
-
-
-
-
-
- {$
- }
-
-
-
-
- (*$
- )
-
-
-
- {
- }
-
-
- (*
- *)
-
- //
-
- '
-
-
-
- #$
-
-
-
-
- #
-
-
-
-
- $
-
-
-
- .
- e
-
-
-
-
- and
- else
- inherited
- packed
- then
- array
- end
- initialization
- procedure
- threadvar
- as
- except
- inline
- program
- to
- asm
- exports
- interface
- property
- try
- begin
- file
- is
- raise
- type
- case
- final
- label
- record
- unit
- class
- finalization
- library
- repeat
- unsafe
- const
- finally
- mod
- resourcestring
- until
- constructor
- for
- nil
- sealed
- uses
- destructor
- function
- not
- set
- var
- dispinterface
- goto
- object
- shl
- while
- div
- if
- of
- shr
- with
- do
- implementation
- or
- static
- xor
- downto
- in
- out
- string
-
-
- at
- on
-
-
- absolute
- dynamic
- local
- platform
- requires
- abstract
- export
- message
- private
- resident
- assembler
- external
- name
- protected
- safecall
- automated
- far
- near
- public
- stdcall
- cdecl
- forward
- nodefault
- published
- stored
- contains
- implements
- overload
- read
- varargs
- default
- index
- override
- readonly
- virtual
- deprecated
- inline
- package
- register
- write
- dispid
- library
- pascal
- reintroduce
- writeonly
-
-
+
+
+
+
+
+ {$
+ }
+
+
+
+
+ (*$
+ )
+
+
+
+ {
+ }
+
+
+ (*
+ *)
+
+ //
+
+ '
+
+
+
+ #$
+
+
+
+
+ #
+
+
+
+
+ $
+
+
+
+ .
+ e
+
+
+
+
+ and
+ else
+ inherited
+ packed
+ then
+ array
+ end
+ initialization
+ procedure
+ threadvar
+ as
+ except
+ inline
+ program
+ to
+ asm
+ exports
+ interface
+ property
+ try
+ begin
+ file
+ is
+ raise
+ type
+ case
+ final
+ label
+ record
+ unit
+ class
+ finalization
+ library
+ repeat
+ unsafe
+ const
+ finally
+ mod
+ resourcestring
+ until
+ constructor
+ for
+ nil
+ sealed
+ uses
+ destructor
+ function
+ not
+ set
+ var
+ dispinterface
+ goto
+ object
+ shl
+ while
+ div
+ if
+ of
+ shr
+ with
+ do
+ implementation
+ or
+ static
+ xor
+ downto
+ in
+ out
+ string
+
+
+ at
+ on
+
+
+ absolute
+ dynamic
+ local
+ platform
+ requires
+ abstract
+ export
+ message
+ private
+ resident
+ assembler
+ external
+ name
+ protected
+ safecall
+ automated
+ far
+ near
+ public
+ stdcall
+ cdecl
+ forward
+ nodefault
+ published
+ stored
+ contains
+ implements
+ overload
+ read
+ varargs
+ default
+ index
+ override
+ readonly
+ virtual
+ deprecated
+ inline
+ package
+ register
+ write
+ dispid
+ library
+ pascal
+ reintroduce
+ writeonly
+
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ini-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ini-hl.xml
index 8a938f3..84be9c6 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ini-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ini-hl.xml
@@ -1,45 +1,45 @@
-
-
-
- ;
-
-
- ^(\[.+\]\s*)$
-
- MULTILINE
-
-
-
- ^(.+)(?==)
-
- MULTILINE
-
+
+
+
+ ;
+
+
+ ^(\[.+\]\s*)$
+
+ MULTILINE
+
+
+
+ ^(.+)(?==)
+
+ MULTILINE
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/java-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/java-hl.xml
index 672d518..d499d83 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/java-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/java-hl.xml
@@ -1,117 +1,117 @@
-
-
-
-
- /**
- */
-
-
-
- /*
- */
-
- //
-
- "
- \
-
-
- '
- \
-
-
- @
- (
- )
-
-
- 0x
-
-
-
- .
- e
- f
- d
- l
-
-
-
- abstract
- boolean
- break
- byte
- case
- catch
- char
- class
- const
- continue
- default
- do
- double
- else
- extends
- final
- finally
- float
- for
- goto
- if
- implements
- import
- instanceof
- int
- interface
- long
- native
- new
- package
- private
- protected
- public
- return
- short
- static
- strictfp
- super
- switch
- synchronized
- this
- throw
- throws
- transient
- try
- void
- volatile
- while
-
+
+
+
+
+ /**
+ */
+
+
+
+ /*
+ */
+
+ //
+
+ "
+ \
+
+
+ '
+ \
+
+
+ @
+ (
+ )
+
+
+ 0x
+
+
+
+ .
+ e
+ f
+ d
+ l
+
+
+
+ abstract
+ boolean
+ break
+ byte
+ case
+ catch
+ char
+ class
+ const
+ continue
+ default
+ do
+ double
+ else
+ extends
+ final
+ finally
+ float
+ for
+ goto
+ if
+ implements
+ import
+ instanceof
+ int
+ interface
+ long
+ native
+ new
+ package
+ private
+ protected
+ public
+ return
+ short
+ static
+ strictfp
+ super
+ switch
+ synchronized
+ this
+ throw
+ throws
+ transient
+ try
+ void
+ volatile
+ while
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/javascript-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/javascript-hl.xml
index 08c90ba..5749b88 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/javascript-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/javascript-hl.xml
@@ -1,147 +1,147 @@
-
-
-
-
- /*
- */
-
- //
-
- "
- \
-
-
- '
- \
-
-
- 0x
-
-
-
- .
- e
-
-
-
- break
- case
- catch
- continue
- default
- delete
- do
- else
- finally
- for
- function
- if
- in
- instanceof
- new
- return
- switch
- this
- throw
- try
- typeof
- var
- void
- while
- with
-
- abstract
- boolean
- byte
- char
- class
- const
- debugger
- double
- enum
- export
- extends
- final
- float
- goto
- implements
- import
- int
- interface
- long
- native
- package
- private
- protected
- public
- short
- static
- super
- synchronized
- throws
- transient
- volatile
-
-
- prototype
-
- Array
- Boolean
- Date
- Error
- EvalError
- Function
- Math
- Number
- Object
- RangeError
- ReferenceError
- RegExp
- String
- SyntaxError
- TypeError
- URIError
-
- decodeURI
- decodeURIComponent
- encodeURI
- encodeURIComponent
- eval
- isFinite
- isNaN
- parseFloat
- parseInt
-
- Infinity
- NaN
- undefined
-
+
+
+
+
+ /*
+ */
+
+ //
+
+ "
+ \
+
+
+ '
+ \
+
+
+ 0x
+
+
+
+ .
+ e
+
+
+
+ break
+ case
+ catch
+ continue
+ default
+ delete
+ do
+ else
+ finally
+ for
+ function
+ if
+ in
+ instanceof
+ new
+ return
+ switch
+ this
+ throw
+ try
+ typeof
+ var
+ void
+ while
+ with
+
+ abstract
+ boolean
+ byte
+ char
+ class
+ const
+ debugger
+ double
+ enum
+ export
+ extends
+ final
+ float
+ goto
+ implements
+ import
+ int
+ interface
+ long
+ native
+ package
+ private
+ protected
+ public
+ short
+ static
+ super
+ synchronized
+ throws
+ transient
+ volatile
+
+
+ prototype
+
+ Array
+ Boolean
+ Date
+ Error
+ EvalError
+ Function
+ Math
+ Number
+ Object
+ RangeError
+ ReferenceError
+ RegExp
+ String
+ SyntaxError
+ TypeError
+ URIError
+
+ decodeURI
+ decodeURIComponent
+ encodeURI
+ encodeURIComponent
+ eval
+ isFinite
+ isNaN
+ parseFloat
+ parseInt
+
+ Infinity
+ NaN
+ undefined
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/m2-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/m2-hl.xml
index b145f74..a3ef314 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/m2-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/m2-hl.xml
@@ -1,90 +1,90 @@
-
-
-
-
- (*
- *)
-
-
- "
-
-
- '
-
-
- .
- e
-
-
-
- and
- array
- begin
- by
- case
- const
- definition
- div
- do
- else
- elsif
- end
- exit
- export
- for
- from
- if
- implementation
- import
- in
- loop
- mod
- module
- not
- of
- or
- pointer
- procedure
- qualified
- record
- repeat
- return
- set
- then
- to
- type
- until
- var
- while
- with
-
-
+
+
+
+
+ (*
+ *)
+
+
+ "
+
+
+ '
+
+
+ .
+ e
+
+
+
+ and
+ array
+ begin
+ by
+ case
+ const
+ definition
+ div
+ do
+ else
+ elsif
+ end
+ exit
+ export
+ for
+ from
+ if
+ implementation
+ import
+ in
+ loop
+ mod
+ module
+ not
+ of
+ or
+ pointer
+ procedure
+ qualified
+ record
+ repeat
+ return
+ set
+ then
+ to
+ type
+ until
+ var
+ while
+ with
+
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/myxml-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/myxml-hl.xml
index afa4be7..efa90d7 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/myxml-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/myxml-hl.xml
@@ -1,116 +1,116 @@
-
-
-
-
-
-
-
- A
- ABBR
- ACRONYM
- ADDRESS
- APPLET
- AREA
- B
- BASE
- BASEFONT
- BDO
- BIG
- BLOCKQUOTE
- BODY
- BR
- BUTTON
- CAPTION
- CENTER
- CITE
- CODE
- COL
- COLGROUP
- DD
- DEL
- DFN
- DIR
- DIV
- DL
- DT
- EM
- FIELDSET
- FONT
- FORM
- FRAME
- FRAMESET
- H1
- H2
- H3
- H4
- H5
- H6
- HEAD
- HR
- HTML
- I
- IFRAME
- IMG
- INPUT
- INS
- ISINDEX
- KBD
- LABEL
- LEGEND
- LI
- LINK
- MAP
- MENU
- META
- NOFRAMES
- NOSCRIPT
- OBJECT
- OL
- OPTGROUP
- OPTION
- P
- PARAM
- PRE
- Q
- S
- SAMP
- SCRIPT
- SELECT
- SMALL
- SPAN
- STRIKE
- STRONG
- STYLE
- SUB
- SUP
- TABLE
- TBODY
- TD
- TEXTAREA
- TFOOT
- TH
- THEAD
- TITLE
- TR
- TT
- U
- UL
- VAR
- XMP
-
-
-
-
- xsl:
-
-
-
+
+
+
+
+
+
+
+ A
+ ABBR
+ ACRONYM
+ ADDRESS
+ APPLET
+ AREA
+ B
+ BASE
+ BASEFONT
+ BDO
+ BIG
+ BLOCKQUOTE
+ BODY
+ BR
+ BUTTON
+ CAPTION
+ CENTER
+ CITE
+ CODE
+ COL
+ COLGROUP
+ DD
+ DEL
+ DFN
+ DIR
+ DIV
+ DL
+ DT
+ EM
+ FIELDSET
+ FONT
+ FORM
+ FRAME
+ FRAMESET
+ H1
+ H2
+ H3
+ H4
+ H5
+ H6
+ HEAD
+ HR
+ HTML
+ I
+ IFRAME
+ IMG
+ INPUT
+ INS
+ ISINDEX
+ KBD
+ LABEL
+ LEGEND
+ LI
+ LINK
+ MAP
+ MENU
+ META
+ NOFRAMES
+ NOSCRIPT
+ OBJECT
+ OL
+ OPTGROUP
+ OPTION
+ P
+ PARAM
+ PRE
+ Q
+ S
+ SAMP
+ SCRIPT
+ SELECT
+ SMALL
+ SPAN
+ STRIKE
+ STRONG
+ STYLE
+ SUB
+ SUP
+ TABLE
+ TBODY
+ TD
+ TEXTAREA
+ TFOOT
+ TH
+ THEAD
+ TITLE
+ TR
+ TT
+ U
+ UL
+ VAR
+ XMP
+
+
+
+
+ xsl:
+
+
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/perl-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/perl-hl.xml
index da1924a..23fdfd8 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/perl-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/perl-hl.xml
@@ -1,120 +1,120 @@
-
-
-
- #
-
- <<
- '
- "
-
-
-
- "
- \
-
-
- '
- \
-
-
-
- 0x
-
-
-
- .
-
-
-
-
- if
- unless
- while
- until
- foreach
- else
- elsif
- for
- when
- default
- given
-
- caller
- continue
- die
- do
- dump
- eval
- exit
- goto
- last
- next
- redo
- return
- sub
- wantarray
-
- caller
- import
- local
- my
- package
- use
-
- do
- import
- no
- package
- require
- use
-
- bless
- dbmclose
- dbmopen
- package
- ref
- tie
- tied
- untie
- use
-
- and
- or
- not
- eq
- ne
- lt
- gt
- le
- ge
- cmp
-
+
+
+
+ #
+
+ <<
+ '
+ "
+
+
+
+ "
+ \
+
+
+ '
+ \
+
+
+
+ 0x
+
+
+
+ .
+
+
+
+
+ if
+ unless
+ while
+ until
+ foreach
+ else
+ elsif
+ for
+ when
+ default
+ given
+
+ caller
+ continue
+ die
+ do
+ dump
+ eval
+ exit
+ goto
+ last
+ next
+ redo
+ return
+ sub
+ wantarray
+
+ caller
+ import
+ local
+ my
+ package
+ use
+
+ do
+ import
+ no
+ package
+ require
+ use
+
+ bless
+ dbmclose
+ dbmopen
+ package
+ ref
+ tie
+ tied
+ untie
+ use
+
+ and
+ or
+ not
+ eq
+ ne
+ lt
+ gt
+ le
+ ge
+ cmp
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/php-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/php-hl.xml
index 4a70225..0daa348 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/php-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/php-hl.xml
@@ -1,149 +1,149 @@
-
-
-
-
- /**
- */
-
-
-
- ///
-
-
-
- /*
- */
-
- //
- #
-
- "
- \
-
-
-
- '
- \
-
-
-
- <<<
-
-
- 0x
-
-
-
- .
- e
-
-
-
- and
- or
- xor
- __FILE__
- exception
- __LINE__
- array
- as
- break
- case
- class
- const
- continue
- declare
- default
- die
- do
- echo
- else
- elseif
- empty
- enddeclare
- endfor
- endforeach
- endif
- endswitch
- endwhile
- eval
- exit
- extends
- for
- foreach
- function
- global
- if
- include
- include_once
- isset
- list
- new
- print
- require
- require_once
- return
- static
- switch
- unset
- use
- var
- while
- __FUNCTION__
- __CLASS__
- __METHOD__
- final
- php_user_filter
- interface
- implements
- extends
- public
- private
- protected
- abstract
- clone
- try
- catch
- throw
- cfunction
- old_function
- true
- false
-
-
-
-
- ?>
- <?php
- <?=
-
-
+
+
+
+
+ /**
+ */
+
+
+
+ ///
+
+
+
+ /*
+ */
+
+ //
+ #
+
+ "
+ \
+
+
+
+ '
+ \
+
+
+
+ <<<
+
+
+ 0x
+
+
+
+ .
+ e
+
+
+
+ and
+ or
+ xor
+ __FILE__
+ exception
+ __LINE__
+ array
+ as
+ break
+ case
+ class
+ const
+ continue
+ declare
+ default
+ die
+ do
+ echo
+ else
+ elseif
+ empty
+ enddeclare
+ endfor
+ endforeach
+ endif
+ endswitch
+ endwhile
+ eval
+ exit
+ extends
+ for
+ foreach
+ function
+ global
+ if
+ include
+ include_once
+ isset
+ list
+ new
+ print
+ require
+ require_once
+ return
+ static
+ switch
+ unset
+ use
+ var
+ while
+ __FUNCTION__
+ __CLASS__
+ __METHOD__
+ final
+ php_user_filter
+ interface
+ implements
+ extends
+ public
+ private
+ protected
+ abstract
+ clone
+ try
+ catch
+ throw
+ cfunction
+ old_function
+ true
+ false
+
+
+
+
+ ?>
+ <?php
+ <?=
+
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/python-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/python-hl.xml
index 791bc7a..1b1f087 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/python-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/python-hl.xml
@@ -1,100 +1,100 @@
-
-
-
-
-
- @
- (
- )
-
- #
-
- """
-
-
-
- '''
-
-
-
- "
- \
-
-
- '
- \
-
-
- 0x
- l
-
-
-
- .
-
- e
- l
-
-
-
- and
- del
- from
- not
- while
- as
- elif
- global
- or
- with
- assert
- else
- if
- pass
- yield
- break
- except
- import
- print
- class
- exec
- in
- raise
- continue
- finally
- is
- return
- def
- for
- lambda
- try
-
+
+
+
+
+
+ @
+ (
+ )
+
+ #
+
+ """
+
+
+
+ '''
+
+
+
+ "
+ \
+
+
+ '
+ \
+
+
+ 0x
+ l
+
+
+
+ .
+
+ e
+ l
+
+
+
+ and
+ del
+ from
+ not
+ while
+ as
+ elif
+ global
+ or
+ with
+ assert
+ else
+ if
+ pass
+ yield
+ break
+ except
+ import
+ print
+ class
+ exec
+ in
+ raise
+ continue
+ finally
+ is
+ return
+ def
+ for
+ lambda
+ try
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ruby-hl.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ruby-hl.xml
index 78189b0..2f74352 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ruby-hl.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/ruby-hl.xml
@@ -1,109 +1,109 @@
-
-
-
- #
-
- <<
-
-
-
- "
- \
-
-
- %Q{
- }
- \
-
-
- %/
- /
- \
-
-
- '
- \
-
-
- %q{
- }
- \
-
-
- 0x
-
-
-
- .
- e
-
-
-
- alias
- and
- BEGIN
- begin
- break
- case
- class
- def
- defined
- do
- else
- elsif
- END
- end
- ensure
- false
- for
- if
- in
- module
- next
- nil
- not
- or
- redo
- rescue
- retry
- return
- self
- super
- then
- true
- undef
- unless
- until
- when
- while
- yield
-
+
+
+
+ #
+
+ <<
+
+
+
+ "
+ \
+
+
+ %Q{
+ }
+ \
+
+
+ %/
+ /
+ \
+
+
+ '
+ \
+
+
+ %q{
+ }
+ \
+
+
+ 0x
+
+
+
+ .
+ e
+
+
+
+ alias
+ and
+ BEGIN
+ begin
+ break
+ case
+ class
+ def
+ defined
+ do
+ else
+ elsif
+ END
+ end
+ ensure
+ false
+ for
+ if
+ in
+ module
+ next
+ nil
+ not
+ or
+ redo
+ rescue
+ retry
+ return
+ self
+ super
+ then
+ true
+ undef
+ unless
+ until
+ when
+ while
+ yield
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/xslthl-config.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/xslthl-config.xml
index b24e469..910289a 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/xslthl-config.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/highlighting/xslthl-config.xml
@@ -1,46 +1,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/html/highlight.xsl b/SCons/Tool/docbook/docbook-xsl-1.76.1/html/highlight.xsl
index f7307a4..d6fc969 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/html/highlight.xsl
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/html/highlight.xsl
@@ -1,86 +1,86 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/params/bibliography.style.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/params/bibliography.style.xml
index fa44582..363e980 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/params/bibliography.style.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/params/bibliography.style.xml
@@ -1,35 +1,35 @@
-
-
-bibliography.style
-list
-normal
-iso690
-
-
-bibliography.style
-Style used for formatting of biblioentries.
-
-
-
-
-normal
-
-
-
-Description
-
-Currently only normal and
-iso690 styles are supported.
-
-In order to use ISO690 style to the full extent you might need
-to use additional markup described on the
-following WiKi page.
-
-
-
+
+
+bibliography.style
+list
+normal
+iso690
+
+
+bibliography.style
+Style used for formatting of biblioentries.
+
+
+
+
+normal
+
+
+
+Description
+
+Currently only normal and
+iso690 styles are supported.
+
+In order to use ISO690 style to the full extent you might need
+to use additional markup described on the
+following WiKi page.
+
+
+
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/params/highlight.source.xml b/SCons/Tool/docbook/docbook-xsl-1.76.1/params/highlight.source.xml
index 41d7b2f..c4eb1a8 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/params/highlight.source.xml
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/params/highlight.source.xml
@@ -1,82 +1,82 @@
-
-
-highlight.source
-boolean
-
-
-highlight.source
-Should the content of programlisting
-be syntactically highlighted?
-
-
-
-
-
-
-
-
-Description
-
-When this parameter is non-zero, the stylesheets will try to do syntax highlighting of the
-content of programlisting elements. You specify the language for each programlisting
-by using the language attribute. The highlight.default.language
-parameter can be used to specify the language for programlistings without a language
-attribute. Syntax highlighting also works for screen and synopsis elements.
-
-The actual highlighting work is done by the XSLTHL extension module. This is an external Java library that has to be
-downloaded separately (see below).
-
-
-In order to use this extension, you must
-
-add xslthl-2.x.x.jar to your Java classpath. The latest version is available
-from the XSLT syntax highlighting project
-at SourceForge.
-
-
-use a customization layer in which you import one of the following stylesheet modules:
-
-
- html/highlight.xsl
-
-
-
- xhtml/highlight.xsl
-
-
-
- xhtml-1_1/highlight.xsl
-
-
-
- fo/highlight.xsl
-
-
-
-
-
-let either the xslthl.config Java system property or the
-highlight.xslthl.config parameter point to the configuration file for syntax
-highlighting (using URL syntax). DocBook XSL comes with a ready-to-use configuration file,
-highlighting/xslthl-config.xml.
-
-
-
-The extension works with Saxon 6.5.x and Xalan-J. (Saxon 8.5 or later is also supported, but since it is
-an XSLT 2.0 processor it is not guaranteed to work with DocBook XSL in all circumstances.)
-
-The following is an example of a Saxon 6 command adapted for syntax highlighting, to be used on Windows:
-
-
-java -cp c:/Java/saxon.jar;c:/Java/xslthl-2.0.1.jar
--Dxslthl.config=file:///c:/docbook-xsl/highlighting/xslthl-config.xml com.icl.saxon.StyleSheet
--o test.html test.xml myhtml.xsl
-
-
-
-
+
+
+highlight.source
+boolean
+
+
+highlight.source
+Should the content of programlisting
+be syntactically highlighted?
+
+
+
+
+
+
+
+
+Description
+
+When this parameter is non-zero, the stylesheets will try to do syntax highlighting of the
+content of programlisting elements. You specify the language for each programlisting
+by using the language attribute. The highlight.default.language
+parameter can be used to specify the language for programlistings without a language
+attribute. Syntax highlighting also works for screen and synopsis elements.
+
+The actual highlighting work is done by the XSLTHL extension module. This is an external Java library that has to be
+downloaded separately (see below).
+
+
+In order to use this extension, you must
+
+add xslthl-2.x.x.jar to your Java classpath. The latest version is available
+from the XSLT syntax highlighting project
+at SourceForge.
+
+
+use a customization layer in which you import one of the following stylesheet modules:
+
+
+ html/highlight.xsl
+
+
+
+ xhtml/highlight.xsl
+
+
+
+ xhtml-1_1/highlight.xsl
+
+
+
+ fo/highlight.xsl
+
+
+
+
+
+let either the xslthl.config Java system property or the
+highlight.xslthl.config parameter point to the configuration file for syntax
+highlighting (using URL syntax). DocBook XSL comes with a ready-to-use configuration file,
+highlighting/xslthl-config.xml.
+
+
+
+The extension works with Saxon 6.5.x and Xalan-J. (Saxon 8.5 or later is also supported, but since it is
+an XSLT 2.0 processor it is not guaranteed to work with DocBook XSL in all circumstances.)
+
+The following is an example of a Saxon 6 command adapted for syntax highlighting, to be used on Windows:
+
+
+java -cp c:/Java/saxon.jar;c:/Java/xslthl-2.0.1.jar
+-Dxslthl.config=file:///c:/docbook-xsl/highlighting/xslthl-config.xml com.icl.saxon.StyleSheet
+-o test.html test.xml myhtml.xsl
+
+
+
+
diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/jquery.treeview.async.js b/SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/jquery.treeview.async.js
index 2597dde..c91a9c6 100644
--- a/SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/jquery.treeview.async.js
+++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/webhelp/docs/common/jquery/treeview/jquery.treeview.async.js
@@ -1,72 +1,72 @@
-/*
- * Async Treeview 0.1 - Lazy-loading extension for Treeview
- *
- * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
- *
- * Copyright (c) 2007 Jörn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id$
- *
- */
-
-;(function($) {
-
-function load(settings, root, child, container) {
- $.getJSON(settings.url, {root: root}, function(response) {
- function createNode(parent) {
- var current = $("").attr("id", this.id || "").html("" + this.text + "").appendTo(parent);
- if (this.classes) {
- current.children("span").addClass(this.classes);
- }
- if (this.expanded) {
- current.addClass("open");
- }
- if (this.hasChildren || this.children && this.children.length) {
- var branch = $("
");
- for (t in linkTab) {
- results += linkTab[t].toString();
- }
- results += "
";
- } else {
- results = "
" + "Your search returned no results for " + "" + txt_wordsnotfound + "" + "
";
- }
- //alert(results);
- document.getElementById('searchResults').innerHTML = results;
-}
-
-function tokenize(wordsList){
- var stemmedWordsList = new Array(); // Array with the words to look for after removing spaces
- var cleanwordsList = new Array(); // Array with the words to look for
- for(var j in wordsList){
- var word = wordsList[j];
- if(typeof stemmer != "undefined" ){
- stemQueryMap[stemmer(word)] = word;
- } else {
- stemQueryMap[word] = word;
- }
- }
- //stemmedWordsList is the stemmed list of words separated by spaces.
- for (var t in wordsList) {
- wordsList[t] = wordsList[t].replace(/(%22)|^-/g, "");
- if (wordsList[t] != "%20") {
- scriptLetterTab.add(wordsList[t].charAt(0));
- cleanwordsList.push(wordsList[t]);
- }
- }
-
- if(typeof stemmer != "undefined" ){
- //Do the stemming using Porter's stemming algorithm
- for (var i = 0; i < cleanwordsList.length; i++) {
- var stemWord = stemmer(cleanwordsList[i]);
- stemmedWordsList.push(stemWord);
- }
- } else {
- stemmedWordsList = cleanwordsList;
- }
- return stemmedWordsList;
-}
-
-//Invoker of CJKTokenizer class methods.
-function cjkTokenize(wordsList){
- var allTokens= new Array();
- var notCJKTokens= new Array();
- var j=0;
- for(j=0;j";
- return this.input.substring(this.offset,this.offset+2);
- }
-
- function getAllTokens(){
- while(this.incrementToken()){
- var tmp = this.tokenize();
- this.tokens.push(tmp);
- }
- return this.unique(this.tokens);
-// document.getElementById("content").innerHTML += tokens+" ";
-// document.getElementById("content").innerHTML += " dada"+sortedTokens+" ";
-// console.log(tokens.length+"dsdsds");
- /*for(i=0;idada"+un[i]+"- "+stems[i]+" "+ ss;
- document.getElementById("content").innerHTML += " "+sortedTokens[i];
- }*/
- }
-
- function unique(a)
- {
- var r = new Array();
- o:for(var i = 0, n = a.length; i < n; i++)
- {
- for(var x = 0, y = r.length; x < y; x++)
- {
- if(r[x]==a[i]) continue o;
- }
- r[r.length] = a[i];
- }
- return r;
- }
-}
-
-
-/* Scriptfirstchar: to gather the first letter of index js files to upload */
-function Scriptfirstchar() {
- this.strLetters = "";
- this.add = addLettre;
-}
-
-function addLettre(caract) {
-
- if (this.strLetters == 'undefined') {
- this.strLetters = caract;
- } else if (this.strLetters.indexOf(caract) < 0) {
- this.strLetters += caract;
- }
-
- return 0;
-}
-/* end of scriptfirstchar */
-
-/*main loader function*/
-/*tab contains the first letters of each word looked for*/
-function loadTheIndexScripts(tab) {
-
- //alert (tab.strLetters);
- var scriptsarray = new Array();
-
- for (var i = 0; i < tab.strLetters.length; i++) {
-
- scriptsarray[i] = "..\/search" + "\/" + tab.strLetters.charAt(i) + ".js";
- }
- // add the list of html files
- i++;
- scriptsarray[i] = "..\/search" + "\/" + htmlfileList;
-
- //debug
- for (var t in scriptsarray) {
- //alert (scriptsarray[t]);
- }
-
- tab = new ScriptLoader();
- for (t in scriptsarray) {
- tab.add(scriptsarray[t]);
- }
- tab.load();
- //alert ("scripts loaded");
- return (scriptsarray);
-}
-
-/* ScriptLoader: to load the scripts and wait that it's finished */
-function ScriptLoader() {
- this.cpt = 0;
- this.scriptTab = new Array();
- this.add = addAScriptInTheList;
- this.load = loadTheScripts;
- this.onScriptLoaded = onScriptLoadedFunc;
-}
-
-function addAScriptInTheList(scriptPath) {
- this.scriptTab.push(scriptPath);
-}
-
-function loadTheScripts() {
- var script;
- var head;
-
- head = document.getElementsByTagName('head').item(0);
-
- //script = document.createElement('script');
-
- for (var el in this.scriptTab) {
- //alert (el+this.scriptTab[el]);
- script = document.createElement('script');
- script.src = this.scriptTab[el];
- script.type = 'text/javascript';
- script.defer = false;
-
- head.appendChild(script);
- }
-
-}
-
-function onScriptLoadedFunc(e) {
- e = e || window.event;
- var target = e.target || e.srcElement;
- var isComplete = true;
- if (typeof target.readyState != undefined) {
-
- isComplete = (target.readyState == "complete" || target.readyState == "loaded");
- }
- if (isComplete) {
- ScriptLoader.cpt++;
- if (ScriptLoader.cpt == ScriptLoader.scripts.length) {
- ScriptLoader.onLoadComplete();
- }
- }
-}
-
-/*
-function onLoadComplete() {
- alert("loaded !!");
-} */
-
-/* End of scriptloader functions */
-
-// Array.unique( strict ) - Remove duplicate values
-function unique(tab) {
- var a = new Array();
- var i;
- var l = tab.length;
-
- if (tab[0] != undefined) {
- a[0] = tab[0];
- }
- else {
- return -1
- }
-
- for (i = 1; i < l; i++) {
- if (indexof(a, tab[i], 0) < 0) {
- a.push(tab[i]);
- }
- }
- return a;
-}
-function indexof(tab, element, begin) {
- for (var i = begin; i < tab.length; i++) {
- if (tab[i] == element) {
- return i;
- }
- }
- return -1;
-
-}
-/* end of Array functions */
-
-
-/*
- Param: mots= list of words to look for.
- This function creates an hashtable:
- - The key is the index of a html file which contains a word to look for.
- - The value is the list of all words contained in the html file.
-
- Return value: the hashtable fileAndWordList
- */
-function SortResults(mots) {
-
- var fileAndWordList = new Object();
- if (mots.length == 0) {
- return null;
- }
-
- for (var t in mots) {
- // get the list of the indices of the files.
- var listNumerosDesFicStr = w[mots[t].toString()];
- //alert ("listNumerosDesFicStr "+listNumerosDesFicStr);
- var tab = listNumerosDesFicStr.split(",");
-
- //for each file (file's index):
- for (var t2 in tab) {
- var temp = tab[t2].toString();
- if (fileAndWordList[temp] == undefined) {
-
- fileAndWordList[temp] = "" + mots[t];
- } else {
-
- fileAndWordList[temp] += "," + mots[t];
- }
- }
- }
-
- var fileAndWordListValuesOnly = new Array();
-
- // sort results according to values
- var temptab = new Array();
- for (t in fileAndWordList) {
- tab = fileAndWordList[t].split(',');
-
- var tempDisplay = new Array();
- for (var x in tab) {
- if(stemQueryMap[tab[x]] != undefined){
- tempDisplay.push(stemQueryMap[tab[x]]); //get the original word from the stem word.
- } else {
- tempDisplay.push(tab[x]); //no stem is available. (probably a CJK language)
- }
- }
- var tempDispString = tempDisplay.join(", ");
-
- temptab.push(new resultPerFile(t, fileAndWordList[t], tab.length, tempDispString));
- fileAndWordListValuesOnly.push(fileAndWordList[t]);
- }
-
-
- //alert("t"+fileAndWordListValuesOnly.toString());
-
- fileAndWordListValuesOnly = unique(fileAndWordListValuesOnly);
- fileAndWordListValuesOnly = fileAndWordListValuesOnly.sort(compare_nbMots);
- //alert("t: "+fileAndWordListValuesOnly.join(';'));
-
- var listToOutput = new Array();
-
- for (var j in fileAndWordListValuesOnly) {
- for (t in temptab) {
- if (temptab[t].motsliste == fileAndWordListValuesOnly[j]) {
- if (listToOutput[j] == undefined) {
- listToOutput[j] = new Array(temptab[t]);
- } else {
- listToOutput[j].push(temptab[t]);
- }
- }
- }
- }
- return listToOutput;
-}
-
-function resultPerFile(filenb, motsliste, motsnb, motslisteDisplay) {
- this.filenb = filenb;
- this.motsliste = motsliste;
- this.motsnb = motsnb;
- this.motslisteDisplay= motslisteDisplay;
-}
-
-function compare_nbMots(s1, s2) {
- var t1 = s1.split(',');
- var t2 = s2.split(',');
- //alert ("s1:"+t1.length + " " +t2.length)
- if (t1.length == t2.length) {
- return 0;
- } else if (t1.length > t2.length) {
- return 1;
- } else {
- return -1;
- }
- //return t1.length - t2.length);
+/*----------------------------------------------------------------------------
+ * JavaScript for webhelp search
+ *----------------------------------------------------------------------------
+ This file is part of the webhelpsearch plugin for DocBook WebHelp
+ Copyright (c) 2007-2008 NexWave Solutions All Rights Reserved.
+ www.nexwave.biz Nadege Quaine
+ http://kasunbg.blogspot.com/ Kasun Gajasinghe
+ */
+
+//string initialization
+var htmlfileList = "htmlFileList.js";
+var htmlfileinfoList = "htmlFileInfoList.js";
+var useCJKTokenizing = false;
+
+/* Cette fonction verifie la validite de la recherche entrre par l utilisateur */
+function Verifie(ditaSearch_Form) {
+
+ // Check browser compatibitily
+ if (navigator.userAgent.indexOf("Konquerer") > -1) {
+
+ alert(txt_browser_not_supported);
+ return;
+ }
+
+
+ var expressionInput = document.ditaSearch_Form.textToSearch.value;
+ //Set a cookie to store the searched keywords
+ $.cookie('textToSearch', expressionInput);
+
+
+ if (expressionInput.length < 1) {
+
+ // expression is invalid
+ alert(txt_enter_at_least_1_char);
+ // reactive la fenetre de search (utile car cadres)
+ document.ditaSearch_Form.textToSearch.focus();
+ }
+ else {
+
+ // Effectuer la recherche
+ Effectuer_recherche(expressionInput);
+
+ // reactive la fenetre de search (utile car cadres)
+ document.ditaSearch_Form.textToSearch.focus();
+ }
+}
+
+var stemQueryMap = new Array(); // A hashtable which maps stems to query words
+
+/* This function parses the search expression, loads the indices and displays the results*/
+function Effectuer_recherche(expressionInput) {
+
+ /* Display a waiting message */
+ //DisplayWaitingMessage();
+
+ /*data initialisation*/
+ var searchFor = ""; // expression en lowercase et sans les caracte res speciaux
+ //w = new Object(); // hashtable, key=word, value = list of the index of the html files
+ scriptLetterTab = new Scriptfirstchar(); // Array containing the first letter of each word to look for
+ var wordsList = new Array(); // Array with the words to look for
+ var finalWordsList = new Array(); // Array with the words to look for after removing spaces
+ var linkTab = new Array();
+ var fileAndWordList = new Array();
+ var txt_wordsnotfound = "";
+
+
+ /*nqu: expressionInput, la recherche est lower cased, plus remplacement des char speciaux*/
+ searchFor = expressionInput.toLowerCase().replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/\.|%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "").replace(/_di_/g, "%24_");
+
+ searchFor = searchFor.replace(/ +/g, " ");
+ searchFor = searchFor.replace(/ $/, "").replace(/^ /, "");
+
+ wordsList = searchFor.split(" ");
+ wordsList.sort();
+
+ //set the tokenizing method
+ if(typeof indexerLanguage != "undefined" && (indexerLanguage=="zh" || indexerLanguage=="ja" ||indexerLanguage=="ko")){
+ useCJKTokenizing=true;
+ } else {
+ useCJKTokenizing=false;
+ }
+ //If Lucene CJKTokenizer was used as the indexer, then useCJKTokenizing will be true. Else, do normal tokenizing.
+ // 2-gram tokenizinghappens in CJKTokenizing,
+ if(useCJKTokenizing){
+ finalWordsList = cjkTokenize(wordsList);
+ } else {
+ finalWordsList = tokenize(wordsList);
+ }
+
+ //load the scripts with the indices: the following lines do not work on the server. To be corrected
+ /*if (IEBrowser) {
+ scriptsarray = loadTheIndexScripts (scriptLetterTab);
+ } */
+
+ /**
+ * Compare with the indexed words (in the w[] array), and push words that are in it to tempTab.
+ */
+ var tempTab = new Array();
+ for (var t in finalWordsList) {
+ if (w[finalWordsList[t].toString()] == undefined) {
+ txt_wordsnotfound += finalWordsList[t] + " ";
+ } else {
+ tempTab.push(finalWordsList[t]);
+ }
+ }
+ finalWordsList = tempTab;
+
+ if (finalWordsList.length) {
+
+ //search 'and' and 'or' one time
+ fileAndWordList = SortResults(finalWordsList);
+
+ var cpt = fileAndWordList.length;
+ for (var i = cpt - 1; i >= 0; i--) {
+ if (fileAndWordList[i] != undefined) {
+ linkTab.push("
" + "Your search returned no results for " + "" + txt_wordsnotfound + "" + "
";
- }
- //alert(results);
- document.getElementById('searchResults').innerHTML = results;
-}
-
-function tokenize(wordsList){
- var stemmedWordsList = new Array(); // Array with the words to look for after removing spaces
- var cleanwordsList = new Array(); // Array with the words to look for
- for(var j in wordsList){
- var word = wordsList[j];
- if(typeof stemmer != "undefined" ){
- stemQueryMap[stemmer(word)] = word;
- } else {
- stemQueryMap[word] = word;
- }
- }
- //stemmedWordsList is the stemmed list of words separated by spaces.
- for (var t in wordsList) {
- wordsList[t] = wordsList[t].replace(/(%22)|^-/g, "");
- if (wordsList[t] != "%20") {
- scriptLetterTab.add(wordsList[t].charAt(0));
- cleanwordsList.push(wordsList[t]);
- }
- }
-
- if(typeof stemmer != "undefined" ){
- //Do the stemming using Porter's stemming algorithm
- for (var i = 0; i < cleanwordsList.length; i++) {
- var stemWord = stemmer(cleanwordsList[i]);
- stemmedWordsList.push(stemWord);
- }
- } else {
- stemmedWordsList = cleanwordsList;
- }
- return stemmedWordsList;
-}
-
-//Invoker of CJKTokenizer class methods.
-function cjkTokenize(wordsList){
- var allTokens= new Array();
- var notCJKTokens= new Array();
- var j=0;
- for(j=0;j";
- return this.input.substring(this.offset,this.offset+2);
- }
-
- function getAllTokens(){
- while(this.incrementToken()){
- var tmp = this.tokenize();
- this.tokens.push(tmp);
- }
- return this.unique(this.tokens);
-// document.getElementById("content").innerHTML += tokens+" ";
-// document.getElementById("content").innerHTML += " dada"+sortedTokens+" ";
-// console.log(tokens.length+"dsdsds");
- /*for(i=0;idada"+un[i]+"- "+stems[i]+" "+ ss;
- document.getElementById("content").innerHTML += " "+sortedTokens[i];
- }*/
- }
-
- function unique(a)
- {
- var r = new Array();
- o:for(var i = 0, n = a.length; i < n; i++)
- {
- for(var x = 0, y = r.length; x < y; x++)
- {
- if(r[x]==a[i]) continue o;
- }
- r[r.length] = a[i];
- }
- return r;
- }
-}
-
-
-/* Scriptfirstchar: to gather the first letter of index js files to upload */
-function Scriptfirstchar() {
- this.strLetters = "";
- this.add = addLettre;
-}
-
-function addLettre(caract) {
-
- if (this.strLetters == 'undefined') {
- this.strLetters = caract;
- } else if (this.strLetters.indexOf(caract) < 0) {
- this.strLetters += caract;
- }
-
- return 0;
-}
-/* end of scriptfirstchar */
-
-/*main loader function*/
-/*tab contains the first letters of each word looked for*/
-function loadTheIndexScripts(tab) {
-
- //alert (tab.strLetters);
- var scriptsarray = new Array();
-
- for (var i = 0; i < tab.strLetters.length; i++) {
-
- scriptsarray[i] = "..\/search" + "\/" + tab.strLetters.charAt(i) + ".js";
- }
- // add the list of html files
- i++;
- scriptsarray[i] = "..\/search" + "\/" + htmlfileList;
-
- //debug
- for (var t in scriptsarray) {
- //alert (scriptsarray[t]);
- }
-
- tab = new ScriptLoader();
- for (t in scriptsarray) {
- tab.add(scriptsarray[t]);
- }
- tab.load();
- //alert ("scripts loaded");
- return (scriptsarray);
-}
-
-/* ScriptLoader: to load the scripts and wait that it's finished */
-function ScriptLoader() {
- this.cpt = 0;
- this.scriptTab = new Array();
- this.add = addAScriptInTheList;
- this.load = loadTheScripts;
- this.onScriptLoaded = onScriptLoadedFunc;
-}
-
-function addAScriptInTheList(scriptPath) {
- this.scriptTab.push(scriptPath);
-}
-
-function loadTheScripts() {
- var script;
- var head;
-
- head = document.getElementsByTagName('head').item(0);
-
- //script = document.createElement('script');
-
- for (var el in this.scriptTab) {
- //alert (el+this.scriptTab[el]);
- script = document.createElement('script');
- script.src = this.scriptTab[el];
- script.type = 'text/javascript';
- script.defer = false;
-
- head.appendChild(script);
- }
-
-}
-
-function onScriptLoadedFunc(e) {
- e = e || window.event;
- var target = e.target || e.srcElement;
- var isComplete = true;
- if (typeof target.readyState != undefined) {
-
- isComplete = (target.readyState == "complete" || target.readyState == "loaded");
- }
- if (isComplete) {
- ScriptLoader.cpt++;
- if (ScriptLoader.cpt == ScriptLoader.scripts.length) {
- ScriptLoader.onLoadComplete();
- }
- }
-}
-
-/*
-function onLoadComplete() {
- alert("loaded !!");
-} */
-
-/* End of scriptloader functions */
-
-// Array.unique( strict ) - Remove duplicate values
-function unique(tab) {
- var a = new Array();
- var i;
- var l = tab.length;
-
- if (tab[0] != undefined) {
- a[0] = tab[0];
- }
- else {
- return -1
- }
-
- for (i = 1; i < l; i++) {
- if (indexof(a, tab[i], 0) < 0) {
- a.push(tab[i]);
- }
- }
- return a;
-}
-function indexof(tab, element, begin) {
- for (var i = begin; i < tab.length; i++) {
- if (tab[i] == element) {
- return i;
- }
- }
- return -1;
-
-}
-/* end of Array functions */
-
-
-/*
- Param: mots= list of words to look for.
- This function creates an hashtable:
- - The key is the index of a html file which contains a word to look for.
- - The value is the list of all words contained in the html file.
-
- Return value: the hashtable fileAndWordList
- */
-function SortResults(mots) {
-
- var fileAndWordList = new Object();
- if (mots.length == 0) {
- return null;
- }
-
- for (var t in mots) {
- // get the list of the indices of the files.
- var listNumerosDesFicStr = w[mots[t].toString()];
- //alert ("listNumerosDesFicStr "+listNumerosDesFicStr);
- var tab = listNumerosDesFicStr.split(",");
-
- //for each file (file's index):
- for (var t2 in tab) {
- var temp = tab[t2].toString();
- if (fileAndWordList[temp] == undefined) {
-
- fileAndWordList[temp] = "" + mots[t];
- } else {
-
- fileAndWordList[temp] += "," + mots[t];
- }
- }
- }
-
- var fileAndWordListValuesOnly = new Array();
-
- // sort results according to values
- var temptab = new Array();
- for (t in fileAndWordList) {
- tab = fileAndWordList[t].split(',');
-
- var tempDisplay = new Array();
- for (var x in tab) {
- if(stemQueryMap[tab[x]] != undefined){
- tempDisplay.push(stemQueryMap[tab[x]]); //get the original word from the stem word.
- } else {
- tempDisplay.push(tab[x]); //no stem is available. (probably a CJK language)
- }
- }
- var tempDispString = tempDisplay.join(", ");
-
- temptab.push(new resultPerFile(t, fileAndWordList[t], tab.length, tempDispString));
- fileAndWordListValuesOnly.push(fileAndWordList[t]);
- }
-
-
- //alert("t"+fileAndWordListValuesOnly.toString());
-
- fileAndWordListValuesOnly = unique(fileAndWordListValuesOnly);
- fileAndWordListValuesOnly = fileAndWordListValuesOnly.sort(compare_nbMots);
- //alert("t: "+fileAndWordListValuesOnly.join(';'));
-
- var listToOutput = new Array();
-
- for (var j in fileAndWordListValuesOnly) {
- for (t in temptab) {
- if (temptab[t].motsliste == fileAndWordListValuesOnly[j]) {
- if (listToOutput[j] == undefined) {
- listToOutput[j] = new Array(temptab[t]);
- } else {
- listToOutput[j].push(temptab[t]);
- }
- }
- }
- }
- return listToOutput;
-}
-
-function resultPerFile(filenb, motsliste, motsnb, motslisteDisplay) {
- this.filenb = filenb;
- this.motsliste = motsliste;
- this.motsnb = motsnb;
- this.motslisteDisplay= motslisteDisplay;
-}
-
-function compare_nbMots(s1, s2) {
- var t1 = s1.split(',');
- var t2 = s2.split(',');
- //alert ("s1:"+t1.length + " " +t2.length)
- if (t1.length == t2.length) {
- return 0;
- } else if (t1.length > t2.length) {
- return 1;
- } else {
- return -1;
- }
- //return t1.length - t2.length);
+/*----------------------------------------------------------------------------
+ * JavaScript for webhelp search
+ *----------------------------------------------------------------------------
+ This file is part of the webhelpsearch plugin for DocBook WebHelp
+ Copyright (c) 2007-2008 NexWave Solutions All Rights Reserved.
+ www.nexwave.biz Nadege Quaine
+ http://kasunbg.blogspot.com/ Kasun Gajasinghe
+ */
+
+//string initialization
+var htmlfileList = "htmlFileList.js";
+var htmlfileinfoList = "htmlFileInfoList.js";
+var useCJKTokenizing = false;
+
+/* Cette fonction verifie la validite de la recherche entrre par l utilisateur */
+function Verifie(ditaSearch_Form) {
+
+ // Check browser compatibitily
+ if (navigator.userAgent.indexOf("Konquerer") > -1) {
+
+ alert(txt_browser_not_supported);
+ return;
+ }
+
+
+ var expressionInput = document.ditaSearch_Form.textToSearch.value;
+ //Set a cookie to store the searched keywords
+ $.cookie('textToSearch', expressionInput);
+
+
+ if (expressionInput.length < 1) {
+
+ // expression is invalid
+ alert(txt_enter_at_least_1_char);
+ // reactive la fenetre de search (utile car cadres)
+ document.ditaSearch_Form.textToSearch.focus();
+ }
+ else {
+
+ // Effectuer la recherche
+ Effectuer_recherche(expressionInput);
+
+ // reactive la fenetre de search (utile car cadres)
+ document.ditaSearch_Form.textToSearch.focus();
+ }
+}
+
+var stemQueryMap = new Array(); // A hashtable which maps stems to query words
+
+/* This function parses the search expression, loads the indices and displays the results*/
+function Effectuer_recherche(expressionInput) {
+
+ /* Display a waiting message */
+ //DisplayWaitingMessage();
+
+ /*data initialisation*/
+ var searchFor = ""; // expression en lowercase et sans les caracte res speciaux
+ //w = new Object(); // hashtable, key=word, value = list of the index of the html files
+ scriptLetterTab = new Scriptfirstchar(); // Array containing the first letter of each word to look for
+ var wordsList = new Array(); // Array with the words to look for
+ var finalWordsList = new Array(); // Array with the words to look for after removing spaces
+ var linkTab = new Array();
+ var fileAndWordList = new Array();
+ var txt_wordsnotfound = "";
+
+
+ /*nqu: expressionInput, la recherche est lower cased, plus remplacement des char speciaux*/
+ searchFor = expressionInput.toLowerCase().replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/\.|%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "").replace(/_di_/g, "%24_");
+
+ searchFor = searchFor.replace(/ +/g, " ");
+ searchFor = searchFor.replace(/ $/, "").replace(/^ /, "");
+
+ wordsList = searchFor.split(" ");
+ wordsList.sort();
+
+ //set the tokenizing method
+ if(typeof indexerLanguage != "undefined" && (indexerLanguage=="zh" || indexerLanguage=="ja" ||indexerLanguage=="ko")){
+ useCJKTokenizing=true;
+ } else {
+ useCJKTokenizing=false;
+ }
+ //If Lucene CJKTokenizer was used as the indexer, then useCJKTokenizing will be true. Else, do normal tokenizing.
+ // 2-gram tokenizinghappens in CJKTokenizing,
+ if(useCJKTokenizing){
+ finalWordsList = cjkTokenize(wordsList);
+ } else {
+ finalWordsList = tokenize(wordsList);
+ }
+
+ //load the scripts with the indices: the following lines do not work on the server. To be corrected
+ /*if (IEBrowser) {
+ scriptsarray = loadTheIndexScripts (scriptLetterTab);
+ } */
+
+ /**
+ * Compare with the indexed words (in the w[] array), and push words that are in it to tempTab.
+ */
+ var tempTab = new Array();
+ for (var t in finalWordsList) {
+ if (w[finalWordsList[t].toString()] == undefined) {
+ txt_wordsnotfound += finalWordsList[t] + " ";
+ } else {
+ tempTab.push(finalWordsList[t]);
+ }
+ }
+ finalWordsList = tempTab;
+
+ if (finalWordsList.length) {
+
+ //search 'and' and 'or' one time
+ fileAndWordList = SortResults(finalWordsList);
+
+ var cpt = fileAndWordList.length;
+ for (var i = cpt - 1; i >= 0; i--) {
+ if (fileAndWordList[i] != undefined) {
+ linkTab.push("