我们在程序的生前死后中给出了一些例程以及将他们编译成可执行文件所需要执行的指令,在函数和链接库给出了使用gcc编译自己的代码为库的方法。我们发现,即使只是简单的几个源文件需要输入好多行指令,遑论更大的应用程序、浏览器甚至操作系统和游戏规模的软件。
程序员的三大美德:懒惰、急躁和傲慢——Larry Wall(Perl发明者)
为了偷懒,将调用编译器的指令自动化,构建工具就诞生了。
早期主流的构建工具是GNU的make系统,而Makefile是用于自动化构建过程的配置文件,它由makefile语言写成,是GNU Make工具的核心组成部分。make在Unix-like的系统被广泛使用,我们只会简单介绍一下make,因为他已经不是桌面开发的学习和应用重点。
通过使用Make,我们只要为每个源文件指定编译规则,包括需要包含哪些头文件、链接哪些库、使用什么编译优化参数,然后调用Make程序,make程序会解析makefile(你可以将make看作是makefile的解释器),将他们转化为对gcc的调用。
这样,我们就可以不用直接与gcc打交道,而是在其上完成一层抽象,编写更简单的makefile,make会帮助我们实现一些重复而繁杂的工作。
这里是一个使用makefile编写编译规则的例子:makefile e.g.
你发现还是有点麻烦,能不能自己找到要用的头文件和库? 而且对于每个库都需要手动设置规则和头文件/库查找路径的工作基本上属于重复劳动,相互之间的依赖还十分复杂。
我们发现,每个库都可以作为一个单独的模块(编译单元),能不能为一个库编写专门的模块化依赖管理工具,为每个库设计同一的接口,把它们的链接库和头文件以及上游依赖放到规定的位置,当我们要使用这个库的时候,直接通过这个管理工具去选择要使用的库(甚至选择需要用到的库中的几个特定的功能),岂不是十分方便?
这样,每个程序员在开发自己的项目时,就不需要重复编写对模块的依赖(即头文件和库路径)。
总结上面的需求,库的依赖实际上就分为三个部分:
CMake就可以很好地实现这些功能。
由copilot生成的简介:cmake简介
CMake的工作就是,提供一套解析和管理依赖的统一接口,每个库都需要提供一个CMake规定的依赖管理文件(封装!),当程序员使用这些库的时候,通过CMake来解析这些依赖文件,从而自动生成构建规则供底层的构建工具使用。这样,我们就不需要直接编写makefile。
这是一个典型的CMakeLists.txt
构建脚本的内容,使用的仍然是上面make的例子: