在LLVM IR pass中如何提取当前Module对应源文件的绝对路径
LLVM Pass获取Module对应源文件绝对路径的实现方案
首先明确Module::getSourceFileName()的返回值完全由编译时传入的文件路径决定:如果调用clang等前端时传的是绝对路径,该接口直接返回绝对路径;如果传的是相对路径,就只会返回相对路径或者纯文件名,因此无法仅依靠该接口统一获取绝对路径。
以下是两种可行的实现方案:
方案1:基于调试信息提取(通用性最高)
只要编译时添加了-g相关参数生成调试信息,就可以从调试元数据中拿到完整的绝对路径:
- 步骤1:遍历Module中任意一个带实现的非声明函数,取其入口块第一条非调试指令的调试位置
- 步骤2:从调试位置中获取
DIFile元数据,调用DIFile::getDirectory()拿到编译时的工作目录,调用DIFile::getFilename()拿到源文件的路径,两者拼接后即为完整绝对路径
示例代码片段:
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Path.h" std::string getSourceAbsolutePath(Module &M) { // 遍历查找第一个带调试信息的非声明函数 for (Function &F : M) { if (F.isDeclaration() || F.empty()) continue; Instruction &FirstInst = F.front().front(); const DILocation *Loc = FirstInst.getDebugLoc(); if (!Loc) continue; const DIFile *File = Loc->getFile(); SmallString<256> AbsPath = File->getDirectory(); llvm::sys::path::append(AbsPath, File->getFilename()); // 规范化路径,去除其中的./..等相对标识 llvm::sys::path::remove_dots(AbsPath, true); return AbsPath.str().str(); } // 无调试信息时回退到原生接口返回值 return M.getSourceFileName(); }
注意:该方案要求编译源代码时携带-g或-gline-tables-only参数生成调试元数据,否则无法读取目录信息
方案2:编译期注入路径信息
如果无法强制要求编译时带调试参数,可以在编译IR阶段通过自定义选项把当前工作目录注入到Module的命名元数据中,Pass运行时直接读取即可:
- 编译时调用clang添加参数:
-Xclang -fmodule-metadata=source_dir:$PWD,将当前工作目录写入Module的元数据节点 - Pass运行时读取对应命名元数据的取值,和
getSourceFileName()的返回结果拼接即可得到绝对路径
内容的提问来源于stack exchange,提问作者Gwangmu Lee
相关产品推荐
相关产品推荐

