CMake:多库包导出中的依赖项管理 [英] CMake: dependency management in a multi-library package export

查看:54
本文介绍了CMake:多库包导出中的依赖项管理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 MYLIBS 的包,包含两个库,lib1lib2,我想通过配置文件导出包裹.项目结构如下:

I have a package called MYLIBS consisting of two libraries, lib1 and lib2, which I want to export through the configuration file for the package. The project structure is as follows:

├── 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(),因为它没有.

The same as lib1 except that lib1 does not have the add_dependencies() and target_include/link() as it does not have one.

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

In my configuration file template, I have:

@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() 读取配置文件时会出错.

So I go through the export files for libraries one by one and include them. The problem is that I have to do that in the right order, i.e. lib1 first and then lib2, otherwise I get an error when reading the configuration file by FindPackage().

我不太确定传递依赖项如何工作.由于这些库是 include() 来自同一个导出文件,有没有办法告诉 CMake 配置文件或 lib2 的导出文件中的依赖关系我们知道依赖项的导出文件在系统上的位置吗?

I am not really sure how the transitive dependencies would work tbh. Since these libraries are include()ed from the same export file, is there a way of telling CMake about the dependencies in the configuration file or in the export file of lib2 considering that we know where the export files for the dependencies are going to be on the system?

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

I can see target_link_libraries() has a PUBLIC option. How am I supposed to use that? Would it be of any help?

推荐答案

首先,您可以删除 add_dependencies 行.请参阅target_link_libraries 和 add_dependencies.

To begin with, you can remove the add_dependencies line. See target_link_libraries and add_dependencies.

第二,你有<​​/p>

Second, you have

target_include_directories(lib2 PRIVATE /path/to/lib1)

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

But that should not be needed. Instead, remove it, and add this to lib1:

target_include_directories(lib1 PUBLIC /path/to/lib1)

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

Those are just clean-ups though.

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

You didn't post the error, and there is lots of other important information missing in your post, so I do some guessing.

猜想错误类似于

The following imported targets are referenced, but are missing: lib2

您将 lib1lib2 导出到两个单独的导出集" - lib1Exportslib2Exports.将它们放在一个导出集"中可以解决问题,并且是最简单的方法,至少在两个目标示例中是这样.

You export lib1 and lib2 in two separate 'export sets' - lib1Exports and lib2Exports. Putting them in one 'export set' would solve the problem and be the easiest way forward, at least in the two-target example.

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

I guess you know that, and you are not doing it because the scale of your build system is bigger than two targets. However, that leads directly to your problem - it means you must manage the order dependencies between 'export sets'.

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

This is independent of dependencies between targets. An 'export set' is a different 'unit' with an independent dependency graph. CMake doesn't help you to manage it. You have to manage the dependencies between 'export sets'. The problem is that you are not currently managing or expressing those dependencies. See below for your options regarding expressing those dependencies.

target_link_libraries(PUBLIC) 对您没有帮助.阅读 传递性使用要求.

target_link_libraries(PUBLIC) does not help you. Read about it in Transitive Usage Requirements.

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

If you think of an analogy to preprocessor files, you might see your options. Think of lib2_private.h which does not #include lib1_private.h. A alllibs.h will need to include those two in the correct order. Because the _private headers are private, and because clients will always include alllibs.h instead, that will work. In this approach, you manage the total dependency tree in one place.

另一种方法是创建包含

An alternative approach would be to create lib2_internal.h which contains

#include "lib1_private.h"
#include "lib2_private.h" 

和包含

#include "lib1_private.h"

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

In this approach, you manage dependencies close to their dependers, so you would have multiple places which specify subsets of the total dependency tree. The alllibs.h could use

#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 可能.如果您不明白为什么,请再看看我上面所说的它是一个不同的单位".

Your configuration file with the loop is alllibs.h - it is the only file clients include. Can you manage the order entirely there? Yes, if you can manage the order within the @PROJECT_NAME@_LIBRARIES variable. By the way, you should call that @PROJECT_NAME@_EXPORT_SETS probably. If you don't see why, have another look at what I said above about it being a different 'unit'.

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

You didn't give much information, but I guess you are populating that with multiple

list(APPEND MYPROJ_EXPORT_SETS fooExports)

调用,也许在某个宏中.所以这个顺序不容易维护,因为它是一个单独的 set() 调用.

calls, perhaps in some macro. So the order is not easily maintainable, as it would be as a single set() call.

因此,您表达导出集"依赖关系的选项是:

So, your options to express 'export set' dependencies are:

  1. 在配置文件中管理它们 - 用硬编码的有序列表替换循环
  2. 在您填充 MYPROJ_EXPORT_SETS 变量的任何位置添加更多变量来表达导出集的依赖关系,并将配置文件中的循环替换为考虑这些依赖关系的更复杂的东西.
  3. 同(2),但生成中间文件,不关心配置文件中的包含顺序.
  1. Manage them in the configuration file - replace the loop with a hardcoded ordered list
  2. Add more variables to express dependencies of export sets wherever you populate the MYPROJ_EXPORT_SETS variable, and replace the loop in your configuration file with something more complex that takes those dependencies into account.
  3. Same as (2), but generate intermediate files and don't care about the include order within the configuration file.

(1) 可能最有意义,但您可能还需要退后一步,更加认真地思考您正在创建的抽象/包装器,它们导致您来到这里.

(1) probably makes most sense, but you might also have to step back and think harder about the abstractions/wrappers you're creating which led you here.

这篇关于CMake:多库包导出中的依赖项管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆