Skip to content

Commit fb47b6b

Browse files
authored
Merge pull request #4799 from mwichmann/maint/debug-include
Fix debug include printing for multi-source
2 parents abee309 + 2ca71b2 commit fb47b6b

File tree

5 files changed

+130
-37
lines changed

5 files changed

+130
-37
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
3535
a warning for years, but now it's a fatal error).
3636
- Improve covarage of API doc build by ignoring any setting of
3737
__all__ in a package and not showing inherited members from optparse.
38+
- Fix --debug=includes for case of multiple source files.
3839

3940

4041
RELEASE 4.10.1 - Sun, 16 Nov 2025 10:51:57 -0700

RELEASE.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ FIXES
3434

3535
- List fixes of outright bugs
3636

37+
- Fix --debug=includes for case of multiple source files.
38+
3739
IMPROVEMENTS
3840
------------
3941

SCons/Node/__init__.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,25 +1558,26 @@ def is_literal(self) -> bool:
15581558
the command interpreter literally."""
15591559
return True
15601560

1561-
def render_include_tree(self):
1561+
def render_include_tree(self) -> str:
15621562
"""
15631563
Return a text representation, suitable for displaying to the
15641564
user, of the include tree for the sources of this node.
15651565
"""
1566-
if self.is_derived():
1567-
env = self.get_build_env()
1568-
if env:
1569-
for s in self.sources:
1570-
scanner = self.get_source_scanner(s)
1571-
if scanner:
1572-
path = self.get_build_scanner_path(scanner)
1573-
else:
1574-
path = None
1575-
def f(node: Node, env: Environment = env, scanner: ScannerBase = scanner, path=path):
1576-
return node.get_found_includes(env, scanner, path)
1577-
return render_tree(s, f, 1)
1578-
else:
1579-
return None
1566+
if not self.is_derived(): # quick bailout
1567+
return ""
1568+
1569+
tree = ""
1570+
env = self.get_build_env()
1571+
if env:
1572+
for s in self.sources:
1573+
scanner = self.get_source_scanner(s)
1574+
if scanner:
1575+
path = self.get_build_scanner_path(scanner)
1576+
else:
1577+
path = None
1578+
tree += render_tree(s, lambda node: node.get_found_includes(env, scanner, path), prune=True)
1579+
1580+
return tree
15801581

15811582
def get_abspath(self) -> str:
15821583
"""
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python
2+
#
3+
# MIT License
4+
#
5+
# Copyright The SCons Foundation
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining
8+
# a copy of this software and associated documentation files (the
9+
# "Software"), to deal in the Software without restriction, including
10+
# without limitation the rights to use, copy, modify, merge, publish,
11+
# distribute, sublicense, and/or sell copies of the Software, and to
12+
# permit persons to whom the Software is furnished to do so, subject to
13+
# the following conditions:
14+
#
15+
# The above copyright notice and this permission notice shall be included
16+
# in all copies or substantial portions of the Software.
17+
#
18+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19+
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25+
26+
"""
27+
Test that the --debug=includes option prints the implicit
28+
dependencies of a target.
29+
30+
A separate test to make sure it works if there is more than one source.
31+
The main test uses a C compiler, and object builders there are
32+
single-source, so we need a different scheme.
33+
"""
34+
35+
import TestSCons
36+
37+
test = TestSCons.TestSCons()
38+
39+
test.write('SConstruct', """
40+
import os
41+
import os.path
42+
import sys
43+
44+
DefaultEnvironment(tools=[])
45+
46+
def buildIt(env, target, source):
47+
with open(target[0], 'w') as ofp:
48+
for out in source:
49+
with open(source[0], 'r') as ifp:
50+
ofp.write(ifp.read())
51+
return 0
52+
53+
def source_scanner(node, env, path, builder):
54+
return [File('a.inc'), File('b.inc')]
55+
56+
env = Environment(tools=[])
57+
env.Command(
58+
target="f.out",
59+
source=["f1.in", "f2.in"],
60+
action=buildIt,
61+
source_scanner=Scanner(
62+
lambda node, env, path: source_scanner(node, env, path, "w-env")
63+
)
64+
)
65+
""")
66+
67+
# the contents of these sources/includes don't matter
68+
test.write('f1.in', "f1.in\n")
69+
test.write('f2.in', "f2.in\n")
70+
test.write('a.inc', "a.inc\n")
71+
test.write('b.inc', "b.inc\n")
72+
73+
expect = """
74+
+-f1.in
75+
+-a.inc
76+
| +-[a.inc]
77+
| +-b.inc
78+
| +-[a.inc]
79+
| +-[b.inc]
80+
+-[b.inc]
81+
+-f2.in
82+
+-a.inc
83+
| +-[a.inc]
84+
| +-b.inc
85+
| +-[a.inc]
86+
| +-[b.inc]
87+
+-[b.inc]
88+
"""
89+
test.run(arguments="-Q --debug=includes f.out")
90+
test.must_contain_all_lines(test.stdout(), [expect])
91+
92+
test.pass_test()

test/option/debug-includes.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env python
22
#
3-
# __COPYRIGHT__
3+
# MIT License
4+
#
5+
# Copyright The SCons Foundation
46
#
57
# Permission is hereby granted, free of charge, to any person obtaining
68
# a copy of this software and associated documentation files (the
@@ -20,13 +22,12 @@
2022
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2123
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2224
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23-
#
24-
25-
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
2625

2726
"""
2827
Test that the --debug=includes option prints the implicit
2928
dependencies of a target.
29+
30+
This is currently a "live" test, requiring a C toolchain to execute.
3031
"""
3132

3233
import TestSCons
@@ -35,13 +36,14 @@
3536

3637
test.write('SConstruct', """
3738
DefaultEnvironment(tools=[])
38-
env = Environment(OBJSUFFIX = '.obj',
39-
SHOBJSUFFIX = '.shobj',
40-
LIBPREFIX = '',
41-
LIBSUFFIX = '.lib',
42-
SHLIBPREFIX = '',
43-
SHLIBSUFFIX = '.shlib',
44-
)
39+
env = Environment(
40+
OBJSUFFIX='.obj',
41+
SHOBJSUFFIX='.shobj',
42+
LIBPREFIX='',
43+
LIBSUFFIX='.lib',
44+
SHLIBPREFIX='',
45+
SHLIBSUFFIX='.shlib',
46+
)
4547
env.Program('foo.exe', ['foo.c', 'bar.c'])
4648
env.StaticLibrary('foo', ['foo.c', 'bar.c'])
4749
env.SharedLibrary('foo', ['foo.c', 'bar.c'], no_import_lib=True)
@@ -83,12 +85,10 @@
8385
+-foo.h
8486
+-bar.h
8587
"""
86-
test.run(arguments = "--debug=includes foo.obj")
88+
test.run(arguments="--debug=includes foo.obj")
8789

8890
test.must_contain_all_lines(test.stdout(), [includes])
8991

90-
91-
9292
# In an ideal world, --debug=includes would also work when there's a build
9393
# failure, but this would require even more complicated logic to scan
9494
# all of the intermediate nodes that get skipped when the build failure
@@ -108,16 +108,13 @@
108108
# stderr = None)
109109
#test.must_contain_all_lines(test.stdout(), [includes])
110110

111-
112-
113111
# These shouldn't print out anything in particular, but
114112
# they shouldn't crash either:
115-
test.run(arguments = "--debug=includes .")
116-
test.run(arguments = "--debug=includes foo.c")
117-
test.run(arguments = "--debug=includes foo.lib")
118-
test.run(arguments = "--debug=includes foo.shlib")
119-
120-
113+
# TODO: not really true... the two library ones do emit something. Check?
114+
test.run(arguments="--debug=includes .")
115+
test.run(arguments="--debug=includes foo.c")
116+
test.run(arguments="--debug=includes foo.lib")
117+
test.run(arguments="--debug=includes foo.shlib")
121118

122119
test.pass_test()
123120

0 commit comments

Comments
 (0)