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);
150 auto FS =
Worker.makeEffectiveVFS(WorkingDirectory, OverlayFS);
155 llvm::BumpPtrAllocator Alloc;
156 auto DiagEngineWithDiagOpts =
159 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
164 for (
const auto &Cmd : Compilation->getJobs())
167 FrontendCommandLines.begin(), FrontendCommandLines.end());
169 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
170 Consumer, Controller, DiagConsumer,
171 std::move(OverlayFS));
176 return llvm::make_error<llvm::StringError>(
177 DiagPrinterWithOS.
DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
185 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1");
186 return IsCC1Input ?
Worker.computeDependencies(WorkingDirectory, CommandLine,
187 Consumer, Controller,
188 DiagConsumer, OverlayFS)
190 Worker, WorkingDirectory, CommandLine, Consumer,
191 Controller, DiagConsumer, OverlayFS);
198 MakeDependencyPrinterConsumer DepConsumer;
204 DepConsumer.printDependencies(Output);
211 class P1689ModuleDependencyPrinterConsumer
212 :
public MakeDependencyPrinterConsumer {
214 P1689ModuleDependencyPrinterConsumer(
P1689Rule &Rule,
216 : Filename(
Command.Filename), Rule(Rule) {
217 Rule.PrimaryOutput =
Command.Output;
220 void handleProvidedAndRequiredStdCXXModules(
221 std::optional<P1689ModuleInfo> Provided,
222 std::vector<P1689ModuleInfo> Requires)
override {
223 Rule.Provides = std::move(Provided);
225 Rule.Provides->SourcePath = Filename.str();
226 Rule.Requires = std::move(Requires);
229 StringRef getMakeFormatDependencyOutputPath() {
243 std::string lookupModuleOutput(
const ModuleDeps &,
248 std::unique_ptr<DependencyActionController> clone()
const override {
249 return std::make_unique<P1689ActionController>();
254 P1689ModuleDependencyPrinterConsumer Consumer(Rule,
Command);
255 P1689ActionController Controller;
257 Controller, DiagConsumer))
260 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
261 if (!MakeformatOutputPath.empty())
262 Consumer.printDependencies(MakeformatOutput);
266static std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>,
267 std::vector<std::string>>
269 llvm::MemoryBufferRef TUBuffer) {
270 StringRef InputPath = TUBuffer.getBufferIdentifier();
271 auto InputBuf = llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer());
273 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
274 FS->addFile(InputPath, 0, std::move(InputBuf));
276 std::vector<std::string> ModifiedCommandLine(CommandLine);
277 ModifiedCommandLine.emplace_back(InputPath);
279 return std::make_pair(std::move(FS), ModifiedCommandLine);
282static std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>,
283 std::vector<std::string>>
288 static const std::string FakeInput(
291 StringRef InputPath =
292 llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)
293 ?
"Z:\\module-include.input"
294 :
"/module-include.input";
295 auto InputBuf = llvm::MemoryBuffer::getMemBuffer(FakeInput, InputPath);
297 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
298 FS->addFile(InputPath, 0, std::move(InputBuf));
300 std::vector<std::string> ModifiedCommandLine(CommandLine);
301 ModifiedCommandLine.emplace_back(InputPath);
303 return std::make_pair(std::move(FS), ModifiedCommandLine);
306std::optional<TranslationUnitDeps>
310 const llvm::DenseSet<ModuleID> &AlreadySeen,
312 std::optional<llvm::MemoryBufferRef> TUBuffer) {
319 std::vector<std::string> CommandLineWithTUBufferInput;
321 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
323 CommandLine = CommandLineWithTUBufferInput;
327 DiagConsumer, std::move(OverlayFS)))
335 const llvm::DenseSet<ModuleID> &AlreadySeen,
338 *
this, CWD, CommandLine, Controller);
339 if (
auto Error = MaybeCIWithContext.takeError())
342 return MaybeCIWithContext->computeDependenciesByNameOrError(
343 ModuleName, AlreadySeen, Controller);
346static std::optional<SmallVector<std::string, 0>>
353 llvm::BumpPtrAllocator Alloc;
354 const auto [Driver, Compilation] =
360 return StringRef(Cmd.getCreator().getName()) ==
"clang";
363 const auto &Jobs = Compilation->getJobs();
364 if (
const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
369std::optional<CompilerInstanceWithContext>
377 auto DiagEngineWithCmdAndOpts =
378 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, FS,
381 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
384 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
385 if (!CIWithContext.initialize(Controller,
386 std::move(DiagEngineWithCmdAndOpts),
387 std::move(OverlayFS)))
389 return std::move(CIWithContext);
396 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, FS);
400 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
401 MaybeFirstCC1->end());
402 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
403 std::move(CC1CommandLine));
404 if (!CIWithContext.initialize(Controller, std::move(DiagEngineWithCmdAndOpts),
405 std::move(OverlayFS)))
407 return std::move(CIWithContext);
414 auto DiagPrinterWithOS =
415 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
418 DiagPrinterWithOS->DiagPrinter);
420 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
421 return std::move(*
Result);
428 StringRef ModuleName,
const llvm::DenseSet<ModuleID> &AlreadySeen,
433 DiagPrinterWithOS->DiagnosticOutput.clear();
439bool CompilerInstanceWithContext::initialize(
441 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
443 assert(DiagEngineWithDiagOpts &&
"Valid diagnostics engine required!");
444 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
445 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
447 assert(OverlayFS &&
"OverlayFS required!");
448 auto FS =
Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
451 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
452 if (!OriginalInvocation) {
453 DiagEngineWithCmdAndOpts->DiagEngine->Report(
454 diag::err_fe_expected_compiler_job)
455 << llvm::join(CommandLine,
" ");
459 if (
any(
Worker.Service.getOpts().OptimizeArgs &
460 ScanningOptimizations::Macros))
464 std::shared_ptr<ModuleCache> ModCache =
466 CIPtr = std::make_unique<CompilerInstance>(
469 Worker.PCHContainerOps, std::move(ModCache));
473 CI, std::move(FS), DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
477 auto MaybePrebuiltModulesASTMap =
479 if (!MaybePrebuiltModulesASTMap)
482 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
499 llvm::report_fatal_error(
"exceeded maximum by-name scans for worker");
501 assert(CIPtr &&
"CIPtr must be initialized before calling this method");
507 CI.getDiagnostics().Reset();
511 llvm::scope_exit CleanUp([&]() {
512 CI.clearDependencyCollectors();
516 CI.getPreprocessor().removePPCallbacks();
520 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
525 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
528 if (!Controller.
initialize(CI, ModuleInvocation))
534 std::unique_ptr<FrontendAction> Action =
535 std::make_unique<PreprocessOnlyAction>();
536 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
537 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
538 assert(ActionBeginSucceeded &&
"Action BeginSourceFile must succeed");
539 (void)ActionBeginSucceeded;
544 FileID MainFileID =
SM.getMainFileID();
552 assert(!PPFailed &&
"Preprocess must be able to enter the main file.");
554 CB = MDC->getPPCallbacks();
559 MDC->attachToPreprocessor(PP);
560 CB = MDC->getPPCallbacks();
566 FileType, PrevFID, IDLocation);
574 Path.emplace_back(IDLocation,
ModuleID);
575 auto ModResult = CI.loadModule(IDLocation, Path,
Module::Hidden,
false);
577 assert(CB &&
"Must have PPCallbacks after module loading");
583 if (CI.getDiagnostics().hasErrorOccurred())
587 MDC->applyDiscoveredDependencies(ModuleInvocation);
589 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.
IntrusiveRefCntPtr< llvm::vfs::FileSystem > makeEffectiveVFS(StringRef WorkingDirectory, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS=nullptr) const
Creates the effective VFS that will be used for the scan.
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.
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