在模式定义时扩展 make 变量
Expanding make variables at pattern definition time
这是我正在处理的复杂得多的构建系统的一个简单示例。
T := 1
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
T := 2
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
(两种模式都在包含文件中定义,因此它们必须是相同的文本。)
这行不通。虽然模式本身是正确创建的,使用称为 1/foo.o: 1/foo.c
和 2/foo.o: 2/foo.c
的规则,但配方本身在实际执行之前不会 $T
扩展;当然,此时 $T
的值为 2,即使在第一个配方中也是如此。
我知道在定义配方的地方强制扩展变量的唯一方法是将整个模式放在一个多行变量中,然后用 $(eval)
...扩展它怪诞。
我知道这里的答案可能是 否 ,但是还有其他方法可以强制 $T
在上述方法中内联扩展吗?
据我所知,你有三个选择。
- 目标特定变量
- 解析时规则定义(
eval
等)。
- 构造变量名。
使用特定于目标的变量
T := 1
$T/foo.o: T:=$T
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
T := 2
$T/foo.o: T:=$T
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
正如在 问题上所讨论的那样,特定于目标的变量对所讨论目标的所有先决条件都是可见的(除非使用 GNU make 3.82 private
功能),这可能并不总是什么你要
使用解析时规则定义
define foorule
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $$$$@, this is an example
endef
T := 1
$(eval $(foorule))
T := 2
$(eval $(foorule))
但是(如问题中所述)这并不完全漂亮,偶尔需要仔细协商扩展(对于那些想要在配方时扩展的东西与那些不想要的东西相比)。
使用构造变量名
T := 1
T$(T) := $T
$T/foo.o: $T/foo.c
touch $(T1)/foo.o # yes, I know I can use $@, this is an example
T := 2
T$T := $T
$T/foo.o: $T/foo.c
touch $(T2)/foo.o # yes, I know I can use $@, this is an example
这与使用 private
具有相同的非传播效果,代价是将值 "leak" 改为 every 目标(在构造姓名)。
您可以将它包装在一个定义中,以删除变量的手动构建和使用(尽管在大多数情况下这对您仅使用定义本身有何好处尚不清楚)。
可以将私有和定义或构造的 makefile 用途结合起来以实现 make 版本兼容性。但是,.FEATURES
中未指明对 private
的支持,因此需要使用 oneshell
作为代理,因为它也在 make 3.82 中引入。
这是我正在处理的复杂得多的构建系统的一个简单示例。
T := 1
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
T := 2
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
(两种模式都在包含文件中定义,因此它们必须是相同的文本。)
这行不通。虽然模式本身是正确创建的,使用称为 1/foo.o: 1/foo.c
和 2/foo.o: 2/foo.c
的规则,但配方本身在实际执行之前不会 $T
扩展;当然,此时 $T
的值为 2,即使在第一个配方中也是如此。
我知道在定义配方的地方强制扩展变量的唯一方法是将整个模式放在一个多行变量中,然后用 $(eval)
...扩展它怪诞。
我知道这里的答案可能是 否 ,但是还有其他方法可以强制 $T
在上述方法中内联扩展吗?
据我所知,你有三个选择。
- 目标特定变量
- 解析时规则定义(
eval
等)。 - 构造变量名。
使用特定于目标的变量
T := 1
$T/foo.o: T:=$T
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
T := 2
$T/foo.o: T:=$T
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $@, this is an example
正如在 private
功能),这可能并不总是什么你要
使用解析时规则定义
define foorule
$T/foo.o: $T/foo.c
touch $T/foo.o # yes, I know I can use $$$$@, this is an example
endef
T := 1
$(eval $(foorule))
T := 2
$(eval $(foorule))
但是(如问题中所述)这并不完全漂亮,偶尔需要仔细协商扩展(对于那些想要在配方时扩展的东西与那些不想要的东西相比)。
使用构造变量名
T := 1
T$(T) := $T
$T/foo.o: $T/foo.c
touch $(T1)/foo.o # yes, I know I can use $@, this is an example
T := 2
T$T := $T
$T/foo.o: $T/foo.c
touch $(T2)/foo.o # yes, I know I can use $@, this is an example
这与使用 private
具有相同的非传播效果,代价是将值 "leak" 改为 every 目标(在构造姓名)。
您可以将它包装在一个定义中,以删除变量的手动构建和使用(尽管在大多数情况下这对您仅使用定义本身有何好处尚不清楚)。
可以将私有和定义或构造的 makefile 用途结合起来以实现 make 版本兼容性。但是,.FEATURES
中未指明对 private
的支持,因此需要使用 oneshell
作为代理,因为它也在 make 3.82 中引入。