19#include "llvm/ADT/ScopeExit.h"
20#include "llvm/ADT/SmallVectorExtras.h"
21#include "llvm/ADT/iterator.h"
22#include "llvm/TargetParser/Host.h"
33 void handleBuildCommand(Command)
override {}
36 handleDependencyOutputOpts(
const DependencyOutputOptions &Opts)
override {
37 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
40 void handleFileDependency(StringRef
File)
override {
41 SmallString<128> NormalizedFile =
File;
42 llvm::sys::path::remove_dots(NormalizedFile,
true);
43 Dependencies.emplace_back(NormalizedFile.str());
49 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)
override {}
50 void handleModuleDependency(ModuleDeps MD)
override {
52 DependenciesFromModules.push_back(std::string(
File));
55 void handleDirectModuleDependency(ModuleID ID)
override {}
56 void handleVisibleModule(std::string ModuleName)
override {}
57 void handleContextHash(std::string Hash)
override {}
59 void printDependencies(std::string &S) {
60 assert(Opts &&
"Handled dependency output options.");
62 class DependencyPrinter :
public DependencyFileGenerator {
64 DependencyPrinter(DependencyOutputOptions &Opts,
65 ArrayRef<std::string> Dependencies,
66 ArrayRef<std::string> ModuleDependencies)
67 : DependencyFileGenerator(Opts) {
68 for (
const auto &Dep : Dependencies)
70 for (
const auto &Dep : ModuleDependencies)
74 void printDependencies(std::string &S) {
75 llvm::raw_string_ostream
OS(S);
76 outputDependencyFile(OS);
80 DependencyPrinter
Generator(*Opts, Dependencies, DependenciesFromModules);
85 std::unique_ptr<DependencyOutputOptions> Opts;
86 std::vector<std::string> Dependencies;
87 std::vector<std::string> DependenciesFromModules;
91static std::pair<std::unique_ptr<driver::Driver>,
92 std::unique_ptr<driver::Compilation>>
95 llvm::BumpPtrAllocator &Alloc) {
97 Argv.reserve(ArgStrs.size());
98 for (
const std::string &Arg : ArgStrs)
99 Argv.push_back(Arg.c_str());
101 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
102 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
103 "clang LLVM compiler", FS);
104 Driver->setTitle(
"clang_based_tool");
111 Diags.
Report(diag::err_drv_expand_response_file)
112 << llvm::toString(std::move(E));
113 return std::make_pair(
nullptr,
nullptr);
116 std::unique_ptr<driver::Compilation> Compilation(
117 Driver->BuildCompilation(Argv));
119 return std::make_pair(
nullptr,
nullptr);
121 if (Compilation->containsError())
122 return std::make_pair(
nullptr,
nullptr);
124 if (Compilation->getJobs().empty()) {
125 Diags.
Report(diag::err_fe_expected_compiler_job)
126 << llvm::join(ArgStrs,
" ");
127 return std::make_pair(
nullptr,
nullptr);
130 return std::make_pair(std::move(Driver), std::move(Compilation));
139 Out.reserve(Args.size() + 1);
141 llvm::append_range(Out, Args);
155 FS->setCurrentWorkingDirectory(WorkingDirectory);
161 llvm::BumpPtrAllocator Alloc;
162 auto DiagEngineWithDiagOpts =
165 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
170 for (
const auto &Cmd : Compilation->getJobs())
173 FrontendCommandLines.begin(), FrontendCommandLines.end());
175 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
176 Consumer, Controller, DiagConsumer,
182 return llvm::make_error<llvm::StringError>(
183 DiagPrinterWithOS.
DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
191 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1");
192 return IsCC1Input ?
Worker.computeDependencies(WorkingDirectory, CommandLine,
193 Consumer, Controller,
194 DiagConsumer, OverlayFS)
196 Worker, WorkingDirectory, CommandLine, Consumer,
197 Controller, DiagConsumer, OverlayFS);
204 MakeDependencyPrinterConsumer DepConsumer;
210 DepConsumer.printDependencies(Output);
217 class P1689ModuleDependencyPrinterConsumer
218 :
public MakeDependencyPrinterConsumer {
220 P1689ModuleDependencyPrinterConsumer(
P1689Rule &Rule,
222 : Filename(
Command.Filename), Rule(Rule) {
223 Rule.PrimaryOutput =
Command.Output;
226 void handleProvidedAndRequiredStdCXXModules(
227 std::optional<P1689ModuleInfo> Provided,
228 std::vector<P1689ModuleInfo> Requires)
override {
229 Rule.Provides = std::move(Provided);
231 Rule.Provides->SourcePath = Filename.str();
232 Rule.Requires = std::move(Requires);
235 StringRef getMakeFormatDependencyOutputPath() {
249 std::string lookupModuleOutput(
const ModuleDeps &,
254 std::unique_ptr<DependencyActionController> clone()
const override {
255 return std::make_unique<P1689ActionController>();
260 P1689ModuleDependencyPrinterConsumer Consumer(Rule,
Command);
261 P1689ActionController Controller;
263 Controller, DiagConsumer))
266 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
267 if (!MakeformatOutputPath.empty())
268 Consumer.printDependencies(MakeformatOutput);
272static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
273 std::vector<std::string>>
276 StringRef WorkingDirectory,
277 llvm::MemoryBufferRef TUBuffer) {
279 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
282 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
283 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
284 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
285 auto InputPath = TUBuffer.getBufferIdentifier();
287 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
290 OverlayFS->pushOverlay(InMemoryOverlay);
291 std::vector<std::string> ModifiedCommandLine(CommandLine);
292 ModifiedCommandLine.emplace_back(InputPath);
294 return std::make_pair(OverlayFS, ModifiedCommandLine);
297static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
298 std::vector<std::string>>
301 StringRef WorkingDirectory) {
303 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
309 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
310 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
311 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
312 StringRef FakeInputPath(
"module-include.input");
316 static const std::string FakeInput(
318 InMemoryFS->addFile(FakeInputPath, 0,
319 llvm::MemoryBuffer::getMemBuffer(FakeInput));
321 OverlayFS->pushOverlay(InMemoryOverlay);
323 std::vector<std::string> ModifiedCommandLine(CommandLine);
324 ModifiedCommandLine.emplace_back(FakeInputPath);
326 return std::make_pair(OverlayFS, ModifiedCommandLine);
329std::optional<TranslationUnitDeps>
333 const llvm::DenseSet<ModuleID> &AlreadySeen,
335 std::optional<llvm::MemoryBufferRef> TUBuffer) {
342 std::vector<std::string> CommandLineWithTUBufferInput;
344 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
347 CommandLine = CommandLineWithTUBufferInput;
351 DiagConsumer, OverlayFS))
359 const llvm::DenseSet<ModuleID> &AlreadySeen,
362 *
this, CWD, CommandLine, Controller);
363 if (
auto Error = MaybeCIWithContext.takeError())
366 return MaybeCIWithContext->computeDependenciesByNameOrError(
367 ModuleName, AlreadySeen, Controller);
376 llvm::BumpPtrAllocator Alloc;
377 const auto [Driver, Compilation] =
383 return StringRef(Cmd.getCreator().getName()) ==
"clang";
386 const auto &Jobs = Compilation->getJobs();
387 if (
const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
392std::optional<CompilerInstanceWithContext>
397 auto [OverlayFS, ModifiedCommandLine] =
399 auto DiagEngineWithCmdAndOpts =
400 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
403 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
406 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
407 if (!CIWithContext.initialize(
408 Controller, std::move(DiagEngineWithCmdAndOpts), OverlayFS))
410 return std::move(CIWithContext);
417 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
421 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
422 MaybeFirstCC1->end());
423 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
424 std::move(CC1CommandLine));
425 if (!CIWithContext.initialize(Controller, std::move(DiagEngineWithCmdAndOpts),
428 return std::move(CIWithContext);
435 auto DiagPrinterWithOS =
436 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
439 DiagPrinterWithOS->DiagPrinter);
441 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
442 return std::move(*
Result);
449 StringRef ModuleName,
const llvm::DenseSet<ModuleID> &AlreadySeen,
454 DiagPrinterWithOS->DiagnosticOutput.clear();
460bool CompilerInstanceWithContext::initialize(
462 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
464 assert(DiagEngineWithDiagOpts &&
"Valid diagnostics engine required!");
465 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
466 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
469 assert(OverlayFS &&
"OverlayFS required!");
470 bool SawDepFS =
false;
471 OverlayFS->visit([&](llvm::vfs::FileSystem &
VFS) {
474 assert(SawDepFS &&
"OverlayFS not based on DepFS");
478 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
479 if (!OriginalInvocation) {
480 DiagEngineWithCmdAndOpts->DiagEngine->Report(
481 diag::err_fe_expected_compiler_job)
482 << llvm::join(CommandLine,
" ");
486 if (
any(
Worker.Service.getOpts().OptimizeArgs &
487 ScanningOptimizations::Macros))
491 std::shared_ptr<ModuleCache> ModCache =
493 CIPtr = std::make_unique<CompilerInstance>(
496 Worker.PCHContainerOps, std::move(ModCache));
500 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
504 auto MaybePrebuiltModulesASTMap =
506 if (!MaybePrebuiltModulesASTMap)
509 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
526 llvm::report_fatal_error(
"exceeded maximum by-name scans for worker");
528 assert(CIPtr &&
"CIPtr must be initialized before calling this method");
534 CI.getDiagnostics().Reset();
538 llvm::scope_exit CleanUp([&]() {
539 CI.clearDependencyCollectors();
543 CI.getPreprocessor().removePPCallbacks();
547 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), Consumer,
552 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
555 if (!Controller.
initialize(CI, ModuleInvocation))
561 std::unique_ptr<FrontendAction> Action =
562 std::make_unique<PreprocessOnlyAction>();
563 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
564 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
565 assert(ActionBeginSucceeded &&
"Action BeginSourceFile must succeed");
566 (void)ActionBeginSucceeded;
571 FileID MainFileID =
SM.getMainFileID();
579 assert(!PPFailed &&
"Preprocess must be able to enter the main file.");
581 CB = MDC->getPPCallbacks();
586 MDC->attachToPreprocessor(PP);
587 CB = MDC->getPPCallbacks();
593 FileType, PrevFID, IDLocation);
601 Path.emplace_back(IDLocation,
ModuleID);
602 auto ModResult = CI.loadModule(IDLocation, Path,
Module::Hidden,
false);
604 assert(CB &&
"Must have PPCallbacks after module loading");
614 if (CI.getDiagnostics().hasErrorOccurred())
617 MDC->applyDiscoveredDependencies(ModuleInvocation);
619 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.
DependencyOutputFormat OutputFormat
The format for the dependency file.
std::string OutputFile
The file to write dependency output to.
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 llvm::Expected< CompilerInstanceWithContext > initializeOrError(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, dependencies::DependencyActionController &Controller)
Initializing the context and the compiler instance.
static const int32_t MaxNumOfQueries
bool computeDependencies(StringRef ModuleName, dependencies::DependencyConsumer &Consumer, dependencies::DependencyActionController &Controller)
llvm::Expected< dependencies::TranslationUnitDeps > computeDependenciesByNameOrError(StringRef ModuleName, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::DependencyActionController &Controller)
Computes the dependeny for the module named ModuleName.
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::shared_ptr< ModuleDepCollector > initializeScanInstanceDependencyCollector(CompilerInstance &ScanInstance, std::unique_ptr< DependencyOutputOptions > DepOutputOpts, DependencyConsumer &Consumer, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, SmallVector< StringRef > &StableDirs)
Create the dependency collector that will collect the produced dependencies.
std::optional< PrebuiltModulesAttrsMap > computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, SmallVector< StringRef > &StableDirs)
std::shared_ptr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
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.
void forEachFileDep(llvm::function_ref< void(StringRef)> Cb) const
Invokes Cb for all file dependencies of this module.
This is used to identify a specific module.
llvm::raw_string_ostream DiagnosticsOS