C++ 编译依赖管理系统分析以及 srcdep 介绍
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 介绍的更多相关文章
- webpack模块依赖管理介绍
http://webpack.github.io/docs/ webpack is a module bundler. 是一个模块管理器 webpack可以管理模块的依赖关系,并产生可以替代这些模块的 ...
- Java Gradle入门指南之依赖管理(添加依赖、仓库、版本冲突)
开发任何软件,如何管理依赖是一道绕不过去的坎,软件开发过程中,我们往往会使用这样那样的第三方库,这个时候,一个好的依赖管理就显得尤为重要了.作为一个自动构建工作,Gradle对依赖管理有着很好 ...
- 用CocoaPods做iOS程序的依赖管理(转摘)
转摘自:http://blog.devtang.com/blog/2014/05/25/use-cocoapod-to-manage-ios-lib-dependency/ 文档更新说明 2012-1 ...
- Gradle系列教程之依赖管理(转)
转自Lippi-浮生志 :http://ezlippi.com/blog/2015/05/gradle-dependency-management.html 这一章我将介绍Gradle对依赖管理的强大 ...
- 用CocoaPods做iOS程序的依赖管理
CocoaPods简介 每种语言发展到一个阶段,就会出现相应的依赖管理工具,例如Java语言的Maven,nodejs的npm.随着iOS开发者的增多,业界也出现了为iOS程序提供依赖管理的工具,它的 ...
- Gradle实战教程之依赖管理
这是从我个人网站中复制过来的,原文地址:http://coolshell.info/blog/2015/05/gradle-dependency-management.html,转载请注明出处. 简要 ...
- iOS 用CocoaPods做iOS程序的依赖管理
文档更新说明 2012-12-02 v1.0 初稿 2014-01-08 v1.1 增加设置 ruby 淘宝源相关内容 2014-05-25 v2.0 增加国内 spec 镜像.使用私有 pod.po ...
- Maven(六)之依赖管理
前面讲了maven一些关于Maven的简单知识,今天我给大家分享一些Maven的依赖管理.我相信用过maven的人都知道,它很重要的功能就是通过依赖来添加jar包. 让我们领略一下Maven是怎么管理 ...
- 从初识Maven到使用Maven进行依赖管理和项目构建
前些天就安装了Maven,以备自己以后整合项目用,尤其是我们的ssh,ssm项目.想必好多人在开始的时候并不清楚Maven是什么,它能够帮助我们干什么. 所以在学习Maven之前我们一定要知道它是什么 ...
- maven入门(8)maven的依赖管理
我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可. 1. 依赖配置 依赖可以声明如下: <project> ... <dependenci ...
随机推荐
- KTV和泛型(3)
泛型除了KTV,还有一个让人比较疑惑的玩意,而且它就是用来表达疑惑的:? 虽然通过泛型已经达到我们想要的效果了,例如: List<String> list = new ArrayList& ...
- get,post,put,delete四种基础方法对应增删改查
PUT,DELETE,POST,GET四种基础方法对应增删改查 1.GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改.增加数 ...
- JDK中自带的JVM分析工具
目录 一.业务背景 二.Jdk-Bin目录 三.命令行工具 1.jps命令 2.jinfo命令 3.jstat命令 4.jstack命令 5.jmap命令 四.可视化工具 1.jconsole 2.v ...
- 19.-哈希算法&注册登录
一.哈希算法 哈希: 给定明文-计算出一段定长的-不可逆的值 定长输出:不管明文输入多少,哈希都是定长的 不可逆:无法反向计算出对应的明文 雪崩效应:输入改变,输出必然变 md5:32位16进制 ...
- Vue router简单配置入门案例
{ 注意驼峰命名法,不然会报错 } 1.在Views文件夹下创建Vue路由文件,例如: <template> </template> <script> </ ...
- C# 获取打开的EXCEL中某列的行数
背景 在通过C#操作EXCEL时 获取行数 int iRowCount = worksheet.get_Range("A65535", oMissing).get_End(MExc ...
- Websocket集群解决方案
最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息. 所谓的全双工表示客户端和服务端都能向对方发送消息.不使用 ...
- AtCoder Beginner Contest 277 题解
掉大分力(悲 A - ^{-1} 直接模拟. #include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false) #define ...
- mybatis中association和collection使用
mybatis中association和collection使用 一.概述 association:一个复杂的类型关联.许多结果将包成这种类型 collection:复杂类型的集合 这2个属性的使用, ...
- 833(DIV2)——C题题解
题目链接 题目大意: 给定n个数,你可以对数值为0的数改变其为任意值,问最后前缀和为0的个数的最大值. 思路: 这题比较可惜,自己的思路没有问题,但是他少了一些东西.对数组进行前缀和处理,我们可以发现 ...