1 //===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Basic/DiagnosticOptions.h" 10 #include "clang/CodeGen/CodeGenAction.h" 11 #include "clang/Driver/Compilation.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/Tool.h" 14 #include "clang/Frontend/CompilerInstance.h" 15 #include "clang/Frontend/CompilerInvocation.h" 16 #include "clang/Frontend/FrontendDiagnostic.h" 17 #include "clang/Frontend/TextDiagnosticPrinter.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ExecutionEngine/ExecutionEngine.h" 20 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 21 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 22 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 23 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 24 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 25 #include "llvm/IR/DataLayout.h" 26 #include "llvm/IR/Mangler.h" 27 #include "llvm/IR/Module.h" 28 #include "llvm/Support/FileSystem.h" 29 #include "llvm/Support/Host.h" 30 #include "llvm/Support/ManagedStatic.h" 31 #include "llvm/Support/Path.h" 32 #include "llvm/Support/TargetSelect.h" 33 #include "llvm/Support/raw_ostream.h" 34 #include "llvm/Target/TargetMachine.h" 35 36 using namespace clang; 37 using namespace clang::driver; 38 39 // This function isn't referenced outside its translation unit, but it 40 // can't use the "static" keyword because its address is used for 41 // GetMainExecutable (since some platforms don't support taking the 42 // address of main, and some platforms can't implement GetMainExecutable 43 // without being given the address of a function in the main executable). 44 std::string GetExecutablePath(const char *Argv0, void *MainAddr) { 45 return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); 46 } 47 48 namespace llvm { 49 namespace orc { 50 51 class SimpleJIT { 52 private: 53 ExecutionSession ES; 54 std::unique_ptr<TargetMachine> TM; 55 const DataLayout DL; 56 MangleAndInterner Mangle{ES, DL}; 57 JITDylib &MainJD{ES.createBareJITDylib("<main>")}; 58 RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr}; 59 IRCompileLayer CompileLayer{ES, ObjectLayer, 60 std::make_unique<SimpleCompiler>(*TM)}; 61 62 static std::unique_ptr<SectionMemoryManager> createMemMgr() { 63 return std::make_unique<SectionMemoryManager>(); 64 } 65 66 SimpleJIT( 67 std::unique_ptr<TargetMachine> TM, DataLayout DL, 68 std::unique_ptr<DynamicLibrarySearchGenerator> ProcessSymbolsGenerator) 69 : TM(std::move(TM)), DL(std::move(DL)) { 70 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 71 MainJD.addGenerator(std::move(ProcessSymbolsGenerator)); 72 } 73 74 public: 75 ~SimpleJIT() { 76 if (auto Err = ES.endSession()) 77 ES.reportError(std::move(Err)); 78 } 79 80 static Expected<std::unique_ptr<SimpleJIT>> Create() { 81 auto JTMB = JITTargetMachineBuilder::detectHost(); 82 if (!JTMB) 83 return JTMB.takeError(); 84 85 auto TM = JTMB->createTargetMachine(); 86 if (!TM) 87 return TM.takeError(); 88 89 auto DL = (*TM)->createDataLayout(); 90 91 auto ProcessSymbolsGenerator = 92 DynamicLibrarySearchGenerator::GetForCurrentProcess( 93 DL.getGlobalPrefix()); 94 95 if (!ProcessSymbolsGenerator) 96 return ProcessSymbolsGenerator.takeError(); 97 98 return std::unique_ptr<SimpleJIT>(new SimpleJIT( 99 std::move(*TM), std::move(DL), std::move(*ProcessSymbolsGenerator))); 100 } 101 102 const TargetMachine &getTargetMachine() const { return *TM; } 103 104 Error addModule(ThreadSafeModule M) { 105 return CompileLayer.add(MainJD, std::move(M)); 106 } 107 108 Expected<JITEvaluatedSymbol> findSymbol(const StringRef &Name) { 109 return ES.lookup({&MainJD}, Mangle(Name)); 110 } 111 112 Expected<JITTargetAddress> getSymbolAddress(const StringRef &Name) { 113 auto Sym = findSymbol(Name); 114 if (!Sym) 115 return Sym.takeError(); 116 return Sym->getAddress(); 117 } 118 }; 119 120 } // end namespace orc 121 } // end namespace llvm 122 123 llvm::ExitOnError ExitOnErr; 124 125 int main(int argc, const char **argv) { 126 // This just needs to be some symbol in the binary; C++ doesn't 127 // allow taking the address of ::main however. 128 void *MainAddr = (void*) (intptr_t) GetExecutablePath; 129 std::string Path = GetExecutablePath(argv[0], MainAddr); 130 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 131 TextDiagnosticPrinter *DiagClient = 132 new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); 133 134 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 135 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); 136 137 const std::string TripleStr = llvm::sys::getProcessTriple(); 138 llvm::Triple T(TripleStr); 139 140 // Use ELF on Windows-32 and MingW for now. 141 #ifndef CLANG_INTERPRETER_COFF_FORMAT 142 if (T.isOSBinFormatCOFF()) 143 T.setObjectFormat(llvm::Triple::ELF); 144 #endif 145 146 ExitOnErr.setBanner("clang interpreter"); 147 148 Driver TheDriver(Path, T.str(), Diags); 149 TheDriver.setTitle("clang interpreter"); 150 TheDriver.setCheckInputsExist(false); 151 152 // FIXME: This is a hack to try to force the driver to do something we can 153 // recognize. We need to extend the driver library to support this use model 154 // (basically, exactly one input, and the operation mode is hard wired). 155 SmallVector<const char *, 16> Args(argv, argv + argc); 156 Args.push_back("-fsyntax-only"); 157 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); 158 if (!C) 159 return 0; 160 161 // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. 162 163 // We expect to get back exactly one command job, if we didn't something 164 // failed. Extract that job from the compilation. 165 const driver::JobList &Jobs = C->getJobs(); 166 if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { 167 SmallString<256> Msg; 168 llvm::raw_svector_ostream OS(Msg); 169 Jobs.Print(OS, "; ", true); 170 Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); 171 return 1; 172 } 173 174 const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin()); 175 if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") { 176 Diags.Report(diag::err_fe_expected_clang_command); 177 return 1; 178 } 179 180 // Initialize a compiler invocation object from the clang (-cc1) arguments. 181 const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments(); 182 std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation); 183 CompilerInvocation::CreateFromArgs(*CI, CCArgs, Diags); 184 185 // Show the invocation, with -v. 186 if (CI->getHeaderSearchOpts().Verbose) { 187 llvm::errs() << "clang invocation:\n"; 188 Jobs.Print(llvm::errs(), "\n", true); 189 llvm::errs() << "\n"; 190 } 191 192 // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. 193 194 // Create a compiler instance to handle the actual work. 195 CompilerInstance Clang; 196 Clang.setInvocation(std::move(CI)); 197 198 // Create the compilers actual diagnostics engine. 199 Clang.createDiagnostics(); 200 if (!Clang.hasDiagnostics()) 201 return 1; 202 203 // Infer the builtin include path if unspecified. 204 if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && 205 Clang.getHeaderSearchOpts().ResourceDir.empty()) 206 Clang.getHeaderSearchOpts().ResourceDir = 207 CompilerInvocation::GetResourcesPath(argv[0], MainAddr); 208 209 // Create and execute the frontend to generate an LLVM bitcode module. 210 std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction()); 211 if (!Clang.ExecuteAction(*Act)) 212 return 1; 213 214 llvm::InitializeNativeTarget(); 215 llvm::InitializeNativeTargetAsmPrinter(); 216 217 int Res = 255; 218 std::unique_ptr<llvm::LLVMContext> Ctx(Act->takeLLVMContext()); 219 std::unique_ptr<llvm::Module> Module = Act->takeModule(); 220 221 if (Module) { 222 auto J = ExitOnErr(llvm::orc::SimpleJIT::Create()); 223 224 ExitOnErr(J->addModule( 225 llvm::orc::ThreadSafeModule(std::move(Module), std::move(Ctx)))); 226 auto Main = (int (*)(...))ExitOnErr(J->getSymbolAddress("main")); 227 Res = Main(); 228 } 229 230 // Shutdown. 231 llvm::llvm_shutdown(); 232 233 return Res; 234 } 235