CMake简介
CMake就是一个高级的跨平台的编译配置工具,专门用于处理大型的C/C++项目,最常用的额就是使用CMake输出Makefile文件或者Project文件,分别对应Linux上编译和VS上的编译。
CMake安装
1.Centos中CMake安装
在Centos上可以直接使用yum安装,但安装的CMake版本比较老旧,现在介绍使用源码安装,但是需要先安装OpenSSL依赖项,这里以cmake-3.19.8为例说明源码安装的过程。
源码下载地址:https://cmake.org/download/,可以自行下载最新版本
#先安装openssl,需要安装nasm,否则编译出错
#直接使用yum安装
#yun install openssl
#安装cmake-3.19.8
$ tar zxf cmake-3.19.8.tar.gz
$ cd cmake-3.19.8
$ ./configure --prefix=$HOME/.local #制定安装目录
$ make -j4
$ make install
说明:
--prefix
用于制定安装目录,默认安装到/usr/local
目录中,安装时需要root权限。make -j4
用于制定多线程编译,默认单线程编译比较耗时。
2.Ubuntu中CMake安装
$ sudo apt-get install update
$ sudo apt-get install cmake
CMake使用步骤
一般CMake的使用步骤:
- 编写源码
- 编写CMakeLists.txt
- 使用cmake命令生成Makefile文件
- 使用make命令编译
- 运行生成的可执行文件
CMake的所有的语句都写在CMakeLists.txt文件中,且必须要是这个文件名,CMake命令会根据CMakeLists.txt中的语法构建编译规则,生成Makefile文件。可以在CMakeLists.txt中包含其他cmake文件,被包含的文件名可以自定义,一般以.cmake结尾。
CMake语法介绍
介绍一些常用的CMake语法,主要用于编译可执行程序,有关库文件的语法会在后面章节介绍。
- project关键字
可以用来指定工程名和支持的语言,默认支持所有语言,如:
# 指定工程名称,并支持所有语言(建议使用)
project(hello)
# 指定工程名,并支持C++语言
project(hello CXX)
# 指定工程名字,并支持C/C++语言
project(hello C CXX)
该定义指定了两个cmake变量
<projectname_BINARY_DIR>
表示生成的二进制文件的目录;<projectname_SOURCE_DIR>
表示源代码目录。
可以使用message
关键字输出这两个变量:
message(STATUS "binary dir ${hello_BINARY_DIR}")
message(STATUS "source dir ${hello_SOURCE_DIR}")
一般都会是当前编译目录,但这两个变量在外部编译时会有区别,后面会介绍外部编译。但这样会有一个问题:如果改了工程名,这两个变量也会被改变。
解决方案:可以使用两个预定义的变量 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
来代替上面的两个变量,这两个变量就代表当前工程的二进制目录和源码目录。
· cmake_minimum_required关键字
定义CMake最低支持的版本,低于此版本则会出错,如最低支持3.5以上版本
cmake_minimum_required(VERSION 3.5)
· set关键字
用于显示指定变量,类似于变量赋值。如 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
· message关键字
向终端用户输出自定义信息,主要包含3中信息
- SEND_ERROR 生产错误,生成过程被跳过;
- STATUS 输出前缀为 - 的信息
- FATAL_ERROR 立即终止所有cmake过程。
message(STATUS “binary dir ${hello_BINARY_DIR}”)
message(STATUS “source dir ${hello_SOURCE_DIR}”)
#输出内容,会有 – 前缀
– binary dir /home/cheng/tmp/cmake_test
– source dir /home/.cheng/tmp/cmake_test
· aux_source_directory关键字
查找目录中的所有源文件,并赋值给指定变量,如
# 查找当前目录下的所有源文件,将名称保存到src_list变量中,可以使用${src_list} 进行引用
aux_source_directory(. src_list)
这样便可以不用逐个添加源文件了。
· include 关键字
包含其他的cmake文件,被包含的文件一般以cmake结尾,如
include(../cmake/common.cmake)
· add_definitions关键字
添加定义信息,类似于gcc/g++中的CFLAGS和宏定义,如
add_definitions(-g -Wall -O3)
# -D开表示宏定义
if(MSVC)
add_definitions(_D_WIN32_WINNT=0x600)
endif()
· include_directories关键字
添加头文件目录,相当于gcc/g++命令中的 -I
参数的功能,如
# 类似gcc/g++中的-I选项
include_directories(../include)
也可以添加一个 CPLUS_INCLUDE_PATH
环境变量,并将目录追加到环境变量中,但CMake一般不这样用。
· link_directories关键字
添加库文件目录,相当于gcc/g++ 命令的 -L
参数的功能,如
# 类似gcc/g++ 中的-L选项
link_directories(../lib ../lib64)
也可以添加一个 LD_LIBRARY_PATH
环境变量,并将目录追加到环境变量中。Linux中一般出现找不到库文件的问题,就会追加路径到此环境变量中。
· target_link_libraries 关键字
链接库文件到程序中,相当于gcc/g++ 命令的 -l
参数的功能,如
# 类似gcc/g++ 中的 -l 选项
target_link_libraries(hello mylib)
一般都是与add_executable 配合使用,紧跟其后。
· 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)
注意:
- 工程名hello和生成的可执行文件 hello 没有任何关系,可以相同,也可以不相同。
- 这里只介绍了生成可执行程序用到的语法,生成和链接库文件的语法会在后面进行介绍。
CMake 语法的基本原则
- 变量使用
${}
方式取值,但是在if
控制语句中是直接使用变量名; - 指令参数使用括号,参数之间使用空格或者分号分开,如
add_executable(hello main.cc util.cc)
- 指令是大小写无关的,即
add_executable
和ADD_EXECUTABLE
是一样的,但 参数和变量是大小写相关的。goole规范中全部使用小写指令和变量,可视项目情况而定,与项目保持一致就行。
语法注意事项
set(src_list main.cc)
可以写成set(src_list "main.cc")
,这两种写法是一样的,但如果文件名中有空格。中文或者其他特殊字符,则必须要加双引号;add_executable(hello main.cc)
后缀名可以不写,CMake会自动去找.c 和 .cpp 的源文件,但最好明确指定源文件的后缀名。
CMake 外部构建
CMake内部构建,就是在当前工程目录中进行编译,但缺点是会产生很多的临时编译文件,容易污染工程,不方便清理。而外部构建就是编译生成的文件统一放在一个目录中,不会对源代码工程有任何影响,清理也只需要删除这个编译目录。所以强烈推荐使用外部构建,外部构建的一般步骤如下:
# 1.创建并进入编译目录
# 在项目根目录中新建一个 build/release/debug 目录,cmake生成的中间文件都会放在此目录
$ mkdir build
$ cd build/
# 2. 进行cmake编译
$ cmake ..
$ cmake --build .
# 3.编译完成后安装
$ cmake --install .
# 4.更简单的是直接在cmake ..之后执行make,这与 2,3等效
$ cmake ..
$ make && make install
外部构建时有两个变量需要注意:
PROJECT_BINARY_DIR
编译路径,也就是当前build目录;PROJECT_SOURCE_DIR
还是工程中的源码目录。
它们在内部构建的工程中是一样,但在外部构建的工程中就不一样了。
常用 cmake 编译选项
# 指定安装路径,这是最常用的选项,类似 ./configure --prefix
-DCMAKE_INSTALL_PREFIX=$HOME/.local
# 指定第三方库的路径,一般供find_package|find_library|find_program 等命令搜索,
# 若第三方库安装在非标准目录中,则需要用此参数指定路径,也可以是一个分号分隔的路径列表,
# cmake 会在指定的路径中查找第三方库的cmake文件,一般放在lib|lib64中的cmake目录中
-DCMAKE_PREFIX_PATH=$HOME/.local/grpc
-DCMAKE_PREFIX_PATH="/tmp;/tmp/grpc"
# 指定编译类型, Debug | Release,默认编译为Release版本
-DCMAKE_BUILD_TYPE=Debug|Release
# 编译程序,等同于make命令
--build <dir>
# 安装程序, 等同于make install 命令
--install <dir>
# 指定编译平台,可以使用 cmake --help 查看本机支持的编译平台,一般在Windows上需要指定
-G "Visual Studio 14 2015 Win64|MinGW Makefiles|..."
以上已-D
开头的选项也可以在CMakeLists.txt 文件中使用set或list命令添加,如下:
set(CMAKE_PREFIX_PATH "<YOUR_ADDITIONAL_SEARCH_PATH>")
list(APPEND CMAKE_PREFIX_PATH "<YOUR_ADDITIONAL_SEARCH_PATH>")
一般使用set命令就行,如下实例:
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_PREFIX_PATH "/opt/local/grpc")
set(CMAKE_PREFIX_PATH "/opt/local/libevent") #多个搜索路径可以写多条