Skip to content

Commit 0edf6a2

Browse files
committed
Read Variables saved-variables file from the source directory (#816)
Variables() read its saved-variables file(s) (e.g. custom.py) by hand with os.path.exists()/open(), which only looks in the build directory. When the source directory differs from the build directory (for example when building against a separate source tree via Repository), a custom.py placed in the source tree was not found. Resolve the file through the File() node infrastructure instead (rexists()/srcnode() + rfile()), so it is located in the source directory or a repository as well as the build directory. Add a regression test and a CHANGES.txt entry. Signed-off-by: Cornelii Sandberg <corresandberg@gmail.com> Assisted-by: Claude Code (Anthropic)
1 parent e24a1c3 commit 0edf6a2

3 files changed

Lines changed: 81 additions & 5 deletions

File tree

CHANGES.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
1515
From John Doe:
1616
- Whatever John Doe did.
1717

18+
From Cornelii Sandberg:
19+
- Fix Variables() not reading a saved-variables file (e.g. custom.py)
20+
from the source directory when building in a separate variant
21+
directory. The file is now resolved through the File() node
22+
infrastructure, so it is found in the source directory or a
23+
repository (issue #816).
24+
1825
From Joseph Brill:
1926
- Add possible build failure when targeting 32-bit arm using
2027
Visual Studio 2022 with Windows SDK version 10.0.26100.0 or later

SCons/Variables/__init__.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,18 +271,25 @@ def Update(self, env, args: dict | None = None) -> None:
271271

272272
# next set the values specified in any saved-variables script(s)
273273
for filename in self.files:
274-
# TODO: issue #816 use Node to access saved-variables file?
275-
if os.path.exists(filename):
274+
# Resolve the saved-variables file through the File() node so it
275+
# is found in the source directory (or a repository) as well as
276+
# the build directory, e.g. when using a variant dir (issue #816).
277+
node = env.File(filename)
278+
if not node.rexists():
279+
node = node.srcnode()
280+
if node.rexists():
281+
# rfile() resolves to the actual on-disk file, which may live
282+
# in a repository rather than the local (build) directory.
283+
rfile = node.rfile()
276284
# issue #4645: don't exec directly into values,
277285
# so we can iterate through for unknown variables.
278286
temp_values = {}
279-
dirname = os.path.split(os.path.abspath(filename))[0]
287+
dirname = os.path.split(rfile.get_abspath())[0]
280288
if dirname:
281289
sys.path.insert(0, dirname)
282290
try:
283291
temp_values['__name__'] = filename
284-
with open(filename) as f:
285-
contents = f.read()
292+
contents = rfile.get_text_contents()
286293
exec(contents, {}, temp_values)
287294
finally:
288295
if dirname:

test/Variables/source-dir.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 a Variables() saved-variables file (e.g. custom.py) is read from
28+
the source tree when it is not present in the build directory, i.e. when
29+
building against a separate source directory via Repository() (issue #816).
30+
"""
31+
32+
import TestSCons
33+
34+
test = TestSCons.TestSCons()
35+
36+
test.subdir('repository', 'work')
37+
38+
opts = "-Y " + test.workpath('repository')
39+
40+
# The saved-variables file lives only in the source tree (the repository),
41+
# not in the 'work' directory where SCons is actually invoked.
42+
test.write(['repository', 'custom.py'], """\
43+
MY_VARIABLE = 'from_source_tree'
44+
""")
45+
46+
test.write(['repository', 'SConstruct'], """\
47+
DefaultEnvironment(tools=[])
48+
vars = Variables('custom.py')
49+
vars.Add('MY_VARIABLE', 'a test variable', 'default_value')
50+
env = Environment(variables=vars, tools=[])
51+
print("MY_VARIABLE =", env['MY_VARIABLE'])
52+
""")
53+
54+
# Before the issue #816 fix, custom.py was looked up relative to the build
55+
# directory only, so it was not found here and the default value was used.
56+
test.run(chdir='work', options=opts, arguments='.')
57+
58+
expect = "MY_VARIABLE = from_source_tree"
59+
if expect not in test.stdout():
60+
test.fail_test()
61+
62+
test.pass_test()

0 commit comments

Comments
 (0)