Makefile 由来
在使用编译器进行编译时,例如 g++ main.cpp source1.cpp source2.cpp -o main
,将编译三个 cpp
文件,并生成一个 main.exe
的可执行文件。
编译命令非常简单,但这在编译文件非常多时,就会产生问题。该编译命令会将所有文件编译一遍,文件数量非常多时,一次编译就需要很多时间。如果对项目进行修改,一个很小的修改就需要将所有文件编译一遍,包括那些未修改的文件。
为了满足这一需求,我们就需要将编译命令拆开。在上述编译命令中,中间文件是不可见的,一次命令就完成了编译,实际上它整合了许多步骤。
g++ 编译步骤:1、2、3 可以看作是编译阶段,生成一个 .o
文件,4 是一个链接阶段,生成一个可执行文件
- 预处理:头文件展开、宏替换等
- 编译器:将源文件编译成汇编文件
- 汇编器:将汇编文件变成二进制文件
- 链接器:对相应的文件进行链接操作
项目修改时,只有一部分文件需要重新编译,另一部分文件并不需要,要重新进行的只有链接的操作,所以只要对修改的文件进行编译,然后进行一次链接即可。
上述的命令可以等价于以下形式:
g++ main.cpp source1.cpp source2.cpp -c
g++ main.o source1.o source2.o -o main
第一条命令生成了一系列已经完成编译的 .o
文件,第二条命令将这些文件进行链接。这时候如果只修改 main.cpp
文件,只需要重新编译 main.cpp
文件即可,不需要再编译其他文件,然后再进行一次链接操作,如下:
g++ main.cpp -c
g++ main.o source1.o source2.o -o main
但是由于上述过程太麻烦,总不能每次编译都要手动去挑选要编译的文件吧,所以就有了 Makefile,将这一过程自动化。
简单的 Makefile 示例
该示例在 Windows 下执行,如果在 Linux 环境下,指令会有所不同
Makefile 文件:
main: main.o source1.o source2.o
g++ main.o source1.o source2.o -o main
main.o: main.cpp
g++ main.cpp -c
source1.o: source1.cpp
g++ source1.cpp -c
source2.o: source2.cpp
g++ source2.cpp -c
clean:
del *.o *.exe
大致的意思是 main
文件需要 main.o
source1.o
source2.o
才可以进行编译,而后续几行又告诉 main.o
source1.o
source2.o
又需要哪些文件,再执行相应的命令。
clean
命令则是删除指定的文件,例如中间生成的 .o
和最终生成的 .exe
文件。
在执行 make
命令时,程序会自动对比文件更新时间,如果没有更新,则不会重复编译。
# 第一次执行make命令,所有文件都编译了一次
PS C:\makefile> make
g++ main.cpp -c
g++ source1.cpp -c
g++ source2.cpp -c
g++ main.o source1.o source2.o -o main
# 修改main.cpp文件,再次执行make命令
# 此时只对main.cpp进行重新编译
PS C:\makefile> make
g++ main.cpp -c
g++ main.o source1.o source2.o -o main
CMake 由来
虽然 Makefile 已经简化了编译的操作,但还是存在一些问题,从上述的 Makefile 示例文件中可以看到,Makefile 所执行的编译命令是平台相关的,在 Linux 下,就需要再写一份基于 Linux 命令的 Makefile,这对于跨平台的项目来说还是有一些不方便。
所以 CMake 就是为了解决这一问题出现的,CMake 会根据平台,自动生成该平台的 Makefile 文件,于是就解决了 Makefile 跨平台不方便的问题。
CMake 示例
Cmake 入门实战 | HaHack
该博客我觉得已经写的比较详细易懂,内容也比较全,根据自己需求进行阅读即可,本文就不再进行赘述了。