当前位置: 首页 > article >正文

Cmkae外部依赖管理

文章目录

  • 一、cmake依赖管理介绍
  • 二、源码依管理
    • 1. `FetchContent`
      • 与find_package进行集成
    • 2. CPM
    • 3. git submodule
    • 附加: address_sanitizer 和 undefined sanitizer

一、cmake依赖管理介绍

在这里插入图片描述

CMake 是跨平台的构建系统,支持 C/C++、Objective-C、Fortran 等多种语言。CMake 提供了丰富的依赖管理功能,可以帮助开发人员轻松地管理第三方库的依赖关系。

CMake 的依赖管理功能主要包括以下几点:

  • 支持多种依赖获取方式:CMake 支持 Git Clone、下载源码压缩包等多种方式获取第三方库。
  • 支持重复依赖处理:CMake 可以自动处理依赖树中存在的重复依赖。
  • 支持第三方库的 Find 脚本:CMake 官方为许多常用的第三方库提供了 Find 脚本,可以帮助开发人员快速地获取和配置这些库。

CMake 的依赖管理功能可以分为两种类型:

  • 源码依赖:这种依赖是指第三方库的源代码。CMake 可以使用 Git Clone 或下载源码压缩包的方式获取第三方库的源代码。
  • 二进制依赖:这种依赖是指第三方库的二进制文件。CMake 可以使用第三方库的包管理器(例如 Conda 或 Homebrew)来获取第三方库的二进制文件。

今天我们就主要介绍: 源码管理

二、源码依管理

  1. cmake自带的命令:FetchContent
  2. cmake三方社区支持的命令: CPM
  3. git的submodule

该如何选择何种方式作为依赖管理:
如果你的依赖不是cmake项目,那就推荐使用git submodule进行管理
如果你的依赖项目是cmake项目,那FetchContentCPM都能满足需要,但是CPM更为优雅,所以更加推荐

1. FetchContent

使用FetchContent是非常简单的,只需要三步:

  1. 引入头文件
  2. 定义依赖需要下载代码的地址和一些其它属性
  3. enable依赖

比如:

# 从GitHub上下载代码
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
)

# 从网址下载代码
FetchContent_Declare(
  myCompanyIcons
  URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
  URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
)
# 确保依赖项在这里已经完成下载和构建
FetchContent_MakeAvailable(googletest myCompanyIcons)

FetchContent_Declare命令会生成以下变量:

  1. <lowercaseName>_POPULATED: 设置为TRUE
  2. <lowercaseName>_SOURCE_DIR: 设置依赖下载的位置
  3. <lowercaseName>_BINARY_DIR: 设置依赖构建的位置

在设置使用关键字定义依赖源的一些信息时候,有一些可供选择的设置:

# 从GitHub上下载代码
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
  
  # 先通过find_package命令,通过name Gtest来找库,找不到就调用Fetch下载依赖
  # FIND_PACKAGE_ARGS NAMES GTest
  
  # find_package不能从本地找库,要用Fetch下载下来的库
  # OVERRIDE_FIND_PACKAGE
  
  # 该依赖的cmakelist配置文件是在该项目cmake文件夹内。
  # SOURCE_SUBDIR  cmake
  
  # 设置下载的依赖存放路径
  # SOURCE_DIR firmware
  
  # 是否启用浅克隆,(只会克隆当前分支或标签的提交,以及这些提交所引用的所有父提交)
  # GIT_SHALLOW
)
# 确保依赖项在这里已经完成下载和构建
FetchContent_MakeAvailable(googletest myCompanyIcons)

有些情况下,想要对依赖的管理控制的颗粒度更加精细,我们可以:

# 检查是否依赖已经下载
FetchContent_GetProperties(depname)
# 如果还没有下载
if(NOT depname_POPULATED)
		# 执行下载
		FetchContent_Populate(depname	)
endif()

使用该方法进行下载安装依赖,该方法依赖FetchContent_Declare() 提前声明依赖。

但是下载依赖只会下载一次,如果二次调用则会因为错误而停止,

所以项目在调用FetchContent_Populate之前,应该先调用FetchContent_GetProperties()方法,获得当前的状态

使用保存的内容详细信息时,对 FetchContent_MakeAvailable()FetchContent_Populate() 的调用会在全局属性中记录可以随时查询的信息。该信息可以包括与内容相关联的源目录和二进制目录,以及内容填充是否已在当前配置运行期间被处理。

与find_package进行集成

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
  FIND_PACKAGE_ARGS NAMES GTest
)
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG        605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
  FIND_PACKAGE_ARGS
)

# This will try calling find_package() first for both dependencies
FetchContent_MakeAvailable(googletest Catch2)

对于 Catch2 ,不需要为 find_package() 提供额外的参数,因此在 FIND_PACKAGE_ARGS 关键字之后不需要提供额外的参数。对于 googletest ,其包通常称为 GTest ,因此添加参数以支持通过该名称找到它。

OVERRIDE_FIND_PACKAGE : find_package应该只使用FetchContent_Declare里的信息
FIND_PACKAGE_ARGS: 如果find_package成功在本地找到二进制文件,则不需要FetchContent_Declare里的信息。
SOURCE_SUBDIR cmake: 指定依赖的项目cmakelist文件的地址, 该实例配置在项目跟路径下的cmake文件夹。
SOURCE_DIR firmware:指定下载依赖后存放的路径,该设置配置在项目跟路径下的firmware 文件夹

2. CPM

非官方的cmake依赖管理工具: CPM GitHub

使用方法: 直接到release页面,将cmake脚本文件下载,导入到自己的代码中。

image-20231203103400676

include(CPM)
# 使用GitHub用户nlohmann的仓库的json仓的3.11.2版本代码
cpmaddpackage("gh:nlohmann/json#v3.11.2")
  1. gh: : github
  2. nlohmann: 用户名
  3. json: 仓库名
  4. #v3.11.2: tag版本

3. git submodule

cmake demo

如果依赖是cmake项目,不太推荐使用该方法,将该方法封装为一个函数。可以参考:


# 函数add_git_submodule, 接受一个参数dir
function(add_git_submodule dir)
		# 依赖Git
    find_package(Git REQUIRED)

		# 如果指定的文件夹不存在,则调用git submodule的方法拉取最新代码
    if (NOT EXISTS ${CMAKE_SOURCE_DIR}/${dir}/CMakeLists.txt)
        execute_process(COMMAND ${GIT_EXECUTABLE}
            submodule update --init --recursive -- ${CMAKE_SOURCE_DIR}/${dir}
            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
    endif()

		# 拉取下来后将项目进行编译
    if (EXISTS ${CMAKE_SOURCE_DIR}/${dir}/CMakeLists.txt)
        message("Adding: ${dir}/CMakeLists.txt")
        add_subdirectory(${CMAKE_SOURCE_DIR}/${dir})
    else()
        message("Could not add: ${dir}/CMakeLists.txt")
    endif()
endfunction(add_git_submodule)
  • 使用方法:
# 设置cmake模块的路径
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
# 引入cmake的模块(xx.txt, xx就是模块名字)
include(AddGitSubmodule)

add_git_submodule(external/json)

附加: address_sanitizer 和 undefined sanitizer

option(ENABLE_SANITIZE_ADDR "Enable address sanitizer" ON)
option(ENABLE_SANITIZE_UNDEF "Enable undefined sanitizer" ON)

function(add_sanitizer_flags)
    if (NOT ENABLE_SANITIZE_ADDR AND NOT ENABLE_SANITIZE_UNDEF)
        message(STATUS "Sanitizers deactivated.")
        return()
    endif()

    if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
        add_compile_options("-fno-omit-frame-pointer")
        add_link_options("-fno-omit-frame-pointer")

        if(ENABLE_SANITIZE_ADDR)
            add_compile_options("-fsanitize=address")
            add_link_options("-fsanitize=address")
        endif()

        if(ENABLE_SANITIZE_UNDEF)
            add_compile_options("-fsanitize=undefined")
            add_link_options("-fsanitize=undefined")
        endif()
    elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
        if(ENABLE_SANITIZE_ADDR)
            add_compile_options("/fsanitize=address")
        endif()

        if(ENABLE_SANITIZE_UNDEF)
            message(STATUS "Undefined sanitizer not impl. for MSVC!")
        endif()
    else()
        message(STATUS "Sanitizer not supported in this environment!")
    endif()
endfunction(add_sanitizer_flags)

  • 参考:

  • CPP的项目脚手架

  • FetchContent官网文档

  • UdemyCmake(https://github.com/franneck94/UdemyCmake/tree/master)

  • UdemyCmkae vedeo


http://www.kler.cn/a/156044.html

相关文章:

  • 3.5【数据库系统】ER图
  • MySQ怎么使用语法介绍(详细)
  • 【JAVA】Java基础—面向对象编程:封装—保护类的内部数据
  • [HarmonyOS]简单说一下鸿蒙架构
  • Debezium系列之:发件箱事件路由器
  • 【Playwright + Python】系列(十)利用 Playwright 完美处理 Dialogs 对话框
  • qt5.15播放音频示例(4种方法)
  • 【开源】基于Vue.js的智慧社区业务综合平台
  • Python网络爬虫练习
  • Ubuntu系统配置深度学习环境之nvidia显卡驱动和cuda安装
  • 【算法】滑动窗口题单——5.多指针滑动窗口醒醒⭐
  • vue el-radio-group多选封装及使用
  • pytorch 中的dim 的作用范围
  • Promise自定义封装
  • react native 环境准备
  • 三极管在数字电路中的应用
  • PyQt6 QToolButton工具按钮控件
  • Nacos源码解读04——服务发现
  • linux 内核regulator
  • 记录 | linux查看文件夹大小
  • 【c++随笔15】c++常用第三方库
  • 浅学指针(5)sizeof和strlen的进阶理解
  • k8s安装步骤
  • Pandas实战:电商平台用户分析
  • 【一个超简单的爬虫demo】探索新浪网:使用 Python 爬虫获取动态网页数据
  • android studio安装SDK时无法勾选