处理外部C++依赖关系



我们过去使用的项目结构是代码+预构建外部依赖项在SVN中受源代码控制。这很麻烦,因为外部库很大,不需要进行源代码管理,因为它们是预构建的二进制文件。

现在我们在git中有了源代码,预构建的二进制文件在云中。在克隆repo之后,开发人员必须从云中下载这个lib文件夹。这里的问题是,如果您对lib进行了更改,那么在开发人员重新下载这个lib文件夹之前,事情将无法正确构建。

我们的项目通常是为Windows(MSVC)开发的,但我们只是添加了Linux(GCC+Docker)兼容性,未来可能会以Linux为主要版本。所以现在我们的每个库都有一个Windows和一个Linux构建文件夹。我们的开发环境是Windows+VSCode/WSL2/Docker for Linux。

处理外部依赖关系的最佳、常见做法是什么。我能想出两种方法。

  • 对云中的lib文件夹进行版本设置,并在构建过程中进行检查。如果开发人员A添加/更改了它并更新了CMakeLists文件,那么当开发人员B更新他的git repo并尝试构建时,CMake可以看到他拥有的libs文件夹的版本已经过时,并会被告知去更新它。这只是一点小小的努力,几乎没有改变我们的过程。缺点是开发人员A必须记住在云中和cmake检查中更新版本
  • 在本地构建所有外部库。使用git子模块并让cmake在构建主项目时构建所有依赖项。我认为有一种方法可以缓存它,这样它就不会不断重建(其中一些库很大,需要很长时间才能构建)。更多的工作,但更少的维护和需要额外的开发步骤。也可能更容易链接和包括反对

这里的问题是,如果您对lib进行更改,那么在开发人员重新下载这个lib文件夹之前,事情将无法正确构建。

清楚地表明,您想要使用的确切版本是您应该与源代码一起跟踪的内容的一部分。

我认为有一种方法可以缓存它,这样它就不会不断重建(其中一些库很大,需要很长时间才能构建)

只要文件没有更改,就不需要重新生成任何内容。

所以,是的,如果你的项目依赖于特定的外部库,git子模块听起来确实很有吸引力。

还要注意的是,其他构建系统(如介子)对树内依赖项项目有着更清晰的理解,可以检查您的系统是否有依赖项的安装版本,如果没有合适的版本,请下载,如果必要,可以自行构建。

因此,正如您所说,第二种选择可能是最容易维护的解决方案。

I、 然而,它来自一个免费和开源的背景,我的用户和他们的平台是多样化的,Linux发行版有严格的指导方针,不打包相同依赖项的N个副本。因此,这将使此类软件包更难上游到debian、Ubuntu、Fedora、Arch。所以,对我来说,情况是这样的:如果有一个库我们想在项目中使用,我们会非常清楚地定义该库的最旧版本是什么。在一个发布周期内,我们不能更改所需的版本。

比如说,我们已经发布了一些软件的2.0.0版本。CMake文件定义了我们支持的库的哪个版本"释放";软件意味着我们向开发者和用户保证,2.a.b系列中的下一个错误修复/功能扩展版本仍然构建在相同的系统上,其中包括可能安装在那里的相同库。因此,如果2.0.0是在您的计算机上构建的,那么2.0.1和2.9.0也是如此。需要新版本的外部依赖项的开发只能在git分支上进行,该分支不适用于2.a.b的后续版本,而是针对最终的3.0.0版本。在为3.0.0版本选择最低依赖版本时,我们会查看我们支持的操作系统上常见的版本。例如,如果我的时间表是3.0.0将在2022年或2023年内发布,那么该版本将是Ubuntu 22.04LTS中可用的版本(因为在很长一段时间内,这对我们的用户来说将是一个重要的系统,而且相对保守),还考虑到debian版本最有可能是当前不稳定的(或稳定的,取决于你的目标受众是什么),RHEL版本,下一个Fedora,以及目前在我们的condafurge和macports repos中可用的内容。

无论如何,通过这些标准包装渠道无法获得的所有可容忍版本都需要在本地构建。事实证明,如果你不是疯狂的进步,也不试图支持已有5年历史的Linux,那么你需要在本地构建的项目数量就很少了。

在windows上,微软无法提供一种真正合理的方式来下载二进制共享库包,而这些二进制共享库实际上是在不同的应用程序软件之间共享的,这基本上阻碍了你的工作。因此,在Windows系统上,您要么在本地进行所有构建,要么使用第三方方式分发依赖于平台的软件包,比如Conan。

无论你怎么做,你都会让你的构建尽早失败,并清楚地表明找到的库版本还不够新。CMake让这一切变得容易;其CCD_ 1命令采用最小版本作为参数。

最新更新