env.subst 的递归变量替换
Recursive variable substitution with env.subst
根据scons documentation,subst
方法将递归地插入构造变量。不过好像不是递归的:
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?
使用表达式
e["foobar"] = "${foo + ${bar}}"
,如 Kenny Ostrom 所建议的,也无济于事。它会产生语法错误,因为 subst
方法并不能很好地处理嵌套大括号。
实际的问题是:为什么我们在 SConstruct
中直接使用 subst
和在构建命令中使用它时会看到不同的输出?
如果我们加上
print "CPPDEFINES:", e.subst("$CPPDEFINES")
到 SConstruct
,我们看到 FOOBAR
的相同输出 ${foo + 2}
。构建时的区别在于,内部变量 $_CPPDEFFLAGS
是根据 _defines
方法声明的:
'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}'
(来自 print e.Dump()
)。此 _defines
方法通过 subst_path
第二次运行所有变量,例如可以在包含路径中使用变量。
所以subst
方法是正确的,你只需要再次评估:
print "foobar:", e.subst(e.subst("${foobar}"))
获得相同的输出。
只是为了弄清楚 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!
根据scons documentation,subst
方法将递归地插入构造变量。不过好像不是递归的:
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?
使用表达式
e["foobar"] = "${foo + ${bar}}"
,如 Kenny Ostrom 所建议的,也无济于事。它会产生语法错误,因为 subst
方法并不能很好地处理嵌套大括号。
实际的问题是:为什么我们在 SConstruct
中直接使用 subst
和在构建命令中使用它时会看到不同的输出?
如果我们加上
print "CPPDEFINES:", e.subst("$CPPDEFINES")
到 SConstruct
,我们看到 FOOBAR
的相同输出 ${foo + 2}
。构建时的区别在于,内部变量 $_CPPDEFFLAGS
是根据 _defines
方法声明的:
'_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}'
(来自 print e.Dump()
)。此 _defines
方法通过 subst_path
第二次运行所有变量,例如可以在包含路径中使用变量。
所以subst
方法是正确的,你只需要再次评估:
print "foobar:", e.subst(e.subst("${foobar}"))
获得相同的输出。
只是为了弄清楚 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!