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 Make手册中find所有这些特殊variables的列表。

例如,请考虑以下声明:

 all: library.cpp main.cpp 

在这种情况下:

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

$@$<被称为自动variables。 $@是输出variables。 $<被称为第一个inputvariables。 例如:

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

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

-c标志生成.o文件; 看man gcc的更详细的解释。 -o指定要输出到的文件。

有关更多详细信息,请阅读此部分 。

另外,你可以检查GNU手册。 有一种方法来debugging您的生成文件,以更好地理解它。

这将输出生成文件数据库:

 $make -p 

$@$<是特殊的macros。

哪里:

$@是目标的文件名。

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

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

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

有七个“核心”自动variables:

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

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

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

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

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

  • $+ :与$^类似,这是所有由空格分隔的先决条件的名称,除了$+包含重复项。 这个variables是为特定情况创build的,例如重复值有意义的链接器的参数。

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

另外,上述每个variables都有两个变体,以便与其他变体兼容。 一个变体只返回值的目录部分。 这通过向符号$(@D)$(<D)等附加“D”来表示。另一个变体只返回值的文件部分。 这是通过向符号$(@F)$(<F)等附加一个“F”来表示的。注意这些变体名称长度超过一个字符,因此必须用括号括起来。 GNU make为dir和notdir函数提供了一个更可读的替代scheme。

如果main.cpphello.cppfactorial.cpp任何一个发生更改,Makefile会生成hello可执行文件。 实现这个规范的最小可能的Makefile可能是:

 hello: main.cpp hello.cpp factorial.cpp g++ -o hello main.cpp hello.cpp factorial.cpp 
  • 亲:很容易阅读
  • 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 
  • 亲:修复效率问题
  • con:新的维护噩梦,对目标文件规则的潜在错字

为了改善这一点,我们可以用一个.cpp.o规则replace所有的目标文件规则:

 OBJECTS=main.o hello.o factorial.o hello: $(OBJECTS) g++ -o hello $(OBJECTS) .cpp.o: g++ -c $< -o $@ 
  • 亲:回到有一个简短的makefile,有点容易阅读

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

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

Makefile中的其他变化是:

  • 使编译器从g ++更改为任何C ++编译器变得更容易。
  • 更容易更改编译器选项。
  • 更容易更改链接器选项。
  • 使更容易更改C ++源文件和输出。
  • 增加了一个默认的规则'all',它可以作为一个快速检查来确保所有的源文件在尝试构build应用程序之前都已经存在。