CMAKE - 如何正确地将静态库的头文件复制到/ usr/include中?

Mir*_*res 44 c cmake static-libraries

我正在使用C进入CMAKE,实际上我正在创建两个非常小的静态库.

我的目标是:

  1. 这些库被编译并链接到*.a文件中.[这个作品]
  2. 然后我希望将*.a文件复制到/ usr/local/lib [这也是工作]
  3. 据我所知,库(很少),它们是使用链接-lnameoflib,这是一个编译器标志.好.我准备好了我的CMakeLists.txt,它实际上将*.a文件复制到/ usr/local/lib中.但是,为了能够在程序中使用它们,我还需要将它们的头文件复制到/ usr/include中,然后我可以轻松地将它们包含在内/usr/local/lib.这就是我现在理解的方式.

我的问题是 - 如何使用CMAKE将头文件复制到/ usr/include文件夹中的正确方法是什么?我想在/usr/local/include执行时自动复制它们,比如*.a文件.

对于这两个库,我有一个熟悉的CMakeLists.txt:

project(programming-network)

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

INSTALL(TARGETS programming-network
        DESTINATION "lib"
        )
Run Code Online (Sandbox Code Playgroud)

flm*_*620 41

最新的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
)
Run Code Online (Sandbox Code Playgroud)

一些参考:

PUBLIC_HEADER

CMake安装命令

  • 此评论旨在成为一个编辑,但其他人认为它更适合作为评论.如果使用列表代替`"some.h; another.h"`,请确保将变量名称放在引号中.否则会导致错误或只安装列表中的第一项.实际发生的情况取决于列表中的项目数.例如`set_target_properties(myproject PROPERTIES PUBLIC_HEADER"$ {my_header_files}")`是正确的`set_target_properties(myproject PROPERTIES PUBLIC_HEADER $ {my_header_files})`不是. (4认同)
  • @MarcoStramezzi 您可以在 CMake 中使用 file(GLOB ***) 命令来抓取文件 (2认同)
  • @flm8620 我相信 cmake 的作者出于各种原因不鼓励使用 GLOB。有些可能在这里不适用,因为依赖项不是由 PUBLIC_HEADER 属性确定的。不管怎样,这篇文章很有用,帮助了我。 (2认同)

Sor*_*ush 21

几年后,在 CMake 3.23 中,我们可以使用 FILE_SET 作为公共标头:

project(programming-network)

add_library(programming-network STATIC)

target_include_directories(programming-network PRIVATE "${PROJECT_SOURCE_DIR}")

target_sources(programming-network 
    PRIVATE send_string.c recv_line.c
    PUBLIC FILE_SET HEADERS 
    BASE_DIRS ${PROJECT_SOURCE_DIR}
    FILES publicheader1.h publicheader2.h)

install(TARGETS programming-network FILE_SET HEADERS)
Run Code Online (Sandbox Code Playgroud)

现在让我们看看这些命令的作用:

  • add_library():定义目标的名称,STATIC 为静态库,SHARED 为共享库,OBJECT 为对象。

  • target_include_directories():这里的这一行仅适用于当您的子目录和私有标头相对于项目目录相互引用时。但通常,此命令用于在项目中包含外部标头。

  • target_sources():该命令用于添加带PRIVATE关键字的定义文件和私有头文件。此外,它还用于通过FILE_SET关键字添加公共标头。BASE_DIRS就是通过从公共标头的路径中减去基目录,将公共标头的绝对路径转换为相对路径。所以这个公共标头

/home/someuser/programming-network/sub1/publicheader1.h
Run Code Online (Sandbox Code Playgroud)

基目录为

/home/someuser/programming-network/
Run Code Online (Sandbox Code Playgroud)

将安装在

/cmake/install/prefix/include/sub1/publicheader.h
Run Code Online (Sandbox Code Playgroud)

Note也target_sources()可用于 of子目录。CMakeLists.txt

  • install(): 是安装二进制文件、静态/共享库和公共头文件。默认安装子目录是binlibinclude。你也可以像这样改变它
install(TARGETS myTarget
        # for executables and dll on Win
        RUNTIME DESTINATION bin
        # shared libraries
        LIBRARY DESTINATION lib
        # for static libraries
        ARCHIVE DESTINATION lib
        # public headers
        INCLUDES DESTINATION include)
Run Code Online (Sandbox Code Playgroud)

最后,构建并安装项目(对于多配置生成器:MS Visual C++、Xcode)

project(programming-network)

add_library(programming-network STATIC)

target_include_directories(programming-network PRIVATE "${PROJECT_SOURCE_DIR}")

target_sources(programming-network 
    PRIVATE send_string.c recv_line.c
    PUBLIC FILE_SET HEADERS 
    BASE_DIRS ${PROJECT_SOURCE_DIR}
    FILES publicheader1.h publicheader2.h)

install(TARGETS programming-network FILE_SET HEADERS)
Run Code Online (Sandbox Code Playgroud)

对于单配置生成器(make、Ninja),删除上述--config Release术语并更改cmake ..cmake -DCMAKE_BUILD_TYPE=Release ...


J.A*_*ler 13

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

INSTALL (
    DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION include
    FILES_MATCHING PATTERN "*.h*")
Run Code Online (Sandbox Code Playgroud)


Per*_*son 7

我不认为你的解决方案是正确的./usr/include应保留供您的供应商放入文件.

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

它似乎/usr/local/lib是自动搜索,但如果你想使用另一个export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH}"类似于.a二进制文件的dir 工作(但根据你的操作系统,可能会或可能不适用于共享库).

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

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