用于开放源码C/C++库分发的Bazel

2020-09-16 22:56:14

无可奉告,在过去的几天里,我一直在试验Bazel作为CCV的库分发机制。

在这一点上,我非常熟悉密封式构建系统。我的主要知识来自8年前的巴克。当时,我从来没有想过这样的构建系统最终会成为图书馆的分发机制。在同样的8年里,NPM已经占领了世界。Go模块、Cargo和SWIFT包管理器等新的语言相关包管理器普及了将公共存储库(GitHub)用作依赖项引用的概念。在此之前的语言,主要是C/C++都在慢慢地朝这个方向发展。

CCV有一个简单的基于AutoConf的功能检测/配置系统。当./configure&;&;make./configure&;&;生成时,您会期望软件包正常工作。然而,它从未认真尝试过太聪明。我最初在公司使用Monorepos的经验强烈地影响了我决定拥有一个简单的构建系统。我完全期望认真的消费者会使用他们自己的构建系统将库提供给他们的monorepo。

在过去的几年里,这一点一直是正确的。但是,随着我完成NNC,并越来越多地将其用于其他封闭源代码的个人项目,为我的个人项目维护封闭源代码的monorepo设置,同时进行上行修复,这是一种相当不愉快的经历。另一方面,NNC从一开始就意味着是一个低级实现。我被期望在某一时刻拥有高级语言绑定。考虑到我现在正在用封闭源码格式的NNC进行更多与应用程序相关的开发,我觉得现在是合适的时机。

尽管C/C++没有一个真正的库分发机制,但也有竞争者。从久负盛名的apt/rpm,到近年来在开源世界获得了一定份额的柯南。

选择巴泽尔并不是偶然的。我一直在和巴泽尔一起做一些SWIFT开发,体验是积极的。此外,我认为为NNC选择高级绑定语言将是SWIFT。

CCV的构建过程(我更希望不是这样)依赖于主机。我使用autoconf检测系统范围的库,如libjpeg和libpng,以配置适当的编译器选项。虽然CCV可以零依赖地使用,但在该配置中,它有时可能很慢。

来自monorepo背景的Bazel没有很多像autoconf那样容易获得的实用程序。您可以在Starlark中编写自动配置作为存储库规则,但是没有很好的文档来说明如何编写健壮的配置。

我最终让使用CCV的人决定如何启用某些功能。对于CUDA这样的东西,这样的配置是站不住脚的。我最终复制了TensorFlow的CUDA规则。

众所周知,老的C/C++库对库依赖性V.S.工具链无关紧要。Autoconf同时检测工具链配置和可用库。这些类型的主机依赖项使交叉编译本身成为一项技能。

Bazel非常适合树内依赖关系。但是,对于树外依赖关系,没有既定的机制。流行的方法是编写存储库规则来加载相关依赖项。

这对我来说真的很管用。它的多功能性足以处理具有Bazel集成和没有Bazel集成的情况。

然后,使用打包的Bazel依赖项变得非常简单,只需将git_pository添加到工作区并调用正确的<;your_library_name>;_deps()存储库规则。

虽然Bazel提供的库分发机制对我的情况运行良好,但它过于简单。首先,确实没有很好的方法来进行语义版本控制。这是可以理解的。由于来自单一文化,任何人都很难深入到库版本控制的依赖地狱中去。前段时间也发生了一个略有不同的故事。

如果您想要固定某个特定版本的库,而您的依赖项不符合您的要求,这是很麻烦的。无论在C/C++世界中,这都将是混乱的,除非您非常仔细地预先链接它们。在我看来,巴泽尔的理念似乎很大程度上在于保持后备箱的工作状态。到目前为止,它正在发挥作用,但人们不得不怀疑,如果更多的图书馆采用Bazel作为分发机制,它是否还能扩大规模。

在过去的几个月里,在巴泽尔的经历是令人愉快的。虽然在使用特定语言进行开发时,我会继续使用特定于语言的工具(pip、go模块、Cargo、NPM),但在进行跨语言开发时,Bazel对我来说是一个有能力的选择。像workspace、git_pository、http_archive这样的概念非常适合更大的开源生态系统。最令人惊讶的是,如果您需要的话,它可以用于多回购设置。