我应该为外部库提供 CMakeLists.txt 还是提供 find_packages?

Should I supply external libraries with a CMakeLists.txt or supply find_packages instead?

我正在做一个需要一些外部库的项目。因为是跨平台的,所以我用的是cmake。

分发此类项目的首选方式是什么?我应该为外部库(例如 zlib)提供它们自己的 CMakeLists.txt 还是应该通过简单地提供 find_packages()?

来表示依赖关系

前者应有尽有。而后者让开发人员决定如何提供依赖项(例如 vcpkg)

虽然没有普遍首选方法,但我绝对相信您应该坚持find_package。像这样声明你的依赖关系:

find_package(Pkg [version] REQUIRED [components])

仅当您知道 Pkg 本身提供 first-party CMake 包配置文件时,才包含 [version][components]。如果您正在编写和分发库,您将在 MyProjConfig.cmake 文件中包含等效的 find_dependency 调用。

如果某些依赖项没有标准的 CMake 查找模块或提供自己的 CMake 包配置文件,您应该在 ./cmake 中编写自己的并在根 CMakeLists.txt 中添加 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") ],在任何 find_package 调用之前。您也将安装您的查找模块,并在您的配置文件中的模块路径中添加相同的内容。

在查找模块中,您可以使用任何您想要的方法为您的依赖项创建一些导入的目标。使用 PkgConfig 是一个很好的方法。

通过 find_package 立即与许多依赖项提供程序一起工作:vcpkg、cmake_paths Conan 生成器、Linux 发行版系统包,等等。


这样做的主要替代方法是供应代码,这意味着直接将您的依赖项包含在您的构建中,无论是通过 copy/paste 到您的源代码树、git 子模块,还是通过 build-time 从网上下载 (FetchContent).

用于构建这些的机制几乎总是 add_subdirectory 最后,它将您的依赖项的 CMake 构建引入您的。

也许最大的问题是大多数项目的 CMake 代码完全没有准备好以这种方式使用。它可能会破坏您的缓存变量,将无效标志注入您的目标,覆盖您生成的 headers,等等。集成是一场噩梦。

此外,从软件分发的角度来看,这样做会将您的代码绑定到特定版本的依赖项,并从可能想要打包您的代码的其他人手中夺走控制权。例如,Debian 包不允许捆绑它们的依赖项...如果 libA 依赖于 libB,那么每个包都会得到自己的包。使用 find_package,维护者将适当的依赖项注入到您的构建中是微不足道的。如果没有,它通常涉及 difficult-to-maintain 补丁。