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

时间:2018-07-27 19:17:14

标签: cmake libraries

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

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

1 个答案:

答案 0 :(得分:9)

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

  • 配置文件包
  • ExternalProject CMake模块

配置文件包

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

配置文件包通常包含FooConfig.cmakeFooConfigVersion.cmakeFooTargets.cmake之类的文件。

通常来说,如果库Foo已在使用CMake并已提供配置文件包,则使用-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),当前的构建系统运行不正常,或者该库难以使用更广泛的编译器进行构建,或者不支持交叉编译
    • 操作:创建一个名为foo-cmake-buildsystem的项目(最好在GitHub上),该项目可以通过任一方式构建库

      • 使用现有源树的路径配置项目
      • 让项目为您下载源代码
      • 例如,这是为CPython完成的。 GitHub上有一个名为python-cmake-buildsystem的项目
  • 案例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)或需要为您的项目专门编译

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

很少有办法做到这一点。

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

要支持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)

[...]

然后,在文件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 ""
  )

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

请注意,Foo-buildAwesomeProject-build是两个独立的构建树,它们之间的链接 是上面讨论的配置文件包。

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

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

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

结论

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

相关问题