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 $@
$@
和$<
到底做了什么?
答案 0 :(得分:408)
$@
是正在生成的文件的名称,$<
是第一个先决条件(通常是源文件)。您可以在GNU Make manual中找到所有这些特殊变量的列表。
例如,请考虑以下声明:
all: library.cpp main.cpp
在这种情况下:
$@
评估为all
$<
评估为library.cpp
$^
评估为library.cpp main.cpp
答案 1 :(得分:67)
$@
和$<
被称为自动变量。变量$@
表示已创建文件的名称(即目标),$<
表示创建输出文件所需的第一个先决条件。
例如:
hello.o: hello.c hello.h
gcc -c $< -o $@
此处,hello.o
是输出文件。这是$@
扩展到的内容。第一个依赖是hello.c
。这就是$<
扩展到的目标。
-c
标志生成.o
文件;有关更详细的说明,请参阅man gcc
。 -o
指定要创建的输出文件。
有关详细信息,请参阅this article about Linux Makefiles。
另外,您可以查看GNU make
manuals。它可以更容易地制作Makefile并调试它们。
如果运行此命令,它将输出makefile数据库:
make -p
答案 2 :(得分:45)
来自Managing Projects with GNU Make, 3rd Edition( GNU自由文档许可证下):
匹配规则后,自动变量由
make
设置。他们 提供对目标和先决条件列表中元素的访问权限 您不必显式指定任何文件名。他们很 有助于避免代码重复,但在定义时至关重要 更一般的模式规则。有七个“核心”自动变量:
$@
:表示目标的文件名。
$%
:归档成员规范的文件名元素。
$<
:第一个先决条件的文件名。
$?
:比目标更新的所有先决条件的名称, 用空格分隔。
$^
:所有先决条件的文件名,以空格分隔。这个 列表中删除了重复的文件名,因为大多数用途,例如 编辑,复制等,不需要重复。
$+
:与$^
类似,这是所有先决条件的名称 按空格,但$+
包含重复项。这个变量是 为特定情况创建,例如链接器的参数where 重复值具有意义。
$*
:目标文件名的主干。词干通常是文件名 没有后缀。它在模式规则之外的使用是 气馁。此外,上述每个变量都有两个变体 与其他品牌的兼容性。一个变体仅返回目录 部分价值。通过在“。”上附加“D”来表示 符号,
$(@D)
,$(<D)
等。另一个变量仅返回文件 部分价值。通过在“。”上添加“F”来表示 符号,$(@F)
,$(<F)
等。请注意,这些变体名称不仅仅是 一个字符长,因此必须括在括号中。 GNU make 使用dir和notdir提供更具可读性的替代方案 功能
答案 3 :(得分:34)
$@
和$<
是特殊的宏。
其中:
$@
是目标的文件名。
$<
是第一个依赖项的名称。
答案 4 :(得分:18)
如果hello
,main.cpp
,hello.cpp
中的任何一个发生了更改,则Makefile会构建factorial.cpp
可执行文件。实现该规范的最小可能Makefile可能是:
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
为了改进上述内容,我们只编译那些已编辑的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 $@
此处.cpp.o
规则定义了如何从anyfile.o
构建anyfile.cpp
。
$<
与第一个依赖项匹配,在本例中为anyfile.cpp
$@
与目标匹配,在本例中为anyfile.o
。Makefile中存在的其他更改是:
答案 5 :(得分: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的所有行中逐行