使用env.subst进行递归变量替换

时间:2017-09-14 13:15:17

标签: scons

根据scons documentationsubst方法将递归插值构造变量。但是,它似乎不是递归的:

e = Environment(CPPDEFINES = ["FOOBAR=${foobar}"])

e["foo"] = 1
e["bar"] = "${foo + 1}"
e["foobar"] = "$${foo + ${bar}}"

# I want this to print "foobar: 3"
print "foobar:", e.subst("${foobar}")

e.Program("test.c")

打印:

scons: Reading SConscript files ...
foobar: ${foo + 2}
scons: done reading SConscript files.
scons: Building targets ...
gcc -o test.o -c -DFOOBAR=3 test.c
gcc -o test test.o
scons: done building targets.
编译期间

foobar作为CPPDEFINES的一部分正确评估,但不在print语句中。如何让subst完全评估foobar?

2 个答案:

答案 0 :(得分:0)

使用表达式

e["foobar"] = "${foo + ${bar}}" 

,正如肯尼奥斯特罗姆所建议的那样,也没有任何帮助。它会产生语法错误,因为subst方法并不能很好地处理嵌套大括号。

实际问题是:为什么在subst直接使用SConstruct时,以及在构建命令中使用它时,我们会看到不同的输出?

如果我们添加

print "CPPDEFINES:", e.subst("$CPPDEFINES")

SConstruct,我们看到${foo + 2}的输出FOOBAR相同。构建时的差异在于,内部变量$_CPPDEFFLAGS是根据_defines方法声明的:

'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}'

(来自print e.Dump())。这个_defines方法第二次运行所有变量subst_path,例如,可以在包含路径中使用变量。

所以subst方法正在做正确的事情,你只需要再次评估:

print "foobar:", e.subst(e.subst("${foobar}"))

获得相同的输出。

答案 1 :(得分:0)

只是要明确dirkbaechle所说的话;我们可以实现这个目标 只需在两个单独的步骤中进行插值和评估(通过调用subst两次)。这允许我们有任意复杂的表达式:

# Notice how we wrap foobar in $$
e = Environment(CPPDEFINES = ["FOOBARBAZ=$${${foobarbaz}}"])

e["foo"] = 1
e["bar"] = "($foo + 1)"
e["foobar"] = "($foo + $bar)"
e["foobarbaz"] = "($foobar + $foobar)"

print "foobarbaz after substituting once:", e.subst("$${${foobarbaz}}")
print "foobarbaz after substituting twice:", e.subst(e.subst("$${${foobarbaz}}"))

e.Program("test.c")

打印:

scons: Reading SConscript files ...
foobarbaz after substituting once: ${((1 + (1 + 1)) + (1 + (1 + 1)))}
foobarbaz after substituting twice: 6
scons: done reading SConscript files.
scons: Building targets ...
gcc -o test.o -c -DFOOBARBAZ=6 test.c
gcc -o test test.o
scons: done building targets.

再次感谢,dirkbaechle!