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(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
)# 从网址下载代码
FetchContent_Declare(myCompanyIconsURL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gzURL_HASH MD5=5588a7b18261c20068beabfb4f530b87
)
# 确保依赖项在这里已经完成下载和构建
FetchContent_MakeAvailable(googletest myCompanyIcons)

FetchContent_Declare命令会生成以下变量:

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

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

# 从GitHub上下载代码
FetchContent_Declare(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_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(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0FIND_PACKAGE_ARGS NAMES GTest
)
FetchContent_Declare(Catch2GIT_REPOSITORY https://github.com/catchorg/Catch2.gitGIT_TAG        605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1FIND_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)# 依赖Gitfind_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.rhkb.cn/news/211955.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python第三次练习

Python 一、如何判断一个字符串是否是另一个字符串的子串二、如何验证一个字符串中的每一个字符均在另一个字符串中出现三、如何判定一个字符串中既有数字又有字母四、做一个注册登录系统 一、如何判断一个字符串是否是另一个字符串的子串 实现代码&#xff1a; string1 inp…

外包干了2个多月,技术明显有退步了。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

JVM:强软弱虚四种引用

下面依次解释五种引用 一、强引用 把一个对象赋值给一个引用变量&#xff0c;就相当于把这个对象的强引用放到变量中。 只要对象可达&#xff0c; GC一定不会回收这个对象&#xff08;A1&#xff09; 二、软引用 当一个对象&#xff08;A2&#xff09;没有强引用时&#xff…

Rust UI开发(五):iced中如何进行页面布局(pick_list的使用)?(串口调试助手)

注&#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库&#xff0c;用于为rust语言程序构建UI界面。 这是一个系列博文&#xff0c;本文是第五篇&#xff0c;前四篇链接&#xff1a; 1、Rust UI开发&#xff08;一&#xff09;&#xff1a;使用iced构建UI时…

网络安全(一)--网络环境构成,系统的安全

2. 网络攻防环境 目标 了解攻防环境构成了解入侵检测系统&#xff08;平台&#xff09;的部署位置 2.1. 环境构成 2.1.1. 环境框图 一个基本的网络攻防实验环境包括&#xff1a;靶机、攻击机、入侵检测分析系统、网络连接四部分组成。 一个基础的网络攻防实验环境需要如下…

【SpringCloud】通过Redis手动更新Ribbon缓存来解决Eureka微服务架构中服务下线感知的问题

文章目录 前言1.第一次尝试1.1服务被调用方更新1.2压测第一次尝试1.3 问题分析1.4 同步的不是最新列表 2.第二次尝试2.1调用方过滤下线服务2.2压测第二次尝试2.3优化 写到最后 前言 在上文的基础上&#xff0c;通过压测的结果可以看出&#xff0c;使用DiscoveryManager下线服务…

EasyExcel如何读取全部Sheet页数据方法

一、需求描述 Excel表格里面大约有20个sheet页&#xff0c;每个sheet页65535条数据&#xff0c;需要读取全部数据&#xff0c;并导入至数据库。 找了好多种方式&#xff0c;EasyExcel比较符合&#xff0c;下面看代码。 二、实现方式 采用EasyExcel框架的doReadAll()方法 1、…

Linux驱动开发学习笔记2《LED驱动开发试验》

目录 一、Linux下LED灯驱动原理 1.地址映射 二、硬件原理图分析 三、实验程序编写 1.LED 灯驱动程序编写 2.编写测试APP 四、运行测试 1.编译驱动程序和测试APP &#xff08;1&#xff09;编译驱动程序 &#xff08;2&#xff09;编译测试APP 2.运行测试 一、Linux下…

redis应用-分布式锁

目录 什么是分布式锁 分布式锁的基本实现 引入过期时间 引入校验id 引入lua 引入看门狗 引入redlock算法 什么是分布式锁 在一个分布式系统中,也会涉及到多个节点访问同一个公共资源的情况,此时就需要通过锁来做互斥控制,避免出现类似于"线程安全"的问题. 而…

Selenium无头模式容易遇到的坑

在无头模式下&#xff0c;我们看不到浏览器的操作&#xff0c;但是selenium无头模式的浏览器向服务器发送的请求头和正常模式下还是有点区别的&#xff0c;这就导致了一些网站会检测到我们是用selenium来访问的&#xff0c;从而导致一些问题 下面就是我在使用selenium无头模式时…

134. 加油站(贪心算法)

根据题解 这道题使用贪心算法&#xff0c;找到当前可解决问题的状态即可 「贪心算法」的问题需要满足的条件&#xff1a; 最优子结构&#xff1a;规模较大的问题的解由规模较小的子问题的解组成&#xff0c;规模较大的问题的解只由其中一个规模较小的子问题的解决定&#xff…

SpringSecurity(五)

深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式&#xff0c;也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息&#xff0c;但是在SpringBoot项目中&#xff0c;我们慢慢脱离…

SpringBoot读取properties文字乱码问题及相关问题

问题&#xff1a;在idea的编辑器中properties文件一般用UTF-8编码&#xff0c;SpringBoot2读取解码方式默认不是UTF-8&#xff0c;当值出现中文时SpringBoot读取时出现了乱码。 解决方式1&#xff1a;在SpringBoot框架层面解决&#xff0c;在配置类注解上添加encoding属性值为…

Linux---逻辑卷管理

本章主要介绍逻辑卷的管理。 了解什么是逻辑卷创建和删除逻辑卷扩展逻辑卷缩小逻辑卷逻辑卷快照的使用 前面介绍了分区的使用&#xff0c;如果某个分区空间不够&#xff0c;想增加空间是非常困难的。所以&#xff0c;建议尽可能使用逻辑卷而非普通的分区&#xff0c;因为逻辑卷…

localhost工具:本地代码的远程之路 | 京东云技术团队

在日常的开发过程中&#xff0c;本地代码远程调试一直是最理想的开发状态。本文通过介绍京东集团内开发的一个轻量简单的小工具”localhost”&#xff0c;从多角度的方案思考&#xff0c;到原理介绍&#xff0c;到最终的方案落地&#xff0c;在开发阶段发现问题&#xff0c;解决…

【数据结构高阶】AVL树

上期博客我们讲解了set/multiset/map/multimap的使用&#xff0c;下面我们来深入到底层&#xff0c;讲解其内部结构&#xff1a; 目录 一、AVL树的概念 二、AVL树的实现 2.1 节点的定义 2.2 数据的插入 2.2.1 平衡因子的调整 2.2.1.1 调整平衡因子的规律 2.2.2 子树的旋…

识别低效io引起的free buffer waits

产生事发时间段的awr报告 Top 5 wait events 这里重点关注&#xff1a; 1.free buffer waits 2.enq_HW-contention 3.enq:tx-row lock contention enq:HW-contention属于水位线的争用&#xff0c;已经透过alter table allocate extent&#xff0c;提前分配空间,这里不做讨论 …

C++——红黑树

作者&#xff1a;几冬雪来 时间&#xff1a;2023年12月7日 内容&#xff1a;C——红黑树讲解 目录 前言&#xff1a; 红黑树的概念&#xff1a; 红黑树的性质&#xff1a; 红黑树的路径计算&#xff1a; 最长路径和最短路径&#xff1a; AVL树与红黑树的区别&#xff…

让你在组建企业级项目时手到擒来——浅谈各类常用工具和框架概述

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容&#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作…

分布式系统理论基础

目录 引言 CAP定理 CAP的工程启示 1、关于 P 的理解 2、CA非0/1的选择 3、跳出CAP 小结 本文转自&#xff1a;https://www.cnblogs.com/bangerlee/p/5328888.html 该系列博文会告诉你什么是分布式系统&#xff0c;这对后端工程师来说是很重要的一门学问&#xff0c;我们会逐步了…