【问题标题】:Correct way to use third-party libraries in cmake projectcmake项目中使用第三方库的正确方法
【发布时间】:2018-07-27 19:17:14
【问题描述】:

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

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

【问题讨论】:

    标签: cmake libraries


    【解决方案1】:

    回答这个问题需要涵盖几个方面,您会发现以下两个部分:

    • 配置文件包
    • ExternalProject CMake 模块

    配置文件包

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

    配置文件包通常包含FooConfig.cmake、FooConfigVersion.cmake 和FooTargets.cmake 等文件。

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

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

    • 案例一:

      • (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)当前的构建系统运行不好,或者库很难用更广泛的编译器构建,或者不支持交叉编译

      • action:创建一个名为 foo-cmake-buildsystem 的项目(最好在 GitHub 上),允许通过以下任一方式构建库

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

      • (1) 出于任何原因,Foo 的维护者不想转换,或者无法维护替代构建系统,或者系统上已经有库
      • action:您可以创建一个FindFoo.cmake 来创建导入的目标。
        • 此类文件可能特定于您的项目,也可能直接贡献给 CMake
        • 例如FindOpenSSL.cmake、FindGit.cmake、...的情况

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

    ExternalProject CMake 模块

    如果库Foo 是:

    • (1) 在系统上不可用:
      • 或无法使用包管理器安装
      • 或与社区维护软件包(debian、conda-forge、chocolatey 等)合作以拥有此类软件包是不可能的
    • (2) 或者需要专门为你的项目编译

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

    实现这一点的方法很少。

    这是一个运行良好的系统:您可以设置一个 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)
    
    [...]
    

    那么,在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-build和AwesomeProject-build是两个独立的构建树,它们之间的链接 就是上面讨论的配置文件包。

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

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

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

    结论

    还有更多细节,但我希望这能让您更好地了解什么是可能的。

    【讨论】:

      猜你喜欢
      • 2020-06-01
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      • 2014-07-25
      • 2016-12-15
      相关资源
      最近更新 更多