【问题标题】:CMAKE - How to properly copy static library's header file into /usr/include?CMAKE - 如何正确地将静态库的头文件复制到 /usr/include 中?
【发布时间】:2012-05-16 06:23:33
【问题描述】:

我开始使用 C 来使用 CMAKE,实际上我正在创建两个非常小的静态库。

我的目标是:

  1. 这些库被编译并链接到 *.a 文件中。 [这 作品]
  2. 然后我希望将 *.a 文件复制到 /usr/local/lib [这也有效]
  3. 据我所知(很少),它们是使用-lnameoflib 链接的,这是一个编译器标志。好的。我已经准备好我的 CMakeLists.txt,它实际上将 *.a 文件复制到 /usr/local/lib。但是,为了能够在程序中使用它们,我还需要将它们的头文件复制到/usr/local/include,然后我可以通过简单的方法将它们包含在#include <mylibheader.h> 中。我现在就是这么理解的。

我的问题是 - 使用 CMAKE 将头文件复制到 /usr/include 文件夹的正确方法是什么?我希望它在执行 make install 时自动复制它们,就像 *.a 文件一样。

对于这两个库,我都有一个类似的 CMakeLists.txt:

project(programming-network)

add_library(programming-network STATIC
    send_string.c
    recv_line.c
    )

INSTALL(TARGETS programming-network
        DESTINATION "lib"
        )

【问题讨论】:

  • 为什么不在Makefileinstall: \n\tcp $INCLUDES/* /usr/include/ 下添加一行?
  • 好的,但这意味着它不能直接在 CMakeLists.txt 中完成,并且每次运行 cmake 后我都必须在 Makefile 中再次写入?
  • 我想是这样,我对cmake和CMakeLists.txt不太熟悉,我更喜欢使用gnu-automake。
  • 如果您的目标是在使用 -DCMAKE_INSTALL_PREFIX=/usr 调用 CMake 之后安装的,那么您的库最终会以 /usr/lib 结尾(正如预期的那样,前缀设置为 /usr),但您的标头最终会在/include(可能不是预期的)。 Per 的回答更有意义。
  • @lukecampbell 手动向 makefile 添加行会破坏使用 cmake 的目的(这比 automake 好 100 倍)。

标签: c cmake static-libraries


【解决方案1】:

最新的 cmake 版本更好的方法是使用目标的 PUBLIC_HEADER 属性。

project(myproject)

add_library(mylib some.c another.c)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER "some.h;another.h")
INSTALL(TARGETS mylib 
        LIBRARY DESTINATION some/libpath
        PUBLIC_HEADER DESTINATION some/includepath
)

一些参考:

PUBLIC_HEADER

CMake install command

【讨论】:

  • 这正是我想要的。感谢您提供示例代码。
  • @flm8620 如果我有很多头文件怎么办?有没有比在给set_target_properties的字符串中列出所有这些更聪明的解决方案?
  • @MarcoStramezzi 你可以在 CMake 中使用 file(GLOB ***) 命令来抓取文件
  • @flm8620 我相信 cmake 的作者出于各种原因不鼓励使用 GLOB。有些可能在这里不适用,因为依赖关系不是由 PUBLIC_HEADER 属性确定的。无论哪种方式,这篇文章都很有用并帮助了我。
  • 此评论旨在进行编辑,但其他人认为它更适合作为评论。如果您使用列表代替"some.h;another.h",请确保将变量名放在引号中。否则将导致错误或仅安装列表中的第一项。实际发生的情况取决于列表中的项目数。例如set_target_properties(myproject PROPERTIES PUBLIC_HEADER "${my_header_files}") 是正确的set_target_properties(myproject PROPERTIES PUBLIC_HEADER ${my_header_files}) 不是。
【解决方案2】:

以更好的方式,将复制所有匹配模式的文件并保留目录结构。

INSTALL (
    DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION include
    FILES_MATCHING PATTERN "*.h*")

【讨论】:

  • 如果目标与公共标头有依赖关系,此方法将不起作用。在这种情况下,最好从接受的答案中使用 PUBLIC_HEADER 。它将递归地添加头文件(例如来自静态库)。
  • @Akela thx,在去年这个脚本发生了很大变化,我将尝试将整个脚本的项目放在 github 上。基本上我考虑 inlcude 文件夹 PUBLIC 中的所有文件和 src PRIVATE 中的所有文件,所以我做 TARGET_INCLUDE_DIRECTORIES (mylib PUBLIC $ $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src),我还创建了两个文件,mylibConfig.cmake 和 mylibTargets.cmake,包含了它所有的依赖,最后用 INSTALL 安装(DIRECTORY include / DESTINATION include COMPONENT development)。
  • 嗯...我想它甚至可以解决依赖库案例的问题(取决于 mylibTargets.cmake 的实现方式)。无论如何,您的回答对于最初的问题来说非常好。在我有两个库的情况下,一个依赖于另一个,我还添加了类似 mylibTargets.cmake 的内容,其中包含 find_dependency() 调用。我不确定它是否正确,但至少它对我有用。
  • 对不起,我再次检查了它,它适用于库。我不知道,为什么它第一次没有从依赖项中复制标头。到目前为止,这是我心中最好的答案,因为它保留了目录结构。
  • @TomášRůžička,我在 github 上有一个项目,里面有一些 cmake 脚本,它的开发没有考虑到多个目标,最后一次更新是一年前,看看 here 它可能会有所帮助你(1、14 和 68 岁)。我基本上认为包含目录中的所有内容都是公共的,并且在那里定义的结构将被保留,因此按照您的示例使用 gtk 标头,它将类似于${CMAKE_CURRENT_SOURCE_DIR}/include/gtk-4.0/gsk/gsk.h${CMAKE_CURRENT_SOURCE_DIR}/include/gtk-4.0/gsk/vulkan/gskvulkanrenderer.h
【解决方案3】:

我不认为您的解决方案是正确的。 /usr/include 应该留给你的供应商用来放文件。

IMO 正确的做法是在/usr/local/include 中安装标头,然后指示用户到export CPATH="/usr/local/include:${CPATH}"

/usr/local/lib 似乎是自动搜索的,但如果您希望使用另一个目录 export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH}" 对 .a 二进制文件的工作方式类似(但取决于您的操作系统,对于共享库可能适用也可能不好)。

可选,但更麻烦的是在编译时添加-I /usr/local/include-L /usr/local/lib

这是一个有点主观的答案,但对我来说效果很好。

【讨论】:

  • this INSTALL(FILES ${HEADERS} DESTINATION include) 默认情况下将头文件添加到 /usr/local/include,如果要更改它,请执行以下操作: make DESTDIR=/home/user/ my_include 安装
【解决方案4】:

除了the accepted answer,如果您要创建大量库并且set_property 语法会让您望而却步。您可以将其包装在一个非常简单的宏中,例如:

# File: target_public_headers.cmake
macro(target_public_headers TARGET)
  set_target_properties(${TARGET} PROPERTIES PUBLIC_HEADER "${ARGN}")
endmacro()

然后你可以像这样使用它:

project(myproject)

include(target_public_headers)

add_library(mylib some.c another.c)
target_public_headers(mylib some.h another.h) # <<<<<

# If you're exporting this library then you need to tell
# CMake how to include the "installed" version of the headers.
target_include_directories(mylib
  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
  PUBLIC $<INSTALL_INTERFACE:some/includepath>
)

INSTALL(TARGETS mylib 
        LIBRARY DESTINATION some/libpath
        PUBLIC_HEADER DESTINATION some/includepath
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2015-01-17
    • 1970-01-01
    相关资源
    最近更新 更多