LLVM IR pass中,如何提取当前Module的绝对路径?

In LLVM IR pass, how to extract an absolute path of the current Module?

标题说明了一切。我正在编写一个 LLVM IR 模块通道,需要知道与当前模块对应的源代码的绝对路径。我知道如何提取源代码的 name(通过 Module 中的 getSourceFileName()),但我需要的是源代码的完整路径,包括绝对目录路径。我怎样才能找到这个?如果有解决方法,那也行。

好的,我要在这里回答我自己的问题。您可以在 IR/CodeGen/AsmWriter/AsmWriter.cpp:emitRemarksSection() 中找到 LLVM 如何在内部恢复绝对路径。基本上把源码的路径还原成现在clang是运行的当前路径。执行此操作的 API 函数已由 LLVM 提供。

参照此,我们将一个模块的文件名转换为它的完整路径。

  1. 获取文件名。

std::string Filename = M.getSourceFileName();

  1. 将其转换为 char 向量。

llvm::SmallString<128> FilenameVec = StringRef(Filename);

  1. 使其成为完整路径。

llvm::sys::fs::make_absolute(FilenameVec);

文件完整路径直接存储到 FilenameVec。您需要包含 llvm/Support/FileSystem.h 才能使用 make_absolute().

您可以通过将以下代码(正确地)粘贴到任何工作的 IR pass 来尝试。

#include <string>
#include "llvm/Support/FileSystem.h"
      
...

std::string Filename = M.getSourceFileName();   // e.g., Filename = aaa.c
llvm::SmallString<128> FilenameVec = StringRef(Filename);
llvm::sys::fs::make_absolute(FilenameVec);      // e.g., FilenameVec = /path/to/aaa.c

非常感谢@Gwangmu 提出和回答这个问题。为确保生成的完整路径不包含相关组件(例如 /path/to/../aaa.c)并且跨平台一致(例如包括 Windows),您可以调用 real_path 函数,然后将其转换为通用格式。整个片段看起来像:

std::string relFilename = M.getSourceFileName();   // e.g., relFilename = ..\aaa.c
llvm::SmallString<128> FilenameVec = StringRef(Filename);
llvm::SmallString<128> RealPath;
llvm::sys::fs::real_path(FilenameVec, RealPath);  // e.g., RealPath = \path\to\aaa.c  <-- in Windows
//
filesystem::path fp {string(RealPath)};
string genericFilePath = fp.generic_string(); // genericFilePath = /path/to/aaa.c