17#include "llvm/ADT/ScopeExit.h"
18#include "llvm/ADT/SmallVectorExtras.h"
19#include "llvm/ADT/iterator.h"
20#include "llvm/TargetParser/Host.h"
31 void handleBuildCommand(Command)
override {}
34 handleDependencyOutputOpts(
const DependencyOutputOptions &Opts)
override {
35 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
38 void handleFileDependency(StringRef
File)
override {
39 Dependencies.push_back(std::string(
File));
45 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)
override {}
46 void handleModuleDependency(ModuleDeps MD)
override {}
47 void handleDirectModuleDependency(ModuleID ID)
override {}
48 void handleVisibleModule(std::string ModuleName)
override {}
49 void handleContextHash(std::string Hash)
override {}
51 void printDependencies(std::string &S) {
52 assert(Opts &&
"Handled dependency output options.");
54 class DependencyPrinter :
public DependencyFileGenerator {
56 DependencyPrinter(DependencyOutputOptions &Opts,
57 ArrayRef<std::string> Dependencies)
58 : DependencyFileGenerator(Opts) {
59 for (
const auto &Dep : Dependencies)
63 void printDependencies(std::string &S) {
64 llvm::raw_string_ostream
OS(S);
65 outputDependencyFile(OS);
69 DependencyPrinter
Generator(*Opts, Dependencies);
74 std::unique_ptr<DependencyOutputOptions> Opts;
75 std::vector<std::string> Dependencies;
79static std::pair<std::unique_ptr<driver::Driver>,
80 std::unique_ptr<driver::Compilation>>
83 llvm::BumpPtrAllocator &Alloc) {
85 Argv.reserve(ArgStrs.size());
86 for (
const std::string &Arg : ArgStrs)
87 Argv.push_back(Arg.c_str());
89 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
90 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
91 "clang LLVM compiler", FS);
92 Driver->setTitle(
"clang_based_tool");
99 Diags.
Report(diag::err_drv_expand_response_file)
100 << llvm::toString(std::move(E));
101 return std::make_pair(
nullptr,
nullptr);
104 std::unique_ptr<driver::Compilation> Compilation(
105 Driver->BuildCompilation(Argv));
107 return std::make_pair(
nullptr,
nullptr);
109 if (Compilation->containsError())
110 return std::make_pair(
nullptr,
nullptr);
112 if (Compilation->getJobs().empty()) {
113 Diags.
Report(diag::err_fe_expected_compiler_job)
114 << llvm::join(ArgStrs,
" ");
115 return std::make_pair(
nullptr,
nullptr);
118 return std::make_pair(std::move(Driver), std::move(Compilation));
127 Out.reserve(Args.size() + 1);
129 llvm::append_range(Out, Args);
143 FS->setCurrentWorkingDirectory(WorkingDirectory);
149 llvm::BumpPtrAllocator Alloc;
150 auto DiagEngineWithDiagOpts =
153 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
158 for (
const auto &Cmd : Compilation->getJobs())
161 FrontendCommandLines.begin(), FrontendCommandLines.end());
163 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
164 Consumer, Controller, DiagConsumer,
170 return llvm::make_error<llvm::StringError>(
171 DiagPrinterWithOS.
DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
179 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1");
180 return IsCC1Input ?
Worker.computeDependencies(WorkingDirectory, CommandLine,
181 Consumer, Controller,
182 DiagConsumer, OverlayFS)
184 Worker, WorkingDirectory, CommandLine, Consumer,
185 Controller, DiagConsumer, OverlayFS);
188std::optional<std::string>
192 MakeDependencyPrinterConsumer DepConsumer;
198 DepConsumer.printDependencies(Output);
205 class P1689ModuleDependencyPrinterConsumer
206 :
public MakeDependencyPrinterConsumer {
208 P1689ModuleDependencyPrinterConsumer(
P1689Rule &Rule,
210 : Filename(
Command.Filename), Rule(Rule) {
211 Rule.PrimaryOutput =
Command.Output;
214 void handleProvidedAndRequiredStdCXXModules(
215 std::optional<P1689ModuleInfo> Provided,
216 std::vector<P1689ModuleInfo> Requires)
override {
217 Rule.Provides = std::move(Provided);
219 Rule.Provides->SourcePath = Filename.str();
220 Rule.Requires = std::move(Requires);
223 StringRef getMakeFormatDependencyOutputPath() {
226 return Opts->OutputFile;
237 std::string lookupModuleOutput(
const ModuleDeps &,
242 std::unique_ptr<DependencyActionController> clone()
const override {
243 return std::make_unique<P1689ActionController>();
248 P1689ModuleDependencyPrinterConsumer Consumer(Rule,
Command);
249 P1689ActionController Controller;
251 Controller, DiagConsumer))
254 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
255 if (!MakeformatOutputPath.empty())
256 Consumer.printDependencies(MakeformatOutput);
260static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
261 std::vector<std::string>>
264 StringRef WorkingDirectory,
265 llvm::MemoryBufferRef TUBuffer) {
267 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
270 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
271 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
272 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
273 auto InputPath = TUBuffer.getBufferIdentifier();
275 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
278 OverlayFS->pushOverlay(InMemoryOverlay);
279 std::vector<std::string> ModifiedCommandLine(CommandLine);
280 ModifiedCommandLine.emplace_back(InputPath);
282 return std::make_pair(OverlayFS, ModifiedCommandLine);
285static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
286 std::vector<std::string>>
289 StringRef WorkingDirectory) {
291 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
297 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
298 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
299 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
300 StringRef FakeInputPath(
"module-include.input");
304 static const std::string FakeInput(
306 InMemoryFS->addFile(FakeInputPath, 0,
307 llvm::MemoryBuffer::getMemBuffer(FakeInput));
309 OverlayFS->pushOverlay(InMemoryOverlay);
311 std::vector<std::string> ModifiedCommandLine(CommandLine);
312 ModifiedCommandLine.emplace_back(FakeInputPath);
314 return std::make_pair(OverlayFS, ModifiedCommandLine);
317std::optional<TranslationUnitDeps>
321 const llvm::DenseSet<ModuleID> &AlreadySeen,
323 std::optional<llvm::MemoryBufferRef> TUBuffer) {
330 std::vector<std::string> CommandLineWithTUBufferInput;
332 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
335 CommandLine = CommandLineWithTUBufferInput;
339 DiagConsumer, OverlayFS))
347 const llvm::DenseSet<ModuleID> &AlreadySeen,
350 *
this, CWD, CommandLine, LookupModuleOutput);
351 if (
auto Error = MaybeCIWithContext.takeError())
354 return MaybeCIWithContext->computeDependenciesByNameOrError(
355 ModuleName, AlreadySeen, LookupModuleOutput);
364 llvm::BumpPtrAllocator Alloc;
365 const auto [Driver, Compilation] =
371 return StringRef(Cmd.getCreator().getName()) ==
"clang";
374 const auto &Jobs = Compilation->getJobs();
375 if (
const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
380std::optional<CompilerInstanceWithContext>
385 auto [OverlayFS, ModifiedCommandLine] =
387 auto DiagEngineWithCmdAndOpts =
388 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
391 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
394 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
395 if (!CIWithContext.initialize(
396 Controller, std::move(DiagEngineWithCmdAndOpts), OverlayFS))
398 return std::move(CIWithContext);
405 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
409 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
410 MaybeFirstCC1->end());
411 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
412 std::move(CC1CommandLine));
413 if (!CIWithContext.initialize(Controller, std::move(DiagEngineWithCmdAndOpts),
416 return std::move(CIWithContext);
428 auto DiagPrinterWithOS =
429 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
432 DiagPrinterWithOS->DiagPrinter);
434 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
435 return std::move(*
Result);
442 StringRef ModuleName,
const llvm::DenseSet<ModuleID> &AlreadySeen,
448 DiagPrinterWithOS->DiagnosticOutput.clear();
454bool CompilerInstanceWithContext::initialize(
456 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
458 assert(DiagEngineWithDiagOpts &&
"Valid diagnostics engine required!");
459 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
460 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
463 assert(OverlayFS &&
"OverlayFS required!");
464 bool SawDepFS =
false;
465 OverlayFS->visit([&](llvm::vfs::FileSystem &
VFS) {
468 assert(SawDepFS &&
"OverlayFS not based on DepFS");
472 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
473 if (!OriginalInvocation) {
474 DiagEngineWithCmdAndOpts->DiagEngine->Report(
475 diag::err_fe_expected_compiler_job)
476 << llvm::join(CommandLine,
" ");
480 if (
any(
Worker.Service.getOpts().OptimizeArgs &
481 ScanningOptimizations::Macros))
485 std::shared_ptr<ModuleCache> ModCache =
487 CIPtr = std::make_unique<CompilerInstance>(
490 Worker.PCHContainerOps, std::move(ModCache));
494 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
498 auto MaybePrebuiltModulesASTMap =
500 if (!MaybePrebuiltModulesASTMap)
503 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
520 llvm::report_fatal_error(
"exceeded maximum by-name scans for worker");
522 assert(CIPtr &&
"CIPtr must be initialized before calling this method");
528 CI.getDiagnostics().Reset();
532 llvm::scope_exit CleanUp([&]() {
533 CI.clearDependencyCollectors();
537 CI.getPreprocessor().removePPCallbacks();
541 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
546 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
549 if (!Controller.
initialize(CI, ModuleInvocation))
555 std::unique_ptr<FrontendAction> Action =
556 std::make_unique<PreprocessOnlyAction>();
557 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
558 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
559 assert(ActionBeginSucceeded &&
"Action BeginSourceFile must succeed");
560 (void)ActionBeginSucceeded;
565 FileID MainFileID =
SM.getMainFileID();
573 assert(!PPFailed &&
"Preprocess must be able to enter the main file.");
575 CB = MDC->getPPCallbacks();
580 MDC->attachToPreprocessor(PP);
581 CB = MDC->getPPCallbacks();
587 FileType, PrevFID, IDLocation);
595 Path.emplace_back(IDLocation,
ModuleID);
596 auto ModResult = CI.loadModule(IDLocation, Path,
Module::Hidden,
false);
598 assert(CB &&
"Must have PPCallbacks after module loading");
608 MDC->applyDiscoveredDependencies(ModuleInvocation);
610 if (!Controller.
finalize(CI, ModuleInvocation))
Defines the Diagnostic-related interfaces.
Defines the clang::Preprocessor interface.
std::vector< std::string > getCC1CommandLine() const
Generate cc1-compatible command line arguments from this instance, wrapping the result as a std::vect...
Helper class for holding the data necessary to invoke the compiler.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
One of these records is kept for each identifier that is lexed.
@ Hidden
All of the names in this module are hidden.
This interface provides a way to observe the actions of the preprocessor as it does its thing.
virtual void EndOfMainFile()
Callback invoked when the end of the main file is reached.
virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc)
Callback invoked whenever the Lexer moves to a different file for lexing.
virtual void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported)
Callback invoked whenever there was an explicit module-import syntax.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
SourceManager & getSourceManager() const
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A simple dependency action controller that uses a callback.
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
virtual bool initialize(CompilerInstance &ScanInstance, CompilerInvocation &NewInvocation)
Initializes the scan instance and modifies the resulting TU invocation.
virtual bool finalize(CompilerInstance &ScanInstance, CompilerInvocation &NewInvocation)
Finalizes the scan instance and modifies the resulting TU invocation.
virtual void handleBuildCommand(Command Cmd)
An individual dependency scanning worker that is able to run on its own thread.
llvm::vfs::FileSystem & getVFS() const
TranslationUnitDeps takeTranslationUnitDeps()
Command - An executable path/name and argument vector to execute.
const llvm::opt::ArgStringList & getArguments() const
const char * getExecutable() const
static std::optional< CompilerInstanceWithContext > initializeFromCommandline(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, dependencies::DependencyActionController &Controller, DiagnosticConsumer &DC)
Initialize the tool's compiler instance from the commandline.
static const int32_t MaxNumOfQueries
static llvm::Expected< CompilerInstanceWithContext > initializeOrError(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, dependencies::LookupModuleOutputCallback LookupModuleOutput)
Initializing the context and the compiler instance.
llvm::Expected< dependencies::TranslationUnitDeps > computeDependenciesByNameOrError(StringRef ModuleName, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput)
Computes the dependeny for the module named ModuleName.
bool computeDependencies(StringRef ModuleName, dependencies::DependencyConsumer &Consumer, dependencies::DependencyActionController &Controller)
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
SmallVector< StringRef > getInitialStableDirs(const CompilerInstance &ScanInstance)
llvm::function_ref< std::string(const ModuleDeps &, ModuleOutputKind)> LookupModuleOutputCallback
A callback to lookup module outputs for "-fmodule-file=", "-o" etc.
@ VFS
Remove unused -ivfsoverlay arguments.
std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service, DependencyActionController &Controller)
Creates a CompilerInvocation suitable for the dependency scanner.
void initializeScanCompilerInstance(CompilerInstance &ScanInstance, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr< DependencyScanningWorkerFilesystem > DepFS)
ModuleOutputKind
An output from a module compilation, such as the path of the module file.
std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
void canonicalizeDefines(PreprocessorOptions &PPOpts)
Canonicalizes command-line macro defines (e.g. removing "-DX -UX").
std::unique_ptr< DependencyOutputOptions > createDependencyOutputOptions(const CompilerInvocation &Invocation)
Creates dependency output options to be reported to the dependency consumer, deducing missing informa...
std::optional< PrebuiltModulesAttrsMap > computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, SmallVector< StringRef > &StableDirs)
std::shared_ptr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
std::shared_ptr< ModuleDepCollector > initializeScanInstanceDependencyCollector(CompilerInstance &ScanInstance, std::unique_ptr< DependencyOutputOptions > DepOutputOpts, StringRef WorkingDirectory, DependencyConsumer &Consumer, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, llvm::SmallVector< StringRef > &StableDirs)
Create the dependency collector that will collect the produced dependencies.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
llvm::Error expandResponseFiles(SmallVectorImpl< const char * > &Args, bool ClangCLMode, llvm::BumpPtrAllocator &Alloc, llvm::vfs::FileSystem *FS=nullptr)
Expand response files from a clang driver or cc1 invocation.
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
@ Worker
'worker' clause, allowed on 'loop', Combined, and 'routine' directives.
@ Result
The result type of a method or function.
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
A command-line tool invocation that is part of building a TU.
This is used to identify a specific module.
llvm::raw_string_ostream DiagnosticsOS