在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),但维护者愿意从其当前的构建系统生成配置文件包
- 操作:我建议帮助他们.例如,这是对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. - (3)并且当前的构建系统运行不正常,或者该库难以使用更广泛的编译器进行构建,或者不支持交叉编译
-
操作:创建一个名为
foo-cmake-buildsystem
的项目(最好在GitHub上),该项目可以通过任一方式构建库
- (1) library
Foo
is not using CMake - (2) and maintainer of
Foo
do not want (or are not ready) to transition to CMake. - (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: create a project (ideally on GitHub) named
foo-cmake-buildsystem
that will allow to build the library by either
- 使用现有源树的路径配置项目
- 让项目为您下载源文件
- 例如,这是为CPython完成的. GitHub上有一个名为
python-cmake-buildsystem
的项目
- configuring the project with the path to an existing source tree
- having the project downloading the source for you
- this is for example done for CPython. There is a project named
python-cmake-buildsystem
available on GitHub
案例5:
- (1)出于任何原因,
Foo
的维护者不想过渡,或者无法维护替代的构建系统,或者系统上已经存在库 - 操作:您可以创建一个
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等)以拥有此类软件包 *(2)或需要为您的项目专门编译If the library
Foo
is: * (1) not available on the system: * or can't be installed using package manager * or working with the community maintaining packages (debian, conda-forge, chocolatey, ...) to have such package is not possible * (2) or need to be compiled specially for your project然后,
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屋!