在Makefile中将目标特定变量作为前提条件

16

我正在尝试编写一个GNU make Makefile,其中有许多类似的目标,其构建命令在它们之间略有不同。 我正在尝试使用目标特定变量来表示这些差异。 其中一些变量值引用了我想要用作先决条件的文件。 例如:

target_1:special_filename=target1_prereq
target_2:special_filename=target2_prereq

target_1 target_2: common_filename $(special_filename)
    do_something common_filename --a-weird-option=$(special_filename)
当我调用“make target_1”时,如果target1_prereq不存在,我希望它制作target1_prereq。目前看来,尽管使用了正确的参数调用构建命令(do_something),但似乎没有将target1_prereq用作先决条件。
我正在使用GNU Make 3.80。
编辑: 来自真实系统的几个更复杂的情况。其中一些变量本身基于其他变量的值。手动指定先决条件不会扩展。一个稍微复杂一点的例子:
target_1:special_filename_base=target1_prereq
target_2:special_filename_base=target2_prereq

some_filename_a = $(special_filename_base).exta
some_filename_b = $(special_filename_base).extb

target_1 target_2: common_filename $(special_filename_b) $(special_filename_a)
    do_something common_filename --a-weird-option=$(special_filename_a) --second=$(special_filename_b)
3个回答

4

目标特定变量仅在目标的命令中定义(或在其他目标特定分配中定义); 它不能用作目标的先决条件之一。我认为在Make中没有干净的方法可以实现您想要的内容,但有几种笨拙的方法,例如以下方法:

EXTENSIONS = .exta .extb
target_1: $(addprefix target1_prereq,$(EXTENSIONS))
target_2: $(addprefix target2_prereq,$(EXTENSIONS))
target_1 target_2: common_filename do_something common_filename --a-weird-option=$(filter %.exta,$^) --second=$(filter %.extb,$^)

4
为了让其他偶然发现这个帖子的人受益,我重新启动了这个线程。一个更优雅的解决方案是使用二次扩展。 - Seth
@ Seth,我同意:目标_1 目标_2:common_filename $$(special_filename_base).exta $$(special_filename_base).extb ... - Beta

3

我发现了一种规避这个限制的相当干净的方法。它将像这样进行:

target_1:export special_filename_base=target1_prereq
target_2:export special_filename_base=target2_prereq

some_filename_a = $(special_filename_base).exta
some_filename_b = $(special_filename_base).extb

target_1 target_2:
    $(MAKE) -f $(firstword $(MAKEFILE_LIST)) target-proxy

target-proxy: common_filename $(special_filename_b) $(special_filename_a)
    do_something common_filename --a-weird-option=$(special_filename_a) --second=$(special_filename_b)

两个重要的点:

  1. export目标变量,这样它们在重新运行Makefile时将是可访问的。
  2. 创建一个代理目标,它具有target_1 target_2的所有原始先决条件,并在target_1 target_2中再次使用此代理目标调用Makefile。由于目标特定变量到那时已经有了值(我们在那时已经进入了配方)并且它们被export了,所以它们将在target-proxy中可用 - voila :)

这种方法的缺点是我们正在创建另一个make进程 - 如果只是另一个进程,那么可能没问题,但您的情况可能有所不同,所以请格外小心。


看起来确实是使用递归的make选项。通过这样做,可以将先决条件声明为顶级,并避免构建先决条件列表的麻烦。感谢您的回答。 - Pommy

3

作为一个简单的解决方法:

target_1:special_filename=target1_prereq
target_1:target1_prereq
target_2:special_filename=target2_prereq
target_2:target2_prereq
target_1 target_2: common_filename $(special_filename) do_something common_filename --a-weird-option=$(special_filename)

虽然存在一些冗余,但是它是局部的,所以并不太糟糕。


我猜那解决了我发布的特定案例,但我希望有一个更一般化的解决方案。我将编辑一个更复杂的例子。 - Nimrod Gileadi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接