CMake:多库包导出中的依赖项管理
CMake: dependency management in a multi-library package export
我有一个名为MYLIBS的包,由两个库lib1和lib2组成,我想通过包的配置文件导出它们。项目结构如下:
├── Lib1
│ ├── CMakeLists.txt
│ ├── lib1-class.cpp
│ └── lib1-class.h
├── lib2
│ └── CMakeLists.txt
│ ├── lib2-class.cpp
│ ├── lib2-class.h
├── cmake
│ └── LIBSConfig.cmake.in
├── CMakeLists.txt
在 lib2 中,我有:
add_library(lib2
STATIC
${SOURCE_FILES}
)
target_include_directories(lib2 PRIVATE /path/to/lib1)
target_link_libraries(lib2 PUBLIC lib1)
add_dependencies(lib2 lib1)
install(
TARGETS
lib2
DESTINATION
lib/MYLIBS/lib2
EXPORT
lib2Exports
)
install(
EXPORT
lib2Exports
DESTINATION
lib/MYLIBS/lib2
)
与 lib1 相同,只是 lib1 没有add_dependencies()
和target_include/link()
因为它没有。
在我的配置文件模板中,我有:
@PACKAGE_INIT@
## PROJECT_LIBRARIES is filled-in during the package build. in this case : lib1,lib2
set(@PROJECT_NAME@_LIBRARIES @PROJECT_LIBRARIES@)
## The public variables to be used by the client project:
#PROJECT_NAME_INCLUDE_DIRS is all the include paths
#PROJECT_NAME_LIBRARIES is the name of all the libraries
unset(@PROJECT_NAME@_INCLUDE_DIRS)
foreach(INCLUDE_DIR ${INCLUDE_DIRS})
set_and_check(@PROJECT_NAME@_INCLUDE_DIR ${INCLUDE_DIR})
list(APPEND @PROJECT_NAME@_INCLUDE_DIRS ${@PROJECT_NAME@_INCLUDE_DIR})
endforeach()
## PACKAGE_PACKAGE_DIRNAME_include is filled-in during the package build
foreach(lib ${@PROJECT_NAME@_LIBRARIES})
list(APPEND INCLUDE_DIRS @PACKAGE_PACKAGE_DIRNAME_include@/${lib})
endforeach(lib)
# Looks up the information about the exported targets in this package
foreach(lib ${@PROJECT_NAME@_LIBRARIES})
if(NOT TARGET ${lib})
include(@PACKAGE_PACKAGE_DIRNAME_lib@/${lib}/${lib}Exports.cmake)
endif()
endforeach(lib)
因此,我逐个浏览库的导出文件并包含它们。问题是我必须以正确的顺序执行此操作,即首先是lib1,然后是lib2,否则我在读取配置文件时出现错误 FindPackage()
.
我不太确定传递依赖项将如何工作 tbh。由于这些库是从同一个导出文件中include()
的,考虑到我们知道依赖项的导出文件将在系统上的位置,有没有办法告诉 CMake 配置文件或 lib2 导出文件中的依赖项?
我可以看到target_link_libraries()有一个公共选项。我应该如何使用它?会有什么帮助吗?
首先,您可以删除add_dependencies
行。请参阅target_link_libraries和add_dependencies。
第二,你有
target_include_directories(lib2 PRIVATE /path/to/lib1)
但这不应该是必需的。相反,请将其删除,并将其添加到lib1
:
target_include_directories(lib1 PUBLIC /path/to/lib1)
不过,这些只是清理。
您没有发布错误,并且您的帖子中缺少许多其他重要信息,所以我做了一些猜测。
我想错误类似于
The following imported targets are referenced, but are missing: lib2
您将lib1
和lib2
导出到两个单独的"导出集"中 - lib1Exports
和 lib2Exports
中。将它们放在一个"导出集"中可以解决问题,并且是最简单的方法,至少在双目标示例中是这样。
我想你知道这一点,你没有这样做,因为你的构建系统的规模大于两个目标。但是,这直接导致了您的问题 - 这意味着您必须管理"导出集"之间的订单依赖关系。
这与目标之间的依赖关系无关。"导出集"是具有独立依赖关系图的不同"单元"。CMake 不能帮助你管理它。您必须管理"导出集"之间的依赖关系。问题是您当前没有管理或表达这些依赖项。有关表达这些依赖项的选项,请参阅下文。
target_link_libraries(PUBLIC)
对你没有帮助。在可传递使用要求中阅读有关它的信息。
如果您想与预处理器文件进行类比,您可能会看到您的选项。想想lib2_private.h
不#include lib1_private.h
.alllibs.h
需要按正确的顺序include
这两者。由于_private
标头是私有的,并且客户端将始终包含alllibs.h
,因此这将起作用。在此方法中,您可以在一个位置管理总依赖项树。
另一种方法是创建包含以下内容的lib2_internal.h
#include "lib1_private.h"
#include "lib2_private.h"
以及包含以下内容的lib1_internal.h
#include "lib1_private.h"
在此方法中,您可以管理靠近其依赖项的依赖项,因此您将有多个位置指定总依赖项树的子集。alllibs.h
可以使用
#include "lib1_internal.h"
#include "lib2_internal.h"
或
#include "lib2_internal.h"
#include "lib1_internal.h"
顺序无关紧要。
带有循环的配置文件是alllibs.h
- 它是客户端包含的唯一文件。你能完全在那里管理订单吗?是的,如果您可以在@PROJECT_NAME@_LIBRARIES
变量中管理订单。顺便说一句,您可能应该将其称为@PROJECT_NAME@_EXPORT_SETS
。如果你不明白为什么,再看看我上面所说的它是一个不同的"单位"。
没有提供太多信息,但我想您正在用多个填充它
list(APPEND MYPROJ_EXPORT_SETS fooExports)
调用,也许在某个宏中。因此,该顺序不容易维护,因为它将作为单个set()
调用。
因此,表示"导出集"依赖项的选项是:
- 在配置文件中管理它们 - 将循环替换为硬编码的有序列表
- 在填充
MYPROJ_EXPORT_SETS
变量的位置添加更多变量以表示导出集的依赖项,并将配置文件中的循环替换为考虑这些依赖项的更复杂的内容。 - 与 (2) 相同,但生成中间文件,并且不关心配置文件中的包含顺序。
(1)可能是最有意义的,但你可能也必须退后一步,更努力地思考你正在创建的抽象/包装器,这些抽象/包装器将你带到了这里。
- 如何从C++中的依赖类型中获得它所依赖的类型
- 当vector是tje全局变量时,c++中vector的内存管理
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- python venv 如何管理C++依赖项
- 是否有VC 的依赖管理器
- 管理生成文件中的依赖关系复杂性
- 如何在c++中管理依赖关系
- CMake:多库包导出中的依赖项管理
- 管理多个项目的C++依赖项
- 如何在C++中管理并行的依赖继承
- 在没有管理权限的mac上运行具有依赖库的Qt应用程序
- 在PInvoke中管理大量的第三方依赖关系,以提高编译速度
- c++如何管理依赖关系(例如使用github中的库)
- 使用git管理库依赖项
- c++依赖管理最佳实践
- c++:如何管理对象生命周期和依赖关系
- C/ c++构建工具依赖管理
- 我应该如何管理C或C++开源项目中的依赖关系
- 在cmake目标的解决方案资源管理器中添加一些源文件的头依赖项