linux Makefile中的自动变量未正确展开

jm81lzqq  于 2022-11-28  发布在  Linux
关注(0)|答案(2)|浏览(156)

下面是一个例子:

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两次。我想在我改变先决条件的情况下使用$〈。我该如何着手做这件事呢?

dffbzjpn

dffbzjpn1#

问题不在于配方中$<的扩展。问题在于先决条件列表中$@的扩展。
自动变量,如$@,只在方法中定义,而不在目标或先决条件列表中定义。这在GNU Make手册中关于自动变量的章节中有重点介绍:
一个常见的错误是试图在先决条件列表中使用$@;这是行不通。
hello.c实际上不在先决条件列表中,这并不妨碍调用make hello。这只是意味着make hello将始终调用编译器,即使hello.c没有被修改。但这确实意味着$<将与计算出的先决条件列表一样为空。
GNU make确实有一个特性让你做二次扩展的先决条件;这在手册中有解释。但是更简单的解决方案是不依赖先决条件列表中的$@。如果你试图创建你自己的通用C编译方法,对目标文件(.o)目标使用模式规则。对于最终的可执行文件,列出最终可执行文件的所有先决条件(几乎肯定不止一个文件)。
一般来说,这是通过使用单独的变量来完成的,变量的名字类似于SRCSOBJS(或者SOURCESOBJECTS,如果你不介意键入元音字母的话)。通常你会把目标文件作为最终可执行文件的先决条件(这将是一个链接操作),因为每个单独的源文件都有自己的头文件先决条件。

pbpqsu0x

pbpqsu0x2#

基本问题是自动变量只在配方中定义。因此,在先决条件中,$@没有定义。因为$〈将引用依赖于$@的表达式,而$@并不存在,因此$〈也将不存在。
所以,有两种方法可以解决这个问题。第一种方法有点笨拙,但是你可以使用二次扩展。这基本上允许我们做我们想做的事情,而不需要添加太多代码...

HELLO_WORLD=hello

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

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

HELLO_WORLD=hello

all:
        $(MAKE) $(HELLO_WORLD)

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

相关问题