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

$@和$<到底做什么?


当前回答

例如,如果你想编译源代码,但在不同的目录中有对象:

你需要做的是:

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的所有行后面跟着SRC的所有行

其他回答

$@和$<是特殊的宏。

地点:

$@是目标的文件名。

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

例如,如果你想编译源代码,但在不同的目录中有对象:

你需要做的是:

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的所有行后面跟着SRC的所有行

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

例如,考虑以下声明:

all: library.cpp main.cpp

在这种情况下:

$@计算为所有 $<计算为library.cpp $^计算为library.cpp main.cpp

$@和$<被称为自动变量。变量$@表示目标的名称,$<表示创建输出文件所需的第一个前提条件。 例如:

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

在这里,你好。O是输出文件。这就是$@展开的结果。第一个依赖项是hello.c。这就是$<展开的内容。

-c标志生成.o文件;有关更详细的解释,请参阅man GCC。-o指定要创建的输出文件。

要了解更多详细信息,可以阅读linoxide上关于Linux Makefiles的文章。

此外,您可以查看GNU make手册。这将使生成makefile和调试它们变得更容易。

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

make -p 

如果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

教授:非常容易阅读 缺点:维护的噩梦,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规则定义了如何构建任意文件。O从anyfile.cpp。

$<匹配第一个依赖项,在本例中为anyfile.cpp $@匹配目标,在本例中为anyfile.o。

Makefile中的其他更改包括:

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