hello: main.cpp print.cpp factorial.cpp
g++ -o hello main.cpp print.cpp factorial.cpp
上面版本的问题,就是一个源文件每次我们都要重新去编译,而有可能该源文件本身就没有修改过,所以 最好是生成 .o
文件,这样子只有被修改过的源文件才会重新生成 .o
文件,减少编译的时间,并且这里引入了变量,使用 $
和括号 ()
来囊括,如下所示:
CXX = g++
TARGET = hello
OBJ = main.o print.o factorial.o
$(TARGET) : $(OBJ)
$(CXX) -o $(TARGET) $(OBJ)
main.o : main.cpp
$(CXX) -c main.cpp
print.o : print.cpp
$(CXX) -c print.cpp
factorial.o : factorial.cpp
$(CXX) -c factorial.cpp
版本二的问题就是如果每当增加了新的源文件,我们都要写它的 .o 生成规则,这就很麻烦,特别是源文件很多的情况,所以我们可以用匹配符 % 来匹配 .o 以及 .cpp 文件,然后又引入 @、^、
此外还引入了伪目标 .PHONY
,它可以标记一个命令进行执行,该命令不会因为文件路径中有同名的文件而被干扰,并且每次执行该命令都是会重新执行的,而不是看是否有文件被修改过!
后面我们有了新的源文件之后,我们 只需要在 OBJ
变量中添加其 .o
文件名即可!
CXX = g++
TARGET = hello
OBJ = main.o print.o factorial.o
CXXFLAGS = -c -Wall
$(TARGET) : $(OBJ)
$(CXX) -o $@ $^
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $@
.PHONY:clean
clean:
rm -f *.o $(TARGET)
有更好的方案,就是当我们添加新的源文件到当前目录中的时候,我们也不需要去添加对应的 .o
文件!如何做到的呢❓❓❓
这里只添加了第三行,以及修改第四行,其它都是不变的!
第三行表示将当前目录中的符合 .cpp
后缀的文件都放到 SRC
变量中;而第四行使用 patsubst
表示将 SRC
变量中的 .cpp
后缀都改为 .o
,这样子一来就相当于帮我们处理完了 .o
文件了,只不过要注意的是 在当前目录中!
CXX = g++
TARGET = hello
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))
CXXFLAGS = -c -Wall
$(TARGET) : $(OBJ)
$(CXX) -o $@ $^
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $@
.PHONY:clean
clean:
rm -f *.o $(TARGET)
引入 cmake
是因为跨平台的原因,因为在不同平台中编写的 makefile
是不同的,所以就要有一个工具也就是 cmake
来解决!
一般 cmake
文件我们 统一命名为 CMakeLists.txt
,然后看下面的例子:(还是使用上面讲 makefile
中提到的几个文件来举例)
cmake_minimum_required(VERSION 3.10)
project(hello)
add_executable(hello main.cpp print.cpp factorial.cpp)
第一句的意思就是这个 cmake
的版本最低就是 3.10
;然后第二句表示要生成的工程就是 hello
;第三句表示要执行的语句。这样子 cmake
就写完了!
最暴力的方式就是在当前工作目录中直接用下面的指令:
[liren@VM-8-7-centos ~]$ cmake .
它就会执行 cmake
的规则后就会生成 makefile
文件,接着我们执行 make
指令就能创建以下这些文件:
这样子其实直接放在工作目录中是很凌乱的,所以我们不推荐这样子做!因为要这些文件要删除的时候要手动删,如果文件很多的话,看起来是非常吃力的!所以我们一般推荐这么做:
build
。build
中,然后执行指令 cmake ..
表示去上一层目录中找文件 CMakeLists.txt
进行操作。makefile
文件,然后直接 make
后就能得到目标文件了! 这样子做的好处就是将这些生成文件放到一个文件夹 build
中统一保管,这样子一来看起来整洁,并且删除起来我们只需要删除整个文件夹即可,非常方便!
第一个 Makefile
的规则如下:
$(OBJ) : $(SRC)
$(CC) $(CFLAGS) -o $@ -c $<
这个规则使用了 < 变量,它表示所有依赖文件中的第一个文件,即
而第二个 Makefile
的规则如下:
$(OBJDIR)/%.o : $(SRCDIR)/%.cc
$(CC) $(CFLAGS) -o $@ -c $<
这个规则使用了 模式匹配,并且将目标文件和依赖文件的路径都指定为模式。这样,对于每个源文件,该规则都会生成对应的目标文件,并将其放到指定的目录中。
因此,第二个 Makefile
的规则更加准确和合理,可以正确地根据每个源文件生成对应的目标文件。而第一个 Makefile
在处理多个源文件时存在问题,只会使用第一个源文件生成所有目标文件,这是不正确的。
所以,第二个 Makefile
是正确的形式,建议使用该形式来生成目标文件。