mirror of
https://github.com/Nuitka/Nuitka.git
synced 2025-12-14 20:35:49 +01:00
Scons: Added newer inline copy with Scons that supports Visual Studio 2026
* Migrated and expanded our patches to avoid unused tools, deleted more than before. * Remove annotations which is what we do now for inline copies, since they only waste space.
This commit is contained in:
@@ -44,10 +44,14 @@ def initScons():
|
||||
# That's a noop, pylint: disable=unused-argument
|
||||
pass
|
||||
|
||||
# Avoid scons writing the scons database at all, spell-checker: ignore dblite
|
||||
# Avoid scons writing the scons database at all, we don't care for it,
|
||||
# spell-checker: ignore dblite
|
||||
import SCons.dblite # pylint: disable=I0021,import-error
|
||||
|
||||
SCons.dblite.dblite.sync = no_sync
|
||||
try:
|
||||
SCons.dblite.dblite.sync = no_sync
|
||||
except AttributeError:
|
||||
SCons.dblite._Dblite.sync = no_sync # pylint: disable=protected-access
|
||||
|
||||
# We use threads during build, so keep locks if necessary for progress bar
|
||||
# updates.
|
||||
|
||||
@@ -19,6 +19,8 @@ if __name__ == "__main__":
|
||||
if sys.version_info < (2, 7):
|
||||
# Non-Windows, Python 2.6, mostly older RHEL
|
||||
scons_version = "scons-2.3.2"
|
||||
elif os.name == "nt" and sys.version_info >= (3, 7):
|
||||
scons_version = "scons-4.10.1"
|
||||
elif os.name == "nt" and sys.version_info >= (3, 5):
|
||||
# Windows can use latest, supported MSVC 2022 this way
|
||||
scons_version = "scons-4.3.0"
|
||||
|
||||
1619
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Action.py
Normal file
1619
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Action.py
Normal file
File diff suppressed because it is too large
Load Diff
918
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Builder.py
Normal file
918
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Builder.py
Normal file
@@ -0,0 +1,918 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
SCons.Builder
|
||||
|
||||
Builder object subsystem.
|
||||
|
||||
A Builder object is a callable that encapsulates information about how
|
||||
to execute actions to create a target Node (file) from source Nodes
|
||||
(files), and how to create those dependencies for tracking.
|
||||
|
||||
The main entry point here is the Builder() factory method. This provides
|
||||
a procedural interface that creates the right underlying Builder object
|
||||
based on the keyword arguments supplied and the types of the arguments.
|
||||
|
||||
The goal is for this external interface to be simple enough that the
|
||||
vast majority of users can create new Builders as necessary to support
|
||||
building new types of files in their configurations, without having to
|
||||
dive any deeper into this subsystem.
|
||||
|
||||
The base class here is BuilderBase. This is a concrete base class which
|
||||
does, in fact, represent the Builder objects that we (or users) create.
|
||||
|
||||
There is also a proxy that looks like a Builder:
|
||||
|
||||
CompositeBuilder
|
||||
|
||||
This proxies for a Builder with an action that is actually a
|
||||
dictionary that knows how to map file suffixes to a specific
|
||||
action. This is so that we can invoke different actions
|
||||
(compilers, compile options) for different flavors of source
|
||||
files.
|
||||
|
||||
Builders and their proxies have the following public interface methods
|
||||
used by other modules:
|
||||
|
||||
- __call__()
|
||||
THE public interface. Calling a Builder object (with the
|
||||
use of internal helper methods) sets up the target and source
|
||||
dependencies, appropriate mapping to a specific action, and the
|
||||
environment manipulation necessary for overridden construction
|
||||
variable. This also takes care of warning about possible mistakes
|
||||
in keyword arguments.
|
||||
|
||||
- add_emitter()
|
||||
Adds an emitter for a specific file suffix, used by some Tool
|
||||
modules to specify that (for example) a yacc invocation on a .y
|
||||
can create a .h *and* a .c file.
|
||||
|
||||
- add_action()
|
||||
Adds an action for a specific file suffix, heavily used by
|
||||
Tool modules to add their specific action(s) for turning
|
||||
a source file into an object file to the global static
|
||||
and shared object file Builders.
|
||||
|
||||
There are the following methods for internal use within this module:
|
||||
|
||||
- _execute()
|
||||
The internal method that handles the heavily lifting when a
|
||||
Builder is called. This is used so that the __call__() methods
|
||||
can set up warning about possible mistakes in keyword-argument
|
||||
overrides, and *then* execute all of the steps necessary so that
|
||||
the warnings only occur once.
|
||||
|
||||
- get_name()
|
||||
Returns the Builder's name within a specific Environment,
|
||||
primarily used to try to return helpful information in error
|
||||
messages.
|
||||
|
||||
- adjust_suffix()
|
||||
- get_prefix()
|
||||
- get_suffix()
|
||||
- get_src_suffix()
|
||||
- set_src_suffix()
|
||||
Miscellaneous stuff for handling the prefix and suffix
|
||||
manipulation we use in turning source file names into target
|
||||
file names.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections import UserDict, UserList
|
||||
from contextlib import suppress
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Debug
|
||||
import SCons.Executor
|
||||
import SCons.Memoize
|
||||
import SCons.Util
|
||||
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
|
||||
|
||||
_null = _Null
|
||||
|
||||
def match_splitext(path, suffixes = []):
|
||||
if suffixes:
|
||||
matchsuf = [S for S in suffixes if path[-len(S):] == S]
|
||||
if matchsuf:
|
||||
suf = max([(len(_f),_f) for _f in matchsuf])[1]
|
||||
return [path[:-len(suf)], path[-len(suf):]]
|
||||
return SCons.Util.splitext(path)
|
||||
|
||||
class DictCmdGenerator(SCons.Util.Selector):
|
||||
"""This is a callable class that can be used as a
|
||||
command generator function. It holds on to a dictionary
|
||||
mapping file suffixes to Actions. It uses that dictionary
|
||||
to return the proper action based on the file suffix of
|
||||
the source file."""
|
||||
|
||||
def __init__(self, mapping=None, source_ext_match=True):
|
||||
super().__init__(mapping)
|
||||
self.source_ext_match = source_ext_match
|
||||
|
||||
def src_suffixes(self):
|
||||
return list(self.keys())
|
||||
|
||||
def add_action(self, suffix, action):
|
||||
"""Add a suffix-action pair to the mapping.
|
||||
"""
|
||||
self[suffix] = action
|
||||
|
||||
def __call__(self, target, source, env, for_signature):
|
||||
if not source:
|
||||
return []
|
||||
|
||||
if self.source_ext_match:
|
||||
suffixes = self.src_suffixes()
|
||||
ext = None
|
||||
for src in map(str, source):
|
||||
my_ext = match_splitext(src, suffixes)[1]
|
||||
if ext and my_ext != ext:
|
||||
raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s"
|
||||
% (repr(list(map(str, target))), src, ext, my_ext))
|
||||
ext = my_ext
|
||||
else:
|
||||
ext = match_splitext(str(source[0]), self.src_suffixes())[1]
|
||||
|
||||
if not ext:
|
||||
#return ext
|
||||
raise UserError("While building `%s': "
|
||||
"Cannot deduce file extension from source files: %s"
|
||||
% (repr(list(map(str, target))), repr(list(map(str, source)))))
|
||||
|
||||
try:
|
||||
ret = SCons.Util.Selector.__call__(self, env, source, ext)
|
||||
except KeyError as e:
|
||||
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2]))
|
||||
if ret is None:
|
||||
raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \
|
||||
(repr(list(map(str, target))), repr(list(map(str, source))), ext, repr(list(self.keys()))))
|
||||
return ret
|
||||
|
||||
class CallableSelector(SCons.Util.Selector):
|
||||
"""A callable dictionary that will, in turn, call the value it
|
||||
finds if it can."""
|
||||
def __call__(self, env, source):
|
||||
value = SCons.Util.Selector.__call__(self, env, source)
|
||||
if callable(value):
|
||||
value = value(env, source)
|
||||
return value
|
||||
|
||||
class DictEmitter(SCons.Util.Selector):
|
||||
"""A callable dictionary that maps file suffixes to emitters.
|
||||
When called, it finds the right emitter in its dictionary for the
|
||||
suffix of the first source file, and calls that emitter to get the
|
||||
right lists of targets and sources to return. If there's no emitter
|
||||
for the suffix in its dictionary, the original target and source are
|
||||
returned.
|
||||
"""
|
||||
def __call__(self, target, source, env):
|
||||
emitter = SCons.Util.Selector.__call__(self, env, source)
|
||||
if emitter:
|
||||
target, source = emitter(target, source, env)
|
||||
return (target, source)
|
||||
|
||||
class ListEmitter(UserList):
|
||||
"""A callable list of emitters that calls each in sequence,
|
||||
returning the result.
|
||||
"""
|
||||
def __call__(self, target, source, env):
|
||||
for e in self.data:
|
||||
target, source = e(target, source, env)
|
||||
return (target, source)
|
||||
|
||||
# These are a common errors when calling a Builder;
|
||||
# they are similar to the 'target' and 'source' keyword args to builders,
|
||||
# so we issue warnings when we see them. The warnings can, of course,
|
||||
# be disabled.
|
||||
misleading_keywords = {
|
||||
'targets' : 'target',
|
||||
'sources' : 'source',
|
||||
}
|
||||
|
||||
class OverrideWarner(UserDict):
|
||||
"""A class for warning about keyword arguments that we use as
|
||||
overrides in a Builder call.
|
||||
|
||||
This class exists to handle the fact that a single Builder call
|
||||
can actually invoke multiple builders. This class only emits the
|
||||
warnings once, no matter how many Builders are invoked.
|
||||
"""
|
||||
def __init__(self, mapping):
|
||||
super().__init__(mapping)
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner')
|
||||
self.already_warned = None
|
||||
|
||||
def warn(self):
|
||||
if self.already_warned:
|
||||
return
|
||||
for k in self.keys():
|
||||
if k in misleading_keywords:
|
||||
alt = misleading_keywords[k]
|
||||
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
|
||||
SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
|
||||
self.already_warned = 1
|
||||
|
||||
def Builder(**kw):
|
||||
"""A factory for builder objects."""
|
||||
composite = None
|
||||
if 'generator' in kw:
|
||||
if 'action' in kw:
|
||||
raise UserError("You must not specify both an action and a generator.")
|
||||
kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {})
|
||||
del kw['generator']
|
||||
elif 'action' in kw:
|
||||
source_ext_match = kw.get('source_ext_match', True)
|
||||
if 'source_ext_match' in kw:
|
||||
del kw['source_ext_match']
|
||||
if SCons.Util.is_Dict(kw['action']):
|
||||
composite = DictCmdGenerator(kw['action'], source_ext_match)
|
||||
kw['action'] = SCons.Action.CommandGeneratorAction(composite, {})
|
||||
kw['src_suffix'] = composite.src_suffixes()
|
||||
else:
|
||||
kw['action'] = SCons.Action.Action(kw['action'])
|
||||
|
||||
if 'emitter' in kw:
|
||||
emitter = kw['emitter']
|
||||
if SCons.Util.is_String(emitter):
|
||||
# This allows users to pass in an Environment
|
||||
# variable reference (like "$FOO") as an emitter.
|
||||
# We will look in that Environment variable for
|
||||
# a callable to use as the actual emitter.
|
||||
var = SCons.Util.get_environment_var(emitter)
|
||||
if not var:
|
||||
raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter)
|
||||
kw['emitter'] = EmitterProxy(var)
|
||||
elif SCons.Util.is_Dict(emitter):
|
||||
kw['emitter'] = DictEmitter(emitter)
|
||||
elif SCons.Util.is_List(emitter):
|
||||
kw['emitter'] = ListEmitter(emitter)
|
||||
|
||||
result = BuilderBase(**kw)
|
||||
|
||||
if composite is not None:
|
||||
result = CompositeBuilder(result, composite)
|
||||
|
||||
return result
|
||||
|
||||
def _node_errors(builder, env, tlist, slist):
|
||||
"""Validate that the lists of target and source nodes are
|
||||
legal for this builder and environment. Raise errors or
|
||||
issue warnings as appropriate.
|
||||
"""
|
||||
|
||||
# First, figure out if there are any errors in the way the targets
|
||||
# were specified.
|
||||
for t in tlist:
|
||||
if t.side_effect:
|
||||
raise UserError("Multiple ways to build the same target were specified for: %s" % t)
|
||||
if t.has_explicit_builder():
|
||||
# Check for errors when the environments are different
|
||||
# No error if environments are the same Environment instance
|
||||
if (t.env is not None and t.env is not env and
|
||||
# Check OverrideEnvironment case - no error if wrapped Environments
|
||||
# are the same instance, and overrides lists match
|
||||
not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
|
||||
getattr(t.env, 'overrides', 0) == getattr(env, 'overrides', 1) and
|
||||
not builder.multi)):
|
||||
action = t.builder.action
|
||||
t_contents = t.builder.action.get_contents(tlist, slist, t.env)
|
||||
contents = builder.action.get_contents(tlist, slist, env)
|
||||
|
||||
if t_contents == contents:
|
||||
msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
|
||||
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
|
||||
else:
|
||||
try:
|
||||
msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8'))
|
||||
except UnicodeDecodeError:
|
||||
msg = "Two environments with different actions were specified for the same target: %s"%t
|
||||
raise UserError(msg)
|
||||
if builder.multi:
|
||||
if t.builder != builder:
|
||||
msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
|
||||
raise UserError(msg)
|
||||
# TODO(batch): list constructed each time!
|
||||
if t.get_executor().get_all_targets() != tlist:
|
||||
msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, list(map(str, t.get_executor().get_all_targets())), list(map(str, tlist)))
|
||||
raise UserError(msg)
|
||||
elif t.sources != slist:
|
||||
msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, list(map(str, t.sources)), list(map(str, slist)))
|
||||
raise UserError(msg)
|
||||
|
||||
if builder.single_source:
|
||||
if len(slist) > 1:
|
||||
raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist))))
|
||||
|
||||
class EmitterProxy:
|
||||
"""This is a callable class that can act as a
|
||||
Builder emitter. It holds on to a string that
|
||||
is a key into an Environment dictionary, and will
|
||||
look there at actual build time to see if it holds
|
||||
a callable. If so, we will call that as the actual
|
||||
emitter."""
|
||||
def __init__(self, var):
|
||||
self.var = SCons.Util.to_String(var)
|
||||
|
||||
def __call__(self, target, source, env):
|
||||
emitter = self.var
|
||||
|
||||
# Recursively substitute the variable.
|
||||
# We can't use env.subst() because it deals only
|
||||
# in strings. Maybe we should change that?
|
||||
while SCons.Util.is_String(emitter) and emitter in env:
|
||||
emitter = env[emitter]
|
||||
if callable(emitter):
|
||||
target, source = emitter(target, source, env)
|
||||
elif SCons.Util.is_List(emitter):
|
||||
for e in emitter:
|
||||
target, source = e(target, source, env)
|
||||
|
||||
return (target, source)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.var == other.var
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.var < other.var
|
||||
|
||||
def __le__(self, other):
|
||||
return self.var <= other.var
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.var > other.var
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.var >= other.var
|
||||
|
||||
class BuilderBase:
|
||||
"""Base class for Builders, objects that create output
|
||||
nodes (files) from input nodes (files).
|
||||
"""
|
||||
|
||||
def __init__(self, action = None,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
src_suffix = '',
|
||||
target_factory = None,
|
||||
source_factory = None,
|
||||
target_scanner = None,
|
||||
source_scanner = None,
|
||||
emitter = None,
|
||||
multi = False,
|
||||
env = None,
|
||||
single_source = False,
|
||||
name = None,
|
||||
chdir = _null,
|
||||
is_explicit = True,
|
||||
src_builder = None,
|
||||
ensure_suffix = False,
|
||||
**overrides):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.BuilderBase')
|
||||
self._memo = {}
|
||||
self.action = action
|
||||
self.multi = multi
|
||||
if SCons.Util.is_Dict(prefix):
|
||||
prefix = CallableSelector(prefix)
|
||||
self.prefix = prefix
|
||||
if SCons.Util.is_Dict(suffix):
|
||||
suffix = CallableSelector(suffix)
|
||||
self.env = env
|
||||
self.single_source = single_source
|
||||
if 'overrides' in overrides:
|
||||
msg = "The \"overrides\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tspecify the items as keyword arguments to the Builder() call instead."
|
||||
raise TypeError(msg)
|
||||
if 'scanner' in overrides:
|
||||
msg = "The \"scanner\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tuse: source_scanner or target_scanner as appropriate."
|
||||
raise TypeError(msg)
|
||||
self.overrides = overrides
|
||||
|
||||
self.set_suffix(suffix)
|
||||
self.set_src_suffix(src_suffix)
|
||||
self.ensure_suffix = ensure_suffix
|
||||
|
||||
self.target_factory = target_factory
|
||||
self.source_factory = source_factory
|
||||
self.target_scanner = target_scanner
|
||||
self.source_scanner = source_scanner
|
||||
|
||||
self.emitter = emitter
|
||||
|
||||
# Optional Builder name should only be used for Builders
|
||||
# that don't get attached to construction environments.
|
||||
if name:
|
||||
self.name = name
|
||||
self.executor_kw = {}
|
||||
if chdir is not _null:
|
||||
self.executor_kw['chdir'] = chdir
|
||||
self.is_explicit = is_explicit
|
||||
|
||||
if src_builder is None:
|
||||
src_builder = []
|
||||
elif not SCons.Util.is_List(src_builder):
|
||||
src_builder = [ src_builder ]
|
||||
self.src_builder = src_builder
|
||||
|
||||
def __bool__(self):
|
||||
raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
|
||||
|
||||
def get_name(self, env):
|
||||
"""Attempts to get the name of the Builder.
|
||||
|
||||
Look at the BUILDERS variable of env, expecting it to be a
|
||||
dictionary containing this Builder, and return the key of the
|
||||
dictionary. If there's no key, then return a directly-configured
|
||||
name (if there is one) or the name of the class (by default)."""
|
||||
|
||||
try:
|
||||
index = list(env['BUILDERS'].values()).index(self)
|
||||
return list(env['BUILDERS'].keys())[index]
|
||||
except (AttributeError, KeyError, TypeError, ValueError):
|
||||
try:
|
||||
return self.name
|
||||
except AttributeError:
|
||||
return str(self.__class__)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
def splitext(self, path, env=None):
|
||||
if not env:
|
||||
env = self.env
|
||||
if env:
|
||||
suffixes = self.src_suffixes(env)
|
||||
else:
|
||||
suffixes = []
|
||||
return match_splitext(path, suffixes)
|
||||
|
||||
def _adjustixes(self, files, pre, suf, ensure_suffix=False):
|
||||
if not files:
|
||||
return []
|
||||
result = []
|
||||
if not SCons.Util.is_List(files):
|
||||
files = [files]
|
||||
|
||||
for f in files:
|
||||
# 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
|
||||
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
|
||||
|
||||
def _create_nodes(self, env, target = None, source = None):
|
||||
"""Create and return lists of target and source nodes.
|
||||
"""
|
||||
src_suf = self.get_src_suffix(env)
|
||||
|
||||
target_factory = env.get_factory(self.target_factory)
|
||||
source_factory = env.get_factory(self.source_factory)
|
||||
|
||||
source = self._adjustixes(source, None, src_suf)
|
||||
slist = env.arg2nodes(source, source_factory)
|
||||
|
||||
pre = self.get_prefix(env, slist)
|
||||
suf = self.get_suffix(env, slist)
|
||||
|
||||
if target is None:
|
||||
try:
|
||||
t_from_s = slist[0].target_from_source
|
||||
except AttributeError:
|
||||
raise UserError("Do not know how to create a target from source `%s'" % slist[0])
|
||||
except IndexError:
|
||||
tlist = []
|
||||
else:
|
||||
splitext = lambda S: self.splitext(S,env)
|
||||
tlist = [ t_from_s(pre, suf, splitext) ]
|
||||
else:
|
||||
# orig_target = target
|
||||
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
|
||||
tlist = env.arg2nodes(target, target_factory, target=target, source=source)
|
||||
|
||||
if self.emitter:
|
||||
# The emitter is going to do str(node), but because we're
|
||||
# being called *from* a builder invocation, the new targets
|
||||
# don't yet have a builder set on them and will look like
|
||||
# source files. Fool the emitter's str() calls by setting
|
||||
# up a temporary builder on the new targets.
|
||||
new_targets = []
|
||||
for t in tlist:
|
||||
if not t.is_derived():
|
||||
t.builder_set(self)
|
||||
new_targets.append(t)
|
||||
|
||||
orig_tlist = tlist[:]
|
||||
orig_slist = slist[:]
|
||||
|
||||
target, source = self.emitter(target=tlist, source=slist, env=env)
|
||||
|
||||
# Now delete the temporary builders that we attached to any
|
||||
# new targets, so that _node_errors() doesn't do weird stuff
|
||||
# to them because it thinks they already have builders.
|
||||
for t in new_targets:
|
||||
if t.builder is self:
|
||||
# Only delete the temporary builder if the emitter
|
||||
# didn't change it on us.
|
||||
t.builder_set(None)
|
||||
|
||||
# Have to call arg2nodes yet again, since it is legal for
|
||||
# emitters to spit out strings as well as Node instances.
|
||||
tlist = env.arg2nodes(target, target_factory,
|
||||
target=orig_tlist, source=orig_slist)
|
||||
slist = env.arg2nodes(source, source_factory,
|
||||
target=orig_tlist, source=orig_slist)
|
||||
|
||||
return tlist, slist
|
||||
|
||||
def _execute(self, env, target, source, overwarn={}, executor_kw={}):
|
||||
# We now assume that target and source are lists or None.
|
||||
if self.src_builder:
|
||||
source = self.src_builder_sources(env, source, overwarn)
|
||||
|
||||
if self.single_source and len(source) > 1 and target is None:
|
||||
result = []
|
||||
if target is None: target = [None]*len(source)
|
||||
for tgt, src in zip(target, source):
|
||||
if tgt is not None:
|
||||
tgt = [tgt]
|
||||
if src is not None:
|
||||
src = [src]
|
||||
result.extend(self._execute(env, tgt, src, overwarn))
|
||||
return SCons.Node.NodeList(result)
|
||||
|
||||
overwarn.warn()
|
||||
|
||||
tlist, slist = self._create_nodes(env, target, source)
|
||||
|
||||
# If there is more than one target ensure that if we need to reset
|
||||
# the implicit list to new scan of dependency all targets implicit lists
|
||||
# are cleared. (SCons GH Issue #2811 and MongoDB SERVER-33111)
|
||||
if len(tlist) > 1:
|
||||
for t in tlist:
|
||||
t.target_peers = tlist
|
||||
|
||||
# Check for errors with the specified target/source lists.
|
||||
_node_errors(self, env, tlist, slist)
|
||||
|
||||
# The targets are fine, so find or make the appropriate Executor to
|
||||
# build this particular list of targets from this particular list of
|
||||
# sources.
|
||||
|
||||
executor: Executor | None = None
|
||||
key = None
|
||||
|
||||
if self.multi:
|
||||
try:
|
||||
executor = tlist[0].get_executor(create = 0)
|
||||
except (AttributeError, IndexError):
|
||||
pass
|
||||
else:
|
||||
executor.add_sources(slist)
|
||||
|
||||
if executor is None:
|
||||
if not self.action:
|
||||
fmt = "Builder %s must have an action to build %s."
|
||||
raise UserError(fmt % (self.get_name(env or self.env),
|
||||
list(map(str,tlist))))
|
||||
key = self.action.batch_key(env or self.env, tlist, slist)
|
||||
if key:
|
||||
try:
|
||||
executor = SCons.Executor.GetBatchExecutor(key)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
executor.add_batch(tlist, slist)
|
||||
|
||||
if executor is None:
|
||||
executor = SCons.Executor.Executor(self.action, env, [],
|
||||
tlist, slist, executor_kw)
|
||||
if key:
|
||||
SCons.Executor.AddBatchExecutor(key, executor)
|
||||
|
||||
# Now set up the relevant information in the target Nodes themselves.
|
||||
for t in tlist:
|
||||
t.cwd = env.fs.getcwd()
|
||||
t.builder_set(self)
|
||||
t.env_set(env)
|
||||
t.add_source(slist)
|
||||
t.set_executor(executor)
|
||||
t.set_explicit(self.is_explicit)
|
||||
|
||||
if env.get("SCONF_NODE"):
|
||||
for node in tlist:
|
||||
node.attributes.conftest_node = 1
|
||||
|
||||
return SCons.Node.NodeList(tlist)
|
||||
|
||||
def __call__(self, env, target=None, source=None, chdir=_null, **kw):
|
||||
# We now assume that target and source are lists or None.
|
||||
# The caller (typically Environment.BuilderWrapper) is
|
||||
# responsible for converting any scalar values to lists.
|
||||
if chdir is _null:
|
||||
ekw = self.executor_kw
|
||||
else:
|
||||
ekw = self.executor_kw.copy()
|
||||
ekw['chdir'] = chdir
|
||||
if 'chdir' in ekw and SCons.Util.is_String(ekw['chdir']):
|
||||
ekw['chdir'] = env.subst(ekw['chdir'])
|
||||
if kw:
|
||||
if 'srcdir' in kw:
|
||||
def prependDirIfRelative(f, srcdir=kw['srcdir']):
|
||||
import os.path
|
||||
if SCons.Util.is_String(f) and not os.path.isabs(f):
|
||||
f = os.path.join(srcdir, f)
|
||||
return f
|
||||
if not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
source = list(map(prependDirIfRelative, source))
|
||||
del kw['srcdir']
|
||||
if self.overrides:
|
||||
env_kw = self.overrides.copy()
|
||||
env_kw.update(kw)
|
||||
else:
|
||||
env_kw = kw
|
||||
else:
|
||||
env_kw = self.overrides
|
||||
|
||||
# TODO if env_kw: then the following line. there's no purpose in calling if no overrides.
|
||||
env = env.Override(env_kw)
|
||||
return self._execute(env, target, source, OverrideWarner(kw), ekw)
|
||||
|
||||
def adjust_suffix(self, suff):
|
||||
if suff and not suff[0] in [ '.', '_', '$' ]:
|
||||
return '.' + suff
|
||||
return suff
|
||||
|
||||
def get_prefix(self, env, sources=[]):
|
||||
prefix = self.prefix
|
||||
if callable(prefix):
|
||||
prefix = prefix(env, sources)
|
||||
return env.subst(prefix)
|
||||
|
||||
def set_suffix(self, suffix):
|
||||
if not callable(suffix):
|
||||
suffix = self.adjust_suffix(suffix)
|
||||
self.suffix = suffix
|
||||
|
||||
def get_suffix(self, env, sources=[]):
|
||||
suffix = self.suffix
|
||||
if callable(suffix):
|
||||
suffix = suffix(env, sources)
|
||||
return env.subst(suffix)
|
||||
|
||||
def set_src_suffix(self, src_suffix):
|
||||
if not src_suffix:
|
||||
src_suffix = []
|
||||
elif not SCons.Util.is_List(src_suffix):
|
||||
src_suffix = [ 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."""
|
||||
ret = self.src_suffixes(env)
|
||||
if not ret:
|
||||
return ''
|
||||
return ret[0]
|
||||
|
||||
def add_emitter(self, suffix, emitter):
|
||||
"""Add a suffix-emitter mapping to this Builder.
|
||||
|
||||
This assumes that emitter has been initialized with an
|
||||
appropriate dictionary type, and will throw a TypeError if
|
||||
not, so the caller is responsible for knowing that this is an
|
||||
appropriate method to call for the Builder in question.
|
||||
"""
|
||||
self.emitter[suffix] = emitter
|
||||
|
||||
def add_src_builder(self, builder):
|
||||
"""
|
||||
Add a new Builder to the list of src_builders.
|
||||
|
||||
This requires wiping out cached values so that the computed
|
||||
lists of source suffixes get re-calculated.
|
||||
"""
|
||||
self._memo = {}
|
||||
self.src_builder.append(builder)
|
||||
|
||||
def _get_sdict(self, env):
|
||||
"""
|
||||
Returns a dictionary mapping all of the source suffixes of all
|
||||
src_builders of this Builder to the underlying Builder that
|
||||
should be called first.
|
||||
|
||||
This dictionary is used for each target specified, so we save a
|
||||
lot of extra computation by memoizing it for each construction
|
||||
environment.
|
||||
|
||||
Note that this is re-computed each time, not cached, because there
|
||||
might be changes to one of our source Builders (or one of their
|
||||
source Builders, and so on, and so on...) that we can't "see."
|
||||
|
||||
The underlying methods we call cache their computed values,
|
||||
though, so we hope repeatedly aggregating them into a dictionary
|
||||
like this won't be too big a hit. We may need to look for a
|
||||
better way to do this if performance data show this has turned
|
||||
into a significant bottleneck.
|
||||
"""
|
||||
sdict = {}
|
||||
for bld in self.get_src_builders(env):
|
||||
for suf in bld.src_suffixes(env):
|
||||
sdict[suf] = bld
|
||||
return sdict
|
||||
|
||||
def src_builder_sources(self, env, source, overwarn={}):
|
||||
sdict = self._get_sdict(env)
|
||||
|
||||
src_suffixes = self.src_suffixes(env)
|
||||
|
||||
lengths = list(set(map(len, src_suffixes)))
|
||||
|
||||
def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths):
|
||||
node_suffixes = [name[-l:] for l in lengths]
|
||||
for suf in src_suffixes:
|
||||
if suf in node_suffixes:
|
||||
return suf
|
||||
return None
|
||||
|
||||
result = []
|
||||
for s in SCons.Util.flatten(source):
|
||||
if SCons.Util.is_String(s):
|
||||
match_suffix = match_src_suffix(env.subst(s))
|
||||
if not match_suffix and '.' not in s:
|
||||
src_suf = self.get_src_suffix(env)
|
||||
s = self._adjustixes(s, None, src_suf)[0]
|
||||
else:
|
||||
match_suffix = match_src_suffix(s.name)
|
||||
if match_suffix:
|
||||
try:
|
||||
bld = sdict[match_suffix]
|
||||
except KeyError:
|
||||
result.append(s)
|
||||
else:
|
||||
tlist = bld._execute(env, None, [s], overwarn)
|
||||
# If the subsidiary Builder returned more than one
|
||||
# target, then filter out any sources that this
|
||||
# Builder isn't capable of building.
|
||||
if len(tlist) > 1:
|
||||
tlist = [t for t in tlist if match_src_suffix(t.name)]
|
||||
result.extend(tlist)
|
||||
else:
|
||||
result.append(s)
|
||||
|
||||
source_factory = env.get_factory(self.source_factory)
|
||||
|
||||
return env.arg2nodes(result, source_factory)
|
||||
|
||||
def _get_src_builders_key(self, env):
|
||||
return id(env)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_get_src_builders_key)
|
||||
def get_src_builders(self, env):
|
||||
"""
|
||||
Returns the list of source Builders for this Builder.
|
||||
|
||||
This exists mainly to look up Builders referenced as
|
||||
strings in the 'BUILDER' variable of the construction
|
||||
environment and cache the result.
|
||||
"""
|
||||
memo_key = id(env)
|
||||
try:
|
||||
memo_dict = self._memo['get_src_builders']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['get_src_builders'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[memo_key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
builders = []
|
||||
for bld in self.src_builder:
|
||||
if SCons.Util.is_String(bld):
|
||||
try:
|
||||
bld = env['BUILDERS'][bld]
|
||||
except KeyError:
|
||||
continue
|
||||
builders.append(bld)
|
||||
|
||||
memo_dict[memo_key] = builders
|
||||
return builders
|
||||
|
||||
def _subst_src_suffixes_key(self, env):
|
||||
return id(env)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_subst_src_suffixes_key)
|
||||
def subst_src_suffixes(self, env):
|
||||
"""
|
||||
The suffix list may contain construction variable expansions,
|
||||
so we have to evaluate the individual strings. To avoid doing
|
||||
this over and over, we memoize the results for each construction
|
||||
environment.
|
||||
"""
|
||||
memo_key = id(env)
|
||||
try:
|
||||
memo_dict = self._memo['subst_src_suffixes']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['subst_src_suffixes'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[memo_key]
|
||||
except KeyError:
|
||||
pass
|
||||
suffixes = [env.subst(x) for x in self.src_suffix]
|
||||
memo_dict[memo_key] = suffixes
|
||||
return suffixes
|
||||
|
||||
def src_suffixes(self, env):
|
||||
"""
|
||||
Returns the list of source suffixes for all src_builders of this
|
||||
Builder.
|
||||
|
||||
This is essentially a recursive descent of the src_builder "tree."
|
||||
(This value isn't cached because there may be changes in a
|
||||
src_builder many levels deep that we can't see.)
|
||||
"""
|
||||
sdict = {}
|
||||
suffixes = self.subst_src_suffixes(env)
|
||||
for s in suffixes:
|
||||
sdict[s] = 1
|
||||
for builder in self.get_src_builders(env):
|
||||
for s in builder.src_suffixes(env):
|
||||
if s not in sdict:
|
||||
sdict[s] = 1
|
||||
suffixes.append(s)
|
||||
return suffixes
|
||||
|
||||
class CompositeBuilder(SCons.Util.Proxy):
|
||||
"""A Builder Proxy whose main purpose is to always have
|
||||
a DictCmdGenerator as its action, and to provide access
|
||||
to the DictCmdGenerator's add_action() method.
|
||||
"""
|
||||
|
||||
def __init__(self, builder, cmdgen):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.CompositeBuilder')
|
||||
super().__init__(builder)
|
||||
|
||||
# cmdgen should always be an instance of DictCmdGenerator.
|
||||
self.cmdgen = cmdgen
|
||||
self.builder = builder
|
||||
|
||||
__call__ = SCons.Util.Delegate('__call__')
|
||||
|
||||
def add_action(self, suffix, action):
|
||||
self.cmdgen.add_action(suffix, action)
|
||||
self.set_src_suffix(self.cmdgen.src_suffixes())
|
||||
|
||||
def is_a_Builder(obj):
|
||||
""""Returns True if the specified obj is one of our Builder classes.
|
||||
|
||||
The test is complicated a bit by the fact that CompositeBuilder
|
||||
is a proxy, not a subclass of BuilderBase.
|
||||
"""
|
||||
return (isinstance(obj, BuilderBase)
|
||||
or isinstance(obj, CompositeBuilder)
|
||||
or callable(obj))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
404
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/CacheDir.py
Normal file
404
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/CacheDir.py
Normal file
@@ -0,0 +1,404 @@
|
||||
# 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.
|
||||
|
||||
"""CacheDir support
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Errors
|
||||
import SCons.Warnings
|
||||
import SCons.Util
|
||||
|
||||
CACHE_PREFIX_LEN = 2 # first two characters used as subdirectory name
|
||||
CACHE_TAG = (
|
||||
b"Signature: 8a477f597d28d172789f06886806bc55\n"
|
||||
b"# SCons cache directory - see https://bford.info/cachedir/\n"
|
||||
)
|
||||
|
||||
cache_enabled = True
|
||||
cache_debug = False
|
||||
cache_force = False
|
||||
cache_show = False
|
||||
cache_readonly = False
|
||||
cache_tmp_uuid = uuid.uuid4().hex
|
||||
|
||||
def CacheRetrieveFunc(target, source, env):
|
||||
t = target[0]
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cd.requests += 1
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if not fs.exists(cachefile):
|
||||
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
|
||||
return 1
|
||||
cd.hits += 1
|
||||
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
|
||||
if SCons.Action.execute_actions:
|
||||
if fs.islink(cachefile):
|
||||
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
|
||||
else:
|
||||
cd.copy_from_cache(env, cachefile, t.get_internal_path())
|
||||
try:
|
||||
os.utime(cachefile, None)
|
||||
except OSError:
|
||||
pass
|
||||
st = fs.stat(cachefile)
|
||||
fs.chmod(t.get_internal_path(), stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
|
||||
return 0
|
||||
|
||||
def CacheRetrieveString(target, source, env):
|
||||
t = target[0]
|
||||
cd = env.get_CacheDir()
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if t.fs.exists(cachefile):
|
||||
return "Retrieved `%s' from cache" % t.get_internal_path()
|
||||
return ""
|
||||
|
||||
CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString)
|
||||
|
||||
CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None)
|
||||
|
||||
def CachePushFunc(target, source, env):
|
||||
if cache_readonly:
|
||||
return
|
||||
|
||||
t = target[0]
|
||||
if t.nocache:
|
||||
return
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if fs.exists(cachefile):
|
||||
# Don't bother copying it if it's already there. Note that
|
||||
# usually this "shouldn't happen" because if the file already
|
||||
# existed in cache, we'd have retrieved the file from there,
|
||||
# not built it. This can happen, though, in a race, if some
|
||||
# other person running the same build pushes their copy to
|
||||
# the cache after we decide we need to build it but before our
|
||||
# build completes.
|
||||
cd.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile)
|
||||
return
|
||||
|
||||
cd.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile)
|
||||
|
||||
tempfile = "%s.tmp%s"%(cachefile,cache_tmp_uuid)
|
||||
errfmt = "Unable to copy %s to cache. Cache file is %s"
|
||||
|
||||
try:
|
||||
fs.makedirs(cachedir, exist_ok=True)
|
||||
except OSError:
|
||||
msg = errfmt % (str(target), cachefile)
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
try:
|
||||
if fs.islink(t.get_internal_path()):
|
||||
fs.symlink(fs.readlink(t.get_internal_path()), tempfile)
|
||||
else:
|
||||
cd.copy_to_cache(env, t.get_internal_path(), tempfile)
|
||||
fs.rename(tempfile, cachefile)
|
||||
|
||||
except OSError:
|
||||
# It's possible someone else tried writing the file at the
|
||||
# same time we did, or else that there was some problem like
|
||||
# the CacheDir being on a separate file system that's full.
|
||||
# In any case, inability to push a file to cache doesn't affect
|
||||
# the correctness of the build, so just print a warning.
|
||||
msg = errfmt % (str(t), cachefile)
|
||||
cd.CacheDebug(errfmt + '\n', str(t), cachefile)
|
||||
SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg)
|
||||
|
||||
CachePush = SCons.Action.Action(CachePushFunc, None)
|
||||
|
||||
|
||||
class CacheDir:
|
||||
|
||||
def __init__(self, path):
|
||||
"""Initialize a CacheDir object.
|
||||
|
||||
The cache configuration is stored in the object. It
|
||||
is read from the config file in the supplied path if
|
||||
one exists, if not the config file is created and
|
||||
the default config is written, as well as saved in the object.
|
||||
"""
|
||||
self.requests = 0
|
||||
self.hits = 0
|
||||
self.path = path
|
||||
self.current_cache_debug = None
|
||||
self.debugFP = None
|
||||
self.config = {}
|
||||
if path is not None:
|
||||
self._readconfig(path)
|
||||
|
||||
def _add_config(self, path):
|
||||
"""Create the cache config file in *path*.
|
||||
|
||||
Locking isn't necessary in the normal case - when the cachedir is
|
||||
being created - because it's written to a unique directory first,
|
||||
before the directory is renamed. But it is legal to call CacheDir
|
||||
with an existing directory, which may be missing the config file,
|
||||
and in that case we do need locking. Simpler to always lock.
|
||||
"""
|
||||
config_file = os.path.join(path, 'config')
|
||||
# TODO: this breaks the "unserializable config object" test which
|
||||
# does some crazy stuff, so for now don't use setdefault. It does
|
||||
# seem like it would be better to preserve an exisiting value.
|
||||
# self.config.setdefault('prefix_len', CACHE_PREFIX_LEN)
|
||||
self.config['prefix_len'] = CACHE_PREFIX_LEN
|
||||
with SCons.Util.FileLock(config_file, timeout=5, writer=True), open(
|
||||
config_file, "x"
|
||||
) as config:
|
||||
try:
|
||||
json.dump(self.config, config)
|
||||
except Exception:
|
||||
msg = "Failed to write cache configuration for " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
# Add the tag file "carelessly" - the contents are not used by SCons
|
||||
# so we don't care about the chance of concurrent writes.
|
||||
try:
|
||||
tagfile = os.path.join(path, "CACHEDIR.TAG")
|
||||
with open(tagfile, 'xb') as cachedir_tag:
|
||||
cachedir_tag.write(CACHE_TAG)
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
def _mkdir_atomic(self, path):
|
||||
"""Create cache directory at *path*.
|
||||
|
||||
Uses directory renaming to avoid races. If we are actually
|
||||
creating the dir, populate it with the metadata files at the
|
||||
same time as that's the safest way. But it's not illegal to point
|
||||
CacheDir at an existing directory that wasn't a cache previously,
|
||||
so we may have to do that elsewhere, too.
|
||||
|
||||
Returns:
|
||||
``True`` if it we created the dir, ``False`` if already existed,
|
||||
|
||||
Raises:
|
||||
SConsEnvironmentError: if we tried and failed to create the cache.
|
||||
"""
|
||||
directory = os.path.abspath(path)
|
||||
if os.path.exists(directory):
|
||||
return False
|
||||
|
||||
try:
|
||||
# TODO: Python 3.7. See comment below.
|
||||
# tempdir = tempfile.TemporaryDirectory(dir=os.path.dirname(directory))
|
||||
tempdir = tempfile.mkdtemp(dir=os.path.dirname(directory))
|
||||
except OSError as e:
|
||||
msg = "Failed to create cache directory " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg) from e
|
||||
|
||||
# TODO: Python 3.7: the context manager raises exception on cleanup
|
||||
# if the temporary was moved successfully (File Not Found).
|
||||
# Fixed in 3.8+. In the replacement below we manually clean up if
|
||||
# the move failed as mkdtemp() does not. TemporaryDirectory's
|
||||
# cleanup is more sophisitcated so prefer when we can use it.
|
||||
# self._add_config(tempdir.name)
|
||||
# with tempdir:
|
||||
# try:
|
||||
# os.replace(tempdir.name, directory)
|
||||
# return True
|
||||
# except OSError as e:
|
||||
# # did someone else get there first?
|
||||
# if os.path.isdir(directory):
|
||||
# return False # context manager cleans up
|
||||
# msg = "Failed to create cache directory " + path
|
||||
# raise SCons.Errors.SConsEnvironmentError(msg) from e
|
||||
|
||||
self._add_config(tempdir)
|
||||
try:
|
||||
os.replace(tempdir, directory)
|
||||
return True
|
||||
except OSError as e:
|
||||
# did someone else get there first? attempt cleanup.
|
||||
if os.path.isdir(directory):
|
||||
try:
|
||||
shutil.rmtree(tempdir)
|
||||
except Exception: # we tried, don't worry about it
|
||||
pass
|
||||
return False
|
||||
msg = "Failed to create cache directory " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg) from e
|
||||
|
||||
def _readconfig(self, path):
|
||||
"""Read the cache config from *path*.
|
||||
|
||||
If directory or config file do not exist, create and populate.
|
||||
"""
|
||||
config_file = os.path.join(path, 'config')
|
||||
created = self._mkdir_atomic(path)
|
||||
if not created and not os.path.isfile(config_file):
|
||||
# Could have been passed an empty directory
|
||||
self._add_config(path)
|
||||
try:
|
||||
with SCons.Util.FileLock(config_file, timeout=5, writer=False), open(
|
||||
config_file
|
||||
) as config:
|
||||
self.config = json.load(config)
|
||||
except (ValueError, json.decoder.JSONDecodeError):
|
||||
msg = "Failed to read cache configuration for " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
def CacheDebug(self, fmt, target, cachefile):
|
||||
if cache_debug != self.current_cache_debug:
|
||||
if cache_debug == '-':
|
||||
self.debugFP = sys.stdout
|
||||
elif cache_debug:
|
||||
def debug_cleanup(debugFP):
|
||||
debugFP.close()
|
||||
|
||||
self.debugFP = open(cache_debug, 'w')
|
||||
atexit.register(debug_cleanup, self.debugFP)
|
||||
else:
|
||||
self.debugFP = None
|
||||
self.current_cache_debug = cache_debug
|
||||
if self.debugFP:
|
||||
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
|
||||
self.debugFP.write("requests: %d, hits: %d, misses: %d, hit rate: %.2f%%\n" %
|
||||
(self.requests, self.hits, self.misses, self.hit_ratio))
|
||||
|
||||
@classmethod
|
||||
def copy_from_cache(cls, env, src, dst):
|
||||
"""Copy a file from cache."""
|
||||
if env.cache_timestamp_newer:
|
||||
return env.fs.copy(src, dst)
|
||||
else:
|
||||
return env.fs.copy2(src, dst)
|
||||
|
||||
@classmethod
|
||||
def copy_to_cache(cls, env, src, dst):
|
||||
"""Copy a file to cache.
|
||||
|
||||
Just use the FS copy2 ("with metadata") method, except do an additional
|
||||
check and if necessary a chmod to ensure the cachefile is writeable,
|
||||
to forestall permission problems if the cache entry is later updated.
|
||||
"""
|
||||
try:
|
||||
result = env.fs.copy2(src, dst)
|
||||
st = stat.S_IMODE(os.stat(result).st_mode)
|
||||
if not st | stat.S_IWRITE:
|
||||
os.chmod(dst, st | stat.S_IWRITE)
|
||||
return result
|
||||
except AttributeError as ex:
|
||||
raise OSError from ex
|
||||
|
||||
@property
|
||||
def hit_ratio(self):
|
||||
return (100.0 * self.hits / self.requests if self.requests > 0 else 100)
|
||||
|
||||
@property
|
||||
def misses(self):
|
||||
return self.requests - self.hits
|
||||
|
||||
def is_enabled(self):
|
||||
return cache_enabled and self.path is not None
|
||||
|
||||
def is_readonly(self):
|
||||
return cache_readonly
|
||||
|
||||
def get_cachedir_csig(self, node):
|
||||
cachedir, cachefile = self.cachepath(node)
|
||||
if cachefile and os.path.exists(cachefile):
|
||||
return SCons.Util.hash_file_signature(cachefile, SCons.Node.FS.File.hash_chunksize)
|
||||
|
||||
def cachepath(self, node):
|
||||
"""Return where to cache a file.
|
||||
|
||||
Given a Node, obtain the configured cache directory and
|
||||
the path to the cached file, which is generated from the
|
||||
node's build signature. If caching is not enabled for the
|
||||
None, return a tuple of None.
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return None, None
|
||||
|
||||
sig = node.get_cachedir_bsig()
|
||||
subdir = sig[:self.config['prefix_len']].upper()
|
||||
cachedir = os.path.join(self.path, subdir)
|
||||
return cachedir, os.path.join(cachedir, sig)
|
||||
|
||||
def retrieve(self, node):
|
||||
"""Retrieve a node from cache.
|
||||
|
||||
Returns True if a successful retrieval resulted.
|
||||
|
||||
This method is called from multiple threads in a parallel build,
|
||||
so only do thread safe stuff here. Do thread unsafe stuff in
|
||||
built().
|
||||
|
||||
Note that there's a special trick here with the execute flag
|
||||
(one that's not normally done for other actions). Basically
|
||||
if the user requested a no_exec (-n) build, then
|
||||
SCons.Action.execute_actions is set to 0 and when any action
|
||||
is called, it does its showing but then just returns zero
|
||||
instead of actually calling the action execution operation.
|
||||
The problem for caching is that if the file does NOT exist in
|
||||
cache then the CacheRetrieveString won't return anything to
|
||||
show for the task, but the Action.__call__ won't call
|
||||
CacheRetrieveFunc; instead it just returns zero, which makes
|
||||
the code below think that the file *was* successfully
|
||||
retrieved from the cache, therefore it doesn't do any
|
||||
subsequent building. However, the CacheRetrieveString didn't
|
||||
print anything because it didn't actually exist in the cache,
|
||||
and no more build actions will be performed, so the user just
|
||||
sees nothing. The fix is to tell Action.__call__ to always
|
||||
execute the CacheRetrieveFunc and then have the latter
|
||||
explicitly check SCons.Action.execute_actions itself.
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return False
|
||||
|
||||
env = node.get_build_env()
|
||||
if cache_show:
|
||||
if CacheRetrieveSilent(node, [], env, execute=1) == 0:
|
||||
node.build(presub=0, execute=0)
|
||||
return True
|
||||
else:
|
||||
if CacheRetrieve(node, [], env, execute=1) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def push(self, node):
|
||||
if self.is_readonly() or not self.is_enabled():
|
||||
return
|
||||
return CachePush(node, [], node.get_build_env())
|
||||
|
||||
def push_if_forced(self, node):
|
||||
if cache_force:
|
||||
return self.push(node)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
870
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Conftest.py
Normal file
870
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Conftest.py
Normal file
@@ -0,0 +1,870 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright The SCons Foundation
|
||||
# Copyright (c) 2003 Stichting NLnet Labs
|
||||
# Copyright (c) 2001, 2002, 2003 Steven Knight
|
||||
#
|
||||
# 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.
|
||||
|
||||
r"""Autoconf-like configuration support
|
||||
|
||||
The purpose of this module is to define how a check is to be performed.
|
||||
|
||||
A context class is used that defines functions for carrying out the tests,
|
||||
logging and messages. The following methods and members must be present:
|
||||
|
||||
context.Display(msg)
|
||||
Function called to print messages that are normally displayed
|
||||
for the user. Newlines are explicitly used. The text should
|
||||
also be written to the logfile!
|
||||
|
||||
context.Log(msg)
|
||||
Function called to write to a log file.
|
||||
|
||||
context.BuildProg(text, ext)
|
||||
Function called to build a program, using "ext" for the file
|
||||
extension. Must return an empty string for success, an error
|
||||
message for failure. For reliable test results building should
|
||||
be done just like an actual program would be build, using the
|
||||
same command and arguments (including configure results so far).
|
||||
|
||||
context.CompileProg(text, ext)
|
||||
Function called to compile a program, using "ext" for the file
|
||||
extension. Must return an empty string for success, an error
|
||||
message for failure. For reliable test results compiling should be
|
||||
done just like an actual source file would be compiled, using the
|
||||
same command and arguments (including configure results so far).
|
||||
|
||||
context.AppendLIBS(lib_name_list)
|
||||
Append "lib_name_list" to the value of LIBS. "lib_namelist" is
|
||||
a list of strings. Return the value of LIBS before changing it
|
||||
(any type can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.PrependLIBS(lib_name_list)
|
||||
Prepend "lib_name_list" to the value of LIBS. "lib_namelist" is
|
||||
a list of strings. Return the value of LIBS before changing it
|
||||
(any type can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.SetLIBS(value)
|
||||
Set LIBS to "value". The type of "value" is what AppendLIBS()
|
||||
returned. Return the value of LIBS before changing it (any type
|
||||
can be used, it is passed to SetLIBS() later.)
|
||||
|
||||
context.headerfilename
|
||||
Name of file to append configure results to, usually "confdefs.h".
|
||||
The file must not exist or be empty when starting. Empty or None
|
||||
to skip this (some tests will not work!).
|
||||
|
||||
context.config_h (may be missing).
|
||||
If present, must be a string, which will be filled with the
|
||||
contents of a config_h file.
|
||||
|
||||
context.vardict
|
||||
Dictionary holding variables used for the tests and stores results
|
||||
from the tests, used for the build commands. Normally contains
|
||||
"CC", "LIBS", "CPPFLAGS", etc.
|
||||
|
||||
context.havedict
|
||||
Dictionary holding results from the tests that are to be used
|
||||
inside a program. Names often start with "HAVE\_". These are zero
|
||||
(feature not present) or one (feature present). Other variables
|
||||
may have any value, e.g., "PERLVERSION" can be a number and
|
||||
"SYSTEMNAME" a string.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
#
|
||||
# PUBLIC VARIABLES
|
||||
#
|
||||
|
||||
LogInputFiles = 1 # Set that to log the input files in case of a failed test
|
||||
LogErrorMessages = 1 # Set that to log Conftest-generated error messages
|
||||
|
||||
#
|
||||
# PUBLIC FUNCTIONS
|
||||
#
|
||||
|
||||
# Generic remarks:
|
||||
# - When a language is specified which is not supported the test fails. The
|
||||
# message is a bit different, because not all the arguments for the normal
|
||||
# message are available yet (chicken-egg problem).
|
||||
|
||||
|
||||
def CheckBuilder(context, text = None, language = None):
|
||||
"""
|
||||
Configure check to see if the compiler works.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
"text" may be used to specify the code to be build.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("%s\n" % msg)
|
||||
return msg
|
||||
|
||||
if not text:
|
||||
text = """
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
context.Display("Checking if building a %s file works... " % lang)
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckCC(context):
|
||||
"""
|
||||
Configure check for a working C compiler.
|
||||
|
||||
This checks whether the C compiler, as defined in the $CC construction
|
||||
variable, can compile a C source file. It uses the current $CCCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the C compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'CC', text, 'C')
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckSHCC(context):
|
||||
"""
|
||||
Configure check for a working shared C compiler.
|
||||
|
||||
This checks whether the C compiler, as defined in the $SHCC construction
|
||||
variable, can compile a C source file. It uses the current $SHCCCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the (shared) C compiler works... ")
|
||||
text = """
|
||||
int foo(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'SHCC', text, 'C', use_shared = True)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckCXX(context):
|
||||
"""
|
||||
Configure check for a working CXX compiler.
|
||||
|
||||
This checks whether the CXX compiler, as defined in the $CXX construction
|
||||
variable, can compile a CXX source file. It uses the current $CXXCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the C++ compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'CXX', text, 'C++')
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckSHCXX(context):
|
||||
"""
|
||||
Configure check for a working shared CXX compiler.
|
||||
|
||||
This checks whether the CXX compiler, as defined in the $SHCXX construction
|
||||
variable, can compile a CXX source file. It uses the current $SHCXXCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the (shared) C++ compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'SHCXX', text, 'C++', use_shared = True)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def _check_empty_program(context, comp, text, language, use_shared = False):
|
||||
"""Return 0 on success, 1 otherwise."""
|
||||
if comp not in context.env or not context.env[comp]:
|
||||
# The compiler construction variable is not set or empty
|
||||
return 1
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
return 1
|
||||
|
||||
if use_shared:
|
||||
return context.CompileSharedObject(text, suffix)
|
||||
else:
|
||||
return context.CompileProg(text, suffix)
|
||||
|
||||
|
||||
def CheckFunc(context, function_name, header = None, language = None, funcargs = None):
|
||||
"""
|
||||
Configure check for a function "function_name".
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Optional "header" can be defined to define a function prototype, include a
|
||||
header file or anything else that comes before main().
|
||||
Optional "funcargs" can be defined to define an argument list for the
|
||||
generated function invocation.
|
||||
Sets HAVE_function_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
|
||||
.. versionchanged:: 4.7.0
|
||||
The ``funcargs`` parameter was added.
|
||||
"""
|
||||
|
||||
# Remarks from autoconf:
|
||||
# - Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
|
||||
# which includes <sys/select.h> which contains a prototype for select.
|
||||
# Similarly for bzero.
|
||||
# - assert.h is included to define __stub macros and hopefully few
|
||||
# prototypes, which can conflict with char $1(); below.
|
||||
# - Override any gcc2 internal prototype to avoid an error.
|
||||
# - We use char for the function declaration because int might match the
|
||||
# return type of a gcc2 builtin and then its argument prototype would
|
||||
# still apply.
|
||||
# - The GNU C library defines this for functions which it implements to
|
||||
# always fail with ENOSYS. Some functions are actually named something
|
||||
# starting with __ and the normal name is an alias.
|
||||
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = """
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char %s(void);""" % function_name
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
|
||||
return msg
|
||||
|
||||
if not funcargs:
|
||||
funcargs = ''
|
||||
|
||||
text = """
|
||||
%(include)s
|
||||
#include <assert.h>
|
||||
%(hdr)s
|
||||
|
||||
#if _MSC_VER && !__INTEL_COMPILER
|
||||
#pragma function(%(name)s)
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
|
||||
#error "%(name)s has a GNU stub, cannot check"
|
||||
#else
|
||||
%(name)s(%(args)s);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
""" % { 'name': function_name,
|
||||
'include': includetext,
|
||||
'hdr': header,
|
||||
'args': funcargs}
|
||||
|
||||
context.Display("Checking for %s function %s()... " % (lang, function_name))
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + function_name, text,
|
||||
"Define to 1 if the system has the function `%s'." %\
|
||||
function_name)
|
||||
return ret
|
||||
|
||||
|
||||
def CheckHeader(context, header_name, header=None, language=None,
|
||||
include_quotes=None):
|
||||
"""
|
||||
Configure check for a C or C++ header file "header_name".
|
||||
Optional "header" can be defined to do something before including the
|
||||
header file (unusual, supported for consistency).
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Sets HAVE_header_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS and $CPPFLAGS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
# Why compile the program instead of just running the preprocessor?
|
||||
# It is possible that the header file exists, but actually using it may
|
||||
# fail (e.g., because it depends on other header files). Thus this test is
|
||||
# more strict. It may require using the "header" argument.
|
||||
#
|
||||
# Use <> by default, because the check is normally used for system header
|
||||
# files. SCons passes '""' to overrule this.
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"\n' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for header file %s: %s\n"
|
||||
% (header_name, msg))
|
||||
return msg
|
||||
|
||||
if not include_quotes:
|
||||
include_quotes = "<>"
|
||||
|
||||
text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
|
||||
include_quotes[0], header_name, include_quotes[1])
|
||||
|
||||
context.Display("Checking for %s header file %s... " % (lang, header_name))
|
||||
ret = context.CompileProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + header_name, text,
|
||||
"Define to 1 if you have the <%s> header file." % header_name)
|
||||
return ret
|
||||
|
||||
|
||||
def CheckType(context, type_name, fallback = None,
|
||||
header = None, language = None):
|
||||
"""
|
||||
Configure check for a C or C++ type "type_name".
|
||||
Optional "header" can be defined to include a header file.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Sets HAVE_type_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
||||
return msg
|
||||
|
||||
# Remarks from autoconf about this test:
|
||||
# - Grepping for the type in include files is not reliable (grep isn't
|
||||
# portable anyway).
|
||||
# - Using "TYPE my_var;" doesn't work for const qualified types in C++.
|
||||
# Adding an initializer is not valid for some C++ classes.
|
||||
# - Using the type as parameter to a function either fails for K&$ C or for
|
||||
# C++.
|
||||
# - Using "TYPE *my_var;" is valid in C for some types that are not
|
||||
# declared (struct something).
|
||||
# - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
|
||||
# - Using the previous two together works reliably.
|
||||
text = """
|
||||
%(include)s
|
||||
%(header)s
|
||||
|
||||
int main(void) {
|
||||
if ((%(name)s *) 0)
|
||||
return 0;
|
||||
if (sizeof (%(name)s))
|
||||
return 0;
|
||||
}
|
||||
""" % { 'include': includetext,
|
||||
'header': header,
|
||||
'name': type_name }
|
||||
|
||||
context.Display("Checking for %s type %s... " % (lang, type_name))
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + type_name, text,
|
||||
"Define to 1 if the system has the type `%s'." % type_name)
|
||||
if ret and fallback and context.headerfilename:
|
||||
f = open(context.headerfilename, "a")
|
||||
f.write("typedef %s %s;\n" % (fallback, type_name))
|
||||
f.close()
|
||||
|
||||
return ret
|
||||
|
||||
def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
|
||||
"""This check can be used to get the size of a given type, or to check whether
|
||||
the type is of expected size.
|
||||
|
||||
Arguments:
|
||||
- type : str
|
||||
the type to check
|
||||
- includes : sequence
|
||||
list of headers to include in the test code before testing the type
|
||||
- language : str
|
||||
'C' or 'C++'
|
||||
- expect : int
|
||||
if given, will test wether the type has the given number of bytes.
|
||||
If not given, will automatically find the size.
|
||||
|
||||
Returns:
|
||||
status : int
|
||||
0 if the check failed, or the found size of the type if the check succeeded."""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
||||
return msg
|
||||
|
||||
src = includetext + header
|
||||
if expect is not None:
|
||||
# Only check if the given size is the right one
|
||||
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
|
||||
|
||||
# test code taken from autoconf: this is a pretty clever hack to find that
|
||||
# a type is of a given size using only compilation. This speeds things up
|
||||
# quite a bit compared to straightforward code using TryRun
|
||||
src = src + r"""
|
||||
typedef %s scons_check_type;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
|
||||
test_array[0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
st = context.CompileProg(src % (type_name, expect), suffix)
|
||||
if not st:
|
||||
context.Display("yes\n")
|
||||
_Have(context, "SIZEOF_%s" % type_name, expect,
|
||||
"The size of `%s', as computed by sizeof." % type_name)
|
||||
return expect
|
||||
else:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, src, st)
|
||||
return 0
|
||||
else:
|
||||
# Only check if the given size is the right one
|
||||
context.Message('Checking size of %s ... ' % type_name)
|
||||
|
||||
# We have to be careful with the program we wish to test here since
|
||||
# compilation will be attempted using the current environment's flags.
|
||||
# So make sure that the program will compile without any warning. For
|
||||
# example using: 'int main(int argc, char** argv)' will fail with the
|
||||
# '-Wall -Werror' flags since the variables argc and argv would not be
|
||||
# used in the program...
|
||||
#
|
||||
src = src + """
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
printf("%d", (int)sizeof(""" + type_name + """));
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
st, out = context.RunProg(src, suffix)
|
||||
try:
|
||||
size = int(out)
|
||||
except ValueError:
|
||||
# If cannot convert output of test prog to an integer (the size),
|
||||
# something went wront, so just fail
|
||||
st = 1
|
||||
size = 0
|
||||
|
||||
if not st:
|
||||
context.Display("yes\n")
|
||||
_Have(context, "SIZEOF_%s" % type_name, size,
|
||||
"The size of `%s', as computed by sizeof." % type_name)
|
||||
return size
|
||||
else:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, src, st)
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
def CheckDeclaration(context, symbol, includes = None, language = None):
|
||||
"""Checks whether symbol is declared.
|
||||
|
||||
Use the same test as autoconf, that is test whether the symbol is defined
|
||||
as a macro or can be used as an r-value.
|
||||
|
||||
Arguments:
|
||||
symbol : str
|
||||
the symbol to check
|
||||
includes : str
|
||||
Optional "header" can be defined to include a header file.
|
||||
language : str
|
||||
only C and C++ supported.
|
||||
|
||||
Returns:
|
||||
status : bool
|
||||
True if the check failed, False if succeeded."""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
|
||||
if not includes:
|
||||
includes = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
|
||||
return msg
|
||||
|
||||
src = includetext + includes
|
||||
context.Display('Checking whether %s is declared... ' % symbol)
|
||||
|
||||
src = src + r"""
|
||||
int main(void)
|
||||
{
|
||||
#ifndef %s
|
||||
(void) %s;
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
""" % (symbol, symbol)
|
||||
|
||||
st = context.CompileProg(src, suffix)
|
||||
_YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
|
||||
"Set to 1 if %s is defined." % symbol)
|
||||
return st
|
||||
|
||||
|
||||
def CheckMember(context, aggregate_member, header = None, language = None):
|
||||
"""
|
||||
Configure check for a C or C++ member "aggregate_member".
|
||||
Optional "header" can be defined to include a header file.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
|
||||
Arguments:
|
||||
aggregate_member : str
|
||||
the member to check. For example, 'struct tm.tm_gmtoff'.
|
||||
includes : str
|
||||
Optional "header" can be defined to include a header file.
|
||||
language : str
|
||||
only C and C++ supported.
|
||||
|
||||
Returns the status (0 or False = Passed, True/non-zero = Failed).
|
||||
"""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for member %s: %s\n" % (aggregate_member, msg))
|
||||
return True
|
||||
context.Display("Checking for %s member %s... " % (lang, aggregate_member))
|
||||
fields = aggregate_member.split('.')
|
||||
if len(fields) != 2:
|
||||
msg = "shall contain just one dot, for example 'struct tm.tm_gmtoff'"
|
||||
context.Display("Cannot check for member %s: %s\n" % (aggregate_member, msg))
|
||||
return True
|
||||
aggregate, member = fields[0], fields[1]
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ''
|
||||
text = '''
|
||||
%(include)s
|
||||
%(header)s
|
||||
|
||||
int main(void) {
|
||||
if (sizeof ((%(aggregate)s *) 0)->%(member)s)
|
||||
return 0;
|
||||
}''' % {'include': includetext,
|
||||
'header': header,
|
||||
'aggregate': aggregate,
|
||||
'member': member}
|
||||
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + aggregate_member, text,
|
||||
"Define to 1 if the system has the member `%s`." % aggregate_member)
|
||||
return ret
|
||||
|
||||
def CheckLib(context, libs, func_name = None, header = None,
|
||||
extra_libs = None, call = None, language = None, autoadd = 1,
|
||||
append=True, unique=False):
|
||||
"""
|
||||
Configure check for a C or C++ libraries "libs". Searches through
|
||||
the list of libraries, until one is found where the test succeeds.
|
||||
Tests if "func_name" or "call" exists in the library. Note: if it exists
|
||||
in another library the test succeeds anyway!
|
||||
Optional "header" can be defined to include a header file. If not given a
|
||||
default prototype for "func_name" is added.
|
||||
Optional "extra_libs" is a list of library names to be added after
|
||||
"lib_name" in the build command. To be used for libraries that "lib_name"
|
||||
depends on.
|
||||
Optional "call" replaces the call to "func_name" in the test code. It must
|
||||
consist of complete C statements, including a trailing ";".
|
||||
Both "func_name" and "call" arguments are optional, and in that case, just
|
||||
linking against the libs is tested.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
text = """
|
||||
%s
|
||||
%s""" % (includetext, header)
|
||||
|
||||
# Add a function declaration if needed.
|
||||
if func_name and func_name != "main":
|
||||
if not header:
|
||||
text = text + """
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char %s();
|
||||
""" % func_name
|
||||
|
||||
# The actual test code.
|
||||
if not call:
|
||||
call = "%s();" % func_name
|
||||
|
||||
# if no function to test, leave main() blank
|
||||
text = text + """
|
||||
int main(void) {
|
||||
%s
|
||||
return 0;
|
||||
}
|
||||
""" % (call or "")
|
||||
|
||||
if call:
|
||||
i = call.find("\n")
|
||||
if i > 0:
|
||||
calltext = call[:i] + ".."
|
||||
elif call[-1] == ';':
|
||||
calltext = call[:-1]
|
||||
else:
|
||||
calltext = call
|
||||
|
||||
for lib_name in libs:
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
|
||||
return msg
|
||||
|
||||
# if a function was specified to run in main(), say it
|
||||
if call:
|
||||
context.Display("Checking for %s in %s library %s... "
|
||||
% (calltext, lang, lib_name))
|
||||
# otherwise, just say the name of library and language
|
||||
else:
|
||||
context.Display("Checking for %s library %s... "
|
||||
% (lang, lib_name))
|
||||
|
||||
if lib_name:
|
||||
l = [ lib_name ]
|
||||
if extra_libs:
|
||||
l.extend(extra_libs)
|
||||
if append:
|
||||
oldLIBS = context.AppendLIBS(l, unique)
|
||||
else:
|
||||
oldLIBS = context.PrependLIBS(l, unique)
|
||||
sym = "HAVE_LIB" + lib_name
|
||||
else:
|
||||
oldLIBS = -1
|
||||
sym = None
|
||||
|
||||
ret = context.BuildProg(text, suffix)
|
||||
|
||||
_YesNoResult(context, ret, sym, text,
|
||||
"Define to 1 if you have the `%s' library." % lib_name)
|
||||
if oldLIBS != -1 and (ret or not autoadd):
|
||||
context.SetLIBS(oldLIBS)
|
||||
|
||||
if not ret:
|
||||
return ret
|
||||
|
||||
return ret
|
||||
|
||||
def CheckProg(context, prog_name):
|
||||
"""
|
||||
Configure check for a specific program.
|
||||
|
||||
Check whether program prog_name exists in path. If it is found,
|
||||
returns the path for it, otherwise returns None.
|
||||
"""
|
||||
context.Display("Checking whether %s program exists..." % prog_name)
|
||||
path = context.env.WhereIs(prog_name)
|
||||
if path:
|
||||
context.Display(path + "\n")
|
||||
else:
|
||||
context.Display("no\n")
|
||||
return path
|
||||
|
||||
|
||||
#
|
||||
# END OF PUBLIC FUNCTIONS
|
||||
#
|
||||
|
||||
def _YesNoResult(context, ret, key, text, comment = None):
|
||||
r"""
|
||||
Handle the result of a test with a "yes" or "no" result.
|
||||
|
||||
:Parameters:
|
||||
- `ret` is the return value: empty if OK, error message when not.
|
||||
- `key` is the name of the symbol to be defined (HAVE_foo).
|
||||
- `text` is the source code of the program used for testing.
|
||||
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
|
||||
"""
|
||||
if key:
|
||||
_Have(context, key, not ret, comment)
|
||||
if ret:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, text, ret)
|
||||
else:
|
||||
context.Display("yes\n")
|
||||
|
||||
|
||||
def _Have(context, key, have, comment = None):
|
||||
r"""
|
||||
Store result of a test in context.havedict and context.headerfilename.
|
||||
|
||||
:Parameters:
|
||||
- `key` - is a "HAVE_abc" name. It is turned into all CAPITALS and non-alphanumerics are replaced by an underscore.
|
||||
- `have` - value as it should appear in the header file, include quotes when desired and escape special characters!
|
||||
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
|
||||
|
||||
|
||||
The value of "have" can be:
|
||||
- 1 - Feature is defined, add "#define key".
|
||||
- 0 - Feature is not defined, add "/\* #undef key \*/". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done.
|
||||
- number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then.
|
||||
- string - Feature is defined to this string "#define key have".
|
||||
|
||||
|
||||
"""
|
||||
key_up = key.upper()
|
||||
key_up = re.sub('[^A-Z0-9_]', '_', key_up)
|
||||
context.havedict[key_up] = have
|
||||
if have == 1:
|
||||
line = "#define %s 1\n" % key_up
|
||||
elif have == 0:
|
||||
line = "/* #undef %s */\n" % key_up
|
||||
elif isinstance(have, int):
|
||||
line = "#define %s %d\n" % (key_up, have)
|
||||
else:
|
||||
line = "#define %s %s\n" % (key_up, str(have))
|
||||
|
||||
if comment is not None:
|
||||
lines = "\n/* %s */\n" % comment + line
|
||||
else:
|
||||
lines = "\n" + line
|
||||
|
||||
if context.headerfilename:
|
||||
f = open(context.headerfilename, "a")
|
||||
f.write(lines)
|
||||
f.close()
|
||||
elif hasattr(context,'config_h'):
|
||||
context.config_h = context.config_h + lines
|
||||
|
||||
|
||||
def _LogFailed(context, text, msg):
|
||||
"""
|
||||
Write to the log about a failed program.
|
||||
Add line numbers, so that error messages can be understood.
|
||||
"""
|
||||
if LogInputFiles:
|
||||
context.Log("Failed program was:\n")
|
||||
lines = text.split('\n')
|
||||
if len(lines) and lines[-1] == '':
|
||||
lines = lines[:-1] # remove trailing empty line
|
||||
n = 1
|
||||
for line in lines:
|
||||
context.Log("%d: %s\n" % (n, line))
|
||||
n = n + 1
|
||||
if LogErrorMessages:
|
||||
context.Log("Error message: %s\n" % msg)
|
||||
|
||||
|
||||
def _lang2suffix(lang):
|
||||
"""
|
||||
Convert a language name to a suffix.
|
||||
When "lang" is empty or None C is assumed.
|
||||
Returns a tuple (lang, suffix, None) when it works.
|
||||
For an unrecognized language returns (None, None, msg).
|
||||
|
||||
Where:
|
||||
- lang = the unified language name
|
||||
- suffix = the suffix, including the leading dot
|
||||
- msg = an error message
|
||||
"""
|
||||
if not lang or lang in ["C", "c"]:
|
||||
return ("C", ".c", None)
|
||||
if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
|
||||
return ("C++", ".cpp", None)
|
||||
|
||||
return None, None, "Unsupported language: %s" % lang
|
||||
|
||||
|
||||
# vim: set sw=4 et sts=4 tw=79 fo+=l:
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
254
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Debug.py
Normal file
254
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Debug.py
Normal file
@@ -0,0 +1,254 @@
|
||||
# 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.
|
||||
|
||||
"""Code for debugging SCons internal things.
|
||||
|
||||
Shouldn't be needed by most users. Quick shortcuts::
|
||||
|
||||
from SCons.Debug import caller_trace
|
||||
caller_trace()
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import weakref
|
||||
import inspect
|
||||
|
||||
# Global variable that gets set to 'True' by the Main script,
|
||||
# when the creation of class instances should get tracked.
|
||||
track_instances = False
|
||||
# List of currently tracked classes
|
||||
tracked_classes = {}
|
||||
# Global variable that gets set to 'True' by the Main script
|
||||
# when SConscript call tracing should be enabled.
|
||||
sconscript_trace = False
|
||||
|
||||
def logInstanceCreation(instance, name=None):
|
||||
if name is None:
|
||||
name = instance.__class__.__name__
|
||||
if name not in tracked_classes:
|
||||
tracked_classes[name] = []
|
||||
if hasattr(instance, '__dict__'):
|
||||
tracked_classes[name].append(weakref.ref(instance))
|
||||
else:
|
||||
# weakref doesn't seem to work when the instance
|
||||
# contains only slots...
|
||||
tracked_classes[name].append(instance)
|
||||
|
||||
def string_to_classes(s):
|
||||
if s == '*':
|
||||
return sorted(tracked_classes.keys())
|
||||
else:
|
||||
return s.split()
|
||||
|
||||
def fetchLoggedInstances(classes="*"):
|
||||
classnames = string_to_classes(classes)
|
||||
return [(cn, len(tracked_classes[cn])) for cn in classnames]
|
||||
|
||||
def countLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
|
||||
|
||||
def listLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
if inspect.isclass(ref):
|
||||
obj = ref()
|
||||
else:
|
||||
obj = ref
|
||||
if obj is not None:
|
||||
file.write(' %s\n' % repr(obj))
|
||||
|
||||
def dumpLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
file.write(' %s:\n' % obj)
|
||||
for key, value in obj.__dict__.items():
|
||||
file.write(' %20s : %s\n' % (key, value))
|
||||
|
||||
|
||||
if sys.platform[:5] == "linux":
|
||||
# Linux doesn't actually support memory usage stats from getrusage().
|
||||
def memory():
|
||||
with open('/proc/self/stat') as f:
|
||||
mstr = f.read()
|
||||
mstr = mstr.split()[22]
|
||||
return int(mstr)
|
||||
elif sys.platform[:6] == 'darwin':
|
||||
#TODO really get memory stats for OS X
|
||||
def memory():
|
||||
return 0
|
||||
elif sys.platform == 'win32':
|
||||
from SCons.compat.win32 import get_peak_memory_usage
|
||||
memory = get_peak_memory_usage
|
||||
else:
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
def memory():
|
||||
res = resource.getrusage(resource.RUSAGE_SELF)
|
||||
return res[4]
|
||||
|
||||
|
||||
def caller_stack():
|
||||
"""return caller's stack"""
|
||||
import traceback
|
||||
tb = traceback.extract_stack()
|
||||
# strip itself and the caller from the output
|
||||
tb = tb[:-2]
|
||||
result = []
|
||||
for back in tb:
|
||||
# (filename, line number, function name, text)
|
||||
key = back[:3]
|
||||
result.append('%s:%d(%s)' % func_shorten(key))
|
||||
return result
|
||||
|
||||
caller_bases = {}
|
||||
caller_dicts = {}
|
||||
|
||||
def caller_trace(back=0):
|
||||
"""
|
||||
Trace caller stack and save info into global dicts, which
|
||||
are printed automatically at the end of SCons execution.
|
||||
"""
|
||||
global caller_bases, caller_dicts
|
||||
import traceback
|
||||
tb = traceback.extract_stack(limit=3+back)
|
||||
tb.reverse()
|
||||
callee = tb[1][:3]
|
||||
caller_bases[callee] = caller_bases.get(callee, 0) + 1
|
||||
for caller in tb[2:]:
|
||||
caller = callee + caller[:3]
|
||||
try:
|
||||
entry = caller_dicts[callee]
|
||||
except KeyError:
|
||||
caller_dicts[callee] = entry = {}
|
||||
entry[caller] = entry.get(caller, 0) + 1
|
||||
callee = caller
|
||||
|
||||
# print a single caller and its callers, if any
|
||||
def _dump_one_caller(key, file, level=0):
|
||||
leader = ' '*level
|
||||
for v,c in sorted([(-v,c) for c,v in caller_dicts[key].items()]):
|
||||
file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:])))
|
||||
if c in caller_dicts:
|
||||
_dump_one_caller(c, file, level+1)
|
||||
|
||||
# print each call tree
|
||||
def dump_caller_counts(file=sys.stdout):
|
||||
for k in sorted(caller_bases.keys()):
|
||||
file.write("Callers of %s:%d(%s), %d calls:\n"
|
||||
% (func_shorten(k) + (caller_bases[k],)))
|
||||
_dump_one_caller(k, file)
|
||||
|
||||
shorten_list = [
|
||||
( '/scons/SCons/', 1),
|
||||
( '/src/engine/SCons/', 1),
|
||||
( '/usr/lib/python', 0),
|
||||
]
|
||||
|
||||
if os.sep != '/':
|
||||
shorten_list = [(t[0].replace('/', os.sep), t[1]) for t in shorten_list]
|
||||
|
||||
def func_shorten(func_tuple):
|
||||
f = func_tuple[0]
|
||||
for t in shorten_list:
|
||||
i = f.find(t[0])
|
||||
if i >= 0:
|
||||
if t[1]:
|
||||
i = i + len(t[0])
|
||||
return (f[i:],)+func_tuple[1:]
|
||||
return func_tuple
|
||||
|
||||
|
||||
TraceFP = {}
|
||||
if sys.platform == 'win32':
|
||||
TraceDefault = 'con'
|
||||
else:
|
||||
TraceDefault = '/dev/tty'
|
||||
TimeStampDefault = False
|
||||
StartTime = time.perf_counter()
|
||||
PreviousTime = StartTime
|
||||
|
||||
def Trace(msg, tracefile=None, mode='w', tstamp=False):
|
||||
"""Write a trace message.
|
||||
|
||||
Write messages when debugging which do not interfere with stdout.
|
||||
Useful in tests, which monitor stdout and would break with
|
||||
unexpected output. Trace messages can go to the console (which is
|
||||
opened as a file), or to a disk file; the tracefile argument persists
|
||||
across calls unless overridden.
|
||||
|
||||
Args:
|
||||
tracefile: file to write trace message to. If omitted,
|
||||
write to the previous trace file (default: console).
|
||||
mode: file open mode (default: 'w')
|
||||
tstamp: write relative timestamps with trace. Outputs time since
|
||||
scons was started, and time since last trace (default: False)
|
||||
|
||||
"""
|
||||
global TraceDefault
|
||||
global TimeStampDefault
|
||||
global PreviousTime
|
||||
|
||||
def trace_cleanup(traceFP):
|
||||
traceFP.close()
|
||||
|
||||
if tracefile is None:
|
||||
tracefile = TraceDefault
|
||||
else:
|
||||
TraceDefault = tracefile
|
||||
if not tstamp:
|
||||
tstamp = TimeStampDefault
|
||||
else:
|
||||
TimeStampDefault = tstamp
|
||||
try:
|
||||
fp = TraceFP[tracefile]
|
||||
except KeyError:
|
||||
try:
|
||||
fp = TraceFP[tracefile] = open(tracefile, mode)
|
||||
atexit.register(trace_cleanup, fp)
|
||||
except TypeError:
|
||||
# Assume we were passed an open file pointer.
|
||||
fp = tracefile
|
||||
if tstamp:
|
||||
now = time.perf_counter()
|
||||
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
||||
PreviousTime = now
|
||||
fp.write(msg)
|
||||
fp.flush()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
760
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Defaults.py
Normal file
760
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Defaults.py
Normal file
@@ -0,0 +1,760 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""Builders and other things for the local site.
|
||||
|
||||
Here's where we'll duplicate the functionality of autoconf until we
|
||||
move it into the installation procedure or use something like qmconf.
|
||||
|
||||
The code that reads the registry to find MSVC components was borrowed
|
||||
from distutils.msvccompiler.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
from typing import Callable
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.CacheDir
|
||||
import SCons.Environment
|
||||
import SCons.Errors
|
||||
import SCons.PathList
|
||||
import SCons.Scanner.Dir
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
from SCons.Util import is_List, is_String, is_Sequence, is_Tuple, is_Dict, flatten
|
||||
|
||||
# A placeholder for a default Environment (for fetching source files
|
||||
# from source code management systems and the like). This must be
|
||||
# initialized later, after the top-level directory is set by the calling
|
||||
# interface.
|
||||
_default_env = None
|
||||
|
||||
|
||||
# Lazily instantiate the default environment so the overhead of creating
|
||||
# it doesn't apply when it's not needed.
|
||||
def _fetch_DefaultEnvironment(*args, **kwargs):
|
||||
"""Returns the already-created default construction environment."""
|
||||
return _default_env
|
||||
|
||||
|
||||
def DefaultEnvironment(*args, **kwargs):
|
||||
"""Construct the global ("default") construction environment.
|
||||
|
||||
The environment is provisioned with the values from *kwargs*.
|
||||
|
||||
After the environment is created, this function is replaced with
|
||||
a reference to :func:`_fetch_DefaultEnvironment` which efficiently
|
||||
returns the initialized default construction environment without
|
||||
checking for its existence.
|
||||
|
||||
Historically, some parts of the code held references to this function.
|
||||
Thus it still has the existence check for :data:`_default_env` rather
|
||||
than just blindly creating the environment and overwriting itself.
|
||||
"""
|
||||
global _default_env
|
||||
if not _default_env:
|
||||
_default_env = SCons.Environment.Environment(*args, **kwargs)
|
||||
_default_env.Decider('content')
|
||||
global DefaultEnvironment
|
||||
DefaultEnvironment = _fetch_DefaultEnvironment
|
||||
_default_env._CacheDir_path = None
|
||||
return _default_env
|
||||
|
||||
|
||||
# Emitters for setting the shared attribute on object files,
|
||||
# and an action for checking that all of the source files
|
||||
# going into a shared library are, in fact, shared.
|
||||
def StaticObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = False
|
||||
return target, source
|
||||
|
||||
|
||||
def SharedObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return target, source
|
||||
|
||||
|
||||
def SharedFlagChecker(source, target, env):
|
||||
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
||||
if same == '0' or same == '' or same == 'False':
|
||||
for src in source:
|
||||
try:
|
||||
shared = src.attributes.shared
|
||||
except AttributeError:
|
||||
shared = False
|
||||
if not shared:
|
||||
raise SCons.Errors.UserError(
|
||||
"Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
||||
|
||||
|
||||
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
|
||||
|
||||
# Some people were using these variable name before we made
|
||||
# SourceFileScanner part of the public interface. Don't break their
|
||||
# SConscript files until we've given them some fair warning and a
|
||||
# transition period.
|
||||
CScan = SCons.Tool.CScanner
|
||||
# Nuitka: Avoid unused tools
|
||||
# DScan = SCons.Tool.DScanner
|
||||
# LaTeXScan = SCons.Tool.LaTeXScanner
|
||||
# ObjSourceScan = SCons.Tool.SourceFileScanner
|
||||
ProgScan = SCons.Tool.ProgramScanner
|
||||
|
||||
# These aren't really tool scanners, so they don't quite belong with
|
||||
# the rest of those in Tool/__init__.py, but I'm not sure where else
|
||||
# they should go. Leave them here for now.
|
||||
|
||||
DirScanner = SCons.Scanner.Dir.DirScanner()
|
||||
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
||||
|
||||
# Actions for common languages.
|
||||
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
|
||||
ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
|
||||
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
|
||||
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
|
||||
|
||||
DAction = SCons.Action.Action("$DCOM", "$DCOMSTR")
|
||||
ShDAction = SCons.Action.Action("$SHDCOM", "$SHDCOMSTR")
|
||||
|
||||
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
|
||||
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
|
||||
|
||||
LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
|
||||
ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
|
||||
|
||||
LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
||||
|
||||
# Common tasks that we allow users to perform in platform-independent
|
||||
# ways by creating ActionFactory instances.
|
||||
ActionFactory = SCons.Action.ActionFactory
|
||||
|
||||
|
||||
def get_paths_str(dest):
|
||||
"""Generates a string from *dest* for use in a strfunction.
|
||||
|
||||
If *dest* is a list, manually converts each elem to a string.
|
||||
"""
|
||||
def quote(arg):
|
||||
return f'"{arg}"'
|
||||
|
||||
if is_List(dest):
|
||||
elem_strs = [quote(d) for d in dest]
|
||||
return f'[{", ".join(elem_strs)}]'
|
||||
else:
|
||||
return quote(dest)
|
||||
|
||||
|
||||
permission_dic = {
|
||||
'u': {
|
||||
'r': stat.S_IRUSR,
|
||||
'w': stat.S_IWUSR,
|
||||
'x': stat.S_IXUSR
|
||||
},
|
||||
'g': {
|
||||
'r': stat.S_IRGRP,
|
||||
'w': stat.S_IWGRP,
|
||||
'x': stat.S_IXGRP
|
||||
},
|
||||
'o': {
|
||||
'r': stat.S_IROTH,
|
||||
'w': stat.S_IWOTH,
|
||||
'x': stat.S_IXOTH
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def chmod_func(dest, mode):
|
||||
"""Implementation of the Chmod action function.
|
||||
|
||||
*mode* can be either an integer (normally expressed in octal mode,
|
||||
as in 0o755) or a string following the syntax of the POSIX chmod
|
||||
command (for example "ugo+w"). The latter must be converted, since
|
||||
the underlying Python only takes the numeric form.
|
||||
"""
|
||||
from string import digits
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not is_List(dest):
|
||||
dest = [dest]
|
||||
if is_String(mode) and 0 not in [i in digits for i in mode]:
|
||||
mode = int(mode, 8)
|
||||
if not is_String(mode):
|
||||
for element in dest:
|
||||
os.chmod(str(element), mode)
|
||||
else:
|
||||
mode = str(mode)
|
||||
for operation in mode.split(","):
|
||||
if "=" in operation:
|
||||
operator = "="
|
||||
elif "+" in operation:
|
||||
operator = "+"
|
||||
elif "-" in operation:
|
||||
operator = "-"
|
||||
else:
|
||||
raise SyntaxError("Could not find +, - or =")
|
||||
operation_list = operation.split(operator)
|
||||
if len(operation_list) != 2:
|
||||
raise SyntaxError("More than one operator found")
|
||||
user = operation_list[0].strip().replace("a", "ugo")
|
||||
permission = operation_list[1].strip()
|
||||
new_perm = 0
|
||||
for u in user:
|
||||
for p in permission:
|
||||
try:
|
||||
new_perm = new_perm | permission_dic[u][p]
|
||||
except KeyError:
|
||||
raise SyntaxError("Unrecognized user or permission format")
|
||||
for element in dest:
|
||||
curr_perm = os.stat(str(element)).st_mode
|
||||
if operator == "=":
|
||||
os.chmod(str(element), new_perm)
|
||||
elif operator == "+":
|
||||
os.chmod(str(element), curr_perm | new_perm)
|
||||
elif operator == "-":
|
||||
os.chmod(str(element), curr_perm & ~new_perm)
|
||||
|
||||
|
||||
def chmod_strfunc(dest, mode):
|
||||
"""strfunction for the Chmod action function."""
|
||||
if not is_String(mode):
|
||||
return f'Chmod({get_paths_str(dest)}, {mode:#o})'
|
||||
else:
|
||||
return f'Chmod({get_paths_str(dest)}, "{mode}")'
|
||||
|
||||
|
||||
|
||||
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
||||
|
||||
|
||||
|
||||
def copy_func(dest, src, symlinks=True):
|
||||
"""Implementation of the Copy action function.
|
||||
|
||||
Copies *src* to *dest*. If *src* is a list, *dest* must be
|
||||
a directory, or not exist (will be created).
|
||||
|
||||
Since Python :mod:`shutil` methods, which know nothing about
|
||||
SCons Nodes, will be called to perform the actual copying,
|
||||
args are converted to strings first.
|
||||
|
||||
If *symlinks* evaluates true, then a symbolic link will be
|
||||
shallow copied and recreated as a symbolic link; otherwise, copying
|
||||
a symbolic link will be equivalent to copying the symbolic link's
|
||||
final target regardless of symbolic link depth.
|
||||
"""
|
||||
|
||||
dest = str(dest)
|
||||
src = [str(n) for n in src] if is_List(src) else str(src)
|
||||
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if is_List(src):
|
||||
# this fails only if dest exists and is not a dir
|
||||
try:
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
except FileExistsError:
|
||||
raise SCons.Errors.BuildError(
|
||||
errstr=(
|
||||
'Error: Copy() called with a list of sources, '
|
||||
'which requires target to be a directory, '
|
||||
f'but "{dest}" is not a directory.'
|
||||
)
|
||||
)
|
||||
for file in src:
|
||||
shutil.copy2(file, dest)
|
||||
return 0
|
||||
|
||||
elif os.path.islink(src):
|
||||
if symlinks:
|
||||
try:
|
||||
os.symlink(os.readlink(src), dest)
|
||||
except FileExistsError:
|
||||
raise SCons.Errors.BuildError(
|
||||
errstr=(
|
||||
f'Error: Copy() called to create symlink at "{dest}",'
|
||||
' but a file already exists at that location.'
|
||||
)
|
||||
)
|
||||
return 0
|
||||
|
||||
return copy_func(dest, os.path.realpath(src))
|
||||
|
||||
elif os.path.isfile(src):
|
||||
shutil.copy2(src, dest)
|
||||
return 0
|
||||
|
||||
else:
|
||||
shutil.copytree(src, dest, symlinks)
|
||||
return 0
|
||||
|
||||
|
||||
def copy_strfunc(dest, src, symlinks=True):
|
||||
"""strfunction for the Copy action function."""
|
||||
return f'Copy({get_paths_str(dest)}, {get_paths_str(src)})'
|
||||
|
||||
|
||||
Copy = ActionFactory(copy_func, copy_strfunc)
|
||||
|
||||
|
||||
def delete_func(dest, must_exist=False):
|
||||
"""Implementation of the Delete action function.
|
||||
|
||||
Lets the Python :func:`os.unlink` raise an error if *dest* does not exist,
|
||||
unless *must_exist* evaluates false (the default).
|
||||
"""
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
entry = str(entry)
|
||||
# os.path.exists returns False with broken links that exist
|
||||
entry_exists = os.path.exists(entry) or os.path.islink(entry)
|
||||
if not entry_exists and not must_exist:
|
||||
continue
|
||||
# os.path.isdir returns True when entry is a link to a dir
|
||||
if os.path.isdir(entry) and not os.path.islink(entry):
|
||||
shutil.rmtree(entry, True)
|
||||
continue
|
||||
os.unlink(entry)
|
||||
|
||||
|
||||
def delete_strfunc(dest, must_exist=False):
|
||||
"""strfunction for the Delete action function."""
|
||||
return f'Delete({get_paths_str(dest)})'
|
||||
|
||||
|
||||
Delete = ActionFactory(delete_func, delete_strfunc)
|
||||
|
||||
|
||||
def mkdir_func(dest):
|
||||
"""Implementation of the Mkdir action function."""
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
os.makedirs(str(entry), exist_ok=True)
|
||||
|
||||
|
||||
Mkdir = ActionFactory(mkdir_func, lambda _dir: f'Mkdir({get_paths_str(_dir)})')
|
||||
|
||||
|
||||
def move_func(dest, src):
|
||||
"""Implementation of the Move action function."""
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
SCons.Node.FS.invalidate_node_memos(src)
|
||||
shutil.move(src, dest)
|
||||
|
||||
|
||||
Move = ActionFactory(
|
||||
move_func, lambda dest, src: f'Move("{dest}", "{src}")', convert=str
|
||||
)
|
||||
|
||||
|
||||
def touch_func(dest):
|
||||
"""Implementation of the Touch action function."""
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not is_List(dest):
|
||||
dest = [dest]
|
||||
for file in dest:
|
||||
file = str(file)
|
||||
mtime = int(time.time())
|
||||
if os.path.exists(file):
|
||||
atime = os.path.getatime(file)
|
||||
else:
|
||||
with open(file, 'w'):
|
||||
atime = mtime
|
||||
os.utime(file, (atime, mtime))
|
||||
|
||||
|
||||
Touch = ActionFactory(touch_func, lambda file: f'Touch({get_paths_str(file)})')
|
||||
|
||||
|
||||
# Internal utility functions
|
||||
|
||||
# pylint: disable-msg=too-many-arguments
|
||||
def _concat(prefix, items_iter, suffix, env, f=lambda x: x, target=None, source=None, affect_signature=True):
|
||||
"""
|
||||
Creates a new list from 'items_iter' by first interpolating each element
|
||||
in the list using the 'env' dictionary and then calling f on the
|
||||
list, and finally calling _concat_ixes to concatenate 'prefix' and
|
||||
'suffix' onto each element of the list.
|
||||
"""
|
||||
|
||||
if not items_iter:
|
||||
return items_iter
|
||||
|
||||
l = f(SCons.PathList.PathList(items_iter).subst_path(env, target, source))
|
||||
if l is not None:
|
||||
items_iter = l
|
||||
|
||||
if not affect_signature:
|
||||
value = ['$(']
|
||||
else:
|
||||
value = []
|
||||
value += _concat_ixes(prefix, items_iter, suffix, env)
|
||||
|
||||
if not affect_signature:
|
||||
value += ["$)"]
|
||||
|
||||
return value
|
||||
# pylint: enable-msg=too-many-arguments
|
||||
|
||||
|
||||
def _concat_ixes(prefix, items_iter, suffix, env):
|
||||
"""
|
||||
Creates a new list from 'items_iter' by concatenating the 'prefix' and
|
||||
'suffix' arguments onto each element of the list. A trailing space
|
||||
on 'prefix' or leading space on 'suffix' will cause them to be put
|
||||
into separate list elements rather than being concatenated.
|
||||
"""
|
||||
|
||||
result = []
|
||||
|
||||
# ensure that prefix and suffix are strings
|
||||
prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
|
||||
suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
|
||||
|
||||
for x in flatten(items_iter):
|
||||
if isinstance(x, SCons.Node.FS.File):
|
||||
result.append(x)
|
||||
continue
|
||||
x = str(x)
|
||||
if x:
|
||||
|
||||
if prefix:
|
||||
if prefix[-1] == ' ':
|
||||
result.append(prefix[:-1])
|
||||
elif x[:len(prefix)] != prefix:
|
||||
x = prefix + x
|
||||
|
||||
result.append(x)
|
||||
|
||||
if suffix:
|
||||
if suffix[0] == ' ':
|
||||
result.append(suffix[1:])
|
||||
elif x[-len(suffix):] != suffix:
|
||||
result[-1] = result[-1] + suffix
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _stripixes(
|
||||
prefix,
|
||||
items,
|
||||
suffix,
|
||||
stripprefixes,
|
||||
stripsuffixes,
|
||||
env,
|
||||
literal_prefix = "",
|
||||
c = None,
|
||||
):
|
||||
"""Returns a list with text added to items after first stripping them.
|
||||
|
||||
A companion to :func:`_concat_ixes`, used by tools (like the GNU
|
||||
linker) that need to turn something like ``libfoo.a`` into ``-lfoo``.
|
||||
*stripprefixes* and *stripsuffixes* are stripped from *items*.
|
||||
Calls function *c* to postprocess the result.
|
||||
|
||||
Args:
|
||||
prefix: string to prepend to elements
|
||||
items: string or iterable to transform
|
||||
suffix: string to append to elements
|
||||
stripprefixes: prefix string(s) to strip from elements
|
||||
stripsuffixes: suffix string(s) to strip from elements
|
||||
env: construction environment for variable interpolation
|
||||
c: optional function to perform a transformation on the list.
|
||||
The default is `None`, which will select :func:`_concat_ixes`.
|
||||
"""
|
||||
if not items:
|
||||
return items
|
||||
|
||||
if not callable(c):
|
||||
env_c = env['_concat']
|
||||
if env_c != _concat and callable(env_c):
|
||||
# There's a custom _concat() method in the construction
|
||||
# environment, and we've allowed people to set that in
|
||||
# the past (see test/custom-concat.py), so preserve the
|
||||
# backwards compatibility.
|
||||
c = env_c
|
||||
else:
|
||||
c = _concat_ixes
|
||||
|
||||
stripprefixes = list(map(env.subst, flatten(stripprefixes)))
|
||||
stripsuffixes = list(map(env.subst, flatten(stripsuffixes)))
|
||||
|
||||
# This is a little funky: if literal_prefix is the same as os.pathsep
|
||||
# (e.g. both ':'), the normal conversion to a PathList will drop the
|
||||
# literal_prefix prefix. Tell it not to split in that case, which *should*
|
||||
# be okay because if we come through here, we're normally processing
|
||||
# library names and won't have strings like "path:secondpath:thirdpath"
|
||||
# which is why PathList() otherwise wants to split strings.
|
||||
do_split = not literal_prefix == os.pathsep
|
||||
|
||||
stripped = []
|
||||
for l in SCons.PathList.PathList(items, do_split).subst_path(env, None, None):
|
||||
if isinstance(l, SCons.Node.FS.File):
|
||||
stripped.append(l)
|
||||
continue
|
||||
|
||||
if not is_String(l):
|
||||
l = str(l)
|
||||
|
||||
if literal_prefix and l.startswith(literal_prefix):
|
||||
stripped.append(l)
|
||||
continue
|
||||
|
||||
for stripprefix in stripprefixes:
|
||||
lsp = len(stripprefix)
|
||||
if l[:lsp] == stripprefix:
|
||||
l = l[lsp:]
|
||||
# Do not strip more than one prefix
|
||||
break
|
||||
|
||||
for stripsuffix in stripsuffixes:
|
||||
lss = len(stripsuffix)
|
||||
if l[-lss:] == stripsuffix:
|
||||
l = l[:-lss]
|
||||
# Do not strip more than one suffix
|
||||
break
|
||||
|
||||
stripped.append(l)
|
||||
|
||||
return c(prefix, stripped, suffix, env)
|
||||
|
||||
|
||||
def processDefines(defs):
|
||||
"""Return list of strings for preprocessor defines from *defs*.
|
||||
|
||||
Resolves the different forms ``CPPDEFINES`` can be assembled in:
|
||||
if the Append/Prepend routines are used beyond a initial setting it
|
||||
will be a deque, but if written to only once (Environment initializer,
|
||||
or direct write) it can be a multitude of types.
|
||||
|
||||
Any prefix/suffix is handled elsewhere (usually :func:`_concat_ixes`).
|
||||
|
||||
.. versionchanged:: 4.5.0
|
||||
Bare tuples are now treated the same as tuple-in-sequence, assumed
|
||||
to describe a valued macro. Bare strings are now split on space.
|
||||
A dictionary is no longer sorted before handling.
|
||||
"""
|
||||
dlist = []
|
||||
if is_List(defs):
|
||||
for define in defs:
|
||||
if define is None:
|
||||
continue
|
||||
elif is_Sequence(define):
|
||||
if len(define) > 2:
|
||||
raise SCons.Errors.UserError(
|
||||
f"Invalid tuple in CPPDEFINES: {define!r}, "
|
||||
"must be a tuple with only two elements"
|
||||
)
|
||||
name, *value = define
|
||||
if value and value[0] is not None:
|
||||
# TODO: do we need to quote value if it contains space?
|
||||
dlist.append(f"{name}={value[0]}")
|
||||
else:
|
||||
dlist.append(str(define[0]))
|
||||
elif is_Dict(define):
|
||||
for macro, value in define.items():
|
||||
if value is not None:
|
||||
# TODO: do we need to quote value if it contains space?
|
||||
dlist.append(f"{macro}={value}")
|
||||
else:
|
||||
dlist.append(str(macro))
|
||||
elif is_String(define):
|
||||
dlist.append(str(define))
|
||||
else:
|
||||
raise SCons.Errors.UserError(
|
||||
f"CPPDEFINES entry {define!r} is not a tuple, list, "
|
||||
"dict, string or None."
|
||||
)
|
||||
elif is_Tuple(defs):
|
||||
if len(defs) > 2:
|
||||
raise SCons.Errors.UserError(
|
||||
f"Invalid tuple in CPPDEFINES: {defs!r}, "
|
||||
"must be a tuple with only two elements"
|
||||
)
|
||||
name, *value = defs
|
||||
if value and value[0] is not None:
|
||||
# TODO: do we need to quote value if it contains space?
|
||||
dlist.append(f"{name}={value[0]}")
|
||||
else:
|
||||
dlist.append(str(define[0]))
|
||||
elif is_Dict(defs):
|
||||
for macro, value in defs.items():
|
||||
if value is None:
|
||||
dlist.append(str(macro))
|
||||
else:
|
||||
dlist.append(f"{macro}={value}")
|
||||
elif is_String(defs):
|
||||
return defs.split()
|
||||
else:
|
||||
dlist.append(str(defs))
|
||||
|
||||
return dlist
|
||||
|
||||
|
||||
def _defines(prefix, defs, suffix, env, target=None, source=None, c=_concat_ixes):
|
||||
"""A wrapper around :func:`_concat_ixes` that turns a list or string
|
||||
into a list of C preprocessor command-line definitions.
|
||||
"""
|
||||
return c(prefix, env.subst_list(processDefines(defs), target=target, source=source), suffix, env)
|
||||
|
||||
|
||||
class NullCmdGenerator:
|
||||
"""Callable class for use as a no-effect command generator.
|
||||
|
||||
The ``__call__`` method for this class simply returns the thing
|
||||
you instantiated it with. Example usage::
|
||||
|
||||
env["DO_NOTHING"] = NullCmdGenerator
|
||||
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
|
||||
"""
|
||||
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
|
||||
def __call__(self, target, source, env, for_signature=None):
|
||||
return self.cmd
|
||||
|
||||
|
||||
class Variable_Method_Caller:
|
||||
"""A class for finding a construction variable on the stack and
|
||||
calling one of its methods.
|
||||
|
||||
Used to support "construction variables" appearing in string
|
||||
``eval``s that actually stand in for methods--specifically, the use
|
||||
of "RDirs" in a call to :func:`_concat` that should actually execute the
|
||||
``TARGET.RDirs`` method.
|
||||
|
||||
Historical note: This was formerly supported by creating a little
|
||||
"build dictionary" that mapped RDirs to the method, but this got
|
||||
in the way of Memoizing construction environments, because we had to
|
||||
create new environment objects to hold the variables.
|
||||
"""
|
||||
|
||||
def __init__(self, variable, method):
|
||||
self.variable = variable
|
||||
self.method = method
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
try:
|
||||
1 // 0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
frame = sys.exc_info()[2].tb_frame.f_back
|
||||
variable = self.variable
|
||||
while frame:
|
||||
if variable in frame.f_locals:
|
||||
v = frame.f_locals[variable]
|
||||
if v:
|
||||
method = getattr(v, self.method)
|
||||
return method(*args, **kw)
|
||||
frame = frame.f_back
|
||||
return None
|
||||
|
||||
|
||||
def __libversionflags(env, version_var, flags_var):
|
||||
"""
|
||||
if version_var is not empty, returns env[flags_var], otherwise returns None
|
||||
:param env:
|
||||
:param version_var:
|
||||
:param flags_var:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if env.subst('$' + version_var):
|
||||
return env[flags_var]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def __lib_either_version_flag(env, version_var1, version_var2, flags_var):
|
||||
"""
|
||||
if $version_var1 or $version_var2 is not empty, returns env[flags_var], otherwise returns None
|
||||
:param env:
|
||||
:param version_var1:
|
||||
:param version_var2:
|
||||
:param flags_var:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if env.subst('$' + version_var1) or env.subst('$' + version_var2):
|
||||
return env[flags_var]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ConstructionEnvironment = {
|
||||
'BUILDERS': {},
|
||||
'SCANNERS': [SCons.Tool.SourceFileScanner],
|
||||
'CONFIGUREDIR': '#/.sconf_temp',
|
||||
'CONFIGURELOG': '#/config.log',
|
||||
'CPPSUFFIXES': SCons.Tool.CSuffixes,
|
||||
'DSUFFIXES': SCons.Tool.DSuffixes,
|
||||
'ENV': {},
|
||||
'IDLSUFFIXES': SCons.Tool.IDLSuffixes,
|
||||
'_concat': _concat,
|
||||
'_defines': _defines,
|
||||
'_stripixes': _stripixes,
|
||||
'_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||
|
||||
'_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}',
|
||||
'_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}',
|
||||
|
||||
'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, TARGET, SOURCE)}',
|
||||
|
||||
'__libversionflags': __libversionflags,
|
||||
'__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
||||
'__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
||||
'__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||
'__lib_either_version_flag': __lib_either_version_flag,
|
||||
|
||||
'TEMPFILE': NullCmdGenerator,
|
||||
'TEMPFILEARGJOIN': ' ',
|
||||
'TEMPFILEARGESCFUNC': SCons.Subst.quote_spaces,
|
||||
'Dir': Variable_Method_Caller('TARGET', 'Dir'),
|
||||
'Dirs': Variable_Method_Caller('TARGET', 'Dirs'),
|
||||
'File': Variable_Method_Caller('TARGET', 'File'),
|
||||
'RDirs': Variable_Method_Caller('TARGET', 'RDirs'),
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
2910
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Environment.py
Normal file
2910
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Environment.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
# 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.
|
||||
|
||||
import re
|
||||
|
||||
_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
|
||||
|
||||
_rm = re.compile(r'\$[()]')
|
||||
_remove = re.compile(r'\$\([^$]*(\$[^)][^$]*)*\$\)')
|
||||
|
||||
# Regular expressions for splitting strings and handling substitutions,
|
||||
# for use by the scons_subst() and scons_subst_list() functions:
|
||||
#
|
||||
# The first expression compiled matches all of the $-introduced tokens
|
||||
# that we need to process in some way, and is used for substitutions.
|
||||
# The expressions it matches are:
|
||||
#
|
||||
# "$$"
|
||||
# "$("
|
||||
# "$)"
|
||||
# "$variable" [must begin with alphabetic or underscore]
|
||||
# "${any stuff}"
|
||||
#
|
||||
# The second expression compiled is used for splitting strings into tokens
|
||||
# to be processed, and it matches all of the tokens listed above, plus
|
||||
# the following that affect how arguments do or don't get joined together:
|
||||
#
|
||||
# " " [white space]
|
||||
# "non-white-space" [without any dollar signs]
|
||||
# "$" [single dollar sign]
|
||||
#
|
||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str)
|
||||
|
||||
# This regular expression is used to replace strings of multiple white
|
||||
# space characters in the string result from the scons_subst() function.
|
||||
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
|
||||
|
||||
class ValueTypes:
|
||||
"""
|
||||
Enum to store what type of value the variable holds.
|
||||
"""
|
||||
UNKNOWN = 0
|
||||
STRING = 1
|
||||
CALLABLE = 2
|
||||
VARIABLE = 3
|
||||
|
||||
|
||||
class EnvironmentValue:
|
||||
"""
|
||||
Hold a single value. We're going to cache parsed version of the file
|
||||
We're going to keep track of variables which feed into this values evaluation
|
||||
"""
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.var_type = ValueTypes.UNKNOWN
|
||||
|
||||
if callable(self.value):
|
||||
self.var_type = ValueTypes.CALLABLE
|
||||
else:
|
||||
self.parse_value()
|
||||
|
||||
|
||||
def parse_value(self):
|
||||
"""
|
||||
Scan the string and break into component values
|
||||
"""
|
||||
|
||||
try:
|
||||
if '$' not in self.value:
|
||||
self._parsed = self.value
|
||||
self.var_type = ValueTypes.STRING
|
||||
else:
|
||||
# Now we need to parse the specified string
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
print(result)
|
||||
except TypeError:
|
||||
# likely callable? either way we don't parse
|
||||
self._parsed = self.value
|
||||
|
||||
def parse_trial(self):
|
||||
"""
|
||||
Try alternate parsing methods.
|
||||
:return:
|
||||
"""
|
||||
parts = []
|
||||
for c in self.value:
|
||||
pass
|
||||
|
||||
|
||||
class EnvironmentValues:
|
||||
"""
|
||||
A class to hold all the environment variables
|
||||
"""
|
||||
def __init__(self, **kw):
|
||||
self._dict = {}
|
||||
for k in kw:
|
||||
self._dict[k] = EnvironmentValue(kw[k])
|
||||
222
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Errors.py
Normal file
222
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Errors.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# 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.
|
||||
|
||||
"""SCons exception classes.
|
||||
|
||||
Used to handle internal and user errors in SCons.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from SCons.Util.sctypes import to_String, is_String
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from SCons.Executor import Executor
|
||||
|
||||
# Note that not all Errors are defined here, some are at the point of use
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
"""SCons Errors that can occur while building.
|
||||
|
||||
A :class:`BuildError` exception contains information both
|
||||
about the erorr itself, and what caused the error.
|
||||
|
||||
Attributes:
|
||||
node: (*cause*) the error occurred while building this target node(s)
|
||||
errstr: (*info*) a description of the error message
|
||||
status: (*info*) the return code of the action that caused the build error.
|
||||
Must be set to a non-zero value even if the build error is not due
|
||||
to an action returning a non-zero returned code.
|
||||
exitstatus: (*info*) SCons exit status due to this build error.
|
||||
Must be nonzero unless due to an explicit :meth:`Exit` call.
|
||||
Not always the same as ``status``, since actions return a status
|
||||
code that should be respected, but SCons typically exits with 2
|
||||
irrespective of the return value of the failed action.
|
||||
filename: (*info*) The name of the file or directory that caused the
|
||||
build error. Set to ``None`` if no files are associated with
|
||||
this error. This might be different from the target
|
||||
being built. For example, failure to create the
|
||||
directory in which the target file will appear. It
|
||||
can be ``None`` if the error is not due to a particular
|
||||
filename.
|
||||
executor: (*cause*) the executor that caused the build to fail (might
|
||||
be ``None`` if the build failures is not due to the executor failing)
|
||||
action: (*cause*) the action that caused the build to fail (might be
|
||||
``None`` if the build failures is not due to the an
|
||||
action failure)
|
||||
command: (*cause*) the command line for the action that caused the
|
||||
build to fail (might be ``None`` if the build failures
|
||||
is not due to the an action failure)
|
||||
exc_info: (*info*) Info about exception that caused the build
|
||||
error. Set to ``(None, None, None)`` if this build
|
||||
error is not due to an exception.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
node=None, errstr="Unknown error", status=2, exitstatus=2,
|
||||
filename=None, executor = None, action=None, command=None,
|
||||
exc_info=(None, None, None)):
|
||||
|
||||
# py3: errstr should be string and not bytes.
|
||||
|
||||
self.errstr = to_String(errstr)
|
||||
self.status = status
|
||||
self.exitstatus = exitstatus
|
||||
self.filename = filename
|
||||
self.exc_info = exc_info
|
||||
|
||||
self.node = node
|
||||
self.executor = executor
|
||||
self.action = action
|
||||
self.command = command
|
||||
|
||||
super().__init__(node, errstr, status, exitstatus, filename,
|
||||
executor, action, command, exc_info)
|
||||
|
||||
def __str__(self):
|
||||
if self.filename:
|
||||
return self.filename + ': ' + self.errstr
|
||||
else:
|
||||
return self.errstr
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
class UserError(Exception):
|
||||
pass
|
||||
|
||||
class StopError(Exception):
|
||||
pass
|
||||
|
||||
class SConsEnvironmentError(Exception):
|
||||
pass
|
||||
|
||||
class MSVCError(IOError):
|
||||
pass
|
||||
|
||||
class ExplicitExit(Exception):
|
||||
def __init__(self, node=None, status=None, *args):
|
||||
self.node = node
|
||||
self.status = status
|
||||
self.exitstatus = status
|
||||
super().__init__(*args)
|
||||
|
||||
def convert_to_BuildError(status, exc_info=None):
|
||||
"""Convert a return code to a BuildError Exception.
|
||||
|
||||
The `buildError.status` we set here will normally be
|
||||
used as the exit status of the "scons" process.
|
||||
|
||||
Args:
|
||||
status: can either be a return code or an Exception.
|
||||
exc_info (tuple, optional): explicit exception information.
|
||||
|
||||
"""
|
||||
|
||||
if not exc_info and isinstance(status, Exception):
|
||||
exc_info = (status.__class__, status, None)
|
||||
|
||||
|
||||
if isinstance(status, BuildError):
|
||||
buildError = status
|
||||
buildError.exitstatus = 2 # always exit with 2 on build errors
|
||||
elif isinstance(status, ExplicitExit):
|
||||
status = status.status
|
||||
errstr = 'Explicit exit, status %s' % status
|
||||
buildError = BuildError(
|
||||
errstr=errstr,
|
||||
status=status, # might be 0, OK here
|
||||
exitstatus=status, # might be 0, OK here
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, (StopError, UserError)):
|
||||
buildError = BuildError(
|
||||
errstr=str(status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, shutil.SameFileError):
|
||||
# PY3 has a exception for when copying file to itself
|
||||
# It's object provides info differently than below
|
||||
try:
|
||||
filename = status.filename
|
||||
except AttributeError:
|
||||
filename = None
|
||||
|
||||
buildError = BuildError(
|
||||
errstr=status.args[0],
|
||||
status=status.errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
|
||||
elif isinstance(status, (SConsEnvironmentError, OSError, IOError)):
|
||||
# If an IOError/OSError happens, raise a BuildError.
|
||||
# Report the name of the file or directory that caused the
|
||||
# error, which might be different from the target being built
|
||||
# (for example, failure to create the directory in which the
|
||||
# target file will appear).
|
||||
filename = getattr(status, 'filename', None)
|
||||
strerror = getattr(status, 'strerror', None)
|
||||
if strerror is None:
|
||||
strerror = str(status)
|
||||
errno = getattr(status, 'errno', None)
|
||||
if errno is None:
|
||||
errno = 2
|
||||
|
||||
buildError = BuildError(
|
||||
errstr=strerror,
|
||||
status=errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, Exception):
|
||||
buildError = BuildError(
|
||||
errstr='%s : %s' % (status.__class__.__name__, status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif is_String(status):
|
||||
buildError = BuildError(
|
||||
errstr=status,
|
||||
status=2,
|
||||
exitstatus=2)
|
||||
else:
|
||||
buildError = BuildError(
|
||||
errstr="Error %s" % status,
|
||||
status=status,
|
||||
exitstatus=2)
|
||||
|
||||
#import sys
|
||||
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
|
||||
return buildError
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
665
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Executor.py
Normal file
665
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Executor.py
Normal file
@@ -0,0 +1,665 @@
|
||||
# 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.
|
||||
|
||||
"""Execute actions with specific lists of target and source Nodes."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
from contextlib import suppress
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Memoize
|
||||
import SCons.Util
|
||||
from SCons.compat import NoSlotsPyPy
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
|
||||
class Batch:
|
||||
"""Remembers exact association between targets
|
||||
and sources of executor."""
|
||||
|
||||
__slots__ = ('targets',
|
||||
'sources')
|
||||
|
||||
def __init__(self, targets=[], sources=[]):
|
||||
self.targets = targets
|
||||
self.sources = sources
|
||||
|
||||
|
||||
|
||||
class TSList(collections.UserList):
|
||||
"""A class that implements $TARGETS or $SOURCES expansions by wrapping
|
||||
an executor Method. This class is used in the Executor.lvars()
|
||||
to delay creation of NodeList objects until they're needed.
|
||||
|
||||
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.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
def __getattr__(self, attr):
|
||||
nl = self.func()
|
||||
return getattr(nl, attr)
|
||||
def __getitem__(self, i):
|
||||
nl = self.func()
|
||||
return nl[i]
|
||||
def __str__(self):
|
||||
nl = self.func()
|
||||
return str(nl)
|
||||
def __repr__(self):
|
||||
nl = self.func()
|
||||
return repr(nl)
|
||||
|
||||
class TSObject:
|
||||
"""A class that implements $TARGET or $SOURCE expansions by wrapping
|
||||
an Executor method.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
def __getattr__(self, attr):
|
||||
n = self.func()
|
||||
return getattr(n, attr)
|
||||
def __str__(self):
|
||||
n = self.func()
|
||||
if n:
|
||||
return str(n)
|
||||
return ''
|
||||
def __repr__(self):
|
||||
n = self.func()
|
||||
if n:
|
||||
return repr(n)
|
||||
return ''
|
||||
|
||||
def rfile(node):
|
||||
"""
|
||||
A function to return the results of a Node's rfile() method,
|
||||
if it exists, and the Node itself otherwise (if it's a Value
|
||||
Node, e.g.).
|
||||
"""
|
||||
try:
|
||||
rfile = node.rfile
|
||||
except AttributeError:
|
||||
return node
|
||||
else:
|
||||
return rfile()
|
||||
|
||||
|
||||
def execute_nothing(obj, target, kw):
|
||||
return 0
|
||||
|
||||
def execute_action_list(obj, target, kw):
|
||||
"""Actually execute the action list."""
|
||||
env = obj.get_build_env()
|
||||
kw = obj.get_kw(kw)
|
||||
status = 0
|
||||
for act in obj.get_action_list():
|
||||
args = ([], [], env)
|
||||
status = act(*args, **kw)
|
||||
if isinstance(status, SCons.Errors.BuildError):
|
||||
status.executor = obj
|
||||
raise status # TODO pylint E0702: raising int not allowed
|
||||
elif status:
|
||||
msg = "Error %s" % status
|
||||
raise SCons.Errors.BuildError(
|
||||
errstr=msg,
|
||||
node=obj.batches[0].targets,
|
||||
executor=obj,
|
||||
action=act)
|
||||
return status
|
||||
|
||||
_do_execute_map = {0 : execute_nothing,
|
||||
1 : execute_action_list}
|
||||
|
||||
|
||||
def execute_actions_str(obj):
|
||||
env = obj.get_build_env()
|
||||
return "\n".join([action.genstring(obj.get_all_targets(),
|
||||
obj.get_all_sources(),
|
||||
env)
|
||||
for action in obj.get_action_list()])
|
||||
|
||||
def execute_null_str(obj):
|
||||
return ''
|
||||
|
||||
_execute_str_map = {0 : execute_null_str,
|
||||
1 : execute_actions_str}
|
||||
|
||||
|
||||
class Executor(metaclass=NoSlotsPyPy):
|
||||
"""A class for controlling instances of executing an action.
|
||||
|
||||
This largely exists to hold a single association of an action,
|
||||
environment, list of environment override dictionaries, targets
|
||||
and sources for later processing as needed.
|
||||
"""
|
||||
|
||||
__slots__ = ('pre_actions',
|
||||
'post_actions',
|
||||
'env',
|
||||
'overridelist',
|
||||
'batches',
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
|
||||
def __init__(self, action, env=None, overridelist=[{}],
|
||||
targets=[], sources=[], builder_kw={}):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Executor')
|
||||
self.set_action_list(action)
|
||||
self.pre_actions = []
|
||||
self.post_actions = []
|
||||
self.env = env
|
||||
self.overridelist = overridelist
|
||||
if targets or sources:
|
||||
self.batches = [Batch(targets[:], sources[:])]
|
||||
else:
|
||||
self.batches = []
|
||||
self.builder_kw = builder_kw
|
||||
self._do_execute = 1
|
||||
self._execute_str = 1
|
||||
self._memo = {}
|
||||
|
||||
def get_lvars(self):
|
||||
try:
|
||||
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),
|
||||
}
|
||||
return self.lvars
|
||||
|
||||
def _get_changes(self):
|
||||
"""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():
|
||||
unchanged_sources.extend(list(map(rfile, b.sources)))
|
||||
unchanged_targets.extend(b.targets)
|
||||
else:
|
||||
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):
|
||||
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):
|
||||
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()
|
||||
|
||||
def _get_sources(self, *args, **kw):
|
||||
return SCons.Util.NodeList([rfile(n).get_subst_proxy() for n in self.get_all_sources()])
|
||||
|
||||
def _get_target(self, *args, **kw):
|
||||
return self.batches[0].targets[0].get_subst_proxy()
|
||||
|
||||
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):
|
||||
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):
|
||||
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:
|
||||
return []
|
||||
targets_string = self.action_list[0].get_targets(self.env, self)
|
||||
if targets_string[0] == '$':
|
||||
targets_string = targets_string[1:]
|
||||
return self.get_lvars()[targets_string]
|
||||
|
||||
def set_action_list(self, action):
|
||||
if not SCons.Util.is_List(action):
|
||||
if not action:
|
||||
raise SCons.Errors.UserError("Executor must have an action.")
|
||||
action = [action]
|
||||
self.action_list = action
|
||||
|
||||
def get_action_list(self):
|
||||
if self.action_list is None:
|
||||
return []
|
||||
return self.pre_actions + self.action_list + self.post_actions
|
||||
|
||||
def get_all_targets(self):
|
||||
"""Returns all targets for all batches of this Executor."""
|
||||
result = []
|
||||
for batch in self.batches:
|
||||
result.extend(batch.targets)
|
||||
return result
|
||||
|
||||
def get_all_sources(self):
|
||||
"""Returns all sources for all batches of this Executor."""
|
||||
result = []
|
||||
for batch in self.batches:
|
||||
result.extend(batch.sources)
|
||||
return result
|
||||
|
||||
def get_all_children(self):
|
||||
"""Returns all unique children (dependencies) for all batches
|
||||
of this Executor.
|
||||
|
||||
The Taskmaster can recognize when it's already evaluated a
|
||||
Node, so we don't have to make this list unique for its intended
|
||||
canonical use case, but we expect there to be a lot of redundancy
|
||||
(long lists of batched .cc files #including the same .h files
|
||||
over and over), so removing the duplicates once up front should
|
||||
save the Taskmaster a lot of work.
|
||||
"""
|
||||
result = []
|
||||
for target in self.get_all_targets():
|
||||
result.extend(target.children())
|
||||
return SCons.Util.uniquer_hashables(result)
|
||||
|
||||
def get_all_prerequisites(self):
|
||||
"""Returns all unique (order-only) prerequisites for all batches
|
||||
of this Executor.
|
||||
"""
|
||||
result = []
|
||||
for target in self.get_all_targets():
|
||||
if target.prerequisites is not None:
|
||||
result.extend(target.prerequisites)
|
||||
return SCons.Util.uniquer_hashables(result)
|
||||
|
||||
def get_action_side_effects(self):
|
||||
|
||||
"""Returns all side effects for all batches of this
|
||||
Executor used by the underlying Action.
|
||||
"""
|
||||
result = []
|
||||
for target in self.get_action_targets():
|
||||
result.extend(target.side_effects)
|
||||
return SCons.Util.uniquer_hashables(result)
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_build_env(self):
|
||||
"""Fetch or create the appropriate build Environment
|
||||
for this Executor.
|
||||
"""
|
||||
try:
|
||||
return self._memo['get_build_env']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Create the build environment instance with appropriate
|
||||
# overrides. These get evaluated against the current
|
||||
# environment's construction variables so that users can
|
||||
# add to existing values by referencing the variable in
|
||||
# the expansion.
|
||||
overrides = {}
|
||||
for odict in self.overridelist:
|
||||
overrides.update(odict)
|
||||
|
||||
import SCons.Defaults
|
||||
env = self.env or SCons.Defaults.DefaultEnvironment()
|
||||
build_env = env.Override(overrides)
|
||||
|
||||
self._memo['get_build_env'] = build_env
|
||||
|
||||
return build_env
|
||||
|
||||
def get_build_scanner_path(self, scanner):
|
||||
"""Fetch the scanner path for this executor's targets and sources.
|
||||
"""
|
||||
env = self.get_build_env()
|
||||
try:
|
||||
cwd = self.batches[0].targets[0].cwd
|
||||
except (IndexError, AttributeError):
|
||||
cwd = None
|
||||
return scanner.path(env, cwd,
|
||||
self.get_all_targets(),
|
||||
self.get_all_sources())
|
||||
|
||||
def get_kw(self, kw={}):
|
||||
result = self.builder_kw.copy()
|
||||
result.update(kw)
|
||||
result['executor'] = self
|
||||
return result
|
||||
|
||||
# use extra indirection because with new-style objects (Python 2.2
|
||||
# and above) we can't override special methods, and nullify() needs
|
||||
# to be able to do this.
|
||||
|
||||
def __call__(self, target, **kw):
|
||||
return _do_execute_map[self._do_execute](self, target, kw)
|
||||
|
||||
def cleanup(self):
|
||||
self._memo = {}
|
||||
|
||||
def add_sources(self, sources):
|
||||
"""Add source files to this Executor's list. This is necessary
|
||||
for "multi" Builders that can be called repeatedly to build up
|
||||
a source file list for a given target."""
|
||||
# TODO(batch): extend to multiple batches
|
||||
assert (len(self.batches) == 1)
|
||||
# TODO(batch): remove duplicates?
|
||||
sources = [x for x in sources if x not in self.batches[0].sources]
|
||||
self.batches[0].sources.extend(sources)
|
||||
|
||||
def get_sources(self):
|
||||
return self.batches[0].sources
|
||||
|
||||
def add_batch(self, targets, sources):
|
||||
"""Add pair of associated target and source to this Executor's list.
|
||||
This is necessary for "batch" Builders that can be called repeatedly
|
||||
to build up a list of matching target and source files that will be
|
||||
used in order to update multiple target files at once from multiple
|
||||
corresponding source files, for tools like MSVC that support it."""
|
||||
self.batches.append(Batch(targets, sources))
|
||||
|
||||
def prepare(self):
|
||||
"""
|
||||
Preparatory checks for whether this Executor can go ahead
|
||||
and (try to) build its targets.
|
||||
"""
|
||||
for s in self.get_all_sources():
|
||||
if s.missing():
|
||||
msg = "Source `%s' not found, needed by target `%s'."
|
||||
raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0]))
|
||||
|
||||
def add_pre_action(self, action):
|
||||
self.pre_actions.append(action)
|
||||
|
||||
def add_post_action(self, action):
|
||||
self.post_actions.append(action)
|
||||
|
||||
# another extra indirection for new-style objects and nullify...
|
||||
|
||||
def __str__(self):
|
||||
return _execute_str_map[self._execute_str](self)
|
||||
|
||||
def nullify(self):
|
||||
self.cleanup()
|
||||
self._do_execute = 0
|
||||
self._execute_str = 0
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_contents(self):
|
||||
"""Fetch the signature contents. This is the main reason this
|
||||
class exists, so we can compute this once and cache it regardless
|
||||
of how many target or source Nodes there are.
|
||||
|
||||
Returns bytes
|
||||
"""
|
||||
try:
|
||||
return self._memo['get_contents']
|
||||
except KeyError:
|
||||
pass
|
||||
env = self.get_build_env()
|
||||
|
||||
action_list = self.get_action_list()
|
||||
all_targets = self.get_all_targets()
|
||||
all_sources = self.get_all_sources()
|
||||
|
||||
result = bytearray("",'utf-8').join([action.get_contents(all_targets,
|
||||
all_sources,
|
||||
env)
|
||||
for action in action_list])
|
||||
|
||||
self._memo['get_contents'] = result
|
||||
return result
|
||||
|
||||
def get_timestamp(self):
|
||||
"""Fetch a time stamp for this Executor. We don't have one, of
|
||||
course (only files do), but this is the interface used by the
|
||||
timestamp module.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def scan_targets(self, scanner):
|
||||
# TODO(batch): scan by batches
|
||||
self.scan(scanner, self.get_all_targets())
|
||||
|
||||
def scan_sources(self, scanner):
|
||||
# TODO(batch): scan by batches
|
||||
if self.batches[0].sources:
|
||||
self.scan(scanner, self.get_all_sources())
|
||||
|
||||
def scan(self, scanner, node_list):
|
||||
"""Scan a list of this Executor's files (targets or sources) for
|
||||
implicit dependencies and update all of the targets with them.
|
||||
This essentially short-circuits an N*M scan of the sources for
|
||||
each individual target, which is a hell of a lot more efficient.
|
||||
"""
|
||||
env = self.get_build_env()
|
||||
path = self.get_build_scanner_path
|
||||
kw = self.get_kw()
|
||||
|
||||
# TODO(batch): scan by batches)
|
||||
deps = []
|
||||
|
||||
for node in node_list:
|
||||
node.disambiguate()
|
||||
deps.extend(node.get_implicit_deps(env, scanner, path, kw))
|
||||
|
||||
deps.extend(self.get_implicit_deps())
|
||||
|
||||
for tgt in self.get_all_targets():
|
||||
tgt.add_to_implicit(deps)
|
||||
|
||||
def _get_unignored_sources_key(self, node, ignore=()):
|
||||
return (node,) + tuple(ignore)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_get_unignored_sources_key)
|
||||
def get_unignored_sources(self, node, ignore=()):
|
||||
key = (node,) + tuple(ignore)
|
||||
try:
|
||||
memo_dict = self._memo['get_unignored_sources']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['get_unignored_sources'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if node:
|
||||
# TODO: better way to do this (it's a linear search,
|
||||
# but it may not be critical path)?
|
||||
sourcelist = []
|
||||
for b in self.batches:
|
||||
if node in b.targets:
|
||||
sourcelist = b.sources
|
||||
break
|
||||
else:
|
||||
sourcelist = self.get_all_sources()
|
||||
if ignore:
|
||||
idict = {}
|
||||
for i in ignore:
|
||||
idict[i] = 1
|
||||
sourcelist = [s for s in sourcelist if s not in idict]
|
||||
|
||||
memo_dict[key] = sourcelist
|
||||
|
||||
return sourcelist
|
||||
|
||||
def get_implicit_deps(self):
|
||||
"""Return the executor's implicit dependencies, i.e. the nodes of
|
||||
the commands to be executed."""
|
||||
result = []
|
||||
build_env = self.get_build_env()
|
||||
for act in self.get_action_list():
|
||||
deps = act.get_implicit_deps(self.get_all_targets(),
|
||||
self.get_all_sources(),
|
||||
build_env)
|
||||
result.extend(deps)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
_batch_executors: dict[str, Executor] = {}
|
||||
|
||||
def GetBatchExecutor(key):
|
||||
return _batch_executors[key]
|
||||
|
||||
def AddBatchExecutor(key, executor):
|
||||
assert key not in _batch_executors
|
||||
_batch_executors[key] = executor
|
||||
|
||||
nullenv = None
|
||||
|
||||
|
||||
class NullEnvironment(SCons.Util.Null):
|
||||
import SCons.CacheDir
|
||||
_CacheDir_path = None
|
||||
_CacheDir = SCons.CacheDir.CacheDir(None)
|
||||
def get_CacheDir(self):
|
||||
return self._CacheDir
|
||||
|
||||
|
||||
def get_NullEnvironment():
|
||||
"""Use singleton pattern for Null Environments."""
|
||||
global nullenv
|
||||
|
||||
if nullenv is None:
|
||||
nullenv = NullEnvironment()
|
||||
return nullenv
|
||||
|
||||
class Null(metaclass=NoSlotsPyPy):
|
||||
"""A null Executor, with a null build Environment, that does
|
||||
nothing when the rest of the methods call it.
|
||||
|
||||
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',
|
||||
'post_actions',
|
||||
'env',
|
||||
'overridelist',
|
||||
'batches',
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
if SCons.Debug.track_instances:
|
||||
logInstanceCreation(self, 'Executor.Null')
|
||||
self.batches = [Batch(kw['targets'][:], [])]
|
||||
def get_build_env(self):
|
||||
return get_NullEnvironment()
|
||||
def get_build_scanner_path(self):
|
||||
return None
|
||||
def cleanup(self):
|
||||
pass
|
||||
def prepare(self):
|
||||
pass
|
||||
def get_unignored_sources(self, *args, **kw):
|
||||
return tuple(())
|
||||
def get_action_targets(self):
|
||||
return []
|
||||
def get_action_list(self):
|
||||
return []
|
||||
def get_all_targets(self):
|
||||
return self.batches[0].targets
|
||||
def get_all_sources(self):
|
||||
return self.batches[0].targets[0].sources
|
||||
def get_all_children(self):
|
||||
return self.batches[0].targets[0].children()
|
||||
def get_all_prerequisites(self):
|
||||
return []
|
||||
def get_action_side_effects(self):
|
||||
return []
|
||||
def __call__(self, *args, **kw):
|
||||
return 0
|
||||
def get_contents(self):
|
||||
return ''
|
||||
def _morph(self):
|
||||
"""Morph this Null executor to a real Executor object."""
|
||||
batches = self.batches
|
||||
self.__class__ = Executor
|
||||
self.__init__([])
|
||||
self.batches = batches
|
||||
|
||||
# The following methods require morphing this Null Executor to a
|
||||
# real Executor object.
|
||||
|
||||
def add_pre_action(self, action):
|
||||
self._morph()
|
||||
self.add_pre_action(action)
|
||||
def add_post_action(self, action):
|
||||
self._morph()
|
||||
self.add_post_action(action)
|
||||
def set_action_list(self, action):
|
||||
self._morph()
|
||||
self.set_action_list(action)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
242
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Memoize.py
Normal file
242
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Memoize.py
Normal file
@@ -0,0 +1,242 @@
|
||||
# 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.
|
||||
|
||||
"""Decorator-based memoizer to count caching stats.
|
||||
|
||||
A decorator-based implementation to count hits and misses of the computed
|
||||
values that various methods cache in memory.
|
||||
|
||||
Use of this modules assumes that wrapped methods be coded to cache their
|
||||
values in a consistent way. In particular, it requires that the class uses a
|
||||
dictionary named "_memo" to store the cached values.
|
||||
|
||||
Here is an example of wrapping a method that returns a computed value,
|
||||
with no input parameters::
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def foo(self):
|
||||
|
||||
try: # Memoization
|
||||
return self._memo['foo'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_foo_value()
|
||||
|
||||
self._memo['foo'] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
Here is an example of wrapping a method that will return different values
|
||||
based on one or more input arguments::
|
||||
|
||||
def _bar_key(self, argument): # Memoization
|
||||
return argument # Memoization
|
||||
|
||||
@SCons.Memoize.CountDictCall(_bar_key)
|
||||
def bar(self, argument):
|
||||
|
||||
memo_key = argument # Memoization
|
||||
try: # Memoization
|
||||
memo_dict = self._memo['bar'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
memo_dict = {} # Memoization
|
||||
self._memo['dict'] = memo_dict # Memoization
|
||||
else: # Memoization
|
||||
try: # Memoization
|
||||
return memo_dict[memo_key] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_bar_value(argument)
|
||||
|
||||
memo_dict[memo_key] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
Deciding what to cache is tricky, because different configurations
|
||||
can have radically different performance tradeoffs, and because the
|
||||
tradeoffs involved are often so non-obvious. Consequently, deciding
|
||||
whether or not to cache a given method will likely be more of an art than
|
||||
a science, but should still be based on available data from this module.
|
||||
Here are some VERY GENERAL guidelines about deciding whether or not to
|
||||
cache return values from a method that's being called a lot:
|
||||
|
||||
-- The first question to ask is, "Can we change the calling code
|
||||
so this method isn't called so often?" Sometimes this can be
|
||||
done by changing the algorithm. Sometimes the *caller* should
|
||||
be memoized, not the method you're looking at.
|
||||
|
||||
-- The memoized function should be timed with multiple configurations
|
||||
to make sure it doesn't inadvertently slow down some other
|
||||
configuration.
|
||||
|
||||
-- When memoizing values based on a dictionary key composed of
|
||||
input arguments, you don't need to use all of the arguments
|
||||
if some of them don't affect the return values.
|
||||
|
||||
"""
|
||||
|
||||
# A flag controlling whether or not we actually use memoization.
|
||||
use_memoizer = None
|
||||
|
||||
# Global list of counter objects
|
||||
CounterList = {}
|
||||
|
||||
class Counter:
|
||||
"""
|
||||
Base class for counting memoization hits and misses.
|
||||
|
||||
We expect that the initialization in a matching decorator will
|
||||
fill in the correct class name and method name that represents
|
||||
the name of the function being counted.
|
||||
"""
|
||||
def __init__(self, cls_name, method_name):
|
||||
"""
|
||||
"""
|
||||
self.cls_name = cls_name
|
||||
self.method_name = method_name
|
||||
self.hit = 0
|
||||
self.miss = 0
|
||||
def key(self):
|
||||
return self.cls_name+'.'+self.method_name
|
||||
def display(self):
|
||||
print(f" {self.hit:7d} hits {self.miss:7d} misses {self.key()}()")
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.key() == other.key()
|
||||
except AttributeError:
|
||||
return True
|
||||
|
||||
class CountValue(Counter):
|
||||
"""
|
||||
A counter class for simple, atomic memoized values.
|
||||
|
||||
A CountValue object should be instantiated in a decorator for each of
|
||||
the class's methods that memoizes its return value by simply storing
|
||||
the return value in its _memo dictionary.
|
||||
"""
|
||||
def count(self, *args, **kw):
|
||||
""" Counts whether the memoized value has already been
|
||||
set (a hit) or not (a miss).
|
||||
"""
|
||||
obj = args[0]
|
||||
if self.method_name in obj._memo:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
|
||||
class CountDict(Counter):
|
||||
"""
|
||||
A counter class for memoized values stored in a dictionary, with
|
||||
keys based on the method's input arguments.
|
||||
|
||||
A CountDict object is instantiated in a decorator for each of the
|
||||
class's methods that memoizes its return value in a dictionary,
|
||||
indexed by some key that can be computed from one or more of
|
||||
its input arguments.
|
||||
"""
|
||||
def __init__(self, cls_name, method_name, keymaker):
|
||||
"""
|
||||
"""
|
||||
super().__init__(cls_name, method_name)
|
||||
self.keymaker = keymaker
|
||||
def count(self, *args, **kw):
|
||||
""" Counts whether the computed key value is already present
|
||||
in the memoization dictionary (a hit) or not (a miss).
|
||||
"""
|
||||
obj = args[0]
|
||||
try:
|
||||
memo_dict = obj._memo[self.method_name]
|
||||
except KeyError:
|
||||
self.miss = self.miss + 1
|
||||
else:
|
||||
key = self.keymaker(*args, **kw)
|
||||
if key in memo_dict:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
|
||||
def Dump(title=None):
|
||||
""" Dump the hit/miss count for all the counters
|
||||
collected so far.
|
||||
"""
|
||||
if title:
|
||||
print(title)
|
||||
for counter in sorted(CounterList):
|
||||
CounterList[counter].display()
|
||||
|
||||
def EnableMemoization():
|
||||
global use_memoizer
|
||||
use_memoizer = 1
|
||||
|
||||
def CountMethodCall(fn):
|
||||
""" Decorator for counting memoizer hits/misses while retrieving
|
||||
a simple value in a class method. It wraps the given method
|
||||
fn and uses a CountValue object to keep track of the
|
||||
caching statistics.
|
||||
Wrapping gets enabled by calling EnableMemoization().
|
||||
"""
|
||||
if use_memoizer:
|
||||
def wrapper(self, *args, **kwargs):
|
||||
global CounterList
|
||||
key = self.__class__.__name__+'.'+fn.__name__
|
||||
if key not in CounterList:
|
||||
CounterList[key] = CountValue(self.__class__.__name__, fn.__name__)
|
||||
CounterList[key].count(self, *args, **kwargs)
|
||||
return fn(self, *args, **kwargs)
|
||||
wrapper.__name__= fn.__name__
|
||||
return wrapper
|
||||
else:
|
||||
return fn
|
||||
|
||||
def CountDictCall(keyfunc):
|
||||
""" Decorator for counting memoizer hits/misses while accessing
|
||||
dictionary values with a key-generating function. Like
|
||||
CountMethodCall above, it wraps the given method
|
||||
fn and uses a CountDict object to keep track of the
|
||||
caching statistics. The dict-key function keyfunc has to
|
||||
get passed in the decorator call and gets stored in the
|
||||
CountDict instance.
|
||||
Wrapping gets enabled by calling EnableMemoization().
|
||||
"""
|
||||
def decorator(fn):
|
||||
if use_memoizer:
|
||||
def wrapper(self, *args, **kwargs):
|
||||
global CounterList
|
||||
key = self.__class__.__name__+'.'+fn.__name__
|
||||
if key not in CounterList:
|
||||
CounterList[key] = CountDict(self.__class__.__name__, fn.__name__, keyfunc)
|
||||
CounterList[key].count(self, *args, **kwargs)
|
||||
return fn(self, *args, **kwargs)
|
||||
wrapper.__name__= fn.__name__
|
||||
return wrapper
|
||||
else:
|
||||
return fn
|
||||
return decorator
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
150
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/Alias.py
Normal file
150
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/Alias.py
Normal file
@@ -0,0 +1,150 @@
|
||||
# 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.
|
||||
|
||||
"""Alias nodes.
|
||||
|
||||
This creates a hash of global Aliases (dummy targets).
|
||||
"""
|
||||
|
||||
import collections
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
from SCons.Util import hash_signature
|
||||
|
||||
class AliasNameSpace(collections.UserDict):
|
||||
def Alias(self, name, **kw):
|
||||
if isinstance(name, SCons.Node.Alias.Alias):
|
||||
return name
|
||||
try:
|
||||
a = self[name]
|
||||
except KeyError:
|
||||
a = SCons.Node.Alias.Alias(name, **kw)
|
||||
self[name] = a
|
||||
return a
|
||||
|
||||
def lookup(self, name, **kw):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
class AliasNodeInfo(SCons.Node.NodeInfoBase):
|
||||
__slots__ = ('csig',)
|
||||
current_version_id = 2
|
||||
field_list = ['csig']
|
||||
def str_to_node(self, s):
|
||||
return default_ans.Alias(s)
|
||||
|
||||
class AliasBuildInfo(SCons.Node.BuildInfoBase):
|
||||
__slots__ = ()
|
||||
current_version_id = 2
|
||||
|
||||
class Alias(SCons.Node.Node):
|
||||
|
||||
NodeInfo = AliasNodeInfo
|
||||
BuildInfo = AliasBuildInfo
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self.changed_since_last_build = 1
|
||||
self.store_info = 0
|
||||
|
||||
def str_for_display(self):
|
||||
return '"' + self.__str__() + '"'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def make_ready(self):
|
||||
self.get_csig()
|
||||
|
||||
really_build = SCons.Node.Node.build
|
||||
is_up_to_date = SCons.Node.Node.children_are_up_to_date
|
||||
|
||||
def is_under(self, dir):
|
||||
# Make Alias nodes get built regardless of
|
||||
# what directory scons was run from. Alias nodes
|
||||
# are outside the filesystem:
|
||||
return True
|
||||
|
||||
def get_contents(self):
|
||||
"""The contents of an alias is the concatenation
|
||||
of the content signatures of all its sources."""
|
||||
childsigs = [n.get_csig() for n in self.children()]
|
||||
return ''.join(childsigs)
|
||||
|
||||
def sconsign(self):
|
||||
"""An Alias is not recorded in .sconsign files"""
|
||||
pass
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def build(self, **kw):
|
||||
"""A "builder" for aliases."""
|
||||
if len(self.executor.post_actions) + len(self.executor.pre_actions) > 0:
|
||||
# Only actually call Node's build() if there are any
|
||||
# pre or post actions.
|
||||
# Alias nodes will get 1 action and Alias.build()
|
||||
# This fixes GH Issue #2281
|
||||
return self.really_build(**kw)
|
||||
|
||||
|
||||
def convert(self):
|
||||
try: del self.builder
|
||||
except AttributeError: pass
|
||||
self.reset_executor()
|
||||
self.build = self.really_build
|
||||
|
||||
def get_csig(self):
|
||||
"""
|
||||
Generate a node's content signature, the digested signature
|
||||
of its content.
|
||||
|
||||
node - the node
|
||||
cache - alternate node to use for the signature cache
|
||||
returns - the content signature
|
||||
"""
|
||||
try:
|
||||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
contents = self.get_contents()
|
||||
csig = hash_signature(contents)
|
||||
self.get_ninfo().csig = csig
|
||||
return csig
|
||||
|
||||
default_ans = AliasNameSpace()
|
||||
|
||||
SCons.Node.arg2nodes_lookups.append(default_ans.lookup)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
3861
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/FS.py
Normal file
3861
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/FS.py
Normal file
File diff suppressed because it is too large
Load Diff
1807
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/__init__.py
Normal file
1807
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Node/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
227
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/PathList.py
Normal file
227
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/PathList.py
Normal file
@@ -0,0 +1,227 @@
|
||||
# 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.
|
||||
|
||||
"""Handle lists of directory paths.
|
||||
|
||||
These are the path lists that get set as ``CPPPATH``, ``LIBPATH``,
|
||||
etc.) with as much caching of data and efficiency as we can, while
|
||||
still keeping the evaluation delayed so that we Do the Right Thing
|
||||
(almost) regardless of how the variable is specified.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Memoize
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
|
||||
#
|
||||
# Variables to specify the different types of entries in a PathList object:
|
||||
#
|
||||
|
||||
TYPE_STRING_NO_SUBST = 0 # string with no '$'
|
||||
TYPE_STRING_SUBST = 1 # string containing '$'
|
||||
TYPE_OBJECT = 2 # other object
|
||||
|
||||
def node_conv(obj):
|
||||
"""
|
||||
This is the "string conversion" routine that we have our substitutions
|
||||
use to return Nodes, not strings. This relies on the fact that an
|
||||
:class:`~SCons.Node.FS.EntryProxy` object has a ``get()`` method that
|
||||
returns the underlying Node that it wraps, which is a bit of
|
||||
architectural dependence that we might need to break or modify in the
|
||||
future in response to additional requirements.
|
||||
"""
|
||||
try:
|
||||
get = obj.get
|
||||
except AttributeError:
|
||||
if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ):
|
||||
result = obj
|
||||
else:
|
||||
result = str(obj)
|
||||
else:
|
||||
result = get()
|
||||
return result
|
||||
|
||||
class _PathList:
|
||||
"""An actual PathList object.
|
||||
|
||||
Initializes a :class:`PathList` object, canonicalizing the input and
|
||||
pre-processing it for quicker substitution later.
|
||||
|
||||
The stored representation of the :class:`PathList` is a list of tuples
|
||||
containing (type, value), where the "type" is one of the ``TYPE_*``
|
||||
variables defined above. We distinguish between:
|
||||
|
||||
* Strings that contain no ``$`` and therefore need no
|
||||
delayed-evaluation string substitution (we expect that there
|
||||
will be many of these and that we therefore get a pretty
|
||||
big win from avoiding string substitution)
|
||||
|
||||
* Strings that contain ``$`` and therefore need substitution
|
||||
(the hard case is things like ``${TARGET.dir}/include``,
|
||||
which require re-evaluation for every target + source)
|
||||
|
||||
* Other objects (which may be something like an
|
||||
:class:`~SCons.Node.FS.EntryProxy`
|
||||
that needs a method called to return a Node)
|
||||
|
||||
Pre-identifying the type of each element in the :class:`PathList`
|
||||
up-front and storing the type in the list of tuples is intended to
|
||||
reduce the amount of calculation when we actually do the substitution
|
||||
over and over for each target.
|
||||
"""
|
||||
|
||||
def __init__(self, pathlist, split=True):
|
||||
if SCons.Util.is_String(pathlist):
|
||||
if split:
|
||||
pathlist = pathlist.split(os.pathsep)
|
||||
else: # no splitting, but still need a list
|
||||
pathlist = [pathlist]
|
||||
elif not SCons.Util.is_Sequence(pathlist):
|
||||
pathlist = [pathlist]
|
||||
|
||||
pl = []
|
||||
for p in pathlist:
|
||||
try:
|
||||
found = '$' in p
|
||||
except (AttributeError, TypeError):
|
||||
type = TYPE_OBJECT
|
||||
else:
|
||||
if not found:
|
||||
type = TYPE_STRING_NO_SUBST
|
||||
else:
|
||||
type = TYPE_STRING_SUBST
|
||||
pl.append((type, p))
|
||||
|
||||
self.pathlist = tuple(pl)
|
||||
|
||||
def __len__(self): return len(self.pathlist)
|
||||
|
||||
def __getitem__(self, i): return self.pathlist[i]
|
||||
|
||||
def subst_path(self, env, target, source):
|
||||
"""
|
||||
Performs construction variable substitution on a pre-digested
|
||||
PathList for a specific target and source.
|
||||
"""
|
||||
result = []
|
||||
for type, value in self.pathlist:
|
||||
if type == TYPE_STRING_SUBST:
|
||||
value = env.subst(value, target=target, source=source,
|
||||
conv=node_conv)
|
||||
if SCons.Util.is_Sequence(value):
|
||||
result.extend(SCons.Util.flatten(value))
|
||||
elif value:
|
||||
result.append(value)
|
||||
elif type == TYPE_OBJECT:
|
||||
value = node_conv(value)
|
||||
if value:
|
||||
result.append(value)
|
||||
elif value:
|
||||
result.append(value)
|
||||
return tuple(result)
|
||||
|
||||
|
||||
class PathListCache:
|
||||
"""A class to handle caching of PathList lookups.
|
||||
|
||||
This class gets instantiated once and then deleted from the namespace,
|
||||
so it's used as a Singleton (although we don't enforce that in the
|
||||
usual Pythonic ways). We could have just made the cache a dictionary
|
||||
in the module namespace, but putting it in this class allows us to
|
||||
use the same Memoizer pattern that we use elsewhere to count cache
|
||||
hits and misses, which is very valuable.
|
||||
|
||||
Lookup keys in the cache are computed by the :meth:`_PathList_key` method.
|
||||
Cache lookup should be quick, so we don't spend cycles canonicalizing
|
||||
all forms of the same lookup key. For example, ``x:y`` and ``['x', 'y']``
|
||||
logically represent the same list, but we don't bother to
|
||||
split string representations and treat those two equivalently.
|
||||
(Note, however, that we do, treat lists and tuples the same.)
|
||||
|
||||
The main type of duplication we're trying to catch will come from
|
||||
looking up the same path list from two different clones of the
|
||||
same construction environment. That is, given::
|
||||
|
||||
env2 = env1.Clone()
|
||||
|
||||
both ``env1`` and ``env2`` will have the same ``CPPPATH`` value, and we can
|
||||
cheaply avoid re-parsing both values of ``CPPPATH`` by using the
|
||||
common value from this cache.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._memo = {}
|
||||
|
||||
def _PathList_key(self, pathlist):
|
||||
"""Returns the key for memoization of PathLists.
|
||||
|
||||
Note that we want this to be pretty quick, so we don't completely
|
||||
canonicalize all forms of the same list. For example,
|
||||
``dir1:$ROOT/dir2`` and ``['$ROOT/dir1', 'dir']`` may logically
|
||||
represent the same list if you're executing from ``$ROOT``, but
|
||||
we're not going to bother splitting strings into path elements,
|
||||
or massaging strings into Nodes, to identify that equivalence.
|
||||
We just want to eliminate obvious redundancy from the normal
|
||||
case of re-using exactly the same cloned value for a path.
|
||||
"""
|
||||
if SCons.Util.is_Sequence(pathlist):
|
||||
pathlist = tuple(SCons.Util.flatten(pathlist))
|
||||
return pathlist
|
||||
|
||||
@SCons.Memoize.CountDictCall(_PathList_key)
|
||||
def PathList(self, pathlist, split=True):
|
||||
"""Entry point for getting PathLists.
|
||||
|
||||
Returns the cached :class:`_PathList` object for the specified
|
||||
pathlist, creating and caching a new object as necessary.
|
||||
"""
|
||||
pathlist = self._PathList_key(pathlist)
|
||||
try:
|
||||
memo_dict = self._memo['PathList']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['PathList'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[pathlist]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
result = _PathList(pathlist, split)
|
||||
|
||||
memo_dict[pathlist] = result
|
||||
|
||||
return result
|
||||
|
||||
PathList = PathListCache().PathList
|
||||
|
||||
# TODO: removing the class object here means Sphinx doesn't pick up its
|
||||
# docstrings: they're fine for reading here, but are not in API Docs.
|
||||
del PathListCache
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,381 @@
|
||||
# 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.
|
||||
|
||||
"""SCons platform selection.
|
||||
|
||||
Looks for modules that define a callable object that can modify a
|
||||
construction environment as appropriate for a given platform.
|
||||
|
||||
Note that we take a more simplistic view of "platform" than Python does.
|
||||
We're looking for a single string that determines a set of
|
||||
tool-independent variables with which to initialize a construction
|
||||
environment. Consequently, we'll examine both sys.platform and os.name
|
||||
(and anything else that might come in to play) in order to return some
|
||||
specification which is unique enough for our purposes.
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "platform specification" in an arbitrary callable function.
|
||||
No one needs to use or tie in to this subsystem in order to roll
|
||||
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():
|
||||
r"""Return the platform string for our execution environment.
|
||||
|
||||
The returned value should map to one of the SCons/Platform/\*.py
|
||||
files. Since scons is architecture independent, though, we don't
|
||||
care about the machine architecture.
|
||||
"""
|
||||
osname = os.name
|
||||
if osname == 'java':
|
||||
osname = os._osType
|
||||
if osname == 'posix':
|
||||
if sys.platform == 'cygwin':
|
||||
return 'cygwin'
|
||||
elif 'irix' in sys.platform:
|
||||
return 'irix'
|
||||
elif 'sunos' in sys.platform:
|
||||
return 'sunos'
|
||||
elif 'hp-ux' in sys.platform:
|
||||
return 'hpux'
|
||||
elif 'aix' in sys.platform:
|
||||
return 'aix'
|
||||
elif 'darwin' in sys.platform:
|
||||
return 'darwin'
|
||||
else:
|
||||
return 'posix'
|
||||
elif os.name == 'os2':
|
||||
return 'os2'
|
||||
else:
|
||||
return sys.platform
|
||||
|
||||
|
||||
def platform_module(name=platform_default()):
|
||||
"""Return the imported module for the platform.
|
||||
|
||||
This looks for a module name that matches the specified argument.
|
||||
If the name is unspecified, we fetch the appropriate default for
|
||||
our execution environment.
|
||||
"""
|
||||
full_name = 'SCons.Platform.' + name
|
||||
try:
|
||||
return sys.modules[full_name]
|
||||
except KeyError:
|
||||
try:
|
||||
# the specific platform module is a relative import
|
||||
mod = importlib.import_module("." + name, __name__)
|
||||
except ModuleNotFoundError:
|
||||
try:
|
||||
# This support was added to enable running inside
|
||||
# a py2exe bundle a long time ago - unclear if it's
|
||||
# still needed. It is *not* intended to load individual
|
||||
# platform modules stored in a zipfile.
|
||||
import zipimport
|
||||
|
||||
platform = sys.modules['SCons.Platform'].__path__[0]
|
||||
importer = zipimport.zipimporter(platform)
|
||||
if not hasattr(importer, 'find_spec'):
|
||||
# zipimport only added find_spec, exec_module in 3.10,
|
||||
# unlike importlib, where they've been around since 3.4.
|
||||
# If we don't have 'em, use the old way.
|
||||
mod = importer.load_module(full_name)
|
||||
else:
|
||||
spec = importer.find_spec(full_name)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
importer.exec_module(mod)
|
||||
sys.modules[full_name] = mod
|
||||
except zipimport.ZipImportError:
|
||||
raise SCons.Errors.UserError("No platform named '%s'" % name)
|
||||
|
||||
setattr(SCons.Platform, name, mod)
|
||||
return mod
|
||||
|
||||
|
||||
def DefaultToolList(platform, env):
|
||||
"""Select a default tool list for the specified platform."""
|
||||
return SCons.Tool.tool_list(platform, env)
|
||||
|
||||
|
||||
class PlatformSpec:
|
||||
def __init__(self, name, generate):
|
||||
self.name = name
|
||||
self.generate = generate
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
return self.generate(*args, **kw)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class TempFileMunge:
|
||||
"""Convert long command lines to use a temporary file.
|
||||
|
||||
You can set an Environment variable (usually ``TEMPFILE``) to this,
|
||||
then call it with a string argument, and it will perform temporary
|
||||
file substitution on it. This is used to circumvent limitations on
|
||||
the length of command lines. Example::
|
||||
|
||||
env["TEMPFILE"] = TempFileMunge
|
||||
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES', '$LINKCOMSTR')}"
|
||||
|
||||
By default, the name of the temporary file used begins with a
|
||||
prefix of '@'. This may be configured for other tool chains by
|
||||
setting the ``TEMPFILEPREFIX`` variable. Example::
|
||||
|
||||
env["TEMPFILEPREFIX"] = '-@' # diab compiler
|
||||
env["TEMPFILEPREFIX"] = '-via' # arm tool chain
|
||||
env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint
|
||||
|
||||
You can configure the extension of the temporary file through the
|
||||
``TEMPFILESUFFIX`` variable, which defaults to '.lnk' (see comments
|
||||
in the code below). Example::
|
||||
|
||||
env["TEMPFILESUFFIX"] = '.lnt' # PC Lint
|
||||
|
||||
Entries in the temporary file are separated by the value of the
|
||||
``TEMPFILEARGJOIN`` variable, which defaults to an OS-appropriate value.
|
||||
|
||||
A default argument escape function is ``SCons.Subst.quote_spaces``.
|
||||
If you need to apply extra operations on a command argument before
|
||||
writing to a temporary file(fix Windows slashes, normalize paths, etc.),
|
||||
please set `TEMPFILEARGESCFUNC` variable to a custom function. Example::
|
||||
|
||||
import sys
|
||||
import re
|
||||
from SCons.Subst import quote_spaces
|
||||
|
||||
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
|
||||
|
||||
|
||||
def tempfile_arg_esc_func(arg):
|
||||
arg = quote_spaces(arg)
|
||||
if sys.platform != "win32":
|
||||
return arg
|
||||
# GCC requires double Windows slashes, let's use UNIX separator
|
||||
return WINPATHSEP_RE.sub(r"/\1", arg)
|
||||
|
||||
|
||||
env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func
|
||||
|
||||
"""
|
||||
def __init__(self, cmd, cmdstr = None):
|
||||
self.cmd = cmd
|
||||
self.cmdstr = cmdstr
|
||||
|
||||
def __call__(self, target, source, env, for_signature):
|
||||
if for_signature:
|
||||
# If we're being called for signature calculation, it's
|
||||
# because we're being called by the string expansion in
|
||||
# Subst.py, which has the logic to strip any $( $) that
|
||||
# may be in the command line we squirreled away. So we
|
||||
# just return the raw command line and let the upper
|
||||
# string substitution layers do their thing.
|
||||
return self.cmd
|
||||
|
||||
# Now we're actually being called because someone is actually
|
||||
# going to try to execute the command, so we have to do our
|
||||
# own expansion.
|
||||
cmd = env.subst_list(self.cmd, SCons.Subst.SUBST_CMD, target, source)[0]
|
||||
try:
|
||||
maxline = int(env.subst('$MAXLINELENGTH'))
|
||||
except ValueError:
|
||||
maxline = 2048
|
||||
|
||||
length = 0
|
||||
for c in cmd:
|
||||
length += len(c)
|
||||
length += len(cmd) - 1
|
||||
if length <= maxline:
|
||||
return self.cmd
|
||||
|
||||
# Check if we already created the temporary file for this target
|
||||
# It should have been previously done by Action.strfunction() call
|
||||
if SCons.Util.is_List(target):
|
||||
node = target[0]
|
||||
else:
|
||||
node = target
|
||||
|
||||
cmdlist = None
|
||||
|
||||
if SCons.Util.is_List(self.cmd):
|
||||
cmdlist_key = tuple(self.cmd)
|
||||
else:
|
||||
cmdlist_key = self.cmd
|
||||
|
||||
if node and hasattr(node.attributes, 'tempfile_cmdlist'):
|
||||
cmdlist = node.attributes.tempfile_cmdlist.get(cmdlist_key, None)
|
||||
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.
|
||||
if 'TEMPFILESUFFIX' in env:
|
||||
suffix = env.subst('$TEMPFILESUFFIX')
|
||||
else:
|
||||
suffix = '.lnk'
|
||||
|
||||
if 'TEMPFILEDIR' in env:
|
||||
tempfile_dir = env.subst('$TEMPFILEDIR')
|
||||
os.makedirs(tempfile_dir, exist_ok=True)
|
||||
else:
|
||||
tempfile_dir = None
|
||||
|
||||
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):
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.remove(file)
|
||||
|
||||
atexit.register(tmpfile_cleanup, tmp)
|
||||
|
||||
# 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
|
||||
# __call__() and strfunction() methods and lets the
|
||||
# normal action-execution logic handle whether or not to
|
||||
# print/execute the action. The problem, though, is all
|
||||
# of that is decided before we execute this method as
|
||||
# part of expanding the $TEMPFILE construction variable.
|
||||
# Consequently, refactoring this will have to wait until
|
||||
# we get more flexible with allowing Actions to exist
|
||||
# independently and get strung together arbitrarily like
|
||||
# Ant tasks. In the meantime, it's going to be more
|
||||
# user-friendly to not let obsession with architectural
|
||||
# purity get in the way of just being helpful, so we'll
|
||||
# reach into SCons.Action directly.
|
||||
if SCons.Action.print_actions:
|
||||
cmdstr = (
|
||||
env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target, source)
|
||||
if self.cmdstr is not None
|
||||
else ''
|
||||
)
|
||||
# Print our message only if XXXCOMSTR returns an empty string
|
||||
if not cmdstr:
|
||||
cmdstr = (
|
||||
f"Using tempfile {native_tmp} for command line:\n"
|
||||
f'{cmd[0]} {" ".join(args)}'
|
||||
)
|
||||
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 separate temporary files for print and execute.
|
||||
if node is not None:
|
||||
try:
|
||||
# Storing in tempfile_cmdlist by self.cmd provided when intializing
|
||||
# $TEMPFILE{} fixes issue raised in PR #3140 and #3553
|
||||
node.attributes.tempfile_cmdlist[cmdlist_key] = cmdlist
|
||||
except AttributeError:
|
||||
node.attributes.tempfile_cmdlist = {cmdlist_key: cmdlist}
|
||||
|
||||
return cmdlist
|
||||
|
||||
def _print_cmd_str(self, target, source, env, cmdstr):
|
||||
# check if the user has specified a cmd line print function
|
||||
print_func = None
|
||||
try:
|
||||
get = env.get
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
print_func = get('PRINT_CMD_LINE_FUNC')
|
||||
|
||||
# use the default action cmd line print if user did not supply one
|
||||
if not print_func:
|
||||
action = SCons.Action._ActionAction()
|
||||
action.print_cmd_line(cmdstr, target, source, env)
|
||||
else:
|
||||
print_func(cmdstr, target, source, env)
|
||||
|
||||
|
||||
def Platform(name = platform_default()):
|
||||
"""Select a canned Platform specification."""
|
||||
|
||||
module = platform_module(name)
|
||||
spec = PlatformSpec(name, module.generate)
|
||||
return spec
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,80 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for IBM AIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from subprocess import PIPE
|
||||
|
||||
from . import posix
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Action
|
||||
|
||||
def get_xlc(env, xlc=None, packages=[]):
|
||||
# Use the AIX package installer tool lslpp to figure out where a
|
||||
# given xl* compiler is installed and what version it is.
|
||||
xlcPath = None
|
||||
xlcVersion = None
|
||||
|
||||
if xlc is None:
|
||||
xlc = env.get('CC', 'xlc')
|
||||
if SCons.Util.is_List(xlc):
|
||||
xlc = xlc[0]
|
||||
for package in packages:
|
||||
# find the installed filename, which may be a symlink as well
|
||||
cp = SCons.Action.scons_subproc_run(
|
||||
env, ['lslpp', '-fc', package], universal_newlines=True, stdout=PIPE
|
||||
)
|
||||
# output of lslpp is something like this:
|
||||
# #Path:Fileset:File
|
||||
# /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/exe/xlCcpp
|
||||
# /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/bin/xlc_r -> /usr/vac/bin/xlc
|
||||
for line in cp.stdout.splitlines():
|
||||
if xlcPath:
|
||||
continue # read everything to let lslpp terminate
|
||||
fileset, filename = line.split(':')[1:3]
|
||||
filename = filename.split()[0]
|
||||
if ('/' in xlc and filename == xlc) or (
|
||||
'/' not in xlc and filename.endswith('/' + xlc)
|
||||
):
|
||||
xlcVersion = fileset.split()[1]
|
||||
xlcPath, sep, xlc = filename.rpartition('/')
|
||||
return (xlcPath, xlc, xlcVersion)
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 21576
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
env['HOST_OS'] = 'aix'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -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.
|
||||
|
||||
"""Platform-specific initialization for Cygwin systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from . import posix
|
||||
from SCons.Platform import TempFileMunge
|
||||
|
||||
CYGWIN_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
CYGWIN_DEFAULT_PATHS = [
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\cygwin\bin'
|
||||
]
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = ['$LIBPREFIX', '$SHLIBPREFIX', '$IMPLIBPREFIX']
|
||||
env['LIBSUFFIXES'] = ['$LIBSUFFIX', '$SHLIBSUFFIX', '$IMPLIBSUFFIX']
|
||||
env['LIBLITERAPPREFIX'] = ':'
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
env['MAXLINELENGTH'] = 2048
|
||||
env['HOST_OS'] = 'cygwin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,71 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for Mac OS X systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
import os
|
||||
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
env['SHLIBSUFFIX'] = '.dylib'
|
||||
env['HOST_OS'] = 'darwin'
|
||||
# put macports paths at front to override Apple's versions, fink path is after
|
||||
# For now let people who want Macports or Fink tools specify it!
|
||||
# env['ENV']['PATH'] = '/opt/local/bin:/opt/local/sbin:' + env['ENV']['PATH'] + ':/sw/bin'
|
||||
|
||||
# Store extra system paths in env['ENV']['PATHOSX']
|
||||
|
||||
filelist = ['/etc/paths',]
|
||||
# make sure this works on Macs with Tiger or earlier
|
||||
try:
|
||||
dirlist = os.listdir('/etc/paths.d')
|
||||
except (FileNotFoundError, PermissionError):
|
||||
dirlist = []
|
||||
|
||||
for file in dirlist:
|
||||
filelist.append('/etc/paths.d/'+file)
|
||||
|
||||
for file in filelist:
|
||||
if os.path.isfile(file):
|
||||
with open(file) as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line:
|
||||
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
||||
|
||||
# Not sure why this wasn't the case all along?
|
||||
if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
|
||||
env.AppendENVPath('PATH',env['ENV']['PATHOSX'])
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,45 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for HP-UX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 2045000
|
||||
|
||||
env['SHLIBSUFFIX'] = '.sl'
|
||||
env['HOST_OS'] = 'hpux'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,41 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for SGI IRIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import posix
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
env['HOST_OS'] = 'irix'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,35 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for the MinGW system."""
|
||||
|
||||
import sys
|
||||
|
||||
MINGW_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
MINGW_DEFAULT_PATHS = [
|
||||
r'C:\msys64',
|
||||
r'C:\msys64\usr\bin',
|
||||
r'C:\msys',
|
||||
r'C:\msys\usr\bin'
|
||||
]
|
||||
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for OS/2 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
from . import win32
|
||||
|
||||
def generate(env):
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.obj'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['LIBPREFIX'] = ''
|
||||
env['LIBSUFFIX'] = '.lib'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = ['$LIBPREFIX']
|
||||
env['LIBSUFFIXES'] = ['$LIBSUFFIX', '$SHLIBSUFFIX']
|
||||
env['LIBLITERAPPREFIX'] = ''
|
||||
env['HOST_OS'] = 'os2'
|
||||
env['HOST_ARCH'] = win32.get_architecture().arch
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,125 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
|
||||
exitvalmap = {
|
||||
2 : 127,
|
||||
13 : 126,
|
||||
}
|
||||
|
||||
def escape(arg):
|
||||
"""escape shell special characters"""
|
||||
slash = '\\'
|
||||
special = '"$'
|
||||
|
||||
arg = arg.replace(slash, slash+slash)
|
||||
for c in special:
|
||||
arg = arg.replace(c, slash+c)
|
||||
|
||||
# print("ESCAPE RESULT: %s" % arg)
|
||||
return '"' + arg + '"'
|
||||
|
||||
|
||||
def exec_subprocess(l, env):
|
||||
proc = subprocess.Popen(l, env = env, close_fds = True)
|
||||
return proc.wait()
|
||||
|
||||
def subprocess_spawn(sh, escape, cmd, args, env):
|
||||
return exec_subprocess([sh, '-c', ' '.join(args)], env)
|
||||
|
||||
def exec_popen3(l, env, stdout, stderr):
|
||||
proc = subprocess.Popen(l, env = env, close_fds = True,
|
||||
stdout = stdout,
|
||||
stderr = stderr)
|
||||
return proc.wait()
|
||||
|
||||
def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||
# spawn using Popen3 combined with the env command
|
||||
# the command name and the command's stdout is written to stdout
|
||||
# the command's stderr is written to stderr
|
||||
return exec_popen3([sh, '-c', ' '.join(args)],
|
||||
env, stdout, stderr)
|
||||
|
||||
|
||||
def generate(env):
|
||||
# Bearing in mind we have python 2.4 as a baseline, we can just do this:
|
||||
spawn = subprocess_spawn
|
||||
pspawn = piped_env_spawn
|
||||
# Note that this means that 'escape' is no longer used
|
||||
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin:/snap/bin'
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.o'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = ''
|
||||
env['LIBPREFIX'] = 'lib'
|
||||
env['LIBSUFFIX'] = '.a'
|
||||
env['SHLIBPREFIX'] = '$LIBPREFIX'
|
||||
env['SHLIBSUFFIX'] = '.so'
|
||||
env['LIBPREFIXES'] = ['$LIBPREFIX']
|
||||
env['LIBSUFFIXES'] = ['$LIBSUFFIX', '$SHLIBSUFFIX']
|
||||
env['LIBLITERALPREFIX'] = ''
|
||||
env['HOST_OS'] = 'posix'
|
||||
env['HOST_ARCH'] = platform.machine()
|
||||
env['PSPAWN'] = pspawn
|
||||
env['SPAWN'] = spawn
|
||||
env['SHELL'] = 'sh'
|
||||
env['ESCAPE'] = escape
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
#Based on LINUX: ARG_MAX=ARG_MAX=131072 - 3000 for environment expansion
|
||||
#Note: specific platforms might rise or lower this value
|
||||
env['MAXLINELENGTH'] = 128072
|
||||
|
||||
# This platform supports RPATH specifications.
|
||||
env['__RPATH'] = '$_RPATH'
|
||||
|
||||
# GDC is GCC family, but DMD and LDC have different options.
|
||||
# Must be able to have GCC and DMD work in the same build, so:
|
||||
env['__DRPATH'] = '$_DRPATH'
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,135 @@
|
||||
# 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.
|
||||
|
||||
"""Platform support for a Python virtualenv.
|
||||
|
||||
This is support code, not a loadable Platform module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import SCons.Util
|
||||
|
||||
|
||||
virtualenv_enabled_by_default = False
|
||||
|
||||
|
||||
def _enable_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default)
|
||||
|
||||
|
||||
def _ignore_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_IGNORE_VIRTUALENV', False)
|
||||
|
||||
|
||||
enable_virtualenv = _enable_virtualenv_default()
|
||||
ignore_virtualenv = _ignore_virtualenv_default()
|
||||
|
||||
# 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():
|
||||
"""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):
|
||||
"""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):
|
||||
"""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:
|
||||
try:
|
||||
ENV[name] = os.environ[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _inject_venv_path(env, path_list=None):
|
||||
"""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):
|
||||
"""Filter *path_list*, returning values under the virtualenv."""
|
||||
if SCons.Util.is_String(path_list):
|
||||
path_list = path_list.split(os.path.pathsep)
|
||||
return [path for path in path_list if IsInVirtualenv(path)]
|
||||
|
||||
|
||||
def ImportVirtualenv(env):
|
||||
"""Add virtualenv information to *env*."""
|
||||
_inject_venv_variables(env)
|
||||
_inject_venv_path(env)
|
||||
|
||||
|
||||
def Virtualenv():
|
||||
"""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 ""
|
||||
|
||||
|
||||
def IsInVirtualenv(path):
|
||||
"""Check whether *path* is under the virtualenv's directory.
|
||||
|
||||
Returns ``False`` if not using a virtualenv.
|
||||
"""
|
||||
return _is_path_in(path, Virtualenv())
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,447 @@
|
||||
# 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.
|
||||
|
||||
"""Platform-specific initialization for Win32 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from SCons.Platform.posix import exitvalmap
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
import SCons.Util
|
||||
|
||||
CHOCO_DEFAULT_PATH = [
|
||||
r'C:\ProgramData\chocolatey\bin'
|
||||
]
|
||||
|
||||
if False:
|
||||
# Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile
|
||||
try:
|
||||
from ctypes import windll
|
||||
import shutil
|
||||
|
||||
CopyFile = windll.kernel32.CopyFileA
|
||||
SetFileTime = windll.kernel32.SetFileTime
|
||||
|
||||
_shutil_copy = shutil.copy
|
||||
_shutil_copy2 = shutil.copy2
|
||||
|
||||
shutil.copy2 = CopyFile
|
||||
|
||||
def win_api_copyfile(src,dst):
|
||||
CopyFile(src,dst)
|
||||
os.utime(dst)
|
||||
|
||||
shutil.copy = win_api_copyfile
|
||||
|
||||
except AttributeError:
|
||||
parallel_msg = \
|
||||
"Couldn't override shutil.copy or shutil.copy2 falling back to shutil defaults"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
import threading
|
||||
spawn_lock = threading.Lock()
|
||||
|
||||
# This locked version of spawnve works around a Windows
|
||||
# MSVCRT bug, because its spawnve is not thread-safe.
|
||||
# Without this, python can randomly crash while using -jN.
|
||||
# See the python bug at https://github.com/python/cpython/issues/50725
|
||||
# and SCons issue at https://github.com/SCons/scons/issues/2449
|
||||
def spawnve(mode, file, args, env):
|
||||
spawn_lock.acquire()
|
||||
try:
|
||||
if mode == os.P_WAIT:
|
||||
ret = os.spawnve(os.P_NOWAIT, file, args, env)
|
||||
else:
|
||||
ret = os.spawnve(mode, file, args, env)
|
||||
finally:
|
||||
spawn_lock.release()
|
||||
if mode == os.P_WAIT:
|
||||
pid, status = os.waitpid(ret, 0)
|
||||
ret = status >> 8
|
||||
return ret
|
||||
except ImportError:
|
||||
# Use the unsafe method of spawnve.
|
||||
# Please, don't try to optimize this try-except block
|
||||
# away by assuming that the threading module is always present.
|
||||
# In the test test/option-j.py we intentionally call SCons with
|
||||
# a fake threading.py that raises an import exception right away,
|
||||
# simulating a non-existent package.
|
||||
def spawnve(mode, file, args, env):
|
||||
return os.spawnve(mode, file, args, env)
|
||||
|
||||
# The upshot of all this is that, if you are using Python 1.5.2,
|
||||
# you had better have cmd or command.com in your PATH when you run
|
||||
# scons.
|
||||
|
||||
|
||||
def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||
# There is no direct way to do that in python. What we do
|
||||
# here should work for most cases:
|
||||
# In case stdout (stderr) is not redirected to a file,
|
||||
# we redirect it into a temporary file tmpFileStdout
|
||||
# (tmpFileStderr) and copy the contents of this file
|
||||
# to stdout (stderr) given in the argument
|
||||
# Note that because this will paste shell redirection syntax
|
||||
# into the cmdline, we have to call a shell to run the command,
|
||||
# even though that's a bit of a performance hit.
|
||||
if not sh:
|
||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||
return 127
|
||||
|
||||
# one temporary file for stdout and stderr
|
||||
tmpFileStdout, tmpFileStdoutName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStdout) # don't need open until the subproc is done
|
||||
tmpFileStderr, tmpFileStderrName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStderr)
|
||||
|
||||
# check if output is redirected
|
||||
stdoutRedirected = False
|
||||
stderrRedirected = False
|
||||
for arg in args:
|
||||
# are there more possibilities to redirect stdout ?
|
||||
if arg.startswith(">")or arg.startswith("1>"):
|
||||
stdoutRedirected = True
|
||||
# are there more possibilities to redirect stderr ?
|
||||
if arg.startswith("2>"):
|
||||
stderrRedirected = True
|
||||
|
||||
# redirect output of non-redirected streams to our tempfiles
|
||||
if not stdoutRedirected:
|
||||
args.append(">" + tmpFileStdoutName)
|
||||
if not stderrRedirected:
|
||||
args.append("2>" + tmpFileStderrName)
|
||||
|
||||
# actually do the spawn
|
||||
try:
|
||||
args = [sh, '/C', escape(' '.join(args))]
|
||||
ret = spawnve(os.P_WAIT, sh, args, env)
|
||||
except OSError as e:
|
||||
# catch any error
|
||||
try:
|
||||
ret = exitvalmap[e.errno]
|
||||
except KeyError:
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror))
|
||||
if stderr is not None:
|
||||
stderr.write("scons: %s: %s\n" % (cmd, e.strerror))
|
||||
|
||||
# copy child output from tempfiles to our streams
|
||||
# and do clean up stuff
|
||||
if stdout is not None and not stdoutRedirected:
|
||||
try:
|
||||
with open(tmpFileStdoutName, "rb") as tmpFileStdout:
|
||||
output = tmpFileStdout.read()
|
||||
stdout.write(output.decode('oem', "replace").replace("\r\n", "\n"))
|
||||
os.remove(tmpFileStdoutName)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if stderr is not None and not stderrRedirected:
|
||||
try:
|
||||
with open(tmpFileStderrName, "rb") as tmpFileStderr:
|
||||
errors = tmpFileStderr.read()
|
||||
stderr.write(errors.decode('oem', "replace").replace("\r\n", "\n"))
|
||||
os.remove(tmpFileStderrName)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def exec_spawn(l, env):
|
||||
try:
|
||||
result = spawnve(os.P_WAIT, l[0], l, env)
|
||||
except OSError as e:
|
||||
try:
|
||||
result = exitvalmap[e.errno]
|
||||
sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror))
|
||||
except KeyError:
|
||||
result = 127
|
||||
if len(l) > 2:
|
||||
if len(l[2]) < 1000:
|
||||
command = ' '.join(l[0:3])
|
||||
else:
|
||||
command = l[0]
|
||||
else:
|
||||
command = l[0]
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror))
|
||||
return result
|
||||
|
||||
|
||||
def spawn(sh, escape, cmd, args, env):
|
||||
if not sh:
|
||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||
return 127
|
||||
return exec_spawn([sh, '/C', escape(' '.join(args))], env)
|
||||
|
||||
# Windows does not allow special characters in file names anyway, so no
|
||||
# need for a complex escape function, we will just quote the arg, except
|
||||
# that "cmd /c" requires that if an argument ends with a backslash it
|
||||
# needs to be escaped so as not to interfere with closing double quote
|
||||
# that we add.
|
||||
def escape(x):
|
||||
if x[-1] == '\\':
|
||||
x = x + '\\'
|
||||
return '"' + x + '"'
|
||||
|
||||
# Get the windows system directory name
|
||||
_system_root = None
|
||||
|
||||
|
||||
def get_system_root():
|
||||
global _system_root
|
||||
if _system_root is not None:
|
||||
return _system_root
|
||||
|
||||
# A resonable default if we can't read the registry
|
||||
val = os.environ.get('SystemRoot', "C:\\WINDOWS")
|
||||
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows NT system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
except SCons.Util.RegError:
|
||||
try:
|
||||
# Okay, try the Windows 9x system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
_system_root = val
|
||||
return val
|
||||
|
||||
|
||||
def get_program_files_dir():
|
||||
"""
|
||||
Get the location of the program files directory
|
||||
Returns
|
||||
-------
|
||||
|
||||
"""
|
||||
# Now see if we can look in the registry...
|
||||
val = ''
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows Program Files directory
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
|
||||
except SCons.Util.RegError:
|
||||
val = ''
|
||||
|
||||
if val == '':
|
||||
# A reasonable default if we can't read the registry
|
||||
# (Actually, it's pretty reasonable even if we can :-)
|
||||
val = os.path.join(os.path.dirname(get_system_root()),"Program Files")
|
||||
|
||||
return val
|
||||
|
||||
|
||||
class ArchDefinition:
|
||||
"""
|
||||
Determine which windows CPU were running on.
|
||||
A class for defining architecture-specific settings and logic.
|
||||
"""
|
||||
def __init__(self, arch, synonyms=[]):
|
||||
self.arch = arch
|
||||
self.synonyms = synonyms
|
||||
|
||||
SupportedArchitectureList = [
|
||||
ArchDefinition(
|
||||
'x86',
|
||||
['i386', 'i486', 'i586', 'i686'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'x86_64',
|
||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'arm64',
|
||||
['ARM64', 'aarch64', 'AARCH64', 'AArch64'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'ia64',
|
||||
['IA64'],
|
||||
),
|
||||
]
|
||||
|
||||
SupportedArchitectureMap = {}
|
||||
for a in SupportedArchitectureList:
|
||||
SupportedArchitectureMap[a.arch] = a
|
||||
for s in a.synonyms:
|
||||
SupportedArchitectureMap[s] = a
|
||||
|
||||
|
||||
def get_architecture(arch=None):
|
||||
"""Returns the definition for the specified architecture string.
|
||||
|
||||
If no string is specified, the system default is returned (as defined
|
||||
by the registry PROCESSOR_ARCHITECTURE value, PROCESSOR_ARCHITEW6432
|
||||
environment variable, PROCESSOR_ARCHITECTURE environment variable, or
|
||||
the platform machine).
|
||||
"""
|
||||
if arch is None:
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'PROCESSOR_ARCHITECTURE')
|
||||
except SCons.Util.RegError:
|
||||
val = ''
|
||||
if val and val in SupportedArchitectureMap:
|
||||
arch = val
|
||||
if arch is None:
|
||||
arch = os.environ.get('PROCESSOR_ARCHITEW6432')
|
||||
if not arch:
|
||||
arch = os.environ.get('PROCESSOR_ARCHITECTURE')
|
||||
return SupportedArchitectureMap.get(arch, ArchDefinition(platform.machine(), [platform.machine()]))
|
||||
|
||||
|
||||
def generate(env):
|
||||
# Attempt to find cmd.exe (for WinNT/2k/XP) or
|
||||
# command.com for Win9x
|
||||
cmd_interp = ''
|
||||
# First see if we can look in the registry...
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows NT system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
cmd_interp = os.path.join(val, 'System32\\cmd.exe')
|
||||
except SCons.Util.RegError:
|
||||
try:
|
||||
# Okay, try the Windows 9x system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
cmd_interp = os.path.join(val, 'command.com')
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
# For the special case of not having access to the registry, we
|
||||
# use a temporary path and pathext to attempt to find the command
|
||||
# interpreter. If we fail, we try to find the interpreter through
|
||||
# the env's PATH. The problem with that is that it might not
|
||||
# contain an ENV and a PATH.
|
||||
if not cmd_interp:
|
||||
systemroot = get_system_root()
|
||||
tmp_path = systemroot + os.pathsep + \
|
||||
os.path.join(systemroot,'System32')
|
||||
tmp_pathext = '.com;.exe;.bat;.cmd'
|
||||
if 'PATHEXT' in os.environ:
|
||||
tmp_pathext = os.environ['PATHEXT']
|
||||
cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
|
||||
if not cmd_interp:
|
||||
cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
|
||||
|
||||
if not cmd_interp:
|
||||
cmd_interp = env.Detect('cmd')
|
||||
if not cmd_interp:
|
||||
cmd_interp = env.Detect('command')
|
||||
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
|
||||
# Import things from the external environment to the construction
|
||||
# environment's ENV. This is a potential slippery slope, because we
|
||||
# *don't* want to make builds dependent on the user's environment by
|
||||
# default. We're doing this for SystemRoot, though, because it's
|
||||
# needed for anything that uses sockets, and seldom changes, and
|
||||
# for SystemDrive because it's related.
|
||||
#
|
||||
# Weigh the impact carefully before adding other variables to this list.
|
||||
import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP', 'USERPROFILE']
|
||||
for var in import_env:
|
||||
v = os.environ.get(var)
|
||||
if v:
|
||||
env['ENV'][var] = v
|
||||
|
||||
if 'COMSPEC' not in env['ENV']:
|
||||
v = os.environ.get("COMSPEC")
|
||||
if v:
|
||||
env['ENV']['COMSPEC'] = v
|
||||
|
||||
env.AppendENVPath('PATH', get_system_root() + '\\System32')
|
||||
|
||||
env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.obj'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['LIBPREFIX'] = ''
|
||||
env['LIBSUFFIX'] = '.lib'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = ['$LIBPREFIX']
|
||||
env['LIBSUFFIXES'] = ['$LIBSUFFIX']
|
||||
env['LIBLITERALPREFIX'] = ''
|
||||
env['PSPAWN'] = piped_spawn
|
||||
env['SPAWN'] = spawn
|
||||
env['SHELL'] = cmd_interp
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
env['MAXLINELENGTH'] = 2048
|
||||
env['ESCAPE'] = escape
|
||||
|
||||
env['HOST_OS'] = 'win32'
|
||||
env['HOST_ARCH'] = get_architecture().arch
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
1174
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/SConf.py
Normal file
1174
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/SConf.py
Normal file
File diff suppressed because it is too large
Load Diff
442
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/SConsign.py
Normal file
442
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/SConsign.py
Normal file
@@ -0,0 +1,442 @@
|
||||
# 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.
|
||||
|
||||
"""Operations on signature database files (.sconsign). """
|
||||
|
||||
import SCons.compat # pylint: disable=wrong-import-order
|
||||
|
||||
import os
|
||||
import pickle
|
||||
import time
|
||||
|
||||
import SCons.dblite
|
||||
import SCons.Warnings
|
||||
from SCons.compat import PICKLE_PROTOCOL
|
||||
from SCons.Util import print_time
|
||||
|
||||
|
||||
def corrupt_dblite_warning(filename):
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s" % filename,
|
||||
)
|
||||
|
||||
SCons.dblite.IGNORE_CORRUPT_DBFILES = True
|
||||
SCons.dblite.corruption_warning = corrupt_dblite_warning
|
||||
|
||||
# XXX Get rid of the global array so this becomes re-entrant.
|
||||
sig_files = []
|
||||
|
||||
# Info for the database SConsign implementation (now the default):
|
||||
# "DataBase" is a dictionary that maps top-level SConstruct directories
|
||||
# to open database handles.
|
||||
# "DB_Module" is the Python database module to create the handles.
|
||||
# "DB_Name" is the base name of the database file (minus any
|
||||
# extension the underlying DB module will add).
|
||||
DataBase = {}
|
||||
DB_Module = SCons.dblite
|
||||
DB_Name = None
|
||||
DB_sync_list = []
|
||||
|
||||
def current_sconsign_filename():
|
||||
hash_format = SCons.Util.get_hash_format()
|
||||
current_hash_algorithm = SCons.Util.get_current_hash_algorithm_used()
|
||||
# if the user left the options defaulted AND the default algorithm set by
|
||||
# SCons is md5, then set the database name to be the special default name
|
||||
#
|
||||
# otherwise, if it defaults to something like 'sha1' or the user explicitly
|
||||
# set 'md5' as the hash format, set the database name to .sconsign_<algorithm>
|
||||
# eg .sconsign_sha1, etc.
|
||||
if hash_format is None and current_hash_algorithm == 'md5':
|
||||
return ".sconsign"
|
||||
return ".sconsign_" + current_hash_algorithm
|
||||
|
||||
def Get_DataBase(dir):
|
||||
global DB_Name
|
||||
|
||||
if DB_Name is None:
|
||||
DB_Name = current_sconsign_filename()
|
||||
|
||||
top = dir.fs.Top
|
||||
if not os.path.isabs(DB_Name) and top.repositories:
|
||||
mode = "c"
|
||||
for d in [top] + top.repositories:
|
||||
if dir.is_under(d):
|
||||
try:
|
||||
return DataBase[d], mode
|
||||
except KeyError:
|
||||
path = d.entry_abspath(DB_Name)
|
||||
try: db = DataBase[d] = DB_Module.open(path, mode)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
if mode != "r":
|
||||
DB_sync_list.append(db)
|
||||
return db, mode
|
||||
mode = "r"
|
||||
try:
|
||||
return DataBase[top], "c"
|
||||
except KeyError:
|
||||
db = DataBase[top] = DB_Module.open(DB_Name, "c")
|
||||
DB_sync_list.append(db)
|
||||
return db, "c"
|
||||
except TypeError:
|
||||
print("DataBase =", DataBase)
|
||||
raise
|
||||
|
||||
|
||||
def Reset():
|
||||
"""Reset global state. Used by unit tests that end up using
|
||||
SConsign multiple times to get a clean slate for each test."""
|
||||
global sig_files, DB_sync_list
|
||||
sig_files = []
|
||||
DB_sync_list = []
|
||||
|
||||
|
||||
normcase = os.path.normcase
|
||||
|
||||
|
||||
def write():
|
||||
if print_time():
|
||||
start_time = time.perf_counter()
|
||||
|
||||
for sig_file in sig_files:
|
||||
sig_file.write(sync=0)
|
||||
for db in DB_sync_list:
|
||||
try:
|
||||
syncmethod = db.sync
|
||||
except AttributeError:
|
||||
pass # Not all dbm modules have sync() methods.
|
||||
else:
|
||||
syncmethod()
|
||||
try:
|
||||
closemethod = db.close
|
||||
except AttributeError:
|
||||
pass # Not all dbm modules have close() methods.
|
||||
else:
|
||||
closemethod()
|
||||
|
||||
if print_time():
|
||||
elapsed = time.perf_counter() - start_time
|
||||
print('Total SConsign sync time: %f seconds' % elapsed)
|
||||
|
||||
|
||||
class SConsignEntry:
|
||||
"""
|
||||
Wrapper class for the generic entry in a .sconsign file.
|
||||
The Node subclass populates it with attributes as it pleases.
|
||||
|
||||
XXX As coded below, we do expect a '.binfo' attribute to be added,
|
||||
but we'll probably generalize this in the next refactorings.
|
||||
"""
|
||||
__slots__ = ("binfo", "ninfo", "__weakref__")
|
||||
current_version_id = 2
|
||||
|
||||
def __init__(self):
|
||||
# Create an object attribute from the class attribute so it ends up
|
||||
# in the pickled data in the .sconsign file.
|
||||
#_version_id = self.current_version_id
|
||||
pass
|
||||
|
||||
def convert_to_sconsign(self):
|
||||
self.binfo.convert_to_sconsign()
|
||||
|
||||
def convert_from_sconsign(self, dir, name):
|
||||
self.binfo.convert_from_sconsign(dir, name)
|
||||
|
||||
def __getstate__(self):
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj, '__slots__', ()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
state['_version_id'] = self.current_version_id
|
||||
try:
|
||||
del state['__weakref__']
|
||||
except KeyError:
|
||||
pass
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
for key, value in state.items():
|
||||
if key not in ('_version_id', '__weakref__'):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class Base:
|
||||
"""
|
||||
This is the controlling class for the signatures for the collection of
|
||||
entries associated with a specific directory. The actual directory
|
||||
association will be maintained by a subclass that is specific to
|
||||
the underlying storage method. This class provides a common set of
|
||||
methods for fetching and storing the individual bits of information
|
||||
that make up signature entry.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.entries = {}
|
||||
self.dirty = False
|
||||
self.to_be_merged = {}
|
||||
|
||||
def get_entry(self, filename):
|
||||
"""
|
||||
Fetch the specified entry attribute.
|
||||
"""
|
||||
return self.entries[filename]
|
||||
|
||||
def set_entry(self, filename, obj):
|
||||
"""
|
||||
Set the entry.
|
||||
"""
|
||||
self.entries[filename] = obj
|
||||
self.dirty = True
|
||||
|
||||
def do_not_set_entry(self, filename, obj):
|
||||
pass
|
||||
|
||||
def store_info(self, filename, node):
|
||||
entry = node.get_stored_info()
|
||||
entry.binfo.merge(node.get_binfo())
|
||||
self.to_be_merged[filename] = node
|
||||
self.dirty = True
|
||||
|
||||
def do_not_store_info(self, filename, node):
|
||||
pass
|
||||
|
||||
def merge(self):
|
||||
for key, node in self.to_be_merged.items():
|
||||
entry = node.get_stored_info()
|
||||
try:
|
||||
ninfo = entry.ninfo
|
||||
except AttributeError:
|
||||
# This happens with SConf Nodes, because the configuration
|
||||
# subsystem takes direct control over how the build decision
|
||||
# is made and its information stored.
|
||||
pass
|
||||
else:
|
||||
ninfo.merge(node.get_ninfo())
|
||||
self.entries[key] = entry
|
||||
self.to_be_merged = {}
|
||||
|
||||
|
||||
class DB(Base):
|
||||
"""
|
||||
A Base subclass that reads and writes signature information
|
||||
from a global .sconsign.db* file--the actual file suffix is
|
||||
determined by the database module.
|
||||
"""
|
||||
def __init__(self, dir):
|
||||
super().__init__()
|
||||
|
||||
self.dir = dir
|
||||
|
||||
db, mode = Get_DataBase(dir)
|
||||
|
||||
# Read using the path relative to the top of the Repository
|
||||
# (self.dir.tpath) from which we're fetching the signature
|
||||
# information.
|
||||
path = normcase(dir.get_tpath())
|
||||
try:
|
||||
rawentries = db[path]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
self.entries = pickle.loads(rawentries)
|
||||
if not isinstance(self.entries, dict):
|
||||
self.entries = {}
|
||||
raise TypeError
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.get_tpath(), e))
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_from_sconsign(dir, key)
|
||||
|
||||
if mode == "r":
|
||||
# This directory is actually under a repository, which means
|
||||
# likely they're reaching in directly for a dependency on
|
||||
# a file there. Don't actually set any entry info, so we
|
||||
# won't try to write to that .sconsign.dblite file.
|
||||
self.set_entry = self.do_not_set_entry
|
||||
self.store_info = self.do_not_store_info
|
||||
|
||||
sig_files.append(self)
|
||||
|
||||
def write(self, sync=1):
|
||||
if not self.dirty:
|
||||
return
|
||||
|
||||
self.merge()
|
||||
|
||||
db, mode = Get_DataBase(self.dir)
|
||||
|
||||
# Write using the path relative to the top of the SConstruct
|
||||
# directory (self.dir.path), not relative to the top of
|
||||
# the Repository; we only write to our own .sconsign file,
|
||||
# not to .sconsign files in Repositories.
|
||||
path = normcase(self.dir.get_internal_path())
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_to_sconsign()
|
||||
db[path] = pickle.dumps(self.entries, PICKLE_PROTOCOL)
|
||||
|
||||
if sync:
|
||||
try:
|
||||
syncmethod = db.sync
|
||||
except AttributeError:
|
||||
# Not all anydbm modules have sync() methods.
|
||||
pass
|
||||
else:
|
||||
syncmethod()
|
||||
|
||||
|
||||
class Dir(Base):
|
||||
def __init__(self, fp=None, dir=None):
|
||||
"""fp - file pointer to read entries from."""
|
||||
super().__init__()
|
||||
|
||||
if not fp:
|
||||
return
|
||||
|
||||
self.entries = pickle.load(fp)
|
||||
if not isinstance(self.entries, dict):
|
||||
self.entries = {}
|
||||
raise TypeError
|
||||
|
||||
if dir:
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_from_sconsign(dir, key)
|
||||
|
||||
|
||||
class DirFile(Dir):
|
||||
"""Encapsulates reading and writing a per-directory .sconsign file."""
|
||||
def __init__(self, dir):
|
||||
"""dir - the directory for the file."""
|
||||
|
||||
self.dir = dir
|
||||
self.sconsign = os.path.join(dir.get_internal_path(), current_sconsign_filename())
|
||||
|
||||
try:
|
||||
fp = open(self.sconsign, 'rb')
|
||||
except OSError:
|
||||
fp = None
|
||||
|
||||
try:
|
||||
super().__init__(fp, dir)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception:
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
|
||||
|
||||
try:
|
||||
fp.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
sig_files.append(self)
|
||||
|
||||
def write(self, sync=1):
|
||||
"""Write the .sconsign file to disk.
|
||||
|
||||
Try to write to a temporary file first, and rename it if we
|
||||
succeed. If we can't write to the temporary file, it's
|
||||
probably because the directory isn't writable (and if so,
|
||||
how did we build anything in this directory, anyway?), so
|
||||
try to write directly to the .sconsign file as a backup.
|
||||
If we can't rename, try to copy the temporary contents back
|
||||
to the .sconsign file. Either way, always try to remove
|
||||
the temporary file at the end.
|
||||
"""
|
||||
if not self.dirty:
|
||||
return
|
||||
|
||||
self.merge()
|
||||
|
||||
temp = os.path.join(self.dir.get_internal_path(), '.scons%d' % os.getpid())
|
||||
try:
|
||||
file = open(temp, 'wb')
|
||||
fname = temp
|
||||
except OSError:
|
||||
try:
|
||||
file = open(self.sconsign, 'wb')
|
||||
fname = self.sconsign
|
||||
except OSError:
|
||||
return
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_to_sconsign()
|
||||
pickle.dump(self.entries, file, PICKLE_PROTOCOL)
|
||||
file.close()
|
||||
if fname != self.sconsign:
|
||||
try:
|
||||
mode = os.stat(self.sconsign)[0]
|
||||
os.chmod(self.sconsign, 0o666)
|
||||
os.unlink(self.sconsign)
|
||||
except OSError:
|
||||
# Try to carry on in the face of either OSError
|
||||
# (things like permission issues) or IOError (disk
|
||||
# or network issues). If there's a really dangerous
|
||||
# issue, it should get re-raised by the calls below.
|
||||
pass
|
||||
try:
|
||||
os.rename(fname, self.sconsign)
|
||||
except OSError:
|
||||
# An OSError failure to rename may indicate something
|
||||
# like the directory has no write permission, but
|
||||
# the .sconsign file itself might still be writable,
|
||||
# so try writing on top of it directly. An IOError
|
||||
# here, or in any of the following calls, would get
|
||||
# raised, indicating something like a potentially
|
||||
# serious disk or network issue.
|
||||
with open(self.sconsign, 'wb') as f, open(fname, 'rb') as f2:
|
||||
f.write(f2.read())
|
||||
os.chmod(self.sconsign, mode)
|
||||
try:
|
||||
os.unlink(temp)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
ForDirectory = DB
|
||||
|
||||
|
||||
def File(name, dbm_module=None):
|
||||
"""
|
||||
Arrange for all signatures to be stored in a global .sconsign.db*
|
||||
file.
|
||||
"""
|
||||
global ForDirectory, DB_Name, DB_Module
|
||||
if name is None:
|
||||
ForDirectory = DirFile
|
||||
DB_Module = None
|
||||
else:
|
||||
ForDirectory = DB
|
||||
DB_Name = name
|
||||
if dbm_module is not None:
|
||||
DB_Module = dbm_module
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
333
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/C.py
Normal file
333
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/C.py
Normal file
@@ -0,0 +1,333 @@
|
||||
# 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.
|
||||
|
||||
"""Dependency scanner for C/C++ code.
|
||||
|
||||
Two scanners are defined here: the default CScanner, and the optional
|
||||
CConditionalScanner, which must be explicitly selected by calling
|
||||
add_scanner() for each affected suffix.
|
||||
"""
|
||||
|
||||
from typing import Dict
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.cpp
|
||||
import SCons.Util
|
||||
from . import ClassicCPP, FindPathDirs
|
||||
|
||||
|
||||
class SConsCPPScanner(SCons.cpp.PreProcessor):
|
||||
"""SCons-specific subclass of the cpp.py module's processing.
|
||||
|
||||
We subclass this so that: 1) we can deal with files represented
|
||||
by Nodes, not strings; 2) we can keep track of the files that are
|
||||
missing.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.missing = []
|
||||
|
||||
def initialize_result(self, fname):
|
||||
self.result = SCons.Util.UniqueList([fname])
|
||||
|
||||
def finalize_result(self, fname):
|
||||
return self.result[1:]
|
||||
|
||||
def find_include_file(self, t):
|
||||
keyword, quote, fname = t
|
||||
result = SCons.Node.FS.find_file(fname, self.searchpath[quote])
|
||||
if not result:
|
||||
self.missing.append((fname, self.current_file))
|
||||
return result
|
||||
|
||||
def read_file(self, file):
|
||||
try:
|
||||
return file.rfile().get_text_contents()
|
||||
except OSError as e:
|
||||
self.missing.append((file, self.current_file))
|
||||
return ''
|
||||
|
||||
def dictify_CPPDEFINES(env, replace = False):
|
||||
"""Return CPPDEFINES converted to a dict for preprocessor emulation.
|
||||
|
||||
The concept is similar to :func:`~SCons.Defaults.processDefines`:
|
||||
turn the values stored in an internal form in ``env['CPPDEFINES']``
|
||||
into one needed for a specific context - in this case the cpp-like
|
||||
work the C/C++ scanner will do. We can't reuse ``processDefines``
|
||||
output as that's a list of strings for the command line. We also can't
|
||||
pass the ``CPPDEFINES`` variable directly to the ``dict`` constructor,
|
||||
as SCons allows it to be stored in several different ways - it's only
|
||||
after ``Append`` and relatives has been called we know for sure it will
|
||||
be a deque of tuples.
|
||||
|
||||
If requested (*replace* is true), simulate some of the macro
|
||||
replacement that would take place if an actual preprocessor ran,
|
||||
to avoid some conditional inclusions comeing out wrong. A bit
|
||||
of an edge case, but does happen (GH #4623). See 6.10.5 in the C
|
||||
standard and 15.6 in the C++ standard).
|
||||
|
||||
Args:
|
||||
replace: if true, simulate macro replacement
|
||||
|
||||
.. versionchanged:: 4.9.0
|
||||
Simple macro replacement added, and *replace* arg to enable it.
|
||||
"""
|
||||
def _replace(mapping):
|
||||
"""Simplistic macro replacer for dictify_CPPDEFINES.
|
||||
|
||||
Scan *mapping* for a value that is the same as a key in the dict,
|
||||
and replace with the value of that key; the process is repeated a few
|
||||
times, but not forever in case someone left a case that can't be
|
||||
fully resolved. This is a cheap approximation of the preprocessor's
|
||||
macro replacement rules with no smarts - it doesn't "look inside"
|
||||
the values, so only triggers on object-like macros, not on
|
||||
function-like macros, and will not work on complex values, e.g.
|
||||
a value like ``(1UL << PR_MTE_TCF_SHIFT)`` would not have
|
||||
``PR_MTE_TCF_SHIFT`` replaced if that was also a key in ``CPPDEFINES``.
|
||||
|
||||
Args:
|
||||
mapping: a dictionary representing macro names and replacements.
|
||||
|
||||
Returns:
|
||||
a dictionary with replacements made.
|
||||
"""
|
||||
old_ns = mapping
|
||||
loops = 0
|
||||
while loops < 5: # don't recurse forever in case there's circular data
|
||||
# this was originally written as a dict comprehension, but unrolling
|
||||
# lets us add a finer-grained check for whether another loop is
|
||||
# needed, rather than comparing two dicts to see if one changed.
|
||||
again = False
|
||||
ns = {}
|
||||
for k, v in old_ns.items():
|
||||
if v in old_ns:
|
||||
ns[k] = old_ns[v]
|
||||
if not again and ns[k] != v:
|
||||
again = True
|
||||
else:
|
||||
ns[k] = v
|
||||
if not again:
|
||||
break
|
||||
old_ns = ns
|
||||
loops += 1
|
||||
return ns
|
||||
|
||||
cppdefines = env.get('CPPDEFINES', {})
|
||||
if not cppdefines:
|
||||
return {}
|
||||
|
||||
if SCons.Util.is_Tuple(cppdefines):
|
||||
# single macro defined in a tuple
|
||||
try:
|
||||
return {cppdefines[0]: cppdefines[1]}
|
||||
except IndexError:
|
||||
return {cppdefines[0]: None}
|
||||
|
||||
if SCons.Util.is_Sequence(cppdefines):
|
||||
# multiple (presumably) macro defines in a deque, list, etc.
|
||||
result = {}
|
||||
for c in cppdefines:
|
||||
if SCons.Util.is_Sequence(c):
|
||||
try:
|
||||
result[c[0]] = c[1]
|
||||
except IndexError:
|
||||
# could be a one-item sequence
|
||||
result[c[0]] = None
|
||||
elif SCons.Util.is_String(c):
|
||||
try:
|
||||
name, value = c.split('=')
|
||||
result[name] = value
|
||||
except ValueError:
|
||||
result[c] = None
|
||||
else:
|
||||
# don't really know what to do here
|
||||
result[c] = None
|
||||
if replace:
|
||||
return _replace(result)
|
||||
return(result)
|
||||
|
||||
if SCons.Util.is_String(cppdefines):
|
||||
# single macro define in a string
|
||||
try:
|
||||
name, value = cppdefines.split('=')
|
||||
return {name: value}
|
||||
except ValueError:
|
||||
return {cppdefines: None}
|
||||
|
||||
if SCons.Util.is_Dict(cppdefines):
|
||||
# already in the desired form
|
||||
if replace:
|
||||
return _replace(cppdefines)
|
||||
return cppdefines
|
||||
|
||||
return {cppdefines: None}
|
||||
|
||||
class SConsCPPScannerWrapper:
|
||||
"""The SCons wrapper around a cpp.py scanner.
|
||||
|
||||
This is the actual glue between the calling conventions of generic
|
||||
SCons scanners, and the (subclass of) cpp.py class that knows how
|
||||
to look for #include lines with reasonably real C-preprocessor-like
|
||||
evaluation of #if/#ifdef/#else/#elif lines.
|
||||
"""
|
||||
|
||||
def __init__(self, name, variable):
|
||||
self.name = name
|
||||
self.path = FindPathDirs(variable)
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
cpp = SConsCPPScanner(
|
||||
current=node.get_dir(),
|
||||
cpppath=path,
|
||||
dict=dictify_CPPDEFINES(env, replace=True),
|
||||
)
|
||||
result = cpp(node)
|
||||
for included, includer in cpp.missing:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DependencyWarning,
|
||||
"No dependency generated for file: %s (included from: %s) "
|
||||
"-- file not found" % (included, includer),
|
||||
)
|
||||
return result
|
||||
|
||||
def recurse_nodes(self, nodes):
|
||||
return nodes
|
||||
|
||||
def select(self, node):
|
||||
return self
|
||||
|
||||
def CScanner():
|
||||
"""Return a prototype Scanner instance for scanning source files
|
||||
that use the C pre-processor"""
|
||||
|
||||
# Here's how we would (or might) use the CPP scanner code above that
|
||||
# knows how to evaluate #if/#ifdef/#else/#elif lines when searching
|
||||
# for #includes. This is commented out for now until we add the
|
||||
# right configurability to let users pick between the scanners.
|
||||
# return SConsCPPScannerWrapper("CScanner", "CPPPATH")
|
||||
|
||||
cs = ClassicCPP(
|
||||
"CScanner",
|
||||
"$CPPSUFFIXES",
|
||||
"CPPPATH",
|
||||
r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")',
|
||||
)
|
||||
return cs
|
||||
|
||||
|
||||
#
|
||||
# ConditionalScanner
|
||||
#
|
||||
|
||||
|
||||
class SConsCPPConditionalScanner(SCons.cpp.PreProcessor):
|
||||
"""SCons-specific subclass of the cpp.py module's processing.
|
||||
|
||||
We subclass this so that: 1) we can deal with files represented
|
||||
by Nodes, not strings; 2) we can keep track of the files that are
|
||||
missing.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.missing = []
|
||||
self._known_paths = []
|
||||
|
||||
def initialize_result(self, fname):
|
||||
self.result = SCons.Util.UniqueList([fname])
|
||||
|
||||
def find_include_file(self, t):
|
||||
keyword, quote, fname = t
|
||||
paths = tuple(self._known_paths) + self.searchpath[quote]
|
||||
if quote == '"':
|
||||
paths = (self.current_file.dir,) + paths
|
||||
result = SCons.Node.FS.find_file(fname, paths)
|
||||
if result:
|
||||
result_path = result.get_abspath()
|
||||
for p in self.searchpath[quote]:
|
||||
if result_path.startswith(p.get_abspath()):
|
||||
self._known_paths.append(p)
|
||||
break
|
||||
else:
|
||||
self.missing.append((fname, self.current_file))
|
||||
return result
|
||||
|
||||
def read_file(self, file):
|
||||
try:
|
||||
return file.rfile().get_text_contents()
|
||||
except OSError:
|
||||
self.missing.append((file, self.current_file))
|
||||
return ""
|
||||
|
||||
|
||||
class SConsCPPConditionalScannerWrapper:
|
||||
"""
|
||||
The SCons wrapper around a cpp.py scanner.
|
||||
|
||||
This is the actual glue between the calling conventions of generic
|
||||
SCons scanners, and the (subclass of) cpp.py class that knows how
|
||||
to look for #include lines with reasonably real C-preprocessor-like
|
||||
evaluation of #if/#ifdef/#else/#elif lines.
|
||||
"""
|
||||
|
||||
def __init__(self, name, variable):
|
||||
self.name = name
|
||||
self.path = FindPathDirs(variable)
|
||||
|
||||
def __call__(self, node, env, path=(), depth=-1):
|
||||
cpp = SConsCPPConditionalScanner(
|
||||
current=node.get_dir(),
|
||||
cpppath=path,
|
||||
dict=dictify_CPPDEFINES(env),
|
||||
depth=depth,
|
||||
)
|
||||
result = cpp(node)
|
||||
for included, includer in cpp.missing:
|
||||
fmt = "No dependency generated for file: %s (included from: %s) -- file not found"
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DependencyWarning, fmt % (included, includer)
|
||||
)
|
||||
return result
|
||||
|
||||
def recurse_nodes(self, nodes):
|
||||
return nodes
|
||||
|
||||
def select(self, node):
|
||||
return self
|
||||
|
||||
|
||||
def CConditionalScanner():
|
||||
"""
|
||||
Return an advanced conditional Scanner instance for scanning source files
|
||||
|
||||
Interprets C/C++ Preprocessor conditional syntax
|
||||
(#ifdef, #if, defined, #else, #elif, etc.).
|
||||
"""
|
||||
return SConsCPPConditionalScannerWrapper("CConditionalScanner", "CPPPATH")
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
131
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/Dir.py
Normal file
131
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/Dir.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# 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.
|
||||
|
||||
import SCons.Node.FS
|
||||
from . import ScannerBase
|
||||
|
||||
def only_dirs(nodes):
|
||||
is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir)
|
||||
return [node for node in nodes if is_Dir(node)]
|
||||
|
||||
def DirScanner(**kwargs):
|
||||
"""Return a prototype Scanner instance for scanning
|
||||
directories for on-disk files"""
|
||||
kwargs['node_factory'] = SCons.Node.FS.Entry
|
||||
kwargs['recursive'] = only_dirs
|
||||
return ScannerBase(scan_on_disk, "DirScanner", **kwargs)
|
||||
|
||||
def DirEntryScanner(**kwargs):
|
||||
"""Return a prototype Scanner instance for "scanning"
|
||||
directory Nodes for their in-memory entries"""
|
||||
kwargs['node_factory'] = SCons.Node.FS.Entry
|
||||
kwargs['recursive'] = None
|
||||
return ScannerBase(scan_in_memory, "DirEntryScanner", **kwargs)
|
||||
|
||||
skip_entry = {}
|
||||
|
||||
skip_entry_list = [
|
||||
'.',
|
||||
'..',
|
||||
'.sconsign',
|
||||
# Used by the native dblite.py module.
|
||||
'.sconsign.dblite',
|
||||
# Used by dbm and dumbdbm.
|
||||
'.sconsign.dir',
|
||||
# Used by dbm.
|
||||
'.sconsign.pag',
|
||||
# Used by dumbdbm.
|
||||
'.sconsign.dat',
|
||||
'.sconsign.bak',
|
||||
# Used by some dbm emulations using Berkeley DB.
|
||||
'.sconsign.db',
|
||||
# new filenames since multiple hash formats allowed:
|
||||
'.sconsign_md5.dblite',
|
||||
'.sconsign_sha1.dblite',
|
||||
'.sconsign_sha256.dblite',
|
||||
# and all the duplicate files for each sub-sconsfile type
|
||||
'.sconsign_md5',
|
||||
'.sconsign_md5.dir',
|
||||
'.sconsign_md5.pag',
|
||||
'.sconsign_md5.dat',
|
||||
'.sconsign_md5.bak',
|
||||
'.sconsign_md5.db',
|
||||
'.sconsign_sha1',
|
||||
'.sconsign_sha1.dir',
|
||||
'.sconsign_sha1.pag',
|
||||
'.sconsign_sha1.dat',
|
||||
'.sconsign_sha1.bak',
|
||||
'.sconsign_sha1.db',
|
||||
'.sconsign_sha256',
|
||||
'.sconsign_sha256.dir',
|
||||
'.sconsign_sha256.pag',
|
||||
'.sconsign_sha256.dat',
|
||||
'.sconsign_sha256.bak',
|
||||
'.sconsign_sha256.db',
|
||||
]
|
||||
|
||||
for skip in skip_entry_list:
|
||||
skip_entry[skip] = 1
|
||||
skip_entry[SCons.Node.FS._my_normcase(skip)] = 1
|
||||
|
||||
do_not_scan = lambda k: k not in skip_entry
|
||||
|
||||
def scan_on_disk(node, env, path=()):
|
||||
"""
|
||||
Scans a directory for on-disk files and directories therein.
|
||||
|
||||
Looking up the entries will add these to the in-memory Node tree
|
||||
representation of the file system, so all we have to do is just
|
||||
that and then call the in-memory scanning function.
|
||||
"""
|
||||
try:
|
||||
flist = node.fs.listdir(node.get_abspath())
|
||||
except OSError:
|
||||
return []
|
||||
e = node.Entry
|
||||
for f in filter(do_not_scan, flist):
|
||||
# Add ./ to the beginning of the file name so if it begins with a
|
||||
# '#' we don't look it up relative to the top-level directory.
|
||||
e('./' + f)
|
||||
return scan_in_memory(node, env, path)
|
||||
|
||||
def scan_in_memory(node, env, path=()):
|
||||
"""
|
||||
"Scans" a Node.FS.Dir for its in-memory entries.
|
||||
"""
|
||||
try:
|
||||
entries = node.entries
|
||||
except AttributeError:
|
||||
# It's not a Node.FS.Dir (or doesn't look enough like one for
|
||||
# our purposes), which can happen if a target list containing
|
||||
# mixed Node types (Dirs and Files, for example) has a Dir as
|
||||
# the first entry.
|
||||
return []
|
||||
entry_list = sorted(filter(do_not_scan, list(entries.keys())))
|
||||
return [entries[n] for n in entry_list]
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
114
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/Prog.py
Normal file
114
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Scanner/Prog.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# 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.
|
||||
|
||||
"""Dependency scanner for program files."""
|
||||
|
||||
import SCons.Node
|
||||
import SCons.Node.FS
|
||||
import SCons.Util
|
||||
from . import ScannerBase, FindPathDirs
|
||||
|
||||
# global, set by --debug=findlibs
|
||||
print_find_libs = None
|
||||
|
||||
def ProgramScanner(**kwargs):
|
||||
"""Return a prototype Scanner instance for scanning executable
|
||||
files for static-lib dependencies"""
|
||||
kwargs['path_function'] = FindPathDirs('LIBPATH')
|
||||
ps = ScannerBase(scan, "ProgramScanner", **kwargs)
|
||||
return ps
|
||||
|
||||
def _subst_libs(env, libs):
|
||||
"""Substitute environment variables and split into list."""
|
||||
if SCons.Util.is_String(libs):
|
||||
libs = env.subst(libs)
|
||||
if SCons.Util.is_String(libs):
|
||||
libs = libs.split()
|
||||
elif SCons.Util.is_Sequence(libs):
|
||||
_libs = []
|
||||
for l in libs:
|
||||
_libs += _subst_libs(env, l)
|
||||
libs = _libs
|
||||
else:
|
||||
# libs is an object (Node, for example)
|
||||
libs = [libs]
|
||||
return libs
|
||||
|
||||
def scan(node, env, libpath = ()):
|
||||
"""Scans program files for static-library dependencies.
|
||||
|
||||
It will search the LIBPATH environment variable
|
||||
for libraries specified in the LIBS variable, returning any
|
||||
files it finds as dependencies.
|
||||
"""
|
||||
try:
|
||||
libs = env['LIBS']
|
||||
except KeyError:
|
||||
# There are no LIBS in this environment, so just return a null list:
|
||||
return []
|
||||
|
||||
libs = _subst_libs(env, libs)
|
||||
|
||||
try:
|
||||
prefix = env['LIBPREFIXES']
|
||||
if not SCons.Util.is_List(prefix):
|
||||
prefix = [ prefix ]
|
||||
except KeyError:
|
||||
prefix = [ '' ]
|
||||
|
||||
try:
|
||||
suffix = env['LIBSUFFIXES']
|
||||
if not SCons.Util.is_List(suffix):
|
||||
suffix = [ suffix ]
|
||||
except KeyError:
|
||||
suffix = [ '' ]
|
||||
|
||||
pairs = []
|
||||
for suf in map(env.subst, suffix):
|
||||
for pref in map(env.subst, prefix):
|
||||
pairs.append((pref, suf))
|
||||
|
||||
result = []
|
||||
|
||||
if callable(libpath):
|
||||
libpath = libpath()
|
||||
|
||||
find_file = SCons.Node.FS.find_file
|
||||
adjustixes = SCons.Util.adjustixes
|
||||
for lib in libs:
|
||||
if SCons.Util.is_String(lib):
|
||||
for pref, suf in pairs:
|
||||
l = adjustixes(lib, pref, suf)
|
||||
l = find_file(l, libpath, verbose=print_find_libs)
|
||||
if l:
|
||||
result.append(l)
|
||||
else:
|
||||
result.append(lib)
|
||||
|
||||
return result
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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.
|
||||
|
||||
"""Dependency scanner for RC (Interface Definition Language) files."""
|
||||
|
||||
|
||||
import SCons.Node.FS
|
||||
from . import ClassicCPP
|
||||
|
||||
|
||||
def no_tlb(nodes):
|
||||
"""Filter out .tlb files as they are binary and shouldn't be scanned."""
|
||||
|
||||
# print("Nodes:%s"%[str(n) for n in nodes])
|
||||
return [n for n in nodes if str(n)[-4:] != '.tlb']
|
||||
|
||||
|
||||
def RCScan():
|
||||
"""Return a prototype Scanner instance for scanning RC source files"""
|
||||
|
||||
res_re = (
|
||||
r'^(?:\s*#\s*(?:include)|'
|
||||
r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)'
|
||||
r'\s*.*?)'
|
||||
r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||
)
|
||||
resScanner = ClassicCPP(
|
||||
"ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re, recursive=no_tlb
|
||||
)
|
||||
|
||||
return resScanner
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,438 @@
|
||||
# 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.
|
||||
|
||||
"""The Scanner package for the SCons software construction utility."""
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.PathList
|
||||
import SCons.Util
|
||||
|
||||
|
||||
class _Null:
|
||||
pass
|
||||
|
||||
# This is used instead of None as a default argument value so None can be
|
||||
# used as an actual argument value.
|
||||
_null = _Null
|
||||
|
||||
def Scanner(function, *args, **kwargs):
|
||||
"""Factory function to create a Scanner Object.
|
||||
|
||||
Creates the appropriate Scanner based on the type of "function".
|
||||
|
||||
TODO: Deprecate this some day. We've moved the functionality
|
||||
inside the ScannerBase class and really don't need this factory function
|
||||
any more. It was, however, used by some of our Tool modules, so
|
||||
the call probably ended up in various people's custom modules
|
||||
patterned on SCons code.
|
||||
|
||||
"""
|
||||
if SCons.Util.is_Dict(function):
|
||||
return Selector(function, *args, **kwargs)
|
||||
|
||||
return ScannerBase(function, *args, **kwargs)
|
||||
|
||||
|
||||
class FindPathDirs:
|
||||
"""Class to bind a specific E{*}PATH variable name to a function that
|
||||
will return all of the E{*}path directories.
|
||||
"""
|
||||
def __init__(self, variable):
|
||||
self.variable = variable
|
||||
|
||||
def __call__(self, env, dir=None, target=None, source=None, argument=None):
|
||||
try:
|
||||
path = env[self.variable]
|
||||
except KeyError:
|
||||
return ()
|
||||
|
||||
dir = dir or env.fs._cwd
|
||||
path = SCons.PathList.PathList(path).subst_path(env, target, source)
|
||||
return tuple(dir.Rfindalldirs(path))
|
||||
|
||||
|
||||
class ScannerBase:
|
||||
"""Base class for dependency scanners.
|
||||
|
||||
Implements straightforward, single-pass scanning of a single file.
|
||||
|
||||
A Scanner is usually set up with a scanner function (and optionally
|
||||
a path function), but can also be a kind of dispatcher which
|
||||
passes control to other Scanners.
|
||||
|
||||
A scanner function takes three arguments: a Node to scan for
|
||||
dependecies, the construction environment to use, and an optional
|
||||
tuple of paths (as generated by the optional path function).
|
||||
It must return a list containing the Nodes for all the direct
|
||||
dependencies of the file.
|
||||
|
||||
The optional path function is called to return paths that can be
|
||||
searched for implicit dependency files. It takes five arguments:
|
||||
a construction environment, a Node for the directory containing
|
||||
the SConscript file that defined the primary target, a list of
|
||||
target nodes, a list of source nodes, and the optional argument
|
||||
for this instance.
|
||||
|
||||
Examples::
|
||||
|
||||
s = Scanner(my_scanner_function)
|
||||
s = Scanner(function=my_scanner_function)
|
||||
s = Scanner(function=my_scanner_function, argument='foo')
|
||||
|
||||
Args:
|
||||
function: either a scanner function taking two or three arguments
|
||||
and returning a list of File Nodes; or a mapping of keys to
|
||||
other Scanner objects.
|
||||
|
||||
name: an optional name for identifying this scanner object
|
||||
(defaults to "NONE").
|
||||
|
||||
argument: an optional argument that will be passed to both
|
||||
*function* and *path_function*.
|
||||
|
||||
skeys: an optional list argument that can be used
|
||||
to determine if this scanner can be used for a given Node.
|
||||
In the case of File nodes, for example, the *skeys*
|
||||
would be file suffixes.
|
||||
|
||||
path_function: an optional function which returns a tuple
|
||||
of the directories that can be searched for implicit
|
||||
dependency files. May also return a callable which
|
||||
is called with no args and returns the tuple (supporting
|
||||
Bindable class).
|
||||
|
||||
node_class: optional class of Nodes which this scan will return.
|
||||
If not specified, defaults to :class:`SCons.Node.FS.Base`.
|
||||
If *node_class* is ``None``, then this scanner will not enforce
|
||||
any Node conversion and will return the raw results from *function*.
|
||||
|
||||
node_factory: optional factory function to be called to
|
||||
translate the raw results returned by *function*
|
||||
into the expected *node_class* objects.
|
||||
|
||||
scan_check: optional function to be called to first check whether
|
||||
this node really needs to be scanned.
|
||||
|
||||
recursive: optional specifier of whether this scanner should be
|
||||
invoked recursively on all of the implicit dependencies it returns
|
||||
(for example `#include` lines in C source files, which may refer
|
||||
to header files which should themselves be scanned).
|
||||
May be a callable, which will be called to filter
|
||||
the list of nodes found to select a subset for recursive
|
||||
scanning (the canonical example being only recursively
|
||||
scanning subdirectories within a directory). The default
|
||||
is to not do recursive scanning.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
function,
|
||||
name="NONE",
|
||||
argument=_null,
|
||||
skeys=_null,
|
||||
path_function=None,
|
||||
# Node.FS.Base so that, by default, it's okay for a
|
||||
# scanner to return a Dir, File or Entry.
|
||||
node_class=SCons.Node.FS.Base,
|
||||
node_factory=None,
|
||||
scan_check=None,
|
||||
recursive=None,
|
||||
):
|
||||
"""Construct a new scanner object given a scanner function."""
|
||||
# Note: this class could easily work with scanner functions that take
|
||||
# something other than a filename as an argument (e.g. a database
|
||||
# node) and a dependencies list that aren't file names. All that
|
||||
# would need to be changed is the documentation.
|
||||
|
||||
self.function = function
|
||||
self.path_function = path_function
|
||||
self.name = name
|
||||
self.argument = argument
|
||||
|
||||
if skeys is _null:
|
||||
if SCons.Util.is_Dict(function):
|
||||
skeys = list(function.keys())
|
||||
else:
|
||||
skeys = []
|
||||
self.skeys = skeys
|
||||
|
||||
self.node_class = node_class
|
||||
self.node_factory = node_factory
|
||||
self.scan_check = scan_check
|
||||
if callable(recursive):
|
||||
self.recurse_nodes = recursive
|
||||
elif recursive:
|
||||
self.recurse_nodes = self._recurse_all_nodes
|
||||
else:
|
||||
self.recurse_nodes = self._recurse_no_nodes
|
||||
|
||||
def path(self, env, dir=None, target=None, source=None):
|
||||
if not self.path_function:
|
||||
return ()
|
||||
|
||||
if self.argument is not _null:
|
||||
return self.path_function(env, dir, target, source, self.argument)
|
||||
|
||||
return self.path_function(env, dir, target, source)
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
"""Scans a single object.
|
||||
|
||||
Args:
|
||||
node: the node that will be passed to the scanner function
|
||||
env: the environment that will be passed to the scanner function.
|
||||
path: tuple of paths from the `path_function`
|
||||
|
||||
Returns:
|
||||
A list of direct dependency nodes for the specified node.
|
||||
|
||||
"""
|
||||
if self.scan_check and not self.scan_check(node, env):
|
||||
return []
|
||||
|
||||
# here we may morph into a different Scanner instance:
|
||||
self = self.select(node) # pylint: disable=self-cls-assignment
|
||||
|
||||
if self.argument is not _null:
|
||||
node_list = self.function(node, env, path, self.argument)
|
||||
else:
|
||||
node_list = self.function(node, env, path)
|
||||
|
||||
kw = {}
|
||||
if hasattr(node, 'dir'):
|
||||
kw['directory'] = node.dir
|
||||
conv = env.get_factory(self.node_factory)
|
||||
cls = self.node_class
|
||||
nl = [conv(n, **kw) if cls and not isinstance(n, cls) else n for n in node_list]
|
||||
return nl
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.__dict__ == other.__dict__
|
||||
except AttributeError:
|
||||
# other probably doesn't have a __dict__
|
||||
return self.__dict__ == other
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def add_skey(self, skey):
|
||||
"""Add a skey to the list of skeys"""
|
||||
self.skeys.append(skey)
|
||||
|
||||
def get_skeys(self, env=None):
|
||||
if env and SCons.Util.is_String(self.skeys):
|
||||
return env.subst_list(self.skeys)[0]
|
||||
return self.skeys
|
||||
|
||||
def select(self, node):
|
||||
if SCons.Util.is_Dict(self.function):
|
||||
key = node.scanner_key()
|
||||
try:
|
||||
return self.function[key]
|
||||
except KeyError:
|
||||
return None
|
||||
else:
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def _recurse_all_nodes(nodes):
|
||||
return nodes
|
||||
|
||||
@staticmethod
|
||||
def _recurse_no_nodes(nodes):
|
||||
return []
|
||||
|
||||
# recurse_nodes = _recurse_no_nodes
|
||||
|
||||
def add_scanner(self, skey, scanner):
|
||||
self.function[skey] = scanner
|
||||
self.add_skey(skey)
|
||||
|
||||
|
||||
# keep the old name for a while in case external users are using.
|
||||
# there are no more internal uses of this class by the name "Base"
|
||||
Base = ScannerBase
|
||||
|
||||
|
||||
class Selector(ScannerBase):
|
||||
"""
|
||||
A class for selecting a more specific scanner based on the
|
||||
:func:`scanner_key` (suffix) for a specific Node.
|
||||
|
||||
TODO: This functionality has been moved into the inner workings of
|
||||
the ScannerBase class, and this class will be deprecated at some point.
|
||||
(It was never exposed directly as part of the public interface,
|
||||
although it is used by the :func:`Scanner` factory function that was
|
||||
used by various Tool modules and therefore was likely a template
|
||||
for custom modules that may be out there.)
|
||||
"""
|
||||
def __init__(self, mapping, *args, **kwargs):
|
||||
super().__init__(None, *args, **kwargs)
|
||||
self.mapping = mapping
|
||||
self.skeys = list(mapping.keys())
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
return self.select(node)(node, env, path)
|
||||
|
||||
def select(self, node):
|
||||
try:
|
||||
return self.mapping[node.scanner_key()]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def add_scanner(self, skey, scanner):
|
||||
self.mapping[skey] = scanner
|
||||
self.add_skey(skey)
|
||||
|
||||
|
||||
class Current(ScannerBase):
|
||||
"""
|
||||
A class for scanning files that are source files (have no builder)
|
||||
or are derived files and are current (which implies that they exist,
|
||||
either locally or in a repository).
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def current_check(node, env):
|
||||
return not node.has_builder() or node.is_up_to_date()
|
||||
|
||||
kwargs['scan_check'] = current_check
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class Classic(Current):
|
||||
"""
|
||||
A Scanner subclass to contain the common logic for classic CPP-style
|
||||
include scanning, but which can be customized to use different
|
||||
regular expressions to find the includes.
|
||||
|
||||
Note that in order for this to work "out of the box" (without
|
||||
overriding the :meth:`find_include` and :meth:`sort_key1` methods),
|
||||
the regular expression passed to the constructor must return the
|
||||
name of the include file in group 0.
|
||||
"""
|
||||
|
||||
def __init__(self, name, suffixes, path_variable, regex, *args, **kwargs):
|
||||
self.cre = re.compile(regex, re.M)
|
||||
|
||||
def _scan(node, _, path=(), self=self):
|
||||
node = node.rfile()
|
||||
if not node.exists():
|
||||
return []
|
||||
return self.scan(node, path)
|
||||
|
||||
kwargs['function'] = _scan
|
||||
kwargs['path_function'] = FindPathDirs(path_variable)
|
||||
|
||||
# Allow recursive to propagate if child class specifies.
|
||||
# In this case resource scanner needs to specify a filter on which files
|
||||
# get recursively processed. Previously was hardcoded to 1 instead of
|
||||
# defaulted to 1.
|
||||
kwargs['recursive'] = kwargs.get('recursive', True)
|
||||
kwargs['skeys'] = suffixes
|
||||
kwargs['name'] = name
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def find_include(include, source_dir, path):
|
||||
n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path))
|
||||
return n, include
|
||||
|
||||
@staticmethod
|
||||
def sort_key(include):
|
||||
return SCons.Node.FS._my_normcase(include)
|
||||
|
||||
def find_include_names(self, node):
|
||||
return self.cre.findall(node.get_text_contents())
|
||||
|
||||
def scan(self, node, path=()):
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes is not None:
|
||||
includes = node.includes
|
||||
else:
|
||||
includes = self.find_include_names(node)
|
||||
# Intern the names of the include files. Saves some memory
|
||||
# if the same header is included many times.
|
||||
node.includes = list(map(SCons.Util.silent_intern, includes))
|
||||
|
||||
# This is a hand-coded DSU (decorate-sort-undecorate, or
|
||||
# Schwartzian transform) pattern. The sort key is the raw name
|
||||
# of the file as specifed on the #include line (including the
|
||||
# " or <, since that may affect what file is found), which lets
|
||||
# us keep the sort order constant regardless of whether the file
|
||||
# is actually found in a Repository or locally.
|
||||
nodes = []
|
||||
source_dir = node.get_dir()
|
||||
if callable(path):
|
||||
path = path()
|
||||
for include in includes:
|
||||
n, i = self.find_include(include, source_dir, path)
|
||||
|
||||
if n is None:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DependencyWarning,
|
||||
"No dependency generated for file: %s "
|
||||
"(included from: %s) -- file not found" % (i, node),
|
||||
)
|
||||
else:
|
||||
nodes.append((self.sort_key(include), n))
|
||||
|
||||
return [pair[1] for pair in sorted(nodes)]
|
||||
|
||||
class ClassicCPP(Classic):
|
||||
"""
|
||||
A Classic Scanner subclass which takes into account the type of
|
||||
bracketing used to include the file, and uses classic CPP rules
|
||||
for searching for the files based on the bracketing.
|
||||
|
||||
Note that in order for this to work, the regular expression passed
|
||||
to the constructor must return the leading bracket in group 0, and
|
||||
the contained filename in group 1.
|
||||
"""
|
||||
@staticmethod
|
||||
def find_include(include, source_dir, path):
|
||||
include = list(map(SCons.Util.to_str, include))
|
||||
if include[0] == '"':
|
||||
paths = (source_dir,) + tuple(path)
|
||||
else:
|
||||
paths = tuple(path) + (source_dir,)
|
||||
|
||||
n = SCons.Node.FS.find_file(include[1], paths)
|
||||
i = SCons.Util.silent_intern(include[1])
|
||||
return n, i
|
||||
|
||||
@staticmethod
|
||||
def sort_key(include):
|
||||
return SCons.Node.FS._my_normcase(' '.join(include))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,377 @@
|
||||
# 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.
|
||||
|
||||
"""SCons interactive mode. """
|
||||
|
||||
# TODO:
|
||||
#
|
||||
# This has the potential to grow into something with a really big life
|
||||
# of its own, which might or might not be a good thing. Nevertheless,
|
||||
# here are some enhancements that will probably be requested some day
|
||||
# and are worth keeping in mind (assuming this takes off):
|
||||
#
|
||||
# - A command to re-read / re-load the SConscript files. This may
|
||||
# involve allowing people to specify command-line options (e.g. -f,
|
||||
# -I, --no-site-dir) that affect how the SConscript files are read.
|
||||
#
|
||||
# - Additional command-line options on the "build" command.
|
||||
#
|
||||
# Of the supported options that seemed to make sense (after a quick
|
||||
# pass through the list), the ones that seemed likely enough to be
|
||||
# used are listed in the man page and have explicit test scripts.
|
||||
#
|
||||
# These had code changed in Script/Main.py to support them, but didn't
|
||||
# seem likely to be used regularly, so had no test scripts added:
|
||||
#
|
||||
# build --diskcheck=*
|
||||
# build --implicit-cache=*
|
||||
# build --implicit-deps-changed=*
|
||||
# build --implicit-deps-unchanged=*
|
||||
#
|
||||
# These look like they should "just work" with no changes to the
|
||||
# existing code, but like those above, look unlikely to be used and
|
||||
# therefore had no test scripts added:
|
||||
#
|
||||
# build --random
|
||||
#
|
||||
# These I'm not sure about. They might be useful for individual
|
||||
# "build" commands, and may even work, but they seem unlikely enough
|
||||
# that we'll wait until they're requested before spending any time on
|
||||
# writing test scripts for them, or investigating whether they work.
|
||||
#
|
||||
# build -q [??? is there a useful analog to the exit status?]
|
||||
# build --duplicate=
|
||||
# build --profile=
|
||||
# build --max-drift=
|
||||
# build --warn=*
|
||||
# build --Y
|
||||
#
|
||||
# - Most of the SCons command-line options that the "build" command
|
||||
# supports should be settable as default options that apply to all
|
||||
# subsequent "build" commands. Maybe a "set {option}" command that
|
||||
# maps to "SetOption('{option}')".
|
||||
#
|
||||
# - Need something in the 'help' command that prints the -h output.
|
||||
#
|
||||
# - A command to run the configure subsystem separately (must see how
|
||||
# this interacts with the new automake model).
|
||||
#
|
||||
# - Command-line completion of target names; maybe even of SCons options?
|
||||
# Completion is something that's supported by the Python cmd module,
|
||||
# so this should be doable without too much trouble.
|
||||
#
|
||||
|
||||
import cmd
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
class SConsInteractiveCmd(cmd.Cmd):
|
||||
"""\
|
||||
|
||||
build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym.
|
||||
clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym.
|
||||
exit Exit SCons interactive mode.
|
||||
help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms.
|
||||
shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms.
|
||||
version Prints SCons version information.
|
||||
"""
|
||||
|
||||
synonyms = {
|
||||
'b' : 'build',
|
||||
'c' : 'clean',
|
||||
'h' : 'help',
|
||||
'scons' : 'build',
|
||||
'sh' : 'shell',
|
||||
}
|
||||
|
||||
def __init__(self, **kw):
|
||||
cmd.Cmd.__init__(self)
|
||||
for key, val in kw.items():
|
||||
setattr(self, key, val)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
self.shell_variable = 'COMSPEC'
|
||||
else:
|
||||
self.shell_variable = 'SHELL'
|
||||
|
||||
def default(self, argv):
|
||||
print("*** Unknown command: %s" % argv[0])
|
||||
|
||||
def onecmd(self, line):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
print(self.lastcmd)
|
||||
return self.emptyline()
|
||||
self.lastcmd = line
|
||||
if line[0] == '!':
|
||||
line = 'shell ' + line[1:]
|
||||
elif line[0] == '?':
|
||||
line = 'help ' + line[1:]
|
||||
if os.sep == '\\':
|
||||
line = line.replace('\\', '\\\\')
|
||||
argv = shlex.split(line)
|
||||
argv[0] = self.synonyms.get(argv[0], argv[0])
|
||||
if not argv[0]:
|
||||
return self.default(line)
|
||||
else:
|
||||
try:
|
||||
func = getattr(self, 'do_' + argv[0])
|
||||
except AttributeError:
|
||||
return self.default(argv)
|
||||
return func(argv)
|
||||
|
||||
def do_build(self, argv):
|
||||
"""\
|
||||
build [TARGETS] Build the specified TARGETS and their
|
||||
dependencies. 'b' is a synonym.
|
||||
"""
|
||||
import SCons.Node
|
||||
import SCons.SConsign
|
||||
import SCons.Script.Main
|
||||
|
||||
options = copy.deepcopy(self.options)
|
||||
|
||||
options, targets = self.parser.parse_args(argv[1:], values=options)
|
||||
|
||||
SCons.Script.COMMAND_LINE_TARGETS = targets
|
||||
|
||||
if targets:
|
||||
SCons.Script.BUILD_TARGETS = targets
|
||||
else:
|
||||
# If the user didn't specify any targets on the command line,
|
||||
# use the list of default targets.
|
||||
SCons.Script.BUILD_TARGETS = SCons.Script._build_plus_default
|
||||
|
||||
nodes = SCons.Script.Main._build_targets(self.fs,
|
||||
options,
|
||||
targets,
|
||||
self.target_top)
|
||||
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
# Call each of the Node's alter_targets() methods, which may
|
||||
# provide additional targets that ended up as part of the build
|
||||
# (the canonical example being a VariantDir() when we're building
|
||||
# from a source directory) and which we therefore need their
|
||||
# state cleared, too.
|
||||
x = []
|
||||
for n in nodes:
|
||||
x.extend(n.alter_targets()[0])
|
||||
nodes.extend(x)
|
||||
|
||||
# Clean up so that we can perform the next build correctly.
|
||||
#
|
||||
# We do this by walking over all the children of the targets,
|
||||
# and clearing their state.
|
||||
#
|
||||
# We currently have to re-scan each node to find their
|
||||
# children, because built nodes have already been partially
|
||||
# cleared and don't remember their children. (In scons
|
||||
# 0.96.1 and earlier, this wasn't the case, and we didn't
|
||||
# have to re-scan the nodes.)
|
||||
#
|
||||
# Because we have to re-scan each node, we can't clear the
|
||||
# nodes as we walk over them, because we may end up rescanning
|
||||
# a cleared node as we scan a later node. Therefore, only
|
||||
# store the list of nodes that need to be cleared as we walk
|
||||
# the tree, and clear them in a separate pass.
|
||||
#
|
||||
# XXX: Someone more familiar with the inner workings of scons
|
||||
# may be able to point out a more efficient way to do this.
|
||||
|
||||
SCons.Script.Main.progress_display("scons: Clearing cached node information ...")
|
||||
|
||||
seen_nodes = {}
|
||||
|
||||
def get_unseen_children(node, parent, seen_nodes=seen_nodes):
|
||||
def is_unseen(node, seen_nodes=seen_nodes):
|
||||
return node not in seen_nodes
|
||||
return [child for child in node.children(scan=1) if is_unseen(child)]
|
||||
|
||||
def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes):
|
||||
seen_nodes[node] = 1
|
||||
|
||||
# If this file is in a VariantDir and has a
|
||||
# corresponding source file in the source tree, remember the
|
||||
# node in the source tree, too. This is needed in
|
||||
# particular to clear cached implicit dependencies on the
|
||||
# source file, since the scanner will scan it if the
|
||||
# VariantDir was created with duplicate=0.
|
||||
try:
|
||||
rfile_method = node.rfile
|
||||
except AttributeError:
|
||||
return
|
||||
else:
|
||||
rfile = rfile_method()
|
||||
if rfile != node:
|
||||
seen_nodes[rfile] = 1
|
||||
|
||||
for node in nodes:
|
||||
walker = SCons.Node.Walker(node,
|
||||
kids_func=get_unseen_children,
|
||||
eval_func=add_to_seen_nodes)
|
||||
n = walker.get_next()
|
||||
while n:
|
||||
n = walker.get_next()
|
||||
|
||||
for node in seen_nodes.keys():
|
||||
# Call node.clear() to clear most of the state
|
||||
node.clear()
|
||||
# node.clear() doesn't reset node.state, so call
|
||||
# node.set_state() to reset it manually
|
||||
node.set_state(SCons.Node.no_state)
|
||||
node.implicit = None
|
||||
|
||||
# Debug: Uncomment to verify that all Taskmaster reference
|
||||
# counts have been reset to zero.
|
||||
#if node.ref_count != 0:
|
||||
# from SCons.Debug import Trace
|
||||
# Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count))
|
||||
|
||||
# TODO: REMOVE WPD DEBUG 02/14/2022
|
||||
# This call was clearing the list of sconsign files to be written, so it would
|
||||
# only write the results of the first build command. All others wouldn't be written
|
||||
# to .SConsign.
|
||||
# Pretty sure commenting this out is the correct fix.
|
||||
# SCons.SConsign.Reset()
|
||||
SCons.Script.Main.progress_display("scons: done clearing node information.")
|
||||
|
||||
def do_clean(self, argv):
|
||||
"""\
|
||||
clean [TARGETS] Clean (remove) the specified TARGETS
|
||||
and their dependencies. 'c' is a synonym.
|
||||
"""
|
||||
return self.do_build(['build', '--clean'] + argv[1:])
|
||||
|
||||
def do_EOF(self, argv):
|
||||
print()
|
||||
self.do_exit(argv)
|
||||
|
||||
def _do_one_help(self, arg):
|
||||
try:
|
||||
# If help_<arg>() exists, then call it.
|
||||
func = getattr(self, 'help_' + arg)
|
||||
except AttributeError:
|
||||
try:
|
||||
func = getattr(self, 'do_' + arg)
|
||||
except AttributeError:
|
||||
doc = None
|
||||
else:
|
||||
doc = self._doc_to_help(func)
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
doc = self.strip_initial_spaces(func())
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def _doc_to_help(self, obj):
|
||||
doc = obj.__doc__
|
||||
if doc is None:
|
||||
return ''
|
||||
return self._strip_initial_spaces(doc)
|
||||
|
||||
def _strip_initial_spaces(self, s):
|
||||
lines = s.split('\n')
|
||||
spaces = re.match(' *', lines[0]).group(0)
|
||||
def strip_spaces(l, spaces=spaces):
|
||||
if l[:len(spaces)] == spaces:
|
||||
l = l[len(spaces):]
|
||||
return l
|
||||
lines = list(map(strip_spaces, lines))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def do_exit(self, argv):
|
||||
"""\
|
||||
exit Exit SCons interactive mode.
|
||||
"""
|
||||
sys.exit(0)
|
||||
|
||||
def do_help(self, argv):
|
||||
"""\
|
||||
help [COMMAND] Prints help for the specified COMMAND. 'h'
|
||||
and '?' are synonyms.
|
||||
"""
|
||||
if argv[1:]:
|
||||
for arg in argv[1:]:
|
||||
if self._do_one_help(arg):
|
||||
break
|
||||
else:
|
||||
# If bare 'help' is called, print this class's doc
|
||||
# string (if it has one).
|
||||
doc = self._doc_to_help(self.__class__)
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def do_shell(self, argv):
|
||||
"""\
|
||||
shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and
|
||||
'!' are synonyms.
|
||||
"""
|
||||
import subprocess
|
||||
argv = argv[1:]
|
||||
if not argv:
|
||||
argv = os.environ[self.shell_variable]
|
||||
try:
|
||||
# Per "[Python-Dev] subprocess insufficiently platform-independent?"
|
||||
# https://mail.python.org/pipermail/python-dev/2008-August/081979.html "+
|
||||
# Doing the right thing with an argument list currently
|
||||
# requires different shell= values on Windows and Linux.
|
||||
p = subprocess.Popen(argv, shell=(sys.platform=='win32'))
|
||||
except OSError as e:
|
||||
sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror))
|
||||
else:
|
||||
p.wait()
|
||||
|
||||
def do_version(self, argv):
|
||||
"""\
|
||||
version Prints SCons version information.
|
||||
"""
|
||||
sys.stdout.write(self.parser.version + '\n')
|
||||
|
||||
def interact(fs, parser, options, targets, target_top):
|
||||
c = SConsInteractiveCmd(prompt = 'scons>>> ',
|
||||
fs = fs,
|
||||
parser = parser,
|
||||
options = options,
|
||||
targets = targets,
|
||||
target_top = target_top)
|
||||
c.cmdloop()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
1597
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Script/Main.py
Normal file
1597
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Script/Main.py
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,713 @@
|
||||
# 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.
|
||||
|
||||
"""This module defines the Python API provided to SConscript files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import SCons
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Environment
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Node.Alias
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform
|
||||
import SCons.SConf
|
||||
import SCons.Tool
|
||||
from SCons.Util import is_List, is_String, is_Dict, flatten
|
||||
from SCons.Node import SConscriptNodes
|
||||
from . import Main
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import time
|
||||
|
||||
class SConscriptReturn(Exception):
|
||||
pass
|
||||
|
||||
launch_dir = os.path.abspath(os.curdir)
|
||||
|
||||
GlobalDict = None
|
||||
|
||||
# global exports set by Export():
|
||||
global_exports = {}
|
||||
|
||||
# chdir flag
|
||||
sconscript_chdir: bool = True
|
||||
|
||||
def get_calling_namespaces():
|
||||
"""Return the locals and globals for the function that called
|
||||
into this module in the current call stack."""
|
||||
try: 1//0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
frame = sys.exc_info()[2].tb_frame.f_back
|
||||
|
||||
# Find the first frame that *isn't* from this file. This means
|
||||
# that we expect all of the SCons frames that implement an Export()
|
||||
# or SConscript() call to be in this file, so that we can identify
|
||||
# the first non-Script.SConscript frame as the user's local calling
|
||||
# environment, and the locals and globals dictionaries from that
|
||||
# frame as the calling namespaces. See the comment below preceding
|
||||
# the DefaultEnvironmentCall block for even more explanation.
|
||||
while frame.f_globals.get("__name__") == __name__:
|
||||
frame = frame.f_back
|
||||
|
||||
return frame.f_locals, frame.f_globals
|
||||
|
||||
|
||||
def compute_exports(exports):
|
||||
"""Compute a dictionary of exports given one of the parameters
|
||||
to the Export() function or the exports argument to SConscript()."""
|
||||
|
||||
loc, glob = get_calling_namespaces()
|
||||
|
||||
retval = {}
|
||||
try:
|
||||
for export in exports:
|
||||
if is_Dict(export):
|
||||
retval.update(export)
|
||||
else:
|
||||
try:
|
||||
retval[export] = loc[export]
|
||||
except KeyError:
|
||||
retval[export] = glob[export]
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x)
|
||||
|
||||
return retval
|
||||
|
||||
class Frame:
|
||||
"""A frame on the SConstruct/SConscript call stack"""
|
||||
def __init__(self, fs, exports, sconscript):
|
||||
self.globals = BuildDefaultGlobals()
|
||||
self.retval = None
|
||||
self.prev_dir = fs.getcwd()
|
||||
self.exports = compute_exports(exports) # exports from the calling SConscript
|
||||
# make sure the sconscript attr is a Node.
|
||||
if isinstance(sconscript, SCons.Node.Node):
|
||||
self.sconscript = sconscript
|
||||
elif sconscript == '-':
|
||||
self.sconscript = None
|
||||
else:
|
||||
self.sconscript = fs.File(str(sconscript))
|
||||
|
||||
# the SConstruct/SConscript call stack:
|
||||
call_stack = []
|
||||
|
||||
# For documentation on the methods in this file, see the scons man-page
|
||||
|
||||
def Return(*vars, **kw):
|
||||
retval = []
|
||||
try:
|
||||
fvars = flatten(vars)
|
||||
for var in fvars:
|
||||
for v in var.split():
|
||||
retval.append(call_stack[-1].globals[v])
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x)
|
||||
|
||||
if len(retval) == 1:
|
||||
call_stack[-1].retval = retval[0]
|
||||
else:
|
||||
call_stack[-1].retval = tuple(retval)
|
||||
|
||||
stop = kw.get('stop', True)
|
||||
|
||||
if stop:
|
||||
raise SConscriptReturn
|
||||
|
||||
|
||||
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
|
||||
|
||||
def handle_missing_SConscript(f, must_exist = True):
|
||||
"""Take appropriate action on missing file in SConscript() call.
|
||||
|
||||
Print a warning or raise an exception on missing file, unless
|
||||
missing is explicitly allowed by the *must_exist* parameter or by
|
||||
a global flag.
|
||||
|
||||
Args:
|
||||
f: path to missing configuration file
|
||||
must_exist: if true (the default), fail. If false
|
||||
do nothing, allowing a build to declare it's okay to be missing.
|
||||
|
||||
Raises:
|
||||
UserError: if *must_exist* is true or if global
|
||||
:data:`SCons.Script._no_missing_sconscript` is true.
|
||||
|
||||
.. versionchanged: 4.6.0
|
||||
Changed default from False.
|
||||
"""
|
||||
if not must_exist: # explicitly set False: ok
|
||||
return
|
||||
if not SCons.Script._no_missing_sconscript: # system default changed: ok
|
||||
return
|
||||
msg = f"missing SConscript file {f.get_internal_path()!r}"
|
||||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
|
||||
def _SConscript(fs, *files, **kw):
|
||||
top = fs.Top
|
||||
sd = fs.SConstruct_dir.rdir()
|
||||
exports = kw.get('exports', [])
|
||||
|
||||
# evaluate each SConscript file
|
||||
results = []
|
||||
for fn in files:
|
||||
call_stack.append(Frame(fs, exports, fn))
|
||||
old_sys_path = sys.path
|
||||
try:
|
||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1
|
||||
if fn == "-":
|
||||
exec(sys.stdin.read(), call_stack[-1].globals)
|
||||
else:
|
||||
if isinstance(fn, SCons.Node.Node):
|
||||
f = fn
|
||||
else:
|
||||
f = fs.File(str(fn))
|
||||
_file_ = None
|
||||
SConscriptNodes.add(f)
|
||||
|
||||
# Change directory to the top of the source
|
||||
# tree to make sure the os's cwd and the cwd of
|
||||
# fs match so we can open the SConscript.
|
||||
fs.chdir(top, change_os_dir=True)
|
||||
if f.rexists():
|
||||
actual = f.rfile()
|
||||
_file_ = open(actual.get_abspath(), "rb")
|
||||
elif f.srcnode().rexists():
|
||||
actual = f.srcnode().rfile()
|
||||
_file_ = open(actual.get_abspath(), "rb")
|
||||
elif f.has_src_builder():
|
||||
# The SConscript file apparently exists in a source
|
||||
# code management system. Build it, but then clear
|
||||
# the builder so that it doesn't get built *again*
|
||||
# during the actual build phase.
|
||||
f.build()
|
||||
f.built()
|
||||
f.builder_set(None)
|
||||
if f.exists():
|
||||
_file_ = open(f.get_abspath(), "rb")
|
||||
if _file_:
|
||||
# Chdir to the SConscript directory. Use a path
|
||||
# name relative to the SConstruct file so that if
|
||||
# we're using the -f option, we're essentially
|
||||
# creating a parallel SConscript directory structure
|
||||
# in our local directory tree.
|
||||
#
|
||||
# XXX This is broken for multiple-repository cases
|
||||
# where the SConstruct and SConscript files might be
|
||||
# in different Repositories. For now, cross that
|
||||
# bridge when someone comes to it.
|
||||
try:
|
||||
src_dir = kw['src_dir']
|
||||
except KeyError:
|
||||
ldir = fs.Dir(f.dir.get_path(sd))
|
||||
else:
|
||||
ldir = fs.Dir(src_dir)
|
||||
if not ldir.is_under(f.dir):
|
||||
# They specified a source directory, but
|
||||
# it's above the SConscript directory.
|
||||
# Do the sensible thing and just use the
|
||||
# SConcript directory.
|
||||
ldir = fs.Dir(f.dir.get_path(sd))
|
||||
try:
|
||||
fs.chdir(ldir, change_os_dir=sconscript_chdir)
|
||||
except OSError:
|
||||
# There was no local directory, so we should be
|
||||
# able to chdir to the Repository directory.
|
||||
# Note that we do this directly, not through
|
||||
# fs.chdir(), because we still need to
|
||||
# interpret the stuff within the SConscript file
|
||||
# relative to where we are logically.
|
||||
fs.chdir(ldir, change_os_dir=False)
|
||||
os.chdir(actual.dir.get_abspath())
|
||||
|
||||
# Append the SConscript directory to the beginning
|
||||
# of sys.path so Python modules in the SConscript
|
||||
# directory can be easily imported.
|
||||
sys.path = [ f.dir.get_abspath() ] + sys.path
|
||||
|
||||
# This is the magic line that actually reads up
|
||||
# and executes the stuff in the SConscript file.
|
||||
# The locals for this frame contain the special
|
||||
# bottom-of-the-stack marker so that any
|
||||
# exceptions that occur when processing this
|
||||
# SConscript can base the printed frames at this
|
||||
# level and not show SCons internals as well.
|
||||
call_stack[-1].globals.update({stack_bottom:1})
|
||||
old_file = call_stack[-1].globals.get('__file__')
|
||||
try:
|
||||
del call_stack[-1].globals['__file__']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
try:
|
||||
if Main.print_time:
|
||||
start_time = time.perf_counter()
|
||||
scriptdata = _file_.read()
|
||||
scriptname = _file_.name
|
||||
_file_.close()
|
||||
if SCons.Debug.sconscript_trace:
|
||||
print("scons: Entering "+str(scriptname))
|
||||
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
|
||||
if SCons.Debug.sconscript_trace:
|
||||
print("scons: Exiting "+str(scriptname))
|
||||
except SConscriptReturn:
|
||||
if SCons.Debug.sconscript_trace:
|
||||
print("scons: Exiting "+str(scriptname))
|
||||
else:
|
||||
pass
|
||||
finally:
|
||||
if Main.print_time:
|
||||
elapsed = time.perf_counter() - start_time
|
||||
print('SConscript:%s took %0.3f ms' % (f.get_abspath(), elapsed * 1000.0))
|
||||
|
||||
if old_file is not None:
|
||||
call_stack[-1].globals.update({__file__:old_file})
|
||||
|
||||
else:
|
||||
handle_missing_SConscript(f, kw.get('must_exist', True))
|
||||
|
||||
finally:
|
||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
|
||||
sys.path = old_sys_path
|
||||
frame = call_stack.pop()
|
||||
try:
|
||||
fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir)
|
||||
except OSError:
|
||||
# There was no local directory, so chdir to the
|
||||
# Repository directory. Like above, we do this
|
||||
# directly.
|
||||
fs.chdir(frame.prev_dir, change_os_dir=False)
|
||||
rdir = frame.prev_dir.rdir()
|
||||
rdir._create() # Make sure there's a directory there.
|
||||
try:
|
||||
os.chdir(rdir.get_abspath())
|
||||
except OSError as e:
|
||||
# We still couldn't chdir there, so raise the error,
|
||||
# but only if actions are being executed.
|
||||
#
|
||||
# If the -n option was used, the directory would *not*
|
||||
# have been created and we should just carry on and
|
||||
# let things muddle through. This isn't guaranteed
|
||||
# to work if the SConscript files are reading things
|
||||
# from disk (for example), but it should work well
|
||||
# enough for most configurations.
|
||||
if SCons.Action.execute_actions:
|
||||
raise e
|
||||
|
||||
results.append(frame.retval)
|
||||
|
||||
# if we only have one script, don't return a tuple
|
||||
if len(results) == 1:
|
||||
return results[0]
|
||||
else:
|
||||
return tuple(results)
|
||||
|
||||
def SConscript_exception(file=sys.stderr):
|
||||
"""Print an exception stack trace just for the SConscript file(s).
|
||||
This will show users who have Python errors where the problem is,
|
||||
without cluttering the output with all of the internal calls leading
|
||||
up to where we exec the SConscript."""
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
tb = exc_tb
|
||||
while tb and stack_bottom not in tb.tb_frame.f_locals:
|
||||
tb = tb.tb_next
|
||||
if not tb:
|
||||
# We did not find our exec statement, so this was actually a bug
|
||||
# in SCons itself. Show the whole stack.
|
||||
tb = exc_tb
|
||||
stack = traceback.extract_tb(tb)
|
||||
try:
|
||||
type = exc_type.__name__
|
||||
except AttributeError:
|
||||
type = str(exc_type)
|
||||
if type[:11] == "exceptions.":
|
||||
type = type[11:]
|
||||
file.write('%s: %s:\n' % (type, exc_value))
|
||||
for fname, line, func, text in stack:
|
||||
file.write(' File "%s", line %d:\n' % (fname, line))
|
||||
file.write(' %s\n' % text)
|
||||
|
||||
def annotate(node):
|
||||
"""Annotate a node with the stack frame describing the
|
||||
SConscript file and line number that created it."""
|
||||
tb = sys.exc_info()[2]
|
||||
while tb and stack_bottom not in tb.tb_frame.f_locals:
|
||||
tb = tb.tb_next
|
||||
if not tb:
|
||||
# We did not find any exec of an SConscript file: what?!
|
||||
raise SCons.Errors.InternalError("could not find SConscript stack frame")
|
||||
node.creator = traceback.extract_stack(tb)[0]
|
||||
|
||||
# The following line would cause each Node to be annotated using the
|
||||
# above function. Unfortunately, this is a *huge* performance hit, so
|
||||
# leave this disabled until we find a more efficient mechanism.
|
||||
#SCons.Node.Annotate = annotate
|
||||
|
||||
class SConsEnvironment(SCons.Environment.Base):
|
||||
"""An Environment subclass that contains all of the methods that
|
||||
are particular to the wrapper SCons interface and which aren't
|
||||
(or shouldn't be) part of the build engine itself.
|
||||
|
||||
Note that not all of the methods of this class have corresponding
|
||||
global functions, there are some private methods.
|
||||
"""
|
||||
|
||||
#
|
||||
# Private methods of an SConsEnvironment.
|
||||
#
|
||||
@staticmethod
|
||||
def _get_major_minor_revision(version_string):
|
||||
"""Split a version string into major, minor and (optionally)
|
||||
revision parts.
|
||||
|
||||
This is complicated by the fact that a version string can be
|
||||
something like 3.2b1."""
|
||||
version = version_string.split(' ')[0].split('.')
|
||||
v_major = int(version[0])
|
||||
v_minor = int(re.match(r'\d+', version[1]).group())
|
||||
if len(version) >= 3:
|
||||
v_revision = int(re.match(r'\d+', version[2]).group())
|
||||
else:
|
||||
v_revision = 0
|
||||
return v_major, v_minor, v_revision
|
||||
|
||||
def _get_SConscript_filenames(self, ls, kw):
|
||||
"""
|
||||
Convert the parameters passed to SConscript() calls into a list
|
||||
of files and export variables. If the parameters are invalid,
|
||||
throws SCons.Errors.UserError. Returns a tuple (l, e) where l
|
||||
is a list of SConscript filenames and e is a list of exports.
|
||||
"""
|
||||
exports = []
|
||||
|
||||
if len(ls) == 0:
|
||||
try:
|
||||
dirs = kw["dirs"]
|
||||
except KeyError:
|
||||
raise SCons.Errors.UserError("Invalid SConscript usage - no parameters")
|
||||
|
||||
if not is_List(dirs):
|
||||
dirs = [ dirs ]
|
||||
dirs = list(map(str, dirs))
|
||||
|
||||
name = kw.get('name', 'SConscript')
|
||||
|
||||
files = [os.path.join(n, name) for n in dirs]
|
||||
|
||||
elif len(ls) == 1:
|
||||
|
||||
files = ls[0]
|
||||
|
||||
elif len(ls) == 2:
|
||||
|
||||
files = ls[0]
|
||||
exports = self.Split(ls[1])
|
||||
|
||||
else:
|
||||
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments")
|
||||
|
||||
if not is_List(files):
|
||||
files = [ files ]
|
||||
|
||||
if kw.get('exports'):
|
||||
exports.extend(self.Split(kw['exports']))
|
||||
|
||||
variant_dir = kw.get('variant_dir')
|
||||
if variant_dir:
|
||||
if len(files) != 1:
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir")
|
||||
duplicate = kw.get('duplicate', 1)
|
||||
src_dir = kw.get('src_dir')
|
||||
if not src_dir:
|
||||
src_dir, fname = os.path.split(str(files[0]))
|
||||
files = [os.path.join(str(variant_dir), fname)]
|
||||
else:
|
||||
if not isinstance(src_dir, SCons.Node.Node):
|
||||
src_dir = self.fs.Dir(src_dir)
|
||||
fn = files[0]
|
||||
if not isinstance(fn, SCons.Node.Node):
|
||||
fn = self.fs.File(fn)
|
||||
if fn.is_under(src_dir):
|
||||
# Get path relative to the source directory.
|
||||
fname = fn.get_path(src_dir)
|
||||
files = [os.path.join(str(variant_dir), fname)]
|
||||
else:
|
||||
files = [fn.get_abspath()]
|
||||
kw['src_dir'] = variant_dir
|
||||
self.fs.VariantDir(variant_dir, src_dir, duplicate)
|
||||
|
||||
return (files, exports)
|
||||
|
||||
#
|
||||
# Public methods of an SConsEnvironment. These get
|
||||
# entry points in the global namespace so they can be called
|
||||
# as global functions.
|
||||
#
|
||||
|
||||
def Configure(self, *args, **kw):
|
||||
if not SCons.Script.sconscript_reading:
|
||||
raise SCons.Errors.UserError("Calling Configure from Builders is not supported.")
|
||||
kw['_depth'] = kw.get('_depth', 0) + 1
|
||||
return SCons.Environment.Base.Configure(self, *args, **kw)
|
||||
|
||||
def Default(self, *targets):
|
||||
SCons.Script._Set_Default_Targets(self, targets)
|
||||
|
||||
@staticmethod
|
||||
def GetSConsVersion():
|
||||
"""Return the current SCons version.
|
||||
|
||||
.. versionadded:: 4.8.0
|
||||
"""
|
||||
return SConsEnvironment._get_major_minor_revision(SCons.__version__)
|
||||
|
||||
@staticmethod
|
||||
def EnsureSConsVersion(major, minor, revision = 0):
|
||||
"""Exit abnormally if the SCons version is not late enough."""
|
||||
# split string to avoid replacement during build process
|
||||
if SCons.__version__ == '__' + 'VERSION__':
|
||||
SCons.Warnings.warn(SCons.Warnings.DevelopmentVersionWarning,
|
||||
"EnsureSConsVersion is ignored for development version")
|
||||
return
|
||||
if SConsEnvironment.GetSConsVersion() < (major, minor, revision):
|
||||
if revision:
|
||||
scons_ver_string = '%d.%d.%d' % (major, minor, revision)
|
||||
else:
|
||||
scons_ver_string = '%d.%d' % (major, minor)
|
||||
print("SCons %s or greater required, but you have SCons %s" % \
|
||||
(scons_ver_string, SCons.__version__))
|
||||
sys.exit(2)
|
||||
|
||||
@staticmethod
|
||||
def EnsurePythonVersion(major, minor):
|
||||
"""Exit abnormally if the Python version is not late enough."""
|
||||
if sys.version_info < (major, minor):
|
||||
v = sys.version.split()[0]
|
||||
print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v))
|
||||
sys.exit(2)
|
||||
|
||||
@staticmethod
|
||||
def Exit(value=0):
|
||||
sys.exit(value)
|
||||
|
||||
def Export(self, *vars, **kw):
|
||||
for var in vars:
|
||||
global_exports.update(compute_exports(self.Split(var)))
|
||||
global_exports.update(kw)
|
||||
|
||||
@staticmethod
|
||||
def GetLaunchDir():
|
||||
global launch_dir
|
||||
return launch_dir
|
||||
|
||||
def GetOption(self, name):
|
||||
name = self.subst(name)
|
||||
return SCons.Script.Main.GetOption(name)
|
||||
|
||||
def Help(self, text, append = False, local_only = False):
|
||||
"""Update the help text.
|
||||
|
||||
The previous help text has *text* appended to it, except on the
|
||||
first call. On first call, the values of *append* and *local_only*
|
||||
are considered to determine what is appended to.
|
||||
|
||||
Arguments:
|
||||
text: string to add to the help text.
|
||||
append: on first call, if true, keep the existing help text
|
||||
(default False).
|
||||
local_only: on first call, if true and *append* is also true,
|
||||
keep only the help text from AddOption calls.
|
||||
|
||||
.. versionchanged:: 4.6.0
|
||||
The *keep_local* parameter was added.
|
||||
.. versionchanged:: 4.9.0
|
||||
The *keep_local* parameter was renamed *local_only* to match manpage
|
||||
"""
|
||||
text = self.subst(text, raw=1)
|
||||
SCons.Script.HelpFunction(text, append=append, local_only=local_only)
|
||||
|
||||
def Import(self, *vars):
|
||||
try:
|
||||
frame = call_stack[-1]
|
||||
globals = frame.globals
|
||||
exports = frame.exports
|
||||
for var in vars:
|
||||
var = self.Split(var)
|
||||
for v in var:
|
||||
if v == '*':
|
||||
globals.update(global_exports)
|
||||
globals.update(exports)
|
||||
else:
|
||||
if v in exports:
|
||||
globals[v] = exports[v]
|
||||
else:
|
||||
globals[v] = global_exports[v]
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
|
||||
|
||||
def SConscript(self, *ls, **kw):
|
||||
"""Execute SCons configuration files.
|
||||
|
||||
Parameters:
|
||||
*ls (str or list): configuration file(s) to execute.
|
||||
|
||||
Keyword arguments:
|
||||
dirs (list): execute SConscript in each listed directory.
|
||||
name (str): execute script 'name' (used only with 'dirs').
|
||||
exports (list or dict): locally export variables the
|
||||
called script(s) can import.
|
||||
variant_dir (str): mirror sources needed for the build in
|
||||
a variant directory to allow building in it.
|
||||
duplicate (bool): physically duplicate sources instead of just
|
||||
adjusting paths of derived files (used only with 'variant_dir')
|
||||
(default is True).
|
||||
must_exist (bool): fail if a requested script is missing
|
||||
(default is False, default is deprecated).
|
||||
|
||||
Returns:
|
||||
list of variables returned by the called script
|
||||
|
||||
Raises:
|
||||
UserError: a script is not found and such exceptions are enabled.
|
||||
"""
|
||||
|
||||
def subst_element(x, subst=self.subst):
|
||||
if SCons.Util.is_List(x):
|
||||
x = list(map(subst, x))
|
||||
else:
|
||||
x = subst(x)
|
||||
return x
|
||||
ls = list(map(subst_element, ls))
|
||||
subst_kw = {}
|
||||
for key, val in kw.items():
|
||||
if is_String(val):
|
||||
val = self.subst(val)
|
||||
elif SCons.Util.is_List(val):
|
||||
val = [self.subst(v) if is_String(v) else v for v in val]
|
||||
subst_kw[key] = val
|
||||
|
||||
files, exports = self._get_SConscript_filenames(ls, subst_kw)
|
||||
subst_kw['exports'] = exports
|
||||
return _SConscript(self.fs, *files, **subst_kw)
|
||||
|
||||
@staticmethod
|
||||
def SConscriptChdir(flag):
|
||||
global sconscript_chdir
|
||||
sconscript_chdir = flag
|
||||
|
||||
def SetOption(self, name, value):
|
||||
name = self.subst(name)
|
||||
SCons.Script.Main.SetOption(name, value)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
SCons.Environment.Environment = SConsEnvironment
|
||||
|
||||
def Configure(*args, **kw):
|
||||
if not SCons.Script.sconscript_reading:
|
||||
raise SCons.Errors.UserError("Calling Configure from Builders is not supported.")
|
||||
kw['_depth'] = 1
|
||||
return SCons.SConf.SConf(*args, **kw)
|
||||
|
||||
# It's very important that the DefaultEnvironmentCall() class stay in this
|
||||
# file, with the get_calling_namespaces() function, the compute_exports()
|
||||
# function, the Frame class and the SConsEnvironment.Export() method.
|
||||
# These things make up the calling stack leading up to the actual global
|
||||
# Export() or SConscript() call that the user issued. We want to allow
|
||||
# users to export local variables that they define, like so:
|
||||
#
|
||||
# def func():
|
||||
# x = 1
|
||||
# Export('x')
|
||||
#
|
||||
# To support this, the get_calling_namespaces() function assumes that
|
||||
# the *first* stack frame that's not from this file is the local frame
|
||||
# for the Export() or SConscript() call.
|
||||
|
||||
_DefaultEnvironmentProxy = None
|
||||
|
||||
def get_DefaultEnvironmentProxy():
|
||||
global _DefaultEnvironmentProxy
|
||||
if not _DefaultEnvironmentProxy:
|
||||
default_env = SCons.Defaults.DefaultEnvironment()
|
||||
_DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env)
|
||||
return _DefaultEnvironmentProxy
|
||||
|
||||
class DefaultEnvironmentCall:
|
||||
"""A class that implements "global function" calls of
|
||||
Environment methods by fetching the specified method from the
|
||||
DefaultEnvironment's class. Note that this uses an intermediate
|
||||
proxy class instead of calling the DefaultEnvironment method
|
||||
directly so that the proxy can override the subst() method and
|
||||
thereby prevent expansion of construction variables (since from
|
||||
the user's point of view this was called as a global function,
|
||||
with no associated construction environment)."""
|
||||
def __init__(self, method_name, subst=0):
|
||||
self.method_name = method_name
|
||||
if subst:
|
||||
self.factory = SCons.Defaults.DefaultEnvironment
|
||||
else:
|
||||
self.factory = get_DefaultEnvironmentProxy
|
||||
def __call__(self, *args, **kw):
|
||||
env = self.factory()
|
||||
method = getattr(env, self.method_name)
|
||||
return method(*args, **kw)
|
||||
|
||||
|
||||
def BuildDefaultGlobals():
|
||||
"""
|
||||
Create a dictionary containing all the default globals for
|
||||
SConstruct and SConscript files.
|
||||
"""
|
||||
|
||||
global GlobalDict
|
||||
if GlobalDict is None:
|
||||
GlobalDict = {}
|
||||
|
||||
import SCons.Script
|
||||
d = SCons.Script.__dict__
|
||||
def not_a_module(m, d=d, mtype=type(SCons.Script)):
|
||||
return not isinstance(d[m], mtype)
|
||||
for m in filter(not_a_module, dir(SCons.Script)):
|
||||
GlobalDict[m] = d[m]
|
||||
|
||||
return GlobalDict.copy()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,498 @@
|
||||
# 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.
|
||||
|
||||
"""The main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
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.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from io import StringIO
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Special chicken-and-egg handling of the "--debug=memoizer" flag:
|
||||
#
|
||||
# SCons.Memoize contains a metaclass implementation that affects how
|
||||
# the other classes are instantiated. The Memoizer may add shim methods
|
||||
# to classes that have methods that cache computed values in order to
|
||||
# count and report the hits and misses.
|
||||
#
|
||||
# If we wait to enable the Memoization until after we've parsed the
|
||||
# command line options normally, it will be too late, because the Memoizer
|
||||
# will have already analyzed the classes that it's Memoizing and decided
|
||||
# to not add the shims. So we use a special-case, up-front check for
|
||||
# the "--debug=memoizer" flag and enable Memoizer before we import any
|
||||
# of the other modules that use it.
|
||||
# Update: this breaks if the option isn't exactly "--debug=memoizer",
|
||||
# like if there is more than one debug option as a csv. Do a bit more work.
|
||||
|
||||
_args = sys.argv + os.environ.get("SCONSFLAGS", "").split()
|
||||
_args = (
|
||||
arg[len("--debug=") :].split(",")
|
||||
for arg in _args
|
||||
if arg.startswith("--debug=")
|
||||
)
|
||||
_args = list(itertools.chain.from_iterable(_args))
|
||||
if "memoizer" in _args:
|
||||
import SCons.Memoize
|
||||
import SCons.Warnings
|
||||
try:
|
||||
SCons.Memoize.EnableMemoization()
|
||||
except SCons.Warnings.SConsWarning:
|
||||
# Some warning was thrown. Arrange for it to be displayed
|
||||
# or not after warnings are configured.
|
||||
from . import Main
|
||||
exc_type, exc_value, tb = sys.exc_info()
|
||||
Main.delayed_warnings.append((exc_type, exc_value))
|
||||
del _args
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Environment
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.Scanner
|
||||
import SCons.SConf
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Variables
|
||||
import SCons.Defaults
|
||||
|
||||
from . import Main
|
||||
|
||||
main = Main.main
|
||||
|
||||
# The following are global class definitions and variables that used to
|
||||
# live directly in this module back before 0.96.90, when it contained
|
||||
# a lot of code. Some SConscript files in widely-distributed packages
|
||||
# (Blender is the specific example) actually reached into SCons.Script
|
||||
# directly to use some of these. Rather than break those SConscript
|
||||
# files, we're going to propagate these names into the SCons.Script
|
||||
# namespace here.
|
||||
#
|
||||
# Some of these are commented out because it's *really* unlikely anyone
|
||||
# used them, but we're going to leave the comment here to try to make
|
||||
# it obvious what to do if the situation arises.
|
||||
BuildTask = Main.BuildTask
|
||||
CleanTask = Main.CleanTask
|
||||
QuestionTask = Main.QuestionTask
|
||||
#SConscriptSettableOptions = Main.SConscriptSettableOptions
|
||||
|
||||
AddOption = Main.AddOption
|
||||
PrintHelp = Main.PrintHelp
|
||||
GetOption = Main.GetOption
|
||||
SetOption = Main.SetOption
|
||||
ValidateOptions = Main.ValidateOptions
|
||||
Progress = Main.Progress
|
||||
GetBuildFailures = Main.GetBuildFailures
|
||||
DebugOptions = Main.DebugOptions
|
||||
|
||||
#keep_going_on_error = Main.keep_going_on_error
|
||||
#print_dtree = Main.print_dtree
|
||||
#print_explanations = Main.print_explanations
|
||||
#print_includes = Main.print_includes
|
||||
#print_objects = Main.print_objects
|
||||
#print_time = Main.print_time
|
||||
#print_tree = Main.print_tree
|
||||
#memory_stats = Main.memory_stats
|
||||
#ignore_errors = Main.ignore_errors
|
||||
#sconscript_time = Main.sconscript_time
|
||||
#command_time = Main.command_time
|
||||
#exit_status = Main.exit_status
|
||||
#profiling = Main.profiling
|
||||
#repositories = Main.repositories
|
||||
|
||||
from . import SConscript as _SConscript # pylint: disable=import-outside-toplevel
|
||||
|
||||
call_stack = _SConscript.call_stack
|
||||
|
||||
#
|
||||
Action = SCons.Action.Action
|
||||
AddMethod = SCons.Util.AddMethod
|
||||
AllowSubstExceptions = SCons.Subst.SetAllowableExceptions
|
||||
Builder = SCons.Builder.Builder
|
||||
Configure = _SConscript.Configure
|
||||
Environment = SCons.Environment.Environment
|
||||
#OptParser = SCons.SConsOptions.OptParser
|
||||
FindPathDirs = SCons.Scanner.FindPathDirs
|
||||
Platform = SCons.Platform.Platform
|
||||
Virtualenv = SCons.Platform.virtualenv.Virtualenv
|
||||
Return = _SConscript.Return
|
||||
Scanner = SCons.Scanner.ScannerBase
|
||||
Tool = SCons.Tool.Tool
|
||||
WhereIs = SCons.Util.WhereIs
|
||||
|
||||
#
|
||||
BoolVariable = SCons.Variables.BoolVariable
|
||||
EnumVariable = SCons.Variables.EnumVariable
|
||||
ListVariable = SCons.Variables.ListVariable
|
||||
PackageVariable = SCons.Variables.PackageVariable
|
||||
PathVariable = SCons.Variables.PathVariable
|
||||
|
||||
|
||||
# Action factories.
|
||||
Chmod = SCons.Defaults.Chmod
|
||||
Copy = SCons.Defaults.Copy
|
||||
Delete = SCons.Defaults.Delete
|
||||
Mkdir = SCons.Defaults.Mkdir
|
||||
Move = SCons.Defaults.Move
|
||||
Touch = SCons.Defaults.Touch
|
||||
|
||||
# Pre-made, public scanners.
|
||||
CScanner = SCons.Tool.CScanner
|
||||
# Nuitka: Avoid unused tools
|
||||
# DScanner = SCons.Tool.DScanner
|
||||
DirScanner = SCons.Defaults.DirScanner
|
||||
ProgramScanner = SCons.Tool.ProgramScanner
|
||||
SourceFileScanner = SCons.Tool.SourceFileScanner
|
||||
|
||||
# Functions we might still convert to Environment methods.
|
||||
CScan = SCons.Defaults.CScan
|
||||
DefaultEnvironment = SCons.Defaults.DefaultEnvironment
|
||||
|
||||
# Other variables we provide.
|
||||
class TargetList(collections.UserList):
|
||||
def _do_nothing(self, *args, **kw):
|
||||
pass
|
||||
def _add_Default(self, list):
|
||||
self.extend(list)
|
||||
def _clear(self):
|
||||
del self[:]
|
||||
|
||||
ARGUMENTS = {}
|
||||
ARGLIST = []
|
||||
BUILD_TARGETS = TargetList()
|
||||
COMMAND_LINE_TARGETS = []
|
||||
DEFAULT_TARGETS = []
|
||||
|
||||
# BUILD_TARGETS can be modified in the SConscript files. If so, we
|
||||
# want to treat the modified BUILD_TARGETS list as if they specified
|
||||
# targets on the command line. To do that, though, we need to know if
|
||||
# BUILD_TARGETS was modified through "official" APIs or by hand. We do
|
||||
# this by updating two lists in parallel, the documented BUILD_TARGETS
|
||||
# list, above, and this internal _build_plus_default targets list which
|
||||
# should only have "official" API changes. Then Script/Main.py can
|
||||
# compare these two afterwards to figure out if the user added their
|
||||
# own targets to BUILD_TARGETS.
|
||||
_build_plus_default = TargetList()
|
||||
|
||||
def _Add_Arguments(alist):
|
||||
"""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):
|
||||
"""Add value(s) to ``COMMAND_LINE_TARGETS`` and ``BUILD_TARGETS``."""
|
||||
if tlist:
|
||||
COMMAND_LINE_TARGETS.extend(tlist)
|
||||
BUILD_TARGETS.extend(tlist)
|
||||
BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
|
||||
BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
|
||||
_build_plus_default.extend(tlist)
|
||||
_build_plus_default._add_Default = _build_plus_default._do_nothing
|
||||
_build_plus_default._clear = _build_plus_default._do_nothing
|
||||
|
||||
def _Remove_Argument(aarg):
|
||||
"""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):
|
||||
"""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
|
||||
|
||||
def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
|
||||
if d is None:
|
||||
d = [fs.Dir('.')]
|
||||
return d
|
||||
|
||||
_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
|
||||
|
||||
def _Set_Default_Targets(env, tlist):
|
||||
global DEFAULT_TARGETS
|
||||
global _Get_Default_Targets
|
||||
_Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
|
||||
for t in tlist:
|
||||
if t is None:
|
||||
# Delete the elements from the list in-place, don't
|
||||
# reassign an empty list to DEFAULT_TARGETS, so that the
|
||||
# variables will still point to the same object we point to.
|
||||
del DEFAULT_TARGETS[:]
|
||||
BUILD_TARGETS._clear()
|
||||
_build_plus_default._clear()
|
||||
elif isinstance(t, SCons.Node.Node):
|
||||
DEFAULT_TARGETS.append(t)
|
||||
BUILD_TARGETS._add_Default([t])
|
||||
_build_plus_default._add_Default([t])
|
||||
else:
|
||||
nodes = env.arg2nodes(t, env.fs.Entry)
|
||||
DEFAULT_TARGETS.extend(nodes)
|
||||
BUILD_TARGETS._add_Default(nodes)
|
||||
_build_plus_default._add_Default(nodes)
|
||||
|
||||
|
||||
help_text = None
|
||||
|
||||
|
||||
def HelpFunction(text, append = False, local_only = False):
|
||||
"""The implementaion of the the ``Help`` method.
|
||||
|
||||
See :meth:`~SCons.Script.SConscript.Help`.
|
||||
|
||||
.. versionchanged:: 4.6.0
|
||||
The *keep_local* parameter was added.
|
||||
.. versionchanged:: 4.9.0
|
||||
The *keep_local* parameter was renamed *local_only* to match manpage
|
||||
"""
|
||||
global help_text
|
||||
if help_text is None:
|
||||
if append:
|
||||
with StringIO() as s:
|
||||
PrintHelp(s, local_only=local_only)
|
||||
help_text = s.getvalue()
|
||||
else:
|
||||
help_text = ""
|
||||
|
||||
help_text += text
|
||||
|
||||
|
||||
# Will be non-zero if we are reading an SConscript file.
|
||||
sconscript_reading = 0
|
||||
|
||||
_no_missing_sconscript = True
|
||||
_warn_missing_sconscript_deprecated = False # TODO: now unused
|
||||
|
||||
def set_missing_sconscript_error(flag = True):
|
||||
"""Set behavior on missing file in SConscript() call.
|
||||
|
||||
Returns:
|
||||
previous value
|
||||
"""
|
||||
global _no_missing_sconscript
|
||||
old = _no_missing_sconscript
|
||||
_no_missing_sconscript = flag
|
||||
return old
|
||||
|
||||
|
||||
def Variables(files=None, args=ARGUMENTS):
|
||||
return SCons.Variables.Variables(files, args)
|
||||
|
||||
|
||||
# Adding global functions to the SConscript name space.
|
||||
#
|
||||
# Static functions that do not trigger initialization of
|
||||
# DefaultEnvironment() and don't use its state.
|
||||
GetSConsVersion = _SConscript.SConsEnvironment.GetSConsVersion
|
||||
EnsureSConsVersion = _SConscript.SConsEnvironment.EnsureSConsVersion
|
||||
EnsurePythonVersion = _SConscript.SConsEnvironment.EnsurePythonVersion
|
||||
Exit = _SConscript.SConsEnvironment.Exit
|
||||
GetLaunchDir = _SConscript.SConsEnvironment.GetLaunchDir
|
||||
SConscriptChdir = _SConscript.SConsEnvironment.SConscriptChdir
|
||||
|
||||
# Functions that end up calling methods or Builders in the
|
||||
# DefaultEnvironment().
|
||||
GlobalDefaultEnvironmentFunctions = [
|
||||
# Methods from the SConsEnvironment class, above.
|
||||
'Default',
|
||||
'Export',
|
||||
'Help',
|
||||
'Import',
|
||||
#'SConscript', is handled separately, below.
|
||||
|
||||
# Methods from the Environment.Base class.
|
||||
'AddPostAction',
|
||||
'AddPreAction',
|
||||
'Alias',
|
||||
'AlwaysBuild',
|
||||
'CacheDir',
|
||||
'Clean',
|
||||
#The Command() method is handled separately, below.
|
||||
'Decider',
|
||||
'Depends',
|
||||
'Dir',
|
||||
'NoClean',
|
||||
'NoCache',
|
||||
'Entry',
|
||||
'Execute',
|
||||
'File',
|
||||
'FindFile',
|
||||
'FindInstalledFiles',
|
||||
'FindSourceFiles',
|
||||
'Flatten',
|
||||
'GetBuildPath',
|
||||
'Glob',
|
||||
'Ignore',
|
||||
'Install',
|
||||
'InstallAs',
|
||||
'InstallVersionedLib',
|
||||
'Literal',
|
||||
'Local',
|
||||
'ParseDepends',
|
||||
'Precious',
|
||||
'Pseudo',
|
||||
'PyPackageDir',
|
||||
'Repository',
|
||||
'Requires',
|
||||
'SConsignFile',
|
||||
'SideEffect',
|
||||
'Split',
|
||||
'Tag',
|
||||
'Value',
|
||||
'VariantDir',
|
||||
]
|
||||
|
||||
GlobalDefaultBuilders = [
|
||||
# Supported builders.
|
||||
'CFile',
|
||||
'CXXFile',
|
||||
'DVI',
|
||||
'Jar',
|
||||
'Java',
|
||||
'JavaH',
|
||||
'Library',
|
||||
'LoadableModule',
|
||||
'M4',
|
||||
'MSVSProject',
|
||||
'Object',
|
||||
'PCH',
|
||||
'PDF',
|
||||
'PostScript',
|
||||
'Program',
|
||||
'RES',
|
||||
'RMIC',
|
||||
'SharedLibrary',
|
||||
'SharedObject',
|
||||
'StaticLibrary',
|
||||
'StaticObject',
|
||||
'Substfile',
|
||||
'Tar',
|
||||
'Textfile',
|
||||
'TypeLibrary',
|
||||
'Zip',
|
||||
'Package',
|
||||
]
|
||||
|
||||
# DefaultEnvironmentCall() initializes DefaultEnvironment() if it is not
|
||||
# created yet.
|
||||
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
|
||||
exec ("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name)))
|
||||
del name
|
||||
|
||||
# There are a handful of variables that used to live in the
|
||||
# Script/SConscript.py module that some SConscript files out there were
|
||||
# accessing directly as SCons.Script.SConscript.*. The problem is that
|
||||
# "SConscript" in this namespace is no longer a module, it's a global
|
||||
# function call--or more precisely, an object that implements a global
|
||||
# function call through the default Environment. Nevertheless, we can
|
||||
# maintain backwards compatibility for SConscripts that were reaching in
|
||||
# this way by hanging some attributes off the "SConscript" object here.
|
||||
SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
|
||||
|
||||
# Make SConscript look enough like the module it used to be so
|
||||
# that pychecker doesn't barf.
|
||||
SConscript.__name__ = 'SConscript'
|
||||
|
||||
SConscript.Arguments = ARGUMENTS
|
||||
SConscript.ArgList = ARGLIST
|
||||
SConscript.BuildTargets = BUILD_TARGETS
|
||||
SConscript.CommandLineTargets = COMMAND_LINE_TARGETS
|
||||
SConscript.DefaultTargets = DEFAULT_TARGETS
|
||||
|
||||
# The global Command() function must be handled differently than the
|
||||
# global functions for other construction environment methods because
|
||||
# we want people to be able to use Actions that must expand $TARGET
|
||||
# and $SOURCE later, when (and if) the Action is invoked to build
|
||||
# the target(s). We do this with the subst=1 argument, which creates
|
||||
# a DefaultEnvironmentCall instance that wraps up a normal default
|
||||
# construction environment that performs variable substitution, not a
|
||||
# proxy that doesn't.
|
||||
#
|
||||
# There's a flaw here, though, because any other $-variables on a command
|
||||
# line will *also* be expanded, each to a null string, but that should
|
||||
# only be a problem in the unusual case where someone was passing a '$'
|
||||
# on a command line and *expected* the $ to get through to the shell
|
||||
# because they were calling Command() and not env.Command()... This is
|
||||
# unlikely enough that we're going to leave this as is and cross that
|
||||
# bridge if someone actually comes to it.
|
||||
Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
1003
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Subst.py
Normal file
1003
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Subst.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,762 @@
|
||||
# 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.
|
||||
|
||||
"""Serial and Parallel classes to execute build tasks.
|
||||
|
||||
The Jobs class provides a higher level interface to start,
|
||||
stop, and wait on jobs.
|
||||
"""
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from enum import Enum
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Warnings
|
||||
|
||||
|
||||
# The default stack size (in kilobytes) of the threads used to execute
|
||||
# jobs in parallel.
|
||||
#
|
||||
# We use a stack size of 256 kilobytes. The default on some platforms
|
||||
# is too large and prevents us from creating enough threads to fully
|
||||
# parallelized the build. For example, the default stack size on linux
|
||||
# is 8 MBytes.
|
||||
|
||||
explicit_stack_size = None
|
||||
default_stack_size = 256
|
||||
|
||||
interrupt_msg = 'Build interrupted.'
|
||||
|
||||
class InterruptState:
|
||||
def __init__(self):
|
||||
self.interrupted = False
|
||||
|
||||
def set(self):
|
||||
self.interrupted = True
|
||||
|
||||
def __call__(self):
|
||||
return self.interrupted
|
||||
|
||||
|
||||
class Jobs:
|
||||
"""An instance of this class initializes N jobs, and provides
|
||||
methods for starting, stopping, and waiting on all N jobs.
|
||||
"""
|
||||
|
||||
def __init__(self, num, taskmaster):
|
||||
"""
|
||||
Create 'num' jobs using the given taskmaster. The exact implementation
|
||||
used varies with the number of jobs requested and the state of the `legacy_sched` flag
|
||||
to `--experimental`.
|
||||
"""
|
||||
|
||||
# Importing GetOption here instead of at top of file to avoid
|
||||
# circular imports
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from SCons.Script import GetOption
|
||||
|
||||
stack_size = explicit_stack_size
|
||||
if stack_size is None:
|
||||
stack_size = default_stack_size
|
||||
|
||||
experimental_option = GetOption('experimental') or []
|
||||
if 'legacy_sched' in experimental_option:
|
||||
if num > 1:
|
||||
self.job = LegacyParallel(taskmaster, num, stack_size)
|
||||
else:
|
||||
self.job = Serial(taskmaster)
|
||||
else:
|
||||
self.job = NewParallel(taskmaster, num, stack_size)
|
||||
|
||||
self.num_jobs = num
|
||||
|
||||
def run(self, postfunc=lambda: None):
|
||||
"""Run the jobs.
|
||||
|
||||
postfunc() will be invoked after the jobs has run. It will be
|
||||
invoked even if the jobs are interrupted by a keyboard
|
||||
interrupt (well, in fact by a signal such as either SIGINT,
|
||||
SIGTERM or SIGHUP). The execution of postfunc() is protected
|
||||
against keyboard interrupts and is guaranteed to run to
|
||||
completion."""
|
||||
self._setup_sig_handler()
|
||||
try:
|
||||
self.job.start()
|
||||
finally:
|
||||
postfunc()
|
||||
self._reset_sig_handler()
|
||||
|
||||
def were_interrupted(self):
|
||||
"""Returns whether the jobs were interrupted by a signal."""
|
||||
return self.job.interrupted()
|
||||
|
||||
def _setup_sig_handler(self):
|
||||
"""Setup an interrupt handler so that SCons can shutdown cleanly in
|
||||
various conditions:
|
||||
|
||||
a) SIGINT: Keyboard interrupt
|
||||
b) SIGTERM: kill or system shutdown
|
||||
c) SIGHUP: Controlling shell exiting
|
||||
|
||||
We handle all of these cases by stopping the taskmaster. It
|
||||
turns out that it's very difficult to stop the build process
|
||||
by throwing asynchronously an exception such as
|
||||
KeyboardInterrupt. For example, the python Condition
|
||||
variables (threading.Condition) and queues do not seem to be
|
||||
asynchronous-exception-safe. It would require adding a whole
|
||||
bunch of try/finally block and except KeyboardInterrupt all
|
||||
over the place.
|
||||
|
||||
Note also that we have to be careful to handle the case when
|
||||
SCons forks before executing another process. In that case, we
|
||||
want the child to exit immediately.
|
||||
"""
|
||||
def handler(signum, stack, self=self, parentpid=os.getpid()):
|
||||
if os.getpid() == parentpid:
|
||||
self.job.taskmaster.stop()
|
||||
self.job.interrupted.set()
|
||||
else:
|
||||
os._exit(2) # pylint: disable=protected-access
|
||||
|
||||
self.old_sigint = signal.signal(signal.SIGINT, handler)
|
||||
self.old_sigterm = signal.signal(signal.SIGTERM, handler)
|
||||
try:
|
||||
self.old_sighup = signal.signal(signal.SIGHUP, handler)
|
||||
except AttributeError:
|
||||
pass
|
||||
if (self.old_sigint is None) or (self.old_sigterm is None) or \
|
||||
(hasattr(self, "old_sighup") and self.old_sighup is None):
|
||||
msg = "Overwritting previous signal handler which was not installed from Python. " + \
|
||||
"Will not be able to reinstate and so will return to default handler."
|
||||
SCons.Warnings.warn(SCons.Warnings.SConsWarning, msg)
|
||||
|
||||
def _reset_sig_handler(self):
|
||||
"""Restore the signal handlers to their previous state (before the
|
||||
call to _setup_sig_handler()."""
|
||||
sigint_to_use = self.old_sigint if self.old_sigint is not None else signal.SIG_DFL
|
||||
sigterm_to_use = self.old_sigterm if self.old_sigterm is not None else signal.SIG_DFL
|
||||
signal.signal(signal.SIGINT, sigint_to_use)
|
||||
signal.signal(signal.SIGTERM, sigterm_to_use)
|
||||
try:
|
||||
sigterm_to_use = self.old_sighup if self.old_sighup is not None else signal.SIG_DFL
|
||||
signal.signal(signal.SIGHUP, sigterm_to_use)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
class Serial:
|
||||
"""This class is used to execute tasks in series, and is more efficient
|
||||
than Parallel, but is only appropriate for non-parallel builds. Only
|
||||
one instance of this class should be in existence at a time.
|
||||
|
||||
This class is not thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster):
|
||||
"""Create a new serial job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next task
|
||||
that needs to be executed, or None if there are no more tasks. The
|
||||
taskmaster's executed() method will be called for each task when it
|
||||
is successfully executed, or failed() will be called if it failed to
|
||||
execute (e.g. execute() raised an exception)."""
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the taskmaster
|
||||
and executing them, and return when there are no more tasks. If a task
|
||||
fails to execute (i.e. execute() raises an exception), then the job will
|
||||
stop."""
|
||||
|
||||
while True:
|
||||
task = self.taskmaster.next_task()
|
||||
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
task.prepare()
|
||||
if task.needs_execute():
|
||||
task.execute()
|
||||
except Exception:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except Exception:
|
||||
task.exception_set()
|
||||
else:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange for the
|
||||
# build to stop if that's appropriate.
|
||||
task.failed()
|
||||
else:
|
||||
task.executed()
|
||||
|
||||
task.postprocess()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
|
||||
class Worker(threading.Thread):
|
||||
"""A worker thread waits on a task to be posted to its request queue,
|
||||
dequeues the task, executes it, and posts a tuple including the task
|
||||
and a boolean indicating whether the task executed successfully. """
|
||||
|
||||
def __init__(self, requestQueue, resultsQueue, interrupted):
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
self.requestQueue = requestQueue
|
||||
self.resultsQueue = resultsQueue
|
||||
self.interrupted = interrupted
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
task = self.requestQueue.get()
|
||||
|
||||
if task is None:
|
||||
# The "None" value is used as a sentinel by
|
||||
# ThreadPool.cleanup(). This indicates that there
|
||||
# are no more tasks, so we should quit.
|
||||
break
|
||||
|
||||
try:
|
||||
if self.interrupted():
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
task.execute()
|
||||
except Exception:
|
||||
task.exception_set()
|
||||
ok = False
|
||||
else:
|
||||
ok = True
|
||||
|
||||
self.resultsQueue.put((task, ok))
|
||||
|
||||
class ThreadPool:
|
||||
"""This class is responsible for spawning and managing worker threads."""
|
||||
|
||||
def __init__(self, num, stack_size, interrupted):
|
||||
"""Create the request and reply queues, and 'num' worker threads.
|
||||
|
||||
One must specify the stack size of the worker threads. The
|
||||
stack size is specified in kilobytes.
|
||||
"""
|
||||
self.requestQueue = queue.Queue(0)
|
||||
self.resultsQueue = queue.Queue(0)
|
||||
|
||||
try:
|
||||
prev_size = threading.stack_size(stack_size * 1024)
|
||||
except RuntimeError as e:
|
||||
# Only print a warning if the stack size has been explicitly set.
|
||||
if explicit_stack_size is not None:
|
||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||
e.args[0]
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
except ValueError as e:
|
||||
msg = "Setting stack size failed:\n " + str(e)
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
|
||||
# Create worker threads
|
||||
self.workers = []
|
||||
for _ in range(num):
|
||||
worker = Worker(self.requestQueue, self.resultsQueue, interrupted)
|
||||
self.workers.append(worker)
|
||||
|
||||
if 'prev_size' in locals():
|
||||
threading.stack_size(prev_size)
|
||||
|
||||
def put(self, task):
|
||||
"""Put task into request queue."""
|
||||
self.requestQueue.put(task)
|
||||
|
||||
def get(self):
|
||||
"""Remove and return a result tuple from the results queue."""
|
||||
return self.resultsQueue.get()
|
||||
|
||||
def preparation_failed(self, task):
|
||||
self.resultsQueue.put((task, False))
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Shuts down the thread pool, giving each worker thread a
|
||||
chance to shut down gracefully.
|
||||
"""
|
||||
# For each worker thread, put a sentinel "None" value
|
||||
# on the requestQueue (indicating that there's no work
|
||||
# to be done) so that each worker thread will get one and
|
||||
# terminate gracefully.
|
||||
for _ in self.workers:
|
||||
self.requestQueue.put(None)
|
||||
|
||||
# Wait for all of the workers to terminate.
|
||||
#
|
||||
# If we don't do this, later Python versions (2.4, 2.5) often
|
||||
# seem to raise exceptions during shutdown. This happens
|
||||
# in requestQueue.get(), as an assertion failure that
|
||||
# requestQueue.not_full is notified while not acquired,
|
||||
# seemingly because the main thread has shut down (or is
|
||||
# in the process of doing so) while the workers are still
|
||||
# trying to pull sentinels off the requestQueue.
|
||||
#
|
||||
# Normally these terminations should happen fairly quickly,
|
||||
# but we'll stick a one-second timeout on here just in case
|
||||
# someone gets hung.
|
||||
for worker in self.workers:
|
||||
worker.join(1.0)
|
||||
self.workers = []
|
||||
|
||||
class LegacyParallel:
|
||||
"""This class is used to execute tasks in parallel, and is somewhat
|
||||
less efficient than Serial, but is appropriate for parallel builds.
|
||||
|
||||
This class is thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster, num, stack_size):
|
||||
"""Create a new parallel job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next
|
||||
task that needs to be executed, or None if there are no more
|
||||
tasks. The taskmaster's executed() method will be called
|
||||
for each task when it is successfully executed, or failed()
|
||||
will be called if the task failed to execute (i.e. execute()
|
||||
raised an exception).
|
||||
|
||||
Note: calls to taskmaster are serialized, but calls to
|
||||
execute() on distinct tasks are not serialized, because
|
||||
that is the whole point of parallel jobs: they can execute
|
||||
multiple tasks simultaneously. """
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
self.tp = ThreadPool(num, stack_size, self.interrupted)
|
||||
|
||||
self.maxjobs = num
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the
|
||||
taskmaster and executing them, and return when there are no
|
||||
more tasks. If a task fails to execute (i.e. execute() raises
|
||||
an exception), then the job will stop."""
|
||||
|
||||
jobs = 0
|
||||
|
||||
while True:
|
||||
# Start up as many available tasks as we're
|
||||
# allowed to.
|
||||
while jobs < self.maxjobs:
|
||||
task = self.taskmaster.next_task()
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
# prepare task for execution
|
||||
task.prepare()
|
||||
except Exception:
|
||||
task.exception_set()
|
||||
task.failed()
|
||||
task.postprocess()
|
||||
else:
|
||||
if task.needs_execute():
|
||||
# dispatch task
|
||||
self.tp.put(task)
|
||||
jobs += 1
|
||||
else:
|
||||
task.executed()
|
||||
task.postprocess()
|
||||
|
||||
if not task and not jobs:
|
||||
break
|
||||
|
||||
# Let any/all completed tasks finish up before we go
|
||||
# back and put the next batch of tasks on the queue.
|
||||
while True:
|
||||
task, ok = self.tp.get()
|
||||
jobs -= 1
|
||||
|
||||
if ok:
|
||||
task.executed()
|
||||
else:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except Exception:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange
|
||||
# for the build to stop if that's appropriate.
|
||||
task.failed()
|
||||
|
||||
task.postprocess()
|
||||
|
||||
if self.tp.resultsQueue.empty():
|
||||
break
|
||||
|
||||
self.tp.cleanup()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
# An experimental new parallel scheduler that uses a leaders/followers pattern.
|
||||
class NewParallel:
|
||||
|
||||
class State(Enum):
|
||||
READY = 0
|
||||
SEARCHING = 1
|
||||
STALLED = 2
|
||||
COMPLETED = 3
|
||||
|
||||
class Worker(threading.Thread):
|
||||
def __init__(self, owner):
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
self.owner = owner
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
self.owner._work()
|
||||
|
||||
class FakeLock(object):
|
||||
def lock(self):
|
||||
pass
|
||||
def unlock(self):
|
||||
pass
|
||||
def __enter__(self):
|
||||
pass
|
||||
def __exit__(self, *args):
|
||||
pass
|
||||
|
||||
class FakeCondition(object):
|
||||
def __init__(self, lock):
|
||||
pass
|
||||
def wait(self):
|
||||
fatal();
|
||||
def notify(self):
|
||||
pass
|
||||
def notify_all(self):
|
||||
pass
|
||||
def __enter__(self):
|
||||
pass
|
||||
def __exit__(self, *args):
|
||||
pass
|
||||
|
||||
def __init__(self, taskmaster, num, stack_size):
|
||||
self.taskmaster = taskmaster
|
||||
self.max_workers = num
|
||||
self.stack_size = stack_size
|
||||
self.interrupted = InterruptState()
|
||||
self.workers = []
|
||||
|
||||
# The `tm_lock` is what ensures that we only have one
|
||||
# thread interacting with the taskmaster at a time. It
|
||||
# also protects access to our state that gets updated
|
||||
# concurrently. The `can_search_cv` is associated with
|
||||
# this mutex.
|
||||
self.tm_lock = (threading.Lock if self.max_workers > 1 else NewParallel.FakeLock)()
|
||||
|
||||
# Guarded under `tm_lock`.
|
||||
self.jobs = 0
|
||||
self.state = NewParallel.State.READY
|
||||
|
||||
# The `can_search_cv` is used to manage a leader /
|
||||
# follower pattern for access to the taskmaster, and to
|
||||
# awaken from stalls.
|
||||
self.can_search_cv = (threading.Condition if self.max_workers > 1 else NewParallel.FakeCondition)(self.tm_lock)
|
||||
|
||||
# The queue of tasks that have completed execution. The
|
||||
# next thread to obtain `tm_lock`` will retire them.
|
||||
self.results_queue_lock = (threading.Lock if self.max_workers > 1 else NewParallel.FakeLock)()
|
||||
self.results_queue = []
|
||||
|
||||
if self.taskmaster.trace:
|
||||
self.trace = self._setup_logging()
|
||||
else:
|
||||
self.trace = False
|
||||
|
||||
def _setup_logging(self):
|
||||
jl = logging.getLogger("Job")
|
||||
jl.setLevel(level=logging.DEBUG)
|
||||
jl.addHandler(self.taskmaster.trace.log_handler)
|
||||
return jl
|
||||
|
||||
def trace_message(self, message):
|
||||
# This grabs the name of the function which calls trace_message()
|
||||
method_name = sys._getframe(1).f_code.co_name + "():"
|
||||
thread_id=threading.get_ident()
|
||||
self.trace.debug('%s.%s [Thread:%s] %s' % (type(self).__name__, method_name, thread_id, message))
|
||||
|
||||
def start(self):
|
||||
if self.max_workers == 1:
|
||||
self._work()
|
||||
else:
|
||||
self._start_worker()
|
||||
while len(self.workers) > 0:
|
||||
self.workers[0].join()
|
||||
self.workers.pop(0)
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
def _maybe_start_worker(self):
|
||||
if self.max_workers > 1 and len(self.workers) < self.max_workers:
|
||||
if self.jobs >= len(self.workers):
|
||||
self._start_worker()
|
||||
|
||||
def _start_worker(self):
|
||||
prev_size = self._adjust_stack_size()
|
||||
if self.trace:
|
||||
self.trace_message("Starting new worker thread")
|
||||
self.workers.append(NewParallel.Worker(self))
|
||||
self._restore_stack_size(prev_size)
|
||||
|
||||
def _adjust_stack_size(self):
|
||||
try:
|
||||
prev_size = threading.stack_size(self.stack_size * 1024)
|
||||
return prev_size
|
||||
except AttributeError as e:
|
||||
# Only print a warning if the stack size has been
|
||||
# explicitly set.
|
||||
if explicit_stack_size is not None:
|
||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||
e.args[0]
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
except ValueError as e:
|
||||
msg = "Setting stack size failed:\n " + str(e)
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
|
||||
return None
|
||||
|
||||
def _restore_stack_size(self, prev_size):
|
||||
if prev_size is not None:
|
||||
threading.stack_size(prev_size)
|
||||
|
||||
def _work(self):
|
||||
|
||||
task = None
|
||||
|
||||
while True:
|
||||
|
||||
# Obtain `tm_lock`, granting exclusive access to the taskmaster.
|
||||
with self.can_search_cv:
|
||||
|
||||
if self.trace:
|
||||
self.trace_message("Gained exclusive access")
|
||||
|
||||
# Capture whether we got here with `task` set,
|
||||
# then drop our reference to the task as we are no
|
||||
# longer interested in the actual object.
|
||||
completed_task = (task is not None)
|
||||
task = None
|
||||
|
||||
# We will only have `completed_task` set here if
|
||||
# we have looped back after executing a task. If
|
||||
# we have completed a task and find that we are
|
||||
# stalled, we should speculatively indicate that
|
||||
# we are no longer stalled by transitioning to the
|
||||
# 'ready' state which will bypass the condition
|
||||
# wait so that we immediately process the results
|
||||
# queue and hopefully light up new
|
||||
# work. Otherwise, stay stalled, and we will wait
|
||||
# in the condvar. Some other thread will come back
|
||||
# here with a completed task.
|
||||
if self.state == NewParallel.State.STALLED and completed_task:
|
||||
if self.trace:
|
||||
self.trace_message("Detected stall with completed task, bypassing wait")
|
||||
self.state = NewParallel.State.READY
|
||||
|
||||
# Wait until we are neither searching nor stalled.
|
||||
while self.state == NewParallel.State.SEARCHING or self.state == NewParallel.State.STALLED:
|
||||
if self.trace:
|
||||
self.trace_message("Search already in progress, waiting")
|
||||
self.can_search_cv.wait()
|
||||
|
||||
# If someone set the completed flag, bail.
|
||||
if self.state == NewParallel.State.COMPLETED:
|
||||
if self.trace:
|
||||
self.trace_message("Completion detected, breaking from main loop")
|
||||
break
|
||||
|
||||
# Set the searching flag to indicate that a thread
|
||||
# is currently in the critical section for
|
||||
# taskmaster work.
|
||||
#
|
||||
if self.trace:
|
||||
self.trace_message("Starting search")
|
||||
self.state = NewParallel.State.SEARCHING
|
||||
|
||||
# Bulk acquire the tasks in the results queue
|
||||
# under the result queue lock, then process them
|
||||
# all outside that lock. We need to process the
|
||||
# tasks in the results queue before looking for
|
||||
# new work because we might be unable to find new
|
||||
# work if we don't.
|
||||
results_queue = []
|
||||
with self.results_queue_lock:
|
||||
results_queue, self.results_queue = self.results_queue, results_queue
|
||||
|
||||
if self.trace:
|
||||
self.trace_message(f"Found {len(results_queue)} completed tasks to process")
|
||||
for (rtask, rresult) in results_queue:
|
||||
if rresult:
|
||||
rtask.executed()
|
||||
else:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
rtask.targets[0], errstr=interrupt_msg)
|
||||
except Exception:
|
||||
rtask.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange
|
||||
# for the build to stop if that's appropriate.
|
||||
rtask.failed()
|
||||
|
||||
rtask.postprocess()
|
||||
self.jobs -= 1
|
||||
|
||||
# We are done with any task objects that were in
|
||||
# the results queue.
|
||||
results_queue.clear()
|
||||
|
||||
# Now, turn the crank on the taskmaster until we
|
||||
# either run out of tasks, or find a task that
|
||||
# needs execution. If we run out of tasks, go idle
|
||||
# until results arrive if jobs are pending, or
|
||||
# mark the walk as complete if not.
|
||||
while self.state == NewParallel.State.SEARCHING:
|
||||
if self.trace:
|
||||
self.trace_message("Searching for new tasks")
|
||||
task = self.taskmaster.next_task()
|
||||
|
||||
if task:
|
||||
# We found a task. Walk it through the
|
||||
# task lifecycle. If it does not need
|
||||
# execution, just complete the task and
|
||||
# look for the next one. Otherwise,
|
||||
# indicate that we are no longer searching
|
||||
# so we can drop out of this loop, execute
|
||||
# the task outside the lock, and allow
|
||||
# another thread in to search.
|
||||
try:
|
||||
task.prepare()
|
||||
except Exception:
|
||||
task.exception_set()
|
||||
task.failed()
|
||||
task.postprocess()
|
||||
else:
|
||||
if not task.needs_execute():
|
||||
if self.trace:
|
||||
self.trace_message("Found internal task")
|
||||
task.executed()
|
||||
task.postprocess()
|
||||
else:
|
||||
self.jobs += 1
|
||||
if self.trace:
|
||||
self.trace_message("Found task requiring execution")
|
||||
self.state = NewParallel.State.READY
|
||||
self.can_search_cv.notify()
|
||||
# This thread will be busy taking care of
|
||||
# `execute`ing this task. If we haven't
|
||||
# reached the limit, spawn a new thread to
|
||||
# turn the crank and find the next task.
|
||||
self._maybe_start_worker()
|
||||
|
||||
else:
|
||||
# We failed to find a task, so this thread
|
||||
# cannot continue turning the taskmaster
|
||||
# crank. We must exit the loop.
|
||||
if self.jobs:
|
||||
# No task was found, but there are
|
||||
# outstanding jobs executing that
|
||||
# might unblock new tasks when they
|
||||
# complete. Transition to the stalled
|
||||
# state. We do not need a notify,
|
||||
# because we know there are threads
|
||||
# outstanding that will re-enter the
|
||||
# loop.
|
||||
#
|
||||
if self.trace:
|
||||
self.trace_message("Found no task requiring execution, but have jobs: marking stalled")
|
||||
self.state = NewParallel.State.STALLED
|
||||
else:
|
||||
# We didn't find a task and there are
|
||||
# no jobs outstanding, so there is
|
||||
# nothing that will ever return
|
||||
# results which might unblock new
|
||||
# tasks. We can conclude that the walk
|
||||
# is complete. Update our state to
|
||||
# note completion and awaken anyone
|
||||
# sleeping on the condvar.
|
||||
#
|
||||
if self.trace:
|
||||
self.trace_message("Found no task requiring execution, and have no jobs: marking complete")
|
||||
self.state = NewParallel.State.COMPLETED
|
||||
self.can_search_cv.notify_all()
|
||||
|
||||
# We no longer hold `tm_lock` here. If we have a task,
|
||||
# we can now execute it. If there are threads waiting
|
||||
# to search, one of them can now begin turning the
|
||||
# taskmaster crank in NewParallel.
|
||||
if task:
|
||||
if self.trace:
|
||||
self.trace_message("Executing task")
|
||||
ok = True
|
||||
try:
|
||||
if self.interrupted():
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
task.execute()
|
||||
except Exception:
|
||||
ok = False
|
||||
task.exception_set()
|
||||
|
||||
# Grab the results queue lock and enqueue the
|
||||
# executed task and state. The next thread into
|
||||
# the searching loop will complete the
|
||||
# postprocessing work under the taskmaster lock.
|
||||
#
|
||||
if self.trace:
|
||||
self.trace_message("Enqueueing executed task results")
|
||||
with self.results_queue_lock:
|
||||
self.results_queue.append((task, ok))
|
||||
|
||||
# Tricky state "fallthrough" here. We are going back
|
||||
# to the top of the loop, which behaves differently
|
||||
# depending on whether `task` is set. Do not perturb
|
||||
# the value of the `task` variable if you add new code
|
||||
# after this comment.
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
"""SCons.Tool.386asm
|
||||
|
||||
Tool specification for the 386ASM assembler for the Phar Lap ETS embedded
|
||||
operating system.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from SCons.Tool.PharLapCommon import addPharLapPaths
|
||||
import SCons.Util
|
||||
|
||||
as_module = __import__('as', globals(), locals(), [], 1)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for ar to an Environment."""
|
||||
as_module.generate(env)
|
||||
|
||||
env['AS'] = '386asm'
|
||||
env['ASFLAGS'] = SCons.Util.CLVar('')
|
||||
env['ASPPFLAGS'] = '$ASFLAGS'
|
||||
env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET'
|
||||
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET'
|
||||
|
||||
addPharLapPaths(env)
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('386asm')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,429 @@
|
||||
# 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.
|
||||
|
||||
"""Common routines for gettext tools
|
||||
|
||||
Used by several tools of `gettext` toolset.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
class XgettextToolWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
|
||||
|
||||
class XgettextNotFound(XgettextToolWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsginitToolWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsginitNotFound(MsginitToolWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsgmergeToolWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsgmergeNotFound(MsgmergeToolWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsgfmtToolWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MsgfmtNotFound(MsgfmtToolWarning):
|
||||
pass
|
||||
|
||||
|
||||
SCons.Warnings.enableWarningClass(XgettextToolWarning)
|
||||
SCons.Warnings.enableWarningClass(XgettextNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsginitToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsginitNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsgmergeNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsgfmtNotFound)
|
||||
|
||||
|
||||
class _POTargetFactory:
|
||||
""" A factory of `PO` target files.
|
||||
|
||||
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
|
||||
(this is required by builders and actions gettext) and `noclean` flags by
|
||||
default for all produced nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, env, nodefault=True, alias=None, precious=True
|
||||
, noclean=True):
|
||||
""" Object constructor.
|
||||
|
||||
**Arguments**
|
||||
|
||||
- *env* (`SCons.Environment.Environment`)
|
||||
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
|
||||
from default target `'.'`
|
||||
- *alias* (`string`) - if provided, produced nodes will be automatically
|
||||
added to this alias, and alias will be set as `AlwaysBuild`
|
||||
- *precious* (`boolean`) - if `True`, the produced nodes will be set as
|
||||
`Precious`.
|
||||
- *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
|
||||
from `Clean`.
|
||||
"""
|
||||
self.env = env
|
||||
self.alias = alias
|
||||
self.precious = precious
|
||||
self.noclean = noclean
|
||||
self.nodefault = nodefault
|
||||
|
||||
def _create_node(self, name, factory, directory=None, create=1):
|
||||
""" Create node, and set it up to factory settings. """
|
||||
node = factory(name, directory, create)
|
||||
node.set_noclean(self.noclean)
|
||||
node.set_precious(self.precious)
|
||||
if self.nodefault:
|
||||
self.env.Ignore('.', node)
|
||||
if self.alias:
|
||||
self.env.AlwaysBuild(self.env.Alias(self.alias, node))
|
||||
return node
|
||||
|
||||
def Entry(self, name, directory=None, create=1):
|
||||
""" Create `SCons.Node.FS.Entry` """
|
||||
return self._create_node(name, self.env.fs.Entry, directory, create)
|
||||
|
||||
def File(self, name, directory=None, create=1):
|
||||
""" Create `SCons.Node.FS.File` """
|
||||
return self._create_node(name, self.env.fs.File, directory, create)
|
||||
|
||||
|
||||
_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
|
||||
_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
|
||||
|
||||
|
||||
def _read_linguas_from_files(env, linguas_files=None):
|
||||
""" Parse `LINGUAS` file and return list of extracted languages """
|
||||
global _re_comment
|
||||
global _re_lang
|
||||
if not SCons.Util.is_List(linguas_files) \
|
||||
and not SCons.Util.is_String(linguas_files) \
|
||||
and not isinstance(linguas_files, SCons.Node.FS.Base) \
|
||||
and linguas_files:
|
||||
# If, linguas_files==True or such, then read 'LINGUAS' file.
|
||||
linguas_files = ['LINGUAS']
|
||||
if linguas_files is None:
|
||||
return []
|
||||
fnodes = env.arg2nodes(linguas_files)
|
||||
linguas = []
|
||||
for fnode in fnodes:
|
||||
contents = _re_comment.sub("", fnode.get_text_contents())
|
||||
ls = [l for l in _re_lang.findall(contents) if l]
|
||||
linguas.extend(ls)
|
||||
return linguas
|
||||
|
||||
|
||||
from SCons.Builder import BuilderBase
|
||||
|
||||
|
||||
class _POFileBuilder(BuilderBase):
|
||||
""" `PO` file builder.
|
||||
|
||||
This is multi-target single-source builder. In typical situation the source
|
||||
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
|
||||
targets to be updated from this `POT`. We must run
|
||||
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
|
||||
dependencies separatelly for each target file.
|
||||
|
||||
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
|
||||
with target being list of all targets, all targets would be rebuilt each time
|
||||
one of the targets from this list is missing. This would happen, for example,
|
||||
when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
|
||||
`ll.po` file yet). To avoid this, we override
|
||||
`SCons.Builder.BuilerBase._execute()` and call it separatelly for each
|
||||
target. Here we also append to the target list the languages read from
|
||||
`LINGUAS_FILE`.
|
||||
"""
|
||||
|
||||
#
|
||||
# * The argument for overriding _execute(): We must use environment with
|
||||
# builder overrides applied (see BuilderBase.__init__(). Here it comes for
|
||||
# free.
|
||||
# * The argument against using 'emitter': The emitter is called too late
|
||||
# by BuilderBase._execute(). If user calls, for example:
|
||||
#
|
||||
# env.POUpdate(LINGUAS_FILE = 'LINGUAS')
|
||||
#
|
||||
# the builder throws error, because it is called with target=None,
|
||||
# source=None and is trying to "generate" sources or target list first.
|
||||
# If user calls
|
||||
#
|
||||
# env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
|
||||
#
|
||||
# the env.BuilderWrapper() calls our builder with target=None,
|
||||
# source=['foo', 'baz']. The BuilderBase._execute() then splits execution
|
||||
# and execute iterativelly (recursion) self._execute(None, source[i]).
|
||||
# After that it calls emitter (which is quite too late). The emitter is
|
||||
# also called in each iteration, what makes things yet worse.
|
||||
def __init__(self, env, **kw):
|
||||
if 'suffix' not in kw:
|
||||
kw['suffix'] = '$POSUFFIX'
|
||||
if 'src_suffix' not in kw:
|
||||
kw['src_suffix'] = '$POTSUFFIX'
|
||||
if 'src_builder' not in kw:
|
||||
kw['src_builder'] = '_POTUpdateBuilder'
|
||||
if 'single_source' not in kw:
|
||||
kw['single_source'] = True
|
||||
alias = None
|
||||
if 'target_alias' in kw:
|
||||
alias = kw['target_alias']
|
||||
del kw['target_alias']
|
||||
if 'target_factory' not in kw:
|
||||
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
|
||||
super().__init__(**kw)
|
||||
|
||||
def _execute(self, env, target, source, *args, **kw):
|
||||
""" Execute builder's actions.
|
||||
|
||||
Here we append to `target` the languages read from `$LINGUAS_FILE` and
|
||||
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
|
||||
The arguments and return value are same as for
|
||||
`SCons.Builder.BuilderBase._execute()`.
|
||||
"""
|
||||
import SCons.Node
|
||||
linguas_files = None
|
||||
if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']:
|
||||
linguas_files = env['LINGUAS_FILE']
|
||||
# This prevents endless recursion loop (we'll be invoked once for
|
||||
# each target appended here, we must not extend the list again).
|
||||
env['LINGUAS_FILE'] = None
|
||||
linguas = _read_linguas_from_files(env, linguas_files)
|
||||
if SCons.Util.is_List(target):
|
||||
target.extend(linguas)
|
||||
elif target is not None:
|
||||
target = [target] + linguas
|
||||
else:
|
||||
target = linguas
|
||||
if not target:
|
||||
# Let the SCons.BuilderBase to handle this patologic situation
|
||||
return BuilderBase._execute(self, env, target, source, *args, **kw)
|
||||
# The rest is ours
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
result = []
|
||||
for tgt in target:
|
||||
r = BuilderBase._execute(self, env, [tgt], source, *args, **kw)
|
||||
result.extend(r)
|
||||
if linguas_files is not None:
|
||||
env['LINGUAS_FILE'] = linguas_files
|
||||
return SCons.Node.NodeList(result)
|
||||
|
||||
|
||||
def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
|
||||
""" Function for `Translate()` pseudo-builder """
|
||||
if target is None: target = []
|
||||
pot = env.POTUpdate(None, source, *args, **kw)
|
||||
po = env.POUpdate(target, pot, *args, **kw)
|
||||
return po
|
||||
|
||||
|
||||
class RPaths:
|
||||
""" Callable object, which returns pathnames relative to SCons current
|
||||
working directory.
|
||||
|
||||
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
|
||||
for nodes that are outside of current working directory (`env.fs.getcwd()`).
|
||||
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
|
||||
directory and source files (e.g. `*.c`) outside of it. When generating `POT`
|
||||
template file, references to source files are written to `POT` template, so
|
||||
a translator may later quickly jump to appropriate source file and line from
|
||||
its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
|
||||
interpreted by `PO` editor as paths relative to the place, where `PO` file
|
||||
lives. The absolute paths would make resultant `POT` file nonportable, as
|
||||
the references would be correct only on the machine, where `POT` file was
|
||||
recently re-created. For such reason, we need a function, which always
|
||||
returns relative paths. This is the purpose of `RPaths` callable object.
|
||||
|
||||
The `__call__` method returns paths relative to current working directory, but
|
||||
we assume, that *xgettext(1)* is run from the directory, where target file is
|
||||
going to be created.
|
||||
|
||||
Note, that this may not work for files distributed over several hosts or
|
||||
across different drives on windows. We assume here, that single local
|
||||
filesystem holds both source files and target `POT` templates.
|
||||
|
||||
Intended use of `RPaths` - in `xgettext.py`::
|
||||
|
||||
def generate(env):
|
||||
from GettextCommon import RPaths
|
||||
...
|
||||
sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
|
||||
env.Append(
|
||||
...
|
||||
XGETTEXTCOM = 'XGETTEXT ... ' + sources,
|
||||
...
|
||||
XgettextRPaths = RPaths(env)
|
||||
)
|
||||
"""
|
||||
|
||||
# NOTE: This callable object returns pathnames of dirs/files relative to
|
||||
# current working directory. The pathname remains relative also for entries
|
||||
# that are outside of current working directory (node, that
|
||||
# SCons.Node.FS.File and siblings return absolute path in such case). For
|
||||
# simplicity we compute path relative to current working directory, this
|
||||
# seems be enough for our purposes (don't need TARGET variable and
|
||||
# SCons.Defaults.Variable_Caller stuff).
|
||||
|
||||
def __init__(self, env):
|
||||
""" Initialize `RPaths` callable object.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- *env* - a `SCons.Environment.Environment` object, defines *current
|
||||
working dir*.
|
||||
"""
|
||||
self.env = env
|
||||
|
||||
# FIXME: I'm not sure, how it should be implemented (what the *args are in
|
||||
# general, what is **kw).
|
||||
def __call__(self, nodes, *args, **kw):
|
||||
""" Return nodes' paths (strings) relative to current working directory.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
|
||||
- *args* - currently unused.
|
||||
- *kw* - currently unused.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- Tuple of strings, which represent paths relative to current working
|
||||
directory (for given environment).
|
||||
"""
|
||||
import SCons.Node.FS
|
||||
rpaths = ()
|
||||
cwd = self.env.fs.getcwd().get_abspath()
|
||||
for node in nodes:
|
||||
rpath = None
|
||||
if isinstance(node, SCons.Node.FS.Base):
|
||||
rpath = os.path.relpath(node.get_abspath(), cwd)
|
||||
# FIXME: Other types possible here?
|
||||
if rpath is not None:
|
||||
rpaths += (rpath,)
|
||||
return rpaths
|
||||
|
||||
|
||||
def _init_po_files(target, source, env):
|
||||
""" Action function for `POInit` builder. """
|
||||
nop = lambda target, source, env: 0
|
||||
if 'POAUTOINIT' in env:
|
||||
autoinit = env['POAUTOINIT']
|
||||
else:
|
||||
autoinit = False
|
||||
# Well, if everything outside works well, this loop should do single
|
||||
# iteration. Otherwise we are rebuilding all the targets even, if just
|
||||
# one has changed (but is this our fault?).
|
||||
for tgt in target:
|
||||
if not tgt.exists():
|
||||
if autoinit:
|
||||
action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
|
||||
else:
|
||||
msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
|
||||
+ 'If you are a translator, you can create it through: \n' \
|
||||
+ '$MSGINITCOM'
|
||||
action = SCons.Action.Action(nop, msg)
|
||||
status = action([tgt], source, env)
|
||||
if status: return status
|
||||
return 0
|
||||
|
||||
|
||||
def _detect_xgettext(env):
|
||||
""" Detects *xgettext(1)* binary """
|
||||
if 'XGETTEXT' in env:
|
||||
return env['XGETTEXT']
|
||||
xgettext = env.Detect('xgettext')
|
||||
if xgettext:
|
||||
return xgettext
|
||||
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
|
||||
return None
|
||||
|
||||
|
||||
def _xgettext_exists(env):
|
||||
return _detect_xgettext(env)
|
||||
|
||||
|
||||
def _detect_msginit(env):
|
||||
""" Detects *msginit(1)* program. """
|
||||
if 'MSGINIT' in env:
|
||||
return env['MSGINIT']
|
||||
msginit = env.Detect('msginit')
|
||||
if msginit:
|
||||
return msginit
|
||||
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
|
||||
return None
|
||||
|
||||
|
||||
def _msginit_exists(env):
|
||||
return _detect_msginit(env)
|
||||
|
||||
|
||||
def _detect_msgmerge(env):
|
||||
""" Detects *msgmerge(1)* program. """
|
||||
if 'MSGMERGE' in env:
|
||||
return env['MSGMERGE']
|
||||
msgmerge = env.Detect('msgmerge')
|
||||
if msgmerge:
|
||||
return msgmerge
|
||||
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
|
||||
return None
|
||||
|
||||
|
||||
def _msgmerge_exists(env):
|
||||
return _detect_msgmerge(env)
|
||||
|
||||
|
||||
def _detect_msgfmt(env):
|
||||
""" Detects *msgmfmt(1)* program. """
|
||||
if 'MSGFMT' in env:
|
||||
return env['MSGFMT']
|
||||
msgfmt = env.Detect('msgfmt')
|
||||
if msgfmt:
|
||||
return msgfmt
|
||||
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
|
||||
return None
|
||||
|
||||
|
||||
def _msgfmt_exists(env):
|
||||
return _detect_msgfmt(env)
|
||||
|
||||
|
||||
def tool_list(platform, env):
|
||||
""" List tools that shall be generated by top-level `gettext` tool """
|
||||
return ['xgettext', 'msginit', 'msgmerge', 'msgfmt']
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
# 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 .Exceptions import (
|
||||
MSVCInternalError,
|
||||
)
|
||||
|
||||
from . import Dispatcher
|
||||
Dispatcher.register_modulename(__name__)
|
||||
|
||||
|
||||
UNDEFINED = object()
|
||||
|
||||
BOOLEAN_SYMBOLS = {}
|
||||
BOOLEAN_EXTERNAL = {}
|
||||
|
||||
for bool_val, 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_val] = list(symbol_list)
|
||||
for symbol in symbol_case_list:
|
||||
BOOLEAN_SYMBOLS[bool_val].extend([symbol, symbol.lower(), symbol.upper()])
|
||||
|
||||
for symbol in BOOLEAN_SYMBOLS[bool_val]:
|
||||
BOOLEAN_EXTERNAL[symbol] = bool_val
|
||||
|
||||
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',
|
||||
'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_BUILDSERIES_DEFINITION = namedtuple('MSVCBuildSeries', [
|
||||
'vc_buildseries',
|
||||
'vc_buildseries_numeric',
|
||||
'vc_version',
|
||||
'vc_version_numeric',
|
||||
'cl_version',
|
||||
'cl_version_numeric',
|
||||
])
|
||||
|
||||
MSVC_BUILDSERIES_DEFINITION_LIST = []
|
||||
|
||||
MSVC_BUILDSERIES_INTERNAL = {}
|
||||
MSVC_BUILDSERIES_EXTERNAL = {}
|
||||
|
||||
VC_BUILDTOOLS_MAP = {}
|
||||
|
||||
VC_VERSION_MAP = {}
|
||||
CL_VERSION_MAP = {}
|
||||
|
||||
for (vc_buildseries, vc_version, cl_version) in [
|
||||
('145', '14.5', '19.5'),
|
||||
('144', '14.4', '19.4'),
|
||||
('143', '14.3', '19.3'),
|
||||
('142', '14.2', '19.2'),
|
||||
('141', '14.1', '19.1'),
|
||||
('140', '14.0', '19.0'),
|
||||
('120', '12.0', '18.0'),
|
||||
('110', '11.0', '17.0'),
|
||||
('100', '10.0', '16.0'),
|
||||
('90', '9.0', '15.0'),
|
||||
('80', '8.0', '14.0'),
|
||||
('71', '7.1', '13.1'),
|
||||
('70', '7.0', '13.0'),
|
||||
('60', '6.0', '12.0'),
|
||||
]:
|
||||
|
||||
vc_buildseries_def = MSVC_BUILDSERIES_DEFINITION(
|
||||
vc_buildseries=vc_buildseries,
|
||||
vc_buildseries_numeric=int(vc_buildseries),
|
||||
vc_version=vc_version,
|
||||
vc_version_numeric=float(vc_version),
|
||||
cl_version=cl_version,
|
||||
cl_version_numeric=float(cl_version),
|
||||
)
|
||||
|
||||
MSVC_BUILDSERIES_DEFINITION_LIST.append(vc_buildseries_def)
|
||||
|
||||
MSVC_BUILDSERIES_INTERNAL[vc_buildseries] = vc_buildseries_def
|
||||
MSVC_BUILDSERIES_EXTERNAL[vc_buildseries] = vc_buildseries_def
|
||||
MSVC_BUILDSERIES_EXTERNAL[vc_version] = vc_buildseries_def
|
||||
|
||||
VC_VERSION_MAP[vc_version] = vc_buildseries_def
|
||||
CL_VERSION_MAP[cl_version] = vc_buildseries_def
|
||||
|
||||
MSVC_BUILDTOOLS_DEFINITION = namedtuple('MSVCBuildtools', [
|
||||
'vc_buildtools',
|
||||
'vc_buildtools_numeric',
|
||||
'vc_buildseries_list',
|
||||
'vc_runtime_def',
|
||||
'vc_istoolset',
|
||||
'msvc_version',
|
||||
'msvc_version_numeric',
|
||||
])
|
||||
|
||||
MSVC_BUILDTOOLS_DEFINITION_LIST = []
|
||||
|
||||
MSVC_BUILDTOOLS_INTERNAL = {}
|
||||
MSVC_BUILDTOOLS_EXTERNAL = {}
|
||||
|
||||
MSVC_VERSION_NEWEST = None
|
||||
MSVC_VERSION_NEWEST_NUMERIC = 0.0
|
||||
|
||||
for vc_buildtools, vc_buildseries_list, vc_runtime, vc_istoolset in [
|
||||
('v145', ['145'], '140', True),
|
||||
('v143', ['144', '143'], '140', True),
|
||||
('v142', ['142'], '140', True),
|
||||
('v141', ['141'], '140', True),
|
||||
('v140', ['140'], '140', True),
|
||||
('v120', ['120'], '120', False),
|
||||
('v110', ['110'], '110', False),
|
||||
('v100', ['100'], '100', False),
|
||||
('v90', ['90'], '90', False),
|
||||
('v80', ['80'], '80', False),
|
||||
('v71', ['71'], '71', False),
|
||||
('v70', ['70'], '70', False),
|
||||
('v60', ['60'], '60', False),
|
||||
]:
|
||||
|
||||
vc_runtime_def = MSVC_RUNTIME_INTERNAL[vc_runtime]
|
||||
|
||||
vc_buildseries_list = tuple(
|
||||
MSVC_BUILDSERIES_INTERNAL[vc_buildseries]
|
||||
for vc_buildseries in vc_buildseries_list
|
||||
)
|
||||
|
||||
vc_buildtools_numstr = vc_buildtools[1:]
|
||||
|
||||
msvc_version = vc_buildtools_numstr[:-1] + '.' + vc_buildtools_numstr[-1]
|
||||
msvc_version_numeric = float(msvc_version)
|
||||
|
||||
vc_buildtools_def = MSVC_BUILDTOOLS_DEFINITION(
|
||||
vc_buildtools = vc_buildtools,
|
||||
vc_buildtools_numeric = int(vc_buildtools[1:]),
|
||||
vc_buildseries_list = vc_buildseries_list,
|
||||
vc_runtime_def = vc_runtime_def,
|
||||
vc_istoolset = vc_istoolset,
|
||||
msvc_version = msvc_version,
|
||||
msvc_version_numeric = msvc_version_numeric,
|
||||
)
|
||||
|
||||
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[msvc_version] = vc_buildtools_def
|
||||
|
||||
for vc_buildseries_def in vc_buildseries_list:
|
||||
VC_BUILDTOOLS_MAP[vc_buildseries_def.vc_buildseries] = vc_buildtools_def
|
||||
|
||||
if vc_buildtools_def.msvc_version_numeric > MSVC_VERSION_NEWEST_NUMERIC:
|
||||
MSVC_VERSION_NEWEST_NUMERIC = vc_buildtools_def.msvc_version_numeric
|
||||
MSVC_VERSION_NEWEST = vc_buildtools_def.msvc_version
|
||||
|
||||
MSVS_VERSION_INTERNAL = {}
|
||||
MSVS_VERSION_EXTERNAL = {}
|
||||
|
||||
MSVC_VERSION_INTERNAL = {}
|
||||
MSVC_VERSION_EXTERNAL = {}
|
||||
MSVC_VERSION_SUFFIX = {}
|
||||
|
||||
MSVS_VERSION_MAJOR_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 [
|
||||
('2026', '18.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v145', 'v143', 'v142', 'v141', 'v140']),
|
||||
('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)
|
||||
|
||||
msvc_version = vc_buildtools_def.msvc_version
|
||||
|
||||
MSVS_VERSION_INTERNAL[vs_product] = vs_def
|
||||
MSVS_VERSION_EXTERNAL[vs_product] = vs_def
|
||||
MSVS_VERSION_EXTERNAL[vs_version] = vs_def
|
||||
|
||||
MSVC_VERSION_INTERNAL[msvc_version] = vs_def
|
||||
MSVC_VERSION_EXTERNAL[vs_product] = vs_def
|
||||
MSVC_VERSION_EXTERNAL[msvc_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
|
||||
|
||||
MSVC_VERSION_SUFFIX[msvc_version] = vs_def
|
||||
if vs_express:
|
||||
MSVC_VERSION_SUFFIX[msvc_version + 'Exp'] = vs_def
|
||||
|
||||
MSVS_VERSION_MAJOR_MAP[vs_version_major] = vs_def
|
||||
|
||||
if vc_sdk:
|
||||
MSVC_SDK_VERSIONS.update(vc_sdk)
|
||||
|
||||
# EXPERIMENTAL: msvc version/toolset search lists
|
||||
#
|
||||
# VS2017 example:
|
||||
#
|
||||
# defaults['14.1'] = ['14.1', '14.1Exp']
|
||||
# defaults['14.1Exp'] = ['14.1Exp']
|
||||
#
|
||||
# search['14.1'] = ['14.3', '14.2', '14.1', '14.1Exp']
|
||||
# search['14.1Exp'] = ['14.1Exp']
|
||||
|
||||
MSVC_VERSION_TOOLSET_DEFAULTS_MAP = {}
|
||||
MSVC_VERSION_TOOLSET_SEARCH_MAP = {}
|
||||
|
||||
# Pass 1: Build defaults lists and setup express versions
|
||||
for vs_def in VISUALSTUDIO_DEFINITION_LIST:
|
||||
if not vs_def.vc_buildtools_def.vc_istoolset:
|
||||
continue
|
||||
version_key = vs_def.vc_buildtools_def.msvc_version
|
||||
MSVC_VERSION_TOOLSET_DEFAULTS_MAP[version_key] = [version_key]
|
||||
MSVC_VERSION_TOOLSET_SEARCH_MAP[version_key] = []
|
||||
if vs_def.vs_express:
|
||||
express_key = version_key + 'Exp'
|
||||
MSVC_VERSION_TOOLSET_DEFAULTS_MAP[version_key].append(express_key)
|
||||
MSVC_VERSION_TOOLSET_DEFAULTS_MAP[express_key] = [express_key]
|
||||
MSVC_VERSION_TOOLSET_SEARCH_MAP[express_key] = [express_key]
|
||||
|
||||
# Pass 2: Extend search lists (decreasing version order)
|
||||
for vs_def in VISUALSTUDIO_DEFINITION_LIST:
|
||||
if not vs_def.vc_buildtools_def.vc_istoolset:
|
||||
continue
|
||||
version_key = vs_def.vc_buildtools_def.msvc_version
|
||||
for vc_buildtools in vs_def.vc_buildtools_all:
|
||||
toolset_buildtools_def = MSVC_BUILDTOOLS_INTERNAL[vc_buildtools]
|
||||
toolset_vs_def = MSVC_VERSION_INTERNAL[toolset_buildtools_def.msvc_version]
|
||||
buildtools_key = toolset_buildtools_def.msvc_version
|
||||
MSVC_VERSION_TOOLSET_SEARCH_MAP[buildtools_key].extend(MSVC_VERSION_TOOLSET_DEFAULTS_MAP[version_key])
|
||||
|
||||
# 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)]
|
||||
|
||||
|
||||
def verify():
|
||||
from . import Util
|
||||
from .. import vc
|
||||
for msvc_version in vc._VCVER:
|
||||
if msvc_version not in MSVC_VERSION_SUFFIX:
|
||||
err_msg = f'msvc_version {msvc_version!r} not in MSVC_VERSION_SUFFIX'
|
||||
raise MSVCInternalError(err_msg)
|
||||
vc_version = Util.get_msvc_version_prefix(msvc_version)
|
||||
if vc_version not in MSVC_VERSION_INTERNAL:
|
||||
err_msg = f'vc_version {vc_version!r} not in MSVC_VERSION_INTERNAL'
|
||||
raise MSVCInternalError(err_msg)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# 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++.
|
||||
|
||||
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
|
||||
|
||||
from ..common import (
|
||||
debug,
|
||||
)
|
||||
|
||||
_refs = []
|
||||
|
||||
|
||||
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:
|
||||
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()
|
||||
@@ -0,0 +1,56 @@
|
||||
# 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++.
|
||||
"""
|
||||
|
||||
# reminder: add exceptions to MSCommon if necessary
|
||||
|
||||
class VisualCException(Exception):
|
||||
pass
|
||||
|
||||
class MSVCInternalError(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCUserError(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCScriptExecutionError(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCVersionNotFound(MSVCUserError):
|
||||
pass
|
||||
|
||||
class MSVCSDKVersionNotFound(MSVCUserError):
|
||||
pass
|
||||
|
||||
class MSVCToolsetVersionNotFound(MSVCUserError):
|
||||
pass
|
||||
|
||||
class MSVCSpectreLibsNotFound(MSVCUserError):
|
||||
pass
|
||||
|
||||
class MSVCArgumentError(MSVCUserError):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,668 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Version kind categorization for Microsoft Visual C/C++.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from collections import (
|
||||
namedtuple,
|
||||
)
|
||||
|
||||
from ..common import (
|
||||
debug,
|
||||
)
|
||||
|
||||
from . import Registry
|
||||
from . import Util
|
||||
|
||||
from . import Dispatcher
|
||||
Dispatcher.register_modulename(__name__)
|
||||
|
||||
|
||||
# use express install for non-express msvc_version if no other installations found
|
||||
USE_EXPRESS_FOR_NONEXPRESS = True
|
||||
|
||||
# productdir kind
|
||||
|
||||
VCVER_KIND_UNKNOWN = 0 # undefined
|
||||
VCVER_KIND_DEVELOP = 1 # devenv binary
|
||||
VCVER_KIND_EXPRESS = 2 # express binary
|
||||
VCVER_KIND_BTDISPATCH = 3 # no ide binaries (buildtools dispatch folder)
|
||||
VCVER_KIND_VCFORPYTHON = 4 # no ide binaries (2008/9.0)
|
||||
VCVER_KIND_EXPRESS_WIN = 5 # express for windows binary (VSWinExpress)
|
||||
VCVER_KIND_EXPRESS_WEB = 6 # express for web binary (VWDExpress)
|
||||
VCVER_KIND_SDK = 7 # no ide binaries
|
||||
VCVER_KIND_CMDLINE = 8 # no ide binaries
|
||||
|
||||
VCVER_KIND_STR = {
|
||||
VCVER_KIND_UNKNOWN: '<Unknown>',
|
||||
VCVER_KIND_DEVELOP: 'Develop',
|
||||
VCVER_KIND_EXPRESS: 'Express',
|
||||
VCVER_KIND_BTDISPATCH: 'BTDispatch',
|
||||
VCVER_KIND_VCFORPYTHON: 'VCForPython',
|
||||
VCVER_KIND_EXPRESS_WIN: 'Express-Win',
|
||||
VCVER_KIND_EXPRESS_WEB: 'Express-Web',
|
||||
VCVER_KIND_SDK: 'SDK',
|
||||
VCVER_KIND_CMDLINE: 'CmdLine',
|
||||
}
|
||||
|
||||
BITFIELD_KIND_DEVELOP = 0b_1000
|
||||
BITFIELD_KIND_EXPRESS = 0b_0100
|
||||
BITFIELD_KIND_EXPRESS_WIN = 0b_0010
|
||||
BITFIELD_KIND_EXPRESS_WEB = 0b_0001
|
||||
|
||||
VCVER_KIND_PROGRAM = namedtuple("VCVerKindProgram", [
|
||||
'kind', # relpath from pdir to vsroot
|
||||
'program', # ide binaries
|
||||
'bitfield',
|
||||
])
|
||||
|
||||
#
|
||||
|
||||
IDE_PROGRAM_DEVENV_COM = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_DEVELOP,
|
||||
program='devenv.com',
|
||||
bitfield=BITFIELD_KIND_DEVELOP,
|
||||
)
|
||||
|
||||
IDE_PROGRAM_MSDEV_COM = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_DEVELOP,
|
||||
program='msdev.com',
|
||||
bitfield=BITFIELD_KIND_DEVELOP,
|
||||
)
|
||||
|
||||
IDE_PROGRAM_WDEXPRESS_EXE = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_EXPRESS,
|
||||
program='WDExpress.exe',
|
||||
bitfield=BITFIELD_KIND_EXPRESS,
|
||||
)
|
||||
|
||||
IDE_PROGRAM_VCEXPRESS_EXE = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_EXPRESS,
|
||||
program='VCExpress.exe',
|
||||
bitfield=BITFIELD_KIND_EXPRESS,
|
||||
)
|
||||
|
||||
IDE_PROGRAM_VSWINEXPRESS_EXE = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_EXPRESS_WIN,
|
||||
program='VSWinExpress.exe',
|
||||
bitfield=BITFIELD_KIND_EXPRESS_WIN,
|
||||
)
|
||||
|
||||
IDE_PROGRAM_VWDEXPRESS_EXE = VCVER_KIND_PROGRAM(
|
||||
kind=VCVER_KIND_EXPRESS_WEB,
|
||||
program='VWDExpress.exe',
|
||||
bitfield=BITFIELD_KIND_EXPRESS_WEB,
|
||||
)
|
||||
|
||||
# detection configuration
|
||||
|
||||
VCVER_KIND_DETECT = namedtuple("VCVerKindDetect", [
|
||||
'root', # relpath from pdir to vsroot
|
||||
'path', # vsroot to ide dir
|
||||
'programs', # ide binaries
|
||||
])
|
||||
|
||||
# detected binaries
|
||||
|
||||
VCVER_DETECT_BINARIES = namedtuple("VCVerDetectBinaries", [
|
||||
'bitfields', # detect values
|
||||
'have_dev', # develop ide binary
|
||||
'have_exp', # express ide binary
|
||||
'have_exp_win', # express windows ide binary
|
||||
'have_exp_web', # express web ide binary
|
||||
])
|
||||
|
||||
|
||||
VCVER_DETECT_KIND = namedtuple("VCVerDetectKind", [
|
||||
'skip', # skip vs root
|
||||
'save', # save in case no other kind found
|
||||
'kind', # internal kind
|
||||
'binaries_t',
|
||||
'extended',
|
||||
])
|
||||
|
||||
# unknown value
|
||||
|
||||
_VCVER_DETECT_KIND_UNKNOWN = VCVER_DETECT_KIND(
|
||||
skip=True,
|
||||
save=False,
|
||||
kind=VCVER_KIND_UNKNOWN,
|
||||
binaries_t=VCVER_DETECT_BINARIES(
|
||||
bitfields=0b0,
|
||||
have_dev=False,
|
||||
have_exp=False,
|
||||
have_exp_win=False,
|
||||
have_exp_web=False,
|
||||
),
|
||||
extended={},
|
||||
)
|
||||
|
||||
#
|
||||
|
||||
_msvc_pdir_func = None
|
||||
|
||||
def register_msvc_version_pdir_func(func):
|
||||
global _msvc_pdir_func
|
||||
if func:
|
||||
_msvc_pdir_func = func
|
||||
|
||||
_cache_vcver_kind_map = {}
|
||||
|
||||
def msvc_version_register_kind(msvc_version, kind_t):
|
||||
global _cache_vcver_kind_map
|
||||
if kind_t is None:
|
||||
kind_t = _VCVER_DETECT_KIND_UNKNOWN
|
||||
debug('msvc_version=%s, kind=%s', repr(msvc_version), repr(VCVER_KIND_STR[kind_t.kind]))
|
||||
_cache_vcver_kind_map[msvc_version] = kind_t
|
||||
|
||||
def _msvc_version_kind_lookup(msvc_version, env=None):
|
||||
global _cache_vcver_kind_map
|
||||
global _msvc_pdir_func
|
||||
if msvc_version not in _cache_vcver_kind_map:
|
||||
_msvc_pdir_func(msvc_version, env)
|
||||
kind_t = _cache_vcver_kind_map.get(msvc_version, _VCVER_DETECT_KIND_UNKNOWN)
|
||||
debug(
|
||||
'kind=%s, dev=%s, exp=%s, msvc_version=%s',
|
||||
repr(VCVER_KIND_STR[kind_t.kind]),
|
||||
kind_t.binaries_t.have_dev, kind_t.binaries_t.have_exp,
|
||||
repr(msvc_version)
|
||||
)
|
||||
return kind_t
|
||||
|
||||
def msvc_version_is_btdispatch(msvc_version, env=None):
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
is_btdispatch = bool(kind_t.kind == VCVER_KIND_BTDISPATCH)
|
||||
debug(
|
||||
'is_btdispatch=%s, kind:%s, msvc_version=%s',
|
||||
repr(is_btdispatch), repr(VCVER_KIND_STR[kind_t.kind]), repr(msvc_version)
|
||||
)
|
||||
return is_btdispatch
|
||||
|
||||
def msvc_version_is_express(msvc_version, env=None):
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
is_express = bool(kind_t.kind == VCVER_KIND_EXPRESS)
|
||||
debug(
|
||||
'is_express=%s, kind:%s, msvc_version=%s',
|
||||
repr(is_express), repr(VCVER_KIND_STR[kind_t.kind]), repr(msvc_version)
|
||||
)
|
||||
return is_express
|
||||
|
||||
def msvc_version_is_vcforpython(msvc_version, env=None):
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
is_vcforpython = bool(kind_t.kind == VCVER_KIND_VCFORPYTHON)
|
||||
debug(
|
||||
'is_vcforpython=%s, kind:%s, msvc_version=%s',
|
||||
repr(is_vcforpython), repr(VCVER_KIND_STR[kind_t.kind]), repr(msvc_version)
|
||||
)
|
||||
return is_vcforpython
|
||||
|
||||
def msvc_version_skip_uwp_target(env, msvc_version):
|
||||
|
||||
vernum = float(Util.get_msvc_version_prefix(msvc_version))
|
||||
vernum_int = int(vernum * 10)
|
||||
|
||||
if vernum_int != 140:
|
||||
return False
|
||||
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
if kind_t.kind != VCVER_KIND_EXPRESS:
|
||||
return False
|
||||
|
||||
target_arch = env.get('TARGET_ARCH')
|
||||
|
||||
uwp_is_supported = kind_t.extended.get('uwp_is_supported', {})
|
||||
is_supported = uwp_is_supported.get(target_arch, True)
|
||||
|
||||
if is_supported:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _pdir_detect_binaries(pdir, detect):
|
||||
|
||||
vs_root = os.path.join(pdir, detect.root)
|
||||
ide_path = os.path.join(vs_root, detect.path)
|
||||
|
||||
bitfields = 0b_0000
|
||||
for ide_program in detect.programs:
|
||||
prog = os.path.join(ide_path, ide_program.program)
|
||||
if not os.path.exists(prog):
|
||||
continue
|
||||
bitfields |= ide_program.bitfield
|
||||
|
||||
have_dev = bool(bitfields & BITFIELD_KIND_DEVELOP)
|
||||
have_exp = bool(bitfields & BITFIELD_KIND_EXPRESS)
|
||||
have_exp_win = bool(bitfields & BITFIELD_KIND_EXPRESS_WIN)
|
||||
have_exp_web = bool(bitfields & BITFIELD_KIND_EXPRESS_WEB)
|
||||
|
||||
binaries_t = VCVER_DETECT_BINARIES(
|
||||
bitfields=bitfields,
|
||||
have_dev=have_dev,
|
||||
have_exp=have_exp,
|
||||
have_exp_win=have_exp_win,
|
||||
have_exp_web=have_exp_web,
|
||||
)
|
||||
|
||||
debug(
|
||||
'vs_root=%s, dev=%s, exp=%s, exp_win=%s, exp_web=%s, pdir=%s',
|
||||
repr(vs_root),
|
||||
binaries_t.have_dev, binaries_t.have_exp,
|
||||
binaries_t.have_exp_win, binaries_t.have_exp_web,
|
||||
repr(pdir)
|
||||
)
|
||||
|
||||
return vs_root, binaries_t
|
||||
|
||||
_cache_pdir_vswhere_kind = {}
|
||||
|
||||
def msvc_version_pdir_vswhere_kind(msvc_version, pdir, detect_t):
|
||||
global _cache_pdir_vswhere_kind
|
||||
|
||||
vc_dir = os.path.normcase(os.path.normpath(pdir))
|
||||
cache_key = (msvc_version, vc_dir)
|
||||
|
||||
rval = _cache_pdir_vswhere_kind.get(cache_key)
|
||||
if rval is not None:
|
||||
debug('cache=%s', repr(rval))
|
||||
return rval
|
||||
|
||||
extended = {}
|
||||
|
||||
prefix, suffix = Util.get_msvc_version_prefix_suffix(msvc_version)
|
||||
|
||||
vs_root, binaries_t = _pdir_detect_binaries(pdir, detect_t)
|
||||
|
||||
if binaries_t.have_dev:
|
||||
kind = VCVER_KIND_DEVELOP
|
||||
elif binaries_t.have_exp:
|
||||
kind = VCVER_KIND_EXPRESS
|
||||
else:
|
||||
kind = VCVER_KIND_CMDLINE
|
||||
|
||||
skip = False
|
||||
save = False
|
||||
|
||||
if suffix != 'Exp' and kind == VCVER_KIND_EXPRESS:
|
||||
skip = True
|
||||
save = USE_EXPRESS_FOR_NONEXPRESS
|
||||
elif suffix == 'Exp' and kind != VCVER_KIND_EXPRESS:
|
||||
skip = True
|
||||
|
||||
kind_t = VCVER_DETECT_KIND(
|
||||
skip=skip,
|
||||
save=save,
|
||||
kind=kind,
|
||||
binaries_t=binaries_t,
|
||||
extended=extended,
|
||||
)
|
||||
|
||||
debug(
|
||||
'skip=%s, save=%s, kind=%s, msvc_version=%s, pdir=%s',
|
||||
kind_t.skip, kind_t.save, repr(VCVER_KIND_STR[kind_t.kind]),
|
||||
repr(msvc_version), repr(pdir)
|
||||
)
|
||||
|
||||
_cache_pdir_vswhere_kind[cache_key] = kind_t
|
||||
|
||||
return kind_t
|
||||
|
||||
# VS2015 buildtools batch file call detection
|
||||
# vs2015 buildtools do not support sdk_version or UWP arguments
|
||||
|
||||
_VS2015BT_PATH = r'..\Microsoft Visual C++ Build Tools\vcbuildtools.bat'
|
||||
|
||||
_VS2015BT_REGEX_STR = ''.join([
|
||||
r'^\s*if\s+exist\s+',
|
||||
re.escape(fr'"%~dp0..\{_VS2015BT_PATH}"'),
|
||||
r'\s+goto\s+setup_buildsku\s*$',
|
||||
])
|
||||
|
||||
_VS2015BT_VCVARS_BUILDTOOLS = re.compile(_VS2015BT_REGEX_STR, re.IGNORECASE)
|
||||
_VS2015BT_VCVARS_STOP = re.compile(r'^\s*[:]Setup_VS\s*$', re.IGNORECASE)
|
||||
|
||||
def _vs_buildtools_2015_vcvars(vcvars_file):
|
||||
have_buildtools_vcvars = False
|
||||
with open(vcvars_file) as fh:
|
||||
for line in fh:
|
||||
if _VS2015BT_VCVARS_BUILDTOOLS.match(line):
|
||||
have_buildtools_vcvars = True
|
||||
break
|
||||
if _VS2015BT_VCVARS_STOP.match(line):
|
||||
break
|
||||
return have_buildtools_vcvars
|
||||
|
||||
def _vs_buildtools_2015(vs_root, vc_dir):
|
||||
|
||||
is_btdispatch = False
|
||||
|
||||
do_once = True
|
||||
while do_once:
|
||||
do_once = False
|
||||
|
||||
buildtools_file = os.path.join(vs_root, _VS2015BT_PATH)
|
||||
have_buildtools = os.path.exists(buildtools_file)
|
||||
debug('have_buildtools=%s', have_buildtools)
|
||||
if not have_buildtools:
|
||||
break
|
||||
|
||||
vcvars_file = os.path.join(vc_dir, 'vcvarsall.bat')
|
||||
have_vcvars = os.path.exists(vcvars_file)
|
||||
debug('have_vcvars=%s', have_vcvars)
|
||||
if not have_vcvars:
|
||||
break
|
||||
|
||||
have_buildtools_vcvars = _vs_buildtools_2015_vcvars(vcvars_file)
|
||||
debug('have_buildtools_vcvars=%s', have_buildtools_vcvars)
|
||||
if not have_buildtools_vcvars:
|
||||
break
|
||||
|
||||
is_btdispatch = True
|
||||
|
||||
debug('is_btdispatch=%s', is_btdispatch)
|
||||
return is_btdispatch
|
||||
|
||||
_VS2015EXP_VCVARS_LIBPATH = re.compile(
|
||||
''.join([
|
||||
r'^\s*\@if\s+exist\s+\"\%VCINSTALLDIR\%LIB\\store\\(amd64|arm)"\s+',
|
||||
r'set (LIB|LIBPATH)=\%VCINSTALLDIR\%LIB\\store\\(amd64|arm);.*\%(LIB|LIBPATH)\%\s*$'
|
||||
]),
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
_VS2015EXP_VCVARS_STOP = re.compile(r'^\s*[:]GetVSCommonToolsDir\s*$', re.IGNORECASE)
|
||||
|
||||
def _vs_express_2015_vcvars(vcvars_file):
|
||||
n_libpath = 0
|
||||
with open(vcvars_file) as fh:
|
||||
for line in fh:
|
||||
if _VS2015EXP_VCVARS_LIBPATH.match(line):
|
||||
n_libpath += 1
|
||||
elif _VS2015EXP_VCVARS_STOP.match(line):
|
||||
break
|
||||
have_uwp_fix = n_libpath >= 2
|
||||
return have_uwp_fix
|
||||
|
||||
def _vs_express_2015(pdir):
|
||||
|
||||
have_uwp_amd64 = False
|
||||
have_uwp_arm = False
|
||||
|
||||
vcvars_file = os.path.join(pdir, r'vcvarsall.bat')
|
||||
if os.path.exists(vcvars_file):
|
||||
|
||||
vcvars_file = os.path.join(pdir, r'bin\x86_amd64\vcvarsx86_amd64.bat')
|
||||
if os.path.exists(vcvars_file):
|
||||
have_uwp_fix = _vs_express_2015_vcvars(vcvars_file)
|
||||
if have_uwp_fix:
|
||||
have_uwp_amd64 = True
|
||||
|
||||
vcvars_file = os.path.join(pdir, r'bin\x86_arm\vcvarsx86_arm.bat')
|
||||
if os.path.exists(vcvars_file):
|
||||
have_uwp_fix = _vs_express_2015_vcvars(vcvars_file)
|
||||
if have_uwp_fix:
|
||||
have_uwp_arm = True
|
||||
|
||||
debug('have_uwp_amd64=%s, have_uwp_arm=%s', have_uwp_amd64, have_uwp_arm)
|
||||
return have_uwp_amd64, have_uwp_arm
|
||||
|
||||
# winsdk installed 2010 [7.1], 2008 [7.0, 6.1] folders
|
||||
|
||||
_REGISTRY_WINSDK_VERSIONS = {'10.0', '9.0'}
|
||||
|
||||
_cache_pdir_registry_winsdk = {}
|
||||
|
||||
def _msvc_version_pdir_registry_winsdk(msvc_version, pdir):
|
||||
global _cache_pdir_registry_winsdk
|
||||
|
||||
# detect winsdk-only installations
|
||||
#
|
||||
# registry keys:
|
||||
# [prefix]\VisualStudio\SxS\VS7\10.0 <undefined>
|
||||
# [prefix]\VisualStudio\SxS\VC7\10.0 product directory
|
||||
# [prefix]\VisualStudio\SxS\VS7\9.0 <undefined>
|
||||
# [prefix]\VisualStudio\SxS\VC7\9.0 product directory
|
||||
#
|
||||
# winsdk notes:
|
||||
# - winsdk installs do not define the common tools env var
|
||||
# - the product dir is detected but the vcvars batch files will fail
|
||||
# - regular installations populate the VS7 registry keys
|
||||
#
|
||||
|
||||
vc_dir = os.path.normcase(os.path.normpath(pdir))
|
||||
cache_key = (msvc_version, vc_dir)
|
||||
|
||||
rval = _cache_pdir_registry_winsdk.get(cache_key)
|
||||
if rval is not None:
|
||||
debug('cache=%s', repr(rval))
|
||||
return rval
|
||||
|
||||
if msvc_version not in _REGISTRY_WINSDK_VERSIONS:
|
||||
|
||||
is_sdk = False
|
||||
|
||||
debug('is_sdk=%s, msvc_version=%s', is_sdk, repr(msvc_version))
|
||||
|
||||
else:
|
||||
|
||||
vc_dir = os.path.normcase(os.path.normpath(pdir))
|
||||
|
||||
vc_suffix = Registry.vstudio_sxs_vc7(msvc_version)
|
||||
vc_qresults = [record[0] for record in Registry.microsoft_query_paths(vc_suffix)]
|
||||
vc_root = os.path.normcase(os.path.normpath(vc_qresults[0])) if vc_qresults else None
|
||||
|
||||
if vc_dir != vc_root:
|
||||
# registry vc path is not the current pdir
|
||||
|
||||
is_sdk = False
|
||||
|
||||
debug(
|
||||
'is_sdk=%s, msvc_version=%s, pdir=%s, vc_root=%s',
|
||||
is_sdk, repr(msvc_version), repr(vc_dir), repr(vc_root)
|
||||
)
|
||||
|
||||
else:
|
||||
# registry vc path is the current pdir
|
||||
|
||||
vs_suffix = Registry.vstudio_sxs_vs7(msvc_version)
|
||||
vs_qresults = [record[0] for record in Registry.microsoft_query_paths(vs_suffix)]
|
||||
vs_root = vs_qresults[0] if vs_qresults else None
|
||||
|
||||
is_sdk = bool(not vs_root and vc_root)
|
||||
|
||||
debug(
|
||||
'is_sdk=%s, msvc_version=%s, vs_root=%s, vc_root=%s',
|
||||
is_sdk, repr(msvc_version), repr(vs_root), repr(vc_root)
|
||||
)
|
||||
|
||||
_cache_pdir_registry_winsdk[cache_key] = is_sdk
|
||||
|
||||
return is_sdk
|
||||
|
||||
_cache_pdir_registry_kind = {}
|
||||
|
||||
def msvc_version_pdir_registry_kind(msvc_version, pdir, detect_t, is_vcforpython=False):
|
||||
global _cache_pdir_registry_kind
|
||||
|
||||
vc_dir = os.path.normcase(os.path.normpath(pdir))
|
||||
cache_key = (msvc_version, vc_dir)
|
||||
|
||||
rval = _cache_pdir_registry_kind.get(cache_key)
|
||||
if rval is not None:
|
||||
debug('cache=%s', repr(rval))
|
||||
return rval
|
||||
|
||||
extended = {}
|
||||
|
||||
prefix, suffix = Util.get_msvc_version_prefix_suffix(msvc_version)
|
||||
|
||||
vs_root, binaries_t = _pdir_detect_binaries(pdir, detect_t)
|
||||
|
||||
if binaries_t.have_dev:
|
||||
kind = VCVER_KIND_DEVELOP
|
||||
elif binaries_t.have_exp:
|
||||
kind = VCVER_KIND_EXPRESS
|
||||
elif msvc_version == '14.0' and _vs_buildtools_2015(vs_root, pdir):
|
||||
kind = VCVER_KIND_BTDISPATCH
|
||||
elif msvc_version == '9.0' and is_vcforpython:
|
||||
kind = VCVER_KIND_VCFORPYTHON
|
||||
elif binaries_t.have_exp_win:
|
||||
kind = VCVER_KIND_EXPRESS_WIN
|
||||
elif binaries_t.have_exp_web:
|
||||
kind = VCVER_KIND_EXPRESS_WEB
|
||||
elif _msvc_version_pdir_registry_winsdk(msvc_version, pdir):
|
||||
kind = VCVER_KIND_SDK
|
||||
else:
|
||||
kind = VCVER_KIND_CMDLINE
|
||||
|
||||
skip = False
|
||||
save = False
|
||||
|
||||
if kind in (VCVER_KIND_EXPRESS_WIN, VCVER_KIND_EXPRESS_WEB, VCVER_KIND_SDK):
|
||||
skip = True
|
||||
elif suffix != 'Exp' and kind == VCVER_KIND_EXPRESS:
|
||||
skip = True
|
||||
save = USE_EXPRESS_FOR_NONEXPRESS
|
||||
elif suffix == 'Exp' and kind != VCVER_KIND_EXPRESS:
|
||||
skip = True
|
||||
|
||||
if prefix == '14.0' and kind == VCVER_KIND_EXPRESS:
|
||||
have_uwp_amd64, have_uwp_arm = _vs_express_2015(pdir)
|
||||
uwp_is_supported = {
|
||||
'x86': True,
|
||||
'amd64': have_uwp_amd64,
|
||||
'arm': have_uwp_arm,
|
||||
}
|
||||
extended['uwp_is_supported'] = uwp_is_supported
|
||||
|
||||
kind_t = VCVER_DETECT_KIND(
|
||||
skip=skip,
|
||||
save=save,
|
||||
kind=kind,
|
||||
binaries_t=binaries_t,
|
||||
extended=extended,
|
||||
)
|
||||
|
||||
debug(
|
||||
'skip=%s, save=%s, kind=%s, msvc_version=%s, pdir=%s',
|
||||
kind_t.skip, kind_t.save, repr(VCVER_KIND_STR[kind_t.kind]),
|
||||
repr(msvc_version), repr(pdir)
|
||||
)
|
||||
|
||||
_cache_pdir_registry_kind[cache_key] = kind_t
|
||||
|
||||
return kind_t
|
||||
|
||||
# queries
|
||||
|
||||
def get_msvc_version_kind(msvc_version, env=None):
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
kind_str = VCVER_KIND_STR[kind_t.kind]
|
||||
debug(
|
||||
'kind=%s, kind_str=%s, msvc_version=%s',
|
||||
repr(kind_t.kind), repr(kind_str), repr(msvc_version)
|
||||
)
|
||||
return (kind_t.kind, kind_str)
|
||||
|
||||
def msvc_version_sdk_version_is_supported(msvc_version, env=None):
|
||||
|
||||
vernum = float(Util.get_msvc_version_prefix(msvc_version))
|
||||
vernum_int = int(vernum * 10)
|
||||
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
|
||||
if vernum_int >= 141:
|
||||
# VS2017 and later
|
||||
is_supported = True
|
||||
elif vernum_int == 140:
|
||||
# VS2015:
|
||||
# True: Develop, CmdLine
|
||||
# False: Express, BTDispatch
|
||||
is_supported = True
|
||||
if kind_t.kind == VCVER_KIND_EXPRESS:
|
||||
is_supported = False
|
||||
elif kind_t.kind == VCVER_KIND_BTDISPATCH:
|
||||
is_supported = False
|
||||
else:
|
||||
# VS2013 and earlier
|
||||
is_supported = False
|
||||
|
||||
debug(
|
||||
'is_supported=%s, msvc_version=%s, kind=%s',
|
||||
is_supported, repr(msvc_version), repr(VCVER_KIND_STR[kind_t.kind])
|
||||
)
|
||||
return is_supported
|
||||
|
||||
def msvc_version_uwp_is_supported(msvc_version, target_arch=None, env=None):
|
||||
|
||||
vernum = float(Util.get_msvc_version_prefix(msvc_version))
|
||||
vernum_int = int(vernum * 10)
|
||||
|
||||
kind_t = _msvc_version_kind_lookup(msvc_version, env)
|
||||
|
||||
is_target = False
|
||||
|
||||
if vernum_int >= 141:
|
||||
# VS2017 and later
|
||||
is_supported = True
|
||||
elif vernum_int == 140:
|
||||
# VS2015:
|
||||
# True: Develop, CmdLine
|
||||
# Maybe: Express
|
||||
# False: BTDispatch
|
||||
is_supported = True
|
||||
if kind_t.kind == VCVER_KIND_EXPRESS:
|
||||
uwp_is_supported = kind_t.extended.get('uwp_is_supported', {})
|
||||
is_supported = uwp_is_supported.get(target_arch, True)
|
||||
is_target = True
|
||||
elif kind_t.kind == VCVER_KIND_BTDISPATCH:
|
||||
is_supported = False
|
||||
else:
|
||||
# VS2013 and earlier
|
||||
is_supported = False
|
||||
|
||||
debug(
|
||||
'is_supported=%s, is_target=%s, msvc_version=%s, kind=%s, target_arch=%s',
|
||||
is_supported, is_target, repr(msvc_version), repr(VCVER_KIND_STR[kind_t.kind]), repr(target_arch)
|
||||
)
|
||||
|
||||
return is_supported, is_target
|
||||
|
||||
# reset cache
|
||||
|
||||
def reset():
|
||||
global _cache_vcver_kind_map
|
||||
global _cache_pdir_vswhere_kind
|
||||
global _cache_pdir_registry_kind
|
||||
global _cache_pdir_registry_winsdk
|
||||
|
||||
debug('')
|
||||
|
||||
_cache_vcver_kind_map = {}
|
||||
_cache_pdir_vswhere_kind = {}
|
||||
_cache_pdir_registry_kind = {}
|
||||
_cache_pdir_registry_winsdk = {}
|
||||
@@ -0,0 +1,330 @@
|
||||
# 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++ policy handlers.
|
||||
|
||||
Notes:
|
||||
* The default msvc not found policy 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 construction variable.
|
||||
* The default msvc script error policy is to suppress all msvc batch file
|
||||
error messages. This can be changed globally via the function
|
||||
set_msvc_scripterror_policy and/or through the environment via the
|
||||
MSVC_SCRIPTERROR_POLICY construction variable.
|
||||
"""
|
||||
|
||||
from collections import (
|
||||
namedtuple,
|
||||
)
|
||||
|
||||
from contextlib import (
|
||||
contextmanager,
|
||||
)
|
||||
|
||||
import SCons.Warnings
|
||||
|
||||
from ..common import (
|
||||
debug,
|
||||
)
|
||||
|
||||
from .Exceptions import (
|
||||
MSVCArgumentError,
|
||||
MSVCVersionNotFound,
|
||||
MSVCScriptExecutionError,
|
||||
)
|
||||
|
||||
from .Warnings import (
|
||||
MSVCScriptExecutionWarning,
|
||||
)
|
||||
|
||||
from . import Dispatcher
|
||||
Dispatcher.register_modulename(__name__)
|
||||
|
||||
|
||||
# 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(policy_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
|
||||
|
||||
# default definition
|
||||
_MSVC_NOTFOUND_POLICY_DEF = MSVC_NOTFOUND_POLICY_INTERNAL['warning']
|
||||
|
||||
|
||||
# MSVC_SCRIPTERROR_POLICY definition:
|
||||
# error: raise exception
|
||||
# warning: issue warning and continue
|
||||
# ignore: continue
|
||||
|
||||
MSVC_SCRIPTERROR_POLICY_DEFINITION = namedtuple('MSVCBatchErrorPolicyDefinition', [
|
||||
'value',
|
||||
'symbol',
|
||||
])
|
||||
|
||||
MSVC_SCRIPTERROR_DEFINITION_LIST = []
|
||||
|
||||
MSVC_SCRIPTERROR_POLICY_INTERNAL = {}
|
||||
MSVC_SCRIPTERROR_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_SCRIPTERROR_POLICY_DEFINITION(policy_value, policy_symbol)
|
||||
|
||||
MSVC_SCRIPTERROR_DEFINITION_LIST.append(policy_def)
|
||||
|
||||
MSVC_SCRIPTERROR_POLICY_INTERNAL[policy_symbol] = policy_def
|
||||
|
||||
for policy_symbol in policy_symbol_list:
|
||||
MSVC_SCRIPTERROR_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
|
||||
MSVC_SCRIPTERROR_POLICY_EXTERNAL[policy_symbol] = policy_def
|
||||
MSVC_SCRIPTERROR_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
|
||||
|
||||
# default definition
|
||||
_MSVC_SCRIPTERROR_POLICY_DEF = MSVC_SCRIPTERROR_POLICY_INTERNAL['ignore']
|
||||
|
||||
|
||||
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 MSVCArgumentError(err_msg)
|
||||
|
||||
return notfound_policy_def
|
||||
|
||||
def msvc_set_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 msvc_get_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_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)
|
||||
|
||||
@contextmanager
|
||||
def msvc_notfound_policy_contextmanager(MSVC_NOTFOUND_POLICY=None):
|
||||
""" Temporarily change the MSVC not found policy within a context.
|
||||
|
||||
Args:
|
||||
MSVC_NOTFOUND_POLICY:
|
||||
string representing the policy behavior
|
||||
when MSVC is not found or None
|
||||
"""
|
||||
prev_policy = msvc_set_notfound_policy(MSVC_NOTFOUND_POLICY)
|
||||
yield
|
||||
msvc_set_notfound_policy(prev_policy)
|
||||
|
||||
def _msvc_scripterror_policy_lookup(symbol):
|
||||
|
||||
try:
|
||||
scripterror_policy_def = MSVC_SCRIPTERROR_POLICY_EXTERNAL[symbol]
|
||||
except KeyError:
|
||||
err_msg = "Value specified for MSVC_SCRIPTERROR_POLICY is not supported: {}.\n" \
|
||||
" Valid values are: {}".format(
|
||||
repr(symbol),
|
||||
', '.join([repr(s) for s in MSVC_SCRIPTERROR_POLICY_EXTERNAL.keys()])
|
||||
)
|
||||
raise MSVCArgumentError(err_msg)
|
||||
|
||||
return scripterror_policy_def
|
||||
|
||||
def msvc_set_scripterror_policy(MSVC_SCRIPTERROR_POLICY=None):
|
||||
""" Set the default policy when msvc batch file execution errors are detected.
|
||||
|
||||
Args:
|
||||
MSVC_SCRIPTERROR_POLICY:
|
||||
string representing the policy behavior
|
||||
when msvc batch file execution errors are detected or None
|
||||
|
||||
Returns:
|
||||
The previous policy is returned when the MSVC_SCRIPTERROR_POLICY argument
|
||||
is not None. The active policy is returned when the MSVC_SCRIPTERROR_POLICY
|
||||
argument is None.
|
||||
|
||||
"""
|
||||
global _MSVC_SCRIPTERROR_POLICY_DEF
|
||||
|
||||
prev_policy = _MSVC_SCRIPTERROR_POLICY_DEF.symbol
|
||||
|
||||
policy = MSVC_SCRIPTERROR_POLICY
|
||||
if policy is not None:
|
||||
_MSVC_SCRIPTERROR_POLICY_DEF = _msvc_scripterror_policy_lookup(policy)
|
||||
|
||||
debug(
|
||||
'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
|
||||
repr(prev_policy), repr(policy),
|
||||
repr(_MSVC_SCRIPTERROR_POLICY_DEF.symbol), repr(_MSVC_SCRIPTERROR_POLICY_DEF.value)
|
||||
)
|
||||
|
||||
return prev_policy
|
||||
|
||||
def msvc_get_scripterror_policy():
|
||||
"""Return the active policy when msvc batch file execution errors are detected."""
|
||||
debug(
|
||||
'policy.symbol=%s, policy.value=%s',
|
||||
repr(_MSVC_SCRIPTERROR_POLICY_DEF.symbol), repr(_MSVC_SCRIPTERROR_POLICY_DEF.value)
|
||||
)
|
||||
return _MSVC_SCRIPTERROR_POLICY_DEF.symbol
|
||||
|
||||
def msvc_scripterror_handler(env, msg):
|
||||
|
||||
if env and 'MSVC_SCRIPTERROR_POLICY' in env:
|
||||
# environment setting
|
||||
scripterror_policy_src = 'environment'
|
||||
policy = env['MSVC_SCRIPTERROR_POLICY']
|
||||
if policy is not None:
|
||||
# user policy request
|
||||
scripterror_policy_def = _msvc_scripterror_policy_lookup(policy)
|
||||
else:
|
||||
# active global setting
|
||||
scripterror_policy_def = _MSVC_SCRIPTERROR_POLICY_DEF
|
||||
else:
|
||||
# active global setting
|
||||
scripterror_policy_src = 'default'
|
||||
policy = None
|
||||
scripterror_policy_def = _MSVC_SCRIPTERROR_POLICY_DEF
|
||||
|
||||
debug(
|
||||
'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
|
||||
scripterror_policy_src, repr(policy), repr(scripterror_policy_def.symbol), repr(scripterror_policy_def.value)
|
||||
)
|
||||
|
||||
if scripterror_policy_def.value is None:
|
||||
# ignore
|
||||
pass
|
||||
elif scripterror_policy_def.value:
|
||||
raise MSVCScriptExecutionError(msg)
|
||||
else:
|
||||
SCons.Warnings.warn(MSVCScriptExecutionWarning, msg)
|
||||
|
||||
@contextmanager
|
||||
def msvc_scripterror_policy_contextmanager(MSVC_SCRIPTERROR_POLICY=None):
|
||||
""" Temporarily change the msvc batch execution errors policy within a context.
|
||||
|
||||
Args:
|
||||
MSVC_SCRIPTERROR_POLICY:
|
||||
string representing the policy behavior
|
||||
when msvc batch file execution errors are detected or None
|
||||
"""
|
||||
prev_policy = msvc_set_scripterror_policy(MSVC_SCRIPTERROR_POLICY)
|
||||
yield
|
||||
msvc_set_scripterror_policy(prev_policy)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# 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,
|
||||
RegGetValue,
|
||||
)
|
||||
|
||||
from .. common import (
|
||||
debug,
|
||||
)
|
||||
|
||||
from . import Util
|
||||
|
||||
from . import Dispatcher
|
||||
Dispatcher.register_modulename(__name__)
|
||||
|
||||
|
||||
# A null-terminated string that contains unexpanded references to environment variables.
|
||||
REG_EXPAND_SZ = 2
|
||||
|
||||
def read_value(hkey, subkey_valname, expand=True):
|
||||
try:
|
||||
rval_t = RegGetValue(hkey, subkey_valname)
|
||||
except OSError:
|
||||
debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
|
||||
return None
|
||||
rval, regtype = rval_t
|
||||
if regtype == REG_EXPAND_SZ and expand:
|
||||
rval = os.path.expandvars(rval)
|
||||
debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
|
||||
return rval
|
||||
|
||||
def registry_query_path(key, val, suffix, expand=True):
|
||||
extval = val + '\\' + suffix if suffix else val
|
||||
qpath = read_value(key, extval, expand=expand)
|
||||
if qpath and os.path.exists(qpath):
|
||||
qpath = Util.normalize_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, expand=True):
|
||||
paths = []
|
||||
records = []
|
||||
for key, val in REG_SOFTWARE_MICROSOFT:
|
||||
extval = val + '\\' + suffix if suffix else val
|
||||
qpath = read_value(key, extval, expand=expand)
|
||||
if qpath and os.path.exists(qpath):
|
||||
qpath = Util.normalize_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, expand=True):
|
||||
records = []
|
||||
for key, val in REG_SOFTWARE_MICROSOFT:
|
||||
extval = val + '\\' + suffix if suffix else val
|
||||
rval = read_value(key, extval, expand=expand)
|
||||
if rval:
|
||||
records.append((rval, 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)
|
||||
|
||||
def vstudio_sxs_vs7(version):
|
||||
return '\\'.join([r'VisualStudio\SxS\VS7', version])
|
||||
|
||||
def vstudio_sxs_vc7(version):
|
||||
return '\\'.join([r'VisualStudio\SxS\VC7', version])
|
||||
|
||||
def devdiv_vs_servicing_component(version, component):
|
||||
return '\\'.join([r'DevDiv\VS\Servicing', version, component, 'Install'])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
# 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):
|
||||
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):
|
||||
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)
|
||||
if not _Data.default_tools_re_list:
|
||||
debug('default_tools_re_list=%s', _Data.default_tools_re_list)
|
||||
else:
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,494 @@
|
||||
# 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 pathlib
|
||||
import re
|
||||
|
||||
from collections import (
|
||||
namedtuple,
|
||||
)
|
||||
|
||||
from ..common import debug
|
||||
|
||||
from . import Config
|
||||
|
||||
|
||||
# call _initialize method upon class definition completion
|
||||
|
||||
class AutoInitialize:
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
super().__init_subclass__(**kwargs)
|
||||
if hasattr(cls, '_initialize') and callable(getattr(cls, '_initialize', None)):
|
||||
cls._initialize()
|
||||
|
||||
# path utilities
|
||||
|
||||
# windows drive specification (e.g., 'C:')
|
||||
_RE_DRIVESPEC = re.compile(r'^[A-Za-z][:]$', re.IGNORECASE)
|
||||
|
||||
# windows path separators
|
||||
_OS_PATH_SEPS = (os.path.sep, os.path.altsep) if os.path.altsep else (os.path.sep,)
|
||||
|
||||
def listdir_dirs(p):
|
||||
"""
|
||||
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.
|
||||
|
||||
Args:
|
||||
p: str
|
||||
directory path
|
||||
|
||||
Returns:
|
||||
list[tuple[str,str]]: a list of tuples
|
||||
|
||||
"""
|
||||
dirs = []
|
||||
if p and os.path.exists(p) and os.path.isdir(p):
|
||||
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 resolve_path(p, ignore_drivespec=True):
|
||||
"""
|
||||
Make path absolute resolving any symlinks
|
||||
|
||||
Args:
|
||||
p: str
|
||||
system path
|
||||
ignore_drivespec: bool
|
||||
ignore drive specifications when True
|
||||
|
||||
Returns:
|
||||
str: absolute path with symlinks resolved
|
||||
|
||||
"""
|
||||
|
||||
if p:
|
||||
|
||||
if ignore_drivespec and _RE_DRIVESPEC.match(p):
|
||||
# don't attempt to resolve drive specification (e.g., C:)
|
||||
pass
|
||||
else:
|
||||
# both abspath and resolve necessary for an unqualified file name
|
||||
# on a mapped network drive in order to return a mapped drive letter
|
||||
# path rather than a UNC path.
|
||||
p = os.path.abspath(p)
|
||||
try:
|
||||
p = str(pathlib.Path(p).resolve())
|
||||
except OSError as e:
|
||||
debug(
|
||||
'caught exception: path=%s, exception=%s(%s)',
|
||||
repr(p), type(e).__name__, repr(str(e))
|
||||
)
|
||||
|
||||
return p
|
||||
|
||||
def normalize_path(
|
||||
p,
|
||||
strip=True,
|
||||
preserve_trailing=False,
|
||||
expand=False,
|
||||
realpath=True,
|
||||
ignore_drivespec=True,
|
||||
):
|
||||
"""
|
||||
Normalize path
|
||||
|
||||
Args:
|
||||
p: str
|
||||
system path
|
||||
strip: bool
|
||||
remove leading and trailing whitespace when True
|
||||
preserve_trailing: bool
|
||||
preserve trailing path separator when True
|
||||
expand: bool
|
||||
apply expanduser and expandvars when True
|
||||
realpath: bool
|
||||
make the path absolute resolving any symlinks when True
|
||||
ignore_drivespec: bool
|
||||
ignore drive specifications for realpath when True
|
||||
|
||||
Returns:
|
||||
str: normalized path
|
||||
|
||||
"""
|
||||
|
||||
if p and strip:
|
||||
p = p.strip()
|
||||
|
||||
if p:
|
||||
|
||||
trailing = bool(preserve_trailing and p.endswith(_OS_PATH_SEPS))
|
||||
|
||||
if expand:
|
||||
p = os.path.expanduser(p)
|
||||
p = os.path.expandvars(p)
|
||||
|
||||
p = os.path.normpath(p)
|
||||
|
||||
if realpath:
|
||||
p = resolve_path(p, ignore_drivespec=ignore_drivespec)
|
||||
|
||||
p = os.path.normcase(p)
|
||||
|
||||
if trailing:
|
||||
p += os.path.sep
|
||||
|
||||
return p
|
||||
|
||||
# msvc version and msvc toolset version regexes
|
||||
|
||||
re_version_prefix = re.compile('^(?P<version>[0-9]+(?:[.][0-9]+)*)(?![.]).*$')
|
||||
|
||||
re_msvc_version_prefix = re.compile(r'^(?P<version>[1-9][0-9]?[.][0-9]).*$')
|
||||
|
||||
re_msvc_version = re.compile(r'^(?P<msvc_version>[1-9][0-9]?[.][0-9])(?P<suffix>[A-Z]+)*$', re.IGNORECASE)
|
||||
|
||||
re_extended_version = re.compile(r'''^
|
||||
(?P<version>(?:
|
||||
([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
|
||||
([1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}) # XX.YY.AA.B - XX.YY.AA.BB
|
||||
))
|
||||
(?P<suffix>[A-Z]+)*
|
||||
$''', re.IGNORECASE | re.VERBOSE)
|
||||
|
||||
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)
|
||||
|
||||
re_toolset_sxs = re.compile(
|
||||
r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$' # MM.mm.VV.vv format
|
||||
)
|
||||
|
||||
# msvc sdk version regexes
|
||||
|
||||
re_msvc_sdk_version = re.compile(r'''^
|
||||
(?P<version>(?:
|
||||
([1-9][0-9]?[.][0-9])| # XX.Y
|
||||
([1-9][0-9][.][0-9]{1}[.][0-9]{5}[.][0-9]{1,2}) # XX.Y.ZZZZZ.A - XX.Y.ZZZZZ.AA
|
||||
))
|
||||
$''', re.IGNORECASE | re.VERBOSE)
|
||||
|
||||
# version prefix utilities
|
||||
|
||||
def get_version_prefix(version):
|
||||
"""
|
||||
Get the version number prefix from a string.
|
||||
|
||||
Args:
|
||||
version: str
|
||||
version specification
|
||||
|
||||
Returns:
|
||||
str: the version number prefix
|
||||
|
||||
"""
|
||||
rval = ''
|
||||
if version:
|
||||
m = re_version_prefix.match(version)
|
||||
if m:
|
||||
rval = m.group('version')
|
||||
return rval
|
||||
|
||||
def get_msvc_version_prefix(version):
|
||||
"""
|
||||
Get the msvc version number prefix from a string.
|
||||
|
||||
Args:
|
||||
version: str
|
||||
version specification
|
||||
|
||||
Returns:
|
||||
str: the msvc version number prefix
|
||||
|
||||
"""
|
||||
rval = ''
|
||||
if version:
|
||||
m = re_msvc_version_prefix.match(version)
|
||||
if m:
|
||||
rval = m.group('version')
|
||||
return rval
|
||||
|
||||
def get_msvc_version_prefix_suffix(version):
|
||||
"""
|
||||
Get the msvc version number prefix and suffix from a string.
|
||||
|
||||
Args:
|
||||
version: str
|
||||
version specification
|
||||
|
||||
Returns:
|
||||
(str, str): the msvc version prefix and suffix
|
||||
|
||||
"""
|
||||
prefix = suffix = ''
|
||||
if version:
|
||||
m = re_msvc_version.match(version)
|
||||
if m:
|
||||
prefix = m.group('msvc_version')
|
||||
suffix = m.group('suffix') if m.group('suffix') else ''
|
||||
return prefix, suffix
|
||||
|
||||
# toolset version query utilities
|
||||
|
||||
def is_toolset_full(toolset_version):
|
||||
rval = False
|
||||
if toolset_version:
|
||||
if re_toolset_full.match(toolset_version):
|
||||
rval = True
|
||||
return rval
|
||||
|
||||
def is_toolset_140(toolset_version):
|
||||
rval = False
|
||||
if toolset_version:
|
||||
if re_toolset_140.match(toolset_version):
|
||||
rval = True
|
||||
return rval
|
||||
|
||||
def is_toolset_sxs(toolset_version):
|
||||
rval = False
|
||||
if toolset_version:
|
||||
if re_toolset_sxs.match(toolset_version):
|
||||
rval = True
|
||||
return rval
|
||||
|
||||
# msvc version and msvc toolset version decomposition utilties
|
||||
|
||||
_MSVC_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCVersionComponentsDefinition', [
|
||||
'msvc_version', # msvc version (e.g., '14.1Exp')
|
||||
'msvc_verstr', # msvc version numeric string (e.g., '14.1')
|
||||
'msvc_suffix', # msvc version component type (e.g., 'Exp')
|
||||
'msvc_vernum', # msvc version floating point number (e.g, 14.1)
|
||||
'msvc_major', # msvc major version integer number (e.g., 14)
|
||||
'msvc_minor', # msvc minor version integer number (e.g., 1)
|
||||
'msvc_comps', # msvc version components tuple (e.g., ('14', '1'))
|
||||
])
|
||||
|
||||
def msvc_version_components(vcver):
|
||||
"""
|
||||
Decompose an msvc version into components.
|
||||
|
||||
Tuple fields:
|
||||
msvc_version: msvc version (e.g., '14.1Exp')
|
||||
msvc_verstr: msvc version numeric string (e.g., '14.1')
|
||||
msvc_suffix: msvc version component type (e.g., 'Exp')
|
||||
msvc_vernum: msvc version floating point number (e.g., 14.1)
|
||||
msvc_major: msvc major version integer number (e.g., 14)
|
||||
msvc_minor: msvc minor version integer number (e.g., 1)
|
||||
msvc_comps: msvc version components tuple (e.g., ('14', '1'))
|
||||
|
||||
Args:
|
||||
vcver: str
|
||||
msvc version specification
|
||||
|
||||
Returns:
|
||||
None or MSVCVersionComponents namedtuple:
|
||||
"""
|
||||
|
||||
if not vcver:
|
||||
return None
|
||||
|
||||
m = re_msvc_version.match(vcver)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
vs_def = Config.MSVC_VERSION_SUFFIX.get(vcver)
|
||||
if not vs_def:
|
||||
return None
|
||||
|
||||
msvc_version = vcver
|
||||
msvc_verstr = m.group('msvc_version')
|
||||
msvc_suffix = m.group('suffix') if m.group('suffix') else ''
|
||||
msvc_vernum = float(msvc_verstr)
|
||||
|
||||
msvc_comps = tuple(msvc_verstr.split('.'))
|
||||
msvc_major, msvc_minor = (int(x) for x in msvc_comps)
|
||||
|
||||
msvc_version_components_def = _MSVC_VERSION_COMPONENTS_DEFINITION(
|
||||
msvc_version = msvc_version,
|
||||
msvc_verstr = msvc_verstr,
|
||||
msvc_suffix = msvc_suffix,
|
||||
msvc_vernum = msvc_vernum,
|
||||
msvc_major = msvc_major,
|
||||
msvc_minor = msvc_minor,
|
||||
msvc_comps = msvc_comps,
|
||||
)
|
||||
|
||||
return msvc_version_components_def
|
||||
|
||||
_MSVC_EXTENDED_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCExtendedVersionComponentsDefinition', [
|
||||
'msvc_version', # msvc version (e.g., '14.1Exp')
|
||||
'msvc_verstr', # msvc version numeric string (e.g., '14.1')
|
||||
'msvc_suffix', # msvc version component type (e.g., 'Exp')
|
||||
'msvc_suffix_rank', # msvc version component rank (0, 1)
|
||||
'msvc_vernum', # msvc version floating point number (e.g, 14.1)
|
||||
'msvc_major', # msvc major version integer number (e.g., 14)
|
||||
'msvc_minor', # msvc minor version integer number (e.g., 1)
|
||||
'msvc_comps', # msvc version components tuple (e.g., ('14', '1'))
|
||||
'msvc_buildtools', # msvc build tools
|
||||
'msvc_buildtools_num', # msvc build tools integer number
|
||||
'msvc_buildseries', # msvc build series
|
||||
'msvc_buildseries_num', # msvc build series floating point number
|
||||
'msvc_toolset_version', # msvc toolset version
|
||||
'msvc_toolset_comps', # msvc toolset version components
|
||||
'msvc_toolset_is_sxs', # msvc toolset version is sxs
|
||||
'version', # msvc version or msvc toolset version
|
||||
])
|
||||
|
||||
def msvc_extended_version_components(version):
|
||||
"""
|
||||
Decompose an msvc version or msvc toolset version into components.
|
||||
|
||||
Args:
|
||||
version: str
|
||||
version specification
|
||||
|
||||
Returns:
|
||||
None or MSVCExtendedVersionComponents namedtuple:
|
||||
"""
|
||||
|
||||
if not version:
|
||||
return None
|
||||
|
||||
m = re_extended_version.match(version)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
msvc_toolset_version = m.group('version')
|
||||
msvc_toolset_comps = tuple(msvc_toolset_version.split('.'))
|
||||
msvc_toolset_is_sxs = is_toolset_sxs(msvc_toolset_version)
|
||||
|
||||
vc_verstr = get_msvc_version_prefix(msvc_toolset_version)
|
||||
if not vc_verstr:
|
||||
return None
|
||||
|
||||
vc_buildseries_def = Config.MSVC_BUILDSERIES_EXTERNAL.get(vc_verstr)
|
||||
if not vc_buildseries_def:
|
||||
return None
|
||||
|
||||
vc_buildtools_def = Config.VC_BUILDTOOLS_MAP[vc_buildseries_def.vc_buildseries]
|
||||
|
||||
msvc_verstr = vc_buildtools_def.msvc_version
|
||||
msvc_suffix = m.group('suffix') if m.group('suffix') else ''
|
||||
msvc_version = msvc_verstr + msvc_suffix
|
||||
|
||||
vs_def = Config.MSVC_VERSION_SUFFIX.get(msvc_version)
|
||||
if not vs_def:
|
||||
return None
|
||||
|
||||
msvc_vernum = float(msvc_verstr)
|
||||
|
||||
msvc_comps = tuple(msvc_verstr.split('.'))
|
||||
msvc_major, msvc_minor = (int(x) for x in msvc_comps)
|
||||
|
||||
msvc_extended_version_components_def = _MSVC_EXTENDED_VERSION_COMPONENTS_DEFINITION(
|
||||
msvc_version = msvc_version,
|
||||
msvc_verstr = msvc_verstr,
|
||||
msvc_suffix = msvc_suffix,
|
||||
msvc_suffix_rank = 0 if not msvc_suffix else 1,
|
||||
msvc_vernum = msvc_vernum,
|
||||
msvc_major = msvc_major,
|
||||
msvc_minor = msvc_minor,
|
||||
msvc_comps = msvc_comps,
|
||||
msvc_buildtools = vc_buildtools_def.msvc_version,
|
||||
msvc_buildtools_num = vc_buildtools_def.msvc_version_numeric,
|
||||
msvc_buildseries = vc_buildseries_def.vc_version,
|
||||
msvc_buildseries_num = vc_buildseries_def.vc_version_numeric,
|
||||
msvc_toolset_version = msvc_toolset_version,
|
||||
msvc_toolset_comps = msvc_toolset_comps,
|
||||
msvc_toolset_is_sxs = msvc_toolset_is_sxs,
|
||||
version = version,
|
||||
)
|
||||
|
||||
return msvc_extended_version_components_def
|
||||
|
||||
# msvc sdk version decomposition utilties
|
||||
|
||||
_MSVC_SDK_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCSDKVersionComponentsDefinition', [
|
||||
'sdk_version', # sdk version (e.g., '10.0.20348.0')
|
||||
'sdk_verstr', # sdk version numeric string (e.g., '10.0')
|
||||
'sdk_vernum', # sdk version floating point number (e.g, 10.0)
|
||||
'sdk_major', # sdk major version integer number (e.g., 10)
|
||||
'sdk_minor', # sdk minor version integer number (e.g., 0)
|
||||
'sdk_comps', # sdk version components tuple (e.g., ('10', '0', '20348', '0'))
|
||||
])
|
||||
|
||||
def msvc_sdk_version_components(version):
|
||||
"""
|
||||
Decompose an msvc sdk version into components.
|
||||
|
||||
Tuple fields:
|
||||
sdk_version: sdk version (e.g., '10.0.20348.0')
|
||||
sdk_verstr: sdk version numeric string (e.g., '10.0')
|
||||
sdk_vernum: sdk version floating point number (e.g., 10.0)
|
||||
sdk_major: sdk major version integer number (e.g., 10)
|
||||
sdk_minor: sdk minor version integer number (e.g., 0)
|
||||
sdk_comps: sdk version components tuple (e.g., ('10', '0', '20348', '0'))
|
||||
|
||||
Args:
|
||||
version: str
|
||||
sdk version specification
|
||||
|
||||
Returns:
|
||||
None or MSVCSDKVersionComponents namedtuple:
|
||||
"""
|
||||
|
||||
if not version:
|
||||
return None
|
||||
|
||||
m = re_msvc_sdk_version.match(version)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
sdk_version = version
|
||||
sdk_comps = tuple(sdk_version.split('.'))
|
||||
sdk_verstr = '.'.join(sdk_comps[:2])
|
||||
sdk_vernum = float(sdk_verstr)
|
||||
|
||||
sdk_major, sdk_minor = (int(x) for x in sdk_comps[:2])
|
||||
|
||||
msvc_sdk_version_components_def = _MSVC_SDK_VERSION_COMPONENTS_DEFINITION(
|
||||
sdk_version = sdk_version,
|
||||
sdk_verstr = sdk_verstr,
|
||||
sdk_vernum = sdk_vernum,
|
||||
sdk_major = sdk_major,
|
||||
sdk_minor = sdk_minor,
|
||||
sdk_comps = sdk_comps,
|
||||
)
|
||||
|
||||
return msvc_sdk_version_components_def
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Warnings for Microsoft Visual C/C++.
|
||||
"""
|
||||
|
||||
import SCons.Warnings
|
||||
|
||||
class VisualCWarning(SCons.Warnings.WarningOnByDefault):
|
||||
pass
|
||||
|
||||
class MSVCScriptExecutionWarning(VisualCWarning):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
# 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 Util
|
||||
from . import Config
|
||||
from . import Registry
|
||||
|
||||
from .Exceptions import (
|
||||
MSVCInternalError,
|
||||
)
|
||||
|
||||
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.vc_platform: [],
|
||||
_UWP.vc_platform: [],
|
||||
}
|
||||
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.normalize_path(os.path.join(version_nbr_path, 'um'))
|
||||
if not os.path.exists(sdk_inc_path):
|
||||
continue
|
||||
|
||||
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, vc_platform)
|
||||
if key in sdk_version_platform_seen:
|
||||
continue
|
||||
sdk_version_platform_seen.add(key)
|
||||
|
||||
sdk_map[vc_platform].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.normalize_path(os.path.join(sdk_root, r'include\um'))
|
||||
if not os.path.exists(sdk_inc_path):
|
||||
continue
|
||||
|
||||
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, vc_platform)
|
||||
if key in sdk_version_platform_seen:
|
||||
continue
|
||||
sdk_version_platform_seen.add(key)
|
||||
|
||||
sdk_map[vc_platform].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():
|
||||
global _sdk_map_cache
|
||||
global _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 = f'sdk version {sdk_version} not in sdk_dispatch_map'
|
||||
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_msvc_platform(is_uwp=False):
|
||||
platform_def = _UWP if is_uwp else _DESKTOP
|
||||
return platform_def
|
||||
|
||||
def get_sdk_version_list(vs_def, platform_def):
|
||||
version_list = vs_def.vc_sdk_versions if vs_def.vc_sdk_versions is not None else []
|
||||
sdk_map = _sdk_map(version_list)
|
||||
sdk_list = sdk_map.get(platform_def.vc_platform, [])
|
||||
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_msvc_version_prefix(msvc_version)
|
||||
if not verstr:
|
||||
debug('msvc_version is not defined')
|
||||
return sdk_versions
|
||||
|
||||
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_def = get_msvc_platform(is_uwp)
|
||||
sdk_list = get_sdk_version_list(vs_def, platform_def)
|
||||
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# 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++.
|
||||
|
||||
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
|
||||
|
||||
from . import Config # noqa: F401
|
||||
from . import Util # noqa: F401
|
||||
from . import Registry # noqa: F401
|
||||
from . import Kind # noqa: F401
|
||||
from . import SetupEnvDefault # noqa: F401
|
||||
from . import Policy # noqa: F401
|
||||
from . import WinSDK # noqa: F401
|
||||
from . import ScriptArguments # noqa: F401
|
||||
|
||||
from . import Dispatcher as _Dispatcher
|
||||
|
||||
def _reset():
|
||||
_Dispatcher.reset()
|
||||
|
||||
def _verify():
|
||||
_Dispatcher.verify()
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Common functions for Microsoft Visual Studio and Visual C/C++.
|
||||
"""
|
||||
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Platform.win32
|
||||
import SCons.Util # noqa: F401
|
||||
|
||||
from SCons.Tool.MSCommon.sdk import ( # noqa: F401
|
||||
mssdk_exists,
|
||||
mssdk_setup_env,
|
||||
)
|
||||
|
||||
from SCons.Tool.MSCommon.vc import ( # noqa: F401
|
||||
msvc_exists,
|
||||
msvc_setup_env_tool,
|
||||
msvc_setup_env_once,
|
||||
msvc_version_to_maj_min,
|
||||
msvc_find_vswhere,
|
||||
msvc_sdk_versions,
|
||||
msvc_toolset_versions,
|
||||
msvc_toolset_versions_spectre,
|
||||
msvc_query_version_toolset,
|
||||
vswhere_register_executable,
|
||||
vswhere_get_executable,
|
||||
vswhere_freeze_executable,
|
||||
)
|
||||
|
||||
from SCons.Tool.MSCommon.vs import ( # noqa: F401
|
||||
get_default_version,
|
||||
get_vs_by_version,
|
||||
merge_default_version,
|
||||
msvs_exists,
|
||||
query_versions,
|
||||
)
|
||||
|
||||
from .MSVC.Policy import ( # noqa: F401
|
||||
msvc_set_notfound_policy,
|
||||
msvc_get_notfound_policy,
|
||||
msvc_set_scripterror_policy,
|
||||
msvc_get_scripterror_policy,
|
||||
msvc_notfound_policy_contextmanager,
|
||||
msvc_scripterror_policy_contextmanager,
|
||||
)
|
||||
|
||||
from .MSVC.Exceptions import ( # noqa: F401
|
||||
VisualCException,
|
||||
MSVCInternalError,
|
||||
MSVCUserError,
|
||||
MSVCScriptExecutionError,
|
||||
MSVCVersionNotFound,
|
||||
MSVCSDKVersionNotFound,
|
||||
MSVCToolsetVersionNotFound,
|
||||
MSVCSpectreLibsNotFound,
|
||||
MSVCArgumentError,
|
||||
)
|
||||
|
||||
from .vc import ( # noqa: F401
|
||||
MSVCUnsupportedHostArch,
|
||||
MSVCUnsupportedTargetArch,
|
||||
MSVCScriptNotFound,
|
||||
MSVCUseScriptError,
|
||||
MSVCUseSettingsError,
|
||||
VSWhereUserError,
|
||||
)
|
||||
|
||||
from .MSVC.Util import ( # noqa: F401
|
||||
msvc_version_components,
|
||||
msvc_extended_version_components,
|
||||
msvc_sdk_version_components,
|
||||
)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,66 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
MS compilers: Supported Windows chip architectures.
|
||||
"""
|
||||
|
||||
|
||||
class ArchDefinition:
|
||||
"""
|
||||
A class for defining architecture-specific settings and logic.
|
||||
"""
|
||||
def __init__(self, arch, synonyms=[]):
|
||||
self.arch = arch
|
||||
self.synonyms = synonyms
|
||||
|
||||
SupportedArchitectureList = [
|
||||
ArchDefinition(
|
||||
'x86',
|
||||
['i386', 'i486', 'i586', 'i686'],
|
||||
),
|
||||
ArchDefinition(
|
||||
'x86_64',
|
||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||
),
|
||||
ArchDefinition(
|
||||
'ia64',
|
||||
['IA64'],
|
||||
),
|
||||
ArchDefinition(
|
||||
'arm',
|
||||
['ARM'],
|
||||
),
|
||||
]
|
||||
|
||||
SupportedArchitectureMap = {}
|
||||
for a in SupportedArchitectureList:
|
||||
SupportedArchitectureMap[a.arch] = a
|
||||
for s in a.synonyms:
|
||||
SupportedArchitectureMap[s] = a
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,635 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Common helper functions for working with the Microsoft tool chain.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from contextlib import suppress
|
||||
from subprocess import DEVNULL, PIPE
|
||||
from pathlib import Path
|
||||
|
||||
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
|
||||
|
||||
def _check_logfile(logfile):
|
||||
if logfile and '"' in logfile:
|
||||
err_msg = (
|
||||
"SCONS_MSCOMMON_DEBUG value contains double quote character(s)\n"
|
||||
f" SCONS_MSCOMMON_DEBUG={logfile}"
|
||||
)
|
||||
raise SCons.Errors.UserError(err_msg)
|
||||
return logfile
|
||||
|
||||
# SCONS_MSCOMMON_DEBUG is internal-use so undocumented:
|
||||
# set to '-' to print to console, else set to filename to log to
|
||||
LOGFILE = _check_logfile(os.environ.get('SCONS_MSCOMMON_DEBUG'))
|
||||
if LOGFILE:
|
||||
import logging
|
||||
|
||||
class _Debug_Filter(logging.Filter):
|
||||
# custom filter for module relative filename
|
||||
|
||||
modulelist = (
|
||||
# root module and parent/root module
|
||||
'MSCommon', 'Tool',
|
||||
# python library and below: correct iff scons does not have a lib folder
|
||||
'lib',
|
||||
# scons modules
|
||||
'SCons', 'test', 'scons'
|
||||
)
|
||||
|
||||
def get_relative_filename(self, filename, module_list):
|
||||
if not filename:
|
||||
return filename
|
||||
for module in module_list:
|
||||
try:
|
||||
ind = filename.rindex(module)
|
||||
return filename[ind:]
|
||||
except ValueError:
|
||||
pass
|
||||
return filename
|
||||
|
||||
def filter(self, record):
|
||||
relfilename = self.get_relative_filename(record.pathname, self.modulelist)
|
||||
relfilename = relfilename.replace('\\', '/')
|
||||
record.relfilename = relfilename
|
||||
return True
|
||||
|
||||
class _CustomFormatter(logging.Formatter):
|
||||
|
||||
# Log format looks like:
|
||||
# 00109ms:MSCommon/vc.py:find_vc_pdir#447: VC found '14.3' [file]
|
||||
# debug: 00109ms:MSCommon/vc.py:find_vc_pdir#447: VC found '14.3' [stdout]
|
||||
|
||||
log_format=(
|
||||
'%(relativeCreated)05dms'
|
||||
':%(relfilename)s'
|
||||
':%(funcName)s'
|
||||
'#%(lineno)s'
|
||||
': %(message)s'
|
||||
)
|
||||
|
||||
log_format_classname=(
|
||||
'%(relativeCreated)05dms'
|
||||
':%(relfilename)s'
|
||||
':%(classname)s'
|
||||
'.%(funcName)s'
|
||||
'#%(lineno)s'
|
||||
': %(message)s'
|
||||
)
|
||||
|
||||
def __init__(self, log_prefix):
|
||||
super().__init__()
|
||||
if log_prefix:
|
||||
self.log_format = log_prefix + self.log_format
|
||||
self.log_format_classname = log_prefix + self.log_format_classname
|
||||
log_record = logging.LogRecord(
|
||||
'', # name (str)
|
||||
0, # level (int)
|
||||
'', # pathname (str)
|
||||
0, # lineno (int)
|
||||
None, # msg (Any)
|
||||
{}, # args (tuple | dict[str, Any])
|
||||
None # exc_info (tuple[type[BaseException], BaseException, types.TracebackType] | None)
|
||||
)
|
||||
self.default_attrs = set(log_record.__dict__.keys())
|
||||
self.default_attrs.add('relfilename')
|
||||
|
||||
def format(self, record):
|
||||
extras = set(record.__dict__.keys()) - self.default_attrs
|
||||
if 'classname' in extras:
|
||||
log_format = self.log_format_classname
|
||||
else:
|
||||
log_format = self.log_format
|
||||
formatter = logging.Formatter(log_format)
|
||||
return formatter.format(record)
|
||||
|
||||
if LOGFILE == '-':
|
||||
log_prefix = 'debug: '
|
||||
log_handler = logging.StreamHandler(sys.stdout)
|
||||
else:
|
||||
log_prefix = ''
|
||||
try:
|
||||
log_handler = logging.FileHandler(filename=LOGFILE)
|
||||
except (OSError, FileNotFoundError) as e:
|
||||
err_msg = (
|
||||
"Could not create logfile, check SCONS_MSCOMMON_DEBUG\n"
|
||||
f" SCONS_MSCOMMON_DEBUG={LOGFILE}\n"
|
||||
f" {e.__class__.__name__}: {str(e)}"
|
||||
)
|
||||
raise SCons.Errors.UserError(err_msg)
|
||||
log_formatter = _CustomFormatter(log_prefix)
|
||||
log_handler.setFormatter(log_formatter)
|
||||
logger = logging.getLogger(name=__name__)
|
||||
logger.setLevel(level=logging.DEBUG)
|
||||
logger.addHandler(log_handler)
|
||||
logger.addFilter(_Debug_Filter())
|
||||
debug = logger.debug
|
||||
|
||||
def debug_extra(cls=None):
|
||||
if cls:
|
||||
extra = {'classname': cls.__qualname__}
|
||||
else:
|
||||
extra = None
|
||||
return extra
|
||||
|
||||
DEBUG_ENABLED = True
|
||||
|
||||
else:
|
||||
def debug(x, *args, **kwargs):
|
||||
return None
|
||||
|
||||
def debug_extra(*args, **kwargs):
|
||||
return None
|
||||
|
||||
DEBUG_ENABLED = False
|
||||
|
||||
# SCONS_CACHE_MSVC_CONFIG is public, and is documented.
|
||||
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 """
|
||||
envcache = {}
|
||||
p = Path(CONFIG_CACHE)
|
||||
if not CONFIG_CACHE or not p.is_file():
|
||||
return envcache
|
||||
with SCons.Util.FileLock(CONFIG_CACHE, timeout=5, writer=False), p.open('r') as f:
|
||||
# Convert the list of cache entry dictionaries read from
|
||||
# json to the cache dictionary. Reconstruct the cache key
|
||||
# tuple from the key list written to json.
|
||||
# Note we need to take a write lock on the cachefile, as if there's
|
||||
# an error and we try to remove it, that's "writing" on Windows.
|
||||
try:
|
||||
envcache_list = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
# If we couldn't decode it, it could be corrupt. Toss.
|
||||
with suppress(FileNotFoundError):
|
||||
p.unlink()
|
||||
warn_msg = "Could not decode msvc cache file %s: dropping."
|
||||
SCons.Warnings.warn(MSVCCacheInvalidWarning, warn_msg % CONFIG_CACHE)
|
||||
debug(warn_msg, CONFIG_CACHE)
|
||||
else:
|
||||
if isinstance(envcache_list, list):
|
||||
envcache = {tuple(d['key']): d['data'] for d in envcache_list}
|
||||
else:
|
||||
# don't fail if incompatible format, just proceed without it
|
||||
warn_msg = "Incompatible format for msvc cache file %s: file may be overwritten."
|
||||
SCons.Warnings.warn(MSVCCacheInvalidWarning, warn_msg % CONFIG_CACHE)
|
||||
debug(warn_msg, CONFIG_CACHE)
|
||||
|
||||
return envcache
|
||||
|
||||
|
||||
def write_script_env_cache(cache):
|
||||
""" write out cache of msvc env vars if requested """
|
||||
if not CONFIG_CACHE:
|
||||
return
|
||||
|
||||
p = Path(CONFIG_CACHE)
|
||||
try:
|
||||
with SCons.Util.FileLock(CONFIG_CACHE, timeout=5, writer=True), p.open('w') as f:
|
||||
# Convert the cache dictionary to a list of cache entry
|
||||
# dictionaries. The cache key is converted from a tuple to
|
||||
# a list for compatibility with json.
|
||||
envcache_list = [
|
||||
{'key': list(key), 'data': data} for key, data in cache.items()
|
||||
]
|
||||
json.dump(envcache_list, f, indent=2)
|
||||
except TypeError:
|
||||
# data can't serialize to json, don't leave partial file
|
||||
with suppress(FileNotFoundError):
|
||||
p.unlink()
|
||||
except OSError:
|
||||
# can't write the file, just skip
|
||||
pass
|
||||
|
||||
return
|
||||
|
||||
|
||||
_is_win64 = None
|
||||
|
||||
|
||||
def is_win64():
|
||||
"""Return true if running on windows 64 bits.
|
||||
|
||||
Works whether python itself runs in 64 bits or 32 bits."""
|
||||
# Unfortunately, python does not provide a useful way to determine
|
||||
# if the underlying Windows OS is 32-bit or 64-bit. Worse, whether
|
||||
# the Python itself is 32-bit or 64-bit affects what it returns,
|
||||
# so nothing in sys.* or os.* help.
|
||||
|
||||
# Apparently the best solution is to use env vars that Windows
|
||||
# sets. If PROCESSOR_ARCHITECTURE is not x86, then the python
|
||||
# process is running in 64 bit mode (on a 64-bit OS, 64-bit
|
||||
# hardware, obviously).
|
||||
# If this python is 32-bit but the OS is 64, Windows will set
|
||||
# ProgramW6432 and PROCESSOR_ARCHITEW6432 to non-null.
|
||||
# (Checking for HKLM\Software\Wow6432Node in the registry doesn't
|
||||
# work, because some 32-bit installers create it.)
|
||||
global _is_win64
|
||||
if _is_win64 is None:
|
||||
# I structured these tests to make it easy to add new ones or
|
||||
# add exceptions in the future, because this is a bit fragile.
|
||||
_is_win64 = False
|
||||
if os.environ.get('PROCESSOR_ARCHITECTURE', 'x86') != 'x86':
|
||||
_is_win64 = True
|
||||
if os.environ.get('PROCESSOR_ARCHITEW6432'):
|
||||
_is_win64 = True
|
||||
if os.environ.get('ProgramW6432'):
|
||||
_is_win64 = True
|
||||
return _is_win64
|
||||
|
||||
|
||||
def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE):
|
||||
return SCons.Util.RegGetValue(hkroot, value)[0]
|
||||
|
||||
|
||||
def has_reg(value):
|
||||
"""Return True if the given key exists in HKEY_LOCAL_MACHINE."""
|
||||
try:
|
||||
SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value)
|
||||
ret = True
|
||||
except OSError:
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
# Functions for fetching environment variable settings from batch files.
|
||||
|
||||
|
||||
def _force_vscmd_skip_sendtelemetry(env):
|
||||
|
||||
if 'VSCMD_SKIP_SENDTELEMETRY' in env['ENV']:
|
||||
return False
|
||||
|
||||
env['ENV']['VSCMD_SKIP_SENDTELEMETRY'] = '1'
|
||||
debug("force env['ENV']['VSCMD_SKIP_SENDTELEMETRY']=%s", env['ENV']['VSCMD_SKIP_SENDTELEMETRY'])
|
||||
|
||||
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=False):
|
||||
"""Given a dictionary representing a shell environment, add the variables
|
||||
from os.environ needed for the processing of .bat files; the keys are
|
||||
controlled by the keys argument.
|
||||
|
||||
It also makes sure the environment values are correctly encoded.
|
||||
|
||||
If force=True, then all of the key values that exist are copied
|
||||
into the returned dictionary. If force=false, values are only
|
||||
copied if the key does not already exist in the copied dictionary.
|
||||
|
||||
Note: the environment is copied."""
|
||||
normenv = {}
|
||||
if env:
|
||||
for k, v in env.items():
|
||||
normenv[k] = copy.deepcopy(v)
|
||||
|
||||
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
|
||||
# should include it, but keep this here to be safe (needed for reg.exe)
|
||||
sys32_dir = os.path.join(
|
||||
os.environ.get("SystemRoot", os.environ.get("windir", r"C:\Windows")), "System32"
|
||||
)
|
||||
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')
|
||||
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.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
def get_output(vcbat, args=None, env=None, skip_sendtelemetry=False):
|
||||
"""Parse the output of given bat file, with given args."""
|
||||
|
||||
if env is None:
|
||||
# Create a blank environment, for use in launching the tools
|
||||
env = SCons.Environment.Environment(tools=[])
|
||||
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
|
||||
# Ongoing problems getting non-corrupted text led to this
|
||||
# changing to "oem" from "mbcs" - the scripts run presumably
|
||||
# attached to a console, so some particular rules apply.
|
||||
OEM = "oem"
|
||||
if cp.stderr:
|
||||
# TODO: find something better to do with stderr;
|
||||
# this at least prevents errors from getting swallowed.
|
||||
sys.stderr.write(cp.stderr.decode(OEM))
|
||||
if cp.returncode != 0:
|
||||
raise OSError(cp.stderr.decode(OEM))
|
||||
|
||||
return cp.stdout.decode(OEM)
|
||||
|
||||
|
||||
KEEPLIST = (
|
||||
"INCLUDE",
|
||||
"LIB",
|
||||
"LIBPATH",
|
||||
"PATH",
|
||||
"VSCMD_ARG_app_plat",
|
||||
"VCINSTALLDIR", # needed by clang -VS 2017 and newer
|
||||
"VCToolsInstallDir", # needed by clang - VS 2015 and older
|
||||
)
|
||||
# Nuitka: Keep the Windows SDK version too
|
||||
KEEPLIST += ("WindowsSDKVersion",)
|
||||
|
||||
|
||||
|
||||
def parse_output(output, keep=KEEPLIST):
|
||||
"""
|
||||
Parse output from running visual c++/studios vcvarsall.bat and running set
|
||||
To capture the values listed in keep
|
||||
"""
|
||||
|
||||
# dkeep is a dict associating key: path_list, where key is one item from
|
||||
# keep, and path_list the associated list of paths
|
||||
dkeep = {i: [] for i in keep}
|
||||
|
||||
# rdk will keep the regex to match the .bat file output line starts
|
||||
rdk = {}
|
||||
for i in keep:
|
||||
rdk[i] = re.compile(r'%s=(.*)' % i, re.I)
|
||||
|
||||
def add_env(rmatch, key, dkeep=dkeep):
|
||||
path_list = rmatch.group(1).split(os.pathsep)
|
||||
for path in path_list:
|
||||
# Do not add empty paths (when a var ends with ;)
|
||||
if path:
|
||||
# XXX: For some reason, VC98 .bat file adds "" around the PATH
|
||||
# values, and it screws up the environment later, so we strip
|
||||
# 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():
|
||||
match = value.match(line)
|
||||
if match:
|
||||
add_env(match, k)
|
||||
|
||||
return dkeep
|
||||
|
||||
def get_pch_node(env, target, source):
|
||||
"""
|
||||
Get the actual PCH file node
|
||||
"""
|
||||
pch_subst = env.get('PCH', False) and env.subst('$PCH',target=target, source=source, conv=lambda x:x)
|
||||
|
||||
if not pch_subst:
|
||||
return ""
|
||||
|
||||
if SCons.Util.is_String(pch_subst):
|
||||
pch_subst = target[0].dir.File(pch_subst)
|
||||
|
||||
return pch_subst
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,82 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
MS Compilers: .Net Framework support
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from .common import read_reg, debug
|
||||
|
||||
# Original value recorded by dcournapeau
|
||||
_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot'
|
||||
# On SGK's system
|
||||
_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder'
|
||||
|
||||
def find_framework_root():
|
||||
# XXX: find it from environment (FrameworkDir)
|
||||
try:
|
||||
froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT)
|
||||
debug("Found framework install root in registry: %s", froot)
|
||||
except OSError:
|
||||
debug("Could not read reg key %s", _FRAMEWORKDIR_HKEY_ROOT)
|
||||
return None
|
||||
|
||||
if not os.path.exists(froot):
|
||||
debug("%s not found on fs", froot)
|
||||
return None
|
||||
|
||||
return froot
|
||||
|
||||
def query_versions():
|
||||
froot = find_framework_root()
|
||||
if froot:
|
||||
contents = os.listdir(froot)
|
||||
|
||||
l = re.compile('v[0-9]+.*')
|
||||
versions = [e for e in contents if l.match(e)]
|
||||
|
||||
def versrt(a,b):
|
||||
# since version numbers aren't really floats...
|
||||
aa = a[1:]
|
||||
bb = b[1:]
|
||||
aal = aa.split('.')
|
||||
bbl = bb.split('.')
|
||||
# sequence comparison in python is lexicographical
|
||||
# which is exactly what we want.
|
||||
# Note we sort backwards so the highest version is first.
|
||||
return (aal > bbl) - (aal < bbl)
|
||||
|
||||
versions.sort(versrt)
|
||||
else:
|
||||
versions = []
|
||||
|
||||
return versions
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,412 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
MS Compilers: detect the Platform/Windows SDK
|
||||
|
||||
PSDK 2003 R1 is the earliest version detected.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
|
||||
from .common import debug, read_reg
|
||||
|
||||
# SDK Checks. This is of course a mess as everything else on MS platforms. Here
|
||||
# is what we do to detect the SDK:
|
||||
#
|
||||
# For Windows SDK >= 6.0: just look into the registry entries:
|
||||
# HKLM\Software\Microsoft\Microsoft SDKs\Windows
|
||||
# All the keys in there are the available versions.
|
||||
#
|
||||
# For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not
|
||||
# seem to be any sane registry key, so the precise location is hardcoded.
|
||||
#
|
||||
# For versions below 2003R1, it seems the PSDK is included with Visual Studio?
|
||||
# VC++ Professional comes with the SDK, VC++ Express does not.
|
||||
#
|
||||
# Of course, all this changed again after Express was phased out (2005).
|
||||
|
||||
# Location of the SDK (checked for 6.1 only)
|
||||
_CURINSTALLED_SDK_HKEY_ROOT = \
|
||||
r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
|
||||
|
||||
|
||||
class SDKDefinition:
|
||||
"""
|
||||
An abstract base class for trying to find installed SDK directories.
|
||||
"""
|
||||
def __init__(self, version, **kw):
|
||||
self.version = version
|
||||
self.__dict__.update(kw)
|
||||
|
||||
def find_sdk_dir(self):
|
||||
"""Try to find the MS SDK from the registry.
|
||||
|
||||
Return None if failed or the directory does not exist.
|
||||
"""
|
||||
if not SCons.Util.can_read_reg:
|
||||
debug('find_sdk_dir(): can not read registry')
|
||||
return None
|
||||
|
||||
hkey = self.HKEY_FMT % self.hkey_data
|
||||
debug('find_sdk_dir(): checking registry: %s', hkey)
|
||||
|
||||
try:
|
||||
sdk_dir = read_reg(hkey)
|
||||
except OSError:
|
||||
debug('find_sdk_dir(): no SDK registry key %s', hkey)
|
||||
return None
|
||||
|
||||
debug('find_sdk_dir(): Trying SDK Dir: %s', sdk_dir)
|
||||
|
||||
if not os.path.exists(sdk_dir):
|
||||
debug('find_sdk_dir(): %s not on file system', sdk_dir)
|
||||
return None
|
||||
|
||||
ftc = os.path.join(sdk_dir, self.sanity_check_file)
|
||||
if not os.path.exists(ftc):
|
||||
debug("find_sdk_dir(): sanity check %s not found", ftc)
|
||||
return None
|
||||
|
||||
return sdk_dir
|
||||
|
||||
def get_sdk_dir(self):
|
||||
"""Return the MSSSDK given the version string."""
|
||||
try:
|
||||
return self._sdk_dir
|
||||
except AttributeError:
|
||||
sdk_dir = self.find_sdk_dir()
|
||||
self._sdk_dir = sdk_dir
|
||||
return sdk_dir
|
||||
|
||||
def get_sdk_vc_script(self,host_arch, target_arch):
|
||||
""" Return the script to initialize the VC compiler installed by SDK
|
||||
"""
|
||||
|
||||
if host_arch == 'amd64' and target_arch == 'x86':
|
||||
# No cross tools needed compiling 32 bits on 64 bit machine
|
||||
host_arch=target_arch
|
||||
|
||||
arch_string=target_arch
|
||||
if host_arch != target_arch:
|
||||
arch_string='%s_%s'%(host_arch,target_arch)
|
||||
|
||||
debug(
|
||||
"get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s",
|
||||
arch_string,
|
||||
host_arch,
|
||||
target_arch,
|
||||
)
|
||||
file = self.vc_setup_scripts.get(arch_string, None)
|
||||
debug("get_sdk_vc_script():file:%s", file)
|
||||
return file
|
||||
|
||||
class WindowsSDK(SDKDefinition):
|
||||
"""
|
||||
A subclass for trying to find installed Windows SDK directories.
|
||||
"""
|
||||
HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder'
|
||||
def __init__(self, *args, **kw):
|
||||
super().__init__(*args, **kw)
|
||||
self.hkey_data = self.version
|
||||
|
||||
class PlatformSDK(SDKDefinition):
|
||||
"""
|
||||
A subclass for trying to find installed Platform SDK directories.
|
||||
"""
|
||||
HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir'
|
||||
def __init__(self, *args, **kw):
|
||||
super().__init__(*args, **kw)
|
||||
self.hkey_data = self.uuid
|
||||
|
||||
#
|
||||
# The list of VC initialization scripts installed by the SDK
|
||||
# These should be tried if the vcvarsall.bat TARGET_ARCH fails
|
||||
preSDK61VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvarsamd64.bat',
|
||||
'x86_amd64': r'bin\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\vcvarsia64.bat'}
|
||||
|
||||
SDK61VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\amd64\vcvarsamd64.bat',
|
||||
'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\x86_ia64\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\ia64\vcvarsia64.bat'}
|
||||
|
||||
SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvars64.bat',
|
||||
'x86_amd64': r'bin\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\vcvarsia64.bat'}
|
||||
|
||||
SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvars64.bat',
|
||||
'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
|
||||
'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'}
|
||||
|
||||
|
||||
# The list of support SDKs which we know how to detect.
|
||||
#
|
||||
# The first SDK found in the list is the one used by default if there
|
||||
# are multiple SDKs installed. Barring good reasons to the contrary,
|
||||
# this means we should list SDKs from most recent to oldest.
|
||||
#
|
||||
# If you update this list, update the documentation in Tool/mssdk.xml.
|
||||
SupportedSDKList = [
|
||||
WindowsSDK('10.0A',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('10.0',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.1',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.0A',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.0',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('6.1',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
WindowsSDK('6.0A',
|
||||
sanity_check_file=r'include\windows.h',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
WindowsSDK('6.0',
|
||||
sanity_check_file=r'bin\gacutil.exe',
|
||||
include_subdir='include',
|
||||
lib_subdir='lib',
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
PlatformSDK('2003R2',
|
||||
sanity_check_file=r'SetEnv.Cmd',
|
||||
uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1",
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
PlatformSDK('2003R1',
|
||||
sanity_check_file=r'SetEnv.Cmd',
|
||||
uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3",
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
]
|
||||
|
||||
SupportedSDKMap = {}
|
||||
for sdk in SupportedSDKList:
|
||||
SupportedSDKMap[sdk.version] = sdk
|
||||
|
||||
|
||||
# Finding installed SDKs isn't cheap, because it goes not only to the
|
||||
# registry but also to the disk to sanity-check that there is, in fact,
|
||||
# an SDK installed there and that the registry entry isn't just stale.
|
||||
# Find this information once, when requested, and cache it.
|
||||
|
||||
InstalledSDKList = None
|
||||
InstalledSDKMap = None
|
||||
|
||||
def get_installed_sdks():
|
||||
global InstalledSDKList
|
||||
global InstalledSDKMap
|
||||
debug('get_installed_sdks()')
|
||||
if InstalledSDKList is None:
|
||||
InstalledSDKList = []
|
||||
InstalledSDKMap = {}
|
||||
for sdk in SupportedSDKList:
|
||||
debug('trying to find SDK %s', sdk.version)
|
||||
if sdk.get_sdk_dir():
|
||||
debug('found SDK %s', sdk.version)
|
||||
InstalledSDKList.append(sdk)
|
||||
InstalledSDKMap[sdk.version] = sdk
|
||||
return InstalledSDKList
|
||||
|
||||
|
||||
# We may be asked to update multiple construction environments with
|
||||
# SDK information. When doing this, we check on-disk for whether
|
||||
# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
|
||||
# is expensive, cache results by directory.
|
||||
|
||||
SDKEnvironmentUpdates = {}
|
||||
|
||||
def set_sdk_by_directory(env, sdk_dir):
|
||||
global SDKEnvironmentUpdates
|
||||
debug('set_sdk_by_directory: Using dir:%s', sdk_dir)
|
||||
try:
|
||||
env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
|
||||
except KeyError:
|
||||
env_tuple_list = []
|
||||
SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
|
||||
|
||||
include_path = os.path.join(sdk_dir, 'include')
|
||||
mfc_path = os.path.join(include_path, 'mfc')
|
||||
atl_path = os.path.join(include_path, 'atl')
|
||||
|
||||
if os.path.exists(mfc_path):
|
||||
env_tuple_list.append(('INCLUDE', mfc_path))
|
||||
if os.path.exists(atl_path):
|
||||
env_tuple_list.append(('INCLUDE', atl_path))
|
||||
env_tuple_list.append(('INCLUDE', include_path))
|
||||
|
||||
env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
|
||||
env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
|
||||
env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
|
||||
|
||||
for variable, directory in env_tuple_list:
|
||||
env.PrependENVPath(variable, directory)
|
||||
|
||||
def get_sdk_by_version(mssdk):
|
||||
if mssdk not in SupportedSDKMap:
|
||||
raise SCons.Errors.UserError(f"SDK version {mssdk!r} is not supported")
|
||||
get_installed_sdks()
|
||||
return InstalledSDKMap.get(mssdk)
|
||||
|
||||
def get_default_sdk():
|
||||
"""Set up the default Platform/Windows SDK."""
|
||||
get_installed_sdks()
|
||||
if not InstalledSDKList:
|
||||
return None
|
||||
return InstalledSDKList[0]
|
||||
|
||||
def mssdk_setup_env(env):
|
||||
debug('mssdk_setup_env()')
|
||||
if 'MSSDK_DIR' in env:
|
||||
sdk_dir = env['MSSDK_DIR']
|
||||
if sdk_dir is None:
|
||||
return
|
||||
sdk_dir = env.subst(sdk_dir)
|
||||
debug('mssdk_setup_env: Using MSSDK_DIR:%s', sdk_dir)
|
||||
elif 'MSSDK_VERSION' in env:
|
||||
sdk_version = env['MSSDK_VERSION']
|
||||
if sdk_version is None:
|
||||
msg = "SDK version is specified as None"
|
||||
raise SCons.Errors.UserError(msg)
|
||||
sdk_version = env.subst(sdk_version)
|
||||
mssdk = get_sdk_by_version(sdk_version)
|
||||
if mssdk is None:
|
||||
msg = "SDK version %s is not installed" % sdk_version
|
||||
raise SCons.Errors.UserError(msg)
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: Using MSSDK_VERSION:%s', sdk_dir)
|
||||
elif 'MSVS_VERSION' in env:
|
||||
msvs_version = env['MSVS_VERSION']
|
||||
debug('mssdk_setup_env:Getting MSVS_VERSION from env:%s', msvs_version)
|
||||
if msvs_version is None:
|
||||
debug('mssdk_setup_env thinks msvs_version is None')
|
||||
return
|
||||
msvs_version = env.subst(msvs_version)
|
||||
from . import vs
|
||||
msvs = vs.get_vs_by_version(msvs_version, env)
|
||||
debug('mssdk_setup_env:msvs is :%s', msvs)
|
||||
if not msvs:
|
||||
debug('mssdk_setup_env: no VS version detected, bailingout:%s', msvs)
|
||||
return
|
||||
sdk_version = msvs.sdk_version
|
||||
debug('msvs.sdk_version is %s', sdk_version)
|
||||
if not sdk_version:
|
||||
return
|
||||
mssdk = get_sdk_by_version(sdk_version)
|
||||
if not mssdk:
|
||||
mssdk = get_default_sdk()
|
||||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: Using MSVS_VERSION:%s', sdk_dir)
|
||||
else:
|
||||
mssdk = get_default_sdk()
|
||||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: not using any env values. sdk_dir:%s', sdk_dir)
|
||||
|
||||
set_sdk_by_directory(env, sdk_dir)
|
||||
|
||||
#print "No MSVS_VERSION: this is likely to be a bug"
|
||||
|
||||
def mssdk_exists(version=None):
|
||||
sdks = get_installed_sdks()
|
||||
if version is None:
|
||||
return len(sdks) > 0
|
||||
return version in sdks
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
2843
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/MSCommon/vc.py
Normal file
2843
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/MSCommon/vc.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,647 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
MS Compilers: detect Visual Studio and/or Visual C/C++
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
|
||||
from .common import (
|
||||
debug,
|
||||
get_output,
|
||||
is_win64,
|
||||
normalize_env,
|
||||
parse_output,
|
||||
read_reg,
|
||||
)
|
||||
|
||||
from .vc import (
|
||||
find_vc_pdir,
|
||||
get_msvc_version_numeric,
|
||||
reset_installed_vcs,
|
||||
vswhere_freeze_env,
|
||||
)
|
||||
|
||||
|
||||
# Visual Studio express version policy when unqualified version is not installed:
|
||||
# True: use express version for unqualified version (e.g., use 12.0Exp for 12.0)
|
||||
# False: do not use express version for unqualified version
|
||||
_VSEXPRESS_USE_VERSTR = True
|
||||
|
||||
|
||||
class VisualStudio:
|
||||
"""
|
||||
An abstract base class for trying to find installed versions of
|
||||
Visual Studio.
|
||||
"""
|
||||
def __init__(self, version, **kw):
|
||||
self.version = version
|
||||
self.verstr = get_msvc_version_numeric(version)
|
||||
self.vernum = float(self.verstr)
|
||||
self.is_express = True if self.verstr != self.version else False
|
||||
kw['vc_version'] = kw.get('vc_version', version)
|
||||
kw['sdk_version'] = kw.get('sdk_version', version)
|
||||
self.__dict__.update(kw)
|
||||
self._cache = {}
|
||||
|
||||
def find_batch_file(self):
|
||||
vs_dir = self.get_vs_dir()
|
||||
if not vs_dir:
|
||||
debug('no vs_dir')
|
||||
return None
|
||||
batch_file = os.path.join(vs_dir, self.batch_file_path)
|
||||
batch_file = os.path.normpath(batch_file)
|
||||
if not os.path.isfile(batch_file):
|
||||
debug('%s not on file system', batch_file)
|
||||
return None
|
||||
return batch_file
|
||||
|
||||
def find_vs_dir_by_vc(self, env):
|
||||
dir = find_vc_pdir(self.vc_version, env)
|
||||
if not dir:
|
||||
debug('no installed VC %s', self.vc_version)
|
||||
return None
|
||||
return os.path.abspath(os.path.join(dir, os.pardir))
|
||||
|
||||
def find_vs_dir_by_reg(self, env):
|
||||
root = 'Software\\'
|
||||
|
||||
if is_win64():
|
||||
root = root + 'Wow6432Node\\'
|
||||
for key in self.hkeys:
|
||||
if key=='use_dir':
|
||||
return self.find_vs_dir_by_vc(env)
|
||||
key = root + key
|
||||
try:
|
||||
comps = read_reg(key)
|
||||
except OSError:
|
||||
debug('no VS registry key %s', repr(key))
|
||||
else:
|
||||
debug('found VS in registry: %s', comps)
|
||||
return comps
|
||||
return None
|
||||
|
||||
def find_vs_dir(self, env):
|
||||
""" Can use registry or location of VC to find vs dir
|
||||
First try to find by registry, and if that fails find via VC dir
|
||||
"""
|
||||
|
||||
vs_dir = self.find_vs_dir_by_reg(env)
|
||||
if not vs_dir:
|
||||
vs_dir = self.find_vs_dir_by_vc(env)
|
||||
debug('found VS in %s', str(vs_dir))
|
||||
return vs_dir
|
||||
|
||||
def find_executable(self, env):
|
||||
vs_dir = self.get_vs_dir(env)
|
||||
if not vs_dir:
|
||||
debug('no vs_dir (%s)', vs_dir)
|
||||
return None
|
||||
executable = os.path.join(vs_dir, self.executable_path)
|
||||
executable = os.path.normpath(executable)
|
||||
if not os.path.isfile(executable):
|
||||
debug('%s not on file system', executable)
|
||||
return None
|
||||
return executable
|
||||
|
||||
def get_batch_file(self):
|
||||
try:
|
||||
return self._cache['batch_file']
|
||||
except KeyError:
|
||||
batch_file = self.find_batch_file()
|
||||
self._cache['batch_file'] = batch_file
|
||||
return batch_file
|
||||
|
||||
def get_executable(self, env=None):
|
||||
try:
|
||||
debug('using cache:%s', self._cache['executable'])
|
||||
return self._cache['executable']
|
||||
except KeyError:
|
||||
executable = self.find_executable(env)
|
||||
self._cache['executable'] = executable
|
||||
debug('not in cache:%s', executable)
|
||||
return executable
|
||||
|
||||
def get_vs_dir(self, env=None):
|
||||
try:
|
||||
return self._cache['vs_dir']
|
||||
except KeyError:
|
||||
vs_dir = self.find_vs_dir(env)
|
||||
self._cache['vs_dir'] = vs_dir
|
||||
return vs_dir
|
||||
|
||||
def get_supported_arch(self):
|
||||
try:
|
||||
return self._cache['supported_arch']
|
||||
except KeyError:
|
||||
# RDEVE: for the time being use hardcoded lists
|
||||
# supported_arch = self.find_supported_arch()
|
||||
self._cache['supported_arch'] = self.supported_arch
|
||||
return self.supported_arch
|
||||
|
||||
def reset(self):
|
||||
self._cache = {}
|
||||
|
||||
# The list of supported Visual Studio versions we know how to detect.
|
||||
#
|
||||
# How to look for .bat file ?
|
||||
# - VS 2008 Express (x86):
|
||||
# * from registry key productdir, gives the full path to vsvarsall.bat. In
|
||||
# HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VCEpress\9.0\Setup\VC\productdir
|
||||
# * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC
|
||||
# relatively to the path given by the variable.
|
||||
#
|
||||
# - VS 2008 Express (WoW6432: 32 bits on windows x64):
|
||||
# Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir
|
||||
#
|
||||
# - VS 2005 Express (x86):
|
||||
# * from registry key productdir, gives the full path to vsvarsall.bat. In
|
||||
# HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VCEpress\8.0\Setup\VC\productdir
|
||||
# * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC
|
||||
# relatively to the path given by the variable.
|
||||
#
|
||||
# - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a
|
||||
# productdir ?
|
||||
#
|
||||
# - VS 2003 .Net (pro edition ? x86):
|
||||
# * from registry key productdir. The path is then ..\Common7\Tools\
|
||||
# relatively to the key. The key is in HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir
|
||||
# * from environmnent variable VS71COMNTOOLS: the path is the full path to
|
||||
# vsvars32.bat
|
||||
#
|
||||
# - VS 98 (VS 6):
|
||||
# * from registry key productdir. The path is then Bin
|
||||
# relatively to the key. The key is in HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir
|
||||
#
|
||||
# The first version found in the list is the one used by default if
|
||||
# there are multiple versions installed. Barring good reasons to
|
||||
# the contrary, this means we should list versions from most recent
|
||||
# to oldest. Pro versions get listed before Express versions on the
|
||||
# assumption that, by default, you'd rather use the version you paid
|
||||
# good money for in preference to whatever Microsoft makes available
|
||||
# for free.
|
||||
#
|
||||
# If you update this list, update _VCVER and _VCVER_TO_PRODUCT_DIR in
|
||||
# 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',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS170COMNTOOLS',
|
||||
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 2019
|
||||
VisualStudio('14.2',
|
||||
vc_version='14.2',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS160COMNTOOLS',
|
||||
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 2017
|
||||
VisualStudio('14.1',
|
||||
vc_version='14.1',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
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 C++ 2017 Express Edition (for Desktop)
|
||||
VisualStudio('14.1Exp',
|
||||
vc_version='14.1',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm", 'arm64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2015
|
||||
VisualStudio('14.0',
|
||||
vc_version='14.0',
|
||||
sdk_version='10.0',
|
||||
hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS140COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual C++ 2015 Express Edition (for Desktop)
|
||||
VisualStudio('14.0Exp',
|
||||
vc_version='14.0',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS140COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2013
|
||||
VisualStudio('12.0',
|
||||
vc_version='12.0',
|
||||
sdk_version='8.1A',
|
||||
hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS120COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2013 Express Edition (for Desktop)
|
||||
VisualStudio('12.0Exp',
|
||||
vc_version='12.0',
|
||||
sdk_version='8.1A',
|
||||
hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS120COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2012
|
||||
VisualStudio('11.0',
|
||||
sdk_version='8.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS110COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2012 Express Edition (for Desktop)
|
||||
VisualStudio('11.0Exp',
|
||||
vc_version='11.0',
|
||||
sdk_version='8.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS110COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2010
|
||||
VisualStudio('10.0',
|
||||
sdk_version='7.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\10.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS100COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2010 Express Edition
|
||||
VisualStudio('10.0Exp',
|
||||
vc_version='10.0',
|
||||
sdk_version='7.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\10.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS100COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 2008
|
||||
VisualStudio('9.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS90COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2008 Express Edition
|
||||
VisualStudio('9.0Exp',
|
||||
vc_version='9.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS90COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 2005
|
||||
VisualStudio('8.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS80COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio 8',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2005 Express Edition
|
||||
VisualStudio('8.0Exp',
|
||||
vc_version='8.0Exp',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS80COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio 8',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio .NET 2003
|
||||
VisualStudio('7.1',
|
||||
sdk_version='6.0',
|
||||
hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS71COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio .NET 2003',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio .NET
|
||||
VisualStudio('7.0',
|
||||
sdk_version='2003R2',
|
||||
hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VSCOMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio .NET',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 6.0
|
||||
VisualStudio('6.0',
|
||||
sdk_version='2003R1',
|
||||
hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir',
|
||||
'use_dir'],
|
||||
common_tools_var='MSDevDir',
|
||||
executable_path=r'Common\MSDev98\Bin\MSDEV.COM',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
]
|
||||
|
||||
SupportedVSMap = {}
|
||||
for vs in SupportedVSList:
|
||||
SupportedVSMap[vs.version] = vs
|
||||
|
||||
|
||||
# Finding installed versions of Visual Studio isn't cheap, because it
|
||||
# goes not only to the registry but also to the disk to sanity-check
|
||||
# that there is, in fact, a Visual Studio directory there and that the
|
||||
# registry entry isn't just stale. Find this information once, when
|
||||
# requested, and cache it.
|
||||
|
||||
InstalledVSList = None
|
||||
InstalledVSMap = None
|
||||
|
||||
def get_installed_visual_studios(env=None):
|
||||
global InstalledVSList
|
||||
global InstalledVSMap
|
||||
vswhere_freeze_env(env)
|
||||
if InstalledVSList is None:
|
||||
InstalledVSList = []
|
||||
InstalledVSMap = {}
|
||||
for vs in SupportedVSList:
|
||||
debug('trying to find VS %s', vs.version)
|
||||
if vs.get_executable(env):
|
||||
debug('found VS %s', vs.version)
|
||||
InstalledVSList.append(vs)
|
||||
if vs.is_express and vs.verstr not in InstalledVSMap:
|
||||
if _VSEXPRESS_USE_VERSTR:
|
||||
InstalledVSMap[vs.verstr] = vs
|
||||
InstalledVSMap[vs.version] = vs
|
||||
return InstalledVSList
|
||||
|
||||
def _get_installed_vss(env=None):
|
||||
get_installed_visual_studios(env)
|
||||
versions = list(InstalledVSMap.keys())
|
||||
return versions
|
||||
|
||||
def reset_installed_visual_studios():
|
||||
global InstalledVSList
|
||||
global InstalledVSMap
|
||||
debug('')
|
||||
InstalledVSList = None
|
||||
InstalledVSMap = None
|
||||
for vs in SupportedVSList:
|
||||
vs.reset()
|
||||
|
||||
# Need to clear installed VC's as well as they are used in finding
|
||||
# installed VS's
|
||||
reset_installed_vcs()
|
||||
|
||||
|
||||
# We may be asked to update multiple construction environments with
|
||||
# SDK information. When doing this, we check on-disk for whether
|
||||
# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
|
||||
# is expensive, cache results by directory.
|
||||
|
||||
#SDKEnvironmentUpdates = {}
|
||||
#
|
||||
#def set_sdk_by_directory(env, sdk_dir):
|
||||
# global SDKEnvironmentUpdates
|
||||
# try:
|
||||
# env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
|
||||
# except KeyError:
|
||||
# env_tuple_list = []
|
||||
# SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
|
||||
#
|
||||
# include_path = os.path.join(sdk_dir, 'include')
|
||||
# mfc_path = os.path.join(include_path, 'mfc')
|
||||
# atl_path = os.path.join(include_path, 'atl')
|
||||
#
|
||||
# if os.path.exists(mfc_path):
|
||||
# env_tuple_list.append(('INCLUDE', mfc_path))
|
||||
# if os.path.exists(atl_path):
|
||||
# env_tuple_list.append(('INCLUDE', atl_path))
|
||||
# env_tuple_list.append(('INCLUDE', include_path))
|
||||
#
|
||||
# env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
|
||||
# env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
|
||||
# env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
|
||||
#
|
||||
# for variable, directory in env_tuple_list:
|
||||
# env.PrependENVPath(variable, directory)
|
||||
|
||||
def msvs_exists(env=None):
|
||||
return len(get_installed_visual_studios(env)) > 0
|
||||
|
||||
def get_vs_by_version(msvs, env=None):
|
||||
global InstalledVSMap
|
||||
global SupportedVSMap
|
||||
|
||||
debug('called')
|
||||
if msvs not in SupportedVSMap:
|
||||
msg = "Visual Studio version %s is not supported" % repr(msvs)
|
||||
raise SCons.Errors.UserError(msg)
|
||||
get_installed_visual_studios(env)
|
||||
vs = InstalledVSMap.get(msvs)
|
||||
debug('InstalledVSMap:%s', InstalledVSMap)
|
||||
debug('found vs:%s', vs)
|
||||
# Some check like this would let us provide a useful error message
|
||||
# if they try to set a Visual Studio version that's not installed.
|
||||
# However, we also want to be able to run tests (like the unit
|
||||
# tests) on systems that don't, or won't ever, have it installed.
|
||||
# It might be worth resurrecting this, with some configurable
|
||||
# setting that the tests can use to bypass the check.
|
||||
#if not vs:
|
||||
# msg = "Visual Studio version %s is not installed" % repr(msvs)
|
||||
# raise SCons.Errors.UserError, msg
|
||||
return vs
|
||||
|
||||
def get_default_version(env):
|
||||
"""Returns the default version string to use for MSVS.
|
||||
|
||||
If no version was requested by the user through the MSVS environment
|
||||
variable, query all the available visual studios through
|
||||
get_installed_visual_studios, and take the highest one.
|
||||
|
||||
Return
|
||||
------
|
||||
version: str
|
||||
the default version.
|
||||
"""
|
||||
if 'MSVS' not in env or not SCons.Util.is_Dict(env['MSVS']):
|
||||
# get all versions, and remember them for speed later
|
||||
versions = _get_installed_vss(env)
|
||||
env['MSVS'] = {'VERSIONS' : versions}
|
||||
else:
|
||||
versions = env['MSVS'].get('VERSIONS', [])
|
||||
|
||||
if 'MSVS_VERSION' not in env:
|
||||
if versions:
|
||||
env['MSVS_VERSION'] = versions[0] #use highest version by default
|
||||
else:
|
||||
debug('WARNING: no installed versions found, '
|
||||
'using first in SupportedVSList (%s)',
|
||||
SupportedVSList[0].version)
|
||||
env['MSVS_VERSION'] = SupportedVSList[0].version
|
||||
|
||||
env['MSVS']['VERSION'] = env['MSVS_VERSION']
|
||||
|
||||
return env['MSVS_VERSION']
|
||||
|
||||
def get_default_arch(env):
|
||||
"""Return the default arch to use for MSVS
|
||||
|
||||
if no version was requested by the user through the MSVS_ARCH environment
|
||||
variable, select x86
|
||||
|
||||
Return
|
||||
------
|
||||
arch: str
|
||||
"""
|
||||
arch = env.get('MSVS_ARCH', 'x86')
|
||||
|
||||
msvs = InstalledVSMap.get(env['MSVS_VERSION'])
|
||||
|
||||
if not msvs:
|
||||
arch = 'x86'
|
||||
elif arch not in msvs.get_supported_arch():
|
||||
fmt = "Visual Studio version %s does not support architecture %s"
|
||||
raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
|
||||
|
||||
return arch
|
||||
|
||||
def merge_default_version(env):
|
||||
version = get_default_version(env)
|
||||
arch = get_default_arch(env)
|
||||
|
||||
# TODO: refers to versions and arch which aren't defined; called nowhere. Drop?
|
||||
def msvs_setup_env(env):
|
||||
msvs = get_vs_by_version(version, env)
|
||||
if msvs is None:
|
||||
return
|
||||
batfilename = msvs.get_batch_file()
|
||||
|
||||
# XXX: I think this is broken. This will silently set a bogus tool instead
|
||||
# of failing, but there is no other way with the current scons tool
|
||||
# framework
|
||||
if batfilename is not None:
|
||||
|
||||
vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE')
|
||||
|
||||
msvs_list = get_installed_visual_studios(env)
|
||||
vscommonvarnames = [vs.common_tools_var for vs in msvs_list]
|
||||
save_ENV = env['ENV']
|
||||
nenv = normalize_env(env['ENV'],
|
||||
['COMSPEC'] + vscommonvarnames,
|
||||
force=True)
|
||||
try:
|
||||
output = get_output(batfilename, arch, env=nenv)
|
||||
finally:
|
||||
env['ENV'] = save_ENV
|
||||
vars = parse_output(output, vars)
|
||||
|
||||
for k, v in vars.items():
|
||||
env.PrependENVPath(k, v, delete_existing=1)
|
||||
|
||||
def query_versions(env=None):
|
||||
"""Query the system to get available versions of VS. A version is
|
||||
considered when a batfile is found."""
|
||||
versions = _get_installed_vss(env)
|
||||
return versions
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,116 @@
|
||||
"""SCons.Tool.PharLapCommon
|
||||
|
||||
This module contains common code used by all Tools for the
|
||||
Phar Lap ETS tool chain. Right now, this is linkloc and
|
||||
386asm.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
import re
|
||||
|
||||
def getPharLapPath():
|
||||
"""Reads the registry to find the installed path of the Phar Lap ETS
|
||||
development kit.
|
||||
|
||||
Raises UserError if no installed version of Phar Lap can
|
||||
be found."""
|
||||
|
||||
if not SCons.Util.can_read_reg:
|
||||
raise SCons.Errors.InternalError("No Windows registry module was found")
|
||||
try:
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
|
||||
'SOFTWARE\\Pharlap\\ETS')
|
||||
val, type = SCons.Util.RegQueryValueEx(k, 'BaseDir')
|
||||
|
||||
# The following is a hack...there is (not surprisingly)
|
||||
# an odd issue in the Phar Lap plug in that inserts
|
||||
# a bunch of junk data after the phar lap path in the
|
||||
# registry. We must trim it.
|
||||
idx=val.find('\0')
|
||||
if idx >= 0:
|
||||
val = val[:idx]
|
||||
|
||||
return os.path.normpath(val)
|
||||
except SCons.Util.RegError:
|
||||
raise SCons.Errors.UserError("Cannot find Phar Lap ETS path in the registry. Is it installed properly?")
|
||||
|
||||
REGEX_ETS_VER = re.compile(r'#define\s+ETS_VER\s+([0-9]+)')
|
||||
|
||||
def getPharLapVersion():
|
||||
"""Returns the version of the installed ETS Tool Suite as a
|
||||
decimal number. This version comes from the ETS_VER #define in
|
||||
the embkern.h header. For example, '#define ETS_VER 1010' (which
|
||||
is what Phar Lap 10.1 defines) would cause this method to return
|
||||
1010. Phar Lap 9.1 does not have such a #define, but this method
|
||||
will return 910 as a default.
|
||||
|
||||
Raises UserError if no installed version of Phar Lap can
|
||||
be found."""
|
||||
|
||||
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
|
||||
if not os.path.exists(include_path):
|
||||
raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?")
|
||||
with open(include_path) as f:
|
||||
mo = REGEX_ETS_VER.search(f.read())
|
||||
if mo:
|
||||
return int(mo.group(1))
|
||||
# Default return for Phar Lap 9.1
|
||||
return 910
|
||||
|
||||
def addPharLapPaths(env):
|
||||
"""This function adds the path to the Phar Lap binaries, includes,
|
||||
and libraries, if they are not already there."""
|
||||
ph_path = getPharLapPath()
|
||||
|
||||
try:
|
||||
env_dict = env['ENV']
|
||||
except KeyError:
|
||||
env_dict = {}
|
||||
env['ENV'] = env_dict
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'PATH',
|
||||
os.path.join(ph_path, 'bin'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'INCLUDE',
|
||||
os.path.join(ph_path, 'include'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'LIB',
|
||||
os.path.join(ph_path, 'lib'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'LIB',
|
||||
os.path.join(ph_path, os.path.normpath('lib/vclib')))
|
||||
|
||||
env['PHARLAP_PATH'] = getPharLapPath()
|
||||
env['PHARLAP_VERSION'] = str(getPharLapVersion())
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
891
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/__init__.py
Normal file
891
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/__init__.py
Normal file
@@ -0,0 +1,891 @@
|
||||
# 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.
|
||||
|
||||
"""SCons tool selection.
|
||||
|
||||
Looks for modules that define a callable object that can modify a
|
||||
construction environment as appropriate for a given tool (or tool chain).
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "tool specification" in an arbitrary callable function. No
|
||||
one needs to use or tie in to this subsystem in order to roll their own
|
||||
tool specifications.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import importlib.util
|
||||
|
||||
import SCons.Builder
|
||||
import SCons.Errors
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
import SCons.Scanner.C
|
||||
# Nuitka: Avoid unused tools
|
||||
# import SCons.Scanner.D
|
||||
# import SCons.Scanner.Java
|
||||
# import SCons.Scanner.LaTeX
|
||||
import SCons.Scanner.Prog
|
||||
# Nuitka: Avoid unused tools
|
||||
# import SCons.Scanner.SWIG
|
||||
from SCons.Tool.linkCommon import LibSymlinksActionFunction, LibSymlinksStrFun
|
||||
|
||||
DefaultToolpath = []
|
||||
|
||||
CScanner = SCons.Scanner.C.CScanner()
|
||||
# Nuitka: Avoid unused tools
|
||||
# DScanner = SCons.Scanner.D.DScanner()
|
||||
# JavaScanner = SCons.Scanner.Java.JavaScanner()
|
||||
# LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
|
||||
# PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner()
|
||||
ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
|
||||
SourceFileScanner = SCons.Scanner.ScannerBase({}, name='SourceFileScanner')
|
||||
# Nuitka: Avoid unused tools
|
||||
# SWIGScanner = SCons.Scanner.SWIG.SWIGScanner()
|
||||
|
||||
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
|
||||
".h", ".H", ".hxx", ".hpp", ".hh",
|
||||
".F", ".fpp", ".FPP",
|
||||
".m", ".mm",
|
||||
".S", ".spp", ".SPP", ".sx"]
|
||||
|
||||
DSuffixes = ['.d']
|
||||
|
||||
IDLSuffixes = [".idl", ".IDL"]
|
||||
|
||||
LaTeXSuffixes = [".tex", ".ltx", ".latex"]
|
||||
|
||||
SWIGSuffixes = ['.i']
|
||||
|
||||
for suffix in CSuffixes:
|
||||
SourceFileScanner.add_scanner(suffix, CScanner)
|
||||
|
||||
# Nuitka: Avoid unused tools
|
||||
# for suffix in DSuffixes:
|
||||
# SourceFileScanner.add_scanner(suffix, DScanner)
|
||||
|
||||
# for suffix in SWIGSuffixes:
|
||||
# SourceFileScanner.add_scanner(suffix, SWIGScanner)
|
||||
|
||||
# FIXME: what should be done here? Two scanners scan the same extensions,
|
||||
# but look for different files, e.g., "picture.eps" vs. "picture.pdf".
|
||||
# The builders for DVI and PDF explicitly reference their scanners
|
||||
# I think that means this is not needed???
|
||||
|
||||
# Nuitka: Avoid unused tools
|
||||
# for suffix in LaTeXSuffixes:
|
||||
# SourceFileScanner.add_scanner(suffix, LaTeXScanner)
|
||||
# SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
|
||||
|
||||
# Tool aliases are needed for those tools whose module names also
|
||||
# occur in the python standard library (This causes module shadowing and
|
||||
# can break using python library functions under python3) or if the current tool/file names
|
||||
# are not legal module names (violate python's identifier rules or are
|
||||
# python language keywords).
|
||||
TOOL_ALIASES = {
|
||||
'gettext': 'gettext_tool',
|
||||
'clang++': 'clangxx',
|
||||
'as': 'asm',
|
||||
'ninja' : 'ninja_tool'
|
||||
}
|
||||
|
||||
|
||||
class Tool:
|
||||
def __init__(self, name, toolpath=None, **kwargs):
|
||||
if toolpath is None:
|
||||
toolpath = []
|
||||
|
||||
# Rename if there's a TOOL_ALIAS for this tool
|
||||
self.name = TOOL_ALIASES.get(name, name)
|
||||
self.toolpath = toolpath + DefaultToolpath
|
||||
# remember these so we can merge them into the call
|
||||
self.init_kw = kwargs
|
||||
|
||||
module = self._tool_module()
|
||||
self.generate = module.generate
|
||||
self.exists = module.exists
|
||||
if hasattr(module, 'options'):
|
||||
self.options = module.options
|
||||
|
||||
def _tool_module(self):
|
||||
"""Try to load a tool module.
|
||||
|
||||
This will hunt in the toolpath for both a Python file (toolname.py)
|
||||
and a Python module (toolname directory), then try the regular
|
||||
import machinery, then fallback to try a zipfile.
|
||||
"""
|
||||
oldpythonpath = sys.path
|
||||
sys.path = self.toolpath + sys.path
|
||||
# These could be enabled under "if debug:"
|
||||
# sys.stderr.write(f"Tool: {self.name}\n")
|
||||
# sys.stderr.write(f"PATH: {sys.path}\n")
|
||||
# sys.stderr.write(f"toolpath: {self.toolpath}\n")
|
||||
# sys.stderr.write(f"SCONS.TOOL path: {sys.modules['SCons.Tool'].__path__}\n")
|
||||
debug = False
|
||||
spec = None
|
||||
found_name = self.name
|
||||
add_to_scons_tools_namespace = False
|
||||
|
||||
# Search for the tool module, but don't import it, yet.
|
||||
#
|
||||
# First look in the toolpath: these take priority.
|
||||
# TODO: any reason to not just use find_spec here?
|
||||
for path in self.toolpath:
|
||||
sepname = self.name.replace('.', os.path.sep)
|
||||
file_path = os.path.join(path, sepname + ".py")
|
||||
file_package = os.path.join(path, sepname)
|
||||
|
||||
if debug: sys.stderr.write(f"Trying: {file_path} {file_package}\n")
|
||||
|
||||
if os.path.isfile(file_path):
|
||||
spec = importlib.util.spec_from_file_location(self.name, file_path)
|
||||
if debug: sys.stderr.write(f"file_Path: {file_path} FOUND\n")
|
||||
break
|
||||
elif os.path.isdir(file_package):
|
||||
file_package = os.path.join(file_package, '__init__.py')
|
||||
spec = importlib.util.spec_from_file_location(self.name, file_package)
|
||||
if debug: sys.stderr.write(f"PACKAGE: {file_package} Found\n")
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
# Now look in the builtin tools (SCons.Tool package)
|
||||
if spec is None:
|
||||
if debug: sys.stderr.write(f"NO SPEC: {self.name}\n")
|
||||
spec = importlib.util.find_spec("." + self.name, package='SCons.Tool')
|
||||
if spec:
|
||||
found_name = 'SCons.Tool.' + self.name
|
||||
add_to_scons_tools_namespace = True
|
||||
if debug: sys.stderr.write(f"Spec Found? .{self.name}: {spec}\n")
|
||||
|
||||
if spec is None:
|
||||
# we are going to bail out here, format up stuff for the msg
|
||||
sconstools = os.path.normpath(sys.modules['SCons.Tool'].__path__[0])
|
||||
if self.toolpath:
|
||||
sconstools = ", ".join(self.toolpath) + ", " + sconstools
|
||||
msg = f"No tool module '{self.name}' found in {sconstools}"
|
||||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
# We have a module spec, so we're good to go.
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
if module is None:
|
||||
if debug: sys.stderr.write(f"MODULE IS NONE: {self.name}\n")
|
||||
msg = f"Tool module '{self.name}' failed import"
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
# Don't reload a tool we already loaded.
|
||||
sys_modules_value = sys.modules.get(found_name, False)
|
||||
|
||||
found_module = None
|
||||
if sys_modules_value and sys_modules_value.__file__ == spec.origin:
|
||||
found_module = sys.modules[found_name]
|
||||
else:
|
||||
# Not sure what to do in the case that there already
|
||||
# exists sys.modules[self.name] but the source file is
|
||||
# different.. ?
|
||||
sys.modules[found_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
if add_to_scons_tools_namespace:
|
||||
# If we found it in SCons.Tool, add it to the module
|
||||
setattr(SCons.Tool, self.name, module)
|
||||
found_module = module
|
||||
|
||||
if found_module is not None:
|
||||
sys.path = oldpythonpath
|
||||
return found_module
|
||||
|
||||
sys.path = oldpythonpath
|
||||
|
||||
# We try some other things here, but this is essentially dead code,
|
||||
# because we bailed out above if we didn't find a module spec.
|
||||
full_name = 'SCons.Tool.' + self.name
|
||||
try:
|
||||
return sys.modules[full_name]
|
||||
except KeyError:
|
||||
try:
|
||||
# This support was added to enable running inside
|
||||
# a py2exe bundle a long time ago - unclear if it's
|
||||
# still needed. It is *not* intended to load individual
|
||||
# tool modules stored in a zipfile.
|
||||
import zipimport
|
||||
|
||||
tooldir = sys.modules['SCons.Tool'].__path__[0]
|
||||
importer = zipimport.zipimporter(tooldir)
|
||||
if not hasattr(importer, 'find_spec'):
|
||||
# zipimport only added find_spec, exec_module in 3.10,
|
||||
# unlike importlib, where they've been around since 3.4.
|
||||
# If we don't have 'em, use the old way.
|
||||
module = importer.load_module(full_name)
|
||||
else:
|
||||
spec = importer.find_spec(full_name)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
importer.exec_module(module)
|
||||
sys.modules[full_name] = module
|
||||
setattr(SCons.Tool, self.name, module)
|
||||
return module
|
||||
except zipimport.ZipImportError as e:
|
||||
msg = "No tool named '{self.name}': {e}"
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
def __call__(self, env, *args, **kw):
|
||||
if self.init_kw is not None:
|
||||
# Merge call kws into init kws;
|
||||
# but don't bash self.init_kw.
|
||||
if kw is not None:
|
||||
call_kw = kw
|
||||
kw = self.init_kw.copy()
|
||||
kw.update(call_kw)
|
||||
else:
|
||||
kw = self.init_kw
|
||||
env.AppendUnique(TOOLS=[self.name])
|
||||
if hasattr(self, 'options'):
|
||||
import SCons.Variables
|
||||
if 'options' not in env:
|
||||
from SCons.Script import ARGUMENTS
|
||||
env['options'] = SCons.Variables.Variables(args=ARGUMENTS)
|
||||
opts = env['options']
|
||||
|
||||
self.options(opts)
|
||||
opts.Update(env)
|
||||
|
||||
self.generate(env, *args, **kw)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Create common executable program / library / object builders
|
||||
|
||||
def createProgBuilder(env):
|
||||
"""This is a utility function that creates the Program
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
"""
|
||||
|
||||
try:
|
||||
program = env['BUILDERS']['Program']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
program = SCons.Builder.Builder(action=SCons.Defaults.LinkAction,
|
||||
emitter='$PROGEMITTER',
|
||||
prefix='$PROGPREFIX',
|
||||
suffix='$PROGSUFFIX',
|
||||
src_suffix='$OBJSUFFIX',
|
||||
src_builder='Object',
|
||||
target_scanner=ProgramScanner)
|
||||
env['BUILDERS']['Program'] = program
|
||||
|
||||
return program
|
||||
|
||||
|
||||
def createStaticLibBuilder(env):
|
||||
"""This is a utility function that creates the StaticLibrary
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
"""
|
||||
|
||||
try:
|
||||
static_lib = env['BUILDERS']['StaticLibrary']
|
||||
except KeyError:
|
||||
action_list = [SCons.Action.Action("$ARCOM", "$ARCOMSTR")]
|
||||
if env.get('RANLIB', False) or env.Detect('ranlib'):
|
||||
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
|
||||
action_list.append(ranlib_action)
|
||||
|
||||
static_lib = SCons.Builder.Builder(action=action_list,
|
||||
emitter='$LIBEMITTER',
|
||||
prefix='$LIBPREFIX',
|
||||
suffix='$LIBSUFFIX',
|
||||
src_suffix='$OBJSUFFIX',
|
||||
src_builder='StaticObject')
|
||||
env['BUILDERS']['StaticLibrary'] = static_lib
|
||||
env['BUILDERS']['Library'] = static_lib
|
||||
|
||||
return static_lib
|
||||
|
||||
|
||||
def createSharedLibBuilder(env, shlib_suffix='$_SHLIBSUFFIX'):
|
||||
"""This is a utility function that creates the SharedLibrary
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
|
||||
Args:
|
||||
shlib_suffix: The suffix specified for the shared library builder
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
shared_lib = env['BUILDERS']['SharedLibrary']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
action_list = [SCons.Defaults.SharedCheck,
|
||||
SCons.Defaults.ShLinkAction,
|
||||
LibSymlinksAction]
|
||||
shared_lib = SCons.Builder.Builder(action=action_list,
|
||||
emitter="$SHLIBEMITTER",
|
||||
prefix="$SHLIBPREFIX",
|
||||
suffix=shlib_suffix,
|
||||
target_scanner=ProgramScanner,
|
||||
src_suffix='$SHOBJSUFFIX',
|
||||
src_builder='SharedObject')
|
||||
env['BUILDERS']['SharedLibrary'] = shared_lib
|
||||
|
||||
return shared_lib
|
||||
|
||||
|
||||
def createLoadableModuleBuilder(env, loadable_module_suffix='$_LDMODULESUFFIX'):
|
||||
"""This is a utility function that creates the LoadableModule
|
||||
Builder in an Environment if it is not there already.
|
||||
|
||||
If it is already there, we return the existing one.
|
||||
|
||||
Args:
|
||||
loadable_module_suffix: The suffix specified for the loadable module builder
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
ld_module = env['BUILDERS']['LoadableModule']
|
||||
except KeyError:
|
||||
import SCons.Defaults
|
||||
action_list = [SCons.Defaults.SharedCheck,
|
||||
SCons.Defaults.LdModuleLinkAction,
|
||||
LibSymlinksAction]
|
||||
ld_module = SCons.Builder.Builder(action=action_list,
|
||||
emitter="$LDMODULEEMITTER",
|
||||
prefix="$LDMODULEPREFIX",
|
||||
suffix=loadable_module_suffix,
|
||||
target_scanner=ProgramScanner,
|
||||
src_suffix='$SHOBJSUFFIX',
|
||||
src_builder='SharedObject')
|
||||
env['BUILDERS']['LoadableModule'] = ld_module
|
||||
|
||||
return ld_module
|
||||
|
||||
|
||||
def createObjBuilders(env):
|
||||
"""This is a utility function that creates the StaticObject
|
||||
and SharedObject Builders in an Environment if they
|
||||
are not there already.
|
||||
|
||||
If they are there already, we return the existing ones.
|
||||
|
||||
This is a separate function because soooo many Tools
|
||||
use this functionality.
|
||||
|
||||
The return is a 2-tuple of (StaticObject, SharedObject)
|
||||
"""
|
||||
|
||||
try:
|
||||
static_obj = env['BUILDERS']['StaticObject']
|
||||
except KeyError:
|
||||
static_obj = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
prefix='$OBJPREFIX',
|
||||
suffix='$OBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=True)
|
||||
env['BUILDERS']['StaticObject'] = static_obj
|
||||
env['BUILDERS']['Object'] = static_obj
|
||||
|
||||
try:
|
||||
shared_obj = env['BUILDERS']['SharedObject']
|
||||
except KeyError:
|
||||
shared_obj = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
prefix='$SHOBJPREFIX',
|
||||
suffix='$SHOBJSUFFIX',
|
||||
src_builder=['CFile', 'CXXFile'],
|
||||
source_scanner=SourceFileScanner,
|
||||
single_source=True)
|
||||
env['BUILDERS']['SharedObject'] = shared_obj
|
||||
|
||||
return (static_obj, shared_obj)
|
||||
|
||||
|
||||
def createCFileBuilders(env):
|
||||
"""This is a utility function that creates the CFile/CXXFile
|
||||
Builders in an Environment if they
|
||||
are not there already.
|
||||
|
||||
If they are there already, we return the existing ones.
|
||||
|
||||
This is a separate function because soooo many Tools
|
||||
use this functionality.
|
||||
|
||||
The return is a 2-tuple of (CFile, CXXFile)
|
||||
"""
|
||||
|
||||
try:
|
||||
c_file = env['BUILDERS']['CFile']
|
||||
except KeyError:
|
||||
c_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$CFILESUFFIX'})
|
||||
env['BUILDERS']['CFile'] = c_file
|
||||
|
||||
env.SetDefault(CFILESUFFIX='.c')
|
||||
|
||||
try:
|
||||
cxx_file = env['BUILDERS']['CXXFile']
|
||||
except KeyError:
|
||||
cxx_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$CXXFILESUFFIX'})
|
||||
env['BUILDERS']['CXXFile'] = cxx_file
|
||||
env.SetDefault(CXXFILESUFFIX='.cc')
|
||||
|
||||
return (c_file, cxx_file)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Create common Java builders
|
||||
|
||||
def CreateJarBuilder(env):
|
||||
"""The Jar builder expects a list of class files
|
||||
which it can package into a jar file.
|
||||
|
||||
The jar tool provides an interface for passing other types
|
||||
of java files such as .java, directories or swig interfaces
|
||||
and will build them to class files in which it can package
|
||||
into the jar.
|
||||
"""
|
||||
try:
|
||||
java_jar = env['BUILDERS']['JarFile']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
|
||||
java_jar = SCons.Builder.Builder(action=jar_com,
|
||||
suffix='$JARSUFFIX',
|
||||
src_suffix='$JAVACLASSSUFFIX',
|
||||
src_builder='JavaClassFile',
|
||||
source_factory=fs.Entry)
|
||||
env['BUILDERS']['JarFile'] = java_jar
|
||||
return java_jar
|
||||
|
||||
|
||||
def CreateJavaHBuilder(env):
|
||||
try:
|
||||
java_javah = env['BUILDERS']['JavaH']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
|
||||
java_javah = SCons.Builder.Builder(action=java_javah_com,
|
||||
src_suffix='$JAVACLASSSUFFIX',
|
||||
target_factory=fs.Entry,
|
||||
source_factory=fs.File,
|
||||
src_builder='JavaClassFile')
|
||||
env['BUILDERS']['JavaH'] = java_javah
|
||||
return java_javah
|
||||
|
||||
|
||||
def CreateJavaClassFileBuilder(env):
|
||||
try:
|
||||
java_class_file = env['BUILDERS']['JavaClassFile']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
|
||||
java_class_file = SCons.Builder.Builder(action=javac_com,
|
||||
emitter={},
|
||||
# suffix = '$JAVACLASSSUFFIX',
|
||||
src_suffix='$JAVASUFFIX',
|
||||
src_builder=['JavaFile'],
|
||||
target_factory=fs.Entry,
|
||||
source_factory=fs.File,
|
||||
target_scanner=JavaScanner)
|
||||
env['BUILDERS']['JavaClassFile'] = java_class_file
|
||||
return java_class_file
|
||||
|
||||
|
||||
def CreateJavaClassDirBuilder(env):
|
||||
try:
|
||||
java_class_dir = env['BUILDERS']['JavaClassDir']
|
||||
except KeyError:
|
||||
fs = SCons.Node.FS.get_default_fs()
|
||||
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
|
||||
java_class_dir = SCons.Builder.Builder(action=javac_com,
|
||||
emitter={},
|
||||
target_factory=fs.Dir,
|
||||
source_factory=fs.Dir,
|
||||
target_scanner=JavaScanner)
|
||||
env['BUILDERS']['JavaClassDir'] = java_class_dir
|
||||
return java_class_dir
|
||||
|
||||
|
||||
def CreateJavaFileBuilder(env):
|
||||
try:
|
||||
java_file = env['BUILDERS']['JavaFile']
|
||||
except KeyError:
|
||||
java_file = SCons.Builder.Builder(action={},
|
||||
emitter={},
|
||||
suffix={None: '$JAVASUFFIX'})
|
||||
env['BUILDERS']['JavaFile'] = java_file
|
||||
env['JAVASUFFIX'] = '.java'
|
||||
return java_file
|
||||
|
||||
|
||||
class ToolInitializerMethod:
|
||||
"""
|
||||
This is added to a construction environment in place of a
|
||||
method(s) normally called for a Builder (env.Object, env.StaticObject,
|
||||
etc.). When called, it has its associated ToolInitializer
|
||||
object search the specified list of tools and apply the first
|
||||
one that exists to the construction environment. It then calls
|
||||
whatever builder was (presumably) added to the construction
|
||||
environment in place of this particular instance.
|
||||
"""
|
||||
|
||||
def __init__(self, name, initializer):
|
||||
"""
|
||||
Note: we store the tool name as __name__ so it can be used by
|
||||
the class that attaches this to a construction environment.
|
||||
"""
|
||||
self.__name__ = name
|
||||
self.initializer = initializer
|
||||
|
||||
def get_builder(self, env):
|
||||
"""
|
||||
Returns the appropriate real Builder for this method name
|
||||
after having the associated ToolInitializer object apply
|
||||
the appropriate Tool module.
|
||||
"""
|
||||
builder = getattr(env, self.__name__)
|
||||
|
||||
self.initializer.apply_tools(env)
|
||||
|
||||
builder = getattr(env, self.__name__)
|
||||
if builder is self:
|
||||
# There was no Builder added, which means no valid Tool
|
||||
# for this name was found (or possibly there's a mismatch
|
||||
# between the name we were called by and the Builder name
|
||||
# added by the Tool module).
|
||||
return None
|
||||
|
||||
self.initializer.remove_methods(env)
|
||||
|
||||
return builder
|
||||
|
||||
def __call__(self, env, *args, **kw):
|
||||
"""
|
||||
"""
|
||||
builder = self.get_builder(env)
|
||||
if builder is None:
|
||||
return [], []
|
||||
return builder(*args, **kw)
|
||||
|
||||
|
||||
class ToolInitializer:
|
||||
"""
|
||||
A class for delayed initialization of Tools modules.
|
||||
|
||||
Instances of this class associate a list of Tool modules with
|
||||
a list of Builder method names that will be added by those Tool
|
||||
modules. As part of instantiating this object for a particular
|
||||
construction environment, we also add the appropriate
|
||||
ToolInitializerMethod objects for the various Builder methods
|
||||
that we want to use to delay Tool searches until necessary.
|
||||
"""
|
||||
|
||||
def __init__(self, env, tools, names):
|
||||
if not SCons.Util.is_List(tools):
|
||||
tools = [tools]
|
||||
if not SCons.Util.is_List(names):
|
||||
names = [names]
|
||||
self.env = env
|
||||
self.tools = tools
|
||||
self.names = names
|
||||
self.methods = {}
|
||||
for name in names:
|
||||
method = ToolInitializerMethod(name, self)
|
||||
self.methods[name] = method
|
||||
env.AddMethod(method)
|
||||
|
||||
def remove_methods(self, env):
|
||||
"""
|
||||
Removes the methods that were added by the tool initialization
|
||||
so we no longer copy and re-bind them when the construction
|
||||
environment gets cloned.
|
||||
"""
|
||||
for method in self.methods.values():
|
||||
env.RemoveMethod(method)
|
||||
|
||||
def apply_tools(self, env):
|
||||
"""
|
||||
Searches the list of associated Tool modules for one that
|
||||
exists, and applies that to the construction environment.
|
||||
"""
|
||||
for t in self.tools:
|
||||
tool = SCons.Tool.Tool(t)
|
||||
if tool.exists(env):
|
||||
env.Tool(tool)
|
||||
return
|
||||
|
||||
# If we fall through here, there was no tool module found.
|
||||
# This is where we can put an informative error message
|
||||
# about the inability to find the tool. We'll start doing
|
||||
# this as we cut over more pre-defined Builder+Tools to use
|
||||
# the ToolInitializer class.
|
||||
|
||||
|
||||
def Initializers(env):
|
||||
ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib'])
|
||||
|
||||
def Install(self, *args, **kw):
|
||||
return self._InternalInstall(*args, **kw)
|
||||
|
||||
def InstallAs(self, *args, **kw):
|
||||
return self._InternalInstallAs(*args, **kw)
|
||||
|
||||
def InstallVersionedLib(self, *args, **kw):
|
||||
return self._InternalInstallVersionedLib(*args, **kw)
|
||||
|
||||
env.AddMethod(Install)
|
||||
env.AddMethod(InstallAs)
|
||||
env.AddMethod(InstallVersionedLib)
|
||||
|
||||
|
||||
def FindTool(tools, env):
|
||||
for tool in tools:
|
||||
t = Tool(tool)
|
||||
if t.exists(env):
|
||||
return tool
|
||||
return None
|
||||
|
||||
|
||||
def FindAllTools(tools, env):
|
||||
def ToolExists(tool, env=env):
|
||||
return Tool(tool).exists(env)
|
||||
|
||||
return list(filter(ToolExists, tools))
|
||||
|
||||
|
||||
def tool_list(platform, env):
|
||||
other_plat_tools = []
|
||||
# XXX this logic about what tool to prefer on which platform
|
||||
# should be moved into either the platform files or
|
||||
# the tool files themselves.
|
||||
# The search orders here are described in the man page. If you
|
||||
# change these search orders, update the man page as well.
|
||||
if str(platform) == 'win32':
|
||||
"prefer Microsoft tools on Windows"
|
||||
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32']
|
||||
c_compilers = ['msvc', 'mingw', 'gcc', 'clang', 'intelc', 'icl', 'icc', 'cc', 'bcc32']
|
||||
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'clang++', 'cxx', 'bcc32']
|
||||
assemblers = ['masm', 'nasm', 'gas', '386asm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
|
||||
ars = ['mslib', 'ar', 'tlib']
|
||||
# Nuitka: Do not use "midl" or "wix" tool.
|
||||
# other_plat_tools = ['msvs', 'midl', 'wix']
|
||||
other_plat_tools = ['msvs']
|
||||
elif str(platform) == 'os2':
|
||||
"prefer IBM tools on OS/2"
|
||||
linkers = ['ilink', 'gnulink', ] # 'mslink']
|
||||
c_compilers = ['icc', 'gcc', ] # 'msvc', 'cc']
|
||||
cxx_compilers = ['icc', 'g++', ] # 'msvc', 'cxx']
|
||||
assemblers = ['nasm', ] # 'masm', 'gas']
|
||||
fortran_compilers = ['ifl', 'g77']
|
||||
ars = ['ar', ] # 'mslib']
|
||||
elif str(platform) == 'irix':
|
||||
"prefer MIPSPro on IRIX"
|
||||
linkers = ['sgilink', 'gnulink']
|
||||
c_compilers = ['sgicc', 'gcc', 'cc']
|
||||
cxx_compilers = ['sgicxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
|
||||
ars = ['sgiar']
|
||||
elif str(platform) == 'sunos':
|
||||
"prefer Forte tools on SunOS"
|
||||
linkers = ['sunlink', 'gnulink']
|
||||
c_compilers = ['suncc', 'gcc', 'cc']
|
||||
cxx_compilers = ['suncxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
|
||||
'gfortran', 'g77', 'fortran']
|
||||
ars = ['sunar']
|
||||
elif str(platform) == 'hpux':
|
||||
"prefer aCC tools on HP-UX"
|
||||
linkers = ['hplink', 'gnulink']
|
||||
c_compilers = ['hpcc', 'gcc', 'cc']
|
||||
cxx_compilers = ['hpcxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'aix':
|
||||
"prefer AIX Visual Age tools on AIX"
|
||||
linkers = ['aixlink', 'gnulink']
|
||||
c_compilers = ['aixcc', 'gcc', 'cc']
|
||||
cxx_compilers = ['aixcxx', 'g++', 'cxx']
|
||||
assemblers = ['as', 'gas']
|
||||
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'darwin':
|
||||
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
|
||||
linkers = ['applelink', 'gnulink']
|
||||
c_compilers = ['gcc', 'cc']
|
||||
cxx_compilers = ['g++', 'cxx']
|
||||
assemblers = ['as']
|
||||
fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
|
||||
ars = ['ar']
|
||||
elif str(platform) == 'cygwin':
|
||||
"prefer GNU tools on Cygwin, except for a platform-specific linker"
|
||||
linkers = ['cyglink', 'mslink', 'ilink']
|
||||
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
|
||||
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx']
|
||||
assemblers = ['gas', 'nasm', 'masm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
|
||||
ars = ['ar', 'mslib']
|
||||
else:
|
||||
"prefer GNU tools on all other platforms"
|
||||
linkers = ['gnulink', 'ilink']
|
||||
c_compilers = ['gcc', 'clang', 'intelc', 'icc', 'cc']
|
||||
cxx_compilers = ['g++', 'clang++', 'intelc', 'icc', 'cxx']
|
||||
assemblers = ['gas', 'nasm', 'masm']
|
||||
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
|
||||
ars = ['ar', ]
|
||||
|
||||
if not str(platform) == 'win32':
|
||||
other_plat_tools += ['m4', 'rpm']
|
||||
|
||||
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
|
||||
|
||||
# XXX this logic about what tool provides what should somehow be
|
||||
# moved into the tool files themselves.
|
||||
if c_compiler and c_compiler == 'mingw':
|
||||
# MinGW contains a linker, C compiler, C++ compiler,
|
||||
# Fortran compiler, archiver and assembler:
|
||||
cxx_compiler = None
|
||||
linker = None
|
||||
assembler = None
|
||||
fortran_compiler = None
|
||||
ar = None
|
||||
else:
|
||||
# Don't use g++ if the C compiler has built-in C++ support:
|
||||
if c_compiler in ('msvc', 'intelc', 'icc'):
|
||||
cxx_compiler = None
|
||||
else:
|
||||
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
|
||||
linker = FindTool(linkers, env) or linkers[0]
|
||||
# Nuitka: Avoid unused tools
|
||||
# assembler = FindTool(assemblers, env) or assemblers[0]
|
||||
assembler = None
|
||||
# fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
|
||||
fortran_compiler = None
|
||||
# ar = FindTool(ars, env) or ars[0]
|
||||
ar = None
|
||||
|
||||
d_compilers = ['dmd', 'ldc', 'gdc']
|
||||
# Nuitka: Avoid unused tools
|
||||
# d_compiler = FindTool(d_compilers, env) or d_compilers[0]
|
||||
d_compiler = None
|
||||
|
||||
|
||||
other_tools = FindAllTools(other_plat_tools + [
|
||||
# Nuitka: Avoid unused tools
|
||||
# TODO: merge 'install' into 'filesystem' and
|
||||
# make 'filesystem' the default
|
||||
# 'filesystem',
|
||||
# Parser generators
|
||||
# 'lex', 'yacc',
|
||||
# Foreign function interface
|
||||
# 'rpcgen', 'swig',
|
||||
# Java
|
||||
# 'jar', 'javac', 'javah', 'rmic',
|
||||
# TeX
|
||||
# 'dvipdf', 'dvips', 'gs',
|
||||
# 'tex', 'latex', 'pdflatex', 'pdftex',
|
||||
# Archivers
|
||||
# 'tar', 'zip',
|
||||
# File builders (text)
|
||||
# 'textfile',
|
||||
], env)
|
||||
|
||||
tools = [
|
||||
linker,
|
||||
c_compiler,
|
||||
cxx_compiler,
|
||||
fortran_compiler,
|
||||
assembler,
|
||||
ar,
|
||||
d_compiler,
|
||||
] + other_tools
|
||||
|
||||
return [x for x in tools if x]
|
||||
|
||||
|
||||
def find_program_path(env, key_program, default_paths=None, add_path=False):
|
||||
"""
|
||||
Find the location of a tool using various means.
|
||||
|
||||
Mainly for windows where tools aren't all installed in /usr/bin, etc.
|
||||
|
||||
Args:
|
||||
env: Current Construction Environment.
|
||||
key_program: Tool to locate.
|
||||
default_paths: List of additional paths this tool might be found in.
|
||||
add_path: If true, add path found if it was from *default_paths*.
|
||||
"""
|
||||
# First search in the SCons path
|
||||
path = env.WhereIs(key_program)
|
||||
if path:
|
||||
return path
|
||||
|
||||
# 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.
|
||||
if default_paths is None:
|
||||
return path
|
||||
|
||||
save_path = env['ENV']['PATH']
|
||||
for p in default_paths:
|
||||
env.AppendENVPath('PATH', p)
|
||||
path = env.WhereIs(key_program)
|
||||
|
||||
# By default, do not change ['ENV']['PATH'] permananetly
|
||||
# leave that to the caller, unless add_path is true.
|
||||
env['ENV']['PATH'] = save_path
|
||||
if path and add_path:
|
||||
env.AppendENVPath('PATH', os.path.dirname(path))
|
||||
|
||||
return path
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,43 @@
|
||||
"""SCons.Tool.aixc++
|
||||
|
||||
Tool-specific initialization for IBM xlC / Visual Age C++ 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.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __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__"
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.aixcxx import *
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,74 @@
|
||||
"""SCons.Tool.aixcc
|
||||
|
||||
Tool-specific initialization for IBM xlc / Visual Age C 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.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Platform.aix
|
||||
|
||||
from . import cc
|
||||
|
||||
packages = ['vac.C', 'ibmcxx.cmp']
|
||||
|
||||
def get_xlc(env):
|
||||
xlc = env.get('CC', 'xlc')
|
||||
return SCons.Platform.aix.get_xlc(env, xlc, packages)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for xlc / Visual Age
|
||||
suite to an Environment."""
|
||||
path, _cc, version = get_xlc(env)
|
||||
if path and _cc:
|
||||
_cc = os.path.join(path, _cc)
|
||||
|
||||
if 'CC' not in env:
|
||||
env['CC'] = _cc
|
||||
|
||||
cc.generate(env)
|
||||
|
||||
if version:
|
||||
env['CCVERSION'] = version
|
||||
|
||||
def exists(env):
|
||||
path, _cc, version = get_xlc(env)
|
||||
if path and _cc:
|
||||
xlc = os.path.join(path, _cc)
|
||||
if os.path.exists(xlc):
|
||||
return xlc
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,77 @@
|
||||
"""SCons.Tool.aixc++
|
||||
|
||||
Tool-specific initialization for IBM xlC / Visual Age C++ 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.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Platform.aix
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
||||
|
||||
packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp']
|
||||
|
||||
def get_xlc(env):
|
||||
xlc = env.get('CXX', 'xlC')
|
||||
return SCons.Platform.aix.get_xlc(env, xlc, packages)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for xlC / Visual Age
|
||||
suite to an Environment."""
|
||||
path, _cxx, version = get_xlc(env)
|
||||
if path and _cxx:
|
||||
_cxx = os.path.join(path, _cxx)
|
||||
|
||||
if 'CXX' not in env:
|
||||
env['CXX'] = _cxx
|
||||
|
||||
cplusplus.generate(env)
|
||||
|
||||
if version:
|
||||
env['CXXVERSION'] = version
|
||||
|
||||
def exists(env):
|
||||
path, _cxx, version = get_xlc(env)
|
||||
if path and _cxx:
|
||||
xlc = os.path.join(path, _cxx)
|
||||
if os.path.exists(xlc):
|
||||
return xlc
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,78 @@
|
||||
"""SCons.Tool.aixlink
|
||||
|
||||
Tool-specific initialization for the IBM Visual Age linker.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
#
|
||||
# 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 os.path
|
||||
|
||||
import SCons.Util
|
||||
|
||||
from . import aixcc
|
||||
from . import link
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
|
||||
|
||||
def smart_linkflags(source, target, env, for_signature):
|
||||
if cplusplus.iscplusplus(source):
|
||||
build_dir = env.subst('$BUILDDIR', target=target, source=source)
|
||||
if build_dir:
|
||||
return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
|
||||
return ''
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age linker to
|
||||
an Environment.
|
||||
"""
|
||||
link.generate(env)
|
||||
|
||||
env['SMARTLINKFLAGS'] = smart_linkflags
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('$SMARTLINKFLAGS')
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218')
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
|
||||
|
||||
def exists(env):
|
||||
# TODO: sync with link.smart_link() to choose a linker
|
||||
linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
|
||||
alltools = []
|
||||
for langvar, linktools in linkers.items():
|
||||
if langvar in env: # use CC over CXX when user specified CC but not CXX
|
||||
return SCons.Tool.FindTool(linktools, env)
|
||||
alltools.extend(linktools)
|
||||
return SCons.Tool.FindTool(alltools, env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,209 @@
|
||||
"""SCons.Tool.applelink
|
||||
|
||||
Tool-specific initialization for Apple's gnu-like linker.
|
||||
|
||||
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 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.
|
||||
#
|
||||
|
||||
# Even though the Mac is based on the GNU toolchain, it doesn't understand
|
||||
# the -rpath option, so we use the "link" tool instead of "gnulink".
|
||||
from SCons.Util import CLVar
|
||||
from SCons.Errors import UserError
|
||||
from . import link
|
||||
|
||||
# User programmatically describes how SHLIBVERSION maps to values for compat/current.
|
||||
_APPLELIB_MAX_VERSION_VALUES = (65535, 255, 255)
|
||||
|
||||
|
||||
class AppleLinkInvalidCurrentVersionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AppleLinkInvalidCompatibilityVersionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _applelib_check_valid_version(version_string):
|
||||
"""
|
||||
Check that the version # is valid.
|
||||
X[.Y[.Z]]
|
||||
where X 0-65535
|
||||
where Y either not specified or 0-255
|
||||
where Z either not specified or 0-255
|
||||
:param version_string:
|
||||
:return:
|
||||
"""
|
||||
parts = version_string.split('.')
|
||||
if len(parts) > 3:
|
||||
return False, "Version string has too many periods [%s]" % version_string
|
||||
if len(parts) <= 0:
|
||||
return False, "Version string unspecified [%s]" % version_string
|
||||
|
||||
for (i, p) in enumerate(parts):
|
||||
try:
|
||||
p_i = int(p)
|
||||
except ValueError:
|
||||
return False, "Version component %s (from %s) is not a number" % (p, version_string)
|
||||
if p_i < 0 or p_i > _APPLELIB_MAX_VERSION_VALUES[i]:
|
||||
return False, "Version component %s (from %s) is not valid value should be between 0 and %d" % (
|
||||
p, version_string, _APPLELIB_MAX_VERSION_VALUES[i])
|
||||
|
||||
return True, ""
|
||||
|
||||
|
||||
def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-current_version flag if needed.
|
||||
If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
|
||||
will be used.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the current_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_CURRENT_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_CURRENT_VERSION', False):
|
||||
version_string = env['APPLELINK_CURRENT_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = env['SHLIBVERSION']
|
||||
else:
|
||||
return ""
|
||||
|
||||
version_string = ".".join(version_string.split('.')[:3])
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCurrentVersionException(reason)
|
||||
|
||||
return "-Wl,-current_version,%s" % version_string
|
||||
|
||||
|
||||
def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-compatibility_version flag if needed.
|
||||
If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
|
||||
the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the compatibility_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
|
||||
version_string = env['APPLELINK_COMPATIBILITY_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
|
||||
else:
|
||||
return ""
|
||||
|
||||
if version_string is None:
|
||||
return ""
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCompatibilityVersionException(reason)
|
||||
|
||||
return "-Wl,-compatibility_version,%s" % version_string
|
||||
|
||||
def _applelib_soname(target, source, env, for_signature):
|
||||
"""
|
||||
Override default _soname() function from SCons.Tools.linkCommon.SharedLibrary.
|
||||
Apple's file naming for versioned shared libraries puts the version string before
|
||||
the shared library suffix (.dylib), instead of after.
|
||||
"""
|
||||
if "SONAME" in env:
|
||||
# Now verify that SOVERSION is not also set as that is not allowed
|
||||
if "SOVERSION" in env:
|
||||
raise UserError(
|
||||
"Ambiguous library .so naming, both SONAME: %s and SOVERSION: %s are defined. "
|
||||
"Only one can be defined for a target library."
|
||||
% (env["SONAME"], env["SOVERSION"])
|
||||
)
|
||||
return "$SONAME"
|
||||
else:
|
||||
return "$SHLIBPREFIX$_get_shlib_stem$_SHLIBSOVERSION${SHLIBSUFFIX}"
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for applelink to an
|
||||
Environment."""
|
||||
link.generate(env)
|
||||
|
||||
env['FRAMEWORKPATHPREFIX'] = '-F'
|
||||
env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
|
||||
|
||||
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
|
||||
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
env['SHLINKFLAGS'] = CLVar('$LINKFLAGS -dynamiclib')
|
||||
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
|
||||
env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
|
||||
env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
|
||||
# override the default for loadable modules, which are different
|
||||
# on OS X than dynamic shared libs. echoing what XCode does for
|
||||
# pre/suffixes:
|
||||
env['LDMODULEPREFIX'] = ''
|
||||
env['LDMODULESUFFIX'] = ''
|
||||
env['LDMODULEFLAGS'] = CLVar('$LINKFLAGS -bundle')
|
||||
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS' \
|
||||
' $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
# New stuff
|
||||
#
|
||||
env['_SHLIBSUFFIX'] = '${_SHLIBVERSION}${SHLIBSUFFIX}'
|
||||
|
||||
env['__SHLIBVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
|
||||
'"SHLIBVERSION","_APPLELINK_CURRENT_VERSION", "_SHLIBVERSIONFLAGS")}'
|
||||
env['__LDMODULEVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
|
||||
'"LDMODULEVERSION","_APPLELINK_CURRENT_VERSION", "_LDMODULEVERSIONFLAGS")}'
|
||||
|
||||
env["_SHLIBSONAME"] = _applelib_soname
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env['PLATFORM'] == 'darwin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
63
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/ar.py
Normal file
63
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/ar.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""SCons.Tool.ar
|
||||
|
||||
Tool-specific initialization for ar (library archive).
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for ar to an Environment."""
|
||||
SCons.Tool.createStaticLibBuilder(env)
|
||||
|
||||
env['AR'] = 'ar'
|
||||
env['ARFLAGS'] = SCons.Util.CLVar('rc')
|
||||
env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES'
|
||||
env['LIBPREFIX'] = 'lib'
|
||||
env['LIBSUFFIX'] = '.a'
|
||||
|
||||
if env.get('RANLIB',env.Detect('ranlib')) :
|
||||
env['RANLIB'] = env.get('RANLIB','ranlib')
|
||||
env['RANLIBFLAGS'] = SCons.Util.CLVar('')
|
||||
env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('ar')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
49
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/as.py
Normal file
49
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/as.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""SCons.Tool.as
|
||||
|
||||
Tool-specific initialization for generic assembler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
#
|
||||
# forward proxy to the preferred asm version
|
||||
#
|
||||
import SCons.Tool.asm
|
||||
|
||||
# Resolve FLAKE8 F401 (make sider happy)
|
||||
generate = SCons.Tool.asm.generate
|
||||
exists = SCons.Tool.asm.exists
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
78
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/asm.py
Normal file
78
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/asm.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""SCons.Tool.as
|
||||
|
||||
Tool-specific initialization for as, the generic Posix assembler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
assemblers = ['as']
|
||||
|
||||
ASSuffixes = ['.s', '.asm', '.ASM']
|
||||
ASPPSuffixes = ['.spp', '.SPP', '.sx']
|
||||
if SCons.Util.case_sensitive_suffixes('.s', '.S'):
|
||||
ASPPSuffixes.extend(['.S'])
|
||||
else:
|
||||
ASSuffixes.extend(['.S'])
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for as to an Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in ASSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.ASAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ASAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
for suffix in ASPPSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.ASPPAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ASPPAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
env['AS'] = env.Detect(assemblers) or 'as'
|
||||
env['ASFLAGS'] = SCons.Util.CLVar('')
|
||||
env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES'
|
||||
env['ASPPFLAGS'] = '$ASFLAGS'
|
||||
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(assemblers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,81 @@
|
||||
"""SCons.Tool.bcc32
|
||||
|
||||
XXX
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
def findIt(program, env):
|
||||
# First search in the SCons path and then the OS path:
|
||||
borwin = env.WhereIs(program) or SCons.Util.WhereIs(program)
|
||||
if borwin:
|
||||
dir = os.path.dirname(borwin)
|
||||
env.PrependENVPath('PATH', dir)
|
||||
return borwin
|
||||
|
||||
def generate(env):
|
||||
findIt('bcc32', env)
|
||||
"""Add Builders and construction variables for bcc to an
|
||||
Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
for suffix in ['.c', '.cpp']:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
env['CC'] = 'bcc32'
|
||||
env['CCFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
|
||||
env['SHCC'] = '$CC'
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
|
||||
env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.dll'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
env['CFILESUFFIX'] = '.cpp'
|
||||
|
||||
def exists(env):
|
||||
return findIt('bcc32', env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
44
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/c++.py
Normal file
44
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/c++.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""SCons.Tool.c++
|
||||
|
||||
Tool-specific initialization for generic Posix C++ compilers.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.cxx import *
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
105
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cc.py
Normal file
105
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cc.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""SCons.Tool.cc
|
||||
|
||||
Tool-specific initialization for generic Posix C compilers.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Defaults
|
||||
import SCons.Util
|
||||
|
||||
CSuffixes = ['.c', '.m']
|
||||
if not SCons.Util.case_sensitive_suffixes('.c', '.C'):
|
||||
CSuffixes.append('.C')
|
||||
|
||||
def add_common_cc_variables(env):
|
||||
"""
|
||||
Add underlying common "C compiler" variables that
|
||||
are used by multiple tools (specifically, c++).
|
||||
"""
|
||||
if '_CCCOMCOM' not in env:
|
||||
env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
|
||||
# It's a hack to test for darwin here, but the alternative
|
||||
# of creating an applecc.py to contain this seems overkill.
|
||||
# Maybe someday the Apple platform will require more setup and
|
||||
# this logic will be moved.
|
||||
env['FRAMEWORKS'] = SCons.Util.CLVar('')
|
||||
env['FRAMEWORKPATH'] = SCons.Util.CLVar('')
|
||||
if env['PLATFORM'] == 'darwin':
|
||||
env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH'
|
||||
|
||||
if 'CCFLAGS' not in env:
|
||||
env['CCFLAGS'] = SCons.Util.CLVar('')
|
||||
|
||||
if 'SHCCFLAGS' not in env:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
|
||||
compilers = ['cc']
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for C compilers to an Environment.
|
||||
"""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in CSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
add_common_cc_variables(env)
|
||||
|
||||
if 'CC' not in env:
|
||||
env['CC'] = env.Detect(compilers) or compilers[0]
|
||||
env['CFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
|
||||
env['SHCC'] = '$CC'
|
||||
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
|
||||
env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
|
||||
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.os'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
|
||||
env['CFILESUFFIX'] = '.c'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(env.get('CC', compilers))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,91 @@
|
||||
# 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.
|
||||
|
||||
"""Tool-specific initialization for clang.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
|
||||
# Brought into the SCons mainline by Russel Winder 2017.
|
||||
|
||||
import os
|
||||
import re
|
||||
from subprocess import DEVNULL, PIPE
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Tool.cc
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang']
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for clang to an Environment."""
|
||||
SCons.Tool.cc.generate(env)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang
|
||||
clang = SCons.Tool.find_program_path(
|
||||
env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM'])
|
||||
)
|
||||
if clang:
|
||||
clang_bin_dir = os.path.dirname(clang)
|
||||
env.AppendENVPath("PATH", clang_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(env)
|
||||
|
||||
env['CC'] = env.Detect(compilers) or 'clang'
|
||||
if env['PLATFORM'] in ['cygwin', 'win32']:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
else:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
||||
|
||||
# determine compiler version
|
||||
if env['CC']:
|
||||
kw = {
|
||||
'stdout': PIPE,
|
||||
'stderr': DEVNULL,
|
||||
'universal_newlines': True,
|
||||
}
|
||||
cp = SCons.Action.scons_subproc_run(env, [env['CC'], '-dumpversion'], **kw)
|
||||
line = cp.stdout
|
||||
if line:
|
||||
env['CCVERSION'] = line
|
||||
|
||||
env['CCDEPFLAGS'] = '-MMD -MF ${TARGET}.d'
|
||||
env["NINJA_DEPFILE_PARSE_FORMAT"] = 'clang'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
Common routines and data for clang tools
|
||||
"""
|
||||
|
||||
clang_win32_dirs = [
|
||||
r'C:\Program Files\LLVM\bin',
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\msys64',
|
||||
r'C:\msys64\mingw64\bin',
|
||||
r'C:\cygwin\bin',
|
||||
r'C:\msys',
|
||||
]
|
||||
|
||||
def get_clang_install_dirs(platform):
|
||||
if platform == 'win32':
|
||||
return clang_win32_dirs
|
||||
else:
|
||||
return []
|
||||
@@ -0,0 +1,99 @@
|
||||
# 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.
|
||||
|
||||
"""Tool-specific initialization for clang++.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
|
||||
# Brought into the SCons mainline by Russel Winder 2017.
|
||||
|
||||
import os.path
|
||||
import re
|
||||
from subprocess import DEVNULL, PIPE
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Tool.cxx
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang++']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for clang++ to an Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
SCons.Tool.cxx.generate(env)
|
||||
|
||||
env['CXX'] = env.Detect(compilers) or 'clang++'
|
||||
|
||||
# platform specific settings
|
||||
if env['PLATFORM'] == 'aix':
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
elif env['PLATFORM'] == 'hpux':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'sunos':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang++
|
||||
clangxx = SCons.Tool.find_program_path(
|
||||
env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM'])
|
||||
)
|
||||
if clangxx:
|
||||
clangxx_bin_dir = os.path.dirname(clangxx)
|
||||
env.AppendENVPath('PATH', clangxx_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(env)
|
||||
|
||||
# determine compiler version
|
||||
if env['CXX']:
|
||||
kw = {
|
||||
'stdout': PIPE,
|
||||
'stderr': DEVNULL,
|
||||
'universal_newlines': True,
|
||||
}
|
||||
cp = SCons.Action.scons_subproc_run(env, [env['CXX'], '-dumpversion'], **kw)
|
||||
line = cp.stdout
|
||||
if line:
|
||||
env['CXXVERSION'] = line
|
||||
|
||||
env['CCDEPFLAGS'] = '-MMD -MF ${TARGET}.d'
|
||||
env["NINJA_DEPFILE_PARSE_FORMAT"] = 'clang'
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
95
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cxx.py
Normal file
95
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cxx.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# 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.
|
||||
|
||||
"""Tool-specific initialization for generic Posix C++ compilers.
|
||||
|
||||
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 os.path
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Util
|
||||
|
||||
compilers = ['CC', 'c++']
|
||||
|
||||
CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm']
|
||||
if SCons.Util.case_sensitive_suffixes('.c', '.C'):
|
||||
CXXSuffixes.append('.C')
|
||||
|
||||
def iscplusplus(source):
|
||||
if not source:
|
||||
# Source might be None for unusual cases like SConf.
|
||||
return False
|
||||
for s in source:
|
||||
if s.sources:
|
||||
ext = os.path.splitext(str(s.sources[0]))[1]
|
||||
if ext in CXXSuffixes:
|
||||
return True
|
||||
return False
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age C++ compilers
|
||||
to an Environment.
|
||||
"""
|
||||
import SCons.Tool
|
||||
import SCons.Tool.cc
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in CXXSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CXXAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
SCons.Tool.cc.add_common_cc_variables(env)
|
||||
|
||||
if 'CXX' not in env:
|
||||
env['CXX'] = env.Detect(compilers) or compilers[0]
|
||||
env['CXXFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
|
||||
env['SHCXX'] = '$CXX'
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
|
||||
env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
|
||||
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.os'
|
||||
env['OBJSUFFIX'] = '.o'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
|
||||
env['CXXFILESUFFIX'] = '.cc'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(env.get('CXX', compilers))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
235
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cyglink.py
Normal file
235
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/cyglink.py
Normal file
@@ -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.
|
||||
|
||||
"""SCons.Tool.cyglink
|
||||
|
||||
Customization of gnulink for Cygwin (https://www.cygwin.com/)
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from SCons.Tool.linkCommon import StringizeLibSymlinks, EmitLibSymlinks
|
||||
from SCons.Util import CLVar, is_String
|
||||
from . import gnulink
|
||||
|
||||
|
||||
def cyglink_lib_emitter(target, source, env, **kw):
|
||||
verbose = True
|
||||
|
||||
if 'variable_prefix' in kw:
|
||||
var_prefix = kw['variable_prefix']
|
||||
else:
|
||||
var_prefix = 'SHLIB'
|
||||
|
||||
no_import_lib = env.get('no_import_lib', False)
|
||||
|
||||
if verbose:
|
||||
print(f"cyglink_lib_emitter: target[0]={target[0].get_path()!r}")
|
||||
|
||||
if not no_import_lib:
|
||||
# Specify import lib and add to targets
|
||||
|
||||
import_lib = env.subst('$%s_IMPLIBNAME' % var_prefix, target=target, source=source)
|
||||
import_lib_target = env.fs.File(import_lib)
|
||||
import_lib_target.attributes.shared = True
|
||||
target.append(import_lib_target)
|
||||
|
||||
if verbose:
|
||||
print(f"cyglink_lib_emitter: import_lib={import_lib}")
|
||||
print("cyglink_lib_emitter: target=%s" % target)
|
||||
|
||||
for tgt in target:
|
||||
if is_String(tgt):
|
||||
tgt = env.File(tgt)
|
||||
tgt.attributes.shared = True
|
||||
|
||||
return target, source
|
||||
|
||||
|
||||
def cyglink_ldmodule_emitter(target, source, env, **kw):
|
||||
return cyglink_lib_emitter(target, source, env, variable_prefix='LDMODULE')
|
||||
|
||||
|
||||
def cyglink_shlib_symlink_emitter(target, source, env, **kw):
|
||||
"""
|
||||
On cygwin, we only create a symlink from the non-versioned implib to the versioned implib.
|
||||
We don't version the shared library itself.
|
||||
:param target:
|
||||
:param source:
|
||||
:param env:
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
verbose = True
|
||||
|
||||
if 'variable_prefix' in kw:
|
||||
var_prefix = kw['variable_prefix']
|
||||
else:
|
||||
var_prefix = 'SHLIB'
|
||||
|
||||
no_import_lib = env.get('no_import_lib', False)
|
||||
if no_import_lib in ['1', 'True', 'true', True]:
|
||||
if verbose:
|
||||
print("cyglink_shlib_symlink_emitter: no_import_lib=%s" % no_import_lib)
|
||||
return target, source
|
||||
|
||||
no_symlinks = env.subst('$%sNOVERSIONSYMLINKS' % var_prefix)
|
||||
if no_symlinks in ['1', 'True', 'true', True]:
|
||||
return target, source
|
||||
|
||||
shlibversion = env.subst('$%sVERSION' % var_prefix)
|
||||
if shlibversion:
|
||||
if verbose:
|
||||
print("cyglink_shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion))
|
||||
|
||||
# The implib (added by the cyglink_lib_emitter)
|
||||
imp_lib_node = target[1]
|
||||
shlib_noversion_symlink = env.subst('$%s_NOVERSION_SYMLINK' % var_prefix, target=target[0], source=source)
|
||||
|
||||
if verbose:
|
||||
print("cyglink_shlib_symlink_emitter: shlib_noversion_symlink :%s" % shlib_noversion_symlink)
|
||||
print("cyglink_shlib_symlink_emitter: imp_lib_node :%s" % imp_lib_node)
|
||||
|
||||
symlinks = [(env.File(shlib_noversion_symlink), imp_lib_node)]
|
||||
|
||||
if verbose:
|
||||
print("cyglink_shlib_symlink_emitter: symlinks={!r}".format(
|
||||
', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
|
||||
))
|
||||
|
||||
if symlinks:
|
||||
# This does the actual symlinking
|
||||
EmitLibSymlinks(env, symlinks, target[0])
|
||||
|
||||
# This saves the information so if the versioned shared library is installed
|
||||
# it can faithfully reproduce the correct symlinks
|
||||
target[0].attributes.shliblinks = symlinks
|
||||
|
||||
return target, source
|
||||
|
||||
|
||||
def cyglink_ldmod_symlink_emitter(target, source, env, **kw):
|
||||
return cyglink_shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE')
|
||||
|
||||
|
||||
def cyglink_shlibversion(target, source, env, for_signature):
|
||||
var_prefix = 'SHLIB'
|
||||
var = '%sVERSION' % var_prefix
|
||||
if var not in env:
|
||||
return ''
|
||||
|
||||
version = env.subst("$%s" % var, target=target, source=source)
|
||||
version = version.replace('.', '-')
|
||||
return "." + version
|
||||
|
||||
|
||||
def cyglink_ldmodule_version(target, source, env, for_signature):
|
||||
var_prefix = 'LDMODULE'
|
||||
var = '%sVERSION' % var_prefix
|
||||
if var not in env:
|
||||
return ''
|
||||
|
||||
version = env.subst("$%s" % var, target=target, source=source)
|
||||
version = version.replace('.', '-')
|
||||
return "." + version
|
||||
|
||||
|
||||
def _implib_pre_flags(target, source, env, for_signature):
|
||||
no_import_lib = env.get('no_import_lib', False)
|
||||
if no_import_lib in ['1', 'True', 'true', True]:
|
||||
return ''
|
||||
else:
|
||||
return '-Wl,--out-implib=${TARGETS[1]} -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive'
|
||||
|
||||
|
||||
def _implib_post_flags(target, source, env, for_signature):
|
||||
no_import_lib = env.get('no_import_lib', False)
|
||||
if no_import_lib in ['1', 'True', 'true', True]:
|
||||
return ''
|
||||
else:
|
||||
return '-Wl,--no-whole-archive'
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for cyglink to an Environment."""
|
||||
gnulink.generate(env)
|
||||
|
||||
env['LINKFLAGS'] = CLVar('-Wl,-no-undefined')
|
||||
|
||||
env['SHLIBPREFIX'] = 'cyg'
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
|
||||
env['IMPLIBPREFIX'] = 'lib'
|
||||
env['IMPLIBSUFFIX'] = '.dll.a'
|
||||
|
||||
# Variables used by versioned shared libraries
|
||||
# SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
|
||||
|
||||
env['_IMPLIB_PRE_SOURCES'] = _implib_pre_flags
|
||||
env['_IMPLIB_POST_SOURCES'] = _implib_post_flags
|
||||
env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH ' \
|
||||
'$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
env['LDMODULECOM'] = '$LDMODULE -o $TARGET $SHLINKFLAGS $__LDMODULEVERSIONFLAGS $__RPATH ' \
|
||||
'$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
|
||||
# Overwrite emitters. Cyglink does things differently when creating symlinks
|
||||
env['SHLIBEMITTER'] = [cyglink_lib_emitter, cyglink_shlib_symlink_emitter]
|
||||
env['LDMODULEEMITTER'] = [cyglink_ldmodule_emitter, cyglink_ldmod_symlink_emitter]
|
||||
|
||||
# This is the non versioned shlib filename
|
||||
# If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
|
||||
env['SHLIB_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_shlib_stem${IMPLIBSUFFIX}'
|
||||
env['LDMODULE_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${IMPLIBSUFFIX}'
|
||||
|
||||
env['SHLIB_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_shlib_stem${_SHLIB_IMPLIBSUFFIX}'
|
||||
env['LDMODULE_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${_LDMODULE_IMPLIBSUFFIX}'
|
||||
|
||||
env['_cyglink_shlibversion'] = cyglink_shlibversion
|
||||
env['_SHLIB_IMPLIBSUFFIX'] = '${_cyglink_shlibversion}${IMPLIBSUFFIX}'
|
||||
env['_SHLIBSUFFIX'] = '${_cyglink_shlibversion}${SHLIBSUFFIX}'
|
||||
|
||||
env['_cyglink_ldmodule_version'] = cyglink_ldmodule_version
|
||||
|
||||
env['_LDMODULESUFFIX'] = '${_cyglink_ldmodule_version}${LDMODULESUFFIX}'
|
||||
env['_LDMODULE_IMPLIBSUFFIX'] = '${_cyglink_ldmodule_version}${IMPLIBSUFFIX}'
|
||||
|
||||
# Remove variables set by default initialization which aren't needed/used by cyglink
|
||||
# these variables were set by gnulink but are not used in cyglink
|
||||
for rv in ['_SHLIBSONAME', '_LDMODULESONAME']:
|
||||
if rv in env:
|
||||
del env[rv]
|
||||
|
||||
|
||||
def exists(env):
|
||||
return gnulink.exists(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,45 @@
|
||||
# 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.
|
||||
|
||||
"""Initialization with a default tool list.
|
||||
|
||||
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.Tool
|
||||
|
||||
def generate(env):
|
||||
"""Add default tools."""
|
||||
for t in SCons.Tool.tool_list(env['PLATFORM'], env):
|
||||
SCons.Tool.Tool(t)(env)
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,94 @@
|
||||
# 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.
|
||||
|
||||
"""Tool-specific initialization for the filesystem tools.
|
||||
|
||||
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
|
||||
from SCons.Tool.install import copyFunc
|
||||
|
||||
copyToBuilder, copyAsBuilder = None, None
|
||||
|
||||
def copyto_emitter(target, source, env):
|
||||
""" changes the path of the source to be under the target (which
|
||||
are assumed to be directories.
|
||||
"""
|
||||
n_target = []
|
||||
|
||||
for t in target:
|
||||
n_target = n_target + [t.File( str( s ) ) for s in source]
|
||||
|
||||
return (n_target, source)
|
||||
|
||||
def copy_action_func(target, source, env):
|
||||
assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(list(map(str, target)),list(map(str, source)))
|
||||
|
||||
for t, s in zip(target, source):
|
||||
if copyFunc(t.get_path(), s.get_path(), env):
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def copy_action_str(target, source, env):
|
||||
return env.subst_target_source(env['COPYSTR'], 0, target, source)
|
||||
|
||||
copy_action = SCons.Action.Action( copy_action_func, copy_action_str )
|
||||
|
||||
def generate(env):
|
||||
try:
|
||||
env['BUILDERS']['CopyTo']
|
||||
env['BUILDERS']['CopyAs']
|
||||
except KeyError as e:
|
||||
global copyToBuilder
|
||||
if copyToBuilder is None:
|
||||
copyToBuilder = SCons.Builder.Builder(
|
||||
action = copy_action,
|
||||
target_factory = env.fs.Dir,
|
||||
source_factory = env.fs.Entry,
|
||||
multi = 1,
|
||||
emitter = [ copyto_emitter, ] )
|
||||
|
||||
global copyAsBuilder
|
||||
if copyAsBuilder is None:
|
||||
copyAsBuilder = SCons.Builder.Builder(
|
||||
action = copy_action,
|
||||
target_factory = env.fs.Entry,
|
||||
source_factory = env.fs.Entry )
|
||||
|
||||
env['BUILDERS']['CopyTo'] = copyToBuilder
|
||||
env['BUILDERS']['CopyAs'] = copyAsBuilder
|
||||
|
||||
env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"'
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
45
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/g++.py
Normal file
45
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/g++.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""SCons.Tool.g++
|
||||
|
||||
Tool-specific initialization for g++.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.gxx import *
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
56
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gas.py
Normal file
56
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gas.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""SCons.Tool.gas
|
||||
|
||||
Tool-specific initialization for as, the Gnu assembler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
try:
|
||||
as_module = __import__('as', globals(), locals(), [])
|
||||
except:
|
||||
as_module = __import__(__package__+'.as', globals(), locals(), ['*'])
|
||||
|
||||
assemblers = ['as', 'gas']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for as to an Environment."""
|
||||
as_module.generate(env)
|
||||
|
||||
env['AS'] = env.Detect(assemblers) or 'as'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(assemblers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
108
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gcc.py
Normal file
108
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gcc.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# 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.
|
||||
|
||||
"""SCons.Tool.gcc
|
||||
|
||||
Tool-specific initialization for gcc.
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from . import cc
|
||||
import re
|
||||
from subprocess import PIPE
|
||||
|
||||
import SCons.Util
|
||||
|
||||
compilers = ['gcc', 'cc']
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for gcc to an Environment."""
|
||||
|
||||
if 'CC' not in env:
|
||||
env['CC'] = env.Detect(compilers) or compilers[0]
|
||||
|
||||
cc.generate(env)
|
||||
|
||||
if env['PLATFORM'] in ['cygwin', 'win32']:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
else:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
||||
# determine compiler version
|
||||
version = detect_version(env, env['CC'])
|
||||
if version:
|
||||
env['CCVERSION'] = version
|
||||
|
||||
env['CCDEPFLAGS'] = '-MMD -MF ${TARGET}.d'
|
||||
env["NINJA_DEPFILE_PARSE_FORMAT"] = 'gcc'
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
# is executable, and is a GNU compiler (or accepts '--version' at least)
|
||||
return detect_version(env, env.Detect(env.get('CC', compilers)))
|
||||
|
||||
|
||||
def detect_version(env, cc):
|
||||
"""Return the version of the GNU compiler, or None if it is not a GNU compiler."""
|
||||
version = None
|
||||
cc = env.subst(cc)
|
||||
if not cc:
|
||||
return version
|
||||
|
||||
# -dumpversion was added in GCC 3.0. As long as we're supporting
|
||||
# GCC versions older than that, we should use --version and a
|
||||
# regular expression.
|
||||
# pipe = SCons.Action.scons_subproc_run(env, SCons.Util.CLVar(cc) + ['-dumpversion'],
|
||||
cp = SCons.Action.scons_subproc_run(
|
||||
env, SCons.Util.CLVar(cc) + ['--version'], stdout=PIPE
|
||||
)
|
||||
if cp.returncode:
|
||||
return version
|
||||
|
||||
# -dumpversion variant:
|
||||
# line = cp.stdout.strip()
|
||||
# --version variant:
|
||||
try:
|
||||
line = SCons.Util.to_str(cp.stdout.splitlines()[0])
|
||||
except IndexError:
|
||||
return version
|
||||
|
||||
# -dumpversion variant:
|
||||
# version = line
|
||||
# --version variant:
|
||||
match = re.search(r'[0-9]+(\.[0-9]+)+', line)
|
||||
if match:
|
||||
version = match.group(0)
|
||||
|
||||
return version
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,73 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
"""SCons.Tool.gnulink
|
||||
|
||||
Tool-specific initialization for the gnu linker.
|
||||
|
||||
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.Tool.linkCommon
|
||||
import SCons.Util
|
||||
import SCons.Tool
|
||||
|
||||
from . import link
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for gnulink to an Environment."""
|
||||
link.generate(env)
|
||||
|
||||
if env['PLATFORM'] == 'hpux':
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared -fPIC')
|
||||
|
||||
# __RPATH is set to $_RPATH in the platform specification if that
|
||||
# platform supports it.
|
||||
env['RPATHPREFIX'] = '-Wl,-rpath='
|
||||
env['RPATHSUFFIX'] = ''
|
||||
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
|
||||
|
||||
env['LIBLITERALPREFIX'] = ':'
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
# TODO: sync with link.smart_link() to choose a linker
|
||||
linkers = {'CXX': ['g++'], 'CC': ['gcc']}
|
||||
alltools = []
|
||||
for langvar, linktools in linkers.items():
|
||||
if langvar in env: # use CC over CXX when user specified CC but not CXX
|
||||
return SCons.Tool.FindTool(linktools, env)
|
||||
alltools.extend(linktools)
|
||||
return SCons.Tool.FindTool(alltools, env) # find CXX or CC
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
80
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gxx.py
Normal file
80
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/gxx.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# 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.
|
||||
|
||||
"""SCons.Tool.g++
|
||||
|
||||
Tool-specific initialization for g++.
|
||||
|
||||
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.Tool
|
||||
import SCons.Util
|
||||
|
||||
from . import gcc
|
||||
from . import cxx
|
||||
|
||||
compilers = ['g++']
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for g++ to an Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
if 'CXX' not in env:
|
||||
env['CXX'] = env.Detect(compilers) or compilers[0]
|
||||
|
||||
cxx.generate(env)
|
||||
|
||||
# platform specific settings
|
||||
if env['PLATFORM'] == 'aix':
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
elif env['PLATFORM'] == 'hpux':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'sunos':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
# determine compiler version
|
||||
version = gcc.detect_version(env, env['CXX'])
|
||||
if version:
|
||||
env['CXXVERSION'] = version
|
||||
|
||||
env['CCDEPFLAGS'] = '-MMD -MF ${TARGET}.d'
|
||||
env["NINJA_DEPFILE_PARSE_FORMAT"] = 'gcc'
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
# is executable, and is a GNU compiler (or accepts '--version' at least)
|
||||
return gcc.detect_version(env, env.Detect(env.get('CXX', compilers)))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,45 @@
|
||||
"""SCons.Tool.hpc++
|
||||
|
||||
Tool-specific initialization for c++ on HP/UX.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.hpcxx import *
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
53
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/hpcc.py
Normal file
53
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/hpcc.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""SCons.Tool.hpcc
|
||||
|
||||
Tool-specific initialization for HP aCC and cc.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Util
|
||||
|
||||
from . import cc
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for aCC & cc to an Environment."""
|
||||
cc.generate(env)
|
||||
|
||||
env['CXX'] = 'aCC'
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS +Z')
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('aCC')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,85 @@
|
||||
# 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.
|
||||
|
||||
"""SCons.Tool.hpc++
|
||||
|
||||
Tool-specific initialization for c++ on HP/UX.
|
||||
|
||||
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 os.path
|
||||
|
||||
import SCons.Util
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
||||
|
||||
|
||||
acc = None
|
||||
|
||||
# search for the acc compiler and linker front end
|
||||
|
||||
try:
|
||||
dirs = os.listdir('/opt')
|
||||
except OSError:
|
||||
# Not being able to read the directory because it doesn't exist
|
||||
# (IOError) or isn't readable (OSError) is okay.
|
||||
dirs = []
|
||||
|
||||
for dir in dirs:
|
||||
cc = '/opt/' + dir + '/bin/aCC'
|
||||
if os.path.exists(cc):
|
||||
acc = cc
|
||||
break
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for g++ to an Environment."""
|
||||
cplusplus.generate(env)
|
||||
|
||||
if acc:
|
||||
env['CXX'] = acc or 'aCC'
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z')
|
||||
# determine version of aCC
|
||||
with os.popen(acc + ' -V 2>&1') as p:
|
||||
line = p.readline().rstrip()
|
||||
if line.startswith('aCC: HP ANSI C++'):
|
||||
env['CXXVERSION'] = line.split()[-1]
|
||||
|
||||
if env['PLATFORM'] == 'cygwin':
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
|
||||
else:
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z')
|
||||
|
||||
def exists(env):
|
||||
return acc
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,72 @@
|
||||
"""SCons.Tool.hplink
|
||||
|
||||
Tool-specific initialization for the HP linker.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
#
|
||||
# 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.path
|
||||
|
||||
import SCons.Util
|
||||
|
||||
from . import link
|
||||
|
||||
ccLinker = None
|
||||
|
||||
# search for the acc compiler and linker front end
|
||||
|
||||
try:
|
||||
dirs = os.listdir('/opt')
|
||||
except OSError:
|
||||
# Not being able to read the directory because it doesn't exist
|
||||
# (IOError) or isn't readable (OSError) is okay.
|
||||
dirs = []
|
||||
|
||||
for dir in dirs:
|
||||
linker = '/opt/' + dir + '/bin/aCC'
|
||||
if os.path.exists(linker):
|
||||
ccLinker = linker
|
||||
break
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age linker to
|
||||
an Environment.
|
||||
"""
|
||||
link.generate(env)
|
||||
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,+s -Wl,+vnocompatwarnings')
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -b')
|
||||
env['SHLIBSUFFIX'] = '.sl'
|
||||
|
||||
def exists(env):
|
||||
return ccLinker
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
59
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/icc.py
Normal file
59
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/icc.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""SCons.Tool.icc
|
||||
|
||||
Tool-specific initialization for the OS/2 icc 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.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import cc
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for the OS/2 to an Environment."""
|
||||
cc.generate(env)
|
||||
|
||||
env['CC'] = 'icc'
|
||||
env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
|
||||
env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
|
||||
env['CPPDEFPREFIX'] = '/D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '/I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['CFILESUFFIX'] = '.c'
|
||||
env['CXXFILESUFFIX'] = '.cc'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('icc')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
52
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/icl.py
Normal file
52
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/icl.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""SCons.Tool.icl
|
||||
|
||||
Tool-specific initialization for the Intel C/C++ 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.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool.intelc
|
||||
|
||||
# This has been completely superseded by intelc.py, which can
|
||||
# handle both Windows and Linux versions.
|
||||
|
||||
def generate(*args, **kw):
|
||||
"""Add Builders and construction variables for icl to an Environment."""
|
||||
return SCons.Tool.intelc.generate(*args, **kw)
|
||||
|
||||
def exists(*args, **kw):
|
||||
return SCons.Tool.intelc.exists(*args, **kw)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,60 @@
|
||||
"""SCons.Tool.ilink32
|
||||
|
||||
XXX
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Tool.bcc32
|
||||
import SCons.Util
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for Borland ilink to an
|
||||
Environment."""
|
||||
SCons.Tool.createSharedLibBuilder(env)
|
||||
SCons.Tool.createProgBuilder(env)
|
||||
|
||||
env['LINK'] = '$CC'
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('')
|
||||
env['LINKCOM'] = '$LINK -q $LINKFLAGS -e$TARGET $SOURCES $LIBS'
|
||||
env['LIBDIRPREFIX']=''
|
||||
env['LIBDIRSUFFIX']=''
|
||||
env['LIBLINKPREFIX']=''
|
||||
env['LIBLINKSUFFIX']='$LIBSUFFIX'
|
||||
|
||||
|
||||
def exists(env):
|
||||
# Uses bcc32 to do linking as it generally knows where the standard
|
||||
# LIBS are and set up the linking correctly
|
||||
return SCons.Tool.bcc32.findIt('bcc32', env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
510
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/install.py
Normal file
510
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/install.py
Normal file
@@ -0,0 +1,510 @@
|
||||
# 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.
|
||||
|
||||
""" Tool-specific initialization for the install tool.
|
||||
|
||||
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 os
|
||||
import stat
|
||||
from shutil import copy2, copystat
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
from SCons.Subst import SUBST_RAW
|
||||
from SCons.Tool.linkCommon import (
|
||||
StringizeLibSymlinks,
|
||||
CreateLibSymlinks,
|
||||
EmitLibSymlinks,
|
||||
)
|
||||
|
||||
# We keep track of *all* installed files.
|
||||
_INSTALLED_FILES = []
|
||||
_UNIQUE_INSTALLED_FILES = None
|
||||
|
||||
class CopytreeError(OSError):
|
||||
pass
|
||||
|
||||
|
||||
def scons_copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
|
||||
ignore_dangling_symlinks=False, dirs_exist_ok=False):
|
||||
"""Recursively copy a directory tree, SCons version.
|
||||
|
||||
This is a modified copy of the Python 3.7 shutil.copytree function.
|
||||
SCons update: dirs_exist_ok dictates whether to raise an
|
||||
exception in case dst or any missing parent directory already
|
||||
exists. Implementation depends on os.makedirs having a similar
|
||||
flag, which it has since Python 3.2. This version also raises an
|
||||
SCons-defined exception rather than the one defined locally to shtuil.
|
||||
This version uses a change from Python 3.8.
|
||||
TODO: we can remove this forked copy once the minimum Py version is 3.8.
|
||||
|
||||
If exception(s) occur, an Error is raised with a list of reasons.
|
||||
|
||||
If the optional symlinks flag is true, symbolic links in the
|
||||
source tree result in symbolic links in the destination tree; if
|
||||
it is false, the contents of the files pointed to by symbolic
|
||||
links are copied. If the file pointed by the symlink doesn't
|
||||
exist, an exception will be added in the list of errors raised in
|
||||
an Error exception at the end of the copy process.
|
||||
|
||||
You can set the optional ignore_dangling_symlinks flag to true if you
|
||||
want to silence this exception. Notice that this has no effect on
|
||||
platforms that don't support os.symlink.
|
||||
|
||||
The optional ignore argument is a callable. If given, it
|
||||
is called with the `src` parameter, which is the directory
|
||||
being visited by copytree(), and `names` which is the list of
|
||||
`src` contents, as returned by os.listdir():
|
||||
|
||||
callable(src, names) -> ignored_names
|
||||
|
||||
Since copytree() is called recursively, the callable will be
|
||||
called once for each directory that is copied. It returns a
|
||||
list of names relative to the `src` directory that should
|
||||
not be copied.
|
||||
|
||||
The optional copy_function argument is a callable that will be used
|
||||
to copy each file. It will be called with the source path and the
|
||||
destination path as arguments. By default, copy2() is used, but any
|
||||
function that supports the same signature (like copy()) can be used.
|
||||
|
||||
"""
|
||||
names = os.listdir(src)
|
||||
if ignore is not None:
|
||||
ignored_names = ignore(src, names)
|
||||
else:
|
||||
ignored_names = set()
|
||||
|
||||
os.makedirs(dst, exist_ok=dirs_exist_ok)
|
||||
errors = []
|
||||
for name in names:
|
||||
if name in ignored_names:
|
||||
continue
|
||||
srcname = os.path.join(src, name)
|
||||
dstname = os.path.join(dst, name)
|
||||
try:
|
||||
if os.path.islink(srcname):
|
||||
linkto = os.readlink(srcname)
|
||||
if symlinks:
|
||||
# We can't just leave it to `copy_function` because legacy
|
||||
# code with a custom `copy_function` may rely on copytree
|
||||
# doing the right thing.
|
||||
os.symlink(linkto, dstname)
|
||||
copystat(srcname, dstname, follow_symlinks=not symlinks)
|
||||
else:
|
||||
# ignore dangling symlink if the flag is on
|
||||
if not os.path.exists(linkto) and ignore_dangling_symlinks:
|
||||
continue
|
||||
# otherwise let the copy occurs. copy2 will raise an error
|
||||
if os.path.isdir(srcname):
|
||||
scons_copytree(srcname, dstname, symlinks=symlinks,
|
||||
ignore=ignore, copy_function=copy_function,
|
||||
ignore_dangling_symlinks=ignore_dangling_symlinks,
|
||||
dirs_exist_ok=dirs_exist_ok)
|
||||
else:
|
||||
copy_function(srcname, dstname)
|
||||
elif os.path.isdir(srcname):
|
||||
scons_copytree(srcname, dstname, symlinks=symlinks,
|
||||
ignore=ignore, copy_function=copy_function,
|
||||
ignore_dangling_symlinks=ignore_dangling_symlinks,
|
||||
dirs_exist_ok=dirs_exist_ok)
|
||||
else:
|
||||
# Will raise a SpecialFileError for unsupported file types
|
||||
copy_function(srcname, dstname)
|
||||
# catch the Error from the recursive copytree so that we can
|
||||
# continue with other files
|
||||
except CopytreeError as err: # SCons change
|
||||
errors.extend(err.args[0])
|
||||
except OSError as why:
|
||||
errors.append((srcname, dstname, str(why)))
|
||||
try:
|
||||
copystat(src, dst)
|
||||
except OSError as why:
|
||||
# Copying file access times may fail on Windows
|
||||
if getattr(why, 'winerror', None) is None:
|
||||
errors.append((src, dst, str(why)))
|
||||
if errors:
|
||||
raise CopytreeError(errors) # SCons change
|
||||
return dst
|
||||
|
||||
#
|
||||
# Functions doing the actual work of the Install Builder.
|
||||
#
|
||||
def copyFunc(dest, source, env):
|
||||
"""Install a source file or directory into a destination by copying.
|
||||
|
||||
Mode/permissions bits will be copied as well, except that the target
|
||||
will be made writable.
|
||||
|
||||
Returns:
|
||||
POSIX-style error code - 0 for success, non-zero for fail
|
||||
"""
|
||||
if os.path.isdir(source):
|
||||
if os.path.exists(dest):
|
||||
if not os.path.isdir(dest):
|
||||
raise SCons.Errors.UserError("cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)))
|
||||
else:
|
||||
parent = os.path.split(dest)[0]
|
||||
if not os.path.exists(parent):
|
||||
os.makedirs(parent)
|
||||
scons_copytree(source, dest, dirs_exist_ok=True)
|
||||
else:
|
||||
copy2(source, dest)
|
||||
st = os.stat(source)
|
||||
os.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
|
||||
|
||||
return 0
|
||||
|
||||
#
|
||||
# Functions doing the actual work of the InstallVersionedLib Builder.
|
||||
#
|
||||
def copyFuncVersionedLib(dest, source, env):
|
||||
"""Install a versioned library into a destination by copying.
|
||||
|
||||
Any required symbolic links for other library names are created.
|
||||
|
||||
Mode/permissions bits will be copied as well, except that the target
|
||||
will be made writable.
|
||||
|
||||
Returns:
|
||||
POSIX-style error code - 0 for success, non-zero for fail
|
||||
"""
|
||||
if os.path.isdir(source):
|
||||
raise SCons.Errors.UserError("cannot install directory `%s' as a version library" % str(source) )
|
||||
else:
|
||||
# remove the link if it is already there
|
||||
try:
|
||||
os.remove(dest)
|
||||
except:
|
||||
pass
|
||||
copy2(source, dest)
|
||||
st = os.stat(source)
|
||||
os.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
|
||||
installShlibLinks(dest, source, env)
|
||||
|
||||
return 0
|
||||
|
||||
def listShlibLinksToInstall(dest, source, env):
|
||||
install_links = []
|
||||
source = env.arg2nodes(source)
|
||||
dest = env.fs.File(dest)
|
||||
install_dir = dest.get_dir()
|
||||
for src in source:
|
||||
symlinks = getattr(getattr(src, 'attributes', None), 'shliblinks', None)
|
||||
if symlinks:
|
||||
for link, linktgt in symlinks:
|
||||
link_base = os.path.basename(link.get_path())
|
||||
linktgt_base = os.path.basename(linktgt.get_path())
|
||||
install_link = env.fs.File(link_base, install_dir)
|
||||
install_linktgt = env.fs.File(linktgt_base, install_dir)
|
||||
install_links.append((install_link, install_linktgt))
|
||||
return install_links
|
||||
|
||||
def installShlibLinks(dest, source, env):
|
||||
"""If we are installing a versioned shared library create the required links."""
|
||||
Verbose = False
|
||||
symlinks = listShlibLinksToInstall(dest, source, env)
|
||||
if Verbose:
|
||||
print(f'installShlibLinks: symlinks={StringizeLibSymlinks(symlinks)!r}')
|
||||
if symlinks:
|
||||
CreateLibSymlinks(env, symlinks)
|
||||
return
|
||||
|
||||
def installFunc(target, source, env):
|
||||
"""Install a source file into a target.
|
||||
|
||||
Uses the function specified in the INSTALL construction variable.
|
||||
|
||||
Returns:
|
||||
POSIX-style error code - 0 for success, non-zero for fail
|
||||
"""
|
||||
|
||||
try:
|
||||
install = env['INSTALL']
|
||||
except KeyError:
|
||||
raise SCons.Errors.UserError('Missing INSTALL construction variable.')
|
||||
|
||||
assert len(target) == len(source), (
|
||||
"Installing source %s into target %s: "
|
||||
"target and source lists must have same length."
|
||||
% (list(map(str, source)), list(map(str, target)))
|
||||
)
|
||||
for t, s in zip(target, source):
|
||||
if install(t.get_path(), s.get_path(), env):
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def installFuncVersionedLib(target, source, env):
|
||||
"""Install a versioned library into a target.
|
||||
|
||||
Uses the function specified in the INSTALL construction variable.
|
||||
|
||||
Returns:
|
||||
POSIX-style error code - 0 for success, non-zero for fail
|
||||
"""
|
||||
|
||||
try:
|
||||
install = env['INSTALLVERSIONEDLIB']
|
||||
except KeyError:
|
||||
raise SCons.Errors.UserError(
|
||||
'Missing INSTALLVERSIONEDLIB construction variable.'
|
||||
)
|
||||
|
||||
assert len(target) == len(source), (
|
||||
"Installing source %s into target %s: "
|
||||
"target and source lists must have same length."
|
||||
% (list(map(str, source)), list(map(str, target)))
|
||||
)
|
||||
for t, s in zip(target, source):
|
||||
if hasattr(t.attributes, 'shlibname'):
|
||||
tpath = os.path.join(t.get_dir(), t.attributes.shlibname)
|
||||
else:
|
||||
tpath = t.get_path()
|
||||
if install(tpath, s.get_path(), env):
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def stringFunc(target, source, env):
|
||||
installstr = env.get('INSTALLSTR')
|
||||
if installstr:
|
||||
return env.subst_target_source(installstr, SUBST_RAW, target, source)
|
||||
target = str(target[0])
|
||||
source = str(source[0])
|
||||
if os.path.isdir(source):
|
||||
type = 'directory'
|
||||
else:
|
||||
type = 'file'
|
||||
return 'Install %s: "%s" as "%s"' % (type, source, target)
|
||||
|
||||
#
|
||||
# Emitter functions
|
||||
#
|
||||
def add_targets_to_INSTALLED_FILES(target, source, env):
|
||||
""" An emitter that adds all target files to the list stored in the
|
||||
_INSTALLED_FILES global variable. This way all installed files of one
|
||||
scons call will be collected.
|
||||
"""
|
||||
global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES
|
||||
_INSTALLED_FILES.extend(target)
|
||||
|
||||
_UNIQUE_INSTALLED_FILES = None
|
||||
return (target, source)
|
||||
|
||||
def add_versioned_targets_to_INSTALLED_FILES(target, source, env):
|
||||
""" An emitter that adds all target files to the list stored in the
|
||||
_INSTALLED_FILES global variable. This way all installed files of one
|
||||
scons call will be collected.
|
||||
"""
|
||||
global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES
|
||||
Verbose = False
|
||||
_INSTALLED_FILES.extend(target)
|
||||
if Verbose:
|
||||
print(f"add_versioned_targets_to_INSTALLED_FILES: target={list(map(str, target))!r}")
|
||||
symlinks = listShlibLinksToInstall(target[0], source, env)
|
||||
if symlinks:
|
||||
EmitLibSymlinks(env, symlinks, target[0])
|
||||
_UNIQUE_INSTALLED_FILES = None
|
||||
return (target, source)
|
||||
|
||||
class DESTDIR_factory:
|
||||
""" A node factory, where all files will be relative to the dir supplied
|
||||
in the constructor.
|
||||
"""
|
||||
def __init__(self, env, dir):
|
||||
self.env = env
|
||||
self.dir = env.arg2nodes( dir, env.fs.Dir )[0]
|
||||
|
||||
def Entry(self, name):
|
||||
name = SCons.Util.make_path_relative(name)
|
||||
return self.dir.Entry(name)
|
||||
|
||||
def Dir(self, name):
|
||||
name = SCons.Util.make_path_relative(name)
|
||||
return self.dir.Dir(name)
|
||||
|
||||
#
|
||||
# The Builder Definition
|
||||
#
|
||||
install_action = SCons.Action.Action(installFunc, stringFunc)
|
||||
installas_action = SCons.Action.Action(installFunc, stringFunc)
|
||||
installVerLib_action = SCons.Action.Action(installFuncVersionedLib, stringFunc)
|
||||
|
||||
BaseInstallBuilder = None
|
||||
|
||||
def InstallBuilderWrapper(env, target=None, source=None, dir=None, **kw):
|
||||
if target and dir:
|
||||
import SCons.Errors
|
||||
raise SCons.Errors.UserError("Both target and dir defined for Install(), only one may be defined.")
|
||||
if not dir:
|
||||
dir=target
|
||||
|
||||
import SCons.Script
|
||||
install_sandbox = SCons.Script.GetOption('install_sandbox')
|
||||
if install_sandbox:
|
||||
target_factory = DESTDIR_factory(env, install_sandbox)
|
||||
else:
|
||||
target_factory = env.fs
|
||||
|
||||
try:
|
||||
dnodes = env.arg2nodes(dir, target_factory.Dir)
|
||||
except TypeError:
|
||||
raise SCons.Errors.UserError("Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir))
|
||||
sources = env.arg2nodes(source, env.fs.Entry)
|
||||
tgt = []
|
||||
for dnode in dnodes:
|
||||
for src in sources:
|
||||
# Prepend './' so the lookup doesn't interpret an initial
|
||||
# '#' on the file name portion as meaning the Node should
|
||||
# be relative to the top-level SConstruct directory.
|
||||
target = env.fs.Entry('.'+os.sep+src.name, dnode)
|
||||
tgt.extend(BaseInstallBuilder(env, target, src, **kw))
|
||||
return tgt
|
||||
|
||||
|
||||
def InstallAsBuilderWrapper(env, target=None, source=None, **kw):
|
||||
result = []
|
||||
for src, tgt in map(lambda x, y: (x, y), source, target):
|
||||
result.extend(BaseInstallBuilder(env, tgt, src, **kw))
|
||||
return result
|
||||
|
||||
BaseVersionedInstallBuilder = None
|
||||
|
||||
|
||||
def InstallVersionedBuilderWrapper(env, target=None, source=None, dir=None, **kw):
|
||||
if target and dir:
|
||||
import SCons.Errors
|
||||
raise SCons.Errors.UserError("Both target and dir defined for Install(), only one may be defined.")
|
||||
if not dir:
|
||||
dir=target
|
||||
|
||||
import SCons.Script
|
||||
install_sandbox = SCons.Script.GetOption('install_sandbox')
|
||||
if install_sandbox:
|
||||
target_factory = DESTDIR_factory(env, install_sandbox)
|
||||
else:
|
||||
target_factory = env.fs
|
||||
|
||||
try:
|
||||
dnodes = env.arg2nodes(dir, target_factory.Dir)
|
||||
except TypeError:
|
||||
raise SCons.Errors.UserError("Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir))
|
||||
sources = env.arg2nodes(source, env.fs.Entry)
|
||||
tgt = []
|
||||
for dnode in dnodes:
|
||||
for src in sources:
|
||||
# Prepend './' so the lookup doesn't interpret an initial
|
||||
# '#' on the file name portion as meaning the Node should
|
||||
# be relative to the top-level SConstruct directory.
|
||||
target = env.fs.Entry('.'+os.sep+src.name, dnode)
|
||||
tgt.extend(BaseVersionedInstallBuilder(env, target, src, **kw))
|
||||
return tgt
|
||||
|
||||
added = None
|
||||
|
||||
|
||||
def generate(env):
|
||||
|
||||
from SCons.Script import AddOption, GetOption
|
||||
global added
|
||||
if not added:
|
||||
added = 1
|
||||
AddOption('--install-sandbox',
|
||||
dest='install_sandbox',
|
||||
type="string",
|
||||
action="store",
|
||||
help='A directory under which all installed files will be placed.')
|
||||
|
||||
global BaseInstallBuilder
|
||||
if BaseInstallBuilder is None:
|
||||
install_sandbox = GetOption('install_sandbox')
|
||||
if install_sandbox:
|
||||
target_factory = DESTDIR_factory(env, install_sandbox)
|
||||
else:
|
||||
target_factory = env.fs
|
||||
|
||||
BaseInstallBuilder = SCons.Builder.Builder(
|
||||
action = install_action,
|
||||
target_factory = target_factory.Entry,
|
||||
source_factory = env.fs.Entry,
|
||||
multi = True,
|
||||
emitter = [ add_targets_to_INSTALLED_FILES, ],
|
||||
source_scanner = SCons.Scanner.ScannerBase({}, name='Install', recursive=False),
|
||||
name = 'InstallBuilder')
|
||||
|
||||
global BaseVersionedInstallBuilder
|
||||
if BaseVersionedInstallBuilder is None:
|
||||
install_sandbox = GetOption('install_sandbox')
|
||||
if install_sandbox:
|
||||
target_factory = DESTDIR_factory(env, install_sandbox)
|
||||
else:
|
||||
target_factory = env.fs
|
||||
|
||||
BaseVersionedInstallBuilder = SCons.Builder.Builder(
|
||||
action = installVerLib_action,
|
||||
target_factory = target_factory.Entry,
|
||||
source_factory = env.fs.Entry,
|
||||
multi = True,
|
||||
emitter = [ add_versioned_targets_to_INSTALLED_FILES, ],
|
||||
name = 'InstallVersionedBuilder')
|
||||
|
||||
env['BUILDERS']['_InternalInstall'] = InstallBuilderWrapper
|
||||
env['BUILDERS']['_InternalInstallAs'] = InstallAsBuilderWrapper
|
||||
env['BUILDERS']['_InternalInstallVersionedLib'] = InstallVersionedBuilderWrapper
|
||||
|
||||
# We'd like to initialize this doing something like the following,
|
||||
# but there isn't yet support for a ${SOURCE.type} expansion that
|
||||
# will print "file" or "directory" depending on what's being
|
||||
# installed. For now we punt by not initializing it, and letting
|
||||
# the stringFunc() that we put in the action fall back to the
|
||||
# hand-crafted default string if it's not set.
|
||||
#
|
||||
#try:
|
||||
# env['INSTALLSTR']
|
||||
#except KeyError:
|
||||
# env['INSTALLSTR'] = 'Install ${SOURCE.type}: "$SOURCES" as "$TARGETS"'
|
||||
|
||||
try:
|
||||
env['INSTALL']
|
||||
except KeyError:
|
||||
env['INSTALL'] = copyFunc
|
||||
|
||||
try:
|
||||
env['INSTALLVERSIONEDLIB']
|
||||
except KeyError:
|
||||
env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
617
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/intelc.py
Normal file
617
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/intelc.py
Normal file
@@ -0,0 +1,617 @@
|
||||
# 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.
|
||||
|
||||
"""Tool-specific initialization for the Intel C/C++ compiler.
|
||||
|
||||
Supports Linux and Windows compilers, v7 and up.
|
||||
|
||||
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 glob
|
||||
import math
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
|
||||
is_windows = sys.platform == 'win32'
|
||||
is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or
|
||||
('PROCESSOR_ARCHITEW6432' in os.environ and
|
||||
os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64'))
|
||||
is_linux = sys.platform.startswith('linux')
|
||||
is_mac = sys.platform == 'darwin'
|
||||
|
||||
if is_windows:
|
||||
import SCons.Tool.msvc
|
||||
elif is_linux:
|
||||
import SCons.Tool.gcc
|
||||
elif is_mac:
|
||||
import SCons.Tool.gcc
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
# Exceptions for this tool
|
||||
class IntelCError(SCons.Errors.InternalError):
|
||||
pass
|
||||
class MissingRegistryError(IntelCError): # missing registry entry
|
||||
pass
|
||||
class MissingDirError(IntelCError): # dir not found
|
||||
pass
|
||||
class NoRegistryModuleError(IntelCError): # can't read registry at all
|
||||
pass
|
||||
|
||||
def linux_ver_normalize(vstr):
|
||||
"""Normalize a Linux compiler version number.
|
||||
Intel changed from "80" to "9.0" in 2005, so we assume if the number
|
||||
is greater than 60 it's an old-style number and otherwise new-style.
|
||||
Always returns an old-style float like 80 or 90 for compatibility with Windows.
|
||||
Shades of Y2K!"""
|
||||
# Check for version number like 9.1.026: return 91.026
|
||||
# XXX needs to be updated for 2011+ versions (like 2011.11.344 which is compiler v12.1.5)
|
||||
m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr)
|
||||
if m:
|
||||
vmaj,vmin,build = m.groups()
|
||||
return float(vmaj) * 10. + float(vmin) + float(build) / 1000.
|
||||
else:
|
||||
f = float(vstr)
|
||||
if is_windows:
|
||||
return f
|
||||
else:
|
||||
if f < 60: return f * 10.0
|
||||
else: return f
|
||||
|
||||
def check_abi(abi):
|
||||
"""Check for valid ABI (application binary interface) name,
|
||||
and map into canonical one"""
|
||||
if not abi:
|
||||
return None
|
||||
abi = abi.lower()
|
||||
# valid_abis maps input name to canonical name
|
||||
if is_windows:
|
||||
valid_abis = {'ia32' : 'ia32',
|
||||
'x86' : 'ia32',
|
||||
'ia64' : 'ia64',
|
||||
'em64t' : 'em64t',
|
||||
'amd64' : 'em64t'}
|
||||
if is_linux:
|
||||
valid_abis = {'ia32' : 'ia32',
|
||||
'x86' : 'ia32',
|
||||
'x86_64' : 'x86_64',
|
||||
'em64t' : 'x86_64',
|
||||
'amd64' : 'x86_64'}
|
||||
if is_mac:
|
||||
valid_abis = {'ia32' : 'ia32',
|
||||
'x86' : 'ia32',
|
||||
'x86_64' : 'x86_64',
|
||||
'em64t' : 'x86_64'}
|
||||
try:
|
||||
abi = valid_abis[abi]
|
||||
except KeyError:
|
||||
raise SCons.Errors.UserError("Intel compiler: Invalid ABI %s, valid values are %s"% \
|
||||
(abi, list(valid_abis.keys())))
|
||||
return abi
|
||||
|
||||
def get_version_from_list(v, vlist):
|
||||
"""See if we can match v (string) in vlist (list of strings)
|
||||
Linux has to match in a fuzzy way."""
|
||||
if is_windows:
|
||||
# Simple case, just find it in the list
|
||||
if v in vlist: return v
|
||||
else: return None
|
||||
else:
|
||||
# Fuzzy match: normalize version number first, but still return
|
||||
# original non-normalized form.
|
||||
fuzz = 0.001
|
||||
for vi in vlist:
|
||||
if math.fabs(linux_ver_normalize(vi) - linux_ver_normalize(v)) < fuzz:
|
||||
return vi
|
||||
# Not found
|
||||
return None
|
||||
|
||||
def get_intel_registry_value(valuename, version=None, abi=None):
|
||||
"""
|
||||
Return a value from the Intel compiler registry tree. (Windows only)
|
||||
"""
|
||||
# Open the key:
|
||||
if is_win64:
|
||||
K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
|
||||
else:
|
||||
K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
|
||||
try:
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
|
||||
except SCons.Util.RegError:
|
||||
# For version 13 and later, check UUID subkeys for valuename
|
||||
if is_win64:
|
||||
K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper()
|
||||
else:
|
||||
K = 'Software\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper()
|
||||
try:
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
|
||||
uuid = SCons.Util.RegQueryValueEx(k, 'SubKey')[0]
|
||||
|
||||
if is_win64:
|
||||
K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++"
|
||||
else:
|
||||
K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++"
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
|
||||
|
||||
try:
|
||||
v = SCons.Util.RegQueryValueEx(k, valuename)[0]
|
||||
return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
|
||||
except SCons.Util.RegError:
|
||||
if abi.upper() == 'EM64T':
|
||||
abi = 'em64t_native'
|
||||
if is_win64:
|
||||
K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper()
|
||||
else:
|
||||
K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper()
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
|
||||
|
||||
try:
|
||||
v = SCons.Util.RegQueryValueEx(k, valuename)[0]
|
||||
return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
|
||||
except SCons.Util.RegError:
|
||||
raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
|
||||
|
||||
except (SCons.Util.RegError, OSError):
|
||||
raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
|
||||
|
||||
# Get the value:
|
||||
try:
|
||||
v = SCons.Util.RegQueryValueEx(k, valuename)[0]
|
||||
return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
|
||||
except SCons.Util.RegError:
|
||||
raise MissingRegistryError("%s\\%s was not found in the registry."%(K, valuename))
|
||||
|
||||
|
||||
def get_all_compiler_versions():
|
||||
"""Returns a sorted list of strings, like "70" or "80" or "9.0"
|
||||
with most recent compiler version first.
|
||||
"""
|
||||
versions=[]
|
||||
if is_windows:
|
||||
if is_win64:
|
||||
keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++'
|
||||
else:
|
||||
keyname = 'Software\\Intel\\Compilers\\C++'
|
||||
try:
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
|
||||
keyname)
|
||||
except OSError:
|
||||
# For version 13 or later, check for default instance UUID
|
||||
if is_win64:
|
||||
keyname = 'Software\\WoW6432Node\\Intel\\Suites'
|
||||
else:
|
||||
keyname = 'Software\\Intel\\Suites'
|
||||
try:
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
|
||||
keyname)
|
||||
except OSError:
|
||||
return []
|
||||
i = 0
|
||||
versions = []
|
||||
try:
|
||||
while i < 100:
|
||||
subkey = SCons.Util.RegEnumKey(k, i) # raises SConsEnvironmentError
|
||||
# Check that this refers to an existing dir.
|
||||
# This is not 100% perfect but should catch common
|
||||
# installation issues like when the compiler was installed
|
||||
# and then the install directory deleted or moved (rather
|
||||
# than uninstalling properly), so the registry values
|
||||
# are still there.
|
||||
if subkey == 'Defaults': # Ignore default instances
|
||||
i = i + 1
|
||||
continue
|
||||
ok = False
|
||||
for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'):
|
||||
try:
|
||||
d = get_intel_registry_value('ProductDir', subkey, try_abi)
|
||||
except MissingRegistryError:
|
||||
continue # not found in reg, keep going
|
||||
if os.path.exists(d): ok = True
|
||||
if ok:
|
||||
versions.append(subkey)
|
||||
else:
|
||||
try:
|
||||
# Registry points to nonexistent dir. Ignore this
|
||||
# version.
|
||||
value = get_intel_registry_value('ProductDir', subkey, 'IA32')
|
||||
except MissingRegistryError as e:
|
||||
|
||||
# Registry key is left dangling (potentially
|
||||
# after uninstalling).
|
||||
|
||||
print("scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \
|
||||
"scons: *** It seems that the compiler was uninstalled and that the registry\n" \
|
||||
"scons: *** was not cleaned up properly.\n" % subkey)
|
||||
else:
|
||||
print("scons: *** Ignoring "+str(value))
|
||||
|
||||
i = i + 1
|
||||
except OSError:
|
||||
# no more subkeys
|
||||
pass
|
||||
elif is_linux or is_mac:
|
||||
for d in glob.glob('/opt/intel_cc_*'):
|
||||
# Typical dir here is /opt/intel_cc_80.
|
||||
m = re.search(r'cc_(.*)$', d)
|
||||
if m:
|
||||
versions.append(m.group(1))
|
||||
for d in glob.glob('/opt/intel/cc*/*'):
|
||||
# Typical dir here is /opt/intel/cc/9.0 for IA32,
|
||||
# /opt/intel/cce/9.0 for EMT64 (AMD64)
|
||||
m = re.search(r'([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
versions.append(m.group(1))
|
||||
for d in glob.glob('/opt/intel/Compiler/*'):
|
||||
# Typical dir here is /opt/intel/Compiler/11.1
|
||||
m = re.search(r'([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
versions.append(m.group(1))
|
||||
for d in glob.glob('/opt/intel/composerxe-*'):
|
||||
# Typical dir here is /opt/intel/composerxe-2011.4.184
|
||||
m = re.search(r'([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
versions.append(m.group(1))
|
||||
for d in glob.glob('/opt/intel/composer_xe_*'):
|
||||
# Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344
|
||||
# The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x
|
||||
m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
versions.append("%s.%s"%(m.group(1), m.group(2)))
|
||||
for d in glob.glob('/opt/intel/compilers_and_libraries_*'):
|
||||
# JPA: For the new version of Intel compiler 2016.1.
|
||||
m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
versions.append("%s.%s"%(m.group(1), m.group(2)))
|
||||
|
||||
def keyfunc(str):
|
||||
"""Given a dot-separated version string, return a tuple of ints representing it."""
|
||||
return [int(x) for x in str.split('.')]
|
||||
# split into ints, sort, then remove dups
|
||||
return sorted(SCons.Util.unique(versions), key=keyfunc, reverse=True)
|
||||
|
||||
def get_intel_compiler_top(version, abi):
|
||||
"""
|
||||
Return the main path to the top-level dir of the Intel compiler,
|
||||
using the given version.
|
||||
The compiler will be in <top>/bin/icl.exe (icc on linux),
|
||||
the include dir is <top>/include, etc.
|
||||
"""
|
||||
|
||||
if is_windows:
|
||||
if not SCons.Util.can_read_reg:
|
||||
raise NoRegistryModuleError("No Windows registry module was found")
|
||||
top = get_intel_registry_value('ProductDir', version, abi)
|
||||
archdir={'x86_64': 'intel64',
|
||||
'amd64' : 'intel64',
|
||||
'em64t' : 'intel64',
|
||||
'x86' : 'ia32',
|
||||
'i386' : 'ia32',
|
||||
'ia32' : 'ia32'
|
||||
}[abi] # for v11 and greater
|
||||
# pre-11, icl was in Bin. 11 and later, it's in Bin/<abi> apparently.
|
||||
if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \
|
||||
and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")) \
|
||||
and not os.path.exists(os.path.join(top, "Bin", archdir, "icl.exe")):
|
||||
raise MissingDirError("Can't find Intel compiler in %s" % top)
|
||||
elif is_mac or is_linux:
|
||||
def find_in_2008style_dir(version):
|
||||
# first dir is new (>=9.0) style, second is old (8.0) style.
|
||||
dirs=('/opt/intel/cc/%s', '/opt/intel_cc_%s')
|
||||
if abi == 'x86_64':
|
||||
dirs=('/opt/intel/cce/%s',) # 'e' stands for 'em64t', aka x86_64 aka amd64
|
||||
top=None
|
||||
for d in dirs:
|
||||
if os.path.exists(os.path.join(d%version, "bin", "icc")):
|
||||
top = d%version
|
||||
break
|
||||
return top
|
||||
def find_in_2010style_dir(version):
|
||||
dirs=('/opt/intel/Compiler/%s/*'%version)
|
||||
# typically /opt/intel/Compiler/11.1/064 (then bin/intel64/icc)
|
||||
dirs=glob.glob(dirs)
|
||||
# find highest sub-version number by reverse sorting and picking first existing one.
|
||||
dirs.sort()
|
||||
dirs.reverse()
|
||||
top=None
|
||||
for d in dirs:
|
||||
if (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or
|
||||
os.path.exists(os.path.join(d, "bin", "intel64", "icc"))):
|
||||
top = d
|
||||
break
|
||||
return top
|
||||
def find_in_2011style_dir(version):
|
||||
# The 2011 (compiler v12) dirs are inconsistent, so just redo the search from
|
||||
# get_all_compiler_versions and look for a match (search the newest form first)
|
||||
top=None
|
||||
for d in glob.glob('/opt/intel/composer_xe_*'):
|
||||
# Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344
|
||||
# The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x
|
||||
m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d)
|
||||
if m:
|
||||
cur_ver = "%s.%s"%(m.group(1), m.group(2))
|
||||
if cur_ver == version and \
|
||||
(os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or
|
||||
os.path.exists(os.path.join(d, "bin", "intel64", "icc"))):
|
||||
top = d
|
||||
break
|
||||
if not top:
|
||||
for d in glob.glob('/opt/intel/composerxe-*'):
|
||||
# Typical dir here is /opt/intel/composerxe-2011.4.184
|
||||
m = re.search(r'([0-9][0-9.]*)$', d)
|
||||
if m and m.group(1) == version and \
|
||||
(os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or
|
||||
os.path.exists(os.path.join(d, "bin", "intel64", "icc"))):
|
||||
top = d
|
||||
break
|
||||
return top
|
||||
def find_in_2016style_dir(version):
|
||||
# The 2016 (compiler v16) dirs are inconsistent from previous.
|
||||
top = None
|
||||
for d in glob.glob('/opt/intel/compilers_and_libraries_%s/linux'%version):
|
||||
if os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or os.path.exists(os.path.join(d, "bin", "intel64", "icc")):
|
||||
top = d
|
||||
break
|
||||
return top
|
||||
|
||||
top = find_in_2016style_dir(version) or find_in_2011style_dir(version) or find_in_2010style_dir(version) or find_in_2008style_dir(version)
|
||||
# print "INTELC: top=",top
|
||||
if not top:
|
||||
raise MissingDirError("Can't find version %s Intel compiler in %s (abi='%s')"%(version,top, abi))
|
||||
return top
|
||||
|
||||
|
||||
def generate(env, version=None, abi=None, topdir=None, verbose=0):
|
||||
r"""Add Builders and construction variables for Intel C/C++ compiler
|
||||
to an Environment.
|
||||
|
||||
Args:
|
||||
version (str): compiler version to use, like "80"
|
||||
abi (str): 'win32' or whatever Itanium version wants
|
||||
topdir (str): directory containing compiler tree, e.g.
|
||||
"c:\\Program Files\\Intel\\Compiler70".
|
||||
If `topdir` is used, `version` and `abi` are ignored.
|
||||
verbose: if >0, prints compiler version used.
|
||||
|
||||
"""
|
||||
if not (is_mac or is_linux or is_windows):
|
||||
# can't handle this platform
|
||||
return
|
||||
|
||||
if is_windows:
|
||||
SCons.Tool.msvc.generate(env)
|
||||
elif is_linux:
|
||||
SCons.Tool.gcc.generate(env)
|
||||
elif is_mac:
|
||||
SCons.Tool.gcc.generate(env)
|
||||
|
||||
# if version is unspecified, use latest
|
||||
vlist = get_all_compiler_versions()
|
||||
if not version:
|
||||
if vlist:
|
||||
version = vlist[0]
|
||||
else:
|
||||
# User may have specified '90' but we need to get actual dirname '9.0'.
|
||||
# get_version_from_list does that mapping.
|
||||
v = get_version_from_list(version, vlist)
|
||||
if not v:
|
||||
raise SCons.Errors.UserError("Invalid Intel compiler version %s: "%version + \
|
||||
"installed versions are %s"%(', '.join(vlist)))
|
||||
version = v
|
||||
|
||||
# if abi is unspecified, use ia32
|
||||
# alternatives are ia64 for Itanium, or amd64 or em64t or x86_64 (all synonyms here)
|
||||
abi = check_abi(abi)
|
||||
if abi is None:
|
||||
if is_mac or is_linux:
|
||||
# Check if we are on 64-bit linux, default to 64 then.
|
||||
uname_m = os.uname()[4]
|
||||
if uname_m == 'x86_64':
|
||||
abi = 'x86_64'
|
||||
else:
|
||||
abi = 'ia32'
|
||||
else:
|
||||
if is_win64:
|
||||
abi = 'em64t'
|
||||
else:
|
||||
abi = 'ia32'
|
||||
|
||||
if version and not topdir:
|
||||
try:
|
||||
topdir = get_intel_compiler_top(version, abi)
|
||||
except (SCons.Util.RegError, IntelCError):
|
||||
topdir = None
|
||||
|
||||
if not topdir:
|
||||
# Normally this is an error, but it might not be if the compiler is
|
||||
# on $PATH and the user is importing their env.
|
||||
class ICLTopDirWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
|
||||
if (
|
||||
((is_mac or is_linux) and not env.Detect('icc'))
|
||||
or (is_windows and not env.Detect('icl'))
|
||||
):
|
||||
SCons.Warnings.enableWarningClass(ICLTopDirWarning)
|
||||
SCons.Warnings.warn(
|
||||
ICLTopDirWarning,
|
||||
"Failed to find Intel compiler for version='%s', abi='%s'"
|
||||
% (str(version), str(abi)),
|
||||
)
|
||||
else:
|
||||
# should be cleaned up to say what this other version is
|
||||
# since in this case we have some other Intel compiler installed
|
||||
SCons.Warnings.enableWarningClass(ICLTopDirWarning)
|
||||
SCons.Warnings.warn(
|
||||
ICLTopDirWarning,
|
||||
"Can't find Intel compiler top dir for version='%s', abi='%s'"
|
||||
% (str(version), str(abi)),
|
||||
)
|
||||
|
||||
if topdir:
|
||||
archdir={'x86_64': 'intel64',
|
||||
'amd64' : 'intel64',
|
||||
'em64t' : 'intel64',
|
||||
'x86' : 'ia32',
|
||||
'i386' : 'ia32',
|
||||
'ia32' : 'ia32'
|
||||
}[abi] # for v11 and greater
|
||||
if os.path.exists(os.path.join(topdir, 'bin', archdir)):
|
||||
bindir="bin/%s"%archdir
|
||||
libdir="lib/%s"%archdir
|
||||
else:
|
||||
bindir="bin"
|
||||
libdir="lib"
|
||||
if verbose:
|
||||
print("Intel C compiler: using version %s (%g), abi %s, in '%s/%s'"%\
|
||||
(repr(version), linux_ver_normalize(version),abi,topdir,bindir))
|
||||
if is_linux:
|
||||
# Show the actual compiler version by running the compiler.
|
||||
os.system('%s/%s/icc --version'%(topdir,bindir))
|
||||
if is_mac:
|
||||
# Show the actual compiler version by running the compiler.
|
||||
os.system('%s/%s/icc --version'%(topdir,bindir))
|
||||
|
||||
env['INTEL_C_COMPILER_TOP'] = topdir
|
||||
if is_linux:
|
||||
paths={'INCLUDE' : 'include',
|
||||
'LIB' : libdir,
|
||||
'PATH' : bindir,
|
||||
'LD_LIBRARY_PATH' : libdir}
|
||||
for p, v in paths.items():
|
||||
env.PrependENVPath(p, os.path.join(topdir, v))
|
||||
if is_mac:
|
||||
paths={'INCLUDE' : 'include',
|
||||
'LIB' : libdir,
|
||||
'PATH' : bindir,
|
||||
'LD_LIBRARY_PATH' : libdir}
|
||||
for p, v in paths.items():
|
||||
env.PrependENVPath(p, os.path.join(topdir, v))
|
||||
if is_windows:
|
||||
# env key reg valname default subdir of top
|
||||
paths=(('INCLUDE', 'IncludeDir', 'Include'),
|
||||
('LIB' , 'LibDir', 'Lib'),
|
||||
('PATH' , 'BinDir', 'Bin'))
|
||||
# We are supposed to ignore version if topdir is set, so set
|
||||
# it to the emptry string if it's not already set.
|
||||
if version is None:
|
||||
version = ''
|
||||
# Each path has a registry entry, use that or default to subdir
|
||||
for p in paths:
|
||||
try:
|
||||
path=get_intel_registry_value(p[1], version, abi)
|
||||
# These paths may have $(ICInstallDir)
|
||||
# which needs to be substituted with the topdir.
|
||||
path=path.replace('$(ICInstallDir)', topdir + os.sep)
|
||||
except IntelCError:
|
||||
# Couldn't get it from registry: use default subdir of topdir
|
||||
env.PrependENVPath(p[0], os.path.join(topdir, p[2]))
|
||||
else:
|
||||
env.PrependENVPath(p[0], path.split(os.pathsep))
|
||||
# print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]]))
|
||||
|
||||
if is_windows:
|
||||
env['CC'] = 'icl'
|
||||
env['CXX'] = 'icl'
|
||||
env['LINK'] = 'xilink'
|
||||
else:
|
||||
env['CC'] = 'icc'
|
||||
env['CXX'] = 'icpc'
|
||||
# Don't reset LINK here;
|
||||
# use smart_link which should already be here from link.py.
|
||||
#env['LINK'] = '$CC'
|
||||
env['AR'] = 'xiar'
|
||||
env['LD'] = 'xild' # not used by default
|
||||
|
||||
# This is not the exact (detailed) compiler version,
|
||||
# just the major version as determined above or specified
|
||||
# by the user. It is a float like 80 or 90, in normalized form for Linux
|
||||
# (i.e. even for Linux 9.0 compiler, still returns 90 rather than 9.0)
|
||||
if version:
|
||||
env['INTEL_C_COMPILER_VERSION']=linux_ver_normalize(version)
|
||||
|
||||
if is_windows:
|
||||
# Look for license file dir
|
||||
# in system environment, registry, and default location.
|
||||
envlicdir = os.environ.get("INTEL_LICENSE_FILE", '')
|
||||
K = r'SOFTWARE\Intel\Licenses'
|
||||
try:
|
||||
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
|
||||
reglicdir = SCons.Util.RegQueryValueEx(k, "w_cpp")[0]
|
||||
except (AttributeError, SCons.Util.RegError):
|
||||
reglicdir = ""
|
||||
defaultlicdir = r'C:\Program Files\Common Files\Intel\Licenses'
|
||||
|
||||
licdir = None
|
||||
for ld in [envlicdir, reglicdir]:
|
||||
# If the string contains an '@', then assume it's a network
|
||||
# license (port@system) and good by definition.
|
||||
if ld and ('@' in ld or os.path.exists(ld)):
|
||||
licdir = ld
|
||||
break
|
||||
if not licdir:
|
||||
licdir = defaultlicdir
|
||||
if not os.path.exists(licdir):
|
||||
class ICLLicenseDirWarning(SCons.Warnings.SConsWarning):
|
||||
pass
|
||||
SCons.Warnings.enableWarningClass(ICLLicenseDirWarning)
|
||||
SCons.Warnings.warn(
|
||||
ICLLicenseDirWarning,
|
||||
"Intel license dir was not found. "
|
||||
"Tried using the INTEL_LICENSE_FILE environment variable "
|
||||
"(%s), the registry (%s) and the default path (%s). "
|
||||
"Using the default path as a last resort."
|
||||
% (envlicdir, reglicdir, defaultlicdir)
|
||||
)
|
||||
env['ENV']['INTEL_LICENSE_FILE'] = licdir
|
||||
|
||||
def exists(env):
|
||||
if not (is_mac or is_linux or is_windows):
|
||||
# can't handle this platform
|
||||
return 0
|
||||
|
||||
try:
|
||||
versions = get_all_compiler_versions()
|
||||
except (SCons.Util.RegError, IntelCError):
|
||||
versions = None
|
||||
detected = versions is not None and len(versions) > 0
|
||||
if not detected:
|
||||
# try env.Detect, maybe that will work
|
||||
if is_windows:
|
||||
return env.Detect('icl')
|
||||
elif is_linux:
|
||||
return env.Detect('icc')
|
||||
elif is_mac:
|
||||
return env.Detect('icc')
|
||||
return detected
|
||||
|
||||
# end of file
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
72
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/link.py
Normal file
72
nuitka/build/inline_copy/lib/scons-4.10.1/SCons/Tool/link.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Tool-specific initialization for the generic POSIX linker.
|
||||
|
||||
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.Tool
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
from SCons.Tool import createProgBuilder
|
||||
from SCons.Tool.linkCommon import smart_link
|
||||
from SCons.Tool.linkCommon.LoadableModule import setup_loadable_module_logic
|
||||
from SCons.Tool.linkCommon.SharedLibrary import setup_shared_lib_logic
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for gnulink to an Environment."""
|
||||
createProgBuilder(env)
|
||||
|
||||
setup_shared_lib_logic(env)
|
||||
setup_loadable_module_logic(env)
|
||||
|
||||
env['SMARTLINK'] = smart_link
|
||||
env['LINK'] = "$SMARTLINK"
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('')
|
||||
|
||||
# __RPATH is only set to something ($_RPATH typically) on platforms that support it.
|
||||
env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
|
||||
env['LIBDIRPREFIX'] = '-L'
|
||||
env['LIBDIRSUFFIX'] = ''
|
||||
env['_LIBFLAGS'] = '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__, LIBLITERALPREFIX)}'
|
||||
env['LIBLINKPREFIX'] = '-l'
|
||||
env['LIBLINKSUFFIX'] = ''
|
||||
|
||||
|
||||
def exists(env):
|
||||
# This module isn't really a Tool on its own, it's common logic for
|
||||
# other linkers.
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
@@ -0,0 +1,131 @@
|
||||
# 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.
|
||||
|
||||
from SCons.Tool import createLoadableModuleBuilder
|
||||
from .SharedLibrary import shlib_symlink_emitter
|
||||
from . import lib_emitter
|
||||
|
||||
|
||||
def ldmod_symlink_emitter(target, source, env, **kw):
|
||||
return shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE')
|
||||
|
||||
|
||||
def _get_ldmodule_stem(target, source, env, for_signature):
|
||||
"""
|
||||
Get the basename for a library (so for libxyz.so, return xyz)
|
||||
:param target:
|
||||
:param source:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return:
|
||||
"""
|
||||
target_name = str(target)
|
||||
ldmodule_prefix = env.subst('$LDMODULEPREFIX')
|
||||
ldmodule_suffix = env.subst("$_LDMODULESUFFIX")
|
||||
|
||||
if target_name.startswith(ldmodule_prefix):
|
||||
target_name = target_name[len(ldmodule_prefix):]
|
||||
|
||||
if target_name.endswith(ldmodule_suffix):
|
||||
target_name = target_name[:-len(ldmodule_suffix)]
|
||||
|
||||
return target_name
|
||||
|
||||
|
||||
def _ldmodule_soversion(target, source, env, for_signature):
|
||||
"""Function to determine what to use for SOVERSION"""
|
||||
|
||||
if 'SOVERSION' in env:
|
||||
return '.$SOVERSION'
|
||||
elif 'LDMODULEVERSION' in env:
|
||||
ldmod_version = env.subst('$LDMODULEVERSION')
|
||||
# We use only the most significant digit of LDMODULEVERSION
|
||||
return '.' + ldmod_version.split('.')[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def _ldmodule_soname(target, source, env, for_signature):
|
||||
if 'SONAME' in env:
|
||||
return '$SONAME'
|
||||
else:
|
||||
return "$LDMODULEPREFIX$_get_ldmodule_stem${LDMODULESUFFIX}$_LDMODULESOVERSION"
|
||||
|
||||
def _LDMODULEVERSION(target, source, env, for_signature):
|
||||
"""
|
||||
Return "." + version if it's set, otherwise just a blank
|
||||
"""
|
||||
value = env.subst('$LDMODULEVERSION', target=target, source=source)
|
||||
# print("_has_LDMODULEVERSION:%s"%value)
|
||||
if value:
|
||||
return "."+value
|
||||
else:
|
||||
return ""
|
||||
|
||||
def setup_loadable_module_logic(env):
|
||||
"""
|
||||
Just the logic for loadable modules
|
||||
|
||||
For most platforms, a loadable module is the same as a shared
|
||||
library. Platforms which are different can override these, but
|
||||
setting them the same means that LoadableModule works everywhere.
|
||||
|
||||
:param env:
|
||||
:return:
|
||||
"""
|
||||
|
||||
createLoadableModuleBuilder(env)
|
||||
|
||||
env['_get_ldmodule_stem'] = _get_ldmodule_stem
|
||||
env['_LDMODULESOVERSION'] = _ldmodule_soversion
|
||||
env['_LDMODULESONAME'] = _ldmodule_soname
|
||||
|
||||
env['LDMODULENAME'] = '${LDMODULEPREFIX}$_get_ldmodule_stem${_LDMODULESUFFIX}'
|
||||
|
||||
# This is the non versioned LDMODULE filename
|
||||
# If LDMODULEVERSION is defined then this will symlink to $LDMODULENAME
|
||||
env['LDMODULE_NOVERSION_SYMLINK'] = '$_get_shlib_dir${LDMODULEPREFIX}$_get_ldmodule_stem${LDMODULESUFFIX}'
|
||||
|
||||
# This is the sonamed file name
|
||||
# If LDMODULEVERSION is defined then this will symlink to $LDMODULENAME
|
||||
env['LDMODULE_SONAME_SYMLINK'] = '$_get_shlib_dir$_LDMODULESONAME'
|
||||
|
||||
env['_LDMODULEVERSION'] = _LDMODULEVERSION
|
||||
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME'
|
||||
|
||||
env['LDMODULEEMITTER'] = [lib_emitter, ldmod_symlink_emitter]
|
||||
|
||||
env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
|
||||
env['_LDMODULESUFFIX'] = '${LDMODULESUFFIX}${_LDMODULEVERSION}'
|
||||
env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
|
||||
|
||||
env['LDMODULE'] = '$SHLINK'
|
||||
|
||||
env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
|
||||
|
||||
env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES ' \
|
||||
'$_LIBDIRFLAGS $_LIBFLAGS '
|
||||
|
||||
env['LDMODULEVERSION'] = '$SHLIBVERSION'
|
||||
env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user