简易CMake入门


什么是CMake

先来看看维基百科上的定义

CMake是个一个开源的跨平台自动化建构系统

emmmm…这每个字都能看懂,合在一起就不知道在说啥了。还是按我的理解翻译成人话吧

CMake是一个编译辅助工具,可以根据用户的配置生成自动编译脚本

项目编译的难题

我们初学编程的时候,大多时候只须编译一个代码文件,顶多三四个文件。这个时候手打命令行编译已经足以满足我们的需求。

然而,如果我们的技术得到了提高,开始开发一些大型项目的时候,可能动辄需要编译成百上千个文件,这个时候如果还需要手动一个个文件 编译,那一定是地狱般的体验。

众所周知,程序员是个非常懒惰的群体,一旦遇到重复性的或者麻烦的东西,他们总希望能写一个程序或者脚本来解决这些东西。

从 make 到 CMake

于是 make(是的,还没轮到 CMake 登场)诞生了。这个程序允许用户事先编写一个叫做 Makefile 的文件,在里面指定代码文件目录、编译器、外部库、编译 选项等内容,然后使用 make 命令一键编译。

来看看一个手写的Makefile

这是 Linus Torvalds 给 Linux 0.11 的内核源码编写的 Makefile,可以很清楚看到里面指定了as、gcc作为汇编和c的编译器, ld作为连接器,并且明确了需要编译哪些模块,输出哪些中间文件,以及如何连接成可执行文件。

看起来 make 是个十分不错的东西,然而从上面的文件可以看出,Makefile实际上还是非常复杂,举个例子,假设我在开发一个跨平台的程序, 就得针对这两个平台各自写一个Makefile,分别指定对应的编译器。如果我增加了几个代码文件,也得把它们逐个添加进Makefile。如果我把我的代码发布给用户, 让用户编译,也可能因为用户的操作系统环境、使用的编译器不同等因素导致编译失败并且难以发现错误。

于是,在 make 之上,人们又开发出了多种生成 Makefile 的工具。例如 GNU 的 autoconf,Qt 的 qmake,以及我们的主角 CMake。 利用这些工具,可以通过简单的配置,在不同平台、不同环境中方便地生成 Makefile。

CMake安装

这里下载msi安装包并安装即可

CMake用法

CMake的用法很简单,写一个名为CMakeLists.txt的配置文件,再用 CMake 跑一下,就可以生成我们想要的 makefile。

配置文件的内容

先想想,要编译一个程序,我们需要什么东西?编译器及连接器、源文件、外部库。若没有指定,CMake 会自动查找编译器。 因此,我们可以仅指定源文件和外部库。

CMakeLists.txt 类似一个脚本,由一个个“函数”以及可能存在的分支语句组成。因为是简易入门,因此只记录几个简单的函数, 不去管那些高级的写法,一开始的话,够用就行了。

常用函数

来看一个简单的例子。

cmake_minimum_required(VERSION 3.15)

project(SampleProject)

aux_source_directory(. SRC_FILES)

include_directories("./include")

link_directories("./lib")

link_libraries("libcurl.a")

add_executable(${PROJECT_NAME} ${SRC_FILES})

cmake_minimun_required

用法:cmake_minimun_reauired(VERSION <min>)

指定执行这个脚本的 CMake 的最小版本,一般用于兼容,对初学者而言并不重要

project

用法:project(<PROJECT-NAME>)

指定项目名称,CMake会自动把指定的名称存到PROJECT_NAME变量中

aux_source_directory

用法:aux_source_directory(<dir> <variable>)

把<dir>所指定的目录中的所有源代码文件添加到<variable>所指定的变量中

include_directories

用法:include_directories(dir1 [dir2 ...])

指定一个或多个包含目录,也就是头文件所在的目录。一般提供相对目录,也就是相对于CMakeLists.txt所在文件夹的目录。

link_directories

用法:link_directories(directory1 [directory2 ...])

指定一个或多个包含外部库的目录

link_libraries

用法:link_libraries([item1 [item2 ...])

指定一个或多个要连接的库,填写库的文件名

add_executable

用法:add_executable(<name> [source1] [source2 ...])

声明这个项目要输出的其中一个可执行文件,并且指定它的名称,以及对应的一个或多个源代码文件。

明白了这些函数的用法以后,就理解这个CMakeLists在做的事情了:

  • 指定最小 CMake 版本为3.15
  • 把当前目录(CMakeLists.txt)所在目录中所有源代码文件的名称存入 SRC_FILES 中
  • 指定额外的头文件(比如外部库的)的包含目录是当前目录下的 include 文件夹
  • 指定外部库所在的目录是当前目录下的 lib 文件夹
  • 指定要连接 libcurl 这个库,文件名是 libcurl.a
  • 声明要输出一个可执行文件,名称在 PROJECT_NAME 变量中,对应的源代码文件名称在 SRC_FILES

编译

写好配置文件后,把它放到源代码所在目录,在这个目录启动命令行执行cmake .,CMake会自动生成编译所需要的各种文件。然后我们再根据 对应的编译器,执行相关的编译操作。如 MinGW 在 Windows 上使用 mingw32-make指令。

如果在Windows上使用MinGW,CMake可能会报错找不到编译器,这是因为CMake在Windows上默认使用MSVC编译器,只需执行的时候加上参数, 也就是cmake -G "MinGW Makefiles" .就可以了。

这样,就可以编译一个不包含子项目,要连接外部库的程序了。顺带一提,如果不需要连接外部库,上述配置文件中和外部库相关的函数就都不需要了。


文章作者: LouisZ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LouisZ !
  目录