CMake:多库包导出中的依赖关系管理

Mat*_*oob 5 c++ dependencies cmake dependency-management

我有一个名为MYLIBS的包,由两个库lib1lib2组成,我想通过包的配置文件导出它们。项目结构如下:

\n\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Lib1\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 lib1-class.cpp\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 lib1-class.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 lib2\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 lib2-class.cpp\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 lib2-class.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 cmake\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LIBSConfig.cmake.in\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

lib2中我有:

\n\n
add_library(lib2\n        STATIC\n        ${SOURCE_FILES}\n        )\ntarget_include_directories(lib2 PRIVATE /path/to/lib1)\ntarget_link_libraries(lib2 PUBLIC lib1)\nadd_dependencies(lib2 lib1)\ninstall(\n        TARGETS\n        lib2\n        DESTINATION\n        lib/MYLIBS/lib2\n        EXPORT\n        lib2Exports\n)\ninstall(\n        EXPORT\n        lib2Exports\n        DESTINATION\n        lib/MYLIBS/lib2\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

与 lib1 相同,只是 lib1 没有add_dependencies()target_include/link(),因为它没有 。

\n\n

在我的配置文件模板中,我有:

\n\n
@PACKAGE_INIT@\n## PROJECT_LIBRARIES is filled-in during the package build. in this case : lib1,lib2\nset(@PROJECT_NAME@_LIBRARIES @PROJECT_LIBRARIES@)\n\n## The public variables to be used by the client project:\n#PROJECT_NAME_INCLUDE_DIRS is all the include paths\n#PROJECT_NAME_LIBRARIES is the name of all the libraries\n\nunset(@PROJECT_NAME@_INCLUDE_DIRS)\nforeach(INCLUDE_DIR ${INCLUDE_DIRS})\n    set_and_check(@PROJECT_NAME@_INCLUDE_DIR ${INCLUDE_DIR})\n    list(APPEND @PROJECT_NAME@_INCLUDE_DIRS ${@PROJECT_NAME@_INCLUDE_DIR})\nendforeach()\n\n## PACKAGE_PACKAGE_DIRNAME_include is filled-in during the package build\nforeach(lib ${@PROJECT_NAME@_LIBRARIES})\n    list(APPEND INCLUDE_DIRS @PACKAGE_PACKAGE_DIRNAME_include@/${lib})\nendforeach(lib)\n\n# Looks up the information about the exported targets in this package\nforeach(lib ${@PROJECT_NAME@_LIBRARIES})\n    if(NOT TARGET ${lib})\n        include(@PACKAGE_PACKAGE_DIRNAME_lib@/${lib}/${lib}Exports.cmake)\n    endif()\nendforeach(lib)\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,我一一检查库的导出文件并包含它们。问题是我必须按照正确的顺序执行此操作,即先 lib1,然后 lib2,否则在读取配置文件时会出现错误FindPackage()

\n\n

我不太确定传递依赖项将如何工作。由于这些库是从同一个导出文件中导出的,考虑到我们知道依赖项的导出文件将位于系统上的位置,include()是否有一种方法可以告诉 CMake 配置文件或lib2的导出文件中的依赖项?

\n\n

我可以看到 target_link_libraries() 有一个 PUBLIC 选项。我应该如何使用它?有什么帮助吗?

\n

ste*_*ire 6

首先,您可以删除该add_dependencies行。请参阅target_link_libraries 和 add_dependency

其次,你有

target_include_directories(lib2 PRIVATE /path/to/lib1)
Run Code Online (Sandbox Code Playgroud)

但这应该是不需要的。相反,删除它,并将其添加到lib1

target_include_directories(lib1 PUBLIC /path/to/lib1)
Run Code Online (Sandbox Code Playgroud)

不过,这些只是清理工作。

您没有发布错误,并且您的帖子中缺少许多其他重要信息,所以我做了一些猜测。

这个错误是类似的

The following imported targets are referenced, but are missing: lib2
Run Code Online (Sandbox Code Playgroud)

您将lib1和导出lib2到两个单独的“导出集” -lib1Exports和中lib2Exports。将它们放入一个“导出集”中可以解决问题,并且是最简单的方法,至少在两个目标的示例中是这样。

您知道这一点,但您没有这样做,因为您的构建系统的规模大于两个目标。但是,这直接导致您的问题 - 这意味着您必须管理“导出集”之间的顺序依赖性。

这与目标之间的依赖关系无关。“导出集”是具有独立依赖图的不同“单元”。CMake 无法帮助您管理它。您必须管理“导出集”之间的依赖关系。问题是您当前没有管理或表达这些依赖关系。有关表达这些依赖关系的选项,请参阅下文。

target_link_libraries(PUBLIC)对你没有帮助。请阅读传递使用要求中了解相关内容。

如果您将其与预处理器文件进行类比,您可能会看到您的选择。想起来lib2_private.h哪个没有#include lib1_private.h。Aalllibs.h需要以include正确的顺序来处理这两个。因为_private标头是私有的,并且客户端总是会包含这些标alllibs.h头,所以这是可行的。在这种方法中,您可以在一个位置管理整个依赖关系树。

另一种方法是创建lib2_internal.h包含

#include "lib1_private.h"
#include "lib2_private.h" 
Run Code Online (Sandbox Code Playgroud)

其中lib1_internal.h包含

#include "lib1_private.h"
Run Code Online (Sandbox Code Playgroud)

在这种方法中,您可以管理靠近依赖项的依赖项,因此您将有多个位置来指定总依赖项树的子集。可以alllibs.h使用

#include "lib1_internal.h"
#include "lib2_internal.h" 
Run Code Online (Sandbox Code Playgroud)

或者

#include "lib2_internal.h"
#include "lib1_internal.h" 
Run Code Online (Sandbox Code Playgroud)

并且顺序并不重要。

带有循环的配置文件是alllibs.h- 它是客户端包含的唯一文件。你们可以完全在那里管理订单吗?是的,如果您可以管理变量内的顺序@PROJECT_NAME@_LIBRARIES。顺便说一句,你应该这样称呼@PROJECT_NAME@_EXPORT_SETS。如果您不明白为什么,请再看看我上面所说的关于它是一个不同的“单位”的内容。

您没有提供太多信息,但我您正在用多个填充该信息

list(APPEND MYPROJ_EXPORT_SETS fooExports)
Run Code Online (Sandbox Code Playgroud)

调用,也许在某些宏中。因此,该订单不容易维护,因为它是一个单一的set()调用。

因此,表达“导出集”依赖项的选项是:

  1. 在配置文件中管理它们 - 用硬编码的有序列表替换循环
  2. 无论您在何处填充变量,都可以添加更多变量来表达导出集的依赖关系MYPROJ_EXPORT_SETS,并将配置文件中的循环替换为考虑到这些依赖关系的更复杂的内容。
  3. 与(2)相同,但生成中间文件并且不关心配置文件中的包含顺序。

(1) 可能是最有意义的,但您可能还必须退后一步,更加仔细地思考您正在创建的抽象/包装器,这些抽象/包装器导致您来到这里。