sharkie's inn

Back

使用 Makefile 可以让我们免去编译、链接时,老是需要输入繁琐的命令。

使用案例#

假设现在在你的工作目录下有三个文件:main.cpp, print.cpp, calc.cpp.

其中 main.cpp 中使用了 print.cppcalc.cpp 的符号,现在我们想要用把它们编译、链接成一个可执行文件。

原始方法:(生成一个名为 holo 的可执行文件)

g++ -o holo main.cpp print.cpp calc.cpp
shell

使用 Makefile:

Version 1#

在工作目录下新建文件 Makefile,输入如下:

Makefile
holo: main.cpp print.cpp calc.cpp
	g++ -o holo main.cpp print.cpp calc.cpp
makefile

第一行的意思是要生成 holo 对象,冒号后面是为了生成 holo 对象需要的依赖,第二行的意思就是执行具体的命令(注意前面加了 Tab 符!)

然后我们只需要在工作目录下执行 make holo 命令就可以生成对应的可执行文件了!(实际上直接用 make 也可以,因为如果不指定生成对象的话,make 会自动找到第一个对象进行生成)

如果 holo 对象的生成时间是更新于它所有的依赖文件的,那么我们在这种情况下执行 make 的时候是不会执行对应的命令的,因为你的对象已经是最新的了。

Version 2#

CXX = g++
TARGET = holo
OBJ = main.o print.o calc.o

$(TARGET): $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
	$(CXX) -c main.cpp

print.o: print.cpp
	$(CXX) -c print.cpp

calc.o: calc.cpp
	$(CXX) -c calc.cpp
makefile

这个相对于 Version 1 的优势是

  • 定义了一些变量作为可替换的值,增加了可维护性。
  • 对于 TARGET 的所需要的依赖,在 Makefile 文件中都写出了这些依赖所需的依赖,这样我们就可以根据依赖们的时间来推断是否这个依赖(这里指 TARGET 所需的 .o 文件)需要被重新编译。这样就实现了按需编译,减少了不必要的时间。

Version 3#

CXX = g++
TARGET = holo
OBJ = main.o print.o calc.o

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) -o $@ $(CXXFLAGS) $<
	
.PHONY: clean
clean:
	rm -rf *.o $(TARGET)
makefile

这里的 $@ 指前面的生成对象名,$^ 指生成该对象的所有依赖,$< 指生成该对象的第一个依赖。

.PHONY 的作用:如果没有 .PHONY: clean,那么如果你的工作目录里面如果有 clean 文件的话,那么执行 make clean 是不会执行下面的命令了,因为 clean 文件已经是最新的了。所以我们添加 .PHONY: clean 来向 make 说明 clean 并不是实际的生成对象,而是一套指令,直接执行即可。

这个相对于 Version 2 的优势是

  • 对于所有的 .o 对象,定义它的依赖为它的 前缀.cpp,所以对于每次新添加的文件,要修改的地方更少了。
  • 定义了 make clean,执行它可以清除所有由 make 产生的文件。

Version 4#

CXX = g++
TARGET = holo
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) -o $@ $(CXXFLAGS) $<
	
.PHONY: clean
clean:
	rm -rf *.o $(TARGET)
makefile

这个版本和 Version 3 的区别就是对变量 SRCOBJ 的定义。

这个相对于 Version 3 的优势是

  • SRC = $(wildcard *.cpp) 会自动查找工作目录下(不会递归查找工作目录下的目录,如有需要可以配合 find 命令)的所有 cpp 文件,然后赋值给 SRC 变量。
  • OBJ = $(patsubst %.cpp, %.o, $(SRC)) 会将 SRC 的所有 .cpp 文件名替换为对应的 .o 文件名,然后赋值给 OBJ 变量。
Makefile
https://sharkie.cn/blog/makefile
Author sharkie
Published at May 30, 2025
Comment seems to stuck. Try to refresh?✨