diff --git a/CHANGES.txt b/CHANGES.txt
index d8a7783890..97c0e1aa11 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -81,6 +81,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
on a one-time uuid to make a path to the file.
- Clarify VariantDir behavior when switching to not duplicate sources
and tweak wording a bit.
+ - Update documentation of the three file-finding functions in the API
+ (FindFile, FindInstalledFiles, FindSourceFilse) as well as FindPathDirs.
+ Also add a test for FindFile to be sure it locates non-existing
+ derived files as advertised.
RELEASE 4.10.1 - Sun, 16 Nov 2025 10:51:57 -0700
diff --git a/RELEASE.txt b/RELEASE.txt
index e09fc121a3..ad76929e55 100644
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -71,7 +71,7 @@ IMPROVEMENTS
- Simplified and sped up compilation database generation. No longer requires
each entry to have a dedicated node that's always built; instead, the database
*itself* is set to always build.
-
+
- Switch remaining "original style" docstring parameter listings to Google style.
- Additional small tweaks to Environment.py type hints, fold some overly
@@ -118,6 +118,9 @@ DOCUMENTATION
- Clarify VariantDir behavior when switching to not duplicate sources
and tweak wording a bit.
+- Update documentation of the three file-finding functions in the API
+ (FindFile, FindInstalledFiles, FindSourceFilse) as well as FindPathDirs.
+
DEVELOPMENT
-----------
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index fb70671fe3..9a13adda9d 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -1974,6 +1974,7 @@ Example:
+# Searches for 'foo' in 'dir1' and 'dir2', returning the node if found
foo = env.FindFile('foo', ['dir1', 'dir2'])
@@ -1985,16 +1986,16 @@ foo = env.FindFile('foo', ['dir1', 'dir2'])
-Returns the list of targets set up by the
+Return the list of targets set up by the
&b-link-Install;
-or
+and
&b-link-InstallAs;
builders.
-
-
-
This function serves as a convenient method to select the contents of
a binary package.
+The list is populated as &b-Install; and &b-InstallAs; are executed -
+that is, the return reflects builder calls already seen
+but not any calls that may occur later.
@@ -2004,13 +2005,13 @@ Example:
Install('/bin', ['executable_a', 'executable_b'])
-# will return the file node list
+# Returns the file node list
# ['/bin/executable_a', '/bin/executable_b']
FindInstalledFiles()
Install('/lib', ['some_library'])
-# will return the file node list
+# Returns the file node list
# ['/bin/executable_a', '/bin/executable_b', '/lib/some_library']
FindInstalledFiles()
@@ -2019,22 +2020,17 @@ FindInstalledFiles()
-(node='"."')
+([node])
-Returns the list of nodes which serve as the source of the built files.
-It does so by inspecting the dependency tree starting at the optional
-argument
-node
-which defaults to the '"."'-node. It will then return all leaves of
-node.
-These are all children which have no further children.
-
-
-
-This function is a convenient method to select the contents of a Source
-Package.
+Return the list of nodes which represent the sources of the built files.
+It does so by recursively inspecting the dependency tree starting at the optional
+argument node,
+which defaults to the current directory (".").
+It returns all leaf nodes (files with no further dependencies) from the tree.
+This function serves as a convenient method to select the contents of
+a source package.
@@ -2054,8 +2050,9 @@ FindSourceFiles('src')
-As you can see, build support files (&SConstruct; in the above example)
-will also be returned by this function.
+Notice that build support files in the tree
+(&SConstruct; in the above example)
+are also returned.
diff --git a/SCons/Scanner/Scanner.xml b/SCons/Scanner/Scanner.xml
index e3dffe526b..35983bde20 100644
--- a/SCons/Scanner/Scanner.xml
+++ b/SCons/Scanner/Scanner.xml
@@ -31,46 +31,32 @@ This file is processed by the bin/SConsDoc.py module.
-Returns a function
-(actually a callable Python object)
-intended to be used as the
-path_function
-of a Scanner object.
-The returned object will look up the specified
-variable
-in a construction environment
-and treat the construction variable's value as a list of
-directory paths that should be searched
-(like
-&cv-link-CPPPATH;,
-&cv-link-LIBPATH;,
-etc.).
+Return a callable object for use as the
+path_function of a
+Scanner object.
+When called, it looks up the specified
+variable in the &consenv;
+and treats its value as a list of
+directory paths to search
+(like &cv-link-CPPPATH; or &cv-link-LIBPATH;).
-Note that use of
-&f-FindPathDirs;
-is generally preferable to
-writing your own
+Using &f-FindPathDirs;
+is generally preferable to writing your own
path_function
-for the following reasons:
-1) The returned list will contain all appropriate directories
-found in source trees
-(when
-&f-link-VariantDir;
-is used)
-or in code repositories
-(when
-&f-Repository;
-or the
-
-option are used).
-2) scons will identify expansions of
-variable
-that evaluate to the same list of directories as,
-in fact, the same list,
-and avoid re-scanning the directories for files,
-when possible.
+because it handles common &SCons;
+scanning cases correctly and efficiently:
+(1) it returns all appropriate directories
+from source trees when a variant directory is used,
+and from repositories when
+&f-link-Repository; or the
+
+option is in effect.
+(2) it detects when different values of
+variable resolve to the same directory list and
+reuses that result instead of rescanning the same directories,
+avoiding redundant work.
@@ -82,9 +68,9 @@ def my_scan(node, env, path, arg):
# Code to scan file contents goes here...
return include_files
-scanner = Scanner(name = 'myscanner',
- function = my_scan,
- path_function = FindPathDirs('MYPATH'))
+scanner = Scanner(
+ name='myscanner', function=my_scan, path_function=FindPathDirs('MYPATH')
+)
diff --git a/test/FindFile.py b/test/FindFile.py
index c989e008dc..7249eff801 100644
--- a/test/FindFile.py
+++ b/test/FindFile.py
@@ -35,33 +35,41 @@
test.write(['foo', 'testfile2'], 'test 2\n')
test.write(['bar', 'testfile1'], 'test 3\n')
test.write(['bar', 'baz', 'testfile2'], 'test 4\n')
+test.write('source.txt', 'source content\n')
test.write('SConstruct', """
-env = Environment(FILE = 'file', BAR = 'bar')
-file1 = FindFile('testfile1', [ 'foo', '.', 'bar', 'bar/baz' ])
+env = Environment(FILE='file', BAR='bar')
+file1 = FindFile('testfile1', ['foo', '.', 'bar', 'bar/baz'])
with open(file1, 'r') as f:
- print(f.read())
-file2 = env.FindFile('test${FILE}1', [ 'bar', 'foo', '.', 'bar/baz' ])
+ print(f.read(), end='')
+file2 = env.FindFile('test${FILE}1', ['bar', 'foo', '.', 'bar/baz'])
with open(file2, 'r') as f:
- print(f.read())
-file3 = FindFile('testfile2', [ 'foo', '.', 'bar', 'bar/baz' ])
+ print(f.read(), end='')
+file3 = FindFile('testfile2', ['foo', '.', 'bar', 'bar/baz'])
with open(file3, 'r') as f:
- print(f.read())
-file4 = env.FindFile('testfile2', [ '$BAR/baz', 'foo', '.', 'bar' ])
+ print(f.read(), end='')
+file4 = env.FindFile('testfile2', ['$BAR/baz', 'foo', '.', 'bar'])
with open(file4, 'r') as f:
- print(f.read())
-""")
+ print(f.read(), end='')
-expect = test.wrap_stdout(read_str = """test 1
+# Test finding unbuilt derived files
+derived = env.Command('derived.txt', 'source.txt', Copy('$TARGET', '$SOURCE'))
+found_derived = FindFile('derived.txt', ['.'])
+print('Found derived:', str(found_derived))
+""")
+expect = test.wrap_stdout(
+ read_str="""\
+test 1
test 3
-
test 2
-
test 4
+Found derived: derived.txt
+""",
+ build_str="""Copy("derived.txt", "source.txt")
+""",
+)
-""", build_str = "scons: `.' is up to date.\n")
-
-test.run(arguments = ".", stdout = expect)
+test.run(arguments=".", stdout=expect)
test.pass_test()