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 cmakeMac 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
7cmake_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
3while(<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 | |