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. KTV和泛型(3)

    泛型除了KTV,还有一个让人比较疑惑的玩意,而且它就是用来表达疑惑的:? 虽然通过泛型已经达到我们想要的效果了,例如: List<String> list = new ArrayList& ...

  2. get,post,put,delete四种基础方法对应增删改查

    PUT,DELETE,POST,GET四种基础方法对应增删改查 1.GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改.增加数 ...

  3. JDK中自带的JVM分析工具

    目录 一.业务背景 二.Jdk-Bin目录 三.命令行工具 1.jps命令 2.jinfo命令 3.jstat命令 4.jstack命令 5.jmap命令 四.可视化工具 1.jconsole 2.v ...

  4. 19.-哈希算法&注册登录

    一.哈希算法 哈希: 给定明文-计算出一段定长的-不可逆的值 定长输出:不管明文输入多少,哈希都是定长的 不可逆:无法反向计算出对应的明文 雪崩效应:输入改变,输出必然变 md5:32位16进制   ...

  5. Vue router简单配置入门案例

    { 注意驼峰命名法,不然会报错 } 1.在Views文件夹下创建Vue路由文件,例如: <template> </template>  <script> </ ...

  6. C# 获取打开的EXCEL中某列的行数

    背景 在通过C#操作EXCEL时 获取行数 int iRowCount = worksheet.get_Range("A65535", oMissing).get_End(MExc ...

  7. Websocket集群解决方案

    最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息. 所谓的全双工表示客户端和服务端都能向对方发送消息.不使用 ...

  8. AtCoder Beginner Contest 277 题解

    掉大分力(悲 A - ^{-1} 直接模拟. #include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false) #define ...

  9. mybatis中association和collection使用

    mybatis中association和collection使用 一.概述 association:一个复杂的类型关联.许多结果将包成这种类型 collection:复杂类型的集合 这2个属性的使用, ...

  10. 833(DIV2)——C题题解

    题目链接 题目大意: 给定n个数,你可以对数值为0的数改变其为任意值,问最后前缀和为0的个数的最大值. 思路: 这题比较可惜,自己的思路没有问题,但是他少了一些东西.对数组进行前缀和处理,我们可以发现 ...