cmake项目中使用第三方库的正确方法 [英] Correct way to use third-party libraries in cmake project
问题描述
我正在处理使用一些第三方库的项目.我可以将它们作为 git submodule
克隆并放入我的项目中,并使用 add_subdirectory
在我的项目中使用它们.但是编译这些库需要很多时间,而且我无法在我的项目中管理 cmake
变量,并且 install()
命令使我的包包含许多我不知道的东西'不需要.
I'm working on project that use some third-party libraries. I can clone and put them into my project as a git submodule
and use add_subdirectory
to use them in my project. But it take much time to compile these libs, and I can not manage cmake
variables in my projects, and install()
command make my package contains many things that I don't need.
那么在我的项目中使用第三方库的正确方法是什么.我不能告诉客户端安装这些库作为我项目的依赖项.
So what is correct way to use third-party libraries in my project. I can not tell the client to install these libraries as dependencies of my project.
推荐答案
回答这个问题需要涉及几个方面,你会发现以下两个部分:
Answering this question requires to cover few aspects, you will find below two sections:
- 配置文件包
- ExternalProject CMake 模块
如果您正在寻找不在项目范围内构建的集成库,第一步是确保这些库都提供了一个配置文件包.
If you are looking into integrating libraries that are not built within the scope of your project, the first step is to make sure the libraries all provide a config-file package.
一个配置文件包通常包括FooConfig.cmake
、FooConfigVersion.cmake
和FooTargets.cmake
等文件.
A config-file package usually include files like FooConfig.cmake
, FooConfigVersion.cmake
and FooTargets.cmake
.
一般来说,如果库 Foo
已经在使用 CMake 并且已经提供了一个配置文件包,那么使用 -DFoo_DIR:PATH=/path/to/build-or 配置你的项目-install-dir/
允许您从自己的项目中调用 find_package(Foo REQUIRED)
.这将导入您可以链接到您自己的库或可执行文件的 CMake 目标.
Generally speaking, if the library Foo
is already using CMake and already provide a config-file package, configuring your project with -DFoo_DIR:PATH=/path/to/build-or-install-dir/
allow you to call find_package(Foo REQUIRED)
from your own project. This will import CMake targets that you can link against your own libraries or executables.
现在,如果库 Foo
尚未使用 CMake,则有以下选项:
Now if the library Foo
is not already using CMake, there are options:
案例 1:
Case 1:
- (a) 库
Foo
已经在使用 CMake - (b) 但不提供配置文件包
- 行动:我建议改进他们的构建系统
- (a) library
Foo
is already using CMake - (b) but do NOT provide a config-file package
- action: I suggest to improve their build system
情况 2:
- (1) 库
Foo
未使用 CMake - (2) 和
Foo
的维护者愿意过渡到 CMake(或者至少将CMakeLists.txt
与他们当前的构建系统一起使用) - 行动:我建议改进他们的构建系统
- (1) library
Foo
is not using CMake - (2) and maintainer of
Foo
are willing to transition to CMake (or at least have theCMakeLists.txt
along side their current build system) - action: I suggest to improve their build system
情况 3:
- (1) 库
Foo
未使用 CMake - (2) 和
Foo
的维护者不想过渡到 CMake - (3) 但维护者愿意从他们当前的构建系统生成配置文件包
- action:我建议帮助他们.例如,这是为 Qt5 所做的,它现在提供了一个配置文件包.
- (1) library
Foo
is not using CMake - (2) and maintainer of
Foo
do not want to transition to CMake - (3) but maintainer are willing to generate config-file package from their current build system
- action: I suggest to help them. This is for example what was done for Qt5, it now provides a config-file package.
案例 4:
(1) 库
Foo
不 使用 CMake
(2) 和 Foo
的维护者不想(或还没准备好)过渡到 CMake.
(2) and maintainer of Foo
do not want (or are not ready) to transition to CMake.
(3) 并且当前的构建系统运行不佳,或者库难以用更广泛的编译器构建,或者不支持交叉编译
(3) and the current build system is not working well, or the library is difficult to build with a wider range of compiler, or does not support cross-compilation
action:创建一个名为 foo-cmake-buildsystem
的项目(最好在 GitHub 上),该项目将允许通过以下任一方式构建库
action: create a project (ideally on GitHub) named foo-cmake-buildsystem
that will allow to build the library by either
- 使用现有源代码树的路径配置项目
- 让项目为您下载源代码
- 例如,这是为 CPython 完成的.GitHub 上有一个名为
python-cmake-buildsystem
的项目
案例 5:
- (1) 出于任何原因,
Foo
的维护者不想转换,或者无法维护替代构建系统,或者系统上已有库 - action:您可以创建一个
FindFoo.cmake
来创建导入的目标.- 此类文件可以特定于您的项目,也可以直接贡献给 CMake
- 例如
FindOpenSSL.cmake
、FindGit.cmake
、...
- (1) for any reason the maintainer of
Foo
do not want to transition, or maintaining an alternative build system is not possible, or library is already available on the system - action: You could create a
FindFoo.cmake
that would create imported targets.- such file could be specific to your project or could be contributed to CMake directly
- this is for example the case of
FindOpenSSL.cmake
,FindGit.cmake
, ...
要了解有关配置文件包的更多信息,请参阅 https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html
To learn more about config-file package, see https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html
如果库
Foo
是:- (1) 在系统上不可用:
- 或无法使用包管理器安装
- 或者与维护软件包(debian、conda-forge、chocolatey 等)的社区合作来拥有这样的软件包是不可能的
然后,
ExternalProject
CMake 模块将允许您从您自己的项目中下载、配置、构建...这些项目.Then, the
ExternalProject
CMake module will allow you to download, configure, build ... these projects from within your own project.实现这一目标的方法很少.
There are few approaches to make this happen.
这是一个运行良好的系统:您可以设置一个 2 级构建系统,我们称之为:
SuperBuild
.Here is one that has been working well: You could setup a 2-level build system that we call:
SuperBuild
.为了支持
SuperBuild
方法,您的 CMakeLists.txt 可以具有以下结构:To support the
SuperBuild
approach, your CMakeLists.txt could have the following structure: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
中,您将大致有以下两个调用:Then, in the file
SuperBuild.cmake
you would roughly have these two calls: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
中找到通常的构建树.This means that you usual build tree will now be found in the subdirectory
AwesomeProject-build
.注意
Foo-build
和AwesomeProject-build
是两个独立的构建树,它们之间的链接是上面讨论的配置文件包.Note that
Foo-build
andAwesomeProject-build
are two independent build tree, the link between them is the config-file package discussed above.这可以通过使用
-Foo_DIR:PATH=${CMAKE_BINARY_DIR}/Foo-build
配置AwesomeProject
子项目来实现和调用find_package(Foo REQUIRED)
.This is made possible by configuring
AwesomeProject
sub project with-Foo_DIR:PATH=${CMAKE_BINARY_DIR}/Foo-build
and the callingfind_package(Foo REQUIRED)
.如果您使用 VisualStudio 之类的工具,您可以打开任何这些子目录中的解决方案文件.
If you use tools like VisualStudio you can open the solution file found in any of these sub-directory.
要了解有关外部项目的更多信息:https://cmake.org/cmake/help/latest/module/ExternalProject.html
To learn more about external project: https://cmake.org/cmake/help/latest/module/ExternalProject.html
还有更多细节,但我希望这能让您更好地了解什么是可能的.
There are many more details, but I hope this will allow you to get a better understanding of what is possible.
这篇关于cmake项目中使用第三方库的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!