C++工程:总结 CMake 添加第三方库依赖方式git submodule、 find_library、FetchContent、CPM等

2023-05-16

CMake 已经成为了C++工程管理的主流方式,功能非常强大,现在大多数的 C++ 库都已经支持CMake,下面以 jsoncpp 为例,介绍几种引入第三方库的方式。

1. 代码依赖

这种方式是把第三方库的完整代码直接添加到我们的项目中,当做项目代码的一部分进行编译,这种方式会把第三方代码和我们的代码混在一起,并不推荐使用。首先我们需要到 jsoncpp 下载需要的头文件和实现代码,放到项目当中。

工程文件目录

├── CMakeLists.txt
├── jsoncpp
│   ├── include
│   │   └── json
│   │       ├── autolink.h
│   │       ├── config.h
│   │       ├── features.h
│   │       ├── forwards.h
│   │       ├── json.h
│   │       ├── reader.h
│   │       ├── value.h
│   │       └── writer.h
│   ├── json_batchallocator.h
│   ├── json_internalarray.inl
│   ├── json_internalmap.inl
│   ├── json_reader.cpp
│   ├── json_value.cpp
│   ├── json_valueiterator.inl
│   └── json_writer.cpp
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(includes_full_code)
set(CMAKE_CXX_STANDARD 14)
# 包含头文件
include_directories(./jsoncpp/include)
set(jsoncpp jsoncpp/json_reader.cpp jsoncpp/json_writer.cpp jsoncpp/json_value.cpp)
# 添加可执行代码
add_executable(includes_full_code main.cpp ${jsoncpp})

main.cpp

后面的示例的main.cpp都是一样

#include <iostream>
#include "json/json.h"
int main() {
    Json::Value json;
    json["name"] = "Wiki";
    json["age"] = 18;
    std::cout << json.toStyledString() << std::endl;
    return 0;
}

完整代码:includes_full_code_exmaple

2. 内部工程依赖

这种方式和上面 代码依赖 的方式类似,不同的是内部工程依赖会把第三方库的管理职责交给第三方库工程CMakeLists.txt文件,这种方式的好处是职责分明,是最常用的依赖方式。

工程文件目录

目录结果和上面的案例相似,不同的是jsoncpp文件夹多了一个 CMakeLists.txt 文件

├── CMakeLists.txt
├── jsoncpp
│   ├── CMakeLists.txt
│   ├── include
│   │   └── json
│   │       ├── autolink.h
│   │       ├── config.h
│   │       ├── features.h
│   │       ├── forwards.h
│   │       ├── json.h
│   │       ├── reader.h
│   │       ├── value.h
│   │       └── writer.h
│   ├── json_batchallocator.h
│   ├── json_internalarray.inl
│   ├── json_internalmap.inl
│   ├── json_reader.cpp
│   ├── json_value.cpp
│   ├── json_valueiterator.inl
│   └── json_writer.cpp
└── main.cpp

jsoncpp/CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(jsoncpp)
add_library(${PROJECT_NAME} json_reader.cpp json_value.cpp json_writer.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(multi_cmakelists)
# 添加子工程
add_subdirectory(jsoncpp)
add_executable(${PROJECT_NAME} main.cpp)
# 链接子工程
target_link_libraries(${PROJECT_NAME} jsoncpp)

完整代码:multi_cmakelists_example

这种方式除了引入第三方依赖,通常我们也会用这种方式来管理项目中的各个子模块,每个模块都有独立的CMakeLists.txt文件,从而实现子工程的单独引用,源码请看 subdirectory_example。

3. find_library:编译库方式引入

这种方式是用来依赖已经打包好的二进制文件,这种方式也分为静态库(.a、.lib)和动态库(.so、.dll)方式引入,这种方式也可以查找本机已经安装好的库,比如 Android 的 log 库就是通过这种方式引入。

生成.a文件

运行上面的 内部工程依赖 案例后,我们我们可以从项目中找到编译好的 multi_cmakelists/cmake-build-debug/jsoncpp/libjsoncpp.a 文件。

工程文件目录

和上面不同的是,这里只需要导入jsoncpp的头文件和.a文件。

├── CMakeLists.txt
├── jsoncpp
│   ├── include
│   │   └── json
│   │       ├── autolink.h
│   │       ├── config.h
│   │       ├── features.h
│   │       ├── forwards.h
│   │       ├── json.h
│   │       ├── reader.h
│   │       ├── value.h
│   │       └── writer.h
│   └── libjsoncpp.a
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(find_library_example)
include_directories(jsoncpp/include)
add_executable(${PROJECT_NAME} main.cpp)
find_library(jsoncpp_lib NAMES jsoncpp PATHS ./jsoncpp)
target_link_libraries(${PROJECT_NAME} ${jsoncpp_lib})

完整代码:find_library_example

这种方式在 Android 开发很常见,比如我们引入xlog实现日志打印就可以通过这种方式实现,代码参考 xlog_example。

4. FetchContent

FetchContent 是 cmake 3.11.0 版本开始提供的功能,可以非常方便用来添加第三方依赖。

工程文件目录

├── CMakeLists.txt
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(fetch_content_example)
include(FetchContent)
#FetchContent_Declare(jsoncpp
#        GIT_REPOSITORY https://github.com/open-source-parsers/jsoncpp.git
#        GIT_TAG 1.9.4)
# 建议使用压缩包的方式依赖,下载速度更快
FetchContent_Declare(jsoncpp
        URL https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.tar.gz)
FetchContent_MakeAvailable(jsoncpp)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} jsoncpp_lib)

建议通过压缩包的方式引入,因为直接引入git仓库可能会很慢。

完整代码:fetch_content_example

Android SDK 的 CMake 的默认版本是3.10.2,并不支持FetchContent,如果想在Android开发中使用需要安装3.11.0以上版本的cmake,为了降低团队的协同成本,并不建议在 Android 工程使用,建议使用内部工程的方式引入。

5. CPM

CPM.cmake 是在 FetchContent 的基础上封装而来,相比 FetchContent 更加简单易用,使用CPM需要到 CPM.cmake 下载cmake目录的文件CPM.cmake、get_cpm.cmake和testing.cmake,添加到项目当中。

工程文件目录

├── CMakeLists.txt
├── cmake
│   ├── CPM.cmake
│   ├── get_cpm.cmake
│   └── testing.cmake
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(cpm_example)
include(cmake/CPM.cmake)
#CPMAddPackage(
#        GIT_REPOSITORY https://github.com/open-source-parsers/jsoncpp.git
#        GIT_TAG 1.9.4)
# 建议使用压缩包的方式依赖,下载速度更快
CPMAddPackage(
        NAME jsoncpp
        URL https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.tar.gz)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} jsoncpp_lib)

这种方式的细节不需要我们自己处理,都交给了CPM解决,这种方式也同样不建议在 Android 工程使用。

完整代码:cpm_example

6. find_package

find_package 是 cmake 3.19.0 版本开始提供的功能,可以非常方便添加,这种方式主要是从本机上查找已经安装好的库,需要提前通过命令安装。

安装jsoncpp

我的Mac OS,通过下面方法安装可以成功,其它系统可能会出错

# 拉取代码
git clone https://github.com/open-source-parsers/jsoncpp
cd jsoncpp
mkdir -p build/debug
cd build/debug
# 生成Makefile
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -DCMAKE_INSTALL_INCLUDEDIR=include -G "Unix Makefiles" ../..
# 安装
make && make install

如果提示没有安装cmake,需要自行安装cmake

工程文件目录

├── CMakeLists.txt
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(find_package_example)
find_package(jsoncpp REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} jsoncpp_lib)

完整代码:find_package_example

使用这种方式是需要有个大前提,电脑必须已经安装好了对应的库,否则无法正常工作,这种方式只有在特定的场景下使用,比如调用电脑的opencv、openssl。

7. git submodule

这种方式是利用git的submodule实现,推荐Android使用,通过git添加另外一个仓库的依赖,可更新另外一个仓库的依赖,但是代码不会包含进来。

# 在A仓库添加B仓库依赖,操作完后需要提交上去
git submodule add https://github.com/taoweiji/B.git

A仓库拉取及submodule仓库的更新

git clone https://github.com/taoweiji/A.git
git submodule init && git submodule update

8. Android 动态依赖

C++工程:以 xlog 为例介绍 Android NDK 如何依赖第三方C++动态库

总结

C++添加依赖的方式有很多种,没有绝对的好与差,应该根据不同的场景使用不同的依赖方式,例如在Android工程中,我们应该尽量不要改变默认的CMake版本,避免增加环境的依赖。



作者:ImWiki
链接:https://www.jianshu.com/p/f181b5bd0a63
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++工程:总结 CMake 添加第三方库依赖方式git submodule、 find_library、FetchContent、CPM等 的相关文章

随机推荐

  • ESP32-CAM实现局域网/远程视频传输

    手上这个ESP32 CAM买回来已经放了一个学期了 xff0c 最近才开始玩 xff0c 试了试用它来实现视频传输 局域网的视频传输比较简单 xff0c 基本能正确把例程烧进去就可以了 xff0c 这篇文章主要记录一下远程视频传输的实现 E
  • Debian 9.5  中文输入问题

    刚安装完debian9 5 发现输入法无法切换 xff0c 网页显示不了中文 找设置找不到修改的地方 xff0c 于是上网查教程 一开始按照教程需要安装 xff1a fcitx ui classic xff0c fcitx ui light
  • Hive_基于Hive的网站日志分析

    文章目录 概述1 引出需要进行数据预处理的必要性 toc 2 使用RegexSerDe处理apache或者ngnix日志文件 toc 3 根据不同业务拆表 toc 3 1 需求分析3 2 拆表 4 数据清洗 toc 4 1 Hive自定义函
  • python如何判断用户输入回车键?--关于input()函数的前世今生

    前言 最近在写代码的时候 xff0c 需要判断一下用户是不是敲了回车键 xff0c 于是写出了这样的代码 xff1a span class token keyword if span span class token builtin inp
  • PyTorch版YOLOv4训练自己的数据集---基于Google Colab

    colab简介 Google Colaboratory是谷歌开放的一款研究工具 xff0c 主要用于机器学习的开发和研究 工具优势 xff1a Google Colab最大的好处是给广大的AI开发者提供了免费的GPU使用 你可以在上面轻松地
  • Efficientnet_pytorch训练自己的数据集,并对数据进行分类

    准备训练的数据集 相关代码已整理至github https github com whisperLiang efficientnet pytorch git 相关代码已整理至码云 xff1a https gitee com whisperl
  • 水下图像色彩还原(基于可见光衰减及图像去雾算法)

    参考源 参考论文 xff1a UnderwaterHazeLines BMVC2017 Github项目地址 xff1a https github com danaberman underwater hl git 对论文的一些重述 水下图像
  • 强化学习TD3算法笔记1——论文解读

    相关论文 TD3 xff1a TD3 Double DQN Double DQN DDPG DDPG TD3论文结构 摘要 xff1a 提出Actor Critic面对的问题 xff0c 概括了TD3算法和效果引言 xff1a 提出当前对于
  • Efficientnet_pytorch_cbam_gui

    大致说明 这是一个基于efficientnet模型的图像分类方案 模型融入了cbam注意力机制模块 xff0c cutmix CrossEntropyLabelSmooth auto augment等tricks帮助原生的effcientn
  • 可靠性udp传输大文件

    高级计算机网络大作业 可靠性udp传输大文件 实验数据zstd压缩1G文件 xff08 延迟100ms 丢包1 xff09 0 1G文件 xff08 延迟100ms 丢包1 xff09 0 01G文件 xff08 延迟100ms 丢包1 x
  • 一些奇怪问题的解决汇总

    vscode ssh远程连接 问题描述 xff1a Setting up SSH Host 192 168 78 133 details Initializing VS Code Server 一开始尝试了网络的各种方式 xff0c 比如删
  • 控制系统--系统结构图

    结构图基本单元 信号线 表示信号流向 引出点 表示信号引出 xff0c 被引出信号与原信号完全相同 或 从同一位置引出信号完全相同 比较点 将所有输入信号做代数运算 方框 表示信号经过传递函数为 H s
  • 字符串及处理之三: 使用TCHAR系列方案

    使用TCHAR系列方案编写程序 TCHAR是一种字符串类型 xff0c 它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码 xff0c 不需要使用繁琐的宏定义来包含你的代码 TCHAR的引入 xff0c 主要是在Tch
  • Chrome解决“github.com拒绝了我们的访问请求”

    目录 1 网站查询特定IP 2 host文件修改 3 刷新DNS 如果你在Chrome访问github com时出现以下错误 xff1a 本博主之前的Chrome和Edge都无法访问github官网 xff0c 然后就来到了万能的C站找到了
  • STC12C5A60S2_LCD1602驱动

    文章目录 LCD1602 HLCD1602 cmain c LCD1602 H 代码如下 xff1a span class token macro property span class token directive hash span
  • 猿创征文|机器学习实战(8)——随机森林

    目录 1 随机森林 2 极端随机树 3 特征重要性 4 提升法 4 1 AdaBoost 4 2 梯度提升 机器学习实战 xff08 7 xff09 中我们已经提到 xff0c 随机森林是决策树的集成 xff0c 通常用bagging方法训
  • 总结2014——迷茫以及迷茫过后的坚持

    首先 xff0c 借用一句话和大家共勉 xff1a 少一些功利主义的追求 xff0c 多一些不为什么的坚持 xff01 xff01 不知不觉15年也快过了1个月了 xff0c 还是想着要为14年做一下总结 xff1a 记录一下自己的历程 今
  • 汇编总结:lea指令

    ea指令变种 按大小分类 leaw 2个字节 leal 4个字节 leaq 8个字节 lea的用法 leaq a b c d rax 首先lea指令是mov指令的变种 xff0c 据说 xff0c lea指令是x86体系结构中 xff0c
  • CMake语法—选项(option)

    CMake语法 选项 xff08 option xff09 1 选项 1 1 定义 1 2 说明 variable 选项名help text 描述 解释 备注value 选项初始化值 xff08 除ON而外全为OFF xff09 2 应用注
  • C++工程:总结 CMake 添加第三方库依赖方式git submodule、 find_library、FetchContent、CPM等

    CMake 已经成为了C 43 43 工程管理的主流方式 xff0c 功能非常强大 xff0c 现在大多数的 C 43 43 库都已经支持CMake xff0c 下面以 jsoncpp 为例 xff0c 介绍几种引入第三方库的方式 1 代码