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),
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");
610 if (CI.getDiagnostics().hasErrorOccurred())
614 MDC->applyDiscoveredDependencies(ModuleInvocation);
616 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 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::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, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, 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.
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