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

Moh*_*nde 371 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 $@
Run Code Online (Sandbox Code Playgroud)

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

bdo*_*lan 450

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

例如,请考虑以下声明:

all: library.cpp main.cpp
Run Code Online (Sandbox Code Playgroud)

在这种情况下:

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

  • 值得注意的是,`$ @`并不一定最终成为一个文件,它也可能是`.PHONY`目标的名称. (11认同)
  • 当心第一个依赖项是表示列表的变量时,$ &lt;将在扩展后进行求值。因此,当LIST = lib1.cpp lib2.cpp,以及所有:$ {LIST} main.cpp时,$ &lt;被评估为lib1.cpp。几年前,我花了一些时间来弄清楚这种行为所导致的结果。 (2认同)
  • 一般来说,$@ 指的是位于左侧的目标名称: (2认同)

dex*_*ous 70

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

hello.o: hello.c hello.h
         gcc -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

hello.o是输出文件.这是$@扩展到的.第一个依赖是hello.c.这是$<扩展到的.

-c标志生成该.o文件; 请参阅man gcc更详细的解释.该-o指定输出文件来创建.

有关更多详细信息,请阅读有关Linux Makefiles的文章.

另外,您可以查看GNU make手册.它可以更容易地制作Makefile并调试它们.

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

make -p 
Run Code Online (Sandbox Code Playgroud)

  • `$ <`只是第一项.要包含所有内容,请使用`$ ^`. (16认同)
  • 你的答案听起来像“$&lt;”将扩展为“hello.c hello.h”(两者)。请澄清。 (2认同)

ale*_*lex 57

来自使用GNU Make管理项目,第3版(它是在GNU自由文档许可下):

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

有七个"核心"自动变量:

  • $@:表示目标的文件名.

  • $%:归档成员规范的filename元素.

  • $<:第一个先决条件的文件名.

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

  • $^:所有先决条件的文件名,以空格分隔.此列表删除了重复的文件名,因为对于大多数用途,例如编译,复制等,不需要重复.

  • $+:类似于$^,这是由空格分隔的所有先决条件的名称,除了$+包含重复项.此变量是针对特定情况创建的,例如链接器的参数,其中重复值具有含义.

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

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


Eri*_*ric 36

$@$<特殊的宏.

哪里:

$@ 是目标的文件名.

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


Ste*_*uan 18

Makefile的构建hello可执行文件,如果中的任何一个main.cpp,hello.cpp,factorial.cpp改变.实现该规范的最小可能Makefile可能是:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
Run Code Online (Sandbox Code Playgroud)
  • 亲:非常容易阅读
  • con:维护噩梦,重复C++依赖
  • con:效率问题,我们重新编译所有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
Run Code Online (Sandbox Code Playgroud)
  • 亲:解决效率问题
  • con:新的维护噩梦,对象文件规则的潜在错字

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

OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@
Run Code Online (Sandbox Code Playgroud)
  • 亲:回到有一个简短的makefile,有点容易阅读

这里的.cpp.o规则定义如何建立anyfile.oanyfile.cpp.

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

Makefile中存在的其他更改包括:

  • 更容易将编译器从g ++更改为任何C++编译器.
  • 更容易更改编译器选项.
  • 更容易更改链接器选项.
  • 更容易更改C++源文件和输出.
  • 添加了一个默认规则"all",用于快速检查以确保在尝试构建应用程序之前存在所有源文件.