From c94a185bf1ff9a20e31f9ff68f65a1eed50760b1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 15 Jun 2020 11:30:47 -0500 Subject: Fix value node when used as part of a build on python3 --- CHANGES.txt | 3 +++ SCons/Node/Python.py | 3 ++- test/Value/GetContent.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/Value/GetContent.py diff --git a/CHANGES.txt b/CHANGES.txt index 6fc1905..f8d57db 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,6 +13,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From Dirk Baechle: - Added Docker images for building and testing SCons. (issue #3585) + From Jason Kenny + - Fix python3 crash when Value node get_text_content when child content does not have decode() + From James Benton: - Improve Visual Studio solution/project generation code to add support for a per-variant cppflags. Intellisense can be affected by cppflags, diff --git a/SCons/Node/Python.py b/SCons/Node/Python.py index 68c6ee8..ab005df 100644 --- a/SCons/Node/Python.py +++ b/SCons/Node/Python.py @@ -144,7 +144,8 @@ class Value(SCons.Node.Node): ###TODO: something reasonable about universal newlines contents = str(self.value) for kid in self.children(None): - contents = contents + kid.get_contents().decode() + # Get csig() value of child as this is more efficent + contents = contents + kid.get_csig() return contents def get_contents(self): diff --git a/test/Value/GetContent.py b/test/Value/GetContent.py new file mode 100644 index 0000000..8fbbf29 --- /dev/null +++ b/test/Value/GetContent.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test the Value node as a build target +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +import SCons.Script +def null_build(target, source, env): + pass +env = DefaultEnvironment() +env['BUILDERS']['ValueBuilder'] = SCons.Builder.Builder( + action=SCons.Action.Action(null_build), + target_factory=SCons.Node.Python.Value, +) +v = env.ValueBuilder("myvalue",env.Dir("#")) +v[0].get_text_contents() +""") + +test.run() +test.pass_test() + -- cgit v0.12 From b091b2ede559c7288e404cd3990f7646e0e5bf69 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Wed, 21 Oct 2020 11:09:56 -0400 Subject: Fix invalid cache state when using SCons interactive mode SCons.Node.Node.clear() had code to clear cache-related state but it was only clearing a non-unused variable _calculated_sig. Fix this by clearing the three variables now used in practice by get_cachedir_bsig() and the functions that it calls: `cachedir_csig`, `cachesig`, and `contentsig`. Also reset `cached` to 0 because the task scheduler depends on it but doesn't reset it. --- CHANGES.txt | 2 ++ SCons/Node/FSTests.py | 8 ++++++++ SCons/Node/NodeTests.py | 2 ++ SCons/Node/__init__.py | 10 ++++++---- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1f1730c..4b66609 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -35,6 +35,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER User-facing behavior does not change with this fix (GH Issue #3726). - Fix occasional test failures caused by not being able to find a file or directory fixture when running multiple tests with multiple jobs. + - Fix incorrect cache hits and/or misses when running in interactive mode by having + SCons.Node.Node.clear() clear out all caching-related state. From Joachim Kuebart: - Suppress missing SConscript deprecation warning if `must_exist=False` diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py index 65cc363..05e8b2a 100644 --- a/SCons/Node/FSTests.py +++ b/SCons/Node/FSTests.py @@ -3722,6 +3722,14 @@ class clearTestCase(unittest.TestCase): assert not f.exists() assert not f.rexists() assert str(f) == test.workpath('f'), str(f) + # Now verify clear() resets optional File-specific attributes + optional_attrs = ['cachedir_csig', 'cachesig', 'contentsig'] + for attr in optional_attrs: + setattr(f, attr, 'xyz') + f.clear() + for attr in optional_attrs: + assert not hasattr(f, attr), attr + assert not f.cached, f.cached class disambiguateTestCase(unittest.TestCase): diff --git a/SCons/Node/NodeTests.py b/SCons/Node/NodeTests.py index 6e240d4..29a3887 100644 --- a/SCons/Node/NodeTests.py +++ b/SCons/Node/NodeTests.py @@ -1297,6 +1297,7 @@ class NodeTestCase(unittest.TestCase): n.includes = 'testincludes' n.Tag('found_includes', {'testkey':'testvalue'}) n.implicit = 'testimplicit' + n.cached = 1 x = MyExecutor() n.set_executor(x) @@ -1304,6 +1305,7 @@ class NodeTestCase(unittest.TestCase): n.clear() assert n.includes is None, n.includes + assert n.cached == 0, n.cached assert x.cleaned_up def test_get_subst_proxy(self): diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index 8a1677e..0a53fdd 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -869,10 +869,12 @@ class Node(object, metaclass=NoSlotsPyPy): self.clear_memoized_values() self.ninfo = self.new_ninfo() self.executor_cleanup() - try: - delattr(self, '_calculated_sig') - except AttributeError: - pass + for attr in ['cachedir_csig', 'cachesig', 'contentsig']: + try: + delattr(self, attr) + except AttributeError: + pass + self.cached = 0 self.includes = None def clear_memoized_values(self): -- cgit v0.12 From 4ab992d0ce34ed12141975082e23a36ccde4d310 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Wed, 21 Oct 2020 14:30:36 -0400 Subject: Remove one unnecessary part of a test --- SCons/Node/FSTests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py index 05e8b2a..08ccb19 100644 --- a/SCons/Node/FSTests.py +++ b/SCons/Node/FSTests.py @@ -3729,7 +3729,6 @@ class clearTestCase(unittest.TestCase): f.clear() for attr in optional_attrs: assert not hasattr(f, attr), attr - assert not f.cached, f.cached class disambiguateTestCase(unittest.TestCase): -- cgit v0.12 From 75e6573c21098a0eaf61a567267ce9bfe8c8d1c5 Mon Sep 17 00:00:00 2001 From: James Benton Date: Tue, 27 Oct 2020 16:32:10 +0000 Subject: Add COMPILATIONDB_USE_PATH_FILTER for filtering compilation database. The filter is a fnmatch pattern matched against output file. Also rename target->output in docs to match the output of compilation_db. --- CHANGES.txt | 4 ++ SCons/Tool/compilation_db.py | 7 ++- SCons/Tool/compilation_db.xml | 20 ++++++-- doc/user/external.xml | 57 ++++++++++++++++++++-- .../CompilationDatabase/fixture/SConstruct_variant | 4 ++ test/CompilationDatabase/variant_dir.py | 49 +++++++++++++++++++ 6 files changed, 132 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1f1730c..58f9695 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -74,6 +74,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER Could yield a single tempfile with the first TEMPFILE's contents, used by both steps in the action list. + From James Benton: + - Add COMPILATIONDB_USE_PATH_FILTER env option for CompilationDatabase() builder which allows + filtering of entries based on the output file paths using fnmatch (issue #3742). + diff --git a/SCons/Tool/compilation_db.py b/SCons/Tool/compilation_db.py index b610574..52442de 100644 --- a/SCons/Tool/compilation_db.py +++ b/SCons/Tool/compilation_db.py @@ -31,6 +31,7 @@ which is the name that most clang tools search for by default. import json import itertools +import fnmatch import SCons from .cxx import CXXSuffixes @@ -52,7 +53,6 @@ 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 @@ -135,6 +135,7 @@ def write_compilation_db(target, source, env): entries = [] use_abspath = env['COMPILATIONDB_USE_ABSPATH'] in [True, 1, 'True', 'true'] + use_path_filter = env.subst('$COMPILATIONDB_USE_PATH_FILTER') for s in __COMPILATION_DB_ENTRIES: entry = s.read() @@ -148,6 +149,9 @@ def write_compilation_db(target, source, env): source_file = source_file.srcnode().path output_file = output_file.path + if use_path_filter and not fnmatch.fnmatch(output_file, use_path_filter): + continue + path_entry = {'directory': entry['directory'], 'command': entry['command'], 'file': source_file, @@ -244,6 +248,7 @@ def generate(env, **kwargs): ) env['COMPILATIONDB_USE_ABSPATH'] = False + env['COMPILATIONDB_USE_PATH_FILTER'] = '' def exists(env): diff --git a/SCons/Tool/compilation_db.xml b/SCons/Tool/compilation_db.xml index 88ea6ca..fbbdffa 100644 --- a/SCons/Tool/compilation_db.xml +++ b/SCons/Tool/compilation_db.xml @@ -38,6 +38,7 @@ See its __doc__ string for a discussion of the format. __COMPILATIONDB_ENV --> COMPILATIONDB_USE_ABSPATH + COMPILATIONDB_USE_PATH_FILTER @@ -62,10 +63,10 @@ env.CompilationDatabase('my_output.json') You should not specify source files. The &b-CompilationDatabase; builder instruments SCons to collect them from all - the C, C++, assembly source/target pairs. + the C, C++, assembly source/output pairs. - NOTE: You must load the &t-compilation_db; tool prior to specifying any part of your build or some source/target + NOTE: You must load the &t-compilation_db; tool prior to specifying any part of your build or some source/output files will not show up in your output file. @@ -86,7 +87,7 @@ env.CompilationDatabase('my_output.json') This is a boolean flag to instruct &b-link-CompilationDatabase; to - write the file and target members + write the file and output members in the compilation database with absolute or relative paths. @@ -94,6 +95,19 @@ env.CompilationDatabase('my_output.json') + + + + + This is a string which instructs &b-link-CompilationDatabase; to + only include entries where the output member + matches the pattern in the filter string using fnmatch. + + + The default value is an empty string '', which means no entries will be filtered. + + + diff --git a/doc/user/external.xml b/doc/user/external.xml index a72fa54..d84f1bc 100644 --- a/doc/user/external.xml +++ b/doc/user/external.xml @@ -100,17 +100,25 @@ The compilation database can be populated with - source and target files either with paths relative + source and output files either with paths relative to the top of the build, or using absolute paths. This is controlled by COMPILATIONDB_USE_ABSPATH=(True|False) which defaults to False. + The entries in this file can be filtered by using + COMPILATIONDB_USE_PATH_FILTER='fnmatch pattern' where the + filter string is a + + fnmatch + + based pattern. This filtering can be used for outputting different build + variants to different compilation database files. - Example of absolute paths for target and source: + Example of absolute paths for output and source: @@ -126,14 +134,14 @@ env.CompilationDatabase('compile_commands.json') "command": "gcc -o test_main.o -c test_main.c", "directory": "/home/user/sandbox", "file": "/home/user/sandbox/test_main.c", - "target": "/home/user/sandbox/test_main.o" + "output": "/home/user/sandbox/test_main.o" } ] - Example of relative paths for target and source: + Example of relative paths for output and source: @@ -148,7 +156,46 @@ env.CompilationDatabase('compile_commands.json') "command": "gcc -o test_main.o -c test_main.c", "directory": "/home/user/sandbox", "file": "test_main.c", - "target": "test_main.o" + "output": "test_main.o" + } +] + + + + + Example of using filtering for build variants: + + + + +env = Environment() +env.Tool('compilation_db') + +env1 = env.Clone() +env1['COMPILATIONDB_USE_PATH_FILTER'] = 'build/linux32/*' +env1.CompilationDatabase('compile_commands-linux32.json') + +env2 = env.Clone() +env2['COMPILATIONDB_USE_PATH_FILTER'] = 'build/linux64/*' +env2.CompilationDatabase('compile_commands-linux64.json') + + +[ + { + "command": "gcc -m32 -o build/linux32/test_main.o -c test_main.c", + "directory": "/home/user/sandbox", + "file": "test_main.c", + "output": "build/linux32/test_main.o" + } +] + + +[ + { + "command": "gcc -m64 -o build/linux64/test_main.o -c test_main.c", + "directory": "/home/user/sandbox", + "file": "test_main.c", + "output": "build/linux64/test_main.o" } ] diff --git a/test/CompilationDatabase/fixture/SConstruct_variant b/test/CompilationDatabase/fixture/SConstruct_variant index f47c732..d86f593 100644 --- a/test/CompilationDatabase/fixture/SConstruct_variant +++ b/test/CompilationDatabase/fixture/SConstruct_variant @@ -32,6 +32,10 @@ env.CompilationDatabase('compile_commands_over_rel.json', COMPILATIONDB_USE_ABSP env.CompilationDatabase('compile_commands_over_abs_1.json', COMPILATIONDB_USE_ABSPATH=1) env.CompilationDatabase('compile_commands_over_abs_0.json', COMPILATIONDB_USE_ABSPATH=0) +# Try filter for build and build2 output +env.CompilationDatabase('compile_commands_filter_build.json', COMPILATIONDB_USE_PATH_FILTER='build/*') +env.CompilationDatabase('compile_commands_filter_build2.json', COMPILATIONDB_USE_PATH_FILTER='build2/*') + env.VariantDir('build','src') env.Program('build/main', 'build/test_main.c') diff --git a/test/CompilationDatabase/variant_dir.py b/test/CompilationDatabase/variant_dir.py index a36e516..6a2675b 100644 --- a/test/CompilationDatabase/variant_dir.py +++ b/test/CompilationDatabase/variant_dir.py @@ -56,6 +56,14 @@ abs_files = [ 'compile_commands_over_abs_1.json', ] +filter_build_files = [ + 'compile_commands_filter_build.json', +] + +filter_build2_files = [ + 'compile_commands_filter_build2.json', +] + example_rel_file = """[ { "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", @@ -115,4 +123,45 @@ for f in abs_files: test.must_exist(f) test.must_match(f, example_abs_file, mode='r') +example_filter_build_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output_file': os.path.join('build', 'test_main.o'), + 'variant_src_file': os.path.join('build', 'test_main.c') + } + +if sys.platform == 'win32': + example_filter_build_file = example_filter_build_file.replace('\\', '\\\\') + +for f in filter_build_files: + test.must_exist(f) + test.must_match(f, example_filter_build_file, mode='r') + +example_filter_build2_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output2_file)s -c %(src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output2_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output2_file': os.path.join('build2', 'test_main.o'), + } + +if sys.platform == 'win32': + example_filter_build2_file = example_filter_build2_file.replace('\\', '\\\\') + +for f in filter_build2_files: + test.must_exist(f) + test.must_match(f, example_filter_build2_file, mode='r') + test.pass_test() -- cgit v0.12 From 919c9a3645e9c1444bc1c375c5389a95b4afaab6 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 17 Oct 2020 18:10:59 -0600 Subject: Remove some "star imports" Usually, it's unit tests that do this, and it's not really crucial to kill those off, but checkers do complain, including sider if you touch anything in one of those files. In SCons/Environment,py, removed all SCons.Util prefixes, than turned the import of Util into a star import, running a tool on that then changes it to import only the used symbols from Util. Since there are lots, that ought to be a small performance win, since it doesn't have to do namespace lookups on SCons.Util. Signed-off-by: Mats Wichmann --- SCons/DefaultsTests.py | 2 +- SCons/Environment.py | 210 ++++++++++++++++++---------------- SCons/SConfTests.py | 2 +- SCons/SubstTests.py | 4 +- SCons/Tool/packaging/__init__.py | 2 +- SCons/Tool/packaging/msi.py | 2 +- test/exitfns.py | 2 +- test/packaging/msi/explicit-target.py | 2 +- test/packaging/msi/file-placement.py | 2 +- test/packaging/msi/package.py | 2 +- 10 files changed, 124 insertions(+), 106 deletions(-) diff --git a/SCons/DefaultsTests.py b/SCons/DefaultsTests.py index 97dab84..1e1ebdd 100644 --- a/SCons/DefaultsTests.py +++ b/SCons/DefaultsTests.py @@ -30,7 +30,7 @@ import TestCmd import SCons.Errors -from SCons.Defaults import * +from SCons.Defaults import mkdir_func class DefaultsTestCase(unittest.TestCase): def test_mkdir_func0(self): diff --git a/SCons/Environment.py b/SCons/Environment.py index cc62679..4ebd515 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -53,9 +53,27 @@ import SCons.SConf import SCons.SConsign import SCons.Subst import SCons.Tool -import SCons.Util -from SCons.Util import MethodWrapper import SCons.Warnings +from SCons.Util import ( + AppendPath, + CLVar, + LogicalLines, + MethodWrapper, + PrependPath, + Split, + WhereIs, + flatten, + is_Dict, + is_List, + is_Sequence, + is_String, + is_Tuple, + md5, + semi_deepcopy, + semi_deepcopy_dict, + to_String_for_subst, + uniquer_hashables, +) class _Null: pass @@ -69,18 +87,17 @@ _warn_target_signatures_deprecated = True CleanTargets = {} CalculatorArgs = {} -semi_deepcopy = SCons.Util.semi_deepcopy -semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict - def alias_builder(env, target, source): pass -AliasBuilder = SCons.Builder.Builder(action = alias_builder, - target_factory = SCons.Node.Alias.default_ans.Alias, - source_factory = SCons.Node.FS.Entry, - multi = 1, - is_explicit = None, - name='AliasBuilder') +AliasBuilder = SCons.Builder.Builder( + action=alias_builder, + target_factory=SCons.Node.Alias.default_ans.Alias, + source_factory=SCons.Node.FS.Entry, + multi=True, + is_explicit=None, + name='AliasBuilder', +) def apply_tools(env, tools, toolpath): # Store the toolpath in the Environment. @@ -91,7 +108,7 @@ def apply_tools(env, tools, toolpath): return # Filter out null tools from the list. for tool in [_f for _f in tools if _f]: - if SCons.Util.is_List(tool) or isinstance(tool, tuple): + if is_List(tool) or isinstance(tool, tuple): toolname = tool[0] toolargs = tool[1] # should be a dict of kw args tool = env.Tool(toolname, **toolargs) @@ -191,7 +208,7 @@ def _delete_duplicates(l, keep_last): # Note: MethodWrapper moved to SCons.Util as it was needed there # and otherwise we had a circular import problem. -class BuilderWrapper(SCons.Util.MethodWrapper): +class BuilderWrapper(MethodWrapper): """ A MethodWrapper subclass that that associates an environment with a Builder. @@ -214,9 +231,9 @@ class BuilderWrapper(SCons.Util.MethodWrapper): if source is _null: source = target target = None - if target is not None and not SCons.Util.is_List(target): + if target is not None and not is_List(target): target = [target] - if source is not None and not SCons.Util.is_List(source): + if source is not None and not is_List(source): source = [source] return super().__call__(target, source, *args, **kw) @@ -431,24 +448,24 @@ class SubstitutionEnvironment: if not args: return [] - args = SCons.Util.flatten(args) + args = flatten(args) nodes = [] for v in args: - if SCons.Util.is_String(v): + if is_String(v): n = None for l in lookup_list: n = l(v) if n is not None: break if n is not None: - if SCons.Util.is_String(n): + if is_String(n): # n = self.subst(n, raw=1, **kw) kw['raw'] = 1 n = self.subst(n, **kw) if node_factory: n = node_factory(n) - if SCons.Util.is_List(n): + if is_List(n): nodes.extend(n) else: nodes.append(n) @@ -456,7 +473,7 @@ class SubstitutionEnvironment: # v = node_factory(self.subst(v, raw=1, **kw)) kw['raw'] = 1 v = node_factory(self.subst(v, **kw)) - if SCons.Util.is_List(v): + if is_List(v): nodes.extend(v) else: nodes.append(v) @@ -492,7 +509,7 @@ class SubstitutionEnvironment: nkw = {} for k, v in kw.items(): k = self.subst(k, raw, target, source) - if SCons.Util.is_String(v): + if is_String(v): v = self.subst(v, raw, target, source) nkw[k] = v return nkw @@ -511,7 +528,7 @@ class SubstitutionEnvironment: """Substitute a path list, turning EntryProxies into Nodes and leaving Nodes (and other objects) as-is.""" - if not SCons.Util.is_List(path): + if not is_List(path): path = [path] def s(obj): @@ -524,23 +541,23 @@ class SubstitutionEnvironment: try: get = obj.get except AttributeError: - obj = SCons.Util.to_String_for_subst(obj) + obj = to_String_for_subst(obj) else: obj = get() return obj r = [] for p in path: - if SCons.Util.is_String(p): + if is_String(p): p = self.subst(p, target=target, source=source, conv=s) - if SCons.Util.is_List(p): + if is_List(p): if len(p) == 1: p = p[0] else: # We have an object plus a string, or multiple # objects that we need to smush together. No choice # but to make them into a string. - p = ''.join(map(SCons.Util.to_String_for_subst, p)) + p = ''.join(map(to_String_for_subst, p)) else: p = s(p) r.append(p) @@ -558,7 +575,7 @@ class SubstitutionEnvironment: } # if the command is a list, assume it's been quoted # othewise force a shell - if not SCons.Util.is_List(command): kw['shell'] = True + if not is_List(command): kw['shell'] = True # run constructed command p = SCons.Action._subproc(self, command, **kw) out,err = p.communicate() @@ -628,18 +645,18 @@ class SubstitutionEnvironment: the result of that evaluation is then added to the dict. """ dict = { - 'ASFLAGS' : SCons.Util.CLVar(''), - 'CFLAGS' : SCons.Util.CLVar(''), - 'CCFLAGS' : SCons.Util.CLVar(''), - 'CXXFLAGS' : SCons.Util.CLVar(''), + 'ASFLAGS' : CLVar(''), + 'CFLAGS' : CLVar(''), + 'CCFLAGS' : CLVar(''), + 'CXXFLAGS' : CLVar(''), 'CPPDEFINES' : [], - 'CPPFLAGS' : SCons.Util.CLVar(''), + 'CPPFLAGS' : CLVar(''), 'CPPPATH' : [], - 'FRAMEWORKPATH' : SCons.Util.CLVar(''), - 'FRAMEWORKS' : SCons.Util.CLVar(''), + 'FRAMEWORKPATH' : CLVar(''), + 'FRAMEWORKS' : CLVar(''), 'LIBPATH' : [], 'LIBS' : [], - 'LINKFLAGS' : SCons.Util.CLVar(''), + 'LINKFLAGS' : CLVar(''), 'RPATH' : [], } @@ -648,7 +665,7 @@ class SubstitutionEnvironment: if not arg: return - if not SCons.Util.is_String(arg): + if not is_String(arg): for t in arg: do_parse(t) return @@ -818,7 +835,7 @@ class SubstitutionEnvironment: unique: merge flags rather than appending (default: True) """ - if not SCons.Util.is_Dict(args): + if not is_Dict(args): args = self.ParseFlags(args) if not unique: @@ -828,7 +845,7 @@ class SubstitutionEnvironment: for key, value in args.items(): if not value: continue - value = SCons.Util.Split(value) + value = Split(value) try: orig = self[key] except KeyError: @@ -952,7 +969,7 @@ class Base(SubstitutionEnvironment): platform = self._dict.get('PLATFORM', None) if platform is None: platform = SCons.Platform.Platform() - if SCons.Util.is_String(platform): + if is_String(platform): platform = SCons.Platform.Platform(platform) self._dict['PLATFORM'] = str(platform) platform(self) @@ -1081,7 +1098,7 @@ class Base(SubstitutionEnvironment): # claim they can scan the same suffix, earlier scanners # in the list will overwrite later scanners, so that # the result looks like a "first match" to the user. - if not SCons.Util.is_List(scanners): + if not is_List(scanners): scanners = [scanners] else: scanners = scanners[:] # copy so reverse() doesn't mod original @@ -1164,13 +1181,13 @@ class Base(SubstitutionEnvironment): # but Python 1.5.2 apparently doesn't let you use "continue" # within try:-except: blocks, so we have to nest our code. try: - if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]): + if key == 'CPPDEFINES' and is_String(self._dict[key]): self._dict[key] = [self._dict[key]] orig = self._dict[key] except KeyError: # No existing variable in the environment, so just set # it to the new value. - if key == 'CPPDEFINES' and SCons.Util.is_String(val): + if key == 'CPPDEFINES' and is_String(val): self._dict[key] = [val] else: self._dict[key] = val @@ -1209,7 +1226,7 @@ class Base(SubstitutionEnvironment): else: # The original looks like a dictionary, so update it # based on what we think the value looks like. - if SCons.Util.is_List(val): + if is_List(val): if key == 'CPPDEFINES': tmp = [] for (k, v) in orig.items(): @@ -1227,7 +1244,7 @@ class Base(SubstitutionEnvironment): try: update_dict(val) except (AttributeError, TypeError, ValueError): - if SCons.Util.is_Dict(val): + if is_Dict(val): for k, v in val.items(): orig[k] = v else: @@ -1237,7 +1254,7 @@ class Base(SubstitutionEnvironment): # allow Dirs and strings beginning with # for top-relative # Note this uses the current env's fs (in self). def _canonicalize(self, path): - if not SCons.Util.is_String(path): # typically a Dir + if not is_String(path): # typically a Dir path = str(path) if path and path[0] == '#': path = str(self.fs.Dir(path)) @@ -1259,8 +1276,7 @@ class Base(SubstitutionEnvironment): if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] - nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing, - canonicalize=self._canonicalize) + nv = AppendPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: self._dict[envname] = {} @@ -1275,30 +1291,30 @@ class Base(SubstitutionEnvironment): """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - if SCons.Util.is_List(val): + if is_List(val): val = _delete_duplicates(val, delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(val): + elif is_Dict(self._dict[key]) and \ + is_Dict(val): self._dict[key].update(val) - elif SCons.Util.is_List(val): + elif is_List(val): dk = self._dict[key] if key == 'CPPDEFINES': tmp = [] for i in val: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) val = tmp # Construct a list of (key, value) tuples. - if SCons.Util.is_Dict(dk): + if is_Dict(dk): tmp = [] for (k, v) in dk.items(): if v is not None: @@ -1306,23 +1322,23 @@ class Base(SubstitutionEnvironment): else: tmp.append((k,)) dk = tmp - elif SCons.Util.is_String(dk): + elif is_String(dk): dk = [(dk,)] else: tmp = [] for i in dk: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) dk = tmp else: - if not SCons.Util.is_List(dk): + if not is_List(dk): dk = [dk] if delete_existing: dk = [x for x in dk if x not in val] @@ -1331,22 +1347,22 @@ class Base(SubstitutionEnvironment): self._dict[key] = dk + val else: dk = self._dict[key] - if SCons.Util.is_List(dk): + if is_List(dk): if key == 'CPPDEFINES': tmp = [] for i in dk: - if SCons.Util.is_List(i): + if is_List(i): if len(i) >= 2: tmp.append((i[0], i[1])) else: tmp.append((i[0],)) - elif SCons.Util.is_Tuple(i): + elif is_Tuple(i): tmp.append(i) else: tmp.append((i,)) dk = tmp # Construct a list of (key, value) tuples. - if SCons.Util.is_Dict(val): + if is_Dict(val): tmp = [] for (k, v) in val.items(): if v is not None: @@ -1354,7 +1370,7 @@ class Base(SubstitutionEnvironment): else: tmp.append((k,)) val = tmp - elif SCons.Util.is_String(val): + elif is_String(val): val = [(val,)] if delete_existing: dk = list(filter(lambda x, val=val: x not in val, dk)) @@ -1373,9 +1389,9 @@ class Base(SubstitutionEnvironment): self._dict[key] = dk + [val] else: if key == 'CPPDEFINES': - if SCons.Util.is_String(dk): + if is_String(dk): dk = [dk] - elif SCons.Util.is_Dict(dk): + elif is_Dict(dk): tmp = [] for (k, v) in dk.items(): if v is not None: @@ -1383,12 +1399,12 @@ class Base(SubstitutionEnvironment): else: tmp.append((k,)) dk = tmp - if SCons.Util.is_String(val): + if is_String(val): if val in dk: val = [] else: val = [val] - elif SCons.Util.is_Dict(val): + elif is_Dict(val): tmp = [] for i,j in val.items(): if j is not None: @@ -1483,7 +1499,7 @@ class Base(SubstitutionEnvironment): def Decider(self, function): copy_function = self._copy2_from_cache if function in ('MD5', 'content'): - if not SCons.Util.md5: + if not md5: raise UserError("MD5 signatures are not available in this version of Python.") function = self._changed_content elif function == 'MD5-timestamp': @@ -1511,7 +1527,7 @@ class Base(SubstitutionEnvironment): progs (str or list): one or more command names to check for """ - if not SCons.Util.is_List(progs): + if not is_List(progs): progs = [progs] for prog in progs: path = self.WhereIs(prog) @@ -1616,7 +1632,7 @@ class Base(SubstitutionEnvironment): def parse_conf(env, cmd, unique=unique): return env.MergeFlags(cmd, unique) function = parse_conf - if SCons.Util.is_List(command): + if is_List(command): command = ' '.join(command) command = self.subst(command) return function(self, self.backtick(command)) @@ -1634,7 +1650,7 @@ class Base(SubstitutionEnvironment): filename = self.subst(filename) try: with open(filename, 'r') as fp: - lines = SCons.Util.LogicalLines(fp).readlines() + lines = LogicalLines(fp).readlines() except IOError: if must_exist: raise @@ -1716,14 +1732,14 @@ class Base(SubstitutionEnvironment): else: # The original looks like a dictionary, so update it # based on what we think the value looks like. - if SCons.Util.is_List(val): + if is_List(val): for v in val: orig[v] = None else: try: update_dict(val) except (AttributeError, TypeError, ValueError): - if SCons.Util.is_Dict(val): + if is_Dict(val): for k, v in val.items(): orig[k] = v else: @@ -1746,7 +1762,7 @@ class Base(SubstitutionEnvironment): if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] - nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing, + nv = PrependPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: @@ -1762,16 +1778,16 @@ class Base(SubstitutionEnvironment): """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - if SCons.Util.is_List(val): + if is_List(val): val = _delete_duplicates(val, not delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(val): + elif is_Dict(self._dict[key]) and \ + is_Dict(val): self._dict[key].update(val) - elif SCons.Util.is_List(val): + elif is_List(val): dk = self._dict[key] - if not SCons.Util.is_List(dk): + if not is_List(dk): dk = [dk] if delete_existing: dk = [x for x in dk if x not in val] @@ -1780,7 +1796,7 @@ class Base(SubstitutionEnvironment): self._dict[key] = val + dk else: dk = self._dict[key] - if SCons.Util.is_List(dk): + if is_List(dk): # By elimination, val is not a list. Since dk is a # list, wrap val in a list first. if delete_existing: @@ -1845,7 +1861,7 @@ class Base(SubstitutionEnvironment): return self.fs.Dir(self.subst(tp)).srcnode().get_abspath() def Tool(self, tool, toolpath=None, **kw): - if SCons.Util.is_String(tool): + if is_String(tool): tool = self.subst(tool) if toolpath is None: toolpath = self.get('toolpath', []) @@ -1861,17 +1877,17 @@ class Base(SubstitutionEnvironment): path = self['ENV']['PATH'] except KeyError: pass - elif SCons.Util.is_String(path): + elif is_String(path): path = self.subst(path) if pathext is None: try: pathext = self['ENV']['PATHEXT'] except KeyError: pass - elif SCons.Util.is_String(pathext): + elif is_String(pathext): pathext = self.subst(pathext) - prog = SCons.Util.CLVar(self.subst(prog)) # support "program --with-args" - path = SCons.Util.WhereIs(prog[0], path, pathext, reject) + prog = CLVar(self.subst(prog)) # support "program --with-args" + path = WhereIs(prog[0], path, pathext, reject) if path: return path return None @@ -1885,7 +1901,7 @@ class Base(SubstitutionEnvironment): def Action(self, *args, **kw): def subst_string(a, self=self): - if SCons.Util.is_String(a): + if is_String(a): a = self.subst(a) return a nargs = list(map(subst_string, args)) @@ -1914,7 +1930,7 @@ class Base(SubstitutionEnvironment): def Alias(self, target, source=[], action=None, **kw): tlist = self.arg2nodes(target, self.ans.Alias) - if not SCons.Util.is_List(source): + if not is_List(source): source = [source] source = [_f for _f in source if _f] @@ -2062,7 +2078,7 @@ class Base(SubstitutionEnvironment): """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.Dir(e, *args, **kw)) @@ -2071,7 +2087,7 @@ class Base(SubstitutionEnvironment): def PyPackageDir(self, modulename): s = self.subst(modulename) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.PyPackageDir(e)) @@ -2100,7 +2116,7 @@ class Base(SubstitutionEnvironment): """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.Entry(e, *args, **kw)) @@ -2128,7 +2144,7 @@ class Base(SubstitutionEnvironment): """ """ s = self.subst(name) - if SCons.Util.is_Sequence(s): + if is_Sequence(s): result=[] for e in s: result.append(self.fs.File(e, *args, **kw)) @@ -2141,11 +2157,11 @@ class Base(SubstitutionEnvironment): return SCons.Node.FS.find_file(file, tuple(nodes)) def Flatten(self, sequence): - return SCons.Util.flatten(sequence) + return flatten(sequence) def GetBuildPath(self, files): result = list(map(str, self.arg2nodes(files, self.fs.Entry))) - if SCons.Util.is_List(files): + if is_List(files): return result else: return result[0] @@ -2209,7 +2225,7 @@ class Base(SubstitutionEnvironment): def Scanner(self, *args, **kw): nargs = [] for arg in args: - if SCons.Util.is_String(arg): + if is_String(arg): arg = self.subst(arg) nargs.append(arg) nkw = self.subst_kw(kw) @@ -2257,9 +2273,9 @@ class Base(SubstitutionEnvironment): In all cases, the function returns a list of Nodes and strings.""" - if SCons.Util.is_List(arg): + if is_List(arg): return list(map(self.subst, arg)) - elif SCons.Util.is_String(arg): + elif is_String(arg): return self.subst(arg).split() else: return [self.subst(arg)] @@ -2303,7 +2319,7 @@ class Base(SubstitutionEnvironment): """ from SCons.Tool import install if install._UNIQUE_INSTALLED_FILES is None: - install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) + install._UNIQUE_INSTALLED_FILES = uniquer_hashables(install._INSTALLED_FILES) return install._UNIQUE_INSTALLED_FILES diff --git a/SCons/SConfTests.py b/SCons/SConfTests.py index b8ee7d2..a6fe508 100644 --- a/SCons/SConfTests.py +++ b/SCons/SConfTests.py @@ -27,7 +27,7 @@ import io import os import re import sys -from types import * +from types import ModuleType import unittest import TestCmd diff --git a/SCons/SubstTests.py b/SCons/SubstTests.py index 8443cad..be62db0 100644 --- a/SCons/SubstTests.py +++ b/SCons/SubstTests.py @@ -29,7 +29,9 @@ import unittest import SCons.Errors -from SCons.Subst import * +from SCons.Subst import (Literal, SUBST_CMD, SUBST_RAW, SUBST_SIG, SpecialAttrWrapper, collections, + escape_list, quote_spaces, scons_subst, scons_subst_list, scons_subst_once, + subst_dict) class DummyNode: """Simple node work-alike.""" diff --git a/SCons/Tool/packaging/__init__.py b/SCons/Tool/packaging/__init__.py index c45a96b..c378909 100644 --- a/SCons/Tool/packaging/__init__.py +++ b/SCons/Tool/packaging/__init__.py @@ -35,7 +35,7 @@ import SCons.Environment from SCons.Errors import UserError, SConsEnvironmentError from SCons.Script import AddOption, GetOption from SCons.Util import is_List, make_path_relative -from SCons.Variables import * +from SCons.Variables import EnumVariable from SCons.Warnings import warn, SConsWarning diff --git a/SCons/Tool/packaging/msi.py b/SCons/Tool/packaging/msi.py index defb5c6..458e81f 100644 --- a/SCons/Tool/packaging/msi.py +++ b/SCons/Tool/packaging/msi.py @@ -32,7 +32,7 @@ import SCons from SCons.Action import Action from SCons.Builder import Builder -from xml.dom.minidom import * +from xml.dom.minidom import Document from xml.sax.saxutils import escape from SCons.Tool.packaging import stripinstallbuilder diff --git a/test/exitfns.py b/test/exitfns.py index c303a8e..ee2ada1 100644 --- a/test/exitfns.py +++ b/test/exitfns.py @@ -34,7 +34,7 @@ if test.coverage_run(): test.skip_test("This test replaces the exit function which is needed by coverage to write test data; skipping test.") sconstruct = """ -from SCons.exitfuncs import * +from SCons.exitfuncs import register def x1(): print("running x1") diff --git a/test/packaging/msi/explicit-target.py b/test/packaging/msi/explicit-target.py index 85bfa85..015baee 100644 --- a/test/packaging/msi/explicit-target.py +++ b/test/packaging/msi/explicit-target.py @@ -36,7 +36,7 @@ python = TestSCons.python test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Canoot import xml.dom.minidom skipping test\n') diff --git a/test/packaging/msi/file-placement.py b/test/packaging/msi/file-placement.py index 2cc9e61..405e55b 100644 --- a/test/packaging/msi/file-placement.py +++ b/test/packaging/msi/file-placement.py @@ -35,7 +35,7 @@ python = TestSCons.python test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Cannot import xml.dom.minidom; skipping test\n') diff --git a/test/packaging/msi/package.py b/test/packaging/msi/package.py index 4988742..19183bf 100644 --- a/test/packaging/msi/package.py +++ b/test/packaging/msi/package.py @@ -35,7 +35,7 @@ python = TestSCons.python test = TestSCons.TestSCons() try: - from xml.dom.minidom import * + from xml.dom.minidom import parse except ImportError: test.skip_test('Canoot import xml.dom.minidom skipping test\n') -- cgit v0.12 From 208f131feaaa8fb88e3e27ff4eff6a41fc5fec93 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 6 Feb 2020 08:59:32 -0700 Subject: Kill a couple of "for foo in range(len(bar))" Usually these aren't needed; the ones in tex.py defintely weren't. Also one bit of code reformat. Signed-off-by: Mats Wichmann --- SCons/Tool/tex.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/SCons/Tool/tex.py b/SCons/Tool/tex.py index 1d61e2d..a5e65c9 100644 --- a/SCons/Tool/tex.py +++ b/SCons/Tool/tex.py @@ -429,18 +429,23 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None return result # Now decide if latex will need to be run again due to newglossary command. - for ig in range(len(newglossary_suffix)): - if check_MD5(suffix_nodes[newglossary_suffix[ig][2]],newglossary_suffix[ig][2]) or (count == 1): + for ng in newglossary_suffix: + if check_MD5(suffix_nodes[ng[2]], ng[2]) or (count == 1): # We must run makeindex if Verbose: print("Need to run makeindex for newglossary") - newglfile = suffix_nodes[newglossary_suffix[ig][2]] - MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR") + newglfile = suffix_nodes[ng[2]] + MakeNewGlossaryAction = SCons.Action.Action( + "$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" + % (ng[2], ng[0], ng[1]), + "$MAKENEWGLOSSARYCOMSTR", + ) result = MakeNewGlossaryAction(newglfile, newglfile, env) if result != 0: - check_file_error_message('%s (newglossary)' % env['MAKENEWGLOSSARY'], - newglossary_suffix[ig][0]) + check_file_error_message( + '%s (newglossary)' % env['MAKENEWGLOSSARY'], ng[0] + ) return result # Now decide if latex needs to be run yet again to resolve warnings. @@ -786,8 +791,8 @@ def tex_emitter_core(target, source, env, graphics_extensions): file_basename = os.path.join(targetdir, 'bu*.aux') file_list = glob.glob(file_basename) # remove the suffix '.aux' - for i in range(len(file_list)): - file_list.append(SCons.Util.splitext(file_list[i])[0]) + for fl in file_list: + file_list.append(SCons.Util.splitext(fl)[0]) # for multibib we need a list of files if suffix_list[-1] == 'multibib': for multibibmatch in multibib_re.finditer(content): @@ -797,8 +802,8 @@ def tex_emitter_core(target, source, env, graphics_extensions): baselist = multibibmatch.group(1).split(',') if Verbose: print("multibib list ", baselist) - for i in range(len(baselist)): - file_list.append(os.path.join(targetdir, baselist[i])) + for bl in baselist: + file_list.append(os.path.join(targetdir, bl)) # now define the side effects for file_name in file_list: for suffix in suffix_list[:-1]: -- cgit v0.12 From b896b7b9649003016537a005678c576511bf3338 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 18 Nov 2020 07:09:33 -0700 Subject: [PR #3827] fix: don't iterate over object being modified Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + SCons/Tool/tex.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 77fb110..1037f69 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -77,6 +77,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER and to rerun such tests. Useful when an error cascades through several tests, can quickly try if a change improves all the fails. Dropped runtest test for fallback from qmtest, not needed; added new tests. + - Eliminate tex tool usage of "for foo in range(len(iterable))" From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/SCons/Tool/tex.py b/SCons/Tool/tex.py index a5e65c9..0ca7e2d 100644 --- a/SCons/Tool/tex.py +++ b/SCons/Tool/tex.py @@ -791,7 +791,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): file_basename = os.path.join(targetdir, 'bu*.aux') file_list = glob.glob(file_basename) # remove the suffix '.aux' - for fl in file_list: + for fl in file_list.copy(): file_list.append(SCons.Util.splitext(fl)[0]) # for multibib we need a list of files if suffix_list[-1] == 'multibib': -- cgit v0.12 From 3f66f88ae87f89c7d0ad30c67a22fbf1a4a2e94b Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 19 Nov 2020 06:43:27 -0700 Subject: Drop yet more py2 compatibility stuff A checker flagged the zip_longest/izip_longest workaround, that's no longer needed. Similar for the shutil.SameFileError piece, that's standard since 3.4 and doesn't need checking for. The checker also complained about return contents.decode('utf-8', error='backslashreplace') the correct kward is errors, not error - corrected. Signed-off-by: Mats Wichmann --- SCons/Node/FS.py | 2 +- SCons/Node/__init__.py | 14 +++----------- SCons/compat/__init__.py | 9 --------- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index 967f007..5228dc4 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -2721,7 +2721,7 @@ class File(Base): try: return contents.decode('latin-1') except UnicodeDecodeError as e: - return contents.decode('utf-8', error='backslashreplace') + return contents.decode('utf-8', errors='backslashreplace') def get_content_hash(self): diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index 8a1677e..b0c2485 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -42,23 +42,15 @@ be able to depend on any other type of "thing." import collections import copy -from itertools import chain - -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest +from itertools import chain, zip_longest import SCons.Debug -from SCons.Debug import logInstanceCreation import SCons.Executor import SCons.Memoize import SCons.Util -from SCons.Util import MD5signature - -from SCons.Debug import Trace - from SCons.compat import NoSlotsPyPy +from SCons.Debug import logInstanceCreation, Trace +from SCons.Util import MD5signature print_duplicate = 0 diff --git a/SCons/compat/__init__.py b/SCons/compat/__init__.py index 91d10d1..03b12af 100644 --- a/SCons/compat/__init__.py +++ b/SCons/compat/__init__.py @@ -85,15 +85,6 @@ def rename_module(new, old): # Python 3.8 introduced protocol 5 which is mainly an improvement for for out-of-band data buffers PICKLE_PROTOCOL = 4 -import shutil -try: - shutil.SameFileError -except AttributeError: - class SameFileError(Exception): - pass - - shutil.SameFileError = SameFileError - class NoSlotsPyPy(type): """ Metaclass for PyPy compatitbility. -- cgit v0.12 From cf2546d2a4b3354b828482cbaf50ffa1dd344436 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 19 Nov 2020 16:23:38 -0700 Subject: One more unneeded try-import-fixup gettext is always present now, so extra steps not needed. Signed-off-by: Mats Wichmann --- SCons/Script/SConsOptions.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/SCons/Script/SConsOptions.py b/SCons/Script/SConsOptions.py index d25d657..7b79292 100644 --- a/SCons/Script/SConsOptions.py +++ b/SCons/Script/SConsOptions.py @@ -28,12 +28,8 @@ import textwrap no_hyphen_re = re.compile(r'(\s+|(?<=[\w!\"\'&.,?])-{2,}(?=\w))') -try: - from gettext import gettext -except ImportError: - def gettext(message): - return message -_ = gettext +import gettext +_ = gettext.gettext import SCons.Node.FS import SCons.Platform.virtualenv -- cgit v0.12 From 7e3696fe2a249093d5d8f8de3fd575b8249aa506 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 21 Nov 2020 07:57:11 -0700 Subject: Fix Trace function The (internal) Trace function had been left in an inconsistent state by an earlier change, with a variable name mismatch. Fixed. Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + SCons/Debug.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1037f69..7dc5297 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -78,6 +78,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER tests, can quickly try if a change improves all the fails. Dropped runtest test for fallback from qmtest, not needed; added new tests. - Eliminate tex tool usage of "for foo in range(len(iterable))" + - Restore internal Trace function to functional state. From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/SCons/Debug.py b/SCons/Debug.py index 2310cb7..f4b802e 100644 --- a/SCons/Debug.py +++ b/SCons/Debug.py @@ -196,17 +196,17 @@ TimeStampDefault = False StartTime = time.time() PreviousTime = StartTime -def Trace(msg, filename=None, mode='w', tstamp=False): +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 file argument persists + opened as a file), or to a disk file; the tracefile argument persists across calls unless overridden. Args: - filename: file to write trace message to. If omitted, + 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 @@ -220,23 +220,23 @@ def Trace(msg, filename=None, mode='w', tstamp=False): def trace_cleanup(traceFP): traceFP.close() - if file is None: - file = TraceDefault + if tracefile is None: + tracefile = TraceDefault else: - TraceDefault = file + TraceDefault = tracefile if not tstamp: tstamp = TimeStampDefault else: TimeStampDefault = tstamp try: - fp = TraceFP[file] + fp = TraceFP[tracefile] except KeyError: try: - fp = TraceFP[file] = open(file, mode) + fp = TraceFP[tracefile] = open(tracefile, mode) atexit.register(trace_cleanup, fp) except TypeError: # Assume we were passed an open file pointer. - fp = file + fp = tracefile if tstamp: now = time.time() fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime)) -- cgit v0.12 From becb5c6cbc5a370b4778374771777c2b493eaa05 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 22 Nov 2020 07:11:00 -0700 Subject: Move wix tool into windows tool section The wix tool has a slightly expensive "exists" function, so its placement in the tool list as generic means non-Windows platforms also pay this cost. Moved to the win32 section for other_plat_tools as it's only available on Windows platforms. Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + SCons/Tool/__init__.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7dc5297..e044a67 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -79,6 +79,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER runtest test for fallback from qmtest, not needed; added new tests. - Eliminate tex tool usage of "for foo in range(len(iterable))" - Restore internal Trace function to functional state. + - Move wix tool into windows-specific section. From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py index 0c7afb8..87139f1 100644 --- a/SCons/Tool/__init__.py +++ b/SCons/Tool/__init__.py @@ -694,7 +694,7 @@ def tool_list(platform, env): assemblers = ['masm', 'nasm', 'gas', '386asm'] fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] ars = ['mslib', 'ar', 'tlib'] - other_plat_tools = ['msvs', 'midl'] + other_plat_tools = ['msvs', 'midl', 'wix'] elif str(platform) == 'os2': "prefer IBM tools on OS/2" linkers = ['ilink', 'gnulink', ] # 'mslink'] @@ -794,7 +794,6 @@ def tool_list(platform, env): # TODO: merge 'install' into 'filesystem' and # make 'filesystem' the default 'filesystem', - 'wix', # 'midl', 'msvs', # Parser generators 'lex', 'yacc', # Foreign function interface -- cgit v0.12 From cb5fd47fc19798eb7ff6d2358b24cf734a1fb2fc Mon Sep 17 00:00:00 2001 From: James Benton Date: Tue, 27 Oct 2020 16:32:10 +0000 Subject: Add COMPILATIONDB_USE_PATH_FILTER for filtering compilation database. The filter is a fnmatch pattern matched against output file. --- CHANGES.txt | 4 ++ SCons/Tool/compilation_db.py | 7 ++- SCons/Tool/compilation_db.xml | 16 +++++- doc/user/external.xml | 58 ++++++++++++++++++++-- .../CompilationDatabase/fixture/SConstruct_variant | 4 ++ test/CompilationDatabase/variant_dir.py | 49 ++++++++++++++++++ 6 files changed, 131 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1f1730c..58f9695 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -74,6 +74,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER Could yield a single tempfile with the first TEMPFILE's contents, used by both steps in the action list. + From James Benton: + - Add COMPILATIONDB_USE_PATH_FILTER env option for CompilationDatabase() builder which allows + filtering of entries based on the output file paths using fnmatch (issue #3742). + diff --git a/SCons/Tool/compilation_db.py b/SCons/Tool/compilation_db.py index b610574..52442de 100644 --- a/SCons/Tool/compilation_db.py +++ b/SCons/Tool/compilation_db.py @@ -31,6 +31,7 @@ which is the name that most clang tools search for by default. import json import itertools +import fnmatch import SCons from .cxx import CXXSuffixes @@ -52,7 +53,6 @@ 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 @@ -135,6 +135,7 @@ def write_compilation_db(target, source, env): entries = [] use_abspath = env['COMPILATIONDB_USE_ABSPATH'] in [True, 1, 'True', 'true'] + use_path_filter = env.subst('$COMPILATIONDB_USE_PATH_FILTER') for s in __COMPILATION_DB_ENTRIES: entry = s.read() @@ -148,6 +149,9 @@ def write_compilation_db(target, source, env): source_file = source_file.srcnode().path output_file = output_file.path + if use_path_filter and not fnmatch.fnmatch(output_file, use_path_filter): + continue + path_entry = {'directory': entry['directory'], 'command': entry['command'], 'file': source_file, @@ -244,6 +248,7 @@ def generate(env, **kwargs): ) env['COMPILATIONDB_USE_ABSPATH'] = False + env['COMPILATIONDB_USE_PATH_FILTER'] = '' def exists(env): diff --git a/SCons/Tool/compilation_db.xml b/SCons/Tool/compilation_db.xml index 88ea6ca..95d70db 100644 --- a/SCons/Tool/compilation_db.xml +++ b/SCons/Tool/compilation_db.xml @@ -38,6 +38,7 @@ See its __doc__ string for a discussion of the format. __COMPILATIONDB_ENV --> COMPILATIONDB_USE_ABSPATH + COMPILATIONDB_USE_PATH_FILTER @@ -86,7 +87,7 @@ env.CompilationDatabase('my_output.json') This is a boolean flag to instruct &b-link-CompilationDatabase; to - write the file and target members + write the file and output members in the compilation database with absolute or relative paths. @@ -94,6 +95,19 @@ env.CompilationDatabase('my_output.json') + + + + + This is a string which instructs &b-link-CompilationDatabase; to + only include entries where the output member + matches the pattern in the filter string using fnmatch. + + + The default value is an empty string '', which means no entries will be filtered. + + + diff --git a/doc/user/external.xml b/doc/user/external.xml index a72fa54..a10e7f6 100644 --- a/doc/user/external.xml +++ b/doc/user/external.xml @@ -100,17 +100,26 @@ The compilation database can be populated with - source and target files either with paths relative + source and output files either with paths relative to the top of the build, or using absolute paths. This is controlled by COMPILATIONDB_USE_ABSPATH=(True|False) which defaults to False. + The entries in this file can be filtered by using + COMPILATIONDB_USE_PATH_FILTER='fnmatch pattern' + where the filter string is a + + fnmatch + + based pattern which is a typical file glob syntax. + This filtering can be used for outputting different + build variants to different compilation database files. - Example of absolute paths for target and source: + Example of absolute paths for output and source: @@ -126,14 +135,14 @@ env.CompilationDatabase('compile_commands.json') "command": "gcc -o test_main.o -c test_main.c", "directory": "/home/user/sandbox", "file": "/home/user/sandbox/test_main.c", - "target": "/home/user/sandbox/test_main.o" + "output": "/home/user/sandbox/test_main.o" } ] - Example of relative paths for target and source: + Example of relative paths for output and source: @@ -148,7 +157,46 @@ env.CompilationDatabase('compile_commands.json') "command": "gcc -o test_main.o -c test_main.c", "directory": "/home/user/sandbox", "file": "test_main.c", - "target": "test_main.o" + "output": "test_main.o" + } +] + + + + + Example of using filtering for build variants: + + + + +env = Environment() +env.Tool('compilation_db') + +env1 = env.Clone() +env1['COMPILATIONDB_USE_PATH_FILTER'] = 'build/linux32/*' +env1.CompilationDatabase('compile_commands-linux32.json') + +env2 = env.Clone() +env2['COMPILATIONDB_USE_PATH_FILTER'] = 'build/linux64/*' +env2.CompilationDatabase('compile_commands-linux64.json') + + +[ + { + "command": "gcc -m32 -o build/linux32/test_main.o -c test_main.c", + "directory": "/home/user/sandbox", + "file": "test_main.c", + "output": "build/linux32/test_main.o" + } +] + + +[ + { + "command": "gcc -m64 -o build/linux64/test_main.o -c test_main.c", + "directory": "/home/user/sandbox", + "file": "test_main.c", + "output": "build/linux64/test_main.o" } ] diff --git a/test/CompilationDatabase/fixture/SConstruct_variant b/test/CompilationDatabase/fixture/SConstruct_variant index f47c732..d86f593 100644 --- a/test/CompilationDatabase/fixture/SConstruct_variant +++ b/test/CompilationDatabase/fixture/SConstruct_variant @@ -32,6 +32,10 @@ env.CompilationDatabase('compile_commands_over_rel.json', COMPILATIONDB_USE_ABSP env.CompilationDatabase('compile_commands_over_abs_1.json', COMPILATIONDB_USE_ABSPATH=1) env.CompilationDatabase('compile_commands_over_abs_0.json', COMPILATIONDB_USE_ABSPATH=0) +# Try filter for build and build2 output +env.CompilationDatabase('compile_commands_filter_build.json', COMPILATIONDB_USE_PATH_FILTER='build/*') +env.CompilationDatabase('compile_commands_filter_build2.json', COMPILATIONDB_USE_PATH_FILTER='build2/*') + env.VariantDir('build','src') env.Program('build/main', 'build/test_main.c') diff --git a/test/CompilationDatabase/variant_dir.py b/test/CompilationDatabase/variant_dir.py index a36e516..6a2675b 100644 --- a/test/CompilationDatabase/variant_dir.py +++ b/test/CompilationDatabase/variant_dir.py @@ -56,6 +56,14 @@ abs_files = [ 'compile_commands_over_abs_1.json', ] +filter_build_files = [ + 'compile_commands_filter_build.json', +] + +filter_build2_files = [ + 'compile_commands_filter_build2.json', +] + example_rel_file = """[ { "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", @@ -115,4 +123,45 @@ for f in abs_files: test.must_exist(f) test.must_match(f, example_abs_file, mode='r') +example_filter_build_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output_file)s -c %(variant_src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output_file': os.path.join('build', 'test_main.o'), + 'variant_src_file': os.path.join('build', 'test_main.c') + } + +if sys.platform == 'win32': + example_filter_build_file = example_filter_build_file.replace('\\', '\\\\') + +for f in filter_build_files: + test.must_exist(f) + test.must_match(f, example_filter_build_file, mode='r') + +example_filter_build2_file = """[ + { + "command": "%(exe)s mygcc.py cc -o %(output2_file)s -c %(src_file)s", + "directory": "%(workdir)s", + "file": "%(src_file)s", + "output": "%(output2_file)s" + } +]""" % {'exe': sys.executable, + 'workdir': test.workdir, + 'src_file': os.path.join('src', 'test_main.c'), + 'output2_file': os.path.join('build2', 'test_main.o'), + } + +if sys.platform == 'win32': + example_filter_build2_file = example_filter_build2_file.replace('\\', '\\\\') + +for f in filter_build2_files: + test.must_exist(f) + test.must_match(f, example_filter_build2_file, mode='r') + test.pass_test() -- cgit v0.12 From 1a0ba5f53741cc58201084cef93730adaab7b02b Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 23 Nov 2020 20:34:55 -0800 Subject: Update CHANGES.txt working for the change --- CHANGES.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 6440664..38b1cdd 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -30,7 +30,6 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix Issue #3759 - include scons.1, sconsign.1, scons-time.1 manpages in sdist and wheel packages. - Change SCons's build so the generated `SCons/__init__.py` is no longer removed by `scons -c` - From Michał Górny: - Fix dvipdf test failure due to passing incorrect flag to dvipdf. @@ -83,7 +82,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER runtest test for fallback from qmtest, not needed; added new tests. - Eliminate tex tool usage of "for foo in range(len(iterable))" - Restore internal Trace function to functional state. - - Move wix tool into windows-specific section. + - Only try to initialize the wix tool by default (or when tool `default` is explicitly installed) + on Windows based systems. From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command -- cgit v0.12 From 3b7f8b4ce08ce67cca76e0eadf1da3cc6d095fef Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 4 Nov 2020 07:54:29 -0700 Subject: Make the sig for missing file differ from empty file Fixes #3014 Signed-off-by: Mats Wichmann --- SCons/Node/FS.py | 43 ++++++++++++++++++------------------------- SCons/Node/FSTests.py | 10 +++++++--- SCons/Util.py | 4 ++++ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index 5228dc4..51a4f7b 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -2693,11 +2693,13 @@ class File(Base): def scanner_key(self): return self.get_suffix() - def get_contents(self): + def get_contents(self) -> bytes: + """Return the contents of the file as bytes.""" return SCons.Node._get_contents_map[self._func_get_contents](self) - def get_text_contents(self): - """ + def get_text_contents(self) -> str: + """Return the contents of the file in text form. + This attempts to figure out what the encoding of the text is based upon the BOM bytes, and then decodes the contents so that it's a valid python string. @@ -2724,10 +2726,8 @@ class File(Base): return contents.decode('utf-8', errors='backslashreplace') - def get_content_hash(self): - """ - Compute and return the MD5 hash for this file. - """ + def get_content_hash(self) -> str: + """Compute and return the hash of the file contents.""" if not self.rexists(): return MD5signature('') fname = self.rfile().get_abspath() @@ -2740,7 +2740,7 @@ class File(Base): return cs @SCons.Memoize.CountMethodCall - def get_size(self): + def get_size(self) -> int: try: return self._memo['get_size'] except KeyError: @@ -2749,14 +2749,14 @@ class File(Base): if self.rexists(): size = self.rfile().getsize() else: - size = 0 + # sentinel value for doesn't exist, even in repository + size = -1 self._memo['get_size'] = size - return size @SCons.Memoize.CountMethodCall - def get_timestamp(self): + def get_timestamp(self) -> int: try: return self._memo['get_timestamp'] except KeyError: @@ -2768,7 +2768,6 @@ class File(Base): timestamp = 0 self._memo['get_timestamp'] = timestamp - return timestamp convert_copy_attrs = [ @@ -2780,7 +2779,6 @@ class File(Base): 'ninfo', ] - convert_sig_attrs = [ 'bsourcesigs', 'bimplicitsigs', @@ -3173,7 +3171,7 @@ class File(Base): # SIGNATURE SUBSYSTEM # - def get_max_drift_csig(self): + def get_max_drift_csig(self) -> str: """ Returns the content signature currently stored for this node if it's been unmodified longer than the max_drift value, or the @@ -3199,15 +3197,8 @@ class File(Base): return None - 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 - """ + def get_csig(self) -> str: + """Generate a node's content signature.""" ninfo = self.get_ninfo() try: return ninfo.csig @@ -3216,9 +3207,11 @@ class File(Base): csig = self.get_max_drift_csig() if csig is None: - try: - if self.get_size() < File.md5_chunksize: + size = self.get_size() + if size == -1: + contents = SCons.Util.NOFILE + elif size < File.md5_chunksize: contents = self.get_contents() else: csig = self.get_content_hash() diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py index 65cc363..17914c1 100644 --- a/SCons/Node/FSTests.py +++ b/SCons/Node/FSTests.py @@ -2686,8 +2686,11 @@ class FileTestCase(_tempdirTestCase): print("%15s -> csig:%s" % (i3.name, i3.ninfo.csig)) print("%15s -> csig:%s" % (i4.name, i4.ninfo.csig)) - self.assertEqual(i2.name, i2.ninfo.csig, - "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig) + self.assertEqual( + i2.name, + i2.ninfo.csig, + "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig, + ) class GlobTestCase(_tempdirTestCase): @@ -3673,7 +3676,8 @@ class CacheDirTestCase(unittest.TestCase): f9 = fs.File('f9') r = f9.get_cachedir_csig() - assert r == 'd41d8cd98f00b204e9800998ecf8427e', r + exsig = SCons.Util.MD5signature(SCons.Util.NOFILE) + assert r == exsig, r class clearTestCase(unittest.TestCase): diff --git a/SCons/Util.py b/SCons/Util.py index 88aeaae..fae2d64 100644 --- a/SCons/Util.py +++ b/SCons/Util.py @@ -35,6 +35,10 @@ from types import MethodType, FunctionType PYPY = hasattr(sys, 'pypy_translation_info') +# this string will be hashed if a Node refers to a file that doesn't exist +# in order to distinguish from a file that exists but is empty. +NOFILE = "SCONS_MAGIC_MISSING_FILE_STRING" + # unused? def dictify(keys, values, result=None): if result is None: -- cgit v0.12 From 0e5251b992783c1c77ae25eb4b8dba9613ba360e Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 24 Nov 2020 13:23:10 -0700 Subject: Change Trove classification for SCons Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + setup.cfg | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 38b1cdd..fa008d1 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -84,6 +84,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Restore internal Trace function to functional state. - Only try to initialize the wix tool by default (or when tool `default` is explicitly installed) on Windows based systems. + - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/setup.cfg b/setup.cfg index dbb316e..421542f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,7 @@ project-urls = classifiers = Development Status :: 5 - Production/Stable - Topic :: Utilities + Topic :: Software Development :: Build Tools Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only -- cgit v0.12 From 8f93348cbd542b5a90d736d6b13d4b795a162d8e Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 26 Nov 2020 09:53:22 -0700 Subject: Updated sconsign/SConsignFile docs [skip appveyor] The sconsign manpage had some considerably out of date claims, updated to current usage and defaults. The SConsignFile manpage/userguide entry was reworded, mainly to clarify that there's one setting (the presence of env.SConsignFile *might* suggest there could be per-env settings), but also fiddled the wording a fair bit. Use the same arg names as the actual function, since those are usable as kwargs (manpage used to use "file", function accepts "name"). Signed-off-by: Mats Wichmann --- SCons/Environment.xml | 98 ++++++++++++++++++++++++++++++--------------------- SCons/__init__.py | 10 +++--- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/SCons/Environment.xml b/SCons/Environment.xml index a1fd8ec..93c9278 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -2740,59 +2740,74 @@ SConscript('bar/SConscript') # will chdir to bar -([file, dbm_module]) +([name, dbm_module]) -This tells -&scons; -to store all file signatures -in the specified database -file. -If the -file -name is omitted, -.sconsign -is used by default. -(The actual file name(s) stored on disk -may have an appropriated suffix appended -by the -dbm_module.) -If -file -is not an absolute path name, -the file is placed in the same directory as the top-level -&SConstruct; -file. +Store the &SCons; file signature database in +the file name, +using dbm_module +as the file format. +This may be useful to specify alternate +database files and/or file locations for different types of builds. - -If -file -is -None, -then -&scons; -will store file signatures -in a separate -.sconsign -file in each directory, -not in one global database file. -(This was the default behavior -prior to SCons 0.96.91 and 0.97.) +If the optional first argument (or +name keyword argument) +is not an absolute path name, +the file is placed relative to the directory containing the +top-level &SConstruct; file. +The default is +.sconsign. +The actual file name stored on disk +may have an appropriate suffix appended +by the chosen +dbm_module - -The optional +The optional second argument (or dbm_module -argument can be used to specify -which Python database module +keyword argument) can be used to specify +which Python database module to use +for reading/writing the file. The default is to use a custom SCons.dblite module that uses pickled Python data structures, and which works on all Python versions. + +If called with no arguments, +the filename will default to +.sconsign.dblite +in the top directory of the project. +This also the default if +if &f-SConsignFile; is not called. + + +The setting is global, so the only difference +between the global function and the environment method form +is variable expansion. There should only be +one call to this function/method in a given build setup. + + +If +name +is set to +None, +then +&scons; +will store file signatures +in a separate +.sconsign +file in each directory, +not in a single combined database file. +This is a backwards-compatibility meaure to support +what was the default behavior +prior to &SCons; 0.97 (i.e. before 2008). +Use of this mode is discouraged and may be +deprecated in a future &SCons; release. + Examples: @@ -2800,15 +2815,16 @@ Examples: # Explicitly stores signatures in ".sconsign.dblite" -# in the top-level SConstruct directory (the -# default behavior). +# in the top-level SConstruct directory (the default behavior). SConsignFile() # Stores signatures in the file "etc/scons-signatures" # relative to the top-level SConstruct directory. +# SCons will add a database suffix to this name. SConsignFile("etc/scons-signatures") # Stores signatures in the specified absolute file name. +# SCons will add a database suffix to this name. SConsignFile("/home/me/SCons/signatures") # Stores signatures in a separate .sconsign file diff --git a/SCons/__init__.py b/SCons/__init__.py index fcd665e..f9d2085 100644 --- a/SCons/__init__.py +++ b/SCons/__init__.py @@ -1,9 +1,9 @@ __version__="4.0.1.9998" __copyright__="Copyright (c) 2001 - 2020 The SCons Foundation" -__developer__="bdbaddog" -__date__="2020-10-09 19:00:35" -__buildsys__="ProDog2020" -__revision__="93525bed88d19a00f5de400086c0046011d3b833" -__build__="93525bed88d19a00f5de400086c0046011d3b833" +__developer__="mats" +__date__="2020-11-26 16:47:04" +__buildsys__="boulder" +__revision__="64a80e530b0caef9763eb67bd770dd9c8925ea18" +__build__="64a80e530b0caef9763eb67bd770dd9c8925ea18" # make sure compatibility is always in place import SCons.compat # noqa \ No newline at end of file -- cgit v0.12 From 17097d79ac67adff904deae714ec024f497efcdd Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 27 Nov 2020 12:00:25 -0700 Subject: Fix botched checkin [skip appveyor] Checked in the SCons/__init__.py instead of the changes to the sconsign manpage. Restoring the former and updating the latter. Signed-off-by: Mats Wichmann --- SCons/__init__.py | 10 +++---- doc/man/sconsign.xml | 85 +++++++++++++++++++++++----------------------------- 2 files changed, 43 insertions(+), 52 deletions(-) diff --git a/SCons/__init__.py b/SCons/__init__.py index f9d2085..fcd665e 100644 --- a/SCons/__init__.py +++ b/SCons/__init__.py @@ -1,9 +1,9 @@ __version__="4.0.1.9998" __copyright__="Copyright (c) 2001 - 2020 The SCons Foundation" -__developer__="mats" -__date__="2020-11-26 16:47:04" -__buildsys__="boulder" -__revision__="64a80e530b0caef9763eb67bd770dd9c8925ea18" -__build__="64a80e530b0caef9763eb67bd770dd9c8925ea18" +__developer__="bdbaddog" +__date__="2020-10-09 19:00:35" +__buildsys__="ProDog2020" +__revision__="93525bed88d19a00f5de400086c0046011d3b833" +__build__="93525bed88d19a00f5de400086c0046011d3b833" # make sure compatibility is always in place import SCons.compat # noqa \ No newline at end of file diff --git a/doc/man/sconsign.xml b/doc/man/sconsign.xml index d2d14c7..726f86e 100644 --- a/doc/man/sconsign.xml +++ b/doc/man/sconsign.xml @@ -49,67 +49,58 @@ DESCRIPTION -The -sconsign -command -displays the contents of one or more signature database -(sconsign) -files used by the scons build tool. + +Displays the contents of one or more +sconsign files, +the signature database files +used by the SCons build tool. By default, sconsign dumps the entire contents of the sconsign file(s). -Without the verbose option, -each entry is printed in the following format: +Without options, +individual dependency entries are printed in the following format: - -file: signature timestamp length - implicit_dependency_1: signature timestamp length - implicit_dependency_2: signature timestamp length + +depfile: signature timestamp length + implicit_dependency_1: content_signature timestamp length + implicit_dependency_2: content_signature timestamp length ... action_signature [action string] - + None -is printed -in place of any missing timestamp, build signature -(bsig), -or content signature +is printed in place of any missing timestamp, + content signature (csig) -values for -any entry +or +build action signature +values for any entry or any of its dependencies. If the entry has no implicit dependencies, or no build action, -the lines are simply omitted. - - -The verbose option expands the display into a more human -readable format. - +those lines are omitted. By default, sconsign assumes that any file arguments that end with a -.dbm +.dblite suffix contains signature entries for more than one directory (that is, was specified by the -SConsignFile +SConsignFile function). Any file -argument that ends in -.dblite -is assumed to be a traditional -sconsign -file containing the signature entries +argument that has no suffix +is assumed to be an old-style +sconsign file containing the signature entries for a single directory. If neither of those is true, sconsign @@ -127,7 +118,7 @@ If there are no file arguments, the name .sconsign.dblite -is assumed. +is assumed by default. @@ -145,7 +136,7 @@ and the format: -Prints the build action information +Prints only the build action information for all entries or the specified entries. @@ -156,7 +147,7 @@ for all entries or the specified entries. -Prints the content signature (csig) information +Prints only the content signature (csig) information for all entries or the specified entries. @@ -169,11 +160,11 @@ for all entries or the specified entries. When the signatures are being read from a -.dbm +.dblite file, or the - + or - + options are used, prints information about only the signatures @@ -208,15 +199,15 @@ options are specified on the command line. are in the specified FORMAT. Legal values are -dbm -(the DBM format used -when the -SConsignFile -function is used) -or -sconsign -(the default format -used for an individual +dblite +(the SCons.dblite format used by default, +as well as when the +SConsignFile +function is called, except when a filename argument +of None is given) +and +sconsign +(the format used for an individual .sconsign file in each directory). -- cgit v0.12 From ffbc4a40573fad1ccd6685d896af930208a769c1 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 10 Sep 2020 12:56:27 -0600 Subject: dblite tweaks use os.replace instead of the dance around os.rename which behaves differently on Windows. use True/False for flags for clarity. Fix some PEP8 warnings. Signed-off-by: Mats Wichmann --- SCons/SConsign.py | 12 ++++--- SCons/Utilities/sconsign.py | 4 +-- SCons/dblite.py | 77 +++++++++++++++++---------------------------- 3 files changed, 37 insertions(+), 56 deletions(-) diff --git a/SCons/SConsign.py b/SCons/SConsign.py index 8e3ebf4..95b8096 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -35,10 +35,12 @@ from SCons.compat import PICKLE_PROTOCOL def corrupt_dblite_warning(filename): - SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, - "Ignoring corrupt .sconsign file: %s"%filename) + SCons.Warnings.warn( + SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt .sconsign file: %s" % filename, + ) -SCons.dblite.ignore_corrupt_dbfiles = 1 +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. @@ -141,7 +143,7 @@ class SConsignEntry: def __getstate__(self): state = getattr(self, '__dict__', {}).copy() for obj in type(self).mro(): - for name in getattr(obj,'__slots__',()): + for name in getattr(obj, '__slots__', ()): if hasattr(self, name): state[name] = getattr(self, name) @@ -154,7 +156,7 @@ class SConsignEntry: def __setstate__(self, state): for key, value in state.items(): - if key not in ('_version_id','__weakref__'): + if key not in ('_version_id', '__weakref__'): setattr(self, key, value) diff --git a/SCons/Utilities/sconsign.py b/SCons/Utilities/sconsign.py index 3288779..e595b2d 100644 --- a/SCons/Utilities/sconsign.py +++ b/SCons/Utilities/sconsign.py @@ -431,7 +431,7 @@ def main(): # Ensure that we don't ignore corrupt DB files, # this was handled by calling my_import('SCons.dblite') # again in earlier versions... - SCons.dblite.ignore_corrupt_dbfiles = 0 + SCons.dblite.IGNORE_CORRUPT_DBFILES = False except ImportError: sys.stderr.write("sconsign: illegal file format `%s'\n" % a) print(helpstr) @@ -474,7 +474,7 @@ def main(): # Ensure that we don't ignore corrupt DB files, # this was handled by calling my_import('SCons.dblite') # again in earlier versions... - SCons.dblite.ignore_corrupt_dbfiles = 0 + SCons.dblite.IGNORE_CORRUPT_DBFILES = False Do_SConsignDB(Map_Module.get(dbm_name, dbm_name), dbm)(a) else: Do_SConsignDir(a) diff --git a/SCons/dblite.py b/SCons/dblite.py index c6943e3..f744c9a 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -33,20 +33,20 @@ import time from SCons.compat import PICKLE_PROTOCOL -keep_all_files = 00000 -ignore_corrupt_dbfiles = 0 +KEEP_ALL_FILES = False +IGNORE_CORRUPT_DBFILES = False def corruption_warning(filename): - print("Warning: Discarding corrupt database:", filename) - + """Local warning for corrupt db. -dblite_suffix = '.dblite' + Used for self-tests. SCons overwrites this with a + different warning function in SConsign.py. + """ + print("Warning: Discarding corrupt database:", filename) -# TODO: Does commenting this out break switching from py2/3? -# if bytes is not str: -# dblite_suffix += '.p3' -tmp_suffix = '.tmp' +DBLITE_SUFFIX = '.dblite' +TMP_SUFFIX = '.tmp' class dblite: @@ -66,15 +66,13 @@ class dblite: _open = open _pickle_dump = staticmethod(pickle.dump) _pickle_protocol = PICKLE_PROTOCOL - _os_chmod = os.chmod try: _os_chown = os.chown except AttributeError: _os_chown = None - _os_rename = os.rename - _os_unlink = os.unlink + _os_replace = os.replace _shutil_copyfile = shutil.copyfile _time_time = time.time @@ -84,18 +82,18 @@ class dblite: flag = "r" base, ext = os.path.splitext(file_base_name) - if ext == dblite_suffix: + if ext == DBLITE_SUFFIX: # There's already a suffix on the file name, don't add one. self._file_name = file_base_name - self._tmp_name = base + tmp_suffix + self._tmp_name = base + TMP_SUFFIX else: - self._file_name = file_base_name + dblite_suffix - self._tmp_name = file_base_name + tmp_suffix + self._file_name = file_base_name + DBLITE_SUFFIX + self._tmp_name = file_base_name + TMP_SUFFIX self._flag = flag self._mode = mode self._dict = {} - self._needs_sync = 00000 + self._needs_sync = False if self._os_chown is not None and (os.geteuid() == 0 or os.getuid() == 0): # running as root; chown back to current owner/group when done @@ -103,7 +101,7 @@ class dblite: statinfo = os.stat(self._file_name) self._chown_to = statinfo.st_uid self._chgrp_to = statinfo.st_gid - except OSError as e: + except OSError: # db file doesn't exist yet. # Check os.environ for SUDO_UID, use if set self._chown_to = int(os.environ.get('SUDO_UID', -1)) @@ -128,15 +126,12 @@ class dblite: f.close() if len(p) > 0: try: - if bytes is not str: - self._dict = pickle.loads(p, encoding='bytes') - else: - self._dict = pickle.loads(p) + self._dict = pickle.loads(p, encoding='bytes') except (pickle.UnpicklingError, EOFError, KeyError): # Note how we catch KeyErrors too here, which might happen # when we don't have cPickle available (default pickle # throws it). - if ignore_corrupt_dbfiles: + if IGNORE_CORRUPT_DBFILES: corruption_warning(self._file_name) else: raise @@ -150,29 +145,16 @@ class dblite: def sync(self): self._check_writable() - f = self._open(self._tmp_name, "wb", self._mode) - self._pickle_dump(self._dict, f, self._pickle_protocol) - f.close() - - # Windows doesn't allow renaming if the file exists, so unlink - # it first, chmod'ing it to make sure we can do so. On UNIX, we - # may not be able to chmod the file if it's owned by someone else - # (e.g. from a previous run as root). We should still be able to - # unlink() the file if the directory's writable, though, so ignore - # any OSError exception thrown by the chmod() call. - try: - self._os_chmod(self._file_name, 0o777) - except OSError: - pass - self._os_unlink(self._file_name) - self._os_rename(self._tmp_name, self._file_name) + with self._open(self._tmp_name, "wb", self._mode) as f: + self._pickle_dump(self._dict, f, self._pickle_protocol) + self._os_replace(self._tmp_name, self._file_name) if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1 try: self._os_chown(self._file_name, self._chown_to, self._chgrp_to) except OSError: pass - self._needs_sync = 00000 - if keep_all_files: + self._needs_sync = False + if KEEP_ALL_FILES: self._shutil_copyfile( self._file_name, self._file_name + "_" + str(int(self._time_time()))) @@ -194,7 +176,7 @@ class dblite: raise TypeError("value `%s' must be a bytes but is %s" % (value, type(value))) self._dict[key] = value - self._needs_sync = 0o001 + self._needs_sync = True def keys(self): return list(self._dict.keys()) @@ -205,11 +187,8 @@ class dblite: def __contains__(self, key): return key in self._dict - def iterkeys(self): - # Wrapping name in () prevents fixer from "fixing" this - return (self._dict.iterkeys)() - - __iter__ = iterkeys + def __iter__(self): + return iter(self._dict) def __len__(self): return len(self._dict) @@ -278,8 +257,8 @@ def _exercise(): else: raise RuntimeError("pickle exception expected.") - global ignore_corrupt_dbfiles - ignore_corrupt_dbfiles = 2 + global IGNORE_CORRUPT_DBFILES + IGNORE_CORRUPT_DBFILES = True db = open("tmp", "r") assert len(db) == 0, len(db) os.unlink("tmp.dblite") -- cgit v0.12 From eb9cd2e2c153be1a1da1466098aae068e8bd6ecc Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 2 Dec 2020 07:25:30 -0700 Subject: Actually add the CHANGES.txt changes Signed-off-by: Mats Wichmann --- CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index fa008d1..c30699f 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -85,6 +85,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Only try to initialize the wix tool by default (or when tool `default` is explicitly installed) on Windows based systems. - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools + - Use os.replace instead of os.rename in dblite so don't need to + special-case Windows here. From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command -- cgit v0.12 From 2f6a933a155121093e5427fab7e82cefe0cbe6ab Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 4 Dec 2020 08:50:24 -0700 Subject: [PR #3836] add example of SConsign(dbm_modue=...) (skip appveyor) It wasn't clear that you need to pass the module name to SConsignFile, the expectation might be to pass a string, so clarified and an example added to show it. Some of the wording was simplified a bit. Added a testcase of explicity passing dbm_module=SCons.dblite, as this should work. Signed-off-by: Mats Wichmann --- SCons/Environment.xml | 57 ++++++++++++--------- test/SConsignFile/explicit-dbm-module.py | 87 ++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 test/SConsignFile/explicit-dbm-module.py diff --git a/SCons/Environment.xml b/SCons/Environment.xml index 93c9278..d594bdf 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -2744,58 +2744,61 @@ SConscript('bar/SConscript') # will chdir to bar -Store the &SCons; file signature database in -the file name, -using dbm_module -as the file format. +Specify where to store the &SCons; file signature database, +and which database format to use. This may be useful to specify alternate database files and/or file locations for different types of builds. -If the optional first argument (or -name keyword argument) -is not an absolute path name, -the file is placed relative to the directory containing the +The optional name argument +is the base name of the database file(s). +If not an absolute path name, +these are placed relative to the directory containing the top-level &SConstruct; file. The default is .sconsign. -The actual file name stored on disk +The actual database file(s) stored on disk may have an appropriate suffix appended by the chosen dbm_module -The optional second argument (or -dbm_module -keyword argument) can be used to specify -which Python database module to use +The optional dbm_module +argument specifies which +Python database module to use for reading/writing the file. -The default is to use a custom -SCons.dblite +The module must be imported first; +then the imported module name +is passed as the argument. +The default is a custom +SCons.dblite module that uses pickled Python data structures, -and which works on all Python versions. +which works on all Python versions. +See documentation of the Python +dbm module +for other available types. -If called with no arguments, -the filename will default to +If called with no arguments, +the database will default to .sconsign.dblite -in the top directory of the project. -This also the default if +in the top directory of the project, +which is also the default if if &f-SConsignFile; is not called. The setting is global, so the only difference between the global function and the environment method form -is variable expansion. There should only be -one call to this function/method in a given build setup. +is variable expansion on name. +There should only be one active call to this +function/method in a given build setup. -If +If name is set to None, -then &scons; will store file signatures in a separate @@ -2805,7 +2808,7 @@ not in a single combined database file. This is a backwards-compatibility meaure to support what was the default behavior prior to &SCons; 0.97 (i.e. before 2008). -Use of this mode is discouraged and may be +Use of this mode is discouraged and may be deprecated in a future &SCons; release. @@ -2830,6 +2833,10 @@ SConsignFile("/home/me/SCons/signatures") # Stores signatures in a separate .sconsign file # in each directory. SConsignFile(None) + +# Stores signatures in a GNU dbm format .sconsign file +import dbm.gnu +SConsignFile(dbm_module=dbm.gnu) diff --git a/test/SConsignFile/explicit-dbm-module.py b/test/SConsignFile/explicit-dbm-module.py new file mode 100644 index 0000000..09b75ae --- /dev/null +++ b/test/SConsignFile/explicit-dbm-module.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# MIT License +# +# Copyright The SCons Foundation +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Verify SConsignFile() when used with explicit SCons.dblite.""" + +import os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +import SCons.dblite +use_db = 'SCons.dblite' + +test.subdir('subdir') + +test.write('build.py', r""" +import sys +with open(sys.argv[1], 'wb') as ofp, open(sys.argv[2], 'rb') as ifp: + ofp.write(ifp.read()) +sys.exit(0) +""") + +test.write('SConstruct', """ +import %(use_db)s +SConsignFile(dbm_module=%(use_db)s) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +DefaultEnvironment(tools=[]) +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') +""" % locals()) + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write(['subdir', 'f3.in'], "subdir/f3.in\n") +test.write(['subdir', 'f4.in'], "subdir/f4.in\n") + +test.run() + +test.must_exist(test.workpath('.sconsign.dblite')) +test.must_not_exist(test.workpath('.sconsign')) +test.must_not_exist(test.workpath('subdir', '.sconsign')) + +test.must_match('f1.out', "f1.in\n") +test.must_match('f2.out', "f2.in\n") +test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") +test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") + +test.up_to_date(arguments='.') + +test.must_exist(test.workpath('.sconsign.dblite')) +test.must_not_exist(test.workpath('.sconsign')) +test.must_not_exist(test.workpath('subdir', '.sconsign')) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From 75ff4da60792a2f6734a3402345cc19825584558 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 4 Dec 2020 16:52:55 -0700 Subject: [PR #3837] retry sconsign replacement on fail The pending change stopped fiddling to try to get around an unwritable .sconsign.dblite which needs updating - this is apparently expected to work, so added a retry with some permission fiddling. Signed-off-by: Mats Wichmann --- SCons/dblite.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SCons/dblite.py b/SCons/dblite.py index f744c9a..7b5f513 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -73,6 +73,7 @@ class dblite: _os_chown = None _os_replace = os.replace + _os_chmod = os.chmod _shutil_copyfile = shutil.copyfile _time_time = time.time @@ -147,12 +148,20 @@ class dblite: self._check_writable() with self._open(self._tmp_name, "wb", self._mode) as f: self._pickle_dump(self._dict, f, self._pickle_protocol) - self._os_replace(self._tmp_name, self._file_name) + + try: + self._os_replace(self._tmp_name, self._file_name) + except PermissionError: + # if we couldn't replace due to perms, try to fiddle them and retry + self._os_chmod(self._file_name, 0o777) + self._os_replace(self._tmp_name, self._file_name) + if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1 try: self._os_chown(self._file_name, self._chown_to, self._chgrp_to) except OSError: pass + self._needs_sync = False if KEEP_ALL_FILES: self._shutil_copyfile( -- cgit v0.12 From 1250170e9d12f8b894a7bc6a27a63fddaca702b7 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 5 Dec 2020 09:33:39 -0700 Subject: [PR #3836] while we're at it, update SConsignFile tests Formatting, copyright header, make sure to null out tools to speed up Windeows. Signed-off-by: Mats Wichmann --- test/SConsignFile/default.py | 24 +++++++++---------- test/SConsignFile/explicit-dbm-module.py | 3 ++- test/SConsignFile/explicit-file.py | 26 ++++++++++----------- test/SConsignFile/make-directory.py | 17 +++++++------- test/SConsignFile/use-dbhash.py | 18 +++++++------- test/SConsignFile/use-dbm.py | 40 ++++++++++++++------------------ test/SConsignFile/use-dumbdbm.py | 25 ++++++++++---------- test/SConsignFile/use-gdbm.py | 23 +++++++++--------- 8 files changed, 85 insertions(+), 91 deletions(-) diff --git a/test/SConsignFile/default.py b/test/SConsignFile/default.py index ed1ed56..281632d 100644 --- a/test/SConsignFile/default.py +++ b/test/SConsignFile/default.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,12 +22,9 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ -Verify the default behavior of SConsignFile(), called with no arguments. +Verify the behavior of SConsignFile() called with a subst-able path. """ import TestSCons @@ -46,12 +45,13 @@ sys.exit(0) # test.write('SConstruct', """ SConsignFile() -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -70,7 +70,7 @@ test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.must_exist(test.workpath('.sconsign.dblite')) test.must_not_exist(test.workpath('.sconsign')) diff --git a/test/SConsignFile/explicit-dbm-module.py b/test/SConsignFile/explicit-dbm-module.py index 09b75ae..2461d5c 100644 --- a/test/SConsignFile/explicit-dbm-module.py +++ b/test/SConsignFile/explicit-dbm-module.py @@ -3,6 +3,7 @@ # 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 @@ -47,8 +48,8 @@ sys.exit(0) test.write('SConstruct', """ import %(use_db)s SConsignFile(dbm_module=%(use_db)s) -B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') env = Environment(BUILDERS={'B': B}, tools=[]) env.B(target='f1.out', source='f1.in') env.B(target='f2.out', source='f2.in') diff --git a/test/SConsignFile/explicit-file.py b/test/SConsignFile/explicit-file.py index afb2dbd..d579858 100644 --- a/test/SConsignFile/explicit-file.py +++ b/test/SConsignFile/explicit-file.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,12 +22,9 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ -Verify the default behavior of SConsignFile(), called with no arguments. +Verify the default behavior of env.SConsignFile(), called with no arguments. """ import TestSCons @@ -44,14 +43,15 @@ with open(sys.argv[1], 'wb') as ofp, open(sys.argv[2], 'rb') as ifp: # test.write('SConstruct', """ -e = Environment(XXX = 'scons') +DefaultEnvironment(tools=[]) +e = Environment(XXX='scons', tools=[]) e.SConsignFile('my_${XXX}ign') -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f5.out', source = 'f5.in') -env.B(target = 'f6.out', source = 'f6.in') -env.B(target = 'subdir/f7.out', source = 'subdir/f7.in') -env.B(target = 'subdir/f8.out', source = 'subdir/f8.in') +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f5.out', source='f5.in') +env.B(target='f6.out', source='f6.in') +env.B(target='subdir/f7.out', source='subdir/f7.in') +env.B(target='subdir/f8.out', source='subdir/f8.in') """ % locals()) test.write('f5.in', "f5.in\n") @@ -70,7 +70,7 @@ test.must_match('f6.out', "f6.in\n") test.must_match(['subdir', 'f7.out'], "subdir/f7.in\n") test.must_match(['subdir', 'f8.out'], "subdir/f8.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.must_exist(test.workpath('my_sconsign.dblite')) test.must_not_exist(test.workpath('.sconsign')) diff --git a/test/SConsignFile/make-directory.py b/test/SConsignFile/make-directory.py index 50bab79..264ee26 100644 --- a/test/SConsignFile/make-directory.py +++ b/test/SConsignFile/make-directory.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ Verify the ability to make a SConsignFile() in a non-existent @@ -40,15 +39,17 @@ bar_foo_txt = os.path.join('bar', 'foo.txt') test.write('SConstruct', """ import SCons.dblite -env = Environment() +DefaultEnvironment(tools=[]) +env = Environment(tools=[]) env.SConsignFile("sub/dir/sconsign", SCons.dblite) env.Install('bar', 'foo.txt') """) test.write('foo.txt', "Foo\n") - -expect = test.wrap_stdout(read_str = 'Mkdir("%s")\n' % sub_dir, - build_str = 'Install file: "foo.txt" as "%s"\n' % bar_foo_txt) +expect = test.wrap_stdout( + read_str='Mkdir("%s")\n' % sub_dir, + build_str='Install file: "foo.txt" as "%s"\n' % bar_foo_txt, +) test.run(options='-n', stdout=expect) diff --git a/test/SConsignFile/use-dbhash.py b/test/SConsignFile/use-dbhash.py index e57e244..0e8e40c 100644 --- a/test/SConsignFile/use-dbhash.py +++ b/test/SConsignFile/use-dbhash.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ Verify SConsignFile() when used with dbhash. @@ -36,8 +35,9 @@ test = TestSCons.TestSCons() try: import dbm.bsd + use_dbm = 'dbm.bsd' except ImportError: - test.skip_test('No dbhash in this version of Python; skipping test.\n') + test.skip_test('No dbm.bsd in this version of Python; skipping test.\n') test.subdir('subdir') @@ -50,11 +50,11 @@ sys.exit(0) # test.write('SConstruct', """ -import sys -import dbhash -SConsignFile('.sconsign', dbhash) +import %(use_dbm +SConsignFile('.sconsign', %(use_dbm)s) +DefaultEnvironment(tools=[]) B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) +env = Environment(BUILDERS={'B': B}, tools=[]) env.B(target = 'f1.out', source = 'f1.in') env.B(target = 'f2.out', source = 'f2.in') env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') diff --git a/test/SConsignFile/use-dbm.py b/test/SConsignFile/use-dbm.py index 5100916..a1ef1b2 100644 --- a/test/SConsignFile/use-dbm.py +++ b/test/SConsignFile/use-dbm.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ Verify SConsignFile() when used with dbm. @@ -37,15 +36,9 @@ test = TestSCons.TestSCons() try: import dbm.ndbm - - use_db = 'dbm.ndbm' + use_dbm = 'dbm.ndbm' except ImportError: - try: - import dbm - - use_db = 'dbm' - except ImportError: - test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n') + test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n') test.subdir('subdir') @@ -58,16 +51,15 @@ sys.exit(0) # test.write('SConstruct', """ -import sys -import %(use_db)s -SConsignFile('.sconsign', %(use_db)s) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') +import %(use_dbm)s +SConsignFile('.sconsign', %(use_dbm)s) DefaultEnvironment(tools=[]) -env = Environment(BUILDERS = { 'B' : B }, tools=[]) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -80,8 +72,10 @@ test.run() # We don't check for explicit .db or other file, because base "dbm" # can use different file extensions on different implementations. -test.fail_test(os.path.exists('.sconsign') and 'dbm' not in dbm.whichdb('.sconsign'), - message=".sconsign existed and wasn't any type of dbm file") +test.fail_test( + os.path.exists('.sconsign') and 'dbm' not in dbm.whichdb('.sconsign'), + message=".sconsign existed and wasn't any type of dbm file", +) test.must_not_exist(test.workpath('.sconsign.dblite')) test.must_not_exist(test.workpath('subdir', '.sconsign')) test.must_not_exist(test.workpath('subdir', '.sconsign.dblite')) diff --git a/test/SConsignFile/use-dumbdbm.py b/test/SConsignFile/use-dumbdbm.py index 22b0bff..875f3fc 100644 --- a/test/SConsignFile/use-dumbdbm.py +++ b/test/SConsignFile/use-dumbdbm.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ Verify SConsignFile() when used with dumbdbm. @@ -36,7 +35,7 @@ test = TestSCons.TestSCons() try: import dbm.dumb - use_dbm='dbm.dumb' + use_dbm = 'dbm.dumb' except ImportError: test.skip_test('No dbm.dumb in this version of Python; skipping test.\n') @@ -51,15 +50,15 @@ sys.exit(0) # test.write('SConstruct', """ -import sys import %(use_dbm)s SConsignFile('.sconsign', %(use_dbm)s) -B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +DefaultEnvironment(tools=[]) +B = Builder(action=r'%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -83,7 +82,7 @@ test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.must_exist(test.workpath('.sconsign.dat')) test.must_exist(test.workpath('.sconsign.dir')) diff --git a/test/SConsignFile/use-gdbm.py b/test/SConsignFile/use-gdbm.py index 461a482..c1f0c4d 100644 --- a/test/SConsignFile/use-gdbm.py +++ b/test/SConsignFile/use-gdbm.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ Verify SConsignFile() when used with gdbm. @@ -51,15 +50,15 @@ sys.exit(0) # test.write('SConstruct', """ -import sys import %(use_dbm)s SConsignFile('.sconsign', %(use_dbm)s) -B = Builder(action = '%(_python_)s build.py $TARGETS $SOURCES') -env = Environment(BUILDERS = { 'B' : B }) -env.B(target = 'f1.out', source = 'f1.in') -env.B(target = 'f2.out', source = 'f2.in') -env.B(target = 'subdir/f3.out', source = 'subdir/f3.in') -env.B(target = 'subdir/f4.out', source = 'subdir/f4.in') +DefaultEnvironment(tools=[]) +B = Builder(action='%(_python_)s build.py $TARGETS $SOURCES') +env = Environment(BUILDERS={'B': B}, tools=[]) +env.B(target='f1.out', source='f1.in') +env.B(target='f2.out', source='f2.in') +env.B(target='subdir/f3.out', source='subdir/f3.in') +env.B(target='subdir/f4.out', source='subdir/f4.in') """ % locals()) test.write('f1.in', "f1.in\n") @@ -79,7 +78,7 @@ test.must_match('f2.out', "f2.in\n") test.must_match(['subdir', 'f3.out'], "subdir/f3.in\n") test.must_match(['subdir', 'f4.out'], "subdir/f4.in\n") -test.up_to_date(arguments = '.') +test.up_to_date(arguments='.') test.must_exist(test.workpath('.sconsign')) test.must_not_exist(test.workpath('.sconsign.dblite')) -- cgit v0.12 From 21cabcad728cd004166266db4f8fda6627e82b43 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 5 Dec 2020 09:39:41 -0700 Subject: [PR #3836] quiet sider complaints on explicit-dbm-module.py Signed-off-by: Mats Wichmann --- test/SConsignFile/explicit-dbm-module.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/SConsignFile/explicit-dbm-module.py b/test/SConsignFile/explicit-dbm-module.py index 2461d5c..c093271 100644 --- a/test/SConsignFile/explicit-dbm-module.py +++ b/test/SConsignFile/explicit-dbm-module.py @@ -25,15 +25,12 @@ """Verify SConsignFile() when used with explicit SCons.dblite.""" -import os.path - import TestSCons _python_ = TestSCons._python_ test = TestSCons.TestSCons() -import SCons.dblite use_db = 'SCons.dblite' test.subdir('subdir') -- cgit v0.12 From 2fb6e6b0e699ea5e4f98bbfe92066aa5d38c799b Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 5 Dec 2020 12:13:38 -0700 Subject: Flesh out comment on sconsign file sync Signed-off-by: Mats Wichmann --- SCons/dblite.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/SCons/dblite.py b/SCons/dblite.py index 7b5f513..a5186ca 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -71,7 +71,6 @@ class dblite: _os_chown = os.chown except AttributeError: _os_chown = None - _os_replace = os.replace _os_chmod = os.chmod _shutil_copyfile = shutil.copyfile @@ -152,8 +151,15 @@ class dblite: try: self._os_replace(self._tmp_name, self._file_name) except PermissionError: - # if we couldn't replace due to perms, try to fiddle them and retry - self._os_chmod(self._file_name, 0o777) + # If we couldn't replace due to perms, try to change and retry. + # This is mainly for Windows - on POSIX the file permissions + # don't matter, the os.replace would have worked anyway. + # We're giving up if the retry fails, just let the Python + # exception abort us. + try: + self._os_chmod(self._file_name, 0o777) + except PermissionError: + pass self._os_replace(self._tmp_name, self._file_name) if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1 @@ -166,7 +172,8 @@ class dblite: if KEEP_ALL_FILES: self._shutil_copyfile( self._file_name, - self._file_name + "_" + str(int(self._time_time()))) + self._file_name + "_" + str(int(self._time_time())) + ) def _check_writable(self): if self._flag == "r": -- cgit v0.12 From 55237c51268320b5048bb53caa9ec53ae23b2abd Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 8 Dec 2020 11:06:37 -0800 Subject: [ci skip] Add more detail to CHANGES.txt entry for updates to dblite --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index c30699f..613cabe 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -86,7 +86,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER on Windows based systems. - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools - Use os.replace instead of os.rename in dblite so don't need to - special-case Windows here. + special-case Windows here. dblite is the default storage engine for the SConsign file(s). From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command -- cgit v0.12 From 321d48ae6699919858bee412634489ff2d2f78cd Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 8 Dec 2020 14:45:32 -0700 Subject: Fix broken mod to (unused) test An edit to the use-dbhash.py test file missed a bit. Might as well fix, although the test is always skipped since the Python dbm module it tests does not exist in any current Python version. Signed-off-by: Mats Wichmann --- test/SConsignFile/use-dbhash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConsignFile/use-dbhash.py b/test/SConsignFile/use-dbhash.py index 0e8e40c..2968cd7 100644 --- a/test/SConsignFile/use-dbhash.py +++ b/test/SConsignFile/use-dbhash.py @@ -50,7 +50,7 @@ sys.exit(0) # test.write('SConstruct', """ -import %(use_dbm +import %(use_dbm)s SConsignFile('.sconsign', %(use_dbm)s) DefaultEnvironment(tools=[]) B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES') -- cgit v0.12 From d04ebf6041247978f3c0bc4f943ed86854153e23 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 11 Dec 2020 07:23:44 -0700 Subject: Fix a lingering typo in msvc debug output [travis skip] Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + SCons/Tool/MSCommon/vc.py | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 613cabe..aa71c31 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -87,6 +87,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools - Use os.replace instead of os.rename in dblite so don't need to special-case Windows here. dblite is the default storage engine for the SConsign file(s). + - Fix cut-n-paste error in msvc debug printout. From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py index 9a43ae1..e50277d 100644 --- a/SCons/Tool/MSCommon/vc.py +++ b/SCons/Tool/MSCommon/vc.py @@ -203,7 +203,7 @@ def get_host_target(env): # Retain user requested TARGET_ARCH req_target_platform = env.get('TARGET_ARCH') - debug("HOST_ARCH:" + str(req_target_platform)) + debug("TARGET_ARCH:" + str(req_target_platform)) if req_target_platform: # If user requested a specific platform then only try that one. target_platform = req_target_platform @@ -220,9 +220,12 @@ def get_host_target(env): target = _ARCH_TO_CANONICAL[target_platform.lower()] except KeyError: all_archs = str(list(_ARCH_TO_CANONICAL.keys())) - raise MSVCUnsupportedTargetArch("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs)) + raise MSVCUnsupportedTargetArch( + "Unrecognized target architecture %s\n\tValid architectures: %s" + % (target_platform, all_archs) + ) - return (host, target,req_target_platform) + return (host, target, req_target_platform) # If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the # MSVC_VERSION documentation in Tool/msvc.xml. -- cgit v0.12 From 4398c19f8e6cf1210073cd640623a0597ab7bf56 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 12 Dec 2020 08:44:55 -0700 Subject: Quiet some msvs debug output Unconditional prints in msvs.py and msvsTests.py really are only for debugging, comment out and mark with # DEBUG so they're easy to find and turn on again if needed. Reduces size of test run log on Windows by about 2/3. Signed-off-by: Mats Wichmann --- CHANGES.txt | 3 ++- SCons/Tool/msvs.py | 10 +++++++--- SCons/Tool/msvsTests.py | 26 ++++++++++++++++++++------ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index aa71c31..fb872b6 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -87,7 +87,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Pick a better "Topic" Trove classifier for SCons: SW Dev / Build Tools - Use os.replace instead of os.rename in dblite so don't need to special-case Windows here. dblite is the default storage engine for the SConsign file(s). - - Fix cut-n-paste error in msvc debug printout. + - Fix cut-n-paste error in msvc debug printout and make some debug output + in msvs and msvsTests.py be off until needed (uncomment to use) From Simon Tegelid - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index c10b802..eb7872d 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -607,7 +607,8 @@ class _DSPGenerator: config.platform = 'Win32' self.configs[variant] = config - print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") + # DEBUG + # print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") for i in range(len(variants)): AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i], cppdefines[i], cpppaths[i], cppflags[i]) @@ -1444,7 +1445,9 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): '\t\n' % str(self.sconscript)) def Parse(self): - print("_GenerateV10DSP.Parse()") + # DEBUG + # print("_GenerateV10DSP.Parse()") + pass def Build(self): try: @@ -1530,7 +1533,8 @@ class _GenerateV7DSW(_DSWGenerator): config.platform = 'Win32' self.configs[variant] = config - print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") + # DEBUG + # print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") if 'variant' not in env: raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ diff --git a/SCons/Tool/msvsTests.py b/SCons/Tool/msvsTests.py index 30c3b58..336c6f9 100644 --- a/SCons/Tool/msvsTests.py +++ b/SCons/Tool/msvsTests.py @@ -564,17 +564,20 @@ def DummyEnumKey(key, index): rv = key.keyarray[index] except IndexError: raise SCons.Util.RegError -# print "Enum Key",key.name,"[",index,"] =>",rv + # DEBUG + # print "Enum Key",key.name,"[",index,"] =>",rv return rv def DummyEnumValue(key, index): rv = key.valindex(index) -# print "Enum Value",key.name,"[",index,"] =>",rv + # DEBUG + # print "Enum Value",key.name,"[",index,"] =>",rv return rv def DummyQueryValue(key, value): rv = key.value(value) -# print "Query Value",key.name+"\\"+value,"=>",rv + # DEBUG + # print "Query Value",key.name+"\\"+value,"=>",rv return rv def DummyExists(path): @@ -726,8 +729,18 @@ class msvsTestCase(unittest.TestCase): for param_cppdefines, expected_cppdefines in tests_cppdefines: for param_cpppaths, expected_cpppaths in tests_cpppaths: for param_cppflags, expected_cppflags in tests_cppflags: - print('Testing %s. with :\n variant = %s \n cmdargs = "%s" \n cppdefines = "%s" \n cpppaths = "%s" \n cppflags = "%s"' % \ - (str_function_test, list_variant, param_cmdargs, param_cppdefines, param_cpppaths, param_cppflags)) + # DEBUG: + # print( + # 'Testing %s. with :\n variant = %s \n cmdargs = "%s" \n cppdefines = "%s" \n cpppaths = "%s" \n cppflags = "%s"' + # % ( + # str_function_test, + # list_variant, + # param_cmdargs, + # param_cppdefines, + # param_cpppaths, + # param_cppflags, + # ) + # ) param_configs = [] expected_configs = {} for platform in ['Win32', 'x64']: @@ -959,7 +972,8 @@ if __name__ == "__main__": ] for test_class in test_classes: - print("TEST: ", test_class.__doc__) + # DEBUG + # print("TEST: ", test_class.__doc__) back_osenv = copy.deepcopy(os.environ) try: # XXX: overriding the os.environ is bad, but doing it -- cgit v0.12 From 045ce9ce5fc5bdcbe721c19ee71309784fc28b5f Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 12 Dec 2020 10:41:16 -0700 Subject: Keep one msvs debug msg, test expects is Investigate whether it should expect such output at a later date, for now, just let the test pass. Signed-off-by: Mats Wichmann --- SCons/Tool/msvs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index eb7872d..c398365 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -607,8 +607,8 @@ class _DSPGenerator: config.platform = 'Win32' self.configs[variant] = config - # DEBUG - # print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") + # DEBUG: leave enabled, test/MSVS/CPPPATH-dirs.py expects this + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") for i in range(len(variants)): AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i], cppdefines[i], cpppaths[i], cppflags[i]) -- cgit v0.12 From d8c10d5c0ed8bae33f4e57d010b3fc757e7626f6 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 13 Dec 2020 07:46:28 -0700 Subject: [PR #3836] fix misplaced docstrings on two tests [ci skip] Signed-off-by: Mats Wichmann --- test/SConsignFile/default.py | 4 +--- test/SConsignFile/explicit-file.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/SConsignFile/default.py b/test/SConsignFile/default.py index 281632d..868f9d7 100644 --- a/test/SConsignFile/default.py +++ b/test/SConsignFile/default.py @@ -23,9 +23,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -""" -Verify the behavior of SConsignFile() called with a subst-able path. -""" +"""Verify the default behavior of SConsignFile() called with no arguments.""" import TestSCons diff --git a/test/SConsignFile/explicit-file.py b/test/SConsignFile/explicit-file.py index d579858..850b0ef 100644 --- a/test/SConsignFile/explicit-file.py +++ b/test/SConsignFile/explicit-file.py @@ -23,9 +23,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -""" -Verify the default behavior of env.SConsignFile(), called with no arguments. -""" +"""Verify the behavior of env.SConsignFile() called with a subst-able path.""" import TestSCons -- cgit v0.12 From 58422b1ccd8b6d9b070a825586c8fccefda82adc Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 13 Dec 2020 08:16:10 -0700 Subject: [PR #3833] change another place where file might not exist belt-and-suspenders: earlier check for file size should already have filtered out the "not rexists" case, but just to be sure, return NOFILE marker here as well. Signed-off-by: Mats Wichmann --- SCons/Node/FS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index 51a4f7b..290fcb3 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -2729,7 +2729,7 @@ class File(Base): def get_content_hash(self) -> str: """Compute and return the hash of the file contents.""" if not self.rexists(): - return MD5signature('') + return MD5signature(SCons.Util.NOFILE) fname = self.rfile().get_abspath() try: cs = MD5filesignature(fname, chunksize=File.md5_chunksize) -- cgit v0.12 From 465d508842fee8f7b9b693567b1dbde3b896fbf3 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 13 Dec 2020 17:32:57 -0800 Subject: [ci skip] add comment for PR 3833 which fixes Issue #3014. Also reorg contributor order to be alphabetical --- CHANGES.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index fb872b6..631a89a 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -51,6 +51,13 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From Daniel Moody: - Fix issue where java parsed a class incorrectly from lambdas used after a new. + From Simon Tegelid + - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command + with an action list like this: + ['${TEMPFILE("xxx.py -otempfile $SOURCE")}', '${TEMPFILE("yyy.py -o$TARGET tempfile")}'] + Could yield a single tempfile with the first TEMPFILE's contents, used by both steps + in the action list. + From Mats Wichmann: - Complete tests for Dictionary, env.keys() and env.values() for OverrideEnvironment. Enable env.setdefault() method, add tests. @@ -89,15 +96,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER special-case Windows here. dblite is the default storage engine for the SConsign file(s). - Fix cut-n-paste error in msvc debug printout and make some debug output in msvs and msvsTests.py be off until needed (uncomment to use) - - From Simon Tegelid - - Fix using TEMPFILE in multiple actions in an action list. Previously a builder, or command - with an action list like this: - ['${TEMPFILE("xxx.py -otempfile $SOURCE")}', '${TEMPFILE("yyy.py -o$TARGET tempfile")}'] - Could yield a single tempfile with the first TEMPFILE's contents, used by both steps - in the action list. - - + - Fix Issue #3014 - Empty file and missing file have same csig -- cgit v0.12 From 97dbf8d22b518a8f67cf670f8e3449990f3f5813 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 14 Dec 2020 09:06:06 -0800 Subject: Update PR #3384's CHANGE.txt entry to include a note about the changed behavior --- CHANGES.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 611023e..7d11cb9 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -41,6 +41,11 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix incorrect cache hits and/or misses when running in interactive mode by having SCons.Node.Node.clear() clear out all caching-related state. + From Jason Kenny + - Fix python3 crash when Value node get_text_content when child content does not have decode() + NOTE: If you depend on Value node's get_text_content returning concatenated contents of it's + children. This may break your code. It now concatenates the csig() of all children. + From Joachim Kuebart: - Suppress missing SConscript deprecation warning if `must_exist=False` is used. @@ -132,8 +137,6 @@ RELEASE 4.0.0 - Sat, 04 Jul 2020 12:00:27 +0000 removed libxslt support from the Docbook Tool. (issue #3580) - Added Docker images for building and testing SCons. (issue #3585) - From Jason Kenny - - Fix python3 crash when Value node get_text_content when child content does not have decode() From James Benton: - Improve Visual Studio solution/project generation code to add support -- cgit v0.12 From 99f4cad4cc96fa9f3c686d0ef8c28247eb36a5ee Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 20 Dec 2020 16:12:51 -0700 Subject: Adjust CompilationDatase documentation [skip appveyor] Try to be a bit more descriptive about compilation databases. Two of the User Guide examples now use the scons_examples style to show a little more what happens. Fixes #3845. Signed-off-by: Mats Wichmann --- SCons/Tool/compilation_db.xml | 75 +++++++++++------ doc/generated/examples/external_cdb_ex1_1.xml | 5 ++ doc/generated/examples/external_cdb_ex2_1.xml | 3 + doc/user/external.xml | 117 +++++++++++++++++++++----- 4 files changed, 157 insertions(+), 43 deletions(-) create mode 100644 doc/generated/examples/external_cdb_ex1_1.xml create mode 100644 doc/generated/examples/external_cdb_ex2_1.xml diff --git a/SCons/Tool/compilation_db.xml b/SCons/Tool/compilation_db.xml index 40a104e..aac1ed2 100644 --- a/SCons/Tool/compilation_db.xml +++ b/SCons/Tool/compilation_db.xml @@ -31,12 +31,12 @@ See its __doc__ string for a discussion of the format. COMPILATIONDB_COMSTR - +--> COMPILATIONDB_USE_ABSPATH COMPILATIONDB_PATH_FILTER @@ -45,30 +45,55 @@ See its __doc__ string for a discussion of the format. - The &b-CompilationDatabase; builder writes a JSON formatted compilation - database according to the - LLVM specification - which is consumed by a number of clang tools, editors, and other tools. - - - If you don't specify any files, the builder will default to compile_commands.json. + &b-CompilationDatabase; is a special builder which + adds a target to create a JSON formatted + compilation database compatible with + clang tooling + (see the + LLVM specification). + This database is suitable for consumption by various + tools and editors who can use it to obtain build and + dependency information which otherwise would be + internal to &SCons;. + The builder does not require any source files to be specified, + rather it arranges to emit information about all + of the C, C++ and assembler source/output pairs + identified in the build that are not excluded by the + optional filter &cv-link-COMPILATIONDB_PATH_FILTER;. + The target is subject to the usual &SCons; target + selection rules. - If you specify a single file as below - -env.CompilationDatabase('my_output.json') - - SCons will automatically use that as the target file. - If you specify more than one source, the source list will be ignored. + If called with no arguments, + the builder will default to a target name of + compile_commands.json. - You should not specify source files. The &b-CompilationDatabase; builder instruments SCons to collect them from all - the C, C++, assembly source/output pairs. + If called with a single positional argument, + &scons; will "deduce" the target name from that source + argument, giving it the same name, and then + ignore the source. + This is the usual way to call the builder if a + non-default target name is wanted. - NOTE: You must load the &t-compilation_db; tool prior to specifying any part of your build or some source/output - files will not show up in your output file. + If called with either the target= + or source= keyword arguments, + the value of the argument is taken as the target name. + If called with both, the target= + value is used and source= is ignored. + If called with multiple sources, + the source list will be ignored, + since there is no way to deduce what the intent was; + in this case the default target name will be used. + + + You must load the &t-compilation_db; tool prior to specifying + any part of your build or some source/output + files will not show up in the compilation database. + + Available since &scons; 4.0. @@ -78,7 +103,8 @@ env.CompilationDatabase('my_output.json') - The string displayed when CompilationDatabase builder's action is run. + The string displayed when the &b-CompilationDatabase; + builder's action is run. @@ -86,9 +112,10 @@ env.CompilationDatabase('my_output.json') - This is a boolean flag to instruct &b-link-CompilationDatabase; to - write the file and output members - in the compilation database with absolute or relative paths. + A boolean flag to instruct &b-link-CompilationDatabase; + whether to write the file and + output members + in the compilation database using absolute or relative paths. The default value is False (use relative paths) @@ -99,7 +126,7 @@ env.CompilationDatabase('my_output.json') - This is a string which instructs &b-link-CompilationDatabase; to + A string which instructs &b-link-CompilationDatabase; to only include entries where the output member matches the pattern in the filter string using fnmatch, which uses glob style wildcards. diff --git a/doc/generated/examples/external_cdb_ex1_1.xml b/doc/generated/examples/external_cdb_ex1_1.xml new file mode 100644 index 0000000..0d26c02 --- /dev/null +++ b/doc/generated/examples/external_cdb_ex1_1.xml @@ -0,0 +1,5 @@ +% scons -Q +Building compilation database compile_commands.json +cc -o hello.o -c hello.c +cc -o hello hello.o + diff --git a/doc/generated/examples/external_cdb_ex2_1.xml b/doc/generated/examples/external_cdb_ex2_1.xml new file mode 100644 index 0000000..25f32d1 --- /dev/null +++ b/doc/generated/examples/external_cdb_ex2_1.xml @@ -0,0 +1,3 @@ +% scons -Q cdb +Building compilation database compile_database.json + diff --git a/doc/user/external.xml b/doc/user/external.xml index 3d55a8c..9900e93 100644 --- a/doc/user/external.xml +++ b/doc/user/external.xml @@ -70,7 +70,7 @@ - Tooling which wants to perform analysis and modification + Tooling to perform analysis and modification of source code often needs to know not only the source code itself, but also how it will be compiled, as the compilation line affects the behavior of macros, includes, etc. &SCons; has a @@ -93,7 +93,7 @@ compilation database in this format by enabling the &t-link-compilation_db; tool and calling the &b-link-CompilationDatabase; builder - (available since 4.0). + (available since &scons; 4.0). @@ -107,12 +107,12 @@ which defaults to False. The entries in this file can be filtered by using - COMPILATIONDB_PATH_FILTER='fnmatch pattern' - where the filter string is a + COMPILATIONDB_PATH_FILTER='pattern' + where the filter pattern is a string following the Python - fnmatch + fnmatch - based pattern which is a typical file glob syntax. + syntax. This filtering can be used for outputting different build variants to different compilation database files. @@ -120,38 +120,104 @@ - Example of absolute paths for output and source: + The following example illustrates generating a compilation + database containing absolute paths: - + + env = Environment(COMPILATIONDB_USE_ABSPATH=True) env.Tool('compilation_db') -env.CompilationDatabase('compile_commands.json') - +env.CompilationDatabase() +env.Program('hello.c') + + +int main( int argc, char* argv[] ) +{ + return 0; +} + + + + + scons -Q + + + compile_commands.json contains: [ { - "command": "gcc -o test_main.o -c test_main.c", + "command": "gcc -o hello.o -c hello.c", "directory": "/home/user/sandbox", - "file": "/home/user/sandbox/test_main.c", - "output": "/home/user/sandbox/test_main.o" + "file": "/home/user/sandbox/hello.c", + "output": "/home/user/sandbox/hello.o" } ] - Example of relative paths for output and source: + Notice that the generated database contains only an entry for + the hello.c/hello.o pairing, + and nothing for the generation of the final executable + hello - the transformation of + hello.o to hello + does not have any information that affects interpretation + of the source code, + so it is not interesting to the compilation database. - + + + Although it can be a little surprising at first glance, + a compilation database target is, like any other target, + subject to &scons; target selection rules. + This means if you set a default target (that does not + include the compilation database), or use command-line + targets, it might not be selected for building. + This can actually be an advantage, since you don't + necessarily want to regenerate the compilation database + every build. + The following example + shows selecting relative paths (the default) + for output and source, + and also giving a non-default name to the database. + In order to be able to generate the database separately from building, + an alias is set referring to the database, + which can then be used as a target - here we are only + building the compilation database target, not the code. + + + + + env = Environment() env.Tool('compilation_db') -env.CompilationDatabase('compile_commands.json') - +cdb = env.CompilationDatabase('compile_database.json') +Alias('cdb', cdb) +env.Program('test_main.c') + + +#include "test_main.h" +int main( int argc, char* argv[] ) +{ + return 0; +} + + +/* dummy include file */ + + + + + scons -Q cdb + + + compile_database.json contains: + [ { @@ -165,7 +231,15 @@ env.CompilationDatabase('compile_commands.json') - Example of using filtering for build variants: + The following (incomplete) example shows using filtering + to separate build variants. + In the case of using variants, + you want different compilation databases for each, + since the build parameters differ, so the code analysis + needs to see the correct build lines for the 32-bit build + and 64-bit build hinted at here. + For simplicity of presentation, + the example omits the setup details of the variant directories: @@ -181,6 +255,9 @@ env2 = env.Clone() env2['COMPILATIONDB_PATH_FILTER'] = 'build/linux64/*' env2.CompilationDatabase('compile_commands-linux64.json') + + compile_commands-linux32.json contains: + [ { @@ -191,6 +268,9 @@ env2.CompilationDatabase('compile_commands-linux64.json') } ] + + compile_commands-linux64.json contains: + [ { @@ -203,5 +283,4 @@ env2.CompilationDatabase('compile_commands-linux64.json') - -- cgit v0.12 From b286f7a7ddc84b93adefd1f01de92c473865f25a Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 25 Dec 2020 16:47:55 -0700 Subject: Create github workflow for scons build/doc Try to enable a github Action workflow Signed-off-by: Mats Wichmann --- .github/workflows/scons-package.yml | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/scons-package.yml diff --git a/.github/workflows/scons-package.yml b/.github/workflows/scons-package.yml new file mode 100644 index 0000000..fc9ab5d --- /dev/null +++ b/.github/workflows/scons-package.yml @@ -0,0 +1,47 @@ +# This action builds SCons, mainly to make sure the docs generate. + +name: SCons Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + #python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + sudo apt-get update + sudo apt-get -y install docbook-xml docbook-xsl xsltproc fop docbook-xsl-doc-pdf + # try to keeo the texlive install as small as we can to save some time/space + sudo apt-get -y --no-install-recommends install texlive biber texmaker ghostscript texlive-latex-base texlive-latex-extra texlive-bibtex-extra texlive-font-utils latexmk + # This is disabled until the run can be configured to only + # check the code that matters, else we fail on non-essentials + # like the bench/ stuff. + #- name: Lint with flake8 + # run: | + # # stop the build if there are Python syntax errors or undefined names + # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Build SCons and docs + run: | + python bin/docs-update-generated.py + python bin/docs-validate.py + python bin/docs-create-example-outputs.py + python scripts/scons.py + ls -l build/dist + python build/scons-local/scons.py --version -- cgit v0.12 From 2d1bebd6f093bef2bae4d89d2063724a4ca3e102 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 1 Jan 2021 15:32:58 -0700 Subject: Fix awkward consvar code from ancient Python The Append* and Prepend* environment methods which add to existing construction variables had some deeply nested try blocks because according to the comments, Python 1.5.2 would not allow a continue statement inside a try block. This has now been aligned to more modern usage for better readability. Signed-off-by: Mats Wichmann --- CHANGES.txt | 3 +- SCons/Environment.py | 248 ++++++++++++++++++++++++--------------------------- 2 files changed, 121 insertions(+), 130 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 611023e..0604514 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -99,7 +99,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix cut-n-paste error in msvc debug printout and make some debug output in msvs and msvsTests.py be off until needed (uncomment to use) - Fix Issue #3014 - Empty file and missing file have same csig - + - Refactor env.Append/Prepend to remove Py 1.5 era need to nest + try blocks, can now "continue" at the appropriate places. diff --git a/SCons/Environment.py b/SCons/Environment.py index 4ebd515..2b9b294 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -407,9 +407,8 @@ class SubstitutionEnvironment: # key and we don't need to check. If we do check, using a # global, pre-compiled regular expression directly is more # efficient than calling another function or a method. - if key not in self._dict \ - and not _is_valid_var.match(key): - raise UserError("Illegal construction variable `%s'" % key) + if key not in self._dict and not _is_valid_var.match(key): + raise UserError("Illegal construction variable `%s'" % key) self._dict[key] = value def get(self, key, default=None): @@ -635,7 +634,7 @@ class SubstitutionEnvironment: Parse ``flags`` and return a dict with the flags distributed into the appropriate construction variable names. The flags are treated as a typical set of command-line flags for a GNU-like toolchain, - such as might have been generated by one of the \*-config scripts, + such as might have been generated by one of the {foo}-config scripts, and used to populate the entries based on knowledge embedded in this method - the choices are not expected to be portable to other toolchains. @@ -1173,92 +1172,85 @@ class Base(SubstitutionEnvironment): ####################################################################### def Append(self, **kw): - """Append values to existing construction variables in an Environment.""" + """Append values to construction variables in an Environment. + + The variable is created if it is not already present. + """ + kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - # It would be easier on the eyes to write this using - # "continue" statements whenever we finish processing an item, - # but Python 1.5.2 apparently doesn't let you use "continue" - # within try:-except: blocks, so we have to nest our code. try: if key == 'CPPDEFINES' and is_String(self._dict[key]): self._dict[key] = [self._dict[key]] orig = self._dict[key] except KeyError: - # No existing variable in the environment, so just set - # it to the new value. + # No existing var in the environment, so set to the new value. if key == 'CPPDEFINES' and is_String(val): self._dict[key] = [val] else: self._dict[key] = val - else: + continue + + try: + # Check if the original looks like a dict: has .update? + update_dict = orig.update + except AttributeError: try: - # Check if the original looks like a dictionary. - # If it is, we can't just try adding the value because - # dictionaries don't have __add__() methods, and - # things like UserList will incorrectly coerce the - # original dict to a list (which we don't want). - update_dict = orig.update - except AttributeError: + # Just try to add them together. This will work + # in most cases, when the original and new values + # are compatible types. + self._dict[key] = orig + val + except (KeyError, TypeError): try: - # Most straightforward: just try to add them - # together. This will work in most cases, when the - # original and new values are of compatible types. - self._dict[key] = orig + val - except (KeyError, TypeError): - try: - # Check if the original is a list. - add_to_orig = orig.append - except AttributeError: - # The original isn't a list, but the new - # value is (by process of elimination), - # so insert the original in the new value - # (if there's one to insert) and replace - # the variable with it. - if orig: - val.insert(0, orig) - self._dict[key] = val + # Check if the original is a list: has .append? + add_to_orig = orig.append + except AttributeError: + # The original isn't a list, but the new + # value is (by process of elimination), + # so insert the original in the new value + # (if there's one to insert) and replace + # the variable with it. + if orig: + val.insert(0, orig) + self._dict[key] = val + else: + # The original is a list, so append the new + # value to it (if there's a value to append). + if val: + add_to_orig(val) + continue + + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + # We can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + if is_List(val): + if key == 'CPPDEFINES': + tmp = [] + for (k, v) in orig.items(): + if v is not None: + tmp.append((k, v)) else: - # The original is a list, so append the new - # value to it (if there's a value to append). - if val: - add_to_orig(val) + tmp.append((k,)) + orig = tmp + orig += val + self._dict[key] = orig else: - # The original looks like a dictionary, so update it - # based on what we think the value looks like. - if is_List(val): - if key == 'CPPDEFINES': - tmp = [] - for (k, v) in orig.items(): - if v is not None: - tmp.append((k, v)) - else: - tmp.append((k,)) - orig = tmp - orig += val - self._dict[key] = orig - else: - for v in val: - orig[v] = None + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if is_Dict(val): + for k, v in val.items(): + orig[k] = v else: - try: - update_dict(val) - except (AttributeError, TypeError, ValueError): - if is_Dict(val): - for k, v in val.items(): - orig[k] = v - else: - orig[val] = None - self.scanner_map_delete(kw) + orig[val] = None - # allow Dirs and strings beginning with # for top-relative - # Note this uses the current env's fs (in self). - def _canonicalize(self, path): - if not is_String(path): # typically a Dir - path = str(path) - if path and path[0] == '#': - path = str(self.fs.Dir(path)) - return path + self.scanner_map_delete(kw) def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=0): @@ -1295,8 +1287,7 @@ class Base(SubstitutionEnvironment): val = _delete_duplicates(val, delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif is_Dict(self._dict[key]) and \ - is_Dict(val): + elif is_Dict(self._dict[key]) and is_Dict(val): self._dict[key].update(val) elif is_List(val): dk = self._dict[key] @@ -1682,68 +1673,68 @@ class Base(SubstitutionEnvironment): return SCons.Platform.Platform(platform)(self) def Prepend(self, **kw): - """Prepend values to existing construction variables - in an Environment. + """Prepend values to construction variables in an Environment. + + The variable is created if it is not already present. """ + kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): - # It would be easier on the eyes to write this using - # "continue" statements whenever we finish processing an item, - # but Python 1.5.2 apparently doesn't let you use "continue" - # within try:-except: blocks, so we have to nest our code. try: orig = self._dict[key] except KeyError: - # No existing variable in the environment, so just set - # it to the new value. + # No existing var in the environment so set to the new value. self._dict[key] = val - else: + continue + + try: + # Check if the original looks like a dict: has .update? + update_dict = orig.update + except AttributeError: try: - # Check if the original looks like a dictionary. - # If it is, we can't just try adding the value because - # dictionaries don't have __add__() methods, and - # things like UserList will incorrectly coerce the - # original dict to a list (which we don't want). - update_dict = orig.update - except AttributeError: + # Just try to add them together. This will work + # in most cases, when the original and new values + # are compatible types. + self._dict[key] = val + orig + except (KeyError, TypeError): try: - # Most straightforward: just try to add them - # together. This will work in most cases, when the - # original and new values are of compatible types. - self._dict[key] = val + orig - except (KeyError, TypeError): - try: - # Check if the added value is a list. - add_to_val = val.append - except AttributeError: - # The added value isn't a list, but the - # original is (by process of elimination), - # so insert the the new value in the original - # (if there's one to insert). - if val: - orig.insert(0, val) - else: - # The added value is a list, so append - # the original to it (if there's a value - # to append). - if orig: - add_to_val(orig) - self._dict[key] = val - else: - # The original looks like a dictionary, so update it - # based on what we think the value looks like. - if is_List(val): - for v in val: - orig[v] = None + # Check if the added value is a list: has .append? + add_to_val = val.append + except AttributeError: + # The added value isn't a list, but the + # original is (by process of elimination), + # so insert the the new value in the original + # (if there's one to insert). + if val: + orig.insert(0, val) else: - try: - update_dict(val) - except (AttributeError, TypeError, ValueError): - if is_Dict(val): - for k, v in val.items(): - orig[k] = v - else: - orig[val] = None + # The added value is a list, so append + # the original to it (if there's a value + # to append) and replace the original. + if orig: + add_to_val(orig) + self._dict[key] = val + continue + + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + # We can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + if is_List(val): + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None + self.scanner_map_delete(kw) def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, @@ -1782,8 +1773,7 @@ class Base(SubstitutionEnvironment): val = _delete_duplicates(val, not delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val - elif is_Dict(self._dict[key]) and \ - is_Dict(val): + elif is_Dict(self._dict[key]) and is_Dict(val): self._dict[key].update(val) elif is_List(val): dk = self._dict[key] -- cgit v0.12 From b00cfec0f5d7236bd1d2b4d5a50407152c32a739 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 4 Jan 2021 12:52:21 -0700 Subject: Add back accidentally removed env._canonicalize() Signed-off-by: Mats Wichmann --- SCons/Environment.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/SCons/Environment.py b/SCons/Environment.py index 2b9b294..5352b6e 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1252,6 +1252,17 @@ class Base(SubstitutionEnvironment): self.scanner_map_delete(kw) + def _canonicalize(self, path): + """Allow Dirs and strings beginning with # for top-relative. + + Note this uses the current env's fs (in self). + """ + if not is_String(path): # typically a Dir + path = str(path) + if path and path[0] == '#': + path = str(self.fs.Dir(path)) + return path + def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=0): """Append path elements to the path 'name' in the 'ENV' -- cgit v0.12 From ab166424306583f2ba2eb56f975a83b3cf9fd612 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 15:49:00 -0500 Subject: Don't allow duplicate side effects to be added SCons disallows adding duplicate sources, but does not place any limits on adding duplicate side effects. This change adds code to not allow adding duplicate side effects. I considered mimicking Node.sources_set by adding Node.side_effects_set but it seemed unnecessary and would make it harder for Environment.SideEffect to only return the list of side effects that were actually added. --- SCons/Environment.py | 7 +++++-- SCons/EnvironmentTests.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/SCons/Environment.py b/SCons/Environment.py index 4ebd515..0c1315c 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -2249,6 +2249,7 @@ class Base(SubstitutionEnvironment): side_effects = self.arg2nodes(side_effect, self.fs.Entry) targets = self.arg2nodes(target, self.fs.Entry) + added_side_effects = [] for side_effect in side_effects: if side_effect.multiple_side_effect_has_builder(): raise UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect)) @@ -2256,8 +2257,10 @@ class Base(SubstitutionEnvironment): side_effect.side_effect = 1 self.Precious(side_effect) for target in targets: - target.side_effects.append(side_effect) - return side_effects + if side_effect not in target.side_effects: + target.side_effects.append(side_effect) + added_side_effects.append(side_effect) + return added_side_effects def Split(self, arg): """This function converts a string or list into a list of strings diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index 53dd9a7..e7381ab 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -3326,6 +3326,12 @@ def generate(env): assert ggg.side_effects == [s], ggg.side_effects assert ccc.side_effects == [s], ccc.side_effects + # Verify that duplicate side effects are not allowed. + before = len(ggg.side_effects) + s = env.SideEffect('mymmm.pdb', ggg) + assert len(s) == 0, len(s) + assert len(ggg.side_effects) == before, len(ggg.side_effects) + def test_Split(self): """Test the Split() method""" env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb') -- cgit v0.12 From 16fad657267b692528059ecbb1b7ef3069322046 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 15:52:58 -0500 Subject: Update CHANGES.txt --- CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 7d11cb9..06318b1 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -40,6 +40,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER when running multiple tests with multiple jobs. - Fix incorrect cache hits and/or misses when running in interactive mode by having SCons.Node.Node.clear() clear out all caching-related state. + - Change Environment.SideEffect() to not add duplicate side effects. The list of returned + side effects will not include any duplicate side effects. From Jason Kenny - Fix python3 crash when Value node get_text_content when child content does not have decode() -- cgit v0.12 From 6ae20eb0265a21927029a45190f03dabec81776f Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 16:03:34 -0500 Subject: Document the change to SideEffect --- SCons/Environment.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SCons/Environment.xml b/SCons/Environment.xml index d594bdf..e004158 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -2920,6 +2920,12 @@ or &f-env-Clean; function. + + +This function returns the list of side effects that were successfully added. +If the list of side effects contained any side effects that had already been added, +they are not added and included in the returned list. + -- cgit v0.12 From 1209ce9ec631c41a281dd1158928c8dd2292d668 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 16:06:26 -0500 Subject: Update CHANGES.txt for clarity --- CHANGES.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 06318b1..a1ed1a0 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -40,8 +40,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER when running multiple tests with multiple jobs. - Fix incorrect cache hits and/or misses when running in interactive mode by having SCons.Node.Node.clear() clear out all caching-related state. - - Change Environment.SideEffect() to not add duplicate side effects. The list of returned - side effects will not include any duplicate side effects. + - Change Environment.SideEffect() to not add duplicate side effects. + NOTE: The list of returned side effects will not include any duplicate side effects. From Jason Kenny - Fix python3 crash when Value node get_text_content when child content does not have decode() -- cgit v0.12 From f5a7ae701a6a8ee898236fa0c996101cf9814483 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 16:11:02 -0500 Subject: Update RELEASE.txt --- RELEASE.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE.txt b/RELEASE.txt index 1410e35..340c3d5 100755 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -39,8 +39,8 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY - - List modifications to existing features, where the previous behavior - wouldn't actually be considered a bug + - Environment.SideEffect() no longer adds duplicate side effects. + NOTE: The list of returned side effects will not include any duplicate side effects. FIXES -- cgit v0.12 From 97d424e9d5094127a04382de9339cf4db3ab5e8e Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 16:39:19 -0500 Subject: Fix bug where SideEffect() was returning duplicate entries My code was adding the side effect to the return list inside of a "for target in targets" loop, causing duplicate entries if there were multiple targets. Fix this by adding outside of the loop. --- SCons/Environment.py | 5 ++++- SCons/EnvironmentTests.py | 12 +++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/SCons/Environment.py b/SCons/Environment.py index 0c1315c..3b720c8 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -2256,10 +2256,13 @@ class Base(SubstitutionEnvironment): side_effect.add_source(targets) side_effect.side_effect = 1 self.Precious(side_effect) + added = False for target in targets: if side_effect not in target.side_effects: target.side_effects.append(side_effect) - added_side_effects.append(side_effect) + added = True + if added: + added_side_effects.append(side_effect) return added_side_effects def Split(self, arg): diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index e7381ab..e57807b 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -3301,7 +3301,9 @@ def generate(env): foo = env.Object('foo.obj', 'foo.cpp')[0] bar = env.Object('bar.obj', 'bar.cpp')[0] - s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])[0] + s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'Entry', s.__class__.__name__ assert s.get_internal_path() == 'mylib.pdb' assert s.side_effect @@ -3310,7 +3312,9 @@ def generate(env): fff = env.Object('fff.obj', 'fff.cpp')[0] bbb = env.Object('bbb.obj', 'bbb.cpp')[0] - s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])[0] + s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'File', s.__class__.__name__ assert s.get_internal_path() == 'mylll.pdb' assert s.side_effect @@ -3319,7 +3323,9 @@ def generate(env): ggg = env.Object('ggg.obj', 'ggg.cpp')[0] ccc = env.Object('ccc.obj', 'ccc.cpp')[0] - s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])[0] + s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj']) + assert len(s) == 1, len(s) + s = s[0] assert s.__class__.__name__ == 'Dir', s.__class__.__name__ assert s.get_internal_path() == 'mymmm.pdb' assert s.side_effect -- cgit v0.12 From 854322f6dc85cb2308e45f7d5775c16e7b9cf5a2 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 5 Jan 2021 18:18:12 -0800 Subject: split out steps to name them each --- .github/workflows/scons-package.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scons-package.yml b/.github/workflows/scons-package.yml index fc9ab5d..b124592 100644 --- a/.github/workflows/scons-package.yml +++ b/.github/workflows/scons-package.yml @@ -37,11 +37,15 @@ jobs: # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Build SCons and docs + - name: Update Doc sources (some parts are generated) run: | python bin/docs-update-generated.py python bin/docs-validate.py python bin/docs-create-example-outputs.py + - name: Build SCons packages + run: | python scripts/scons.py + - name: Verify package + run: | ls -l build/dist python build/scons-local/scons.py --version -- cgit v0.12 From e3d4125e9bd599b58e7b86320abeda26baff423c Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 5 Jan 2021 20:09:10 -0800 Subject: [ci skip] Add github actions badge --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1d7b858..219151c 100755 --- a/README.rst +++ b/README.rst @@ -25,6 +25,10 @@ SCons - a software construction tool :target: https://codecov.io/gh/SCons/scons :alt: CodeCov Coverage Status +.. image:: https://github.com/SCons/scons/workflows/SCons%20Build/badge.svg + :target: https://github.com/SCons/scons/actions?query=workflow%3A%22SCons+Build%22 + :alt: Github Actions + Welcome to the SCons development tree. The real purpose of this tree is to package SCons for production distribution in a variety of formats, not just to -- cgit v0.12 From d853fd512fa280f4b2602cf0f72a9a5ebc66987c Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 5 Jan 2021 20:17:51 -0800 Subject: [ci skip] Clarify that Node objects are returned from SideEffect() --- CHANGES.txt | 2 +- RELEASE.txt | 2 +- SCons/Environment.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a1ed1a0..4b5970b 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -41,7 +41,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix incorrect cache hits and/or misses when running in interactive mode by having SCons.Node.Node.clear() clear out all caching-related state. - Change Environment.SideEffect() to not add duplicate side effects. - NOTE: The list of returned side effects will not include any duplicate side effects. + NOTE: The list of returned side effect Nodes will not include any duplicate side effect Nodes. From Jason Kenny - Fix python3 crash when Value node get_text_content when child content does not have decode() diff --git a/RELEASE.txt b/RELEASE.txt index 340c3d5..a9f286e 100755 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -40,7 +40,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY - Environment.SideEffect() no longer adds duplicate side effects. - NOTE: The list of returned side effects will not include any duplicate side effects. + NOTE: The list of returned side effect Nodes will not include any duplicate side effect Nodes. FIXES diff --git a/SCons/Environment.xml b/SCons/Environment.xml index e004158..a185815 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -2922,7 +2922,7 @@ function. -This function returns the list of side effects that were successfully added. +This function returns the list of side effect Node objects that were successfully added. If the list of side effects contained any side effects that had already been added, they are not added and included in the returned list. -- cgit v0.12 From 9969aea73ecc5b3dd657ee584b51f6edfc1639a3 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 6 Jan 2021 11:20:16 -0700 Subject: Update manpage section of Fortran suffixes [ci skip] The section mentioned only the .F suffix, added mention of the other variants and a brief note on what the difference means. Added some markup in the individual Fortran tools Doc-only change. Signed-off-by: Mats Wichmann --- SCons/Tool/f03.xml | 4 ++-- SCons/Tool/f08.xml | 4 ++-- SCons/Tool/f77.xml | 4 ++-- SCons/Tool/f90.xml | 4 ++-- SCons/Tool/f95.xml | 4 ++-- SCons/Tool/fortran.xml | 4 ++-- doc/man/scons.xml | 36 ++++++++++++++++++++++++++++++------ 7 files changed, 42 insertions(+), 18 deletions(-) diff --git a/SCons/Tool/f03.xml b/SCons/Tool/f03.xml index 97de0ad..fc14ace 100644 --- a/SCons/Tool/f03.xml +++ b/SCons/Tool/f03.xml @@ -89,7 +89,7 @@ If not set, then &cv-link-F03COM; or &cv-link-FORTRANCOM; The list of file extensions for which the F03 dialect will be used. By -default, this is ['.f03'] +default, this is ['.f03'] @@ -98,7 +98,7 @@ default, this is ['.f03'] The list of file extensions for which the compilation + preprocessor pass for -F03 dialect will be used. By default, this is empty +F03 dialect will be used. By default, this is empty. diff --git a/SCons/Tool/f08.xml b/SCons/Tool/f08.xml index 3f91f3c..fa7f633 100644 --- a/SCons/Tool/f08.xml +++ b/SCons/Tool/f08.xml @@ -89,7 +89,7 @@ If not set, then &cv-link-F08COM; or &cv-link-FORTRANCOM; The list of file extensions for which the F08 dialect will be used. By -default, this is ['.f08'] +default, this is ['.f08'] @@ -98,7 +98,7 @@ default, this is ['.f08'] The list of file extensions for which the compilation + preprocessor pass for -F08 dialect will be used. By default, this is empty +F08 dialect will be used. By default, this is empty. diff --git a/SCons/Tool/f77.xml b/SCons/Tool/f77.xml index ce69828..cade57f 100644 --- a/SCons/Tool/f77.xml +++ b/SCons/Tool/f77.xml @@ -91,7 +91,7 @@ for all Fortran versions. The list of file extensions for which the F77 dialect will be used. By -default, this is ['.f77'] +default, this is ['.f77'] @@ -100,7 +100,7 @@ default, this is ['.f77'] The list of file extensions for which the compilation + preprocessor pass for -F77 dialect will be used. By default, this is empty +F77 dialect will be used. By default, this is empty. diff --git a/SCons/Tool/f90.xml b/SCons/Tool/f90.xml index c57c28b..343aefe 100644 --- a/SCons/Tool/f90.xml +++ b/SCons/Tool/f90.xml @@ -89,7 +89,7 @@ If not set, then &cv-link-F90COM; or &cv-link-FORTRANCOM; The list of file extensions for which the F90 dialect will be used. By -default, this is ['.f90'] +default, this is ['.f90'] @@ -98,7 +98,7 @@ default, this is ['.f90'] The list of file extensions for which the compilation + preprocessor pass for -F90 dialect will be used. By default, this is empty +F90 dialect will be used. By default, this is empty. diff --git a/SCons/Tool/f95.xml b/SCons/Tool/f95.xml index f628ab1..3f38030 100644 --- a/SCons/Tool/f95.xml +++ b/SCons/Tool/f95.xml @@ -89,7 +89,7 @@ If not set, then &cv-link-F95COM; or &cv-link-FORTRANCOM; The list of file extensions for which the F95 dialect will be used. By -default, this is ['.f95'] +default, this is ['.f95'] @@ -98,7 +98,7 @@ default, this is ['.f95'] The list of file extensions for which the compilation + preprocessor pass for -F95 dialect will be used. By default, this is empty +F95 dialect will be used. By default, this is empty. diff --git a/SCons/Tool/fortran.xml b/SCons/Tool/fortran.xml index 560a484..a4f0cec 100644 --- a/SCons/Tool/fortran.xml +++ b/SCons/Tool/fortran.xml @@ -85,7 +85,7 @@ If not set, then &cv-link-FORTRANCOM; The list of file extensions for which the FORTRAN dialect will be used. By -default, this is ['.f', '.for', '.ftn'] +default, this is ['.f', '.for', '.ftn'] @@ -94,7 +94,7 @@ default, this is ['.f', '.for', '.ftn'] The list of file extensions for which the compilation + preprocessor pass for -FORTRAN dialect will be used. By default, this is ['.fpp', '.FPP'] +FORTRAN dialect will be used. By default, this is ['.fpp', '.FPP'] diff --git a/doc/man/scons.xml b/doc/man/scons.xml index 45bc9bd..688225b 100644 --- a/doc/man/scons.xml +++ b/doc/man/scons.xml @@ -6879,20 +6879,35 @@ suffix as a C source file. -.F file suffix +Fortran file suffixes -&scons; handles the upper-case -.F -file suffix differently, +&scons; handles upper-case +Fortran file suffixes differently depending on the capabilities of the underlying system. On a case-sensitive system such as Linux or UNIX, &scons; treats a file with a .F -suffix as a Fortran source file +as a Fortran source file that is to be first run through -the standard C preprocessor. +the standard C preprocessor, +while the lower-case version is not. +This matches the convention of gfortran, +which may also be followed by other Fortran compilers. +This also applies to other naming variants, +.FOR, +.FTN, +.F90, +.F95, +.F03 and +.F08; +files suffixed with +.FPP +and .fpp +are both run through the preprocessor, +as indicated by the pp +part of the name. On a case-insensitive system such as Windows, &scons; treats a file with a @@ -6900,6 +6915,15 @@ such as Windows, suffix as a Fortran source file that should not be run through the C preprocessor. + +Run through the C preprocessor +here means that a different set of &consvars; will +be applied in constructed commands, for example +&cv-link-FORTRANPPCOM; and &cv-link-FORTRANPPCOMSTR; +instead of +&cv-link-FORTRANCOM; and &cv-link-FORTRANCOMSTR;. +See the Fortran-related &consvars; for more details. + -- cgit v0.12 From 4d9d1a67bd34c30c11df2fb773748308919507f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Jan 2021 23:43:56 +0000 Subject: Bump lxml from 4.5.0 to 4.6.2 Bumps [lxml](https://github.com/lxml/lxml) from 4.5.0 to 4.6.2. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-4.5.0...lxml-4.6.2) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cc94763..16ac5a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,5 @@ readme-renderer sphinx sphinx_rtd_theme -lxml==4.5.0 +lxml==4.6.2 rst2pdf \ No newline at end of file -- cgit v0.12 From 0d8e8b49865b13a25d462e51496275d7c98d53a2 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Fri, 8 Jan 2021 13:30:55 -0600 Subject: remove unnecessary python check swig test --- test/SWIG/recursive-includes-cpp.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/SWIG/recursive-includes-cpp.py b/test/SWIG/recursive-includes-cpp.py index 1a9091f..fd896f9 100644 --- a/test/SWIG/recursive-includes-cpp.py +++ b/test/SWIG/recursive-includes-cpp.py @@ -40,9 +40,8 @@ DefaultEnvironment( tools = [ 'swig' ] ) test = TestSCons.TestSCons() # Check for prerequisites of this test. -for pre_req in ['swig', 'python']: - if not test.where_is(pre_req): - test.skip_test('Can not find installed "' + pre_req + '", skipping test.%s' % os.linesep) +if not test.where_is('swig'): + test.skip_test('Can not find installed "swig", skipping test.%s' % os.linesep) python, python_include, python_libpath, python_lib = \ test.get_platform_python_info(python_h_required=True) -- cgit v0.12