SCons:如何在scons脚本中调用自定义Python函数并正确设置依赖性

5 投票
1 回答
3138 浏览
提问于 2025-04-17 06:50

我写了一个Python函数,用来替换字符串,并在scons脚本中调用它。

def Replace(env, filename, old, new):
    with open(filename,"r+") as f:
    d = f.read()
    d = d.replace(old, new)
    f.truncate(0)
    f.seek(0)
    f.write(d)
    f.close()
env.AddMethod(Replace,'Replace')

在SConscript中

lib = env.SharedLibrary('lib', object, extra_libs)
tmp = env.Command([],[],[env.Replace(somefile, 'A', 'b')] )
env.Depends(tmp,lib )

我希望在库构建完成后运行Replace()这个方法。可是scons总是在第一次解析脚本的时候就运行了Replace()。看起来我好像漏掉了一些依赖关系。

1 个回答

4

我觉得你可能在寻找可以执行Python函数的构建工具

这里有个棘手的地方,就是SCons并不想按照你强迫它的方式工作。构建操作应该是可重复的,并且不会破坏原有的内容,而在你的代码中,你实际上是把somefile的原始内容给破坏掉了。相反,你可以使用目标/源的概念,以及某种模板文件来实现同样的效果。

import os
import re

def replace_action(target, source, env):
    # NB. this is a pretty sloppy way to write a builder, but
    #     for things that are used internally or infrequently
    #     it should be more than sufficient
    assert( len(target) == 1 )
    assert( len(source) == 1 )
    srcf = str(source[0])
    dstf = str(target[0])
    with open(srcf, "r") as f:
        contents = f.read()
        # In cases where this builder fails, check to make sure you
        # have correctly added REPLST to your environment
        for old, new in env['REPLST']:
            contents = re.sub( old, new, contents )
        with open( dstf, "w") as outf:
            outf.write(contents)

replace_builder = Builder(action = replace_action)

env = Environment( ENV = os.environ )
env.Append( BUILDERS = {'Replace' : replace_builder } )
b = env.Replace( 'somefile', ['somefile.tmpl'], REPLST=[('A','b')] )
lib = env.SharedLibrary('lib', object + [b], extra_libs )

需要注意的是,在我的测试中,替换函数在处理多行数据时表现得不太好,所以我换成了使用完整的正则表达式(re.sub)。这可能会慢一些,但提供了更大的灵活性。

撰写回答