clang  14.0.0git
Interpreter.cpp
Go to the documentation of this file.
1 //===------ Interpreter.cpp - Incremental Compilation and Execution -------===//
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 // This file implements the component which performs incremental code
10 // compilation and execution.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
16 #include "IncrementalExecutor.h"
17 #include "IncrementalParser.h"
18 
19 #include "clang/AST/ASTContext.h"
20 #include "clang/Basic/TargetInfo.h"
24 #include "clang/Driver/Driver.h"
25 #include "clang/Driver/Job.h"
26 #include "clang/Driver/Options.h"
27 #include "clang/Driver/Tool.h"
31 
32 #include "llvm/IR/Module.h"
33 #include "llvm/Support/Errc.h"
34 #include "llvm/Support/Host.h"
35 
36 using namespace clang;
37 
38 // FIXME: Figure out how to unify with namespace init_convenience from
39 // tools/clang-import-test/clang-import-test.cpp and
40 // examples/clang-interpreter/main.cpp
41 namespace {
42 /// Retrieves the clang CC1 specific flags out of the compilation's jobs.
43 /// \returns NULL on error.
45 GetCC1Arguments(DiagnosticsEngine *Diagnostics,
46  driver::Compilation *Compilation) {
47  // We expect to get back exactly one Command job, if we didn't something
48  // failed. Extract that job from the Compilation.
49  const driver::JobList &Jobs = Compilation->getJobs();
50  if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))
51  return llvm::createStringError(llvm::errc::not_supported,
52  "Driver initialization failed. "
53  "Unable to create a driver job");
54 
55  // The one job we find should be to invoke clang again.
56  const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));
57  if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
58  return llvm::createStringError(llvm::errc::not_supported,
59  "Driver initialization failed");
60 
61  return &Cmd->getArguments();
62 }
63 
65 CreateCI(const llvm::opt::ArgStringList &Argv) {
66  std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
68 
69  // Register the support for object-file-wrapped Clang modules.
70  // FIXME: Clang should register these container operations automatically.
71  auto PCHOps = Clang->getPCHContainerOperations();
72  PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
73  PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
74 
75  // Buffer diagnostics from argument parsing so that we can output them using
76  // a well formed diagnostic object.
78  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
79  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
81  Clang->getInvocation(), llvm::makeArrayRef(Argv.begin(), Argv.size()),
82  Diags);
83 
84  // Infer the builtin include path if unspecified.
85  if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
86  Clang->getHeaderSearchOpts().ResourceDir.empty())
87  Clang->getHeaderSearchOpts().ResourceDir =
88  CompilerInvocation::GetResourcesPath(Argv[0], nullptr);
89 
90  // Create the actual diagnostics engine.
91  Clang->createDiagnostics();
92  if (!Clang->hasDiagnostics())
93  return llvm::createStringError(llvm::errc::not_supported,
94  "Initialization failed. "
95  "Unable to create diagnostics engine");
96 
97  DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
98  if (!Success)
99  return llvm::createStringError(llvm::errc::not_supported,
100  "Initialization failed. "
101  "Unable to flush diagnostics");
102 
103  // FIXME: Merge with CompilerInstance::ExecuteAction.
104  llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
105  Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
106 
107  Clang->setTarget(TargetInfo::CreateTargetInfo(
108  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
109  if (!Clang->hasTarget())
110  return llvm::createStringError(llvm::errc::not_supported,
111  "Initialization failed. "
112  "Target is missing");
113 
114  Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts());
115 
116  return std::move(Clang);
117 }
118 
119 } // anonymous namespace
120 
122 IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
123 
124  // If we don't know ClangArgv0 or the address of main() at this point, try
125  // to guess it anyway (it's possible on some platforms).
126  std::string MainExecutableName =
127  llvm::sys::fs::getMainExecutable(nullptr, nullptr);
128 
129  ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
130 
131  // Prepending -c to force the driver to do something if no action was
132  // specified. By prepending we allow users to override the default
133  // action and use other actions in incremental mode.
134  // FIXME: Print proper driver diagnostics if the driver flags are wrong.
135  ClangArgv.insert(ClangArgv.begin() + 1, "-c");
136 
137  if (!llvm::is_contained(ClangArgv, " -x")) {
138  // We do C++ by default; append right after argv[0] if no "-x" given
139  ClangArgv.push_back("-x");
140  ClangArgv.push_back("c++");
141  }
142 
143  // Put a dummy C++ file on to ensure there's at least one compile job for the
144  // driver to construct.
145  ClangArgv.push_back("<<< inputs >>>");
146 
147  // Buffer diagnostics from argument parsing so that we can output them using a
148  // well formed diagnostic object.
151  CreateAndPopulateDiagOpts(ClangArgv);
152  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
153  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
154 
155  driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
156  llvm::sys::getProcessTriple(), Diags);
157  Driver.setCheckInputsExist(false); // the input comes from mem buffers
158  llvm::ArrayRef<const char *> RF = llvm::makeArrayRef(ClangArgv);
159  std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
160 
161  if (Compilation->getArgs().hasArg(driver::options::OPT_v))
162  Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
163 
164  auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
165  if (auto Err = ErrOrCC1Args.takeError())
166  return std::move(Err);
167 
168  return CreateCI(**ErrOrCC1Args);
169 }
170 
171 Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
172  llvm::Error &Err) {
173  llvm::ErrorAsOutParameter EAO(&Err);
174  auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
175  TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
176  IncrParser = std::make_unique<IncrementalParser>(std::move(CI),
177  *TSCtx->getContext(), Err);
178 }
179 
181 
183 Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
184  llvm::Error Err = llvm::Error::success();
185  auto Interp =
186  std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
187  if (Err)
188  return std::move(Err);
189  return std::move(Interp);
190 }
191 
193  return IncrParser->getCI();
194 }
195 
197 Interpreter::Parse(llvm::StringRef Code) {
198  return IncrParser->Parse(Code);
199 }
200 
202  assert(T.TheModule);
203  if (!IncrExecutor) {
204  const llvm::Triple &Triple =
206  llvm::Error Err = llvm::Error::success();
207  IncrExecutor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, Triple);
208 
209  if (Err)
210  return Err;
211  }
212  // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
213  if (auto Err = IncrExecutor->addModule(std::move(T.TheModule)))
214  return Err;
215 
216  if (auto Err = IncrExecutor->runCtors())
217  return Err;
218 
219  return llvm::Error::success();
220 }
clang::Interpreter::Parse
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
Definition: Interpreter.cpp:197
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
TargetInfo.h
clang::driver::JobList::begin
iterator begin()
Definition: Job.h:285
clang::driver::Compilation::getJobs
JobList & getJobs()
Definition: Compilation.h:207
clang::DiagnosticsEngine
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:191
Job.h
ModuleBuilder.h
Interpreter.h
llvm::Expected
Definition: LLVM.h:41
clang::format::ParseError::Success
@ Success
clang::PartialTranslationUnit::TheModule
std::unique_ptr< llvm::Module > TheModule
The llvm IR produced for the input.
Definition: PartialTranslationUnit.h:33
clang::Interpreter::getCompilerInstance
const CompilerInstance * getCompilerInstance() const
Definition: Interpreter.cpp:192
clang::Interpreter
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:46
Options.h
Tool.h
clang::driver::JobList
JobList - A sequence of jobs to perform.
Definition: Job.h:261
ASTContext.h
TextDiagnosticBuffer.h
clang::TargetInfo::CreateTargetInfo
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:656
clang::CompilerInstance::getASTContext
ASTContext & getASTContext() const
Definition: CompilerInstance.h:464
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:74
clang::IncrementalCompilerBuilder::create
static llvm::Expected< std::unique_ptr< CompilerInstance > > create(std::vector< const char * > &ClangArgv)
Definition: Interpreter.cpp:122
Cmd
CompileCommand Cmd
Definition: InterpolatingCompilationDatabase.cpp:130
clang::TargetInfo::getTriple
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1130
clang::driver::Command
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
Compilation.h
llvm::ArrayRef< const char * >
IncrementalParser.h
IncrementalExecutor.h
clang::driver::JobList::size
size_type size() const
Definition: Job.h:284
clang::DiagnosticIDs
Used for handling and querying diagnostic IDs.
Definition: DiagnosticIDs.h:166
clang::driver::Compilation
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:747
clang::TextDiagnosticBuffer
Definition: TextDiagnosticBuffer.h:25
clang::Interpreter::Execute
llvm::Error Execute(PartialTranslationUnit &T)
Definition: Interpreter.cpp:201
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:59
clang::Interpreter::~Interpreter
~Interpreter()
Definition: Interpreter.cpp:180
clang::PartialTranslationUnit
The class keeps track of various objects created as part of processing incremental inputs.
Definition: PartialTranslationUnit.h:29
clang::TextDiagnosticBuffer::FlushDiagnostics
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
Definition: TextDiagnosticBuffer.cpp:53
clang::CreateAndPopulateDiagOpts
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
Definition: CompilerInvocation.cpp:2283
CompilerInstance.h
clang::CompilerInvocation::GetResourcesPath
static std::string GetResourcesPath(const char *Argv0, void *MainAddr)
Get the directory where the compiler headers reside, relative to the compiler binary (found by the pa...
Definition: CompilerInvocation.cpp:2836
PreprocessorOptions.h
clang::Interpreter::create
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI)
Definition: Interpreter.cpp:183
clang::CompilerInvocation::CreateFromArgs
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
Definition: CompilerInvocation.cpp:4523
ObjectFilePCHContainerOperations.h
llvm::IntrusiveRefCntPtr
Definition: LLVM.h:47
clang::DiagnosticOptions
Options for controlling the compiler diagnostics engine.
Definition: DiagnosticOptions.h:70
clang::driver::Driver::setCheckInputsExist
void setCheckInputsExist(bool Value)
Definition: Driver.h:333
clang::driver::Driver::BuildCompilation
Compilation * BuildCompilation(ArrayRef< const char * > Args)
BuildCompilation - Construct a compilation object for a command line argument vector.
Definition: Driver.cpp:999