Clang 递归包含路径

Ven*_*eno 5 linux windows compiler-errors clang

我在包含依赖项文件夹时遇到问题,因为这不是递归查找标头。

文件夹结构:

- main.cpp
- dependency
  - sub1
    - header1.h
  - sub2
    - header2.h
  - root-header.h
Run Code Online (Sandbox Code Playgroud)

主程序

#include "root-header.h"
#include "header1.h"
#include "header2.h"

int main() {

}
Run Code Online (Sandbox Code Playgroud)

命令:

clang main.cpp -I"dependency"
Run Code Online (Sandbox Code Playgroud)

错误:

fatal error: 'header1.h' file not found
Run Code Online (Sandbox Code Playgroud)

该命令仅检测依赖文件夹内的 header.h 到一级,如何使clang递归查找依赖文件夹内的所有标头。是否需要添加任何编译器参数?

谢谢

Dan*_*hea 2

传统的解决方案是以下之一:

1.更改源代码中的include指令

该解决方案使用指令进行编译,clang++ -Idependency main.cpp但修改#include指令以按子目录包含标头,例如:

#include "sub1/header1.h"
#include "sub2/header2.h"
Run Code Online (Sandbox Code Playgroud)

这显然是对代码的修改,因此通常仅当sub1sub2在软件的较大结构中有意义时才有意义(例如,包名称始终相同)。或者...

2.使用shell工具遍历目录并构建包含路径

该解决方案用于find在包含路径上注入子目录,例如:

$ clang++ `find ./dependency -type d -exec echo -I'{}' \;` main.cpp 
Run Code Online (Sandbox Code Playgroud)

它扫描以识别子目录并将它们添加到预处理器包含路径中。

讨论

这两种方法都应该可以在 UNIX(包括 Linux、macOS、WSL 等)上的基本上任何 C/C++ 编译器上进行少量更改。

请注意,上面的第二种方法将在每次编译时涉及一些额外的文件系统搅动,如果子目录的数量非常大,这可能会很明显。公平地说,这个成本对于该用例来说是至关重要的,即使编译器前端中存在对递归包含的内置支持,它仍然需要在每个编译上执行类似昂贵的递归目录遍历才能找到所有文件。

3. 摊销目录遍历

但是,如果我们假设此目录结构中包含的所有标头都具有唯一的名称,那么我们可以改进第二个解决方案。这是一个合理的假设,因为否则源文件中的不合格#include指令将是不明确的,从而导致正交问题。有了这个假设,我们可以创建一个缓存来分摊依赖目录遍历的成本,如下所示:

#include "sub1/header1.h"
#include "sub2/header2.h"
Run Code Online (Sandbox Code Playgroud)

然后编译就变成了:

$ clang++ `find ./dependency -type d -exec echo -I'{}' \;` main.cpp 
Run Code Online (Sandbox Code Playgroud)

或者,如果您还想支持选项 1 和选项 3#include指令的混合,那么:

$ mkdir allheaders ; cd allheaders
$ find ../dependency -type f -exec ln -s '{}' . \;  
Run Code Online (Sandbox Code Playgroud)

这种方法可以大大加快编译速度,因为预处理器只需要打开一个用户目录并按基本名称打开文件。由于文件系统的工作方式,目录可能包含大量标头(其中一部分可能未使用),这一事实不应显着降低性能。

如果我们进一步假设目录中的文件名dependency很少或从不更改,那么我们只需要执行一次目录遍历步骤,并且可以使用allheaders缓存目录来分摊重复编译的成本。