【问题标题】:Expanding make variables at pattern definition time在模式定义时扩展 make 变量
【发布时间】:2015-05-19 20:54:32
【问题描述】:

这是一个我正在研究的更复杂的构建系统的简单示例。

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.c2/foo.o: 2/foo.c 的规则,但配方本身在实际执行之前不会扩展$T;当然,此时$T 的值为 2,即使在第一个配方中也是如此。

我知道在定义配方的地方强制扩展变量的唯一方法是将整个模式放在一个多行变量中,然后用 $(eval)... 扩展它,这很奇怪。

我意识到这里的答案可能会是,但是还有其他方法可以强制$T 在上述配方中内联扩展吗?

【问题讨论】:

  • 您可以使用特定于目标的变量在解析时“捕获”变量来执行此类操作。请参阅我链接的问题。
  • 特定于目标的变量非常危险;它们通过依赖树向下传播,这意味着如果通过多个顶级规则可以看到相同的依赖,并且这些顶级规则使用不同的目标特定变量,那么依赖看到的定义取决于 makefile 的执行顺序。这是未定义的。
  • 啊! cmets 中的多线程竞争条件!
  • 是的,除了直接 eval 和特定于目标的变量之外,我不确定您还有其他选择。 (至少这不像你在解析时写出并在配方时读取的特定于目标的 env 文件那样可怕的黑客攻击。)

标签: gnu-make


【解决方案1】:

据我所知,您有三个选择。

  1. 目标特定变量
  2. 解析时规则定义(eval 等)。
  3. 构造变量名称。

使用特定于目标的变量

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

正如in the comments 在问题上所讨论的,目标特定变量对相关目标的所有先决条件都是可见的(除非使用 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 具有相同的非传播效果,但代价是“泄漏”到每个目标(在构造名称下)。

您可以将其包装在定义中,以消除手动构造和使用变量(尽管在大多数情况下,与仅使用定义本身相比,这对您有何好处尚不清楚)。

可以将私有和定义或构造的 makefile 使用结合起来以实现 make 版本兼容性。但是private 的支持并未在.FEATURES 中指明,因此需要使用oneshell 作为代理,因为它也在make 3.82 中引入。

【讨论】:

  • 我实际上会选择选项 2,除了每次我这样做$(eval $(var)) 我都在里面死了一点......谢谢你的全面回答;这就是我的想法,但很高兴得到确认。 (我已经过了讨厌make的地步。现在它让我如此,如此悲伤。)
  • 顺便说一句:T($T) := $T。这是特殊语法还是错字?现在我正在使用$(eval T$T := $T) 执行此操作,但这很痛苦。
  • 错字。我的意思是T$(T)T$T 也可以。
  • 确实如此。我想知道为什么我认为我需要eval耸耸肩无论如何,ta。
  • 如果这是一个 make 生成器,我可能会进行特征检测并更喜欢 private,以便最终定义版本可以消失。但这是相当大的开销(可能还有两种不同的配方生成模型),所以可能不值得。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
相关资源
最近更新 更多