为什么我不能在 Makefile 先决条件中使用 $(@D)?

问题描述 投票:0回答:1

当我编译 C 文件并将生成的目标文件输出到它们自己的目录中时,我需要确保该目录存在。 我见过两种方法:

  1. 始终创建当前目标的目录:
    obj/%.o: src/%.c
        @mkdir -p $(@D)
        $(CC) ...
    
  2. 添加
    obj/
    目录作为先决条件
    obj/%.o: src/%.c | obj/
        $(CC) ...
    
    obj/:
        mkdir -p $@
    

来自

1.
我喜欢它使用
$(@D)
来避免重复并使其更加健壮,来自
2.
我喜欢
mkdir
只被调用一次,我觉得它在概念上更有意义。

当我尝试像这样结合两者时

obj/%.o: src/%.c | $(@D)
    $(CC) ...

obj/:
    mkdir -p $@

然后编译器会抱怨

obj/
目录不存在。

makefile
1个回答
0
投票

因为这就是 make 的工作原理;来自手册

认识到自动变量值可用的有限范围非常重要:它们仅在配方中具有值。特别是,您不能在规则的目标列表中的任何位置使用它们;它们在那里没有任何价值,并将扩展为空字符串。此外,无法在规则的先决条件列表中直接访问它们。一个常见的错误是尝试在先决条件列表中使用 $@;这是行不通的。然而,GNU make 有一个特殊功能,即二次扩展(请参阅二次扩展),这将允许在先决条件列表中使用自动变量值。

如果你问,为什么 make 会这样工作,那是因为 make 总是在解析 makefile 时扩展目标和先决条件,而不是在匹配规则时扩展。 否则,这样的事情就无法工作:

OBJ = foo

$(OBJ)/%.o : %.c | $(OBJ) ;

OBJ = bar

$(OBJ)/%.o : %.cpp | $(OBJ) ;

尝试特殊情况,某些变量或函数立即扩展,而另一些则推迟到以后,会很混乱,甚至更难以解释和理解。 当然,在规则实际匹配之前,我们不知道

$(@D)
应该是什么,因为
%
可能包含一个目录。

© www.soinside.com 2019 - 2024. All rights reserved.