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 保姆级教程(下)

参考3:CMake 保姆级教程---bilibili视频【C/C++】

参考4:完全入门CMake语法与CMakeList编写

相关推荐
四谎真好看1 天前
Java 黑马程序员学习笔记(进阶篇28)
java·笔记·学习·学习笔记
charlee441 天前
CMake构建学习笔记26-OpenBLAS库的构建
多线程·cmake·openblas·blas/lapack
大佬,救命!!!1 天前
最新的python3.14版本下仿真环境配置深度学习机器学习相关
开发语言·人工智能·python·深度学习·机器学习·学习笔记·环境配置
charlee442 天前
CMake构建学习笔记30-Ceres Solver库的构建
静态库·非线性优化·cmake·buildcppdependency·ceres solver
大佬,救命!!!2 天前
C++函数式策略模式代码练习
开发语言·c++·学习笔记·学习方法·策略模式·迭代加深·多文件编译
charlee443 天前
CMake构建学习笔记28-gmp&mpfr库的构建
cmake
charlee443 天前
CMake构建学习笔记27-初步完成C&C++自动化构建工具
跨平台·cmake·构建·依赖管理
四谎真好看7 天前
Java 黑马程序员学习笔记(进阶篇27)
java·开发语言·笔记·学习·学习笔记