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.cpp
, hello.cpp
, factorial.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应用程序之前都已经存在。