无法在GNU Make中设置目标

时间:2015-12-18 07:24:58

标签: makefile gnu-make

当我执行这个GNU Makefile时:

foo: BUILD_DIR = foo_dir
bar: BUILD_DIR = bar_dir

BINARY = $(BUILD_DIR)/my_binary

.PHONY: foo
foo: $(BINARY)

.PHONY: bar
bar: $(BINARY)

$(BINARY):
    @echo $(BINARY)
    @echo $@

我明白了:

$ make foo
foo_dir/my_binary # <= this is what I want
/my_binary        # <= this is NOT what I want
$ make bar
bar_dir/my_binary # <= this is what I want
/my_binary        # <= this is NOT what I want

相反,我想:

$ make foo
foo_dir/my_binary
foo_dir/my_binary
$ make bar
bar_dir/my_binary
bar_dir/my_binary

我该怎么做?我使用GNU Make 3.81。

1 个答案:

答案 0 :(得分:1)

这里的技巧是了解 make 如何解析Makefile。 首先, make 读取Makefile, 随之而来的是依赖图。 它扩展了一些宏, 同时存储其他人以供日后扩展。

foo: $(BINARY)

make 扩展此依赖关系行。 请注意,此时 make 没有构建目标的概念, 所以目标特定变量还没有进入讨论。 ${BINARY}$(BUILD_DIR)/my_binary, 但是${BUILD_DIR}是空的。 在构建foo之前,您已告知 make , 它必须建立/my_binary

$(BINARY):
    @echo $(BINARY)
    @echo $@

现在,当 make 读取此片段时,它会再次展开目标行。 再次, 因为您没有为${BUILD_DIR}提供默认值, 依赖项行中${BINARY}的扩展为/my_binary。 食谱 (那个shell命令块) 存储为单个递归扩展变量。 现阶段没有扩大。

这样做的结果是你告诉 make 如何构建/my_binaryfoo取决于它。

第二阶段 make 查看您要求它制作的内容, 它检查它现在在内存中的依赖图。 它检查它是否知道如何构建所有内容 (这是可能生成可怕的make: *** No rule to make target 'blah'. Stop.消息的地方), 并检查哪些目标已经是最新的。

您要求它构建foo, 所以它尽职尽责决定先建立/my_binary Make 在此阶段不会注意到配方(shell命令)。

最后阶段实际上是执行所需的食谱, 按要求的顺序。 正是在这一点上, make 通过扩展早先收集的配方来获取所需的shell命令。

@echo $(BINARY)
@echo $@

我们正在建设中, 目标特定变量有效。 我们正在建设foo, 所以现在${BUILD_DIR}foo_dir$@/my_binary。 配方的扩展是

@echo foo_dir/my_binary
@echo /my_binary

只有在这次扩张之后 make执行每个结果行, 逐一, 在单独的shell调用中。 这个扩展 - 整个配方 - 执行之前 - 任何事情都很重要! (例如${BINARY}可以扩展为多行。) 啧。

提示

您遇到问题,因为 make 意外地扩展了变量的非特定目标版本。

  1. 始终使用--warn
  2. 运行 make
  3. 提供断言:

    BUILD_DIR = $(error Ooops, unexpected expansion of $$BUILD_DIR) 
    
  4. TL;博士

    有很多方法可以做你想做的事。 我是静态模式规则的忠实粉丝。 如果您的目标及其依赖关系可以通过 make 的noddy模式匹配来描述,那么这些工作就很顺利。

    .PHONY: foo bar
    foo bar: %: %_dir/my_binary
        echo $@
    

    这应该用宏来整理。 希望您现在能够更好地了解如何解析它:

    targets := foo bar
    
    .PHONY: ${targets}
    ${targets}: %: %_dir/my_binary
        echo $@
    

    哦,我应该提一下,配方中的$*会扩展到模式中匹配的%。 这通常很有帮助(尽管在这种情况下很$*$@相同)。