【问题标题】:CMake: Can we specify include directories for a specific set of files not forming an executable or lib?CMake:我们可以为不构成可执行文件或 lib 的特定文件集指定包含目录吗?
【发布时间】:2020-06-22 05:44:48
【问题描述】:

如果我有这个源代码树:

C:\app:
    src:
        CMakeLists.txt
        main.cpp --> #include "acme/header_only_lib/api.h"

D:\3rdparty\acme\header_only_lib:
    api.h --> #include "detail.h"
    detail.h 

不使用符号链接技巧,也不向 3rdparty 文件夹添加文件,如果我必须在 main.cpp 中保留 #include "acme/header_only_lib/api.h",我应该如何在 CMake 中指定包含目录,以便 api.h 可以看到 detail.h,没有添加D:\3rdparty\acme\header_only_lib的全局包含目录? header-only-lib 既不是可执行文件也不是库目标,我无法修改它的代码。我也不想通过添加D:\3rdparty\acme\header_only_lib 来污染我的全局包含目录,因为里面的文件名太常见了,很容易与其他库/未来代码发生冲突。

是否有一个 CMake 机制,我可以说: 仅对于D:\3rdparty\acme\header_only_lib\api.h,添加D:\3rdparty\acme\header_only_lib 作为包含目录?

【问题讨论】:

  • 将D:\3rdparty 和D:\3rdparty\acme\header_only_lib 添加为包含路径。
  • 抱歉,我的问题不够具体:我试图通过全局引入 D:\3rdparty\acme\header_only_lib 来不污染全局包含,因为存在文件名冲突的真正问题.您是否知道某种指定“本地”包含(仅可见,header_only_lib 中的文件)而不是“全局”包含的方法?

标签: c++ cmake


【解决方案1】:

要将目录添加到包含目录的全局列表中,请使用例如

include_directories( ${CMAKE_SOURCE_DIR}/3rdparty )

请注意,您不应将绝对路径(如D:\)硬编码到您的 CMakeLists.txt 中,因为这会使您无法在任何其他位置构建您的项目。 CMake 提供了像 ${CMAKE_SOURCE_DIR} 和 ${CMAKE_BINARY_DIR} 这样的变量来达到这个目的。

如果您只想将目录添加到构建的特定部分的包含目录列表中,请使用例如

target_include_directories( app PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty )

这将添加目录仅为目标(可执行文件/库)app。

请注意,如果您的 acme/header_only_lib 应该与 app 二进制文件一起安装,则此方法将不起作用,因为您的 acme 标头需要在客户端计算机上“看到”彼此,即如果它们驻留在acme/header_only_lib 子目录中但没有子目录相互寻址,则不太可能。这将需要您的客户(不使用 您的 CMakeLists.txt 进行构建)将 acme/header_only_lib 添加到包含路径中以使您的标头库正常工作——您不应该这样做。

【讨论】:

  • 我不太明白最后一段,让我消化一下。但是关于target_include_directories:acme/header_only_lib 不是二进制目标(既不是可执行文件也不是库),而是纯粹的头文件。那么是否仍然可以使用target_include_directories?据我了解,这是不可能的。我试图避免这样一种情况,即为了让api.h 看到detail.h,我将它们的父文件夹添加到全局包含中,因为这样更容易发生文件名冲突。
  • @moog 这就是最后一段的内容。用于“外部”使用的标头库——无论是由app 还是您的项目的客户端——不应该需要对包含路径进行任何扩展。你应该在那里#include "acme/lib/detail.h"。添加到包含路径,如果有的话,应该只用于“内部”头文件(那些被你用来构建你的二进制文件,它们没有安装在你的源代码树之外的任何地方)。
  • "你应该#include "acme/lib/detail.h" there":你说的“there”,你的意思是api.h应该是#include "acme/lib/detail.h" ,以免其客户扩展其全球范围?完全同意! (如果这就是你的意思)。太糟糕了,许多纯源代码库不这样做。使用这些库的客户最终不得不污染全局包含,只是为了适应他们的实现细节#include 查找。我想知道 CMake 是否有任何机制可以将包含仅扩展到一组不形成可执行文件/lib 的特定源文件。
  • @moog:这确实是我的意思。 -- “我在想……”:CMake 应该如何为未编译的东西(如仅标头库的内容)扩展编译器的包含路径?只有api 实际由编译器处理。如果它包含您的 acme/header_only_lib 标头,那很好,但这是 acme 目标的一部分。将使用您的 acme 库的任何人(api 除外)都将运行他/她自己的编译器,这甚至可能不受(任何)CMake 构建的控制......
【解决方案2】:

使用include_directories 或target_include_directories:

include_directories("D:\3rdparty")

如果您只想对 main 目标进行此更改,则使用 target_include_directories 或:

add_executable(main main.cpp)
target_include_directories(main PUBLIC "D:\3rdparty")

那你可以#include "acme/header_only_lib/api.h" 或#include <acme/header_only_lib/api.h>

仅标头库

如果您只想为header-only-lib 执行此操作,您需要在其 CMake 文件中执行此操作。首先将库添加为INTERFACE,没有源文件:

add_library(header-only INTERFACE) 

然后包含它的目录:

target_include_directories(header-only INTERFACE include-dir-for-header-only) 

然后将其链接到主要目标

find_library(HeaderOnly
    NAMES header-only
    HINTS "D:\3rdparty\path-to-lib"
)
target_link_libraries(main header-only)

【讨论】:

  • 但是api.h还是看不到detail.h,对吧?
  • 如果api.h和detail.h在同一个目录,api.h是包含detail.h,应该可以看到。
  • api.h 可以看到 detail.h 仅当 A)使用它们的文件(即 #include-ing 它们的文件)与它们并排,或 B) api/detail.h 的包含文件夹位于包含目录中。 #include 的搜索机制使用 1)“调用”文件的文件夹,以及 2)包含目录。例如,在 gcc 上:gcc.gnu.org/onlinedocs/cpp/Search-Path.html,在 msvc 上:docs.microsoft.com/en-us/cpp/preprocessor/… 同级文件不保证相互可见性。
猜你喜欢
  • 1970-01-01
  • 2015-01-08
  • 2011-12-07
  • 2021-01-03
  • 1970-01-01
  • 2016-12-15
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
相关资源
最近更新 更多