如何获取为给定目标计算的所有源依赖项 SCons?
How can I get all the source dependencies SCons computed for a given target?
我想在构建给定目标后立即以编程方式执行此操作,在 SCons 构建期间 运行,而不是使用 --tree
或任何其他 scons 命令。我有一个目标节点。它可能有一些明确的依赖关系、使用过的扫描仪、基于文件扩展名的扫描仪,以及 SCons 计算的任何其他东西。所以喜欢:
all_source_nodes = tgt_node.get_all_sources(...)
我搜索了文档和 API。只在 FS 节点上看到 get_stored_implicit
。我得到 None 以及 .prerequisites
和 .implicit
节点成员。
我还发现 .sources
节点成员显示了传递到构建器中的直接源。当然,这也不够,因为我基本上需要依赖子树的所有节点,这要多得多。
在处理 SConstruct/SConscript 时,您不会获得大部分信息。
之后依赖关系图被完全填充。
您可能可以使用 sconsign。
它会在 SCons 完成后读取构建数据库,您可以查询特定目标。
尤里卡! :) 构建信息数据和递归扫描器应用程序的组合为我提供了所有 scons --tree=prune
报告。下面是完整代码,以及一些信息性消息。
__FULL_DEPS = {} # all dependencies for the node and its children recursively
__DIRECT_DEPS = {} # only the dependencies obtained from SCons for the node itself (direct and scanned)
# Find scons deps for this target - these are all in the subtree (same as __FULL_DEPS[tgt])
scons_deps = find_deps(tgt, None, env)
tgt_deps = set(map(str, scons_deps)) # Some nodes refer to the same paths
def find_deps(node, children_func, env):
"""Recursively traverses children dependencies from build info and by applying
children_func (scanner) to collect the full set of all dependencies
starting with 'node' as the dependency tree root.
:Parameters:
- node the current target we check (root node of the sub-tree)
- children_func the function called to get the children of a node. May be None.
- env the current environment
:Return:
The set of all source nodes in the dependency sub-tree
While the node objects are unique, the underlying files/dirs may repeat on rare occasions.
Collects the global __DIRECT_DEPS and __FULL_DEPS caches
"""
if node in __FULL_DEPS:
print("_find_deps '{}' deps - from CACHE: {}."
.format(str(node), len(__FULL_DEPS[node])))
return __FULL_DEPS[node]
children = set(node.all_children()) # children may repeat
# Apply children func, if available and merge in the results
scanned_deps = set()
if children_func:
scanned_deps = set(children_func(node))
children |= scanned_deps
__DIRECT_DEPS[node] = children
# Iterate all the unvisited children and recursively call find_deps with children_func
# specific to each child.
# FYI: Scanner use code is based on SCons code in Node.render_include_tree()
subtree_deps = set()
for child in sorted(children):
scanner = node.get_source_scanner(child)
# Note: get_build_scanner_path fails on nodes without executor
scanner_path = node.get_build_scanner_path(scanner) if (scanner and node.get_executor()) else None
def children_func(node, env=env, scanner=scanner, path=None):
return node.get_found_includes(env, scanner, path)
subtree_deps |= find_deps(child, children_func, env)
__FULL_DEPS[node] = children | subtree_deps
print("_find_deps '{}' deps: {} children ({} scanned) + {} from sub-tree"
.format(str(node), len(children), len(scanned_deps), len(subtree_deps)))
return __FULL_DEPS[node]
在高性能机器上大约一秒钟内获得 700 多个依赖项。这应该在 post-action 中调用,即在构建节点之后。在构建节点之前调用时可能仍然可以正常工作。
我想在构建给定目标后立即以编程方式执行此操作,在 SCons 构建期间 运行,而不是使用 --tree
或任何其他 scons 命令。我有一个目标节点。它可能有一些明确的依赖关系、使用过的扫描仪、基于文件扩展名的扫描仪,以及 SCons 计算的任何其他东西。所以喜欢:
all_source_nodes = tgt_node.get_all_sources(...)
我搜索了文档和 API。只在 FS 节点上看到 get_stored_implicit
。我得到 None 以及 .prerequisites
和 .implicit
节点成员。
我还发现 .sources
节点成员显示了传递到构建器中的直接源。当然,这也不够,因为我基本上需要依赖子树的所有节点,这要多得多。
在处理 SConstruct/SConscript 时,您不会获得大部分信息。
之后依赖关系图被完全填充。
您可能可以使用 sconsign。 它会在 SCons 完成后读取构建数据库,您可以查询特定目标。
尤里卡! :) 构建信息数据和递归扫描器应用程序的组合为我提供了所有 scons --tree=prune
报告。下面是完整代码,以及一些信息性消息。
__FULL_DEPS = {} # all dependencies for the node and its children recursively
__DIRECT_DEPS = {} # only the dependencies obtained from SCons for the node itself (direct and scanned)
# Find scons deps for this target - these are all in the subtree (same as __FULL_DEPS[tgt])
scons_deps = find_deps(tgt, None, env)
tgt_deps = set(map(str, scons_deps)) # Some nodes refer to the same paths
def find_deps(node, children_func, env):
"""Recursively traverses children dependencies from build info and by applying
children_func (scanner) to collect the full set of all dependencies
starting with 'node' as the dependency tree root.
:Parameters:
- node the current target we check (root node of the sub-tree)
- children_func the function called to get the children of a node. May be None.
- env the current environment
:Return:
The set of all source nodes in the dependency sub-tree
While the node objects are unique, the underlying files/dirs may repeat on rare occasions.
Collects the global __DIRECT_DEPS and __FULL_DEPS caches
"""
if node in __FULL_DEPS:
print("_find_deps '{}' deps - from CACHE: {}."
.format(str(node), len(__FULL_DEPS[node])))
return __FULL_DEPS[node]
children = set(node.all_children()) # children may repeat
# Apply children func, if available and merge in the results
scanned_deps = set()
if children_func:
scanned_deps = set(children_func(node))
children |= scanned_deps
__DIRECT_DEPS[node] = children
# Iterate all the unvisited children and recursively call find_deps with children_func
# specific to each child.
# FYI: Scanner use code is based on SCons code in Node.render_include_tree()
subtree_deps = set()
for child in sorted(children):
scanner = node.get_source_scanner(child)
# Note: get_build_scanner_path fails on nodes without executor
scanner_path = node.get_build_scanner_path(scanner) if (scanner and node.get_executor()) else None
def children_func(node, env=env, scanner=scanner, path=None):
return node.get_found_includes(env, scanner, path)
subtree_deps |= find_deps(child, children_func, env)
__FULL_DEPS[node] = children | subtree_deps
print("_find_deps '{}' deps: {} children ({} scanned) + {} from sub-tree"
.format(str(node), len(children), len(scanned_deps), len(subtree_deps)))
return __FULL_DEPS[node]
在高性能机器上大约一秒钟内获得 700 多个依赖项。这应该在 post-action 中调用,即在构建节点之后。在构建节点之前调用时可能仍然可以正常工作。