From d04f2b3a804ee5dca41608c7ff44404b681b8fc8 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 10 Dec 2022 17:08:12 -1000 Subject: Solution for Issue #4275 (Compilation db get's tmp file command line), also extending serveral APIs to allow specifying an overrides dictionary which would override (at the last minute) any envvar or potentially env TARGET/SOURCE when subst is being called a subst() or subst_list(). Tests created. Docs still need to be updated. --- SCons/Action.py | 14 +++++++------- SCons/ActionTests.py | 8 ++++---- SCons/Environment.py | 8 ++++---- SCons/Subst.py | 13 +++++++++++-- SCons/SubstTests.py | 15 +++++++++++++++ SCons/Tool/compilation_db.py | 9 +++++++++ 6 files changed, 50 insertions(+), 17 deletions(-) diff --git a/SCons/Action.py b/SCons/Action.py index 8151b2a..1f5e548 100644 --- a/SCons/Action.py +++ b/SCons/Action.py @@ -875,11 +875,11 @@ class CommandAction(_ActionAction): return ' '.join(map(str, self.cmd_list)) return str(self.cmd_list) - def process(self, target, source, env, executor=None): + def process(self, target, source, env, executor=None, overrides=False): if executor: - result = env.subst_list(self.cmd_list, 0, executor=executor) + result = env.subst_list(self.cmd_list, 0, executor=executor, overrides=overrides) else: - result = env.subst_list(self.cmd_list, 0, target, source) + result = env.subst_list(self.cmd_list, 0, target, source, overrides=overrides) silent = None ignore = None while True: @@ -896,18 +896,18 @@ class CommandAction(_ActionAction): pass return result, ignore, silent - def strfunction(self, target, source, env, executor=None): + def strfunction(self, target, source, env, executor=None, overrides=False): if self.cmdstr is None: return None if self.cmdstr is not _null: from SCons.Subst import SUBST_RAW if executor: - c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) + c = env.subst(self.cmdstr, SUBST_RAW, executor=executor, overrides=overrides) else: - c = env.subst(self.cmdstr, SUBST_RAW, target, source) + c = env.subst(self.cmdstr, SUBST_RAW, target, source, overrides=overrides) if c: return c - cmd_list, ignore, silent = self.process(target, source, env, executor) + cmd_list, ignore, silent = self.process(target, source, env, executor, overrides=overrides) if silent: return '' return _string_from_cmd_list(cmd_list[0]) diff --git a/SCons/ActionTests.py b/SCons/ActionTests.py index 0a7f25b..101953b 100644 --- a/SCons/ActionTests.py +++ b/SCons/ActionTests.py @@ -142,15 +142,15 @@ class Environment: self.d[k] = v # Just use the underlying scons_subst*() utility methods. - def subst(self, strSubst, raw=0, target=[], source=[], conv=None): + def subst(self, strSubst, raw=0, target=[], source=[], conv=None, overrides=False): return SCons.Subst.scons_subst(strSubst, self, raw, - target, source, self.d, conv=conv) + target, source, self.d, conv=conv, overrides=overrides) subst_target_source = subst - def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None): + def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None, overrides=False): return SCons.Subst.scons_subst_list(strSubst, self, raw, - target, source, self.d, conv=conv) + target, source, self.d, conv=conv, overrides=overrides) def __getitem__(self, item): return self.d[item] diff --git a/SCons/Environment.py b/SCons/Environment.py index 293447f..7212c89 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -481,7 +481,7 @@ class SubstitutionEnvironment: def lvars(self): return {} - def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None): + def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None, overrides=False): """Recursively interpolates construction variables from the Environment into the specified string, returning the expanded result. Construction variables are specified by a $ prefix @@ -496,7 +496,7 @@ class SubstitutionEnvironment: lvars['__env__'] = self if executor: lvars.update(executor.get_lvars()) - return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv) + return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv, overrides=overrides) def subst_kw(self, kw, raw=0, target=None, source=None): nkw = {} @@ -507,7 +507,7 @@ class SubstitutionEnvironment: nkw[k] = v return nkw - def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None): + def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None, overrides=False): """Calls through to SCons.Subst.scons_subst_list(). See the documentation for that function.""" gvars = self.gvars() @@ -515,7 +515,7 @@ class SubstitutionEnvironment: lvars['__env__'] = self if executor: lvars.update(executor.get_lvars()) - return SCons.Subst.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv) + return SCons.Subst.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv, overrides=overrides) def subst_path(self, path, target=None, source=None): """Substitute a path list, turning EntryProxies into Nodes diff --git a/SCons/Subst.py b/SCons/Subst.py index 7535772..645639b 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -804,7 +804,8 @@ _separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str) # space characters in the string result from the scons_subst() function. _space_sep = re.compile(r'[\t ]+(?![^{]*})') -def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None): + +def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None, overrides=False): """Expand a string or list containing construction variable substitutions. @@ -834,6 +835,10 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={ lvars = lvars.copy() lvars.update(d) + # Allow last ditch chance to override lvars + if overrides: + lvars.update(overrides) + # We're (most likely) going to eval() things. If Python doesn't # find a __builtins__ value in the global dictionary used for eval(), # it copies the current global values for you. Avoid this by @@ -882,7 +887,7 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={ return result -def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None): +def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None,overrides=False): """Substitute construction variables in a string (or list or other object) and separate the arguments into a command list. @@ -908,6 +913,10 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv lvars = lvars.copy() lvars.update(d) + # Allow caller to specify last ditch override of lvars + if overrides: + lvars.update(overrides) + # We're (most likely) going to eval() things. If Python doesn't # find a __builtins__ value in the global dictionary used for eval(), # it copies the current global values for you. Avoid this by diff --git a/SCons/SubstTests.py b/SCons/SubstTests.py index 1a203a0..16bd3c7 100644 --- a/SCons/SubstTests.py +++ b/SCons/SubstTests.py @@ -713,6 +713,14 @@ class CLVar_TestCase(unittest.TestCase): assert cmd_list[0][3] == "call", cmd_list[0][3] assert cmd_list[0][4] == "test", cmd_list[0][4] + + def test_subst_overriding_lvars_overrides(self): + """Test that optional passed arg overrides overrides gvars, and existing lvars.""" + env=DummyEnv({'XXX' : 'xxx'}) + result = scons_subst('$XXX', env, gvars=env.Dictionary(), overrides={'XXX': 'yyz'}) + assert result == 'yyz', result + + class scons_subst_list_TestCase(SubstTestCase): basic_cases = [ @@ -1102,6 +1110,13 @@ class scons_subst_list_TestCase(SubstTestCase): result = scons_subst_list('$XXX', env, gvars={'XXX' : 'yyy'}) assert result == [['yyy']], result + def test_subst_list_overriding_lvars_overrides(self): + """Test that optional passed arg overrides overrides gvars, and existing lvars.""" + env = DummyEnv({'XXX':'xxx'}) + result = scons_subst_list('$XXX', env, gvars=env.Dictionary(), overrides={'XXX': 'yyy'}) + assert result == [['yyy']], result + + class scons_subst_once_TestCase(unittest.TestCase): loc = { diff --git a/SCons/Tool/compilation_db.py b/SCons/Tool/compilation_db.py index 9e72fe9..a4954c1 100644 --- a/SCons/Tool/compilation_db.py +++ b/SCons/Tool/compilation_db.py @@ -34,6 +34,8 @@ import itertools import fnmatch import SCons +from SCons.Platform import TempFileMunge + from .cxx import CXXSuffixes from .cc import CSuffixes from .asm import ASSuffixes, ASPPSuffixes @@ -53,6 +55,7 @@ class __CompilationDbNode(SCons.Node.Python.Value): SCons.Node.Python.Value.__init__(self, value) self.Decider(changed_since_last_build_node) + def changed_since_last_build_node(child, target, prev_ni, node): """ Dummy decider to force always building""" return True @@ -103,6 +106,11 @@ def make_emit_compilation_DB_entry(comstr): return emit_compilation_db_entry +class CompDBTEMPFILE(TempFileMunge): + def __call__(self, target, source, env, for_signature): + return self.cmd + + def compilation_db_entry_action(target, source, env, **kw): """ Create a dictionary with evaluated command line, target, source @@ -119,6 +127,7 @@ def compilation_db_entry_action(target, source, env, **kw): target=env["__COMPILATIONDB_UOUTPUT"], source=env["__COMPILATIONDB_USOURCE"], env=env["__COMPILATIONDB_ENV"], + overrides={'TEMPFILE': CompDBTEMPFILE} ) entry = { -- cgit v0.12