我正在使用 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 的新手,我很难解析这些大型项目。在这方面确实缺乏质量指南。
如有任何帮助或指导,我们将不胜感激。