ChatGPT解决这个技术问题 Extra ChatGPT

makefile 符号 $@ 和 $< 是什么意思?

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
    $(CC) $(CFLAGS) $< -o $@

$@$< 究竟做了什么?

上面的链接坏了,这是另一个:gnu.org/software/make/manual/html_node/Automatic-Variables.html
“.cpp.o:”表示从“.cpp”(源文件)构建“.o”(目标文件)
我觉得应该注意以下链接中有一个制作教程,我相信 Mohit 在他的帖子中获得了制作文件。 mrbook.org/blog/tutorials/make
Microsoft 将其称为 Filename Macros(用于 NMAKE),它比 Automatic Variables(用于 MAKE)更清晰。出于教育目的,看到双方都是有用的。
@user2188550,两边是什么?

S
Steve Lorimer

$@ 是正在生成的目标的名称,$< 是第一个先决条件(通常是源文件)。您可以在 GNU Make manual 中找到所有这些特殊变量的列表。

例如,考虑以下声明:

all: library.cpp main.cpp

在这种情况下:

$@ 评估为所有

$< 计算为 library.cpp

$^ 计算为 library.cpp main.cpp


值得注意的是,$@ 不一定最终必须是一个文件,它也可以是一个 .PHONY 目标的名称。
我可以在命令行选项中添加:$@s 以生成诸如 name.os 之类的程序集输出吗?
请注意,当第一个依赖项是表示列表的变量时, $< 在展开后对其进行评估。因此,当 LIST = lib1.cpp lib2.cpp 和 all: ${LIST} main.cpp 时,$< 被评估为 lib1.cpp。几年前,我花了一些时间弄清楚这种行为导致的结果中发生了什么。
通常 $@ 指的是位于左侧的目标名称:
如果有人有足够的代表来进行 1 个字符的更改,那么上面帖子中的 http:// 链接现在会重定向到 https:// 链接,并且应该进行更新。
a
alex

Managing Projects with GNU Make, 3rd Edition, p. 16(它在 GNU 自由文档许可证 下):

在匹配规则后,自动变量由 make 设置。它们提供对目标和先决条件列表中元素的访问,因此您不必显式指定任何文件名。它们对于避免代码重复非常有用,但在定义更通用的模式规则时至关重要。有七个“核心”自动变量: $@:代表目标的文件名。 $%:归档成员规范的文件名元素。 $<:第一个先决条件的文件名。 $?:比目标更新的所有先决条件的名称,以空格分隔。 $^:所有先决条件的文件名,以空格分隔。此列表已删除重复的文件名,因为对于大多数用途,例如编译、复制等,不需要重复。 $+:与 $^ 类似,这是由空格分隔的所有先决条件的名称,除了 $+ 包含重复项。该变量是为特定情况创建的,例如重复值有意义的链接器参数。 $*:目标文件名的词干。词干通常是没有后缀的文件名。不鼓励在模式规则之外使用它。此外,上述每个变量都有两个变体以与其他品牌兼容。一种变体仅返回值的目录部分。这通过将“D”附加到符号 $(@D)、$(


u
user8395964

$@$< 称为自动变量。变量 $@ 表示目标的名称,$< 表示创建输出文件所需的第一个先决条件。
例如:

hello.o: hello.c hello.h
         gcc -c $< -o $@

这里,hello.o 是输出文件。这就是 $@ 扩展的内容。第一个依赖项是 hello.c。这就是 $< 扩展的内容。

-c 标志生成 .o 文件;有关更详细的说明,请参见 man gcc-o 指定要创建的输出文件。

有关详细信息,您可以阅读 this article on linoxide about Linux Makefiles

此外,您可以检查 GNU make manuals。这将使制作 Makefile 和调试它们变得更加容易。

如果运行此命令,它将输出 makefile 数据库:

make -p 

您的答案听起来像 $< 将扩展到 hello.c hello.h(两者)。请说清楚。
是的,它将包括 hello.c 和 hello.h
$< 只是第一项。要包括所有,请使用 $^
贝科博士是对的。作者应该修改他的答案。
u
user101032

$@$< 是特殊的宏。

在哪里:

$@ 是目标的文件名。

$< 是第一个依赖项的名称。


S
Stephen Quan

如果 main.cpphello.cppfactorial.cpp 中的任何一项发生更改,Makefile 将构建 hello 可执行文件。实现该规范的最小可能 Makefile 可能是:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp

亲:非常容易阅读

缺点:维护噩梦,C++ 依赖项的重复

缺点:效率问题,我们重新编译所有 C++,即使只更改了一个

为了改进上述内容,我们只编译那些被编辑过的 C++ 文件。然后,我们只需将生成的目标文件链接在一起。

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

main.o: main.cpp
    g++ -c main.cpp

hello.o: hello.cpp
    g++ -c hello.cpp

factorial.o: factorial.cpp
    g++ -c factorial.cpp

亲:修复效率问题

缺点:新的维护噩梦,目标文件规则的潜在错字

为了改进这一点,我们可以用一个 .cpp.o 规则替换所有对象文件规则:

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

.cpp.o:
    g++ -c $< -o $@

亲:回到有一个简短的makefile,有点容易阅读

这里的 .cpp.o 规则定义了如何从 anyfile.cpp 构建 anyfile.o

$< 匹配第一个依赖项,在本例中为 anyfile.cpp

$@ 匹配目标,在本例中为 anyfile.o。

Makefile 中存在的其他更改是:

更容易将编译器从 g++ 更改为任何 C++ 编译器。

更容易更改编译器选项。

更容易更改链接器选项。

使更改 C++ 源文件和输出变得更容易。

添加了默认规则“全部”,作为快速检查以确保在尝试构建应用程序之前所有源文件都存在。


A
Aominé

例如,如果您想编译源代码但在不同的目录中有对象:

你需要做:

gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...

但是对于大多数宏,结果将是所有对象后跟所有源,例如:

gcc -c -o <all OBJ path> <all SRC path>

所以这不会编译任何东西 ^^ 并且您将无法将对象文件放在不同的目录中:(

解决方案是使用这些特殊的宏

$@ $<

这将为 SRC (src/file.c) 中的每个 .c 文件生成一个 .o 文件 (obj/file.o)

$(OBJ):$(SRC)
   gcc -c -o $@ $< $(HEADERS) $(FLAGS)

它的意思是 :

    $@ = $(OBJ)
    $< = $(SRC)

但是逐行替换所有 OBJ 行,然后是所有 SRC 行