CMake 的详细定义网上都有,这里不再表述。简而言之,CMake 就是一个高级的跨平台的编译配置工具,专门用于处理大型的 C/C++ 项目,当然也可以用来编译单个的 C/C++ 文件(杀鸡用牛刀而已)。最常用的就是使用 CMake 输出 Makefile 文件或者 Project 文件,分别对应 Linux 上的编译和 Windows Visual Studio 上的编译。
在 CentOS 上可以直接使用 yum 安装,但安装的 CMake 版本比较老旧,本文介绍使用源码安装,但需要先安装 OpenSSL 依赖项。这里以 cmake-3.19.8 为例说明源码安装的过程:
# 先安装 openssl,需要安装 nasm,否则编译出错
# 也可以直接 yum 安装:
# yum install openssl
$ tar zxf openssl-1.1.1l.tar.gz
$ cd openssl-1.1.1l
$ ./config --prefix=$HOME/.local # 指定安装目录
$ make -j4 # 4线程编译,加快速度
$ make install
# 安装 cmake-3.19.8
$ tar zxf cmake-3.19.8.tar.gz
$ cd cmake-3.19.8
$ ./configure --prefix=$HOME/.local # 指定安装目录
$ make -j4 # 4线程编译,加快速度
$ make install
说明:
--prefix
用于指定安装目录,默认安装到 /usr/local
目录中,安装时需要 root 权限。make -j4
用于指定多线程编译,默认单线程编译比较耗时。一般 CMake 的使用步骤:
CMake 的所有的语句都写在 CMakeLists.txt 文件中,且必须要是这个文件名,CMake 命令会根据 CMakeLists.txt 中的语法构建编译规则,生成 Makefile 文件。可以在 CMakeLists.txt 中包含其他的 cmake 文件,被包含的文件名可以自定义,一般以 .cmake 结尾。
本章介绍一些常用的 CMake 语法,主要用于编译可执行程序,有关库文件的语法会在后面章节中介绍。
可以用来指定工程名和支持的语言,默认支持所有语言,如
# 指定工程名字,并支持所有语言(建议使用)
project(hello)
# 指定工程名字,并支持 C++ 语言
project(hello CXX)
# 指定工程名字,并支持 C/C++ 语言
project(hello C CXX)
该定义指定了两个 cmake 变量
表示生成的二进制文件的目录;
表示源代码目录。可以使用 message
关键字输出这两个变量
message(STATUS "binary dir ${hello_BINARY_DIR}")
message(STATUS "source dir ${hello_SOURCE_DIR}")
一般都会是当前编译目录,但这两个变量在外部编译时会有区别,后面会介绍外部编译。但这样会有一个问题:如果改了工程名,这两个变量也会被改变。
解决方案:可以使用两个预定义的变量 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
来代替上面的两个变量,这两个变量就代表当前工程的二进制目录和源码目录。
定义 CMake 最低支持的版本,低于次版本则会报错,如最低支持3.5以上的版本
cmake_minimum_required(VERSION 3.5)
用于显示指定变量,类似于变量赋值。如 set(src_list main.cc)
表示 src_list 变量包含了 main.cc 文件。多个文件使用空格分开,如
set(src_list main.cc)
set(src_list main.cc util.cc test.cc)
还可以设置其他信息,如 C++ 支持的版本
set(CMAKE_CXX_STANDARD 11) # C++11
set(CMAKE_CXX_STANDARD 14) # C++14
向终端用户输出自定义信息,主要包含 3 种信息:
message(STATUS "binary dir ${hello_BINARY_DIR}")
message(STATUS "source dir ${hello_SOURCE_DIR}")
# 输出内容,会有 -- 前缀
-- binary dir /home/mayw/tmp/cmake_test
-- source dir /home/mayw/tmp/cmake_test
查找目录中的所有源文件,并赋值给指定变量,如
# 查找当前目录下的所有源文件,将名称保存到 src_list 变量中,可以使用 ${src_list} 进行引用
aux_source_directory(. src_list)
这样便可以不用逐个添加源文件了,详细信息可以参考官网 aux_source_directory 。
包含其他的 cmake 文件,被包含的文件一般以 cmake结尾,如
include(../cmake/common.cmake)
添加定义信息,类似于 gcc/g++ 中的 CFLAGS 和 宏定义,如
add_definitions(-g -Wall -O3)
# -D开表示宏定义
if(MSVC)
add_definitions(-D_WIN32_WINNT=0x600)
endif()
添加头文件目录,相当于 gcc/g++ 命令的 -I
参数的功能,如
# 类似 gcc/g++ 中的 -I 选项
include_directories(../include)
也可以添加一个 CPLUS_INCLUDE_PATH
环境变量,并将目录追加到环境变量中,但 CMake 一般不这样用。
添加库文件目录,相当于 gcc/g++ 命令的 -L
参数的功能,如
# 类似 gcc/g++ 中的 -L 选项
include_directories(../lib ../lib64)
也可以添加一个 LD_LIBRARY_PATH
环境变量,并将目录追加到环境变量中。Linux 中一般出现找不到库文件的问题,就会追加路径到次环境变量中。
链接库文件到程序中,相当于 gcc/g++ 命令的 -l
参数的功能,如
# 类似 gcc/g++ 中的 -l 选项
target_link_libraries(hello mylib)
一般都是与 add_executable 配合使用,紧跟其后。
指定生成的可执行文件,如
set(src_list main.cc)
add_executable(hello ${src_list})
# 生成可执行文件 hello,源文件读取变量 src_list 里的内容,也就是 main.cc,也可以直接写为
add_executable(hello main.cc)
# 若要链接 libmylib.so,可以添加
target_link_libraries(hello mylib)
本例可以将 cmake 文件直接简化为三行代码
project(hello)
add_executable(hello main.cc)
target_link_libraries(hello mylib)
注意:
${}
方式取值,但是在 if
控制语句中是直接使用变量名;add_executable(hello main.cc util.cc)
add_executable
和 ADD_EXECUTABLE
是一样的,但 参数和变量是大小写相关的。google 规范中全部使用小写指令和变量,可视项目情况而定,与项目保持一致就行。语法注意事项
set(src_list main.cc)
可以写成 set(src_list "main.cc")
,这两种写法是一样的,但如果文件名中有空格、中文或其他特殊字符,则必须要加双引号;add_executable(hello main.cc)
后缀名可以不写,CMake 会自动去找 .c 和 .cpp 的源文件文件,但最好明确指定源文件的后缀名。