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