找回密码
 立即注册
首页 业界区 业界 LLVM/Clang LibTooling Out-of-Tree开发

LLVM/Clang LibTooling Out-of-Tree开发

庾签 2025-9-20 15:00:04
Clang LibTooling官方给出的教程中给出了直接在LLVM/Clang代码目录下进行工具开发的示例,但这样对于代码管理不甚方便,为此,尝试独立于LLVM代码树开发(即Out-of-Tree)
省流:在编译Clang时,添加CMake选项:-DLLVM_ENABLE_RTTI=ON官方Tutorial分析

官方给出的LibTooling Tutorial大体上已经满足了开发环境的配置
官方Tutorial:https://clang.llvm.org/docs/LibASTMatchersTutorial.html如果使用官方的配置方法,尝试在其他路径下撰写项目,仅在编译时再链接LLVM/Clang库则会出现如下报错:
  1. user@debian:~/my-tool/build$ make
  2. [ 50%] Linking CXX executable my_tool
  3. /usr/bin/ld: CMakeFiles/my_tool.dir/src/MyTool.cpp.o:(.data.rel.ro._ZTIZN5clang7tooling24newFrontendActionFactoryINS_12ast_matchers11MatchFinderEEESt10unique_ptrINS0_21FrontendActionFactoryESt14default_deleteIS5_EEPT_PNS0_19SourceFileCallbacksEEN28FrontendActionFactoryAdapter22ConsumerFactoryAdaptorE[_ZTIZN5clang7tooling24newFrontendActionFactoryINS_12ast_matchers11MatchFinderEEESt10unique_ptrINS0_21FrontendActionFactoryESt14default_deleteIS5_EEPT_PNS0_19SourceFileCallbacksEEN28FrontendActionFactoryAdapter22ConsumerFactoryAdaptorE]+0x10): undefined reference to `typeinfo for clang::ASTFrontendAction'
  4. /usr/bin/ld: CMakeFiles/my_tool.dir/src/MyTool.cpp.o:(.data.rel.ro._ZTIZN5clang7tooling24newFrontendActionFactoryINS_12ast_matchers11MatchFinderEEESt10unique_ptrINS0_21FrontendActionFactoryESt14default_deleteIS5_EEPT_PNS0_19SourceFileCallbacksEE28FrontendActionFactoryAdapter[_ZTIZN5clang7tooling24newFrontendActionFactoryINS_12ast_matchers11MatchFinderEEESt10unique_ptrINS0_21FrontendActionFactoryESt14default_deleteIS5_EEPT_PNS0_19SourceFileCallbacksEE28FrontendActionFactoryAdapter]+0x10): undefined reference to `typeinfo for clang::tooling::FrontendActionFactory'
  5. /usr/bin/ld: CMakeFiles/my_tool.dir/src/MyTool.cpp.o:(.data.rel.ro._ZTI15FunctionPrinter[_ZTI15FunctionPrinter]+0x10): undefined reference to `typeinfo for clang::ast_matchers::MatchFinder::MatchCallback'
  6. collect2: error: ld returned 1 exit status
  7. make[2]: *** [CMakeFiles/my_tool.dir/build.make:156: my_tool] Error 1
  8. make[1]: *** [CMakeFiles/Makefile2:351: CMakeFiles/my_tool.dir/all] Error 2
  9. make: *** [Makefile:91: all] Error 2
复制代码
报错分析:这是一个非常典型的C++编译选项不匹配导致的链接错误: undefined reference to 'typeinfo for ...' 意味着代码和链接的库之间 RTTI (Run-Time Type Information) 设置不一致(from Gemini2.5 pro) Out-of-Tree开发环境配置

下面我们梳理Out-of-Tree开发环境配置
Step 0: Obtaining Clang

(与官方Tutorial相同)
As Clang is part of the LLVM project, you’ll need to download LLVM’s source code first. Both Clang and LLVM are in the same git repository, under different directories. For further information, see the getting started guide.
  1. mkdir ~/clang-llvm && cd ~/clang-llvmgit clone https://github.com/llvm/llvm-project.git
复制代码
Next, you need to obtain the CMake build system and Ninja build tool.
  1. cd ~/clang-llvm
  2. git clone https://github.com/martine/ninja.git
  3. cd ninja
  4. git checkout release
  5. ./configure.py --bootstrap
  6. sudo cp ninja /usr/bin/
  7. cd ~/clang-llvm
  8. git clone https://gitlab.kitware.com/cmake/cmake.git
  9. cd cmake
  10. ./bootstrap
  11. make
  12. sudo make install
复制代码
Step 1: 编译构建Clang

(与官方不同,out-of-tree环境)
  1. cd ~/clang-llvm
  2. mkdir build && cd build
  3. cmake -G Ninja ../llvm-project/llvm \
  4.     -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
  5.     -DCMAKE_BUILD_TYPE=Release \
  6.     -DLLVM_BUILD_TESTS=ON    \
  7.     -DCMAKE_INSTALL_PREFIX=/usr/local \ #安装及库文件路径
  8.     -DLLVM_ENABLE_RTTI=ON   # out-of-tree关键选项
  9. ninja
  10. ninja check       # Test LLVM only.
  11. ninja clang-test  # Test Clang only.
复制代码
最后将编译好的clang及其库文件安装至系统
  1. sudo ninja install
复制代码
简单验证:
  1. # 确认 libclangTooling.a 已被安装到指定位置
  2. ls /usr/local/lib/libclangTooling.a
  3. # 输出:/usr/local/lib/libclangTooling.a
复制代码
至此,基础out-of-tree环境基础完成 创建独立的 Out-of-Tree LibTooling 项目


  • 项目结构
  1. my-tool/
  2. ├── build         
  3. ├── CMakeLists.txt  #项目CMakeLists
  4. ├── src
  5. │   └── MyTool.cpp  #项目源代码
  6. └── test_samples    #测试用例目录
  7.     └── test_function_name.c
复制代码

  • CMakeLists.txt
可直接复制使用,注意修改地方已经标明
  1. cmake_minimum_required(VERSION 3.14)
  2. project(MyTool)
  3. set(CMAKE_CXX_STANDARD 17)
  4. find_package(LLVM REQUIRED CONFIG)
  5. find_package(Clang REQUIRED CONFIG)
  6. # 添加头文件路径
  7. include_directories(${LLVM_INCLUDE_DIRS})
  8. include_directories(${CLANG_INCLUDE_DIRS})
  9. link_directories(${LLVM_LIBRARY_DIRS})
  10. # 定义可执行文件
  11. # ==========注意修改此处1==========
  12. add_executable(my_tool
  13.   src/MyTool.cpp
  14. )
  15. # ==========注意修改此处2==========
  16. # 链接 Clang 库
  17. target_link_libraries(my_tool
  18.   PRIVATE
  19.   clangTooling
  20.   clangAST
  21.   clangASTMatchers
  22.   clangBasic
  23.   clangFrontend
  24.   clangSerialization
  25.   clangDriver
  26.   LLVMSupport
  27. )
复制代码

  • 撰写最小化的工具代码 (MyTool.cpp)
[code]#include "clang/ASTMatchers/ASTMatchers.h"#include "clang/ASTMatchers/ASTMatchFinder.h"#include "clang/Tooling/CommonOptionsParser.h"#include "clang/Tooling/Tooling.h"#include "llvm/Support/CommandLine.h"// 使用 namespaces 简化代码using namespace clang;using namespace clang::ast_matchers;using namespace clang::tooling;using namespace llvm;// 定义一个 Matcher 来查找所有函数定义(不仅仅是声明)// .bind("func") 将匹配到的节点绑定到名字 "func" 上,方便后续在回调中获取DeclarationMatcher FunctionMatcher = functionDecl(isDefinition()).bind("func");// 定义一个回调类,当 Matcher 找到匹配项时,它的 run 方法会被调用class FunctionPrinter : public MatchFinder::MatchCallback {public:  // 重写 run 方法  virtual void run(const MatchFinder::MatchResult &Result) {    // 从匹配结果中获取绑定的 "func" 节点    // 并将其转换为 FunctionDecl (函数声明) 类型    if (const FunctionDecl *FD = Result.Nodes.getNodeAs("func")) {      // 获取函数名      StringRef FuncName = FD->getName();      // 获取源码位置信息      SourceManager &SM = *Result.SourceManager;      SourceLocation FuncLocation = FD->getLocation();      // 使用 llvm:uts()(一个线程安全的cout)打印结果      outs()

相关推荐

您需要登录后才可以回帖 登录 | 立即注册