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 |
|