如何让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
相关产品推荐
相关产品推荐

