文章目录
- 一、前言
- 二、一些基本概念
- 三、常用基本命令
-
- [1、CMakeLists.txt文件通过 # 注释行,通过 #[[内容]] 注释块](# 注释行,通过 #[[内容]] 注释块)
- 2、指定使用的本地cmak工具最低版本
- 3、定义工程名称,还可指定版本、描述、URL、支持的语言
- 4、设置C++语言标准,默认使用C++11标准
-
- [4.1 设置标准版本](#4.1 设置标准版本)
- [4.2 版本支持与否的处理](#4.2 版本支持与否的处理)
- [4.3 C++语言扩展的开关](#4.3 C++语言扩展的开关)
- 5、定义"可执行程序"输出及名字,链接若干源文件
-
- [5.1 多个源文件可用空格或分号隔开,也可用变量存储源文件名](#5.1 多个源文件可用空格或分号隔开,也可用变量存储源文件名)
- [5.2 使用变量(默认字符串类型)存储多个源文件名](#5.2 使用变量(默认字符串类型)存储多个源文件名)
- 6、制作动态/静态库:动态库有可执行权限,静态库没有可执行权限
- 7、设置可执行文件/库的输出路径,若路径不存在自动生成
-
- [7.1 指定---可执行文件输出路径](#7.1 指定—可执行文件输出路径)
- [7.1 指定---库输出路径](#7.1 指定—库输出路径)
- 8、搜索文件(不必一一指定源文件)
-
- [8.1 aux_source_directory(路径 变量名)](#8.1 aux_source_directory(路径 变量名))
- [8.2 file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径及类型)](#8.2 file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径及类型))
- 9、变量操作
-
- [9.1 字符串拼接------会覆盖原本变量字符串](#9.1 字符串拼接——会覆盖原本变量字符串)
- [9.2 字符串追加------不会覆盖](#9.2 字符串追加——不会覆盖)
- [9.3 字符串移除](#9.3 字符串移除)
- [9.4 list命令的其它功能](#9.4 list命令的其它功能)
- 10、指定头文件路径
- 11、链接三方库(静态、动态)
-
- [11.1 静态库的链接------指定库的路径和库名](#11.1 静态库的链接——指定库的路径和库名)
- [11.2 动态库的链接------指定库的路径和库名,链接动态库的语句在生成可执行程序/库之后](#11.2 动态库的链接——指定库的路径和库名,链接动态库的语句在生成可执行程序/库之后)
- 12、日志------调试命令message,可以打印变量值,默认为STATUS等级
- 13、自定义宏------add_definitions
- 14、定义可配置项
- 15、条件语句
-
- [15.1 单个分支:如果ENABKE_DEBUG为ON,则定义调试宏](#15.1 单个分支:如果ENABKE_DEBUG为ON,则定义调试宏)
- [15.2 多个分支:根据系统类型添加不同的预定义宏](#15.2 多个分支:根据系统类型添加不同的预定义宏)
- 16、CMake嵌套
- 参考资料
一、前言
- 个人学习、工作自用笔记,若有错误请看参考文档与视频
二、一些基本概念
1、cmake
- cmake是一个项目构建工具,可以跨平台,makefile写起来繁琐,依赖于系统。
- 可以通过命令行、可以通过GUI
2、列表项编译工具链toolchain
- 预处理器、编译器、汇编器、链接器
2.1 预处理器
- 头文件展开、宏替换、去除注释
2.2 编译器(gcc/g++)
- 将源文件编译为汇编文件(词法/语法/语义分析、目标代码生成)
2.3 汇编器
- 得到二进制文件(windows系统下为.obj文件,linux下为.o文件)
2.4 链接器
- 将多个二进制文件链接,生成一个可执行程序或动态/静态链接库
3、编译/项目构建
3.1 少量文件
- 通过gcc/g++命令将源代码编译为可执行程序或库
3.2 大量文件结构复杂
- 编写Makefile文件,填写若干指令,告诉编译器如何编译文件,使用批处理命令make执行编译
3.3 大量文件结构复杂(不依赖于平台)
- 编写CMakeLists.txt,使用cmake命令生成Makefile等一系列文件,后续步骤如3.2所示
4、构建过程
- FirsetStep: cmake CMakeLists.txt文件所在路径
- SecondStep: make
5、库与进程
- 动态库在内存中有且仅有一份,且不属于某个进程
6、版本发布
- 版本发布包括:include头文件+静态/动态库;
- 因为库为二进制,所以需要提供头文件,其为库文件的接口与说明
7、库链接的传递性
- 库链接具有传递性
三、常用基本命令
1、CMakeLists.txt文件通过 # 注释行,通过 #[[内容]] 注释块
2、指定使用的本地cmak工具最低版本
cmake_minimum_required(3.16)
3、定义工程名称,还可指定版本、描述、URL、支持的语言
project(qgis v1.0)
4、设置C++语言标准,默认使用C++11标准
4.1 设置标准版本
set(CMAKE_CXX_STANDARD 17)
- 也可以在执行cmake命令的时候,设置CMAKE_CXX_STANDARD宏来指定C++标准
- cmake CMakeLists.txt文件所在路径 -DCMAKE_CXX_STANDARD=11
- -D表示设置宏的值
4.2 版本支持与否的处理
- 当编译器不支持指定的C++标准版本时,若将该变量设为ON,CMake将报错并终止构建过程
- 若将该变量设为OFF,CMake将自动降级到编译器支持的最接近的C++标准版本
set(CMAKE_CXX_STANDARD_REQUIRED ON)
4.3 C++语言扩展的开关
- 若设为OFF,可确保项目遵循C++标准,具有更好的可移植性;
- 设为ON,则允许使用编译器特定的C++语言扩展
set(CMAKE_CXX_EXTENSIONS OFF)
5、定义"可执行程序"输出及名字,链接若干源文件
5.1 多个源文件可用空格或分号隔开,也可用变量存储源文件名
add_executable(qgis a.cpp b.app)
5.2 使用变量(默认字符串类型)存储多个源文件名
-
使用固定语法${变量名}取值
set(SRC a.cpp b.cpp)
add_executable(qgis ${SRC})
6、制作动态/静态库:动态库有可执行权限,静态库没有可执行权限
-
库全名的组成:lib+库名+.后缀
-
下方命令生成libqgis.a或libqgis.so文件(Linux)
-
若未指定库类型,默认生成静态库文件
add_library(库名 STATIC {SRC}) add_library(库名 SHARED {SRC})
7、设置可执行文件/库的输出路径,若路径不存在自动生成
7.1 指定---可执行文件输出路径
- EXECUTABLE_OUTPUT_PATH为cmake自带的指定可执行文件/动态库输出路径的变量
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
7.1 指定---库输出路径
- EXECUTABLE_OUTPUT_PATH为cmake自带的指定静态/动态库输出路径的变量
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
8、搜索文件(不必一一指定源文件)
8.1 aux_source_directory(路径 变量名)
-
PROJECT_SOURCE_DIR为项目的绝对路径,CMAKE_CURRENT_SOURCE_DIR为CMakeLists.txt所在路径
aux_source_directory({PROJECT_SOURCE_DIR}/src SRC_LIST) aux_source_directory({CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(qgis ${SRC_LIST})
8.2 file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径及类型)
-
指定搜索.cpp后缀文件
file(GLOB SRC_LIST ${PROJECT_SOURCE_DIR}/src/*.cpp) -
递归搜索文件夹中的文件
file(GLOB_RECURSE SRC_LIST {PROJECT_SOURCE_DIR}/src/*.cpp) add_executable(qgis {SRC_LIST})
9、变量操作
9.1 字符串拼接------会覆盖原本变量字符串
- 使用set拼接两个字符串变量(源文件分布在多个目录下,使用file读取多个字符串)
set(变量名 ${变量名1} ${变量名2} ...)
9.2 字符串追加------不会覆盖
- 使用list对变量追加字符串(拼接),list就是变量
list(APPEND list名 ${变量名1} ${变量名2} ...)
9.3 字符串移除
- 多个字符串拼接后会在底层维护字符串之间的分隔符(;),规范字符串的移除
list(REMOVE_ITEM list名 字符串或${变量名1})
9.4 list命令的其它功能
- 获取list的长度
list(LENGTH list名 存储长度的变量名) - 获取列表中指定索引值的元素,可以指定多个索引
- 索引从0开始,从前往后;也可以为负数,从后往前
list(GET list名 索引1 索引2) - 将列表中的字符串用连接符(字符串)连接起来,组成一个字符串
list(JOIN list名 连接符 新创建的字符串变量名) - 查找列表中是否存在指定的元素,若未找到,返回负一
list(FIND list名 字符串或变量名 新创建的变量名) - 指定位置插入若干元素
list(INSERT list名 索引 若干字符串或变量名) - 0索引位置插入若干元素
list(PREPEND list名 索引 若干字符串或变量名) - 移除列表最后一个元素
list(POP_BACK list名 弹出元素变量名(可选)) - 移除列表最后一个元素
list(POP_FRONT list名 弹出元素变量名(可选)) - 移除列表中指定索引元素
list(REMOVE_AT list名 索引1 索引2 ...) - 移除列表中的重复元素
list(REMOVE_DUPLICATES list名) - 翻转列表
list(REVERSE list名) - 列表排序
- 排序方法COMPARE:STRING|FILE_BASENAME|NATURAL
- 大小写敏感CASE:SENSITIVE|INSENSITIVE
- 排序顺序ORDER:ASCENDING|DESCENDING
list(SORT list名 STRING SENSITIVE ASCENDING)
10、指定头文件路径
- 指定头文件路径后,源文件include头文件时只写文件名.h即可,不必填写全路径
include_directories(${PROJECT_SOURCE_DIR}/include)
11、链接三方库(静态、动态)
- 系统库直接指定库的名字即可,因为系统知道其位置;第三方库需要告诉当前项目库的路径
- 若三方库为静态库,编译会将其打包到可执行文件;若三方库为动态库,后续部署项目,需要拷贝动态库并设置环境变量
- link_directories设置库的查询位置
- 实际link_libraries和target_link_libraries均可链接动态库和静态库,推荐后者
11.1 静态库的链接------指定库的路径和库名
link_directories(${PROJECT_SOURCE_DIR}/lib)
link_libraries(库名1 库名1 ......)
11.2 动态库的链接------指定库的路径和库名,链接动态库的语句在生成可执行程序/库之后
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_executable(qgis ${SRC})
target_link_libraries(target(可执行文件/库/源文件) 权限PRIVATE/PUBLIC/INTERFACE(可省略,默认PUBLIC) 库名)
12、日志------调试命令message,可以打印变量值,默认为STATUS等级
- 消息类型:STATUS|WARNING|AUTHOR_WARNING|SEND_ERROR|FATAL_ERROR
- STATUS:非重要消息
- WARNING:CMake警告,会继续执行
- AUTHOR_WARNING:CMake重要警告(dev),会继续执行
- SEND_ERROR:CMake错误,继续执行,但是会跳过生成的步骤
- FINAL_ERROR:CMake致命错误,终止所有处理过程
message(消息类型 "输出字符串")
13、自定义宏------add_definitions
- 通过在代码中定义宏,控制测试代码是否生效(#ifdef 宏 测试语句 #endif)
- 可以不在代码中定义宏,在gcc/g++命令中指定宏:例如指定DEBUG宏(g++ test.cpp -DDEBUG -o app)
- 在CMake中也可以做类似的事情,命令为add_definitions,宏名称前加-D
add_definitions(-DDEBUG_OUTPUT)
14、定义可配置项
- 下列命令定义了一个名为ENABKE_DEBUG的可配置选项,为布尔型变量
- 第二个参数是对配置项的描述,第三个为变量的值,默认为ON
option(ENABKE_DEBUG "Enable debug output" ON)
15、条件语句
15.1 单个分支:如果ENABKE_DEBUG为ON,则定义调试宏
-
可在执行CMake命令时候,通过cmake -DDEBUG_DEBUG=OFF 关闭宏,不输出调试语句
if(ENABLE_DEBUG)
add_definitions(-DDEBUG_OUTPUT)
endif()
15.2 多个分支:根据系统类型添加不同的预定义宏
if(WIN32)
# 针对windows系统设置宏
add_definitions(-DWINDOWS_VERSION)
elseif(UNIX)
# 针对类Unix系统设置宏
else()
# 其它系统:报错
message(FINAL_ERROR, "UnKnown operating system")
endif()
16、CMake嵌套
- source_dir为子节点(模块)对应的目录
- 主目录含一个父CMakeLists.txt文件,每个模块含一个子CMakeLists.txt文件
- 通过以下命令在父文件中添加子文件目录
add_subdirectory(source_dir)
参考资料
参考1:CMake 保姆级教程(上)
参考2:CMake 保姆级教程(下)