【问题标题】:Physical layout on disk of large cross-platform C++ project with many third party dependencies具有许多第三方依赖项的大型跨平台 C++ 项目的磁盘物理布局
【发布时间】:2013-11-06 04:10:26
【问题描述】:

我正在重新组织 large cross-platform C++ project 的物理(磁盘上)布局,其中包含许多第三方依赖项,使用 CMake 构建。

由于我们需要支持 Windows,一个没有完善的包管理器的平台,我们很久以前就决定在源代码树中包含我们依赖的第三方库。但是,在我们支持的其他平台(例如 Linux 和 Mac OS X)上,这些第三方库中的许多都以包的形式提供,或者已经存在于系统中,并且可以通过 CMake 轻松找到。

目前项目布局如下:

root/
    src/
        3rd-party-lib1/       (build system modified to output to build/)
        3rd-party-lib2/       (build system modified to output to build/)
        project-module1/      (our own code)
        project-module2/      (our own code)
    build/                    (CMake is invoked from here)
        3rd-party-lib1-bin/
        3rd-party-lib2-bin/

第三方库已经过调整,以便在构建时将二进制文件输出到root/build/<lib>/

这种布局的问题是多方面的:

  • 第三方库不再是 100% 原创。这使得更新它们比要求的要困难一些。
  • src/ 目录包含我们自己的代码和第三方代码的混合体,令人困惑。
  • src/ 目录非常大。因为src/ 包含第三方库,与实际的原始源代码量相比,它非常大,使得备份我们自己的代码比需要的要复杂一些(我们不能再归档整个src/ 目录)。
  • 项目存储库 (Git) 非常大,由于包含第三方库(其中可能包含大量非源文件,例如文档、测试数据等),以及 每次我们更新它们时它都会变大。不幸的是,没有办法回到这里,除非我们决定使用新的存储库重新启动(不幸的是丢失了整个提交历史记录)。
  • 在 Linux 或 Mac OS X 上构建项目的用户根本不需要其中许多包含的第三方库(例如 zlib、libpng),尽管它们极大地简化了 Windows 用户的操作。

另一种布局如下:

root/
    3rdparty/
        3rd-party-lib1/       (100% original, contains built artifacts)
        3rd-party-lib2/       (100% original, contains built artifacts)
    src/
        project-module1/      (our own code)
        project-module2/      (our own code)
    build/                    (CMake is invoked from here)

需要修改我们的 CMake 文件,以便在每个库的正确位置查找第三方头文件和库。

在原生跨平台项目中处理第三方库的最佳做法是什么?哪种布局会为我们的开发人员在各自的平台上带来最出人意料的构建体验?也欢迎现有项目中成功布局的具体示例。

【问题讨论】:

  • 也许 Windows 的数据包管理器可以解决这个问题。我尝试自己构建一个:vertexwahn.de/bluego.html - 现在只支持 boost 和 Qt。在我自己的项目中,我使用混合方法 - Boost、Qt、OptiX、Cuda、Windows SDK 假定由用户安装 - 其他库(如 gtest、OpenEXR、zlib、freetype、glews 等)随源代码一起提供。
  • 感谢您的意见。我们还希望用户已经在他们的机器上安装了 Qt 和 Boost。我真正关心的是其他较小且鲜为人知的库,例如 ILMBase、OpenEXR、Alembic、zlib、libpng 等。
  • 刚刚发现 NuGet for C++:blogs.msdn.com/b/vcblog/archive/2013/04/26/nuget-for-c.aspx。一些库已经支持:nuget.org/profiles/coapp 但我没有实践经验。
  • 为什么不为 Windows 构建 FindPackage.cmake 文件并使用 CMAKE_MODULE_PATH?这样,您可以使用 find_package 编写“标准”CMakeLists.txt,并可以通过迁移 FindPackage.cmake 将您的第 3 方库迁移出项目?
  • 这是一个有趣的想法,安德烈。到目前为止,我已将所有第三方库移动到顶级 3rdparty/libs/ 目录中;我将它们全部构建到位,并指示 CMake 将它们“安装”在 3rdparty/install/ 目录中。您的建议可能允许简化我自己的 CMakeLists.txt 文件。

标签: c++ build cmake cross-platform organization


【解决方案1】:

我的经验建议以下最佳做法:

  • 当完全按原样使用第三方开源库时,在主 git 存储库中提交下载的压缩 tarball 的本地副本,以避免网络连接问题阻止软件构建。

  • 当第三方开源库几乎按原样使用,但需要调整时(这个 交叉编译时很常见:许多包需要对其配置步骤进行轻微调整),将压缩的 tarball 和“统一差异”补丁文件存储在主 git repo 中,并在 ExternalProject_Add 的 PATCH_COMMAND 步骤中应用补丁。

  • 当您的组织(将)对第三方开源库进行大量修改或扩展时,请使用单独的 git 存储库来保存指向上游存储库的指针(当它也使用 git 时最简单,但上游svn 也可以管理)。将组织的更改提交到与用于镜像上游的分支不同的分支。如果你愿意,你可以在主 git repo 和这个之间引入子模块关系,虽然因为 DOWNLOAD_COMMAND 可以直接从任意 git repo 获取,所以技术上没有必要这样做。

  • 通过将它们归档在主 git 存储库中来处理单个目标平台的小型、不常见的第三方专有二进制文件是合理的。但是,可用于各种平台、较大或经常演变的第三方二进制文件应存储在自己的 git 存储库中,并通过 DOWNLOAD_COMMAND 获取,如上所述。

【讨论】:

  • +1,但恕我直言,无需将 tarball/二进制文件提交到主 git repo。为什么不简单地制作发布快照并使用 ExternalProject_Add 从自定义位置下载它?
  • 根据具体情况,这可能是一个合理的替代方案——甚至仅使用 ExternalProject_Add_Step 就足够了。但是,存在一个严重的风险,即如何构建快照的知识会随着时间的推移而丢失。为了防止这种情况,以一致可重复的形式捕获快照生成过程非常重要。但是,除非这个过程真的很耗时,否则将生成它的算法与生成主构建的算法分开是没有价值的。
  • 感谢@newbrific 的出色回答!为了不阻止其他贡献者分享他们的想法和经验,我将把这个问题留得更久。
猜你喜欢
  • 2013-12-21
  • 1970-01-01
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 2016-11-16
  • 2011-02-03
  • 2011-06-16
相关资源
最近更新 更多