【问题标题】:CMake target_sources and installCMake target_sources 并安装
【发布时间】:2020-03-18 09:31:30
【问题描述】:

我很难弄清楚如何安装target_sources() 中指定的PUBLIC 标头。

似乎target_sources() 对于除了将私有源添加到可执行文件之外的任何东西都有些神秘。 在阅读了大量材料后,尤其是 this blog entry 很有帮助,我设法理解并绕过了 target_sources() 和 PUBLIC 文件的问题。我的 C++ 库项目的许多子目录之一中的 CMakeLists.txt 如下所示:

target_sources(mylib
    PRIVATE
        foo.cpp

    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/foo.hpp>
        $<INSTALL_INTERFACE:foo.hpp>
)

这使我能够成功构建库。但是,在安装时,target_sources()PUBLIC 部分中列出的头文件永远不会安装。

我的安装如下所示:

install(
    TARGETS
        mylib
    EXPORT mylib-targets
    LIBRARY
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        COMPONENT lib
    ARCHIVE
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        COMPONENT lib
    RUNTIME
        DESTINATION ${CMAKE_INSTALL_BINDIR}
        COMPONENT bin
    INCLUDES
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib

但是,这不会安装任何标头。 这个stackoverflow answer 提到了PUBLIC_HEADER 的使用,但阅读文档并没有让我觉得这与我的情况相关。

问题:使用install() 安装PUBLICINTERFACE 标头的正确方法是什么?

背景:我的目标是在我的源代码树的每个子目录中都有一个单独的CMakeLists.txt。这些列表中的每一个都应该使用target_sources()PRIVATEPUBLIC 文件添加到构建中。所有PUBLIC(和INTERFACE)源都应该在安装过程中安装。

【问题讨论】:

  • 那么您最终是否将set_target_propertiestarget_sources 添加到您的每个子目录CMakeLists.txt 中?
  • 是的。现在一切都使用子目录中的各种target() 函数完成了。但是,公共标头会添加到名为 HEADERS_PUBLIC 的列表中,然后将其传递给 target_sources() 以及相应的安装指令。如果这对您有所帮助,我可以用骨架发布一篇关于此的博客文章。可能需要几天时间。
  • 不,没关系。不过谢谢你的提议。我相信我现在可以正常工作了;虽然我没有在子目录CMakeLists.txt 中使用install 命令(从您的评论来看,这听起来像是您正在做的事情)。

标签: cmake


【解决方案1】:

target_sources 命令的PUBLIC 部分 nothing commonpublic headers 安装了install 命令的PUBLIC_HEADER 选项。

您希望将库视为public 的标头应列在目标的PUBLIC_HEADER 属性中。

install(TARGETS) 的文档有一个很好的设置和安装私有标头的示例。在您的情况下,这将是:

# This defines `foo.hpp` located in the current source directory as a 'public header'.
set_target_properties(mylib PROPERTIES PUBLIC_HEADER foo.hpp)
# This install public headers among with the library.
install(
  TARGETS
    mylib
  PUBLIC_HEADER
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib
  # ... other options
)

另请参阅相关问题:How to configure CMakeLists.txt to install public headers of a shared library?


另请注意,install(TARGETS) 命令的 INCLUDESPUBLIC_HEADERS 子句是不同的东西:

  • INCLUDES 指定已安装库的包含目录
  • PUBLIC_HEADERS 指定安装时将复制所有目标公共标头的目录。

例如如果您希望通过

使用您的头文件
#include <mylib/foo.h>

那么您需要为install() 命令提供以下选项:

  PUBLIC_HEADER
    # The header will be places at ${CMAKE_INSTALL_INCLUDEDIR}/mylib/foo.h
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib
  INCLUDES
    # This directory will be used as include directory.
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}

所以&lt;include-directory&gt;(通过/)与#include&lt;&gt; 指令中的相对路径 相结合,将为头文件提供绝对路径

【讨论】:

  • PUBLIC_HEADER 文档总是让我觉得这是 macOS/iOS 独有的功能。鉴于您的帖子,我认为这是不正确的?
  • 我会将此属性解释为:“此属性预期适用于 macOS/iOS,但也适用于其他平台可用”。请参阅短语“在非 Apple 平台上,可以使用install(TARGETS) 命令的PUBLIC_HEADER 选项安装这些标头。”在documentation中对该属性的描述的末尾。
  • 我的结论是:target_sources() 在使用install(TARGETS) 时绝对没有效果。因此,当尝试在我的库的每个子目录中使用单独的CMakeLists.txt 时,我只是使用“旧”方法将每个源文件的路径(相对于顶级CMakeLists.txt)添加到变量(列表) 然后使用install(FILES)。那是对的吗?我一直在寻找一种在每个子目录中都有一个CMakeLists.txt 的方法,列出该目录相对于CMakeLists.txt 的源文件,同时在安装时保留目录结构。
  • 是的,在非 Apple 平台上 PUBLIC_HEADER 与简单的 install(FILES) 相比没有优势。至于target_sources,我发现它只对INTERFACE 目标有用。对于普通库,直接在add_library 调用中列出其源代码会更简单。
猜你喜欢
  • 1970-01-01
  • 2021-06-22
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
  • 2023-03-16
  • 2016-09-30
相关资源
最近更新 更多