2.2 makefile与CMake
我们在Windows机器上编译和调试C/C++程序时可以使用Visual Studio,在Linux机器上编译 C/C++程序时最终使用的是 gcc/g++,当然,在调试时使用 gdb。我们一般使用makefile文件组织大型C/C++或者含有多个C/C++文件的项目,有人认为makefile不太方便,于是发明了CMake。CMake将含有CMake指令的文件生成makefile文件,含有CMake指令的文件的名称一般是CMakeLists.txt,使用CMake是在实际开发中组织和管理C/C++项目的常用方式,也适用于大多数C/C++开源项目。
对 Linux 下的一些 C/C++开源项目,执行 configure 命令后一般会生成CMakeLists.txt文件,接着执行CMake命令会生成makefile文件,然后执行make命令利用gcc/g++对项目进行编译。
对于 Windows 系统,可以直接从 CMake 官网下载相应的安装包安装 CMake;对于Linux系统,以CentOS为例,执行如下命令即可安装CMake:
安装好CMake之后需要编写CMakeList.txt。CMakeLists.txt的样例如下。
样例一:
样例二:
下面对以上代码中的一些内容进行解释。
(1)首行的 cmake_minimum_required 指令指定支持该 CMakeLists.txt 文件的 CMake最低版本号。
(2)project 指令指定该项目的名称,注意,项目名称不是最终生成的二进制程序名,在一个项目下面可以生成多个二进制程序名。
(3)set定义和设置各种变量,set括号后的第1个名称是定义的变量名称,其后是变量的值,例如上述文件定义了CMAKE_CXX_FLAGS、net_srcs、mysqlapi_src、chatserver_srcs、fileserver_srcs、imgserver_srcs共6个变量,之后可以使用${变量名}引用这些变量。这些变量可以是内置的变量,例如CMAKE_CXX_FLAGS指定g++编译选项,EXECUTABLE_OUTPUT_PATH 指定输出的二进制文件路径,也可以是自定义变量如 chatserver_srcs、fileserver_srcs等。
(4)CMake使用aux_source_directory指令指定源码目录,使用include_directories指令指定include目录,使用link_directories指定lib目录。
(5)CMake使用指令指定生成的动态库或静态库的名称,格式如下:
例如:
我们不需要写全 libhello.so 或 libhello.a,只需填写 hello 即可,CMake 会自动生成libhello.X。类型有如下三种。
◎ SHARED:动态库(扩展名为.so)。
◎ STATIC:静态库(扩展名为.a)。
◎ MODULE:在使用dyld的系统中有效,若不支持dyld,则被当作SHARED对待。
EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他组件依赖或者手工构建。如下命令会生成一个 libkafkawrapper.so文件,且libkafkawrapper.so文件的生成依赖librdkafka.so、librdkafka++.so、libcrypto.so、libssl.so这4个库:
(6)TARGET_LINK_LIBRARIES指定生成的二进制文件依赖的其他库,上文已有介绍。
编写完CMakeLists.txt文件后,进入CMakeLists.txt文件所在的目录,依次执行如下命令即可生成最终的二进制文件:
CMakeLists.txt也支持递归执行,先执行父目录的CMakeLists.txt 文件,再执行子目录的CMakeLists.txt文件。
若想了解CMake的更多信息,则可以参考CMake官网。
接下来看看如何利用CMake生成Visual Studio工程文件。
对于习惯了Visual Studio强大的管理项目、编码和调试功能的读者来说,在Linux下使用gcc/g++编译和使用gdb调试是痛苦的事情。对于大多数C/C++开源项目,如果我们不在意 Windows和 Linux在一些底层 API接口上的使用差别,想熟悉该项目的执行脉络和原理,则在Windows上使用Visual Studio调试该项目也未尝不可。凡是可以使用CMake编译的Linux程序(即提供了CMakeLists.txt文件),我们都可以利用CMake生成Windows上的Visual Studio工程文件。
这里以著名的开源网络库 libuv 为例。从 libuv 官网下载最新的 libuv 的源码,得到libuv-1.x.zip文件并解压。笔者在自己的机器上将代码解压缩至E:\libuv-1.x,在解压缩后的目录中确实存在一个CMakeLists.txt文件,如下图所示。
启动Windows机器上的CMake图形化工具(cmake-gui),按下图所示进行设置。
设置完成之后,单击界面上的 Configure 按钮,会提示 vsprojects 目录不存在,提示是否创建,单击Yes按钮进行创建。
如果在机器上安装了多个版本的Visual Studio,则接下来会弹出对话框让我们选择要生成的工程文件对应的Visual Studio版本号,可以根据自己的实际情况按需选择,这里选择Visual Studio 16 2019。
单击Finish按钮后开始启动CMake的检测和配置工作。等待一会儿,在CMake底部的输出框中提示“Configuring Done”,表示配置工作已经完成。
接下来单击 Generate按钮即可生成所选版本的 Visual Studio 工程文件,生成的文件位于vsprojects目录下。
我们可以在界面上单击Open Project按钮直接打开工程文件,也可以找到对应目录下的libuv.sln文件并打开。打开后的界面如下图所示。
接下来就可以使用Visual Studio对libuv进行编译和调试了。
再次深入回顾上述过程:单击Configure按钮之后,和在Linux机器上执行cmake命令一样,CMake也在检测所在的系统环境是否匹配在 CMakeLists.txt中定义的各种环境,其本质上是生成了一份可以在 Windows 机器上编译和运行的代码(也就是说该源码支持在Windows机器上运行)。因此,对于很多虽然提供了CMakeLists.txt文件但并不支持在Windows机器上运行的Linux工程,虽然利用上述方法也能最终生成Visual Studio工程文件,但这些文件并不能直接在Windows机器上无错地编译和调试。
由于不同的 CMake 版本支持的 CMakeLists.txt 中的语法可能略有差别,有些 CMakeLists.txt 文件在使用 configure 方法时可能会产生一些错误,所以需要做些修改才能通过。