自动变量无法在Makefile中正确扩展

时间:2019-05-09 17:51:00

标签: c linux makefile gnu-make

我正在使用以下代码:

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。如果要更改先决条件,我想使用$ <。我将如何去做?

2 个答案:

答案 0 :(得分:4)

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

自动变量(例如$@)仅在配方中定义,而在目标或先决条件列表中未定义。 GNU Make manual section on automatic variables中突出显示了此内容:

  

一个常见的错误是尝试在先决条件列表中使用$@;这是行不通的。

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

GNU make确实具有一项功能,可让您进行前提条件的第二扩展。手册中对此进行了说明。但是,更简单的解决方案是仅不依赖先决条件列表中的$@。如果要创建自己的通用C编译配方,请对目标文件(.o)目标使用模式规则。对于最终可执行文件,请列出最终可执行文件的所有先决条件(几乎可以肯定不止一个文件)。

通常,这是通过使用名称分别为SRCSOBJS(如果您不介意键入元音,则分别使用SOURCESOBJECTS)的变量来完成的。通常,您将目标文件作为最终可执行文件的先决条件(这将是链接操作),因为每个单独的源文件都有其自己的标头先决条件。

答案 1 :(得分:1)

基本问题是自动变量仅在配方中定义。因此,前提条件是未定义$ @。因为$ <将引用不依赖$ @的表达式,所以$ <也将不存在。

因此,实际上有两种方法可以解决此问题。第一种方法比较笨拙,但是可以使用辅助扩展。从本质上讲,这使我们无需添加太多代码即可做自己想做的事情。

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 $@