在 CMake 中导出第三方静态库依赖项的惯用方法是什么?
What is the idiomatic way to export a 3rd party static library dependency in CMake?
我有以下使用 Abseil in a library: (minimal repository to reproduce)
的简化 CMake 代码
cmake_minimum_required(VERSION 3.20)
project(MyProject)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
set(ABSL_PROPAGATE_CXX_STD ON)
find_package(absl REQUIRED)
add_library(MyStaticLibTarget STATIC MyStaticLib.cpp)
target_link_libraries(MyStaticLibTarget absl::strings)
install(TARGETS MyStaticLibTarget EXPORT MyProjectTargets)
install(TARGETS strings EXPORT MyProjectTargets)
if(EXPORT_MYSTATICLIB)
export(TARGETS MyStaticLibTarget FILE lib/cmake/MyProject/MyProjectTargets.cmake)
endif()
# Setup for downstream clients of MyProject?
install(EXPORT MyProjectTargets DESTINATION lib/cmake/MyProject COMPONENT cmake-exports)
但是,如果我尝试使用 export
代码路径,我 运行 会出现错误,当 运行ning CMake 时:
cmake -G Ninja -S . -B build -DABSL_ENABLE_INSTALL=ON -DEXPORT_MYSTATICLIB=ON
# CMake Error in CMakeLists.txt:
# export called with target "MyStaticLibTarget" which requires target
# "strings" that is not in any export set.
我不明白错误信息;在我看来 strings
已经是 MyProjectTargets
的一部分(我认为这是一个导出集?),所以不应该有任何错误。
也就是说,根据错误消息,我尝试为 strings
添加一个 export
行,并通过传递修复了所有错误,最后我得到了
export(TARGETS
strings
strings_internal
type_traits
base
config
throw_delegate
dynamic_annotations
log_severity
base_internal
raw_logging_internal
atomic_hook
core_headers
spinlock_wait
endian
bits
int128
memory
errno_saver
meta
APPEND FILE lib/cmake/MyProject/MyProjectTargets.cmake)
确实修复了所有错误!在实践中,对于较大的图书馆来说,这将是非常痛苦的。这似乎也是“错误”的解决方案,因为我手动命名了 Abseil 的许多内部细节。
- 如上所述手动添加目标是“正确”的解决方案吗?
- 有没有更好的方法可以达到和上面一样的效果?
我有以下限制:
- 我需要导出
MyStaticLibTarget
以便下游客户端使用。
- 我很确定依赖项(在
target_link_libraries
中)需要是 public,因为在实际情况中(这是一个最小的例子),Abseil headers 将是包含在图书馆的 public headers.
TLDR: 遵循柯南文档,尤其是 cmake_find_package docs and skim the cheatsheet.
按照@Tsyvarev 在评论中的建议,我使用了不同的设置并完成了这项工作,您可以在 conan 分支中看到最终结果。
步骤如下:
- 使用 Conan 下载并安装 Abseil,使用本地项目
conanfile.txt
。现在,“安装”是一个可怕的词(我不想修改全局状态),但 Conan 本质上只是缓存源和构建工件,这意味着您可以在不同目录中拥有相同库的多个版本,并且不同的项目可以使用这些不同的版本,它应该“正常工作”。 (至少,这是我目前的基本理解。)
[requires] # Which 3rd party conan packages we are using
abseil/20210324.2
[generators] # How to create build system files that capture the dependency information
cmake_find_package
cmake_paths
有了上面的配置,柯南就可以运行了:
conan install . --install-folder build/conan
# Bunch of CMake files will be available under build/conan
- 通过向
CMakeLists.txt
添加一行,将 CMake 指向 Conan 生成的文件。
include("${CMAKE_BINARY_DIR}/conan/conan_paths.cmake")
- 使用CMake正常配置。
cmake -G Ninja -S . -B build -DEXPORT_MYSTATICLIB=ON
(不再需要 ABSL_ENABLE_INSTALL
option is handled by Conan 和。)
我有以下使用 Abseil in a library: (minimal repository to reproduce)
的简化 CMake 代码cmake_minimum_required(VERSION 3.20)
project(MyProject)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
set(ABSL_PROPAGATE_CXX_STD ON)
find_package(absl REQUIRED)
add_library(MyStaticLibTarget STATIC MyStaticLib.cpp)
target_link_libraries(MyStaticLibTarget absl::strings)
install(TARGETS MyStaticLibTarget EXPORT MyProjectTargets)
install(TARGETS strings EXPORT MyProjectTargets)
if(EXPORT_MYSTATICLIB)
export(TARGETS MyStaticLibTarget FILE lib/cmake/MyProject/MyProjectTargets.cmake)
endif()
# Setup for downstream clients of MyProject?
install(EXPORT MyProjectTargets DESTINATION lib/cmake/MyProject COMPONENT cmake-exports)
但是,如果我尝试使用 export
代码路径,我 运行 会出现错误,当 运行ning CMake 时:
cmake -G Ninja -S . -B build -DABSL_ENABLE_INSTALL=ON -DEXPORT_MYSTATICLIB=ON
# CMake Error in CMakeLists.txt:
# export called with target "MyStaticLibTarget" which requires target
# "strings" that is not in any export set.
我不明白错误信息;在我看来 strings
已经是 MyProjectTargets
的一部分(我认为这是一个导出集?),所以不应该有任何错误。
也就是说,根据错误消息,我尝试为 strings
添加一个 export
行,并通过传递修复了所有错误,最后我得到了
export(TARGETS
strings
strings_internal
type_traits
base
config
throw_delegate
dynamic_annotations
log_severity
base_internal
raw_logging_internal
atomic_hook
core_headers
spinlock_wait
endian
bits
int128
memory
errno_saver
meta
APPEND FILE lib/cmake/MyProject/MyProjectTargets.cmake)
确实修复了所有错误!在实践中,对于较大的图书馆来说,这将是非常痛苦的。这似乎也是“错误”的解决方案,因为我手动命名了 Abseil 的许多内部细节。
- 如上所述手动添加目标是“正确”的解决方案吗?
- 有没有更好的方法可以达到和上面一样的效果?
我有以下限制:
- 我需要导出
MyStaticLibTarget
以便下游客户端使用。 - 我很确定依赖项(在
target_link_libraries
中)需要是 public,因为在实际情况中(这是一个最小的例子),Abseil headers 将是包含在图书馆的 public headers.
TLDR: 遵循柯南文档,尤其是 cmake_find_package docs and skim the cheatsheet.
按照@Tsyvarev 在评论中的建议,我使用了不同的设置并完成了这项工作,您可以在 conan 分支中看到最终结果。
步骤如下:
- 使用 Conan 下载并安装 Abseil,使用本地项目
conanfile.txt
。现在,“安装”是一个可怕的词(我不想修改全局状态),但 Conan 本质上只是缓存源和构建工件,这意味着您可以在不同目录中拥有相同库的多个版本,并且不同的项目可以使用这些不同的版本,它应该“正常工作”。 (至少,这是我目前的基本理解。)
有了上面的配置,柯南就可以运行了:[requires] # Which 3rd party conan packages we are using abseil/20210324.2 [generators] # How to create build system files that capture the dependency information cmake_find_package cmake_paths
conan install . --install-folder build/conan # Bunch of CMake files will be available under build/conan
- 通过向
CMakeLists.txt
添加一行,将 CMake 指向 Conan 生成的文件。include("${CMAKE_BINARY_DIR}/conan/conan_paths.cmake")
- 使用CMake正常配置。
(不再需要cmake -G Ninja -S . -B build -DEXPORT_MYSTATICLIB=ON
ABSL_ENABLE_INSTALL
option is handled by Conan 和。)