You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Clang AST工具自动识别stddef.h等系统头文件路径?

Clang AST访问器的头文件路径问题及解决

我借助ChatGPT编写了一个基础的Clang AST访问器,代码如下:

#include <iostream>
#include <llvm/Support/CommandLine.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/ASTMatchers/ASTMatchers.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/AST/RecordLayout.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendAction.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Rewrite/Frontend/FrontendActions.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>

using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;

static llvm::cl::OptionCategory MyToolCategory("my-tool options");

class OffsetOfVisitor : public RecursiveASTVisitor<OffsetOfVisitor> {
public:
    explicit OffsetOfVisitor(ASTContext *Context)
        : Context(Context) {}

    bool VisitFieldDecl(FieldDecl *FD) {
        const RecordDecl *Parent = FD->getParent();

        std::string FieldName = FD->getNameAsString();
        if (FieldName.empty()) {
            return true;
        }

        std::string ParentName;
        if (const TypedefNameDecl *TND = Parent->getTypedefNameForAnonDecl()) {
            ParentName = TND->getNameAsString();
        }

        if (ParentName.empty()) {
            return true;
        }

        llvm::outs() << ParentName << ' ' << FieldName << "\n";

        return true;
    }

private:
    ASTContext *Context;
};

class OffsetOfConsumer : public ASTConsumer {
public:
    explicit OffsetOfConsumer(ASTContext *Context)
        : Visitor(Context) {}

    void HandleTranslationUnit(ASTContext &Context) override {
        Visitor.TraverseDecl(Context.getTranslationUnitDecl());
    }

private:
    OffsetOfVisitor Visitor;
};

class OffsetOfAction : public ASTFrontendAction {
public:
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef File) override {
        return std::make_unique<OffsetOfConsumer>(&CI.getASTContext());
    }
};

int main(int argc, const char **argv) {
    auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
    if (!ExpectedParser) {
        return 1;
    }

    clang::tooling::CommonOptionsParser &OptionsParser = ExpectedParser.get();
    clang::tooling::ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());

    int result = Tool.run(newFrontendActionFactory<OffsetOfAction>().get());

    return result;
}

// vim: et ts=4 sw=4

运行时错误

运行该工具时,出现头文件找不到的错误:

# ../visitor t2.cpp
In file included from /home/pjoot/vv/test/t2.cpp:1:
/usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found
   33 | #include <stddef.h>
      |          ^~~~~~~~~~
__fsid_t __val
__mbstate_t __count
__mbstate_t __value
1 error generated.
Error while processing /home/pjoot/vv/test/t2.cpp.

问题定位

运行Clang预处理器后,发现stddef.h位于Clang专属路径:

# 28 "/usr/include/stdio.h" 2 3 4

extern "C" {

# 1 "/usr/bin/../lib/clang/17/include/stddef.h" 1 3 4

此时可以通过手动添加包含路径规避问题:

../visitor t2.cpp -- -I /usr/bin/../lib/clang/17/include

待解决问题

  • 如何通过代码为工具添加该-I路径,避免每次调用都手动传入?
  • 更佳方案:能否让Clang AST访问器自动使用Clang自身的所有默认包含路径?

最终解决方法

后续找到有效解决方法,通过添加Make规则,将工具及依赖头文件整理到合适的目录结构:

> make install
rm -rf tool
mkdir -p tool/bin tool/lib/clang/17
install visitor tool/bin/
(cd tool/lib/clang/17 && ln -s /usr/bin/../lib/clang/17/include)

> find tool -name stddef.h
tool/lib/clang/17/include/stddef.h

> cd test

> ../tool/bin/visitor t2.cpp
__fsid_t __val
__mbstate_t __count
__mbstate_t __value

使用符号链接替代复制操作,避免复制200多个头文件。虽然在Makefile中硬编码Clang内部路径不够优雅,但可以接受。

内容的提问来源于stack exchange,提问作者Peeter Joot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:13:15