生成文件符号$ @和$ <是什么意思?


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

什么做的$@$<准确呢?


5
上面的链接已断开,这是另一个链接:gnu.org/software/make/manual/html_node/Automatic-Variables.html
asciz 2013年

1
嗨,“。cpp.o:”作为目标是什么意思?(在最后一行之前?)。
pseudonym_127

3
“ .cpp.o:”表示从“ .cpp”(源文件)构建“ .o”(目标文件)
jaguzu 2013年

1
我认为应该注意,在下面的链接中有一个make教程,我相信Mohit从他的帖子中获得了makefile。mrbook.org/blog/tutorials/make
DeepDeadpool,2015年

Microsoft将其称为“ 文件名宏”(对于NMAKE)比“ 自动变量”(对于MAKE)更清晰。双方都出于教育目的很有用。
伊万津尼奥

Answers:


502

$@是要生成的文件的名称,也是$<第一个前提条件(通常是源文件)。您可以在GNU Make手册中找到所有这些特殊变量的列表。

例如,考虑以下声明:

all: library.cpp main.cpp

在这种情况下:

  • $@ 评估为 all
  • $< 评估为 library.cpp
  • $^ 评估为 library.cpp main.cpp

16
值得注意的是,$@不一定要最终成为文件,它也可以是.PHONY目标的名称。
Ephemera 2015年

我可以在命令行选项中添加以下内容:$@s生成程序集输出(例如name.os)吗?
huseyin tugrul buyukisik

4
当心第一个依赖项是表示列表的变量时,$ <将在扩展后进行求值。因此,当LIST = lib1.cpp lib2.cpp以及所有:$ {LIST} main.cpp时,$ <被评估为lib1.cpp。几年前,我花了一些时间来弄清楚这种行为所导致的结果。
灿金

通常,$ @表示目标名称,该名称位于以下位置:
Deepak Kiran

78

$@$<被称为自动变量。该变量$@代表已创建文件的名称(即目标),并$<代表创建输出文件所需的第一个先决条件。
例如:

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

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

-c标志生成.o文件;请参阅man gcc以获取更详细的说明。该-o指定输出文件来创建。

有关更多详细信息,您可以阅读有关Linux Makefiles的文章

另外,您可以查看GNU make手册。这将使制作文件和调试它们变得更加容易。

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

make -p 

1
您的答案听起来像$<将扩展为hello.c hello.h(两者)。请说清楚。
Beco博士

是的,它将同时包含hello.c和hello.h
灵巧的

19
$<只是第一项。要包含所有内容,请使用$^
Beco博士

1
贝科博士是正确的。作者应修改其答案。
PT Huynh 2015年

67

摘自《使用GNU Make管理项目》,第三版,p。16(根据GNU自由文档许可证):

make匹配规则后通过设置自动变量。它们提供对目标和先决条件列表中元素的访问,因此您不必显式指定任何文件名。它们对于避免代码重复非常有用,但是在定义更通用的模式规则时至关重要。

有七个“核心”自动变量:

  • $@:代表目标的文件名。

  • $%:归档成员规范的文件名元素。

  • $<:第一个必备条件的文件名。

  • $?:比目标更新的所有先决条件的名称,用空格分隔。

  • $^:所有必备组件的文件名,以空格分隔。此列表已删除重复的文件名,因为对于大多数用途(例如编译,复制等),不需要重复的文件名。

  • $+:类似于$^,这是所有必备项的名称,用空格分隔,但$+包括重复项。该变量是为特定情况创建的,例如链接器的参数,其中重复的值具有含义。

  • $*:目标文件名的主干。词干通常是没有后缀的文件名。不建议在模式规则之外使用它。

此外,上述每个变量都有两个变体,以便与其他品牌兼容。一个变体仅返回值的目录部分。这是通过附加一个“d”到符号,指示$(@D)$(<D)等等。其他变体只返回值的文件部分。这是通过附加一个“F”的符号,表示$(@F)$(<F)等需要注意的是,这些不同名称的超过一个字符长,所以必须用括号括起来。GNU make通过dir和notdir函数提供了更具可读性的替代方法。


37

$@$<特殊的宏。

哪里:

$@ 是目标的文件名。

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


19

Makefile的构建hello可执行文件,如果中的任何一个main.cpphello.cppfactorial.cpp改变。实现该规范的最小可能的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.oanyfile.cpp

  • $< 匹配第一个依赖项,在这种情况下, anyfile.cpp
  • $@匹配目标,在这种情况下为anyfile.o

Makefile中存在的其他更改是:

  • 使将编译器从g ++更改为任何C ++编译器变得更加容易。
  • 使更改编译器选项更加容易。
  • 使更改链接器选项更加容易。
  • 使更改C ++源文件和输出变得更加容易。
  • 添加了默认规则“全部”,该规则可以快速检查以确保在尝试构建应用程序之前所有源文件都存在。

1

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

您需要做:

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的所有行中逐行INSTEAD,然后是SRC的所有行


我想知道,用“ u”而不是“ you”来节省所有的时间,您将如何处理?
伊万津尼奥(Ivanzinho)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.