Makefile 中的自动变量未正确扩展

Automatic variable not expanding properly in Makefile

我正在使用以下代码:

HELLO_WORLD=hello

$(HELLO_WORLD): $(addsuffix .c,$@)
        gcc $< -o $@

然而,当我 运行 代码时,我收到以下错误,暗示 $< 没有计算任何东西:

gcc  -o hello
gcc: fatal error: no input files

当我使用下面的代码时...

HELLO_WORLD=hello

$(HELLO_WORLD): $(addsuffix .c,$@)
        gcc $(addsuffix .c,$@) -o $@

...Makefile 对以下命令求值...

gcc hello.c -o hello

...这正是我想要的。但是,我不想使用 addsuffix 两次。如果更改先决条件,我想使用 $<。我该怎么做?

问题不在于配方中 $< 的扩展。问题是先决条件列表中 $@ 的扩展。

自动变量,例如 $@,只在配方中定义,不在目标或先决条件列表中。这在 GNU Make manual section on automatic variables:

中突出显示

A common mistake is attempting to use $@ within the prerequisites list; this will not work.

hello.c 实际上不在先决条件列表中这一事实并不妨碍您调用 make hello。这只是意味着 make hello 将始终调用编译器,即使 hello.c 未被修改。但这确实意味着 $< 将与计算的先决条件列表一样空。

GNU make 确实有一个功能可以让你对先决条件进行二次扩展;这在手册中有解释。但更简单的解决方案是根本不依赖先决条件列表中的 $@ 。如果您正在尝试创建自己的通用 C 编译配方,请为 object 文件 (.o) 目标使用模式规则。对于最终的可执行文件,列出最终可执行文件的所有先决条件(几乎肯定不止一个文件)。

通常这是使用单独的变量完成的,名称如 SRCSOBJS(如果您不介意输入元音,则可以使用 SOURCESOBJECTS)。通常,您将 object 文件作为最终可执行文件的先决条件(这将是一个 link 操作),因为每个单独的源文件都有其自己的 header 先决条件。

根本问题是自动变量只在配方中定义。因此,在先决条件中, $@ 未定义。因为 $< 将引用依赖于不存在的 $@ 的表达式,因此 $< 也将不存在。

所以,实际上有两种方法可以解决这个问题。第一种方式有点笨拙,但你可以使用二次扩展。这基本上允许我们在不添加太多代码的情况下做我们想做的事...

HELLO_WORLD=hello

SECONDARYEXPANSION:
$(HELLO_WORLD): $(addsuffix .c,$$@)
        gcc $< -o $@

更合适的方法是重构 Makefile 并使用模式规则。这为我们提供了构建任何 C 文件的通用方法。使用以下 Makefile,我们可以 运行 "make" 或 "make hello" 来构建可执行文件。

HELLO_WORLD=hello

all:
        $(MAKE) $(HELLO_WORLD)

%: %.c
        gcc $< -o $@