【问题标题】:Creating a C++ Shared Library with CMake using several headers使用 CMake 使用多个标头创建 C++ 共享库
【发布时间】:2020-01-17 21:30:28
【问题描述】:

我是 CMake 的新手,我试图在 Ubuntu 中开发一个共享库。 我设法创建了一些基本的 CMakeLists.txt 文件,它允许我编译一个非常简单的库,只有一个头文件和一个源文件。

其实我的项目树是:

.
├── CMakesList.txt
├── First.h
|
└── src
    └──First.cpp

我能够使用this answer 来创建 CMakeLists.txt 文件。

但是,然后我尝试通过向库中添加 Second 类来为示例增加一点复杂性。

现在,我的公共标头First.h 也导入了include/Second.h。项目树是这样的:

.
├── CMakesList.txt
├── First.h
|
└── include
|    └──Second.h
|
└── src
    └──First.cpp
    └──Second.cpp

我已经对 CMakesList 文件进行了必要的更改,如下所示:

cmake_minimum_required(VERSION 3.1...3.15)

project(First VERSION 1.0 
              DESCRIPTION "It does very little"
              LANGUAGES CXX)

include(GNUInstallDirs)

add_library(First SHARED 
    src/First.cpp
    src/Second.cpp)

set_target_properties(First PROPERTIES
    VERSION ${PROJECT_VERSION}
    PUBLIC_HEADER First.h)

configure_file(FIRST.pc.in FIRST.pc @ONLY)

target_include_directories(First PRIVATE .)

install(TARGETS First
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

install(FILES ${CMAKE_BINARY_DIR}/First.pc
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)

这个文件也成功运行了。它构建没有错误的库。

但是,现在,当我链接库并在另一个项目中使用它时,它无法编译,并给我以下错误:

 /usr/local/include/First.h:36: error: include/Second.h: No such file or directory
 #include "include/Second.h"
          ^~~~~~~~~~~~~~

所以我想我的问题是:

我怎样才能创建一个目录(在这种情况下,在 /usr/local/include/),其中包含我的公共标头请求的所有必要标头(以及可以由我的公共标头等请求的标头)?在这种情况下,我想在我的公共标头所在的同一目录中包含“包含”目录。

抱歉这个愚蠢的问题,我只是在探索!

提前致谢!

【问题讨论】:

  • "... 包含我的公共标头请求的所有必要标头" - 只需枚举该标头,例如,作为目标的 PUBLIC_HEADER 属性。 CMake 不提供扫描标头依赖项并安装它们的功能。执行这样的事情并不是那么简单: 1. 如果您的头文件包含系统一,则不应安装系统头文件(它已经安装)。 2. 如果某些#include 被一些宏检查所保护怎么办?是否应该安装此标头?为安装提供确切的标题列表要简单得多。
  • @Tsyvarev gcc -MM 如果可以的话
  • @Jezz:是的,我知道解决问题 1 并不像我所说的那么难。但它并没有解决问题 2(通过“通过一些宏检查来保护”我的意思是宏可以在某些配置中设置,但可以在其他配置中取消设置;gcc -MM 仅使用当前的宏设置)。跨度>

标签: c++ cmake shared-libraries


【解决方案1】:

首先,您必须声明所有标题。我不知道用 cmake 自动查找头文件依赖项的任何方法(并且 GLOB 不是一个选项)。如果你很懒,你可以复制粘贴ls -1 include 的输出。或者,您可以创建gcc -MM First.h 的检查输出。

如果你只是想在/usr/local/include/first中安装Second.h,我认为下面的代码应该可以工作:

install(FILES include/Second.h
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/first)

不过,也许所有的标头都应该放在/usr/local/include/first 中,这样就更容易了:

set_target_properties(First PROPERTIES
    VERSION ${PROJECT_VERSION}
    PUBLIC_HEADER "First.h;include/Second.h")
install(TARGETS First
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/first)

注意PUBLIC_HEADER 有一个参数,这个参数是一个列表。语法PUBLIC_HEADER First.h include/Second.h(不带双引号)只会将First.h 作为参数传递。另见:CMake: difference between ${} and "${}"

【讨论】:

  • 只是为了向将来可能会阅读此内容的人添加您的答案,如果编译仍然给出找不到文件的错误,请尝试运行:〜$ sudo ldconfig。然后再试一次。
  • 不适合我...这只会安装set_target_properties 列出的第一个标头(又名,仅First.h 而不是include/Second.h)。我做错了什么??
  • 啊,我想通了...您可以使用分号分隔的列表(可能在变量中),但是当您将它传递给set_target_properties 时必须引用它。又名:file(GLOB PUBLIC_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/libcwd/*.h"),然后是 set_target_properties(cwd_r PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}")。没有引号就不能工作,使用空格也不能工作。我将编辑答案以反映这一点(可能需要较新版本的 cmake)。
  • @CarloWood 确实如此。另请参阅stackoverflow.com/questions/13582282/…
猜你喜欢
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2017-05-29
相关资源
最近更新 更多