CMake学习笔记
CMake学习笔记
开始
介绍:
- CMake是一个高级编译配置工具,用于团队写作或多语言开发项目的编译工具,所有操作都通过编写编译CMakeLists.txt来完成操作.
- CMake可以进行编译构建处理大型的C/C++项目,本质是使用编译cmake生成makefile
- 官网:CMake
安装:
- Windows:通过官方网站,选择对应系统以及版本进行下载,下载地址:https://cmake.org/download/
- Linux:Linux系统下可以选择使用包管理器进行下载,也可以选择去官方网站进行下载- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- # ubuntu/debian
 sudo apt-get install cmake
 #centos
 sudo yum install cmake
 # fedora
 sudo dnf install cmake
 #arch linux
 sudo pacman -s cmake
- Mac os:Macos系统也可以通过官方网站进行下载,或者使用Homebrew进行安装- 1 - brew install cmake
小试牛刀:
- 新建一个文件夹 
- 创建一个main.cpp文件 - 1 
 2
 3
 4
 5
 6
 7- #include <iostream>
 int main (int argc, char *argv[]) {
 std::cout<<"Hello world"<<std::endl;
 return 0;
 }
- 平常我们可能会使用gdb,makefile来进行编译构建cpp文件生成可执行文件,这次我们学会使用cmake来进行编译生成makefile,然后进一步生成可执行文件 
- 创建一个CMakeLists.txt文件,并编辑内容 - 1 
 2
 3
 4
 5
 6
 7- cmake_minimum_required(VERSION 3.5)
 project(main)
 set(list main.cpp)
 add_executable(main ${list})
- 保存退出,在项目目录下输入以下命令 - 1 
 2
 3
 4
 5
 6
 7
 8- # 对当前项目目录的CMakeLists.txt进行编译构建
 cmake .
 # 对生成的makefile进行make,生成可执行文件
 make
 # 运行可执行文件
 ./main
CMake编译项目流程:
- 通过编写CMakeLists.txt文件,来进行编译构建项目
- 通过cmake命令生成对应的Makefile
- 通过make命令生成项目的可执行文件
CMake语法
语法基本原则
语法基本原则:
- 变量使用${}方式进行取值,在**IF控制语句中不需要使用${}**,而是直接使用变量名
- 指令(参数1 参数2...),参数使用小括号括起,参数之间使用空格或分号分开
- 使用#进行行注释
- 使用#[[]]形式进行块注释
- 指令是大小写无关的(指令写大小写都可),参数和变量是大小写相关的
注意事项:
- set(main main.cpp)可以写成set(main “main.cpp”),如果源文件名中含有空格,就必须要加双引号
- add_executable(hello main)后缀可以不写,它会自动找寻.c和.cpp文件,但是最好不要这样写,可能会出现文件冲突
CMake命令
cmake [options] [dir]:执行构建cmake工程命令
| 1 |  | 
**指令参数[options]**:
- -B:用于指定构建目录(指定build目录)
- -D:用于定义CMake变量
- -E:调用CMake内置命令的参数
- -G:用于指定生成器
- -S:用于指定源代码目录
常用变量:
- CMAKE_SOURCE_DIR:最顶层CMakeLists.txt所在目录
- CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists.txt所在路径
- PROJECT_SOURCE_DIR:工程根目录
- CMAKE_ARCHIVE_OUTPUT_DIRECTORY:静态库的输出目录
- CMAKE_LIBRARY_OUTPUT_DIRECTORY:动态库的输出目录
- CMAKE_RUNTIME_OUTPUT_DIRECTORY:可执行文件的输出目录
CMake判断语句
CMake判断语句:
| 1 |  | 
比较操作符:
- EQUAL:检查是否相等
- LESS:检查是否小于
- GREATER:检查是否大于
- LESS_EQUAL:检查是否小于或等于
- GREATER_EQUAL:检查是否大于或等于
- STREQUAL:检查字符串是否相等
- STRLESS:检查字符串是否小于(按字典顺序)
- STRGREATER:检查字符串是否大于(按字典顺序)
- EXISTS:检查文件或目录是否存在
- IS_DIRECTORY:检查是否是目录
- IS_SYMLINK:检查是否是符号链接
- IS_ABSOLUTE:检查路径是否是绝对路径
逻辑操作符:
- AND:逻辑与
- OR:逻辑或
- NOT:逻辑非
CMake循环语句
CMake循环语句:
- foreach:用于遍历列表中的每个元素或特定范围的值- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20- # 遍历s_value-e_value
 foreach(i s_value value1 ... e_value)
 <commands>
 endforeach()
 # 遍历列表遍历
 foreach(i IN LISTS <list_name>)
 <commands>
 endforeach()
 # 示例
 foreach(i 1 2 3 4)
 message(STATUS "${i}")
 endforeach()
 set(test 1 2 3 4)
 foreach(i IN LISTS test)
 message(STATUS "${i}")
 endforeach()
- while:用于在给定条件为真时重复执行命令- 1 
 2
 3- while(<condition>)
 <commands>
 endwhile()
CMake函数
CMake中定义函数:
| 1 |  | 
CMake提供常用函数:
PROJECT():
- 用来指定工程的名字、支持的语言以及版本号,默认支持所有语言
- 并且隐式定义了<projectname>_BINARY_DIR和<projectname>_SOURCE_DIR两个CMake变量,两个变量都指向当前的工作目录
- 但是工程名变化,隐式定义的两个变量也会随之更改,我们可以直接使用两个预定义的PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR进行代替使用
| 1 |  | 
CMAKE_MINIMUM_REQUIRED():设置所需的最低CMake版本
| 1 |  | 
SET():用来设置变量的值
| 1 |  | 
MESSAGE():向终端输出用户自定义信息
消息的一些类型:
- SEND_ERROR:产生错误,继续处理,跳过生成过程
- STATUS:输出用户自定义信息并添加前缀–
- FATAL_ERROR:立即终止所有cmake过程
- WARNING:发出警告,继续处理
| 1 |  | 
ADD_COMPILE_OPTIONS():添加编译参数
| 1 |  | 
ADD_SUBDIRECTORY():可以将指定的存放源文件的子目录加入工程,并在该子目录中执行CMakeLists.txt,并指定编译输出路径
| 1 |  | 
ADD_LIBRARY():创建一个库(静态库或动态库)
type:
- STATIC:静态库
- SHARED:动态库
| 1 |  | 
ADD_EXECUTABLE():生成可执行文件
| 1 |  | 
INSTALL():用于指定在安装时运行的规则,可以用来安装包括目标二进制、动态库、静态库以及文件、目录、脚本等到指定目录,用于执行make install命令下安装对应文件
type:
- TARGETS:目标二进制文件
- FILES:文件
- PROGAMS:非目标文件的可执行程序安装(比如脚本之类)
- DIRECTORY:文件夹
- SCRIPT:脚本文件
- CODE:代码
DESTINATION:
- 后面跟着绝对路径
- 后面跟着相对路径,相对路径默认会给你的路径添加CMAKE_INSTALL_PREFIX作为前缀(默认为/usr/local/),可以自己更改CMAKE_INSTALL_PREFIX的值
| 1 |  | 
AUX_SOURCE_DIRECTORY():用于查找指定目录下的源文件
| 1 |  | 
LINK_DIRECTORIES():在指定路径下寻找库文件
| 1 |  | 
FIND_LIBRARY():查找库文件路径
| 1 |  | 
LINK_LIBRARIES():链接静态库
| 1 |  | 
TARGET_LINK_LIBRARIES():链接动态库
| 1 |  | 
set_target_properties/SET_TARGET_PROPERTIES():设置目标属性,可以用来设置输出名称,对于动态库可以指定动态库版本和API版本
| 1 |  | 
静态/动态库
构建前准备:
- 创建工程目录
- 在根目录下创建一个CMakeLists.txt,并创建子目录src、include、lib和build
- 将源文件放在在src目录下
- 将源文件引用的头文件放入include目录下
| 1 |  | 
构建静态/动态库:
- 使用add_library函数创建库 
- 静态库:- 1 
 2- # 库名就是你要生成的静态库的名字,<source>...为源文件列表
 add_library(<库名> STATIC <source>...)
- 动态库:- 1 
 2- # 库名就是你要生成的动态库的名字,在linux中最终名字会为lib库名.so,<source>...为源文件列表
 add_library(<库名> SHARED <source>...)
编写CMakeLists:
| 1 |  | 
构建:
- 将以上步骤做好后 
- 进入到build目录进行输入 - 1 - cmake ..
- 然后在进行make 
- 在lib目录查看动态库是否生成成功 
构建同名动态库和静态库:
| 1 |  | 
设置动态库版本号:
| 1 |  | 
链接静态/动态库:
- 在项目中当我们需要依赖于第三方的静态或动态库时,就需要在CMakeLists.txt中将依赖库链接到项目中 
- 静态库:- 1 
 2- # 一般需要使用link_directories/find_library指定库文件所在目录或者查找库文件路径
 link_libraries(<库名/路径>)
- 动态库:- 1 
 2- # 一般需要使用link_directories/find_library指定库文件所在目录或者查找库文件路径
 target_link_libraries(<target> <库名/路径> [<库名/路径>...]])
工程创建
构建方式
概念:
- CMake的构建方式分为内部构建和外部构建
- 内部构建:就在工程目录下构建编译生成可执行文件,会产生很多临时文件,不方便清理,我们上面构建工程的方式就是内部构建
- 外部构建:会把项目构建编译生成的临时文件放在build目录中,不会对源文件有任何影响,**(建议使用)**
外部构建:
- 在工程目录下 - 创建build目录
- 进入到build目录
- 执行以下命令构建 - 1 
 2- # ..表示上级目录也就是工程目录
 cmake ..
注意:
通过外部构建方式构建项目,其隐式定义的<projectname>_BINARY_DIR是指向build目录的,<projectname>_SOURCE_DIR是指向源工程目录
工程规范
概念:
- 为了让我们的项目工程更规范,让其看起来更像一个工程
- 我们可以选择按以下后面的工程规范进行创建CMake工程
工程规范:
- bin目录:存放生成的可执行文件
- lib目录:存放生成的中间库文件(静态库输出目录)
- include目录:存放头文件
- src目录:存放源文件
- build目录:存放项目编译过程中产生的临时的中间文件
- thirdparty目录:存放依赖的第三方库的文件
- doc目录:用来存放项目的文档
- example目录:存放示例文件
- README.MD:项目自述文件
创建工程
工程创建:
- 在项目目录下创建CMakeLists.txt,还有创建src、include、doc、lib和bin目录 
- 将源代码放入src目录中,引用的头文件放入include目录下,将项目相关文档放入doc中 
- 在src中可以新建多个目录放置源文件,然后每个目录创建CMakeLists.txt 
- 示例目录结构如下: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- > tree
 .
 ├── bin
 ├── CMakeLists.txt
 ├── doc
 ├── include
 ├── lib
 └── src
 ├── hmod
 │ └── CMakeLists.txt
 └── yule
 └── CMakeLists.txt
编写顶层CMakeLists:
| 1 |  | 
次级CMakeLists:
| 1 |  | 
编译构建:
| 1 |  |