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

相关推荐
程序员沉梦听雨2 天前
【搜索引擎】Kibana使用指南
java·后端·学习笔记
死磕音视频3 天前
Gemini Notebook 入门:把公开 YouTube 教程变成可提问的学习笔记
学习笔记·youtube·gemini·notebooklm
行者-全栈开发5 天前
【鸿蒙心迹】三方库移植(二)——CMake 交叉编译与符号冲突排查实录(HarmonyOS 7.x)
harmonyos·cmake·交叉编译·三方库移植·ohos·符号冲突
宇宙无敌暴龙战士6665 天前
MySQL 8 库表操作学习笔记:SQL 基础、库表管理、约束与用户授权全流程
数据库·sql·mysql·学习笔记·后端开发
曲径海盗10 天前
【Python 学习第 41 天】for 循环
python·学习笔记·编程入门
骑着蜗牛撵大象32710 天前
大模型 SDK 编译就崩?用 CMakeLists 把 httplib、JSON 与 OpenSSL 装配成可复用的 ChatServer
android·java·c++·http·json·cmake·大模型sdk
曲径海盗11 天前
【Python 学习第 38 天】for 循环
python·学习笔记·编程入门
曲径海盗11 天前
【Python 学习第 40 天】for 循环
python·学习笔记·编程入门
曲径海盗12 天前
【Python 学习第 37 天】for 循环
python·学习笔记·编程入门
曲径海盗12 天前
【Python 学习第 39 天】for 循环
python·学习笔记·编程入门