【问题标题】:Make: Set variable depending on which target is to be buildMake:根据要构建的目标设置变量
【发布时间】:2017-04-19 20:55:47
【问题描述】:

在 (GNU) make 中,我希望在特定目标的构建链开始时为变量分配一个值。对于目标a.sob.so,每个都取决于b.o,我可以像这样手动执行此操作:

# Rules
all: a.so b.so
a.so: b.o
    @echo Current .so is $(current)
    touch $@
b.so: b.o
    @echo Current .so is $(current)
    touch $@
b.o:
    @echo Current .so is $(current)
    touch $@

# Set the "current" variable based on which .so is being build
a.so: current = a.so
b.so: current = b.so

这里,current 在执行a.sob.o 的规则时具有值a.so,而current 仅在执行b.so 的规则时具有值b.so。这就是我要的。我对此的心智模型是,一旦 make 发现应该构建 a.so(即在运行 a.sob.so 的规则之前),就会触发 a.so: current = a.so 行。如果我错了,请纠正我。

在我的实际情况中,我有更多 .so 文件,所以我想用这样的东西替换最后两行;

%.so: current = $@

或者这个;

sofiles = a b
$(addsuffix .so, $(sofiles)): current = $@

但是,这两种方法都会导致相同的错误行为,即使在即将构建 b.o 目标时,current 变量也会被重新设置。为什么b.o 目标会触发这些行?如何实现与为每个 .so 手动编写 a.so: current = a.so 时相同的行为,但实际上不为每个 .so 连接它?

注意:我知道示例代码中显示的用例很奇怪,并且如果没有这个尴尬的current 变量,也可以达到追求的效果。但是,我对任何不使用此变量即可解决问题的解决方案不感兴趣。

【问题讨论】:

    标签: makefile build compilation gnu-make


    【解决方案1】:

    这里有很多事情要讨论。首先,您对特定于目标的变量如何工作的心理模型并不十分准确(“一旦 make 发现应该构建 a.so,就会触发行 a.so: current = a.so”)。真正发生的是每个目标 make 遇到都会创建一个新的“范围”,该“范围”在创建该目标及其所有先决条件时处于活动状态,并且该目标的特定于目标的变量在该范围内有效。一旦该范围退出(目标完成),那么这些变量设置就消失了。

    在上面的示例中,currentb.o 的配方中的值 a.sob.o 被创建为 a.so 的先决条件时。如果b.o 是作为b.so 的先决条件创建的,那么current 将是b.so。因为您的makefile首先列出a.so,所以它将首先构建,并且因为b.o只会构建一次(每次调用make),它可能看起来总是使用a.so作为current的值,但那是不完全准确。考虑一下:

    $ make all
    Current .so is a.so
    touch b.o
    Current .so is a.so
    touch a.so
    Current .so is b.so
    touch b.so
    

    还有这个:

    $ rm -f b.o
    $ make b.so
    Current .so is b.so
    touch b.o
    Current .so is b.so
    touch b.so
    

    如果 b.o 已构建,请查看如何将 current 设置为 b.so,因为它是 b.so 而不是 a.so 的先决条件。

    还有这个:

    $ rm -f b.o
    $ make b.o
    Current .so is
    touch b.o
    

    这里因为b.o不是任何.so的先决条件,那么current根本没有设置!

    接下来要考虑的是这一行:

    %.so : current = $@
    

    这条线不是为b.o“触发”的。但是,这会将特定于模式的变量 current 设置为值 $@(注意,NOT$@ 变量的扩展!)。这意味着每次扩展 $(current) 时,它都会扩展为 $@,这是 当前 目标名称,无论它用于什么配方。所以这不会扩展为 a.sob.so 除非当前目标名称实际上是 a.sob.so。如果目标名称是b.o,则$@ 扩展为b.o

    如果你想这样做你不能使用像$@这样的变量,你必须使用真正的值。您可以使用eval 执行此操作,例如:

    sofiles = a b
    $(foreach SO,$(sofiles),$(eval $(SO).so: current = $(SO).so))
    

    但是,基于上面的第一个 cmets,我不确定这是否足以满足您的需求。

    【讨论】:

    • 感谢您的详细回答。是的,current 仅在构建 .so 文件时设置(或构建其他文件作为 .so 文件的先决条件)。这就是意图。此外,使用eval(强制变量扩展立即发生,对吗?)完美无缺!
    • eval 评估它的参数,就好像它是 makefile 的一部分,几乎就像一个内联包含文件。见gnu.org/software/make/manual/html_node/Eval-Function.html
    猜你喜欢
    • 1970-01-01
    • 2011-07-18
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多