C++ 编译依赖管理系统分析以及 srcdep 介绍

如果用 C++ 写一个中小型软件,有要用到很多第三方库的话,相信不少人会觉得比较麻烦。很多新兴的语言都有了统一的依赖管理系统和构建系统,但是 C/C++ 界一直没有比较正统的。(也不奇怪,连统一的 string 都没有,怎么可能有统一的依赖、构建体系?)

在上一篇,我们尝试选择一个构建体系的时候,一开始觉得 CMake 比较接近事实标准了。同样,CMake 也正在尝试把手伸到依赖管理上面。CMake 的理念一开始起源于 makefile,其实是比较简单、干净的,一个包有 include_dir、lib_dir 等,然后就可以构建了。但我的观点还是,Moedern CMake 把这一切都搞复杂了,它尝试面向对象地解决依赖问题+构建问题。但是它在 include_dir、lib_dir 之上发明了很多新的概念,增加了学习成本,掩盖了底层细节——C++er 一般不喜欢被隐藏细节,你最好及解决问题也让我知道是怎么解决的。再加上 CMake 相对另类的语法以及看不懂的文档这两个 debuff,导致学习成本比起一般新事物高得多。所以,尽管它在市占率上可能ou 接近事实标准,我们还是把它当成一个普通的系统来看待,不给特殊待遇。何况,大家用 CMake 来构建的比例有多少、用来管理依赖的又有多少呢,说不清楚,我也没调查过。

C++ 领域,市面上是有一些的依赖管理系统的,但可能都没有形成大一统。我觉得可以按这几个角度去做分类:

  • 源代码依赖还是二进制依赖
  • 是否需要包仓库服务器
  • 是否与构建系统绑定
  • 依赖包跟系统还是跟项目
依赖管理系统 源代码依赖还是二进制依赖 是否需要包仓库服务器 是否与构建系统绑定 依赖包跟系统还是跟项目
git submodule
git subtree
源代码 跟项目
cmake 源代码 跟项目
vcpkg 二进制 否,但一般和 cmake 配合 跟系统
conan 二进制 否,但一般和 cmake 配合 跟项目
gclient 源代码 否,但 google 未做开放性适配 跟项目

见识有限,我知道的大概有这些,如果其他的大家可以补充,开阔开阔眼界。

然后怎么选呢?我想提出几条规则,然后做分析。

第一,要源代码依赖,不要二进制依赖。

因为 C++ 各平台编译方式不尽相同,即使同一平台,也可以有不同的编译器参数、宏定义等。同时,也不存在二进制兼容性。因此,二进制依赖会有很多问题。除非已选定特定平台特定参数,才能有效地实行二进制依赖。从通用性角度上讲,源代码依赖是合理的。

第二,不要自建仓库的。

首先,一般依赖系统想要自建仓库,形成生态,本来就非常难,需要由大厂牵头或者知名社区领军人物牵头。在 C++ 领域,牛人隐士颇多,一个人、一个组织或一家公司,想要一言九鼎进行宣传、号召,更难。

其次,自建仓库需要将每个包进行标准化。这是一项不可能完成的工作。很多代码的历史堪比计算机历史,尊重其原作者的编译方式是最兼容、风险最低的方式。

最后,从开发者角度来说,去每个软件的官网引用其代码是最安全、放心的做法。从某个依赖体系的中心化仓库去引用,总是会有担心。

从实际来看,即使现在生态最好的 vcpkg 和 conan,也只有一两千的包量,相比 npm、maven,实在是零头。

按这两条规则,排除了目前如日中天的 vcpkg 和 conan。剩下的里面,cmake 的 FetchContent 是和 cmake 强绑定的,如果都用 cmake 一条龙,那么选它。直接用 git submodule 或 subtree,也是能当依赖系统用的,只是可能没那么方便和直观,也不知道什么原因导致业界没这么用?gclient 其实是理念上最符合的,它没 cmake 那么晦涩、抽象,而是直截了当地配置什么包,从哪里下载,放到项目的哪里。但是 google 没有特意推广的意图,主要还是为 chrome 及其他周边项目服务。

所以呢,笔者按这个理念要自己写一个,只管从哪儿下载、放到本地哪里,把 gclient 的 runhook 也去掉,只有 sync。

起个名字,叫 srcdep,强调源代码依赖,项目地址为 https://github.com/Streamlet/srcdep

用法就是在项目跟目录建立一个 SRCDEP.yaml,内容为

DEPS:
path/to/local/directory: # 第一个包的目标目录
# GIT 依赖
# 需要配置 GET_REPO 和 GIT_TAG
GIT_REPO: url_of_git_repo
GIT_TAG: git_tag_or_branch_or_commit
path/to/another/directory: # 第二个包的目标目录
# 普通 URL 依赖
# 需要至少配置一个 URL
URL: package_url
# 如果 URL 不是一个正常的扩展名结尾,那么需要配一下 URL_FORMAT,以便知道怎么解压
URL_FORMAT: tar.gz
# 如果包解压出来是一个目录,但咱们需要把这个目录下面的文件直接丢到 path/to/another/directory
# 那么配置一下 ROOT_DIR,意思是包内的根目录名称,需要把这个目录视为包的根目录
ROOT_DIR: root_dir_in_archive
# 校验方式,支持 MD5、SHA1、SHA224、SHA256、SHA384、SHA512
URL_HASH:
SHA256: sha256_hash_of_the_package

然后用 python 实现,把 srcdep 的目录丢到 PATH 环境变量里,在项目里执行一把,就下载所有依赖包。

跟构建完全分离,构建可以走上一节的 gn+ninja。

这样,我们完成了 C++ 下快速开发小型组件和小型应用的基础设施的搭建。

C++ 编译依赖管理系统分析以及 srcdep 介绍的更多相关文章

  1. webpack模块依赖管理介绍

    http://webpack.github.io/docs/ webpack is a module bundler. 是一个模块管理器 webpack可以管理模块的依赖关系,并产生可以替代这些模块的 ...

  2. Java Gradle入门指南之依赖管理(添加依赖、仓库、版本冲突)

        开发任何软件,如何管理依赖是一道绕不过去的坎,软件开发过程中,我们往往会使用这样那样的第三方库,这个时候,一个好的依赖管理就显得尤为重要了.作为一个自动构建工作,Gradle对依赖管理有着很好 ...

  3. 用CocoaPods做iOS程序的依赖管理(转摘)

    转摘自:http://blog.devtang.com/blog/2014/05/25/use-cocoapod-to-manage-ios-lib-dependency/ 文档更新说明 2012-1 ...

  4. Gradle系列教程之依赖管理(转)

    转自Lippi-浮生志 :http://ezlippi.com/blog/2015/05/gradle-dependency-management.html 这一章我将介绍Gradle对依赖管理的强大 ...

  5. 用CocoaPods做iOS程序的依赖管理

    CocoaPods简介 每种语言发展到一个阶段,就会出现相应的依赖管理工具,例如Java语言的Maven,nodejs的npm.随着iOS开发者的增多,业界也出现了为iOS程序提供依赖管理的工具,它的 ...

  6. Gradle实战教程之依赖管理

    这是从我个人网站中复制过来的,原文地址:http://coolshell.info/blog/2015/05/gradle-dependency-management.html,转载请注明出处. 简要 ...

  7. iOS 用CocoaPods做iOS程序的依赖管理

    文档更新说明 2012-12-02 v1.0 初稿 2014-01-08 v1.1 增加设置 ruby 淘宝源相关内容 2014-05-25 v2.0 增加国内 spec 镜像.使用私有 pod.po ...

  8. Maven(六)之依赖管理

    前面讲了maven一些关于Maven的简单知识,今天我给大家分享一些Maven的依赖管理.我相信用过maven的人都知道,它很重要的功能就是通过依赖来添加jar包. 让我们领略一下Maven是怎么管理 ...

  9. 从初识Maven到使用Maven进行依赖管理和项目构建

    前些天就安装了Maven,以备自己以后整合项目用,尤其是我们的ssh,ssm项目.想必好多人在开始的时候并不清楚Maven是什么,它能够帮助我们干什么. 所以在学习Maven之前我们一定要知道它是什么 ...

  10. maven入门(8)maven的依赖管理

    我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可. 1. 依赖配置    依赖可以声明如下: <project> ... <dependenci ...

随机推荐

  1. python关于Django搭建简单博客项目(详解一)

    上一篇我们说了如何搭建简易博客网站,下面我们来进行详细解答.本文没有特定顺序,请结合上一篇和源代码参照学习. 相关源代码和解析请参看:https://github.com/Cheng0829/mysi ...

  2. 京东云开发者| Redis数据结构(二)-List、Hash、Set及Sorted Set的结构实现

    1 引言 之前介绍了Redis的数据存储及String类型的实现,接下来再来看下List.Hash.Set及Sorted Set的数据结构的实现. 2 List List类型通常被用作异步消息队列.文 ...

  3. static 关键字分析

    在java中static 关键字用途很广,可以修饰成员变量 方法 甚至类(静态内部类),这里不分析static 修饰类 static修饰的内容的运行顺序 java的程序执行之前有一个类的加载的过程,在 ...

  4. Codeforces 1670 E. Hemose on the Tree

    题意 给你个数p,n = 2^p: 有一棵树有n个节点,告诉你怎么连边: 每个点有个权值,每条边也有个权值,权值需要自行分配,[1,2,3..n...2n-1],总共2n-1个权值: 你需要选一个节点 ...

  5. spring-ioc知识点

    1.bean管理 -spring创建对象 -在spring的配置文件中,使用bean标签.标签里添加对应的属性.就可以实现对象的创建 -在bean标签中有很多属性 -id属性:唯一的标识 -class ...

  6. Java函数式编程:三、流与函数式编程

    本文是Java函数式编程的最后一篇,承接上文: Java函数式编程:一.函数式接口,lambda表达式和方法引用 Java函数式编程:二.高阶函数,闭包,函数组合以及柯里化 前面都是概念和铺垫,主要讲 ...

  7. VBA粗犷整理

    PART1: 三.查找 1.从某一行向上/下找到第一个不为空的行 intRowPntEnd = ActiveSheet.Cells(intRowPntStart, intColPnt).End(xlD ...

  8. 成熟企业级开源监控解决方案Zabbix6.2关键功能实战-下

    @ 目录 实战 Zabbix server源码安装使用示例 部署 配置 Zabbix agent2使用示例 部署 配置 Zabbix proxy使用示例 部署 配置 自定义监控使用示例 触发器使用示例 ...

  9. onps栈使用说明(2)——ping、域名解析等网络工具测试

    1. ping测试 协议栈提供ping工具,其头文件为"net_tools/ping.h",将其include进你的目标系统中即可使用这个工具. -- #include " ...

  10. 匿名方法、Lambda表达和自定义泛型委托以及Func、Action系统泛型委托

    1.匿名方法的概念:一个方法没有具体的名称,而只有关键字delegate.方法参数.方法体.这种方法是匿名方法. 匿名方法的好处:将具体方法和委托直接关联在一起,如果我们基于委托只需要一个方法的时候, ...