mirror of
https://github.com/mapnik/mapnik.git
synced 2026-02-01 17:36:36 +00:00
Upgrade to scons-4.10.1
This commit is contained in:
parent
48219e570d
commit
855e904280
4
scons/scons-README
vendored
4
scons/scons-README
vendored
@ -43,8 +43,10 @@ scons-local package, or any SCons package, at the SCons download page:
|
||||
EXECUTION REQUIREMENTS
|
||||
======================
|
||||
|
||||
Running SCons requires Python 3.6 or higher. There should be no other
|
||||
Running SCons requires Python 3.7 or higher. There should be no other
|
||||
dependencies or requirements to run standard SCons.
|
||||
|
||||
The last release to support Python 3.6 was 4.8.1.
|
||||
The last release to support Python 3.5 was 4.2.0.
|
||||
|
||||
The default SCons configuration assumes use of the Microsoft Visual C++
|
||||
|
||||
8
scons/scons-configure-cache.py
vendored
8
scons/scons-configure-cache.py
vendored
@ -32,15 +32,15 @@ The files are split into directories named by the first few
|
||||
digits of the signature. The prefix length used for directory
|
||||
names can be changed by this script.
|
||||
"""
|
||||
__revision__ = "scripts/scons-configure-cache.py 39a12f34d532ab2493e78a7b73aeab2250852790 Thu, 27 Mar 2025 11:44:24 -0700 bdbaddog"
|
||||
__revision__ = "scripts/scons-configure-cache.py 055b01f429d58b686701a56df863a817c36bb103 Sun, 16 Nov 2025 14:18:20 -0700 bdbaddog"
|
||||
|
||||
__version__ = "4.9.1"
|
||||
__version__ = "4.10.1"
|
||||
|
||||
__build__ = "39a12f34d532ab2493e78a7b73aeab2250852790"
|
||||
__build__ = "055b01f429d58b686701a56df863a817c36bb103"
|
||||
|
||||
__buildsys__ = "M1Dog2021"
|
||||
|
||||
__date__ = "Thu, 27 Mar 2025 11:44:24 -0700"
|
||||
__date__ = "Sun, 16 Nov 2025 14:18:20 -0700"
|
||||
|
||||
__developer__ = "bdbaddog"
|
||||
|
||||
|
||||
@ -114,6 +114,7 @@ import SCons.Warnings
|
||||
from SCons.Debug import logInstanceCreation
|
||||
from SCons.Errors import InternalError, UserError
|
||||
from SCons.Executor import Executor
|
||||
from SCons.Node import Node
|
||||
|
||||
class _Null:
|
||||
pass
|
||||
@ -487,10 +488,11 @@ class BuilderBase:
|
||||
# fspath() is to catch PathLike paths. We avoid the simpler
|
||||
# str(f) so as not to "lose" files that are already Nodes:
|
||||
# TypeError: expected str, bytes or os.PathLike object, not File
|
||||
with suppress(TypeError):
|
||||
f = os.fspath(f)
|
||||
if SCons.Util.is_String(f):
|
||||
f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
|
||||
if not isinstance(f, Node):
|
||||
with suppress(TypeError):
|
||||
f = os.fspath(f)
|
||||
if SCons.Util.is_String(f):
|
||||
f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
|
||||
result.append(f)
|
||||
return result
|
||||
|
||||
@ -699,7 +701,7 @@ class BuilderBase:
|
||||
src_suffix = []
|
||||
elif not SCons.Util.is_List(src_suffix):
|
||||
src_suffix = [ src_suffix ]
|
||||
self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix]
|
||||
self.src_suffix = [suf if callable(suf) else self.adjust_suffix(suf) for suf in src_suffix]
|
||||
|
||||
def get_src_suffix(self, env):
|
||||
"""Get the first src_suffix in the list of src_suffixes."""
|
||||
@ -649,7 +649,7 @@ class SubstitutionEnvironment:
|
||||
args - filename strings or nodes to convert; nodes are just
|
||||
added to the list without further processing.
|
||||
node_factory - optional factory to create the nodes; if not
|
||||
specified, will use this environment's ``fs.File method.
|
||||
specified, will use this environment's ``fs.File`` method.
|
||||
lookup_list - optional list of lookup functions to call to
|
||||
attempt to find the file referenced by each *args*.
|
||||
kw - keyword arguments that represent additional nodes to add.
|
||||
@ -1295,14 +1295,31 @@ class Base(SubstitutionEnvironment):
|
||||
if parse_flags:
|
||||
self.MergeFlags(parse_flags)
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Handle missing attribute in an environment.
|
||||
|
||||
Assume this is a builder that's not instantiated, becasue that has
|
||||
been a common failure mode. Could also be a typo. Emit a
|
||||
message about this to try to help. We can't get too clever,
|
||||
other parts of SCons depend on seeing the :exc:`AttributeError` that
|
||||
triggers this call, so all we do is produce our own message.
|
||||
|
||||
.. versionadded:: 4.10.0
|
||||
"""
|
||||
raise AttributeError(
|
||||
f"Builder or other environment method {name!r} not found.\n"
|
||||
"Check spelling, check external program exists in env['ENV']['PATH'],\n"
|
||||
"and check that a suitable tool is being loaded"
|
||||
) from None
|
||||
|
||||
|
||||
#######################################################################
|
||||
# Utility methods that are primarily for internal use by SCons.
|
||||
# These begin with lower-case letters.
|
||||
#######################################################################
|
||||
|
||||
def get_builder(self, name):
|
||||
"""Fetch the builder with the specified name from the environment.
|
||||
"""
|
||||
"""Fetch the builder with the specified name from the environment."""
|
||||
try:
|
||||
return self._dict['BUILDERS'][name]
|
||||
except KeyError:
|
||||
@ -1755,8 +1772,8 @@ class Base(SubstitutionEnvironment):
|
||||
(pretty-print) or ``<<non-serializable: function>>`` (JSON).
|
||||
|
||||
Args:
|
||||
key: if omitted, format the whole dict of variables,
|
||||
else format *key*(s) with the corresponding values.
|
||||
key: variables to format together with their values.
|
||||
If omitted, format the whole dict of variables,
|
||||
format: specify the format to serialize to. ``"pretty"`` generates
|
||||
a pretty-printed string, ``"json"`` a JSON-formatted string.
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
from contextlib import suppress
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Memoize
|
||||
@ -163,10 +164,6 @@ class Executor(metaclass=NoSlotsPyPy):
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'_changed_sources_list',
|
||||
'_changed_targets_list',
|
||||
'_unchanged_sources_list',
|
||||
'_unchanged_targets_list',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
@ -193,49 +190,56 @@ class Executor(metaclass=NoSlotsPyPy):
|
||||
return self.lvars
|
||||
except AttributeError:
|
||||
self.lvars = {
|
||||
'CHANGED_SOURCES' : TSList(self._get_changed_sources),
|
||||
'CHANGED_TARGETS' : TSList(self._get_changed_targets),
|
||||
'SOURCE' : TSObject(self._get_source),
|
||||
'SOURCES' : TSList(self._get_sources),
|
||||
'TARGET' : TSObject(self._get_target),
|
||||
'TARGETS' : TSList(self._get_targets),
|
||||
'UNCHANGED_SOURCES' : TSList(self._get_unchanged_sources),
|
||||
'UNCHANGED_TARGETS' : TSList(self._get_unchanged_targets),
|
||||
'CHANGED_SOURCES': TSList(self._get_changed_sources),
|
||||
'CHANGED_TARGETS': TSList(self._get_changed_targets),
|
||||
'SOURCE': TSObject(self._get_source),
|
||||
'SOURCES': TSList(self._get_sources),
|
||||
'TARGET': TSObject(self._get_target),
|
||||
'TARGETS': TSList(self._get_targets),
|
||||
'UNCHANGED_SOURCES': TSList(self._get_unchanged_sources),
|
||||
'UNCHANGED_TARGETS': TSList(self._get_unchanged_targets),
|
||||
}
|
||||
return self.lvars
|
||||
|
||||
def _get_changes(self) -> None:
|
||||
cs = []
|
||||
ct = []
|
||||
us = []
|
||||
ut = []
|
||||
"""Populate all the changed/unchanged lists.
|
||||
|
||||
.. versionchanged:: 4.10.0
|
||||
``_changed_sources``, ``_changed_targets``, ``_unchanged_sources``
|
||||
and ``_unchanged_targets`` are no longer separate instance
|
||||
attributes, but rather saved in the :attr:`_memo` dict.
|
||||
"""
|
||||
changed_sources = []
|
||||
changed_targets = []
|
||||
unchanged_sources = []
|
||||
unchanged_targets = []
|
||||
for b in self.batches:
|
||||
# don't add targets marked always build to unchanged lists
|
||||
# add to changed list as they always need to build
|
||||
if not b.targets[0].always_build and b.targets[0].is_up_to_date():
|
||||
us.extend(list(map(rfile, b.sources)))
|
||||
ut.extend(b.targets)
|
||||
unchanged_sources.extend(list(map(rfile, b.sources)))
|
||||
unchanged_targets.extend(b.targets)
|
||||
else:
|
||||
cs.extend(list(map(rfile, b.sources)))
|
||||
ct.extend(b.targets)
|
||||
self._changed_sources_list = SCons.Util.NodeList(cs)
|
||||
self._changed_targets_list = SCons.Util.NodeList(ct)
|
||||
self._unchanged_sources_list = SCons.Util.NodeList(us)
|
||||
self._unchanged_targets_list = SCons.Util.NodeList(ut)
|
||||
changed_sources.extend(list(map(rfile, b.sources)))
|
||||
changed_targets.extend(b.targets)
|
||||
self._memo["_get_changed_sources"] = changed_sources
|
||||
self._memo["_get_changed_targets"] = changed_targets
|
||||
self._memo["_get_unchanged_sources"] = unchanged_sources
|
||||
self._memo["_get_unchanged_targets"] = unchanged_targets
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def _get_changed_sources(self, *args, **kw):
|
||||
try:
|
||||
return self._changed_sources_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._changed_sources_list
|
||||
with suppress(KeyError):
|
||||
return self._memo["_get_changed_sources"]
|
||||
self._get_changes() # sets the memo entry
|
||||
return self._memo["_get_changed_sources"]
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def _get_changed_targets(self, *args, **kw):
|
||||
try:
|
||||
return self._changed_targets_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._changed_targets_list
|
||||
with suppress(KeyError):
|
||||
return self._memo["_get_changed_targets"]
|
||||
self._get_changes() # sets the memo entry
|
||||
return self._memo["_get_changed_targets"]
|
||||
|
||||
def _get_source(self, *args, **kw):
|
||||
return rfile(self.batches[0].sources[0]).get_subst_proxy()
|
||||
@ -249,19 +253,19 @@ class Executor(metaclass=NoSlotsPyPy):
|
||||
def _get_targets(self, *args, **kw):
|
||||
return SCons.Util.NodeList([n.get_subst_proxy() for n in self.get_all_targets()])
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def _get_unchanged_sources(self, *args, **kw):
|
||||
try:
|
||||
return self._unchanged_sources_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._unchanged_sources_list
|
||||
with suppress(KeyError):
|
||||
return self._memo["_get_unchanged_sources"]
|
||||
self._get_changes() # sets the memo entry
|
||||
return self._memo["_get_unchanged_sources"]
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def _get_unchanged_targets(self, *args, **kw):
|
||||
try:
|
||||
return self._unchanged_targets_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._unchanged_targets_list
|
||||
with suppress(KeyError):
|
||||
return self._memo["_get_unchanged_targets"]
|
||||
self._get_changes() # sets the memo entry
|
||||
return self._memo["_get_unchanged_targets"]
|
||||
|
||||
def get_action_targets(self):
|
||||
if not self.action_list:
|
||||
@ -585,6 +589,9 @@ class Null(metaclass=NoSlotsPyPy):
|
||||
This might be able to disappear when we refactor things to
|
||||
disassociate Builders from Nodes entirely, so we're not
|
||||
going to worry about unit tests for this--at least for now.
|
||||
|
||||
Note the slots have to match :class:`Executor` exactly,
|
||||
or the :meth:`_morph` will fail.
|
||||
"""
|
||||
|
||||
__slots__ = ('pre_actions',
|
||||
@ -595,10 +602,6 @@ class Null(metaclass=NoSlotsPyPy):
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'_changed_sources_list',
|
||||
'_changed_targets_list',
|
||||
'_unchanged_sources_list',
|
||||
'_unchanged_targets_list',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
@ -145,17 +145,29 @@ def initialize_do_splitdrive() -> None:
|
||||
do_splitdrive = bool(os.path.splitdrive('X:/foo')[0])
|
||||
|
||||
if do_splitdrive:
|
||||
# Note there's a little dilemma here - we should be able to use the
|
||||
# Python os.path.splitdrive, which is well debugged over the years.
|
||||
# For normal usage it should work, but we also want to as much as
|
||||
# possible run the full testsuite on whichever platform, even if it's
|
||||
# "wrong" for some feature. POSIX splitdrive doesn't do what we want
|
||||
# when running the drive and UNC path tests, and the NT one isn't
|
||||
# designed for use on non-win32. So for now stuck on our private one.
|
||||
# _my_splitdrive = os.path.splitdrive
|
||||
|
||||
def _my_splitdrive(p):
|
||||
if p[1:2] == ':':
|
||||
return p[:2], p[2:]
|
||||
if p[0:2] == '//':
|
||||
# Note that we leave a leading slash in the path
|
||||
# because UNC paths are always absolute.
|
||||
# We leave a leading slash in the path because UNC paths
|
||||
# are always absolute.
|
||||
#
|
||||
# TODO: returning "//" for the drive part is actually
|
||||
# completely wrong. UNC paths must have minimum three
|
||||
# slashes (if using '//server/share/path' style), or five
|
||||
# ('//?/UNC/server/share/path)' and we should return the
|
||||
# part up to but not including the next slash.
|
||||
return '//', p[1:]
|
||||
return '', p
|
||||
# TODO: the os routine should work and be better debugged than ours,
|
||||
# but unit test test_unc_path fails on POSIX platforms. Resolve someday.
|
||||
# _my_splitdrive = os.path.splitdrive
|
||||
|
||||
# Keep some commonly used values in global variables to skip to
|
||||
# module look-up costs.
|
||||
@ -1011,7 +1023,7 @@ class Entry(Base):
|
||||
def diskcheck_match(self) -> None:
|
||||
pass
|
||||
|
||||
def disambiguate(self, must_exist=None):
|
||||
def disambiguate(self, must_exist=False):
|
||||
"""
|
||||
"""
|
||||
if self.isfile():
|
||||
@ -1069,7 +1081,7 @@ class Entry(Base):
|
||||
system, we check to see into what sort of subclass we should
|
||||
morph this Entry."""
|
||||
try:
|
||||
self = self.disambiguate(must_exist=1)
|
||||
self = self.disambiguate(must_exist=True)
|
||||
except SCons.Errors.UserError:
|
||||
# There was nothing on disk with which to disambiguate
|
||||
# this entry. Leave it as an Entry, but return a null
|
||||
@ -215,7 +215,7 @@ def get_contents_dir(node):
|
||||
contents.append('%s %s\n' % (n.get_csig(), n.name))
|
||||
return ''.join(contents)
|
||||
|
||||
def get_contents_file(node):
|
||||
def get_contents_file(node) -> bytes:
|
||||
if not node.rexists():
|
||||
return b''
|
||||
fname = node.rfile().get_abspath()
|
||||
@ -560,6 +560,12 @@ class Node(metaclass=NoSlotsPyPy):
|
||||
'_func_target_from_source']
|
||||
|
||||
class Attrs:
|
||||
"""A generic place to store extra information about the Node.
|
||||
|
||||
Defines ``__slots__`` for performance, but different consumers
|
||||
define their own attributes, so to avoid having to collect them
|
||||
all here, we add a ``__dict__`` slot to get dynamic attributes.
|
||||
"""
|
||||
__slots__ = ('shared', '__dict__')
|
||||
|
||||
|
||||
@ -622,6 +628,9 @@ class Node(metaclass=NoSlotsPyPy):
|
||||
# what line in what file created the node, for example).
|
||||
Annotate(self)
|
||||
|
||||
def __fspath__(self) -> str:
|
||||
return str(self)
|
||||
|
||||
def disambiguate(self, must_exist: bool = False):
|
||||
return self
|
||||
|
||||
@ -43,14 +43,22 @@ their own platform definition.
|
||||
import SCons.compat
|
||||
|
||||
import atexit
|
||||
import contextlib
|
||||
import importlib
|
||||
import locale
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Errors
|
||||
import SCons.Platform
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
|
||||
TEMPFILE_DEFAULT_ENCODING = "utf-8"
|
||||
|
||||
|
||||
def platform_default():
|
||||
@ -66,15 +74,15 @@ def platform_default():
|
||||
if osname == 'posix':
|
||||
if sys.platform == 'cygwin':
|
||||
return 'cygwin'
|
||||
elif sys.platform.find('irix') != -1:
|
||||
elif 'irix' in sys.platform:
|
||||
return 'irix'
|
||||
elif sys.platform.find('sunos') != -1:
|
||||
elif 'sunos' in sys.platform:
|
||||
return 'sunos'
|
||||
elif sys.platform.find('hp-ux') != -1:
|
||||
elif 'hp-ux' in sys.platform:
|
||||
return 'hpux'
|
||||
elif sys.platform.find('aix') != -1:
|
||||
elif 'aix' in sys.platform:
|
||||
return 'aix'
|
||||
elif sys.platform.find('darwin') != -1:
|
||||
elif 'darwin' in sys.platform:
|
||||
return 'darwin'
|
||||
else:
|
||||
return 'posix'
|
||||
@ -242,6 +250,25 @@ class TempFileMunge:
|
||||
if cmdlist is not None:
|
||||
return cmdlist
|
||||
|
||||
# try encoding the tempfile data before creating the file -
|
||||
# avoid orphaned files
|
||||
tempfile_esc_func = env.get('TEMPFILEARGESCFUNC', SCons.Subst.quote_spaces)
|
||||
args = [tempfile_esc_func(arg) for arg in cmd[1:]]
|
||||
join_char = env.get('TEMPFILEARGJOIN', ' ')
|
||||
contents = join_char.join(args) + "\n"
|
||||
encoding = env.get('TEMPFILEENCODING', TEMPFILE_DEFAULT_ENCODING)
|
||||
try:
|
||||
tempfile_contents = bytes(contents, encoding=encoding)
|
||||
except (UnicodeError, LookupError, TypeError):
|
||||
exc_type, exc_value, _ = sys.exc_info()
|
||||
if 'TEMPFILEENCODING' in env:
|
||||
encoding_msg = "env['TEMPFILEENCODING']"
|
||||
else:
|
||||
encoding_msg = "default"
|
||||
err_msg = f"tempfile encoding error: [{exc_type.__name__}] {exc_value!s}"
|
||||
err_msg += f"\n {type(self).__name__} encoding: {encoding_msg} = {encoding!r}"
|
||||
raise SCons.Errors.UserError(err_msg)
|
||||
|
||||
# Default to the .lnk suffix for the benefit of the Phar Lap
|
||||
# linkloc linker, which likes to append an .lnk suffix if
|
||||
# none is given.
|
||||
@ -256,32 +283,21 @@ class TempFileMunge:
|
||||
else:
|
||||
tempfile_dir = None
|
||||
|
||||
fd, tmp = tempfile.mkstemp(suffix, dir=tempfile_dir, text=True)
|
||||
fd, tmp = tempfile.mkstemp(suffix, dir=tempfile_dir)
|
||||
try:
|
||||
os.write(fd, tempfile_contents)
|
||||
finally:
|
||||
os.close(fd)
|
||||
native_tmp = SCons.Util.get_native_path(tmp)
|
||||
|
||||
# arrange for cleanup on exit:
|
||||
|
||||
def tmpfile_cleanup(file) -> None:
|
||||
os.remove(file)
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.remove(file)
|
||||
|
||||
atexit.register(tmpfile_cleanup, tmp)
|
||||
|
||||
if env.get('SHELL', None) == 'sh':
|
||||
# The sh shell will try to escape the backslashes in the
|
||||
# path, so unescape them.
|
||||
native_tmp = native_tmp.replace('\\', r'\\\\')
|
||||
|
||||
if 'TEMPFILEPREFIX' in env:
|
||||
prefix = env.subst('$TEMPFILEPREFIX')
|
||||
else:
|
||||
prefix = "@"
|
||||
|
||||
tempfile_esc_func = env.get('TEMPFILEARGESCFUNC', SCons.Subst.quote_spaces)
|
||||
args = [tempfile_esc_func(arg) for arg in cmd[1:]]
|
||||
join_char = env.get('TEMPFILEARGJOIN', ' ')
|
||||
os.write(fd, bytearray(join_char.join(args) + "\n", encoding="utf-8"))
|
||||
os.close(fd)
|
||||
|
||||
# XXX Using the SCons.Action.print_actions value directly
|
||||
# like this is bogus, but expedient. This class should
|
||||
# really be rewritten as an Action that defines the
|
||||
@ -311,10 +327,18 @@ class TempFileMunge:
|
||||
)
|
||||
self._print_cmd_str(target, source, env, cmdstr)
|
||||
|
||||
if env.get('SHELL', None) == 'sh':
|
||||
# The sh shell will try to escape the backslashes in the
|
||||
# path, so unescape them.
|
||||
native_tmp = native_tmp.replace('\\', r'\\\\')
|
||||
if 'TEMPFILEPREFIX' in env:
|
||||
prefix = env.subst('$TEMPFILEPREFIX')
|
||||
else:
|
||||
prefix = "@"
|
||||
cmdlist = [cmd[0], prefix + native_tmp]
|
||||
|
||||
# Store the temporary file command list into the target Node.attributes
|
||||
# to avoid creating two temporary files one for print and one for execute.
|
||||
# to avoid creating separate temporary files for print and execute.
|
||||
if node is not None:
|
||||
try:
|
||||
# Storing in tempfile_cmdlist by self.cmd provided when intializing
|
||||
@ -21,7 +21,12 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""'Platform" support for a Python virtualenv."""
|
||||
"""Platform support for a Python virtualenv.
|
||||
|
||||
This is support code, not a loadable Platform module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
@ -41,70 +46,85 @@ def _ignore_virtualenv_default():
|
||||
|
||||
enable_virtualenv = _enable_virtualenv_default()
|
||||
ignore_virtualenv = _ignore_virtualenv_default()
|
||||
virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
|
||||
|
||||
# Variables to export:
|
||||
# - Python docs:
|
||||
# When a virtual environment has been activated, the VIRTUAL_ENV environment
|
||||
# variable is set to the path of the environment. Since explicitly
|
||||
# activating a virtual environment is not required to use it, VIRTUAL_ENV
|
||||
# cannot be relied upon to determine whether a virtual environment is being
|
||||
# used.
|
||||
# - pipenv: shell sets PIPENV_ACTIVE, cannot find it documented.
|
||||
# Any others we should include?
|
||||
VIRTUALENV_VARIABLES = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
|
||||
|
||||
|
||||
def _running_in_virtualenv():
|
||||
"""Returns True if scons is executed within a virtualenv"""
|
||||
# see https://stackoverflow.com/a/42580137
|
||||
return (hasattr(sys, 'real_prefix') or
|
||||
(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
|
||||
def _running_in_virtualenv() -> bool:
|
||||
"""Check whether scons is running in a virtualenv."""
|
||||
# TODO: the virtualenv command used to inject a sys.real_prefix before
|
||||
# Python started officially tracking virtualenvs with the venv module.
|
||||
# All Pythons since 3.3 use sys.base_prefix for tracking (PEP 405);
|
||||
# virtualenv has retired their old behavior and now only makes
|
||||
# venv-style virtualenvs. We're now using the detection suggested in
|
||||
# PEP 668, and should be able to drop the real_prefix check soon.
|
||||
return sys.base_prefix != sys.prefix or hasattr(sys, 'real_prefix')
|
||||
|
||||
|
||||
def _is_path_in(path, base) -> bool:
|
||||
"""Returns true if **path** is located under the **base** directory."""
|
||||
if not path or not base: # empty path may happen, base too
|
||||
def _is_path_in(path: str, base: str) -> bool:
|
||||
"""Check if *path* is located under the *base* directory."""
|
||||
if not path or not base: # empty path or base are possible
|
||||
return False
|
||||
rp = os.path.relpath(path, base)
|
||||
return (not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir)
|
||||
|
||||
|
||||
def _inject_venv_variables(env) -> None:
|
||||
"""Copy any set virtualenv variables from ``os.environ`` to *env*."""
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
ENV = env['ENV']
|
||||
for name in virtualenv_variables:
|
||||
for name in VIRTUALENV_VARIABLES:
|
||||
try:
|
||||
ENV[name] = os.environ[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _inject_venv_path(env, path_list=None) -> None:
|
||||
"""Modify environment such that SCons will take into account its virtualenv
|
||||
when running external tools."""
|
||||
"""Insert virtualenv-related paths from ``os.environe`` to *env*."""
|
||||
if path_list is None:
|
||||
path_list = os.getenv('PATH')
|
||||
env.PrependENVPath('PATH', select_paths_in_venv(path_list))
|
||||
|
||||
|
||||
def select_paths_in_venv(path_list):
|
||||
"""Returns a list of paths from **path_list** which are under virtualenv's
|
||||
home directory."""
|
||||
def select_paths_in_venv(path_list: str | list[str]) -> list[str]:
|
||||
"""Filter *path_list*, returning values under the virtualenv."""
|
||||
if SCons.Util.is_String(path_list):
|
||||
path_list = path_list.split(os.path.pathsep)
|
||||
# Find in path_list the paths under the virtualenv's home
|
||||
return [path for path in path_list if IsInVirtualenv(path)]
|
||||
|
||||
|
||||
def ImportVirtualenv(env) -> None:
|
||||
"""Copies virtualenv-related environment variables from OS environment
|
||||
to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``.
|
||||
"""
|
||||
"""Add virtualenv information to *env*."""
|
||||
_inject_venv_variables(env)
|
||||
_inject_venv_path(env)
|
||||
|
||||
|
||||
def Virtualenv():
|
||||
"""Returns path to the virtualenv home if scons is executing within a
|
||||
virtualenv or None, if not."""
|
||||
def Virtualenv() -> str:
|
||||
"""Return whether operating in a virtualenv.
|
||||
|
||||
Returns the path to the virtualenv home if scons is executing
|
||||
within a virtualenv, else and empty string.
|
||||
"""
|
||||
if _running_in_virtualenv():
|
||||
return sys.prefix
|
||||
return None
|
||||
return ""
|
||||
|
||||
|
||||
def IsInVirtualenv(path):
|
||||
"""Returns True, if **path** is under virtualenv's home directory. If not,
|
||||
or if we don't use virtualenv, returns False."""
|
||||
def IsInVirtualenv(path: str) -> bool:
|
||||
"""Check whether *path* is under the virtualenv's directory.
|
||||
|
||||
Returns ``False`` if not using a virtualenv.
|
||||
"""
|
||||
return _is_path_in(path, Virtualenv())
|
||||
|
||||
|
||||
@ -136,10 +136,10 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||
stderrRedirected = False
|
||||
for arg in args:
|
||||
# are there more possibilities to redirect stdout ?
|
||||
if arg.find(">", 0, 1) != -1 or arg.find("1>", 0, 2) != -1:
|
||||
if arg.startswith(">")or arg.startswith("1>"):
|
||||
stdoutRedirected = True
|
||||
# are there more possibilities to redirect stderr ?
|
||||
if arg.find("2>", 0, 2) != -1:
|
||||
if arg.startswith("2>"):
|
||||
stderrRedirected = True
|
||||
|
||||
# redirect output of non-redirected streams to our tempfiles
|
||||
@ -315,7 +315,8 @@ class LaTeX(ScannerBase):
|
||||
|
||||
for n in try_names:
|
||||
for search_path in search_paths:
|
||||
paths = tuple([d.Dir(inc_subdir) for d in search_path])
|
||||
paths = tuple([d.Dir(inc_subdir) for d in search_path] +
|
||||
list(search_path))
|
||||
i = SCons.Node.FS.find_file(n, paths)
|
||||
if i:
|
||||
return i, include
|
||||
@ -407,16 +408,16 @@ class LaTeX(ScannerBase):
|
||||
include = queue.pop()
|
||||
inc_type, inc_subdir, inc_filename = include
|
||||
|
||||
try:
|
||||
if seen[inc_filename]:
|
||||
continue
|
||||
except KeyError:
|
||||
seen[inc_filename] = True
|
||||
|
||||
#
|
||||
# Handle multiple filenames in include[1]
|
||||
#
|
||||
n, i = self.find_include(include, source_dir, path_dict)
|
||||
try:
|
||||
if seen[str(n)]:
|
||||
continue
|
||||
except KeyError:
|
||||
seen[str(n)] = True
|
||||
|
||||
if n is None:
|
||||
# Do not bother with 'usepackage' warnings, as they most
|
||||
# likely refer to system-level files
|
||||
@ -432,7 +433,9 @@ class LaTeX(ScannerBase):
|
||||
# recurse down
|
||||
queue.extend(self.scan(n, inc_subdir))
|
||||
|
||||
return [pair[1] for pair in sorted(nodes)]
|
||||
# Don't sort on a tuple where the second element is an object, just
|
||||
# use the first element of the tuple which is the "sort_key" value
|
||||
return [pair[1] for pair in sorted(nodes, key=lambda n: n[0])]
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
@ -144,7 +144,7 @@ class Progressor:
|
||||
self.func = obj
|
||||
elif SCons.Util.is_List(obj):
|
||||
self.func = self.spinner
|
||||
elif obj.find(self.target_string) != -1:
|
||||
elif self.target_string in obj:
|
||||
self.func = self.replace_string
|
||||
else:
|
||||
self.func = self.string
|
||||
@ -465,19 +465,28 @@ class TreePrinter:
|
||||
self.prune = prune
|
||||
self.status = status
|
||||
self.sLineDraw = sLineDraw
|
||||
|
||||
def get_all_children(self, node):
|
||||
return node.all_children()
|
||||
|
||||
def get_derived_children(self, node):
|
||||
children = node.all_children(None)
|
||||
return [x for x in children if x.has_builder()]
|
||||
|
||||
def display(self, t) -> None:
|
||||
if self.derived:
|
||||
func = self.get_derived_children
|
||||
else:
|
||||
func = self.get_all_children
|
||||
s = self.status and 2 or 0
|
||||
SCons.Util.print_tree(t, func, prune=self.prune, showtags=s, lastChild=True, singleLineDraw=self.sLineDraw)
|
||||
|
||||
s = 2 if self.status else 0
|
||||
SCons.Util.print_tree(
|
||||
t,
|
||||
func,
|
||||
prune=self.prune,
|
||||
showtags=s,
|
||||
lastChild=True,
|
||||
singleLineDraw=self.sLineDraw,
|
||||
)
|
||||
|
||||
def python_version_string():
|
||||
return sys.version.split()[0]
|
||||
@ -519,7 +528,7 @@ def AddOption(*args, **kw) -> SConsOption:
|
||||
"""Add a local option to the option parser - Public API.
|
||||
|
||||
If the SCons-specific *settable* kwarg is true (default ``False``),
|
||||
the option will allow calling :func:``SetOption`.
|
||||
the option will allow calling :func:`SetOption`.
|
||||
|
||||
.. versionchanged:: 4.8.0
|
||||
The *settable* parameter added to allow including the new option
|
||||
@ -635,7 +644,7 @@ def find_deepest_user_frame(tb):
|
||||
# of SCons:
|
||||
for frame in tb:
|
||||
filename = frame[0]
|
||||
if filename.find(os.sep+'SCons'+os.sep) == -1:
|
||||
if f'{os.sep}SCons{os.sep}' not in filename:
|
||||
return frame
|
||||
return tb[0]
|
||||
|
||||
@ -30,16 +30,16 @@ something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
"""
|
||||
|
||||
import time
|
||||
start_time = time.time()
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from io import StringIO
|
||||
|
||||
import sys
|
||||
start_time = time.time()
|
||||
|
||||
# Special chicken-and-egg handling of the "--debug=memoizer" flag:
|
||||
#
|
||||
@ -135,7 +135,7 @@ DebugOptions = Main.DebugOptions
|
||||
#profiling = Main.profiling
|
||||
#repositories = Main.repositories
|
||||
|
||||
from . import SConscript as _SConscript
|
||||
from . import SConscript as _SConscript # pylint: disable=import-outside-toplevel
|
||||
|
||||
call_stack = _SConscript.call_stack
|
||||
|
||||
@ -208,13 +208,15 @@ DEFAULT_TARGETS = []
|
||||
# own targets to BUILD_TARGETS.
|
||||
_build_plus_default = TargetList()
|
||||
|
||||
def _Add_Arguments(alist) -> None:
|
||||
def _Add_Arguments(alist: list[str]) -> None:
|
||||
"""Add value(s) to ``ARGLIST`` and ``ARGUMENTS``."""
|
||||
for arg in alist:
|
||||
a, b = arg.split('=', 1)
|
||||
ARGUMENTS[a] = b
|
||||
ARGLIST.append((a, b))
|
||||
|
||||
def _Add_Targets(tlist) -> None:
|
||||
def _Add_Targets(tlist: list[str]) -> None:
|
||||
"""Add value(s) to ``COMMAND_LINE_TARGETS`` and ``BUILD_TARGETS``."""
|
||||
if tlist:
|
||||
COMMAND_LINE_TARGETS.extend(tlist)
|
||||
BUILD_TARGETS.extend(tlist)
|
||||
@ -224,6 +226,52 @@ def _Add_Targets(tlist) -> None:
|
||||
_build_plus_default._add_Default = _build_plus_default._do_nothing
|
||||
_build_plus_default._clear = _build_plus_default._do_nothing
|
||||
|
||||
def _Remove_Argument(aarg: str) -> None:
|
||||
"""Remove *aarg* from ``ARGLIST`` and ``ARGUMENTS``.
|
||||
|
||||
Used to remove a variables-style argument that is no longer valid.
|
||||
This can happpen because the command line is processed once early,
|
||||
before we see any :func:`SCons.Script.Main.AddOption` calls, so we
|
||||
could not recognize it belongs to an option and is not a standalone
|
||||
variable=value argument.
|
||||
|
||||
.. versionadded:: 4.10.0
|
||||
|
||||
"""
|
||||
if aarg:
|
||||
a, b = aarg.split('=', 1)
|
||||
if (a, b) in ARGLIST:
|
||||
ARGLIST.remove((a, b))
|
||||
ARGUMENTS.pop(a, None)
|
||||
# ARGLIST might have had multiple values for 'a'. If there
|
||||
# are any left, put that in ARGUMENTS, keeping the last one
|
||||
# (retaining cmdline order)
|
||||
for item in ARGLIST:
|
||||
if item[0] == a:
|
||||
ARGUMENTS[a] = item[1]
|
||||
|
||||
def _Remove_Target(targ: str) -> None:
|
||||
"""Remove *targ* from ``BUILD_TARGETS`` and ``COMMAND_LINE_TARGETS``.
|
||||
|
||||
Used to remove a target that is no longer valid. This can happpen
|
||||
because the command line is processed once early, before we see any
|
||||
:func:`SCons.Script.Main.AddOption` calls, so we could not recognize
|
||||
it belongs to an option and is not a standalone target argument.
|
||||
|
||||
Since we are "correcting an error", we also have to fix up the internal
|
||||
:data:`_build_plus_default` list.
|
||||
|
||||
.. versionadded:: 4.10.0
|
||||
|
||||
"""
|
||||
if targ:
|
||||
if targ in COMMAND_LINE_TARGETS:
|
||||
COMMAND_LINE_TARGETS.remove(targ)
|
||||
if targ in BUILD_TARGETS:
|
||||
BUILD_TARGETS.remove(targ)
|
||||
if targ in _build_plus_default:
|
||||
_build_plus_default.remove(targ)
|
||||
|
||||
def _Set_Default_Targets_Has_Been_Called(d, fs):
|
||||
return DEFAULT_TARGETS
|
||||
|
||||
@ -25,11 +25,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
import re
|
||||
from collections import UserList, UserString
|
||||
from inspect import signature, Parameter
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
from SCons.Util import is_String, is_Sequence
|
||||
|
||||
# Indexed by the SUBST_* constants below.
|
||||
@ -57,10 +58,12 @@ def raise_exception(exception, target, s):
|
||||
|
||||
|
||||
class Literal:
|
||||
"""A wrapper for a string. If you use this object wrapped
|
||||
around a string, then it will be interpreted as literal.
|
||||
When passed to the command interpreter, all special
|
||||
characters will be escaped."""
|
||||
"""A string wrapper for a string to prevent expansion.
|
||||
|
||||
If you use this object wrapped around a string, then it will
|
||||
be interpreted as literal. When passed to the command interpreter,
|
||||
all special characters will be escaped.
|
||||
"""
|
||||
def __init__(self, lstr) -> None:
|
||||
self.lstr = lstr
|
||||
|
||||
@ -76,7 +79,7 @@ class Literal:
|
||||
def is_literal(self) -> bool:
|
||||
return True
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, Literal):
|
||||
return False
|
||||
return self.lstr == other.lstr
|
||||
@ -84,9 +87,17 @@ class Literal:
|
||||
def __neq__(self, other) -> bool:
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.lstr)
|
||||
|
||||
def __contains__(self, key) -> bool:
|
||||
# handle cases where key is not a str
|
||||
if isinstance(key, UserString):
|
||||
key = key.data
|
||||
if isinstance(key, Literal):
|
||||
key = key.lstr
|
||||
return key in self.lstr
|
||||
|
||||
class SpecialAttrWrapper:
|
||||
"""This is a wrapper for what we call a 'Node special attribute.'
|
||||
This is any of the attributes of a Node that we can reference from
|
||||
@ -126,21 +137,23 @@ def quote_spaces(arg):
|
||||
else:
|
||||
return str(arg)
|
||||
|
||||
class CmdStringHolder(collections.UserString):
|
||||
"""This is a special class used to hold strings generated by
|
||||
scons_subst() and scons_subst_list(). It defines a special method
|
||||
escape(). When passed a function with an escape algorithm for a
|
||||
particular platform, it will return the contained string with the
|
||||
proper escape sequences inserted.
|
||||
class CmdStringHolder(UserString):
|
||||
"""Holder for substituted strings intended for the command line.
|
||||
|
||||
Holds strings generated by :func:`scons_subst`, :func:`scons_subst_list`.
|
||||
Defines an :meth:`escape` method which allows supplying
|
||||
platform-specific escape and quote functions. The contained string
|
||||
will be escaped, quoted, or neither depending on the value of
|
||||
*literal* and the string contents.
|
||||
"""
|
||||
def __init__(self, cmd, literal=None) -> None:
|
||||
def __init__(self, cmd, literal: bool = False) -> None:
|
||||
super().__init__(cmd)
|
||||
self.literal = literal
|
||||
|
||||
def is_literal(self) -> bool:
|
||||
return self.literal
|
||||
|
||||
def escape(self, escape_func, quote_func=quote_spaces):
|
||||
def escape(self, escape_func, quote_func=quote_spaces) -> str:
|
||||
"""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
|
||||
@ -149,7 +162,6 @@ class CmdStringHolder(collections.UserString):
|
||||
After calling this function, the next call to str() will
|
||||
return the escaped string.
|
||||
"""
|
||||
|
||||
if self.is_literal():
|
||||
return escape_func(self.data)
|
||||
elif ' ' in self.data or '\t' in self.data:
|
||||
@ -157,7 +169,7 @@ class CmdStringHolder(collections.UserString):
|
||||
else:
|
||||
return self.data
|
||||
|
||||
def escape_list(mylist, escape_func):
|
||||
def escape_list(mylist, escape_func) -> list[str]:
|
||||
"""Escape a list of arguments by running the specified escape_func
|
||||
on every object in the list that has an escape() method."""
|
||||
def escape(obj, escape_func=escape_func):
|
||||
@ -201,15 +213,15 @@ class NLWrapper:
|
||||
_create_nodelist = _gen_nodelist
|
||||
|
||||
|
||||
class Targets_or_Sources(collections.UserList):
|
||||
class Targets_or_Sources(UserList):
|
||||
"""A class that implements $TARGETS or $SOURCES expansions by in turn
|
||||
wrapping a NLWrapper. This class handles the different methods used
|
||||
to access the list, calling the NLWrapper to create proxies on demand.
|
||||
|
||||
Note that we subclass collections.UserList purely so that the
|
||||
is_Sequence() function will identify an object of this class as
|
||||
a list during variable expansion. We're not really using any
|
||||
collections.UserList methods in practice.
|
||||
Note that we subclass :class:`~collections.UserList` purely so that the
|
||||
:func:`~SCons.Util.is_Sequence` function will identify an object of this
|
||||
class as a list during variable expansion. We're not really using any
|
||||
:class:`~collections.UserList` methods in practice.
|
||||
"""
|
||||
def __init__(self, nl) -> None:
|
||||
self.nl = nl
|
||||
@ -476,7 +488,7 @@ class StringSubber:
|
||||
return self.expand(args, lvars)
|
||||
|
||||
|
||||
class ListSubber(collections.UserList):
|
||||
class ListSubber(UserList):
|
||||
"""A class to construct the results of a scons_subst_list() call.
|
||||
|
||||
Like StringSubber, this class binds a specific construction
|
||||
@ -549,8 +561,8 @@ class ListSubber(collections.UserList):
|
||||
self.close_strip('$)')
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or key.find('.') >= 0:
|
||||
if key[0] == '{':
|
||||
if key.startswith('{') or '.' in key:
|
||||
if key.startswith('{'):
|
||||
key = key[1:-1]
|
||||
|
||||
# Store for error messages if we fail to expand the
|
||||
@ -650,7 +662,7 @@ class ListSubber(collections.UserList):
|
||||
"""Arrange for the next word to start a new line. This
|
||||
is like starting a new word, except that we have to append
|
||||
another line to the result."""
|
||||
collections.UserList.append(self, [])
|
||||
UserList.append(self, [])
|
||||
self.next_word()
|
||||
|
||||
def this_word(self) -> None:
|
||||
@ -707,7 +719,7 @@ class ListSubber(collections.UserList):
|
||||
y = self.conv(y)
|
||||
if is_String(y):
|
||||
#y = CmdStringHolder(y, literal1 or literal2)
|
||||
y = CmdStringHolder(y, None)
|
||||
y = CmdStringHolder(y, literal=False)
|
||||
self[-1][-1] = y
|
||||
|
||||
def add_new_word(self, x) -> None:
|
||||
@ -867,7 +879,7 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
|
||||
if mode == SUBST_SIG:
|
||||
result = _list_remove[mode](remove.split(result))
|
||||
if result is None:
|
||||
raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
|
||||
raise SCons.Errors.UserError(f"Unbalanced $(/$) in: {res}")
|
||||
result = ' '.join(result)
|
||||
else:
|
||||
result = remove.sub('', result)
|
||||
@ -950,7 +962,7 @@ def scons_subst_once(strSubst, env, key):
|
||||
|
||||
We do this with some straightforward, brute-force code here...
|
||||
"""
|
||||
if isinstance(strSubst, str) and strSubst.find('$') < 0:
|
||||
if isinstance(strSubst, str) and '$' not in strSubst:
|
||||
return strSubst
|
||||
|
||||
matchlist = ['$' + key, '${' + key + '}']
|
||||
@ -144,6 +144,7 @@ if CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS:
|
||||
|
||||
# MSVC batch file arguments:
|
||||
#
|
||||
# VS2026: UWP, SDK, TOOLSET, SPECTRE
|
||||
# VS2022: UWP, SDK, TOOLSET, SPECTRE
|
||||
# VS2019: UWP, SDK, TOOLSET, SPECTRE
|
||||
# VS2017: UWP, SDK, TOOLSET, SPECTRE
|
||||
@ -36,6 +36,8 @@ installation is used only when no other installation is detected.
|
||||
+---------+---------+----------------------------------------------------------+
|
||||
| Product | VCVer | Priority |
|
||||
+=========+=========+==========================================================+
|
||||
| VS2026 | 14.5 | Enterprise, Professional, Community, BuildTools |
|
||||
+=========+=========+==========================================================+
|
||||
| VS2022 | 14.3 | Enterprise, Professional, Community, BuildTools |
|
||||
+---------+---------+----------------------------------------------------------+
|
||||
| VS2019 | 14.2 | Enterprise, Professional, Community, BuildTools |
|
||||
@ -224,6 +226,7 @@ Example usage:
|
||||
::
|
||||
|
||||
for version in [
|
||||
'14.5',
|
||||
'14.4',
|
||||
'14.3',
|
||||
'14.2',
|
||||
@ -360,6 +363,8 @@ Supported MSVC batch file arguments by product:
|
||||
+---------+---------+--------+---------+---------+
|
||||
| Product | UWP | SDK | Toolset | Spectre |
|
||||
+=========+=========+========+=========+=========+
|
||||
| VS2026 | X | X | X | X |
|
||||
+=========+=========+========+=========+=========+
|
||||
| VS2022 | X | X | X | X |
|
||||
+---------+---------+--------+---------+---------+
|
||||
| VS2019 | X | X | X | X |
|
||||
@ -514,6 +519,8 @@ BuildSeries Versions
|
||||
+-------------+-------+-------+
|
||||
| BuildSeries | VCVER | CLVER |
|
||||
+=============+=======+=======+
|
||||
| 14.5 | 14.5X | 19.5 |
|
||||
+-------------+-------+-------+
|
||||
| 14.4 | 14.4X | 19.4 |
|
||||
+-------------+-------+-------+
|
||||
| 14.3 | 14.3X | 19.3 |
|
||||
@ -547,6 +554,8 @@ BuildTools Versions
|
||||
+------------+-------------+----------+
|
||||
| BuildTools | BuildSeries | MSVCRT |
|
||||
+============+=============+==========+
|
||||
| v145 | 14.5 | 140/ucrt |
|
||||
+------------+-------------+----------+
|
||||
| v143 | 14.4, 14.3 | 140/ucrt |
|
||||
+------------+-------------+----------+
|
||||
| v142 | 14.2 | 140/ucrt |
|
||||
@ -575,33 +584,35 @@ BuildTools Versions
|
||||
Product Versions
|
||||
----------------
|
||||
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| Product | VSVER | SCons | SDK | BuildTools |
|
||||
+==========+=======+=======+===========+========================+
|
||||
| 2022 | 17.0 | 14.3 | 10.0, 8.1 | v143, v142, v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2019 | 16.0 | 14.2 | 10.0, 8.1 | v142, v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2017 | 15.0 | 14.1 | 10.0, 8.1 | v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2015 | 14.0 | 14.0 | 10.0, 8.1 | v140 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2013 | 12.0 | 12.0 | | v120 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2012 | 11.0 | 11.0 | | v110 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2010 | 10.0 | 10.0 | | v100 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2008 | 9.0 | 9.0 | | v90 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2005 | 8.0 | 8.0 | | v80 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2003.NET | 7.1 | 7.1 | | v71 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 2002.NET | 7.0 | 7.0 | | v70 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
| 6.0 | 6.0 | 6.0 | | v60 |
|
||||
+----------+-------+-------+-----------+------------------------+
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| Product | VSVER | SCons | SDK | BuildTools |
|
||||
+==========+=======+=======+===========+==============================+
|
||||
| 2026 | 18.0 | 14.5 | 10.0, 8.1 | v145, v143, v142, v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2022 | 17.0 | 14.3 | 10.0, 8.1 | v143, v142, v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2019 | 16.0 | 14.2 | 10.0, 8.1 | v142, v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2017 | 15.0 | 14.1 | 10.0, 8.1 | v141, v140 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2015 | 14.0 | 14.0 | 10.0, 8.1 | v140 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2013 | 12.0 | 12.0 | | v120 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2012 | 11.0 | 11.0 | | v110 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2010 | 10.0 | 10.0 | | v100 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2008 | 9.0 | 9.0 | | v90 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2005 | 8.0 | 8.0 | | v80 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2003.NET | 7.1 | 7.1 | | v71 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 2002.NET | 7.0 | 7.0 | | v70 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
| 6.0 | 6.0 | 6.0 | | v60 |
|
||||
+----------+-------+-------+-----------+------------------------------+
|
||||
|
||||
|
||||
SCons Implementation Notes
|
||||
@ -713,7 +724,7 @@ into the current document format as appropriate.
|
||||
|
||||
|
||||
Problems:
|
||||
- For VS >= 2017, VS and VS are not 1:1, there can be many VC for one VS
|
||||
- For VS >= 2017, VC and VS are not 1:1, there can be many VC for one VS
|
||||
- For vswhere-ready versions, detection does not proceed beyond the
|
||||
product level ("2019") into individual "features" (individual msvc)
|
||||
- As documented for MSVC_VERSION, compilers can only be requested if versions
|
||||
@ -30,6 +30,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from contextlib import suppress
|
||||
from subprocess import DEVNULL, PIPE
|
||||
from pathlib import Path
|
||||
@ -38,6 +39,44 @@ import SCons.Errors
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
|
||||
# TODO: Hard-coded list of the variables that (may) need to be
|
||||
# imported from os.environ[] for the chain of development batch
|
||||
# files to execute correctly. One call to vcvars*.bat may
|
||||
# end up running a dozen or more scripts, changes not only with
|
||||
# each release but with what is installed at the time. We think
|
||||
# in modern installations most are set along the way and don't
|
||||
# need to be picked from the env, but include these for safety's sake.
|
||||
# Any VSCMD variables definitely are picked from the env and
|
||||
# control execution in interesting ways.
|
||||
# Note these really should be unified - either controlled by vs.py,
|
||||
# or synced with the the common_tools_var # settings in vs.py.
|
||||
VS_VC_VARS = [
|
||||
'COMSPEC', # path to "shell"
|
||||
'OS', # name of OS family: Windows_NT or undefined (95/98/ME)
|
||||
'VS180COMNTOOLS', # path to common tools for given version
|
||||
'VS170COMNTOOLS',
|
||||
'VS160COMNTOOLS',
|
||||
'VS150COMNTOOLS',
|
||||
'VS140COMNTOOLS',
|
||||
'VS120COMNTOOLS',
|
||||
'VS110COMNTOOLS',
|
||||
'VS100COMNTOOLS',
|
||||
'VS90COMNTOOLS',
|
||||
'VS80COMNTOOLS',
|
||||
'VS71COMNTOOLS',
|
||||
'VSCOMNTOOLS',
|
||||
'MSDevDir',
|
||||
'VSCMD_DEBUG', # enable logging and other debug aids
|
||||
'VSCMD_SKIP_SENDTELEMETRY',
|
||||
'windir', # windows directory (SystemRoot not available in 95/98/ME)
|
||||
'VCPKG_DISABLE_METRICS',
|
||||
'VCPKG_ROOT',
|
||||
'POWERSHELL_TELEMETRY_OPTOUT',
|
||||
'PSDisableModuleAnalysisCacheCleanup',
|
||||
'PSModuleAnalysisCachePath',
|
||||
]
|
||||
|
||||
class MSVCCacheInvalidWarning(SCons.Warnings.WarningOnByDefault):
|
||||
pass
|
||||
|
||||
@ -305,6 +344,112 @@ def _force_vscmd_skip_sendtelemetry(env):
|
||||
return True
|
||||
|
||||
|
||||
class _PathManager:
|
||||
|
||||
_PSEXECUTABLES = (
|
||||
"pwsh.exe",
|
||||
"powershell.exe",
|
||||
)
|
||||
|
||||
_PSMODULEPATH_MAP = {os.path.normcase(os.path.abspath(p)): p for p in [
|
||||
# os.path.expandvars(r"%USERPROFILE%\Documents\PowerShell\Modules"), # current user
|
||||
os.path.expandvars(r"%ProgramFiles%\PowerShell\Modules"), # all users
|
||||
os.path.expandvars(r"%ProgramFiles%\PowerShell\7\Modules"), # installation location
|
||||
# os.path.expandvars(r"%USERPROFILE%\Documents\WindowsPowerShell\Modules"), # current user
|
||||
os.path.expandvars(r"%ProgramFiles%\WindowsPowerShell\Modules"), # all users
|
||||
os.path.expandvars(r"%windir%\System32\WindowsPowerShell\v1.0\Modules"), # installation location
|
||||
]}
|
||||
|
||||
_cache_norm_path = {}
|
||||
|
||||
@classmethod
|
||||
def _get_norm_path(cls, p):
|
||||
norm_path = cls._cache_norm_path.get(p)
|
||||
if norm_path is None:
|
||||
norm_path = os.path.normcase(os.path.abspath(p))
|
||||
cls._cache_norm_path[p] = norm_path
|
||||
cls._cache_norm_path[norm_path] = norm_path
|
||||
return norm_path
|
||||
|
||||
_cache_is_psmodulepath = {}
|
||||
|
||||
@classmethod
|
||||
def _is_psmodulepath(cls, p):
|
||||
is_psmodulepath = cls._cache_is_psmodulepath.get(p)
|
||||
if is_psmodulepath is None:
|
||||
norm_path = cls._get_norm_path(p)
|
||||
is_psmodulepath = bool(norm_path in cls._PSMODULEPATH_MAP)
|
||||
cls._cache_is_psmodulepath[p] = is_psmodulepath
|
||||
cls._cache_is_psmodulepath[norm_path] = is_psmodulepath
|
||||
return is_psmodulepath
|
||||
|
||||
_cache_psmodulepath_paths = {}
|
||||
|
||||
@classmethod
|
||||
def get_psmodulepath_paths(cls, pathspec):
|
||||
psmodulepath_paths = cls._cache_psmodulepath_paths.get(pathspec)
|
||||
if psmodulepath_paths is None:
|
||||
psmodulepath_paths = []
|
||||
for p in pathspec.split(os.pathsep):
|
||||
p = p.strip()
|
||||
if not p:
|
||||
continue
|
||||
if not cls._is_psmodulepath(p):
|
||||
continue
|
||||
psmodulepath_paths.append(p)
|
||||
psmodulepath_paths = tuple(psmodulepath_paths)
|
||||
cls._cache_psmodulepath_paths[pathspec] = psmodulepath_paths
|
||||
return psmodulepath_paths
|
||||
|
||||
_cache_psexe_paths = {}
|
||||
|
||||
@classmethod
|
||||
def get_psexe_paths(cls, pathspec):
|
||||
psexe_paths = cls._cache_psexe_paths.get(pathspec)
|
||||
if psexe_paths is None:
|
||||
psexe_set = set(cls._PSEXECUTABLES)
|
||||
psexe_paths = []
|
||||
for p in pathspec.split(os.pathsep):
|
||||
p = p.strip()
|
||||
if not p:
|
||||
continue
|
||||
for psexe in psexe_set:
|
||||
psexe_path = os.path.join(p, psexe)
|
||||
if not os.path.exists(psexe_path):
|
||||
continue
|
||||
psexe_paths.append(p)
|
||||
psexe_set.remove(psexe)
|
||||
break
|
||||
if psexe_set:
|
||||
continue
|
||||
break
|
||||
psexe_paths = tuple(psexe_paths)
|
||||
cls._cache_psexe_paths[pathspec] = psexe_paths
|
||||
return psexe_paths
|
||||
|
||||
_cache_minimal_pathspec = {}
|
||||
|
||||
@classmethod
|
||||
def get_minimal_pathspec(cls, pathlist):
|
||||
pathlist_t = tuple(pathlist)
|
||||
minimal_pathspec = cls._cache_minimal_pathspec.get(pathlist_t)
|
||||
if minimal_pathspec is None:
|
||||
minimal_paths = []
|
||||
seen = set()
|
||||
for p in pathlist:
|
||||
p = p.strip()
|
||||
if not p:
|
||||
continue
|
||||
norm_path = cls._get_norm_path(p)
|
||||
if norm_path in seen:
|
||||
continue
|
||||
seen.add(norm_path)
|
||||
minimal_paths.append(p)
|
||||
minimal_pathspec = os.pathsep.join(minimal_paths)
|
||||
cls._cache_minimal_pathspec[pathlist_t] = minimal_pathspec
|
||||
return minimal_pathspec
|
||||
|
||||
|
||||
def normalize_env(env, keys, force: bool=False):
|
||||
"""Given a dictionary representing a shell environment, add the variables
|
||||
from os.environ needed for the processing of .bat files; the keys are
|
||||
@ -325,6 +470,11 @@ def normalize_env(env, keys, force: bool=False):
|
||||
for k in keys:
|
||||
if k in os.environ and (force or k not in normenv):
|
||||
normenv[k] = os.environ[k]
|
||||
debug("keys: normenv[%s]=%s", k, normenv[k])
|
||||
else:
|
||||
debug("keys: skipped[%s]", k)
|
||||
|
||||
syspath_pathlist = normenv.get("PATH", "").split(os.pathsep)
|
||||
|
||||
# add some things to PATH to prevent problems:
|
||||
# Shouldn't be necessary to add system32, since the default environment
|
||||
@ -332,24 +482,37 @@ def normalize_env(env, keys, force: bool=False):
|
||||
sys32_dir = os.path.join(
|
||||
os.environ.get("SystemRoot", os.environ.get("windir", r"C:\Windows")), "System32"
|
||||
)
|
||||
if sys32_dir not in normenv["PATH"]:
|
||||
normenv["PATH"] = normenv["PATH"] + os.pathsep + sys32_dir
|
||||
syspath_pathlist.append(sys32_dir)
|
||||
|
||||
# Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
|
||||
# error starting with Visual Studio 2017, although the script still
|
||||
# seems to work anyway.
|
||||
sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem')
|
||||
if sys32_wbem_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
|
||||
syspath_pathlist.append(sys32_wbem_dir)
|
||||
|
||||
# Without Powershell in PATH, an internal call to a telemetry
|
||||
# function (starting with a VS2019 update) can fail
|
||||
# Note can also set VSCMD_SKIP_SENDTELEMETRY to avoid this.
|
||||
sys32_ps_dir = os.path.join(sys32_dir, r'WindowsPowerShell\v1.0')
|
||||
if sys32_ps_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_ps_dir
|
||||
|
||||
# Find the powershell executable paths. Add the known powershell.exe
|
||||
# path to the end of the shell system path (just in case).
|
||||
# The VS vcpkg component prefers pwsh.exe if it's on the path.
|
||||
sys32_ps_dir = os.path.join(sys32_dir, 'WindowsPowerShell', 'v1.0')
|
||||
psexe_searchlist = os.pathsep.join([os.environ.get("PATH", ""), sys32_ps_dir])
|
||||
psexe_pathlist = _PathManager.get_psexe_paths(psexe_searchlist)
|
||||
|
||||
# Add powershell executable paths in the order discovered.
|
||||
syspath_pathlist.extend(psexe_pathlist)
|
||||
|
||||
normenv['PATH'] = _PathManager.get_minimal_pathspec(syspath_pathlist)
|
||||
debug("PATH: %s", normenv['PATH'])
|
||||
|
||||
# Add psmodulepath paths in the order discovered.
|
||||
psmodulepath_pathlist = _PathManager.get_psmodulepath_paths(os.environ.get("PSModulePath", ""))
|
||||
if psmodulepath_pathlist:
|
||||
normenv["PSModulePath"] = _PathManager.get_minimal_pathspec(psmodulepath_pathlist)
|
||||
|
||||
debug("PSModulePath: %s", normenv.get('PSModulePath',''))
|
||||
return normenv
|
||||
|
||||
|
||||
@ -360,41 +523,13 @@ def get_output(vcbat, args=None, env=None, skip_sendtelemetry=False):
|
||||
# Create a blank environment, for use in launching the tools
|
||||
env = SCons.Environment.Environment(tools=[])
|
||||
|
||||
# TODO: Hard-coded list of the variables that (may) need to be
|
||||
# imported from os.environ[] for the chain of development batch
|
||||
# files to execute correctly. One call to vcvars*.bat may
|
||||
# end up running a dozen or more scripts, changes not only with
|
||||
# each release but with what is installed at the time. We think
|
||||
# in modern installations most are set along the way and don't
|
||||
# need to be picked from the env, but include these for safety's sake.
|
||||
# Any VSCMD variables definitely are picked from the env and
|
||||
# control execution in interesting ways.
|
||||
# Note these really should be unified - either controlled by vs.py,
|
||||
# or synced with the the common_tools_var # settings in vs.py.
|
||||
vs_vc_vars = [
|
||||
'COMSPEC', # path to "shell"
|
||||
'OS', # name of OS family: Windows_NT or undefined (95/98/ME)
|
||||
'VS170COMNTOOLS', # path to common tools for given version
|
||||
'VS160COMNTOOLS',
|
||||
'VS150COMNTOOLS',
|
||||
'VS140COMNTOOLS',
|
||||
'VS120COMNTOOLS',
|
||||
'VS110COMNTOOLS',
|
||||
'VS100COMNTOOLS',
|
||||
'VS90COMNTOOLS',
|
||||
'VS80COMNTOOLS',
|
||||
'VS71COMNTOOLS',
|
||||
'VSCOMNTOOLS',
|
||||
'MSDevDir',
|
||||
'VSCMD_DEBUG', # enable logging and other debug aids
|
||||
'VSCMD_SKIP_SENDTELEMETRY',
|
||||
'windir', # windows directory (SystemRoot not available in 95/98/ME)
|
||||
]
|
||||
env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False)
|
||||
env['ENV'] = normalize_env(env['ENV'], VS_VC_VARS, force=False)
|
||||
|
||||
if skip_sendtelemetry:
|
||||
_force_vscmd_skip_sendtelemetry(env)
|
||||
|
||||
# debug("ENV=%r", env['ENV'])
|
||||
|
||||
if args:
|
||||
debug("Calling '%s %s'", vcbat, args)
|
||||
cmd_str = '"%s" %s & set' % (vcbat, args)
|
||||
@ -402,10 +537,15 @@ def get_output(vcbat, args=None, env=None, skip_sendtelemetry=False):
|
||||
debug("Calling '%s'", vcbat)
|
||||
cmd_str = '"%s" & set' % vcbat
|
||||
|
||||
beg_time = time.time()
|
||||
|
||||
cp = SCons.Action.scons_subproc_run(
|
||||
env, cmd_str, stdin=DEVNULL, stdout=PIPE, stderr=PIPE,
|
||||
)
|
||||
|
||||
end_time = time.time()
|
||||
debug("Elapsed %.2fs", end_time - beg_time)
|
||||
|
||||
# Extra debug logic, uncomment if necessary
|
||||
# debug('stdout:%s', cp.stdout)
|
||||
# debug('stderr:%s', cp.stderr)
|
||||
@ -460,6 +600,7 @@ def parse_output(output, keep=KEEPLIST):
|
||||
# it.
|
||||
path = path.strip('"')
|
||||
dkeep[key].append(str(path))
|
||||
debug("dkeep[%s].append(%r)", key, path)
|
||||
|
||||
for line in output.splitlines():
|
||||
for k, value in rdk.items():
|
||||
@ -736,6 +736,7 @@ def _skip_sendtelemetry(env):
|
||||
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
|
||||
# MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
_VCVER = [
|
||||
"14.5",
|
||||
"14.3",
|
||||
"14.2",
|
||||
"14.1", "14.1Exp",
|
||||
@ -759,6 +760,7 @@ _VSWHERE_VSMAJOR_TO_VCVERSION = {}
|
||||
_VSWHERE_SUPPORTED_VCVER = set()
|
||||
|
||||
for vs_major, vc_version, vc_ver_list in (
|
||||
('18', '14.5', None),
|
||||
('17', '14.3', None),
|
||||
('16', '14.2', None),
|
||||
('15', '14.1', ['14.1Exp']),
|
||||
@ -855,7 +857,7 @@ _VCVER_TO_PRODUCT_DIR = {
|
||||
|
||||
# detect ide binaries
|
||||
|
||||
VS2022_VS2002_DEV = (
|
||||
VS2026_VS2002_DEV = (
|
||||
MSVC.Kind.IDE_PROGRAM_DEVENV_COM, # devenv.com
|
||||
)
|
||||
|
||||
@ -885,27 +887,28 @@ _VCVER_KIND_DETECT = {
|
||||
|
||||
# 'VCVer': (relpath from pdir to vsroot, path from vsroot to ide binaries, ide binaries)
|
||||
|
||||
'14.3': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV), # 2022
|
||||
'14.2': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV), # 2019
|
||||
'14.1': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2017_EXP), # 2017
|
||||
'14.1Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2017_EXP), # 2017
|
||||
'14.5': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV), # 2026
|
||||
'14.3': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV), # 2022
|
||||
'14.2': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV), # 2019
|
||||
'14.1': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2017_EXP), # 2017
|
||||
'14.1Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2017_EXP), # 2017
|
||||
|
||||
'14.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2015
|
||||
'14.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2015
|
||||
'12.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2013
|
||||
'12.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2013
|
||||
'11.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2012
|
||||
'11.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2015_VS2012_EXP), # 2012
|
||||
'14.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2015
|
||||
'14.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2015
|
||||
'12.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2013
|
||||
'12.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2013
|
||||
'11.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2012
|
||||
'11.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2015_VS2012_EXP), # 2012
|
||||
|
||||
'10.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2010
|
||||
'10.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2010
|
||||
'9.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2008
|
||||
'9.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2008
|
||||
'8.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2005
|
||||
'8.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV + VS2010_VS2005_EXP), # 2005
|
||||
'10.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2010
|
||||
'10.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2010
|
||||
'9.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2008
|
||||
'9.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2008
|
||||
'8.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2005
|
||||
'8.0Exp': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV + VS2010_VS2005_EXP), # 2005
|
||||
|
||||
'7.1': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV), # 2003
|
||||
'7.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2022_VS2002_DEV), # 2001
|
||||
'7.1': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV), # 2003
|
||||
'7.0': _DETECT(root='..', path=r'Common7\IDE', programs=VS2026_VS2002_DEV), # 2001
|
||||
|
||||
'6.0': _DETECT(root='..', path=r'Common\MSDev98\Bin', programs=VS1998_DEV), # 1998
|
||||
}
|
||||
@ -213,6 +213,18 @@ class VisualStudio:
|
||||
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
|
||||
SupportedVSList = [
|
||||
# Visual Studio 2026
|
||||
VisualStudio('14.5',
|
||||
vc_version='14.5',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS180COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm", 'arm64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2022
|
||||
VisualStudio('14.3',
|
||||
vc_version='14.3',
|
||||
@ -408,7 +408,7 @@ def createObjBuilders(env):
|
||||
suffix='$OBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=1)
|
||||
single_source=True)
|
||||
env['BUILDERS']['StaticObject'] = static_obj
|
||||
env['BUILDERS']['Object'] = static_obj
|
||||
|
||||
@ -421,7 +421,7 @@ def createObjBuilders(env):
|
||||
suffix='$SHOBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=1)
|
||||
single_source=True)
|
||||
env['BUILDERS']['SharedObject'] = shared_obj
|
||||
|
||||
return (static_obj, shared_obj)
|
||||
@ -156,11 +156,14 @@ def write_compilation_db(target, source, env) -> None:
|
||||
source_file = entry['file']
|
||||
output_file = entry['output']
|
||||
|
||||
if not source_file.is_derived():
|
||||
source_file = source_file.srcnode()
|
||||
|
||||
if use_abspath:
|
||||
source_file = source_file.srcnode().abspath
|
||||
source_file = source_file.abspath
|
||||
output_file = output_file.abspath
|
||||
else:
|
||||
source_file = source_file.srcnode().path
|
||||
source_file = source_file.path
|
||||
output_file = output_file.path
|
||||
|
||||
if use_path_filter and not fnmatch.fnmatch(output_file, use_path_filter):
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user