Here's my compile function, which compiles the Module
to an object file and then invokes the Clang++ compilation API to generate an executable.
I don't know if it correctly answers your question, as the object file exists momentarily and is just deleted afterwards (last line)
An optimization is of course to do it all in-memory.
The constructor of clang::driver::Driver
does have a "Virtual File System" optional argument, which can probably be used.
#include "clang/Driver/Driver.h"
#include "clang/Driver/Compilation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/IR/Module.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/Host.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
using namespace llvm::sys;
void writeModuleToFile(Module *module)
{
auto TargetTriple = getDefaultTargetTriple();
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
std::string Error;
auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
auto CPU = "generic";
auto Features = "";
TargetOptions opt;
auto RM = Optional<Reloc::Model>();
auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM);
module->setDataLayout(TargetMachine->createDataLayout());
module->setTargetTriple(TargetTriple);
auto Filename = "output.o";
std::error_code EC;
raw_fd_ostream dest(Filename, EC, sys::fs::OF_None);
legacy::PassManager pass;
auto FileType = CGFT_ObjectFile;
if (TargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType))
{
errs() << "TargetMachine can't emit a file of this type";
return;
}
pass.run(*module);
dest.flush();
IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions;
clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(errs(), &*DiagOpts);
IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
clang::driver::Driver TheDriver("/usr/bin/clang++-12", TargetTriple, Diags);
auto args = ArrayRef<const char *>{"-g", "output.o", "-o", "main"};
std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args));
if (C && !C->containsError())
{
SmallVector<std::pair<int, const clang::driver::Command *>, 4> FailingCommands;
TheDriver.ExecuteCompilation(*C, FailingCommands);
}
remove(Filename);
}