Compile to native

My toy-compiler is generating a CGFT_ObjectFile, that I link into a “runner” CPP script (that simply calls it).
These two I can compile with clang+±12 to get an executable. Can llvm or clang++ do all this in one go, through the C++ API?
Are there any links that describe this?

You should be able to set it all up by tweaking the linker invocation in the driver.

Are you able to share your CPP script and the full invocation? Just to get a better idea of what we’re trying to automate here :slight_smile:

-Andrzej

This is the function that generates the object file:

void writeModuleToFile(Module *module)
{
    auto TargetTriple = sys::getDefaultTargetTriple();
    InitializeAllTargetInfos();
    InitializeAllTargets();
    InitializeAllTargetMCs();
    InitializeAllAsmParsers();
    InitializeAllAsmPrinters();

    std::string Error;
    auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);

    if (!Target)
    {
        errs() << Error;
        return;
    }

    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);

    if (EC)
    {
        errs() << "Could not open file: " << EC.message();
        return;
    }

    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();
}

My runner script - the module is built with a main function called “main_func”.

#include <iostream>

extern "C" {
    int main_func();
}

int main() {
    main_func();
    return 0;
}

Generate executable:

# Generate .o file
./mycompiler someinputfile
# Compile and link to executable
clang++-12 -g Runner.cpp output.o -o main
# Run
./main

Here is an example how to call the driver which you can integrate into mycompiler: pocl/pocl_llvm_build.cc at 170c24a8f299459f23edfaf05758f99a89051030 · pocl/pocl · GitHub
If you wish the opposite (clang driver calling your compiler), you will need to add a new toolchain under clang/lib/Driver/ToolChains for your target.

Have you looked at:

Also, your design is very similar that what we do in LLVM Flang, so you can take a look there:

-Andrzej

Thanks both, I’ll have a look at the links.

With ExecuteAndWait - am I understanding correctly, that you would use this to invoke the equivalent of this:
clang++-12 -g Runner.cpp output.o -o main.

Will that require clang+±12 to be available on the machine - or can it be baked into my compiler?

The pocl example uses a CLANG variable as executable-path - is that defined here?: pocl/LLVM.cmake at 170c24a8f299459f23edfaf05758f99a89051030 · pocl/pocl · GitHub
Does that mean CLANG is linked into the compiler, and available as CLANG or does it just store the path to clang on the machine?

Okay it works, and I don’t need the Runner.cpp script anymore.

I still generate the object-file, but then I add the following right after which spits out the executable:

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(CLANGXX, 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);
}

I define CLANGXX similar to how pocl does it here: pocl/LLVM.cmake at 170c24a8f299459f23edfaf05758f99a89051030 · pocl/pocl · GitHub

This seems to evaluate to an absolute path (/usr/bin/clang+±12), but if I build my compiler and purge clang-12 (and /usr/bin/clang+±12 is now gone), I can still run all this… Not entirely sure how that works. Is that CMAKE magic?

I have all of the following (clang related) in my CMakeLists.txt:

find_package(Clang REQUIRED)
find_program_or_die( CLANGXX "clang++-12" "clang++ binary")
...
include_directories(${CLANG_INCLUDE_DIRS})
...
add_definitions(${CLANG_DEFINITIONS})
...
target_link_libraries(balance LLVM clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangBasic clangEdit clangLex)