Skip to content

LLVM

clang

预处理过程

Include Priority

先看看 C 标准怎么说。

C23 - 6.10.3 Source file inclusion:

#include 预处理器指令有三种形式。但是最后一种形式在完成宏替换后,应当匹配前两种形式

#include <a>
#include "b"
#include c

标准说明,两种形式的搜索方式均由实现定义

再看看 GCC 怎么说。GCC 简单地把 include path 分为三类:当前目录,系统目录,引号目录。-isystem-iquote 分别控制各自的目录,-I 同时控制两种目录。

The C Preprocessor - Header Files

GNU 简单地把 Header files 分为两类:

  • System header files:使用 <>,在 standard list of system directories 中搜索
  • Your own header files:使用 "",优先在文件所在目录中搜索,然后是 quote directories 和与 <> 相同的 directories

再看选项:

  • -I:添加到 standard list of system directories 和 quote directories 的首位,多个参数将从左到右搜索
  • -iquote:添加到 quote directories
  • -isystem:添加到 standard list of system directories

查看 default search directory list:

cpp -v /dev/null -o /dev/null

此外,GNU 扩展了一个 #include_next 指令,将搜索下一个同名的 header file,用于在不修改系统头文件的情况下进行调整。具体用法:自己写一个新的同名头文件,在其中做一些修改,然后用 #include_next 包含系统头文件。

最后看 Clang 怎么说。Clang 文档从未明确说明搜索顺序,并且搞出了一堆五花八门的 include search path 和 prefix 来。

Clang Compiler User's Manual - Controlling Diagnostics in System Headers

Warnings are suppressed when they occur in system headers. By default, an included file is treated as a system header if it is found in an include path specified by -isystem, but this can be overridden in several ways.

默认情况下,include file 都认为是 system header,忽略其中的错误

When the name in a #include directive is found within a header search path and starts with a system prefix, the header is treated as a system header. The last prefix on the command-line which matches the specified header name takes precedence.

不管是 <> 还是 "",只要 #include 字符串的前缀与 Clang 的 system header 前缀匹配,就认为是 system header。如果有多个 system header prefix 匹配,则最后一个优先。

可以用 --system-header-prefix--no-system-header-prefix 来控制 system header 前缀。

A #include directive which finds a file relative to the current directory is treated as including a system header if the including file is treated as a system header.

相对路径也可以被认为是 system header。

Clang command line argument reference — Include Path Management

  • -I<dir>: Add directory to include search path.
    • For C++ inputs, if there are multiple -I options, these directories are searched in the order they are given before the standard system directories are searched.
    • If the same directory is in the SYSTEM include search paths, for example if also specified with -isystem, the -I option will be ignored
  • -cxx-isystem<directory>: Add directory to the C++ SYSTEM include search path
  • -iapinotes-modules<directory>: Add directory to the API notes search path referenced by module name
  • -idirafter<arg>: Add directory to AFTER include search path
  • -iquote<directory>: Add directory to QUOTE include search path
  • -isystem<directory>: Add directory to SYSTEM include search path
  • -F<arg>: Add directory to framework include search path
  • --embed-dir=<dir>: Add directory to embed search path
  • -iframework<arg>: Add directory to SYSTEM framework search path

与 Prefix 有关的:

  • -iwithprefix<dir>: Set directory to SYSTEM include search path with prefix
  • -iwithprefixbefore<dir>: Set directory to include search path with prefix

可以看到,在 Clang 中,有多种 include search path,和 prefix 一起控制头文件的搜索。

libclang

  • 功能:将源代码翻译为 AST,并支持对 AST 的操作
  • 头文件:clang-c/Index.h
  • 前缀:CX
graph TD
    CXIndex{{CXIndex}}
    CXTranslationUnit{{CXTranslationUnit}}
    CXCursor{{CXCursor}}
    CXType{{CXType}}
    CXString{{CXString}}
    CXUnsavedFile{{CXUnsavedFile}}

    clang_createIndex[clang_createIndex]
    clang_parseTranslationUnit[clang_parseTranslationUnit]
    clang_getTranslationUnitCursor[clang_getTranslationUnitCursor]
    clang_visitChildren[clang_visitChildren]
    clang_getCursorDisplayName[clang_getCursorDisplayName]
    clang_getCursorType[clang_getCursorType]
    clang_disposeString[clang_disposeString]

    CXIndex --> clang_parseTranslationUnit
    CXTranslationUnit --> clang_getTranslationUnitCursor
    CXCursor --> clang_visitChildren
    CXCursor --> clang_getCursorDisplayName
    CXCursor --> clang_getCursorType
    CXString --> clang_disposeString
    CXUnsavedFile --> clang_parseTranslationUnit 

    clang_createIndex --> CXIndex
    clang_parseTranslationUnit --> CXTranslationUnit
    clang_getTranslationUnitCursor --> CXCursor
    clang_getCursorDisplayName --> CXString
    clang_getCursorType --> CXType

clang_parseTranslationUnit2()