LLVM API,用于将 IR 组装和链接到可执行文件

问题描述 投票:0回答:0

我正在使用 LLVM 15.0.7 在 C++ 中构建一种玩具语言,遵循典型的 kaleidoscope 指南。但是,我的语言不使用 JIT,而是编译的。我想要的是能够将我的 LLVM Module 变成一个可执行文件(即 a.out),理想情况下可以控制它链接的文件。

我目前的“解决方案”非常老套,涉及以下内容:

llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();

auto TargetTriple = llvm::sys::getDefaultTargetTriple();
myLlvmModule->setTargetTriple(TargetTriple);

std::string Error;
auto Target = llvm::TargetRegistry::lookupTarget(TargetTriple, Error);
if (!Target)
    return 1;

auto CPU = "generic";
auto Features = "";

llvm::TargetOptions opt;
auto RM = llvm::Optional<llvm::Reloc::Model>();
auto TheTargetMachine =
    Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM, llvm::None, llvm::CodeGenOpt::Aggressive);

myLlvmModule->setDataLayout(TheTargetMachine->createDataLayout());

auto Filename = "out.o";
std::error_code EC;
llvm::raw_fd_ostream dest(Filename, EC, llvm::sys::fs::OF_None);

if (EC)
    return 1;

llvm::legacy::PassManager pass;
auto FileType = llvm::CGFT_ObjectFile;

if (TheTargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType))
    return 1;

pass.run(*myLlvmModule);
dest.flush();

system("cc out.o");
remove("out.o");

基本上,我将 IR 组装到一个目标文件中,然后将它传递给 Clang 或 GCC,并在其中处理链接并发送到可执行文件。

显然,这不是一个好的解决方案,因为我无法控制用户拥有的 Clang/GCC 版本,并且像这样调用另一个进程会使我的编译器不再“自包含”。最重要的是,它违背了学习手工完成这些步骤的目的。

真的不想在我的项目中调用system()。必须有更好的方法,对吗?当然,其他基于 LLVM 的编译器不会这样做!当然 LLVM 有一个 API 工具,它采用内存中的 IR 表示并输出一个可执行文件,或者一个链接目标文件的工具......对吗?

我试着查看 LLVM 源代码中的 Object 子目录,看看是否有一些工具可以让我手动执行那个 system 调用正在做的事情,但我对 LLVM 的经验还不够,不知道该看什么为了。我也尝试过查看其他编译器以获取有关如何实现这一点的灵感,但同样,作为 LLVM 的新手,我很难解析这些大型项目。在这方面确实缺乏质量指南。

如有任何帮助或指导,我们将不胜感激。

c++ linker clang llvm llvm-ir
© www.soinside.com 2019 - 2024. All rights reserved.