Conan 在工作中
这是一篇来自德国莱茵金属防务电子公司 Nils Brinkmann 的客座文章。如果您有任何关于本文的问题,可以通过 LinkedIn 联系他。
Conan 在工作中
几个月前,我们抓住机会,围绕 Conan 重塑了我们的开发环境。Conan 的理念和想法在开源世界中运作良好,但关于如何在闭源环境中集成它的信息并不多。在这篇文章中,我想概述我们做了什么以及我们为什么这样做。
莱茵金属防务电子公司在国防领域雇佣了 1000 多名开发人员。我在一个由 5 名开发人员组成的团队中工作,负责将 3D 引擎集成到模拟器中。我们的项目范围从几百个工时到跨越数年、价值数百万美元的项目。我们目前仅在我们团队内部使用 Conan,但计划至少将其推广到整个部门,覆盖 150 多名开发人员。
组件结构
我们的代码库包含 200 多个小型组件,每个组件都有其指定的任务。它们有时只有不到 100 行代码,大多数组件平均约有 1000 行代码。所有这些组件都相互依赖。这就是 Conan 对我们帮助最大的地方:与其使用自行编写的机制来解决依赖关系树,我们现在可以使用 Conan 自动按正确的顺序构建所有必需的内容。
我们将每个组件设置在自己的存储库中:除了源代码之外,还有一个简单的 CMakeFile.txt
和一个 conanfile.py
。能够使用基于 Python 的构建机制也有助于克服另一个大问题:CMake 虽然很酷,但你不想在其中进行脚本编写。现在,我们能够直接在 Conanfile 中执行更复杂的任务(例如代码生成),而不是依赖于 CMake 的魔法。
模板
除了少数例外,我们的大多数组件结构都非常简单。90% 的 Conanfile 看起来都一样,因此我们认为最好使用某种模板。Conan 允许通过继承来实现这一点。
这样做将大部分逻辑(如 build()
、export()
或 package_info()
)保留在模板中,而组件 Conanfile 仅包含特定信息,如依赖项或版本号。这也很容易维护:如果我们想在构建机制中添加一些内容,只需修改一个文件即可。以下是如何使用组件 Conanfile 的示例
from conans import ConanFile, CMake
import ConanTemplate
class SpecificConanfile(ConanTemplate):
name = "Bing"
version = "1.0.12.56d8f23a"
author = "John Doe"
def requirements(self):
self.requires("Foo/1.0.1.d5ee9fad@rde/release")
self.requires("Baz/1.0.0.ad681ab5@rde/release")
self.requires("Frob/1.0.8.be290a40@rde/release")
发布策略
在我们的旧环境中,我们只是将所有内容都放在一个大型存储库中。这非常单一,但在依赖项方面也很容易维护:我们只需要确保存储库中的所有内容在提交新的代码更改之前都能相互协作即可。然而,其不灵活的特性限制了我们的扩展能力。现在,Conan 使以前会是一项繁琐的任务成为可能:在维护组件依赖关系的同时,将所有内容都管理在小型模块化存储库中。
为了将所有内容整合在一起,我们引入了以下发布策略
- 每个组件都需要与其他组件的 HEAD 版本兼容
- 每个组件都需要依赖于其他组件的特定发布版本
- 每个组件都应使用其依赖项的最新版本。
这导致我们的组件位于两个 Conan 通道中
component/HEAD@rde/CI
:此通道用于每个组件的最新版本。一旦 CI 能够构建新的提交,它就会将组件上传到该通道。component/major.minor.patch.commit@rde/release
:这是发布通道,其中仅包含我们组件的发布版本。其背后的 CI 机制可能足够复杂,可以单独撰写一篇博文来介绍 - 本质上,只有与所有依赖项及其依赖方兼容的组件才会发布,从而确保仅发布兼容的组件。
> conan search *
Foo/1.0.1.26e92cb8@rde/release
Bar/2.1.15.84145ecb@rde/release
Baz/1.5.0.00cf1aa4@rde/release
Foo/HEAD@rde/CI
Bar/HEAD@rde/CI
Baz/HEAD@rde/CI
Boost/1.59.0@rde/thirdparty
ZMQ/4.1.1@rde/thirdparty
Protobuf/2.6.1@rde/thirdparty
第三方
现代软件建立在像 Boost、ZeroMQ 和 Protobuf 这样的巨人的肩膀上 - 我们的软件也不例外。在这种情况下,与开源世界的区别在于,公司不希望依赖于 Github 或 Sourceforge 等外部资源。这导致第三方软件在内部托管,以便在需要时始终可以使用源代码。当然,我们尽可能地提供帮助,在任何时候提供输入、反馈和补丁。在某些情况下,我们修改了 Conan 食谱以使用特定组件的内部版本,在其他情况下,我们创建了我们自己需要的东西。
下一步是什么?
所述系统已使用了几周,我们对其结果非常满意。我们不再使用不灵活的单一存储库,而是拥有一个灵活的、由具有单一用途的组件组成的集合,这些组件可以相互协作。但是,我们远未完成,我可以保证,在实际使用中,它将带来大量的优化。以下是我将来希望解决的一些主题
基础设施
这是我们尚未做太多工作的一部分。目前,我们仅使用一个简单的 Conan 服务器来处理所有事情。由于 Conan 的去中心化结构,我们可以通过添加更多服务器轻松地扩展它。我们已经考虑过备份服务器、弃用组件的服务器或本地开发人员服务器(在无法连接到公司网络的情况下)。
部署
我们目前正在讨论如何使用 Conan 部署我们的组件。以可重复的方式将我们的软件部署到生产系统是一项重大挑战。自动化执行此操作将改善开发人员、测试人员以及最终客户的生活。也许这是未来博文的不错主题。
使我们的东西过时
Conan 非常年轻,并且每天都在改进。我们不得不创建一些自定义脚本,这些脚本在将来希望不再需要。我们正在努力提出功能请求并在任何时候提供反馈。
广而告之
Conan 已经获得了一些势头,但越多越好。看看 Nuget 或 Pip 就能了解可能实现的目标。对于任何 C++ 开发人员来说,只需一个 conan install
就能获取所有内容,这将是一个梦想成真。