如何从SConscript调用的辅助脚本中调用SCons全局函数?
问题描述
我将计算特定源文件和头文件目录路径的复杂逻辑抽离到单独的.py文件中,供多个SConscript导入复用。但现在在这个辅助脚本中调用SCons全局函数Glob时遇到了问题——此前该函数可在SConscript中直接调用,放到独立辅助脚本后却找不到调用方式,我对Python并不熟悉,希望解决这个问题。
更新:关于SCons全局函数的特殊处理
通过查看SCons主入口文件(SConscript.py,与源码树中分散的SConscript文件不同)的代码,发现Glob()能作为全局函数调用是SCons的特殊处理逻辑:
_DefaultEnvironmentProxy = None def get_DefaultEnvironmentProxy(): global _DefaultEnvironmentProxy if not _DefaultEnvironmentProxy: default_env = SCons.Defaults.DefaultEnvironment() _DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env) return _DefaultEnvironmentProxy class DefaultEnvironmentCall(object): """A class that implements "global function" calls of Environment methods by fetching the specified method from the DefaultEnvironment's class. Note that this uses an intermediate proxy class instead of calling the DefaultEnvironment method directly so that the proxy can override the subst() method and thereby prevent expansion of construction variables (since from the user's point of view this was called as a global function, with no associated construction environment).""" def __init__(self, method_name, subst=0): self.method_name = method_name if subst: self.factory = SCons.Defaults.DefaultEnvironment else: self.factory = get_DefaultEnvironmentProxy def __call__(self, *args, **kw): env = self.factory() method = getattr(env, self.method_name) return method(*args, **kw) def BuildDefaultGlobals(): """ Create a dictionary containing all the default globals for SConstruct and SConscript files. """ global GlobalDict if GlobalDict is None: GlobalDict = {} import SCons.Script # <-------This is referring to a directory with a file named __init__.py, which I've learned is something special in Python d = SCons.Script.__dict__ def not_a_module(m, d=d, mtype=type(SCons.Script)): return not isinstance(d[m], mtype) for m in filter(not_a_module, dir(SCons.Script)): GlobalDict[m] = d[m] return GlobalDict.copy()
我尝试在辅助脚本中导入SCons.Script:
import SCons.Script
但仍报错:
NameError: name 'Glob' is not defined: File "D:\Git\......\SConstruct", line 412: SConscript(theSconscript, duplicate=0) File "c:\python37\lib\site-packages\scons\SCons\Script\SConscript.py", line 671: return method(*args, **kw) File "c:\python37\lib\site-packages\scons\SCons\Script\SConscript.py", line 608: return _SConscript(self.fs, *files, **subst_kw) . . . File "D:\Git\........\SConscript", line 433: . . . File "D:\Git\............\PathSelector.py", line 78: src_files.extend(Glob((os.path.join(src_path_a, '*.c')), strings=1))
解决方案
根据SCons的实现逻辑,全局Glob实际是代理到默认环境的方法,在独立Python脚本中需要显式通过模块或环境对象调用,有两种可行方式:
方式一:直接通过SCons.Script模块调用
修改辅助脚本中的代码,给Glob加上模块前缀:
import SCons.Script # 替换原有的Glob调用 src_files.extend(SCons.Script.Glob(os.path.join(src_path_a, '*.c'), strings=1))
或者也可以直接导入Glob函数:
from SCons.Script import Glob # 这样就能直接用Glob(...)调用了 src_files.extend(Glob(os.path.join(src_path_a, '*.c'), strings=1))
方式二:获取默认环境后调用其Glob方法
直接获取SCons的默认构建环境,调用环境的Glob方法:
import SCons.Defaults default_env = SCons.Defaults.DefaultEnvironment() src_files.extend(default_env.Glob(os.path.join(src_path_a, '*.c'), strings=1))
额外建议
如果你的辅助脚本需要和特定构建环境交互,更推荐从调用它的SConscript中传递环境对象。比如在SConscript中:
# 导入辅助模块 import PathSelector # 把当前构建环境env传进去 PathSelector.your_function(env, ...)
然后在辅助脚本中使用传入的环境调用Glob:
def your_function(env, ...): src_files.extend(env.Glob(os.path.join(src_path_a, '*.c'), strings=1))
这种方式能保证和当前构建环境的配置一致,更灵活可靠。
内容的提问来源于stack exchange,提问作者phonetagger
相关产品推荐
相关产品推荐

