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 RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr}; 58 IRCompileLayer CompileLayer{ES, ObjectLayer, SimpleCompiler(*TM)}; 59 60 static std::unique_ptr<SectionMemoryManager> createMemMgr() { 61 return std::make_unique<SectionMemoryManager>(); 62 } 63 64 SimpleJIT( 65 std::unique_ptr<TargetMachine> TM, DataLayout DL, 66 std::unique_ptr<DynamicLibrarySearchGenerator> ProcessSymbolsGenerator) 67 : TM(std::move(TM)), DL(std::move(DL)) { 68 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 69 ES.getMainJITDylib().addGenerator(std::move(ProcessSymbolsGenerator)); 70 } 71 72 public: 73 static Expected<std::unique_ptr<SimpleJIT>> Create() { 74 auto JTMB = JITTargetMachineBuilder::detectHost(); 75 if (!JTMB) 76 return JTMB.takeError(); 77 78 auto TM = JTMB->createTargetMachine(); 79 if (!TM) 80 return TM.takeError(); 81 82 auto DL = (*TM)->createDataLayout(); 83 84 auto ProcessSymbolsGenerator = 85 DynamicLibrarySearchGenerator::GetForCurrentProcess( 86 DL.getGlobalPrefix()); 87 88 if (!ProcessSymbolsGenerator) 89 return ProcessSymbolsGenerator.takeError(); 90 91 return std::unique_ptr<SimpleJIT>(new SimpleJIT( 92 std::move(*TM), std::move(DL), std::move(*ProcessSymbolsGenerator))); 93 } 94 95 const TargetMachine &getTargetMachine() const { return *TM; } 96 97 Error addModule(ThreadSafeModule M) { 98 return CompileLayer.add(ES.getMainJITDylib(), std::move(M)); 99 } 100 101 Expected<JITEvaluatedSymbol> findSymbol(const StringRef &Name) { 102 return ES.lookup({&ES.getMainJITDylib()}, Mangle(Name)); 103 } 104 105 Expected<JITTargetAddress> getSymbolAddress(const StringRef &Name) { 106 auto Sym = findSymbol(Name); 107 if (!Sym) 108 return Sym.takeError(); 109 return Sym->getAddress(); 110 } 111 }; 112 113 } // end namespace orc 114 } // end namespace llvm 115 116 llvm::ExitOnError ExitOnErr; 117 118 int main(int argc, const char **argv) { 119 // This just needs to be some symbol in the binary; C++ doesn't 120 // allow taking the address of ::main however. 121 void *MainAddr = (void*) (intptr_t) GetExecutablePath; 122 std::string Path = GetExecutablePath(argv[0], MainAddr); 123 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 124 TextDiagnosticPrinter *DiagClient = 125 new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); 126 127 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 128 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); 129 130 const std::string TripleStr = llvm::sys::getProcessTriple(); 131 llvm::Triple T(TripleStr); 132 133 // Use ELF on Windows-32 and MingW for now. 134 #ifndef CLANG_INTERPRETER_COFF_FORMAT 135 if (T.isOSBinFormatCOFF()) 136 T.setObjectFormat(llvm::Triple::ELF); 137 #endif 138 139 ExitOnErr.setBanner("clang interpreter"); 140 141 Driver TheDriver(Path, T.str(), Diags); 142 TheDriver.setTitle("clang interpreter"); 143 TheDriver.setCheckInputsExist(false); 144 145 // FIXME: This is a hack to try to force the driver to do something we can 146 // recognize. We need to extend the driver library to support this use model 147 // (basically, exactly one input, and the operation mode is hard wired). 148 SmallVector<const char *, 16> Args(argv, argv + argc); 149 Args.push_back("-fsyntax-only"); 150 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); 151 if (!C) 152 return 0; 153 154 // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. 155 156 // We expect to get back exactly one command job, if we didn't something 157 // failed. Extract that job from the compilation. 158 const driver::JobList &Jobs = C->getJobs(); 159 if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { 160 SmallString<256> Msg; 161 llvm::raw_svector_ostream OS(Msg); 162 Jobs.Print(OS, "; ", true); 163 Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); 164 return 1; 165 } 166 167 const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin()); 168 if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") { 169 Diags.Report(diag::err_fe_expected_clang_command); 170 return 1; 171 } 172 173 // Initialize a compiler invocation object from the clang (-cc1) arguments. 174 const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments(); 175 std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation); 176 CompilerInvocation::CreateFromArgs(*CI, CCArgs, Diags); 177 178 // Show the invocation, with -v. 179 if (CI->getHeaderSearchOpts().Verbose) { 180 llvm::errs() << "clang invocation:\n"; 181 Jobs.Print(llvm::errs(), "\n", true); 182 llvm::errs() << "\n"; 183 } 184 185 // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. 186 187 // Create a compiler instance to handle the actual work. 188 CompilerInstance Clang; 189 Clang.setInvocation(std::move(CI)); 190 191 // Create the compilers actual diagnostics engine. 192 Clang.createDiagnostics(); 193 if (!Clang.hasDiagnostics()) 194 return 1; 195 196 // Infer the builtin include path if unspecified. 197 if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && 198 Clang.getHeaderSearchOpts().ResourceDir.empty()) 199 Clang.getHeaderSearchOpts().ResourceDir = 200 CompilerInvocation::GetResourcesPath(argv[0], MainAddr); 201 202 // Create and execute the frontend to generate an LLVM bitcode module. 203 std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction()); 204 if (!Clang.ExecuteAction(*Act)) 205 return 1; 206 207 llvm::InitializeNativeTarget(); 208 llvm::InitializeNativeTargetAsmPrinter(); 209 210 int Res = 255; 211 std::unique_ptr<llvm::LLVMContext> Ctx(Act->takeLLVMContext()); 212 std::unique_ptr<llvm::Module> Module = Act->takeModule(); 213 214 if (Module) { 215 auto J = ExitOnErr(llvm::orc::SimpleJIT::Create()); 216 217 ExitOnErr(J->addModule( 218 llvm::orc::ThreadSafeModule(std::move(Module), std::move(Ctx)))); 219 auto Main = (int (*)(...))ExitOnErr(J->getSymbolAddress("main")); 220 Res = Main(); 221 } 222 223 // Shutdown. 224 llvm::llvm_shutdown(); 225 226 return Res; 227 } 228