为什么会出现cmake
1、 什么是CMake
-- 是一个项目构建工具,其实cmake和makefile是差不多的,只不过cmake更高级,可以跨平台使用,并且使用起来更加灵活,更符合逻辑。
2、为什么会出现cmake?
c++程序的编译流程:
编译流程分为四个阶段:预处理、编译、汇编、链接
以Linux系统下g++编译为例:
通过g++的选项可以查看过程中的每一步:
-- 预处理: 处理一些#号定义的命令或语句(如#define、#include、#ifdef等),生成.i文件
-- 编译:进行词法分析、语法分析和语义分析等,生成.s的汇编文件
-- 汇编:将对应的汇编指令翻译成机器指令,生成二进制.o目标文件
-- 链接:调用链接器对程序需要调用的库进行链接。链接分为两种
-- 静态链接
-
在链接期,将静态链接库中的内容直接装填到可执行程序中。
-
在程序执行时,这些代码都会被装入该进程的虚拟地址空间中。
-- 动态链接
-
在链接期,只在可执行程序中记录与动态链接库中共享对象的映射信息。
-
在程序执行时,动态链接库的全部内容被映射到该进程的虚拟地址空间。其本质就是将链接的过程推迟到运行时处理
举个例子,现在仅仅给你一个main文件,里面只声明了add函数并调用了add函数,但是不包括add函数的实现,现在要对这个main文件进行编译运行,那么会走到哪一步?前三步走完都不会报错,直到遇到链接,才会报错,因为找不到add函数的实现。
你可以这样理解:每个文件都是独立编译的,直到链接开始前,这些文件被处理成.o文件,里面是一些机器码,等到链接的时候,这些文件才被组合起来。声明相当于你提前向你的程序做出了一份承诺:我现在有一个add函数,你在main文件里只管调用就行,我已经在其它文件里实现了!于是,main文件转头忙活自己的事,尽管它没见过add函数的实现,因为你已经向它做出了承诺。但是等到链接的时候才发现:根本没有add函数的实现。所以报错。
程序编译演化史
写一份main文件,按照上面的流程,使用g++一步一步编译看看每一步会输出什么文件。你在整个过程中遇到的命令大概如下:
g++ -E main.cpp -o main.i
g++ -E add.cpp -o add.i
g++ -S main.i -o main.s
g++ -S add.i -o add.s
g++ -c main.s -o main.o
g++ -c add.s -o add.o
g++ main.o add.o -o main
当然,一般情况下我们会这么编译:
g++ main.cpp add.cpp -o main
现在引入一个问题:你有一个大的工程文件,里面有上百个cpp文件,分别存放在不同的目录中。这种情况如果用g++编译,其难度可想而知。于是,可以得出一个结论:g++对于大型工程并不是特别好用。
接着我们尝试做一些改进。
g++敲命令去编译,对于大型文件简直就是噩梦,每次编译都要敲一大串命令。但是写成文件总比敲命令要方便,要是把这些命令写成文件,每次编译的时候直接复用这个文件就好了。于是,Makefile诞生了。
上面的一大串命令写成对应的Makefile文件是这样的:
main: main.o add.o
g++ main.o add.o -o main
main.o add.o: main.s add.s
g++ -c main.s -o main.o
g++ -c add.s -o add.o
main.s add.s:main.i add.i
g++ -S main.i -o main.s
g++ -S add.i -o add.s
main.i add.i: main.cpp add.cpp
g++ -E main.cpp -o main.i
g++ -E add.cpp -o add.i
Makefile底层执行逻辑是只执行第一个命令,也就是:
main: main.o add.o
g++ main.o add.o -o main
但是由于没有main.o add.o ,所以才会向下执行。
嗯,看起来Makefile是g++的升级,我们可以借助Makefile文件实现相对于直接使用g++更快的编译。我们的问题被解决了吗?解决了一部分,但是还没完全解决。这次的问题出在跨平台上。
g++是Linux平台下的编译器,如果你使用win下的Visual Studio开发代码,它使用的是MSVC编译器,Makefile并不适用这种编译器,它跟Makefile相对应的文件是.sln文件。也就是说尽管大家都要经过预处理,编译,汇编,链接这四个步骤,但是大家走的路是不相同的。
于是,CMake就出现了。
Cmake本质上帮我们做的事情就是针对于不同的编译器,生成相对应的编译命令。针对Linux下的g++就是Makefile文件,针对win下的MSVC就是.sln文件。
CMake相当于在用户和操作系统上的编译器之间做了一层抽象,用户借助于CMake,不用关心自己的操作系统上用了什么编译器就能直接完成工程的快速编译。