Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 1 | //===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Daniel Dunbar | c1b1729 | 2010-06-15 17:48:49 +0000 | [diff] [blame] | 10 | #include "clang/CodeGen/CodeGenAction.h" |
Chandler Carruth | 8675b4a | 2012-12-04 09:37:22 +0000 | [diff] [blame] | 11 | #include "clang/Basic/DiagnosticOptions.h" |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 12 | #include "clang/Driver/Compilation.h" |
| 13 | #include "clang/Driver/Driver.h" |
| 14 | #include "clang/Driver/Tool.h" |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 15 | #include "clang/Frontend/CompilerInstance.h" |
Chandler Carruth | 8675b4a | 2012-12-04 09:37:22 +0000 | [diff] [blame] | 16 | #include "clang/Frontend/CompilerInvocation.h" |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 17 | #include "clang/Frontend/FrontendDiagnostic.h" |
| 18 | #include "clang/Frontend/TextDiagnosticPrinter.h" |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 19 | #include "llvm/ADT/SmallString.h" |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 20 | #include "llvm/ExecutionEngine/ExecutionEngine.h" |
Rafael Espindola | e89d289 | 2014-07-24 17:13:09 +0000 | [diff] [blame] | 21 | #include "llvm/ExecutionEngine/MCJIT.h" |
Chandler Carruth | ffd5551 | 2013-01-02 11:45:17 +0000 | [diff] [blame] | 22 | #include "llvm/IR/Module.h" |
Rafael Espindola | 9678d27 | 2013-06-26 05:03:40 +0000 | [diff] [blame] | 23 | #include "llvm/Support/FileSystem.h" |
Michael J. Spencer | 8aaf499 | 2010-11-29 18:12:39 +0000 | [diff] [blame] | 24 | #include "llvm/Support/Host.h" |
Chandler Carruth | 8675b4a | 2012-12-04 09:37:22 +0000 | [diff] [blame] | 25 | #include "llvm/Support/ManagedStatic.h" |
Michael J. Spencer | 8aaf499 | 2010-11-29 18:12:39 +0000 | [diff] [blame] | 26 | #include "llvm/Support/Path.h" |
Evan Cheng | 494eb06 | 2011-08-24 18:09:14 +0000 | [diff] [blame] | 27 | #include "llvm/Support/TargetSelect.h" |
Chandler Carruth | 8675b4a | 2012-12-04 09:37:22 +0000 | [diff] [blame] | 28 | #include "llvm/Support/raw_ostream.h" |
Ahmed Charles | dfca6f9 | 2014-03-09 11:36:40 +0000 | [diff] [blame] | 29 | #include <memory> |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 30 | using namespace clang; |
| 31 | using namespace clang::driver; |
| 32 | |
Dan Gohman | ff66a7c | 2010-11-17 17:23:53 +0000 | [diff] [blame] | 33 | // This function isn't referenced outside its translation unit, but it |
| 34 | // can't use the "static" keyword because its address is used for |
| 35 | // GetMainExecutable (since some platforms don't support taking the |
| 36 | // address of main, and some platforms can't implement GetMainExecutable |
| 37 | // without being given the address of a function in the main executable). |
Rafael Espindola | 9678d27 | 2013-06-26 05:03:40 +0000 | [diff] [blame] | 38 | std::string GetExecutablePath(const char *Argv0) { |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 39 | // This just needs to be some symbol in the binary; C++ doesn't |
| 40 | // allow taking the address of ::main however. |
| 41 | void *MainAddr = (void*) (intptr_t) GetExecutablePath; |
Rafael Espindola | 9678d27 | 2013-06-26 05:03:40 +0000 | [diff] [blame] | 42 | return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 43 | } |
| 44 | |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 45 | static llvm::ExecutionEngine * |
| 46 | createExecutionEngine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr) { |
| 47 | return llvm::EngineBuilder(std::move(M)) |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 48 | .setEngineKind(llvm::EngineKind::Either) |
| 49 | .setErrorStr(ErrorStr) |
| 50 | .create(); |
Rafael Espindola | fb3d5d1 | 2014-07-24 15:54:23 +0000 | [diff] [blame] | 51 | } |
| 52 | |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 53 | static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp) { |
Alp Toker | 60c88cb | 2014-07-01 03:19:50 +0000 | [diff] [blame] | 54 | llvm::InitializeNativeTarget(); |
Rafael Espindola | e89d289 | 2014-07-24 17:13:09 +0000 | [diff] [blame] | 55 | llvm::InitializeNativeTargetAsmPrinter(); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 56 | |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 57 | llvm::Module &M = *Mod; |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 58 | std::string Error; |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 59 | std::unique_ptr<llvm::ExecutionEngine> EE( |
| 60 | createExecutionEngine(std::move(Mod), &Error)); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 61 | if (!EE) { |
| 62 | llvm::errs() << "unable to make execution engine: " << Error << "\n"; |
| 63 | return 255; |
| 64 | } |
| 65 | |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 66 | llvm::Function *EntryFn = M.getFunction("main"); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 67 | if (!EntryFn) { |
| 68 | llvm::errs() << "'main' function not found in module.\n"; |
| 69 | return 255; |
| 70 | } |
| 71 | |
| 72 | // FIXME: Support passing arguments. |
| 73 | std::vector<std::string> Args; |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 74 | Args.push_back(M.getModuleIdentifier()); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 75 | |
Rafael Espindola | e89d289 | 2014-07-24 17:13:09 +0000 | [diff] [blame] | 76 | EE->finalizeObject(); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 77 | return EE->runFunctionAsMain(EntryFn, Args, envp); |
| 78 | } |
| 79 | |
| 80 | int main(int argc, const char **argv, char * const *envp) { |
| 81 | void *MainAddr = (void*) (intptr_t) GetExecutablePath; |
Rafael Espindola | 9678d27 | 2013-06-26 05:03:40 +0000 | [diff] [blame] | 82 | std::string Path = GetExecutablePath(argv[0]); |
Douglas Gregor | cdb4d69 | 2012-10-23 22:36:49 +0000 | [diff] [blame] | 83 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
Benjamin Kramer | 1921fac | 2010-08-26 13:48:56 +0000 | [diff] [blame] | 84 | TextDiagnosticPrinter *DiagClient = |
Douglas Gregor | cdb4d69 | 2012-10-23 22:36:49 +0000 | [diff] [blame] | 85 | new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 86 | |
Dylan Noblesmith | c95d819 | 2012-02-20 14:00:23 +0000 | [diff] [blame] | 87 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
Douglas Gregor | cdb4d69 | 2012-10-23 22:36:49 +0000 | [diff] [blame] | 88 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); |
Rafael Espindola | 3175daa | 2014-07-24 20:47:42 +0000 | [diff] [blame] | 89 | |
| 90 | // Use ELF on windows for now. |
| 91 | std::string TripleStr = llvm::sys::getProcessTriple(); |
| 92 | llvm::Triple T(TripleStr); |
| 93 | if (T.isOSBinFormatCOFF()) |
| 94 | T.setObjectFormat(llvm::Triple::ELF); |
| 95 | |
| 96 | Driver TheDriver(Path, T.str(), Diags); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 97 | TheDriver.setTitle("clang interpreter"); |
Alp Toker | ed412da | 2014-07-09 01:37:36 +0000 | [diff] [blame] | 98 | TheDriver.setCheckInputsExist(false); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 99 | |
| 100 | // FIXME: This is a hack to try to force the driver to do something we can |
| 101 | // recognize. We need to extend the driver library to support this use model |
| 102 | // (basically, exactly one input, and the operation mode is hard wired). |
Dmitri Gribenko | f857950 | 2013-01-12 19:30:44 +0000 | [diff] [blame] | 103 | SmallVector<const char *, 16> Args(argv, argv + argc); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 104 | Args.push_back("-fsyntax-only"); |
Ahmed Charles | af94d56 | 2014-03-09 11:34:25 +0000 | [diff] [blame] | 105 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 106 | if (!C) |
| 107 | return 0; |
| 108 | |
| 109 | // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. |
| 110 | |
| 111 | // We expect to get back exactly one command job, if we didn't something |
| 112 | // failed. Extract that job from the compilation. |
| 113 | const driver::JobList &Jobs = C->getJobs(); |
Justin Bogner | 4075f6c | 2014-10-03 01:08:27 +0000 | [diff] [blame] | 114 | if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { |
Dylan Noblesmith | f1a13f2 | 2012-02-13 12:32:26 +0000 | [diff] [blame] | 115 | SmallString<256> Msg; |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 116 | llvm::raw_svector_ostream OS(Msg); |
Hans Wennborg | b212b34 | 2013-09-12 18:23:34 +0000 | [diff] [blame] | 117 | Jobs.Print(OS, "; ", true); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 118 | Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); |
| 119 | return 1; |
| 120 | } |
| 121 | |
Justin Bogner | 4075f6c | 2014-10-03 01:08:27 +0000 | [diff] [blame] | 122 | const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin()); |
David Blaikie | c11bf80 | 2014-09-04 16:04:28 +0000 | [diff] [blame] | 123 | if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") { |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 124 | Diags.Report(diag::err_fe_expected_clang_command); |
| 125 | return 1; |
| 126 | } |
| 127 | |
| 128 | // Initialize a compiler invocation object from the clang (-cc1) arguments. |
David Blaikie | c11bf80 | 2014-09-04 16:04:28 +0000 | [diff] [blame] | 129 | const driver::ArgStringList &CCArgs = Cmd.getArguments(); |
Ahmed Charles | af94d56 | 2014-03-09 11:34:25 +0000 | [diff] [blame] | 130 | std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation); |
Benjamin Kramer | 25d3d78 | 2010-04-20 11:50:39 +0000 | [diff] [blame] | 131 | CompilerInvocation::CreateFromArgs(*CI, |
| 132 | const_cast<const char **>(CCArgs.data()), |
| 133 | const_cast<const char **>(CCArgs.data()) + |
| 134 | CCArgs.size(), |
Benjamin Kramer | 6a2542b | 2010-04-20 11:55:38 +0000 | [diff] [blame] | 135 | Diags); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 136 | |
| 137 | // Show the invocation, with -v. |
| 138 | if (CI->getHeaderSearchOpts().Verbose) { |
| 139 | llvm::errs() << "clang invocation:\n"; |
Hans Wennborg | b212b34 | 2013-09-12 18:23:34 +0000 | [diff] [blame] | 140 | Jobs.Print(llvm::errs(), "\n", true); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 141 | llvm::errs() << "\n"; |
| 142 | } |
| 143 | |
| 144 | // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. |
| 145 | |
| 146 | // Create a compiler instance to handle the actual work. |
| 147 | CompilerInstance Clang; |
Ahmed Charles | a337444 | 2014-03-09 11:46:32 +0000 | [diff] [blame] | 148 | Clang.setInvocation(CI.release()); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 149 | |
| 150 | // Create the compilers actual diagnostics engine. |
Sean Silva | f1b49e2 | 2013-01-20 01:58:28 +0000 | [diff] [blame] | 151 | Clang.createDiagnostics(); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 152 | if (!Clang.hasDiagnostics()) |
| 153 | return 1; |
| 154 | |
| 155 | // Infer the builtin include path if unspecified. |
| 156 | if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && |
| 157 | Clang.getHeaderSearchOpts().ResourceDir.empty()) |
| 158 | Clang.getHeaderSearchOpts().ResourceDir = |
| 159 | CompilerInvocation::GetResourcesPath(argv[0], MainAddr); |
| 160 | |
| 161 | // Create and execute the frontend to generate an LLVM bitcode module. |
Ahmed Charles | af94d56 | 2014-03-09 11:34:25 +0000 | [diff] [blame] | 162 | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction()); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 163 | if (!Clang.ExecuteAction(*Act)) |
| 164 | return 1; |
| 165 | |
| 166 | int Res = 255; |
Rafael Espindola | aca3be8 | 2014-08-19 14:32:16 +0000 | [diff] [blame] | 167 | if (std::unique_ptr<llvm::Module> Module = Act->takeModule()) |
Rafael Espindola | a296664 | 2014-08-19 04:04:30 +0000 | [diff] [blame] | 168 | Res = Execute(std::move(Module), envp); |
Daniel Dunbar | 0076d94 | 2010-02-25 08:49:05 +0000 | [diff] [blame] | 169 | |
| 170 | // Shutdown. |
| 171 | |
| 172 | llvm::llvm_shutdown(); |
| 173 | |
| 174 | return Res; |
| 175 | } |