在cmake项目中使用第三方库的正确方法

Phạ*_*ông 4 cmake libraries

我正在研究使用某些第三方库的项目。我可以将它们作为克隆并放入我的项目中,git submodule并用于add_subdirectory在项目中使用它们。但是编译这些库需要很多时间,而且我无法cmake在项目中管理变量,而install()命令使我的程序包包含了许多我不需要的东西。

那么在我的项目中使用第三方库的正确方法是什么。我不能告诉客户端将这些库安装为我项目的依赖项。

J-C*_*phe 14

回答此问题需要涵盖几个方面,您将在以下两个部分中找到:

  • 配置文件包
  • ExternalProject CMake模块

配置文件包

如果要集成不在项目范围内的库,则第一步是确保所有库都提供配置文件包。

配置文件包通常包含FooConfig.cmakeFooConfigVersion.cmake和等文件FooTargets.cmake

一般来说,如果该库Foo已经在使用CMake并且已经提供了config-file包,则配置项目时将-DFoo_DIR:PATH=/path/to/build-or-install-dir/允许您find_package(Foo REQUIRED)从自己的项目中调用。这将导入CMake目标,您可以针对自己的库或可执行文件进行链接。

现在,如果库Foo尚未使用CMake,则有以下选项:

  • 情况1:

    • (a)库Foo已经在使用CMake
    • (b)但提供配置文件包
    • 行动:我建议改善他们的建造系统
  • 情况2:

    • (1)库Foo使用的CMake
    • (2)的维护者Foo愿意过渡到CMake(或至少拥有CMakeLists.txt当前的构建系统)
    • 行动:我建议改善他们的建造系统
  • 情况3:

    • (1)库Foo使用的CMake
    • (2)Foo不想迁移到CMake的维护者
    • (3)但维护者愿意从当前的构建系统生成配置文件包
    • 行动:我建议帮助他们。例如,这是对Qt5所做的事情,现在它提供了一个配置文件包。
  • 情况4:

    • (1)库 Foo使用的CMake
    • (2)的维护者Foo不希望(或尚未准备好)过渡到CMake。
    • (3)并且当前的构建系统运行不正常,或者该库难以使用更广泛的编译器进行构建,或者不支持交叉编译
    • 动作:创建一个项目(最好在GitHub上)foo-cmake-buildsystem,该项目将允许通过以下任一方式来构建库

      • 使用现有源树的路径配置项目
      • 让项目为您下载源代码
      • 例如,这是为CPython完成的。python-cmake-buildsystemGitHub上有一个可用的项目
  • 情况5:

    • (1)出于任何原因,其维护者Foo不希望过渡,或者无法维护替代构建系统,或者系统上已经存在库
    • 行动:您可以创建一个FindFoo.cmake将创建导入目标的。
      • 这样的文件可能特定于您的项目,也可以直接贡献给CMake。
      • 这是例子的情况下FindOpenSSL.cmakeFindGit.cmake...

要了解有关配置文件包的更多信息,请参见https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html

ExternalProject CMake模块

如果该库Foo是:*(1)在系统上不可用:*或无法使用软件包管理器安装*或与社区维护软件包(debian,conda-forge,chocolatey等)一起工作以拥有此类软件包*(2)或需要针对您的项目专门编译

然后,ExternalProjectCMake模块将允许您从自己的项目中下载,配置,构建...这些项目。

很少有办法做到这一点。

这是一个运行良好的系统:您可以设置一个称为我们的2级构建系统:SuperBuild

为了支持该SuperBuild方法,您的CMakeLists.txt可以具有以下结构:

project(AwesomeProject)

[...]

option(Awesome_ENABLE_EXTRA "Enable more awesome stuff" OFF)

option(AwesomeProject_SUPERBUILD "Build ${PROJECT_NAME} and the projects it depends on." ON)

[...]

if(AwesomeProject_SUPERBUILD)
  include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake")
  return()
endif()

find_package(Foo REQUIRED)

add_library(AwesomeLib ....)
target_library_libraries(AwesomeLib PUBLIC Foo)

[...]
Run Code Online (Sandbox Code Playgroud)

然后,在文件中,SuperBuild.cmake您将大致执行以下两个调用:

ExternalProject_Add(Foo
  GIT_REPOSITORY "git://github.com/Foo/Foo"
  GIT_TAG "123456"
  SOURCE_DIR ${CMAKE_BINARY_DIR}/Foo
  BINARY_DIR ${CMAKE_BINARY_DIR}/Foo-build
  CMAKE_CACHE_ARGS
    -DFOO_ENABLE_BAR:BOOL=1
  INSTALL_COMMAND ""
  )


ExternalProject_Add(AwesomeProject
  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
  BINARY_DIR ${CMAKE_BINARY_DIR}/AwesomeProject-build
  DOWNLOAD_COMMAND ""
  UPDATE_COMMAND ""
  CMAKE_CACHE_ARGS
    -Foo_DIR:PATH=${CMAKE_BINARY_DIR}/Foo-build
    -DAwesome_ENABLE_EXTRA:BOOL=${Awesome_ENABLE_EXTRA}
  INSTALL_COMMAND ""
  )
Run Code Online (Sandbox Code Playgroud)

这意味着您现在可以在子目录中找到常规的构建树AwesomeProject-build

请注意,Foo-buildAwesomeProject-build是两个独立的构建树,它们之间的链接是上面讨论的config-file程序包。

通过AwesomeProject使用-Foo_DIR:PATH=${CMAKE_BINARY_DIR}/Foo-build 和调用配置子项目,可以实现这一点find_package(Foo REQUIRED)

如果使用VisualStudio之类的工具,则可以打开在任何这些子目录中找到的解决方案文件。

要了解有关外部项目的更多信息:https : //cmake.org/cmake/help/latest/module/ExternalProject.html

结论

还有更多细节,但是我希望这可以使您更好地了解可能的情况。

  • “我建议改进他们的构建系统”完全没有帮助,并且没有提供任何有关如何补救这种情况的信息......这怎么会是热门搜索结果? (8认同)