【问题标题】:Is there a concept like include directory aliases?有没有像包含目录别名这样的概念?
【发布时间】:2019-11-05 02:12:42
【问题描述】:

在一个跨平台项目中,我使用了许多第三方库。我最终决定将它们的源代码包含到我的存储库中,而不需要在每个平台上再次下载它们。这是许可证允许的。

要包含这些库的标头,我需要指定它们的文件路径。有些库在name/include/name/file.h 中有它们,但通常每个库都有不同的目录结构。

我想在我的代码中始终以 #include "name/file.h" 的形式包含标题,其中 name 是库的名称。但我既不想修改库的目录结构,也不想将所有头文件复制到所需结构的包含目录中。

有没有办法定义诸如包含目录别名之类的东西?例如,Bullet Physics 的标题位于 bullet/src 中,Sqlite 的标题直接位于 sqlite 中,SFML 的标题位于 @987654325 中@。我想指定如下内容:

#alias "dependencies/bullet/src" "bullet"
#alias "dependencies/sqlite" "sqlite"
#alias "dependencies/sfml/include/SFML" "sfml"

这样#include "sfml/System.hpp" 就等同于
#include "dependencies/sfml/include/SFML/System.hpp"

该技术不必处于预处理器阶段。例如,它也可以是一个 CMake 标志,以正确的方式生成项目。但是,我认为编译器必须以某种方式意识到这种技术,才能使这成为可能。

【问题讨论】:

  • 您可以从构建系统中添加不同的-I 选项吗?
  • 否;最接近的方法是命令行上的-I 选项集合。此外,如果您使用 SFML,他们推荐的符号是 #include "SFML/System.hpp";这就是您应该在代码中编写的内容。然后你修复编译环境,以便 -Idependencies/sfml/include 包含在编译中,或者你使用符号链接(如果它们足够便携的话)在包含项目头文件的主目录中创建像 SFML 这样的子目录。跨度>
  • -I 标志不允许我提供别名。这会向包含空间发送垃圾邮件,并使从单个给定库中查找标头变得不必要地困难。
  • 没有-I 选项将使bullet/src/hdr.h 可作为bullet/hdr.h 访问
  • 创建一个依赖目录,其中包含指向第 3 方库的各种包含目录的软链接。

标签: c++ include cmake cross-platform project


【解决方案1】:

没有;最接近的方法是在命令行中使用 -I 选项的集合。

另外,如果你使用 SFML,推荐的符号是#include "SFML/System.hpp";这就是您应该在代码中编写的内容。然后修复编译环境,以便在编译中包含-Idependencies/sfml/include,或者使用符号链接(如果它们足够便携)在包含项目标头的主目录中创建像SFML 这样的子目录。

安装 SFML 等软件包时,标头将放置在一个目录中 - 通常默认为 /usr/local/include,通常在该目录下的子目录中。也就是说,会有一个目录/usr/local/include/SFML 包含SFML 标头。其他软件包的机会也是如此。您应该在构建区域下的某个位置安装这些标头,以便可以正常找到标头 - 您只需指定找到标头的基本 include 目录。 (注意:当你安装Bullet Physics library时,头文件被放置在一个目录.../include/bullet下,下面有各种子目录,所以它也遵循这个约定。)

否则就是与系统对抗,而当你对抗系统时,你最终会失败。比顺其自然更难。

【讨论】:

  • 为什么我需要安装 Bullet 才能将标题集中到一个位置?当然,我需要为每个平台构建一次所有库并构建配置。但是标题不应该受此影响,不是吗?
  • 并非我项目中的所有库都遵循include/name/ 约定。是否有工具可以提取第一个头文件以及它递归包含的所有头文件,以手动创建该文件夹?
  • 您的哪些库在安装时不会将头文件安装在类似于/usr/local/include 的目录中或/usr/local/include 下的子目录中?这些是两个“标准”位置。对于第一种情况,我们鼓励您写#include "libheader.h";对于第二个,我们鼓励您写#include "libname/libheader.h"。我知道一个不遵循该约定的系统。它使用子目录 incl 而不是 include (并且版本 1 早于约定)。但是,即使使用适当的-I/usr/software/incl 目录也可以解决此问题。
  • 与此目录结构不同的库是zliblibzipSQLite,以及仅标头库GLM。不过,我可能会遗漏一些东西,就像 Bullet 一样。
  • 配置 ./configure --prefix=$HOME/oss 时,zlib 1.2.8 构建过程会在 $HOME/oss/include 中安装两个标头(zlib.hzconf.h)。因此,如果您在命令行中编写#include "zlib.h" 并使用-I$HOME/oss/include,则会选择标题。如果您在配置中省略了--prefix,代码将被放置在/usr/local 下。我还没有检查其他库,但我希望找到类似的行为——安装后,标头位于 .../include 目录中的适当位置。
【解决方案2】:

简短的回答是“不”。

有几个不同的选项:

  • 符号链接 - 设置您自己的“myincludes”目录,然后将所有相关文件链接到那里,在它们的相对位置。
  • 对您的项目使用更复杂的 -I 选项。
  • 编写您自己的预处理器(根据一些规则,它将给定的#include 转换为“实际位置的实际文件”)
  • 调整各个项目的安装目录。
  • 不要执行上述任何操作,并使用实际文件系统中出现的名称。

我个人更喜欢“不要这样做”选项。一方面,移动/更改文件的包含方式很可能会使某些人感到困惑,并且第三方代码肯定不会以这种方式编写,因此您将无法使用其他任何人的代码来保持这种风格。

【讨论】:

  • 感谢您的回答!包括它们出现在文件系统上的库会很糟糕,因为一些库直接包含它们的头文件。所以我需要将我的dependencies 设置为包含目录以获取#include "library/header.h"。这样做会将我的所有依赖项注入包含空间、文档和其他不需要的文件。调整其他项目的目录感觉不对,并且使更新库的工作量更大,但可能是有可能的。您能否详细说明您对更复杂 -I 选项的含义?
  • 我[基本上和乔纳森说同样的话。如果关注的是 Windows 文件系统特性,那么问题在于 Windows 的构建/安装,而不是通过在您编译的源文件中添加更多混乱来解决。
【解决方案3】:

我在一次构建运行中构建所有内容(不在包中) 通过执行以下操作,我设法使用 Cmake 完成了您想要的操作:

在最高的CMakeLists.txt

set(TEMP_INCLUDE_DIR ${CMAKE_BINARY_DIR}/tempIncludes)
file(MAKE_DIRECTORY ${TEMP_INCLUDE_DIR})
target_include_directories(<TARGET_NAME> PUBLIC
  $<BUILD_INTERFACE:${TEMP_INCLUDE_DIR}>
)

这将在二进制目录中创建一个文件夹(在您清理项目时将其删除,因此它不会修改您的实际文件夹结构,并且我假设您没有使用源代码构建)

然后在目标库的 CMakeLists.txt 中:

set(LIB_NAME <ThirdPartyLibraryName>)
set(INCLUDE_FOLDER <WhatEverThirdPartyIncludeDirectory>)
set(HEADER_FILES
    ${INCLUDE_FOLDER}/<Header1>.h
    ${INCLUDE_FOLDER}/<Header2>.h
)
file(COPY ${HEADER_FILES} DESTINATION ${TEMP_INCLUDE_DIR}/${LIB_NAME}/)

这将创建一个文件夹结构,其中所有包含文件都复制到标准目录中,允许您使用所需的#include "name/file.h" 形式。

【讨论】:

    猜你喜欢
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 2012-08-05
    相关资源
    最近更新 更多