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 &,
244 P1689ModuleDependencyPrinterConsumer Consumer(Rule,
Command);
245 P1689ActionController Controller;
247 Controller, DiagConsumer))
250 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
251 if (!MakeformatOutputPath.empty())
252 Consumer.printDependencies(MakeformatOutput);
256static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
257 std::vector<std::string>>
260 StringRef WorkingDirectory,
261 llvm::MemoryBufferRef TUBuffer) {
263 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
266 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
267 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
268 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
269 auto InputPath = TUBuffer.getBufferIdentifier();
271 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
274 OverlayFS->pushOverlay(InMemoryOverlay);
275 std::vector<std::string> ModifiedCommandLine(CommandLine);
276 ModifiedCommandLine.emplace_back(InputPath);
278 return std::make_pair(OverlayFS, ModifiedCommandLine);
284static const std::string
288static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
289 std::vector<std::string>>
292 StringRef WorkingDirectory) {
294 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
300 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
301 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
302 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
303 StringRef FakeInputPath(
"module-include.input");
304 InMemoryFS->addFile(FakeInputPath, 0,
305 llvm::MemoryBuffer::getMemBuffer(
FakeInput));
307 OverlayFS->pushOverlay(InMemoryOverlay);
309 std::vector<std::string> ModifiedCommandLine(CommandLine);
310 ModifiedCommandLine.emplace_back(FakeInputPath);
312 return std::make_pair(OverlayFS, ModifiedCommandLine);
315std::optional<TranslationUnitDeps>
319 const llvm::DenseSet<ModuleID> &AlreadySeen,
321 std::optional<llvm::MemoryBufferRef> TUBuffer) {
328 std::vector<std::string> CommandLineWithTUBufferInput;
330 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
333 CommandLine = CommandLineWithTUBufferInput;
337 DiagConsumer, OverlayFS))
345 const llvm::DenseSet<ModuleID> &AlreadySeen,
347 auto MaybeCIWithContext =
349 if (
auto Error = MaybeCIWithContext.takeError())
352 return MaybeCIWithContext->computeDependenciesByNameOrError(
353 ModuleName, AlreadySeen, LookupModuleOutput);
362 llvm::BumpPtrAllocator Alloc;
363 const auto [Driver, Compilation] =
369 return StringRef(Cmd.getCreator().getName()) ==
"clang";
372 const auto &Jobs = Compilation->getJobs();
373 if (
const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
378std::optional<CompilerInstanceWithContext>
382 auto [OverlayFS, ModifiedCommandLine] =
384 auto DiagEngineWithCmdAndOpts =
385 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
388 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
391 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
392 if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts),
395 return std::move(CIWithContext);
402 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
406 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
407 MaybeFirstCC1->end());
408 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
409 std::move(CC1CommandLine));
410 if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts), OverlayFS))
412 return std::move(CIWithContext);
419 auto DiagPrinterWithOS =
420 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
423 DiagPrinterWithOS->DiagPrinter);
425 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
426 return std::move(*
Result);
433 StringRef ModuleName,
const llvm::DenseSet<ModuleID> &AlreadySeen,
439 DiagPrinterWithOS->DiagnosticOutput.clear();
445bool CompilerInstanceWithContext::initialize(
446 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
448 assert(DiagEngineWithDiagOpts &&
"Valid diagnostics engine required!");
449 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
450 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
453 assert(OverlayFS &&
"OverlayFS required!");
454 bool SawDepFS =
false;
455 OverlayFS->visit([&](llvm::vfs::FileSystem &
VFS) {
458 assert(SawDepFS &&
"OverlayFS not based on DepFS");
462 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
463 if (!OriginalInvocation) {
464 DiagEngineWithCmdAndOpts->DiagEngine->Report(
465 diag::err_fe_expected_compiler_job)
466 << llvm::join(CommandLine,
" ");
470 if (
any(
Worker.Service.getOpts().OptimizeArgs &
471 ScanningOptimizations::Macros))
475 std::shared_ptr<ModuleCache> ModCache =
477 CIPtr = std::make_unique<CompilerInstance>(
479 Worker.PCHContainerOps, std::move(ModCache));
483 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
487 auto MaybePrebuiltModulesASTMap =
489 if (!MaybePrebuiltModulesASTMap)
492 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
509 llvm::report_fatal_error(
"exceeded maximum by-name scans for worker");
511 assert(CIPtr &&
"CIPtr must be initialized before calling this method");
517 CI.getDiagnostics().Reset();
521 llvm::scope_exit CleanUp([&]() {
522 CI.clearDependencyCollectors();
526 CI.getPreprocessor().removePPCallbacks();
530 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
535 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
540 std::unique_ptr<FrontendAction> Action =
541 std::make_unique<PreprocessOnlyAction>();
542 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
543 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
544 assert(ActionBeginSucceeded &&
"Action BeginSourceFile must succeed");
545 (void)ActionBeginSucceeded;
550 FileID MainFileID =
SM.getMainFileID();
558 assert(!PPFailed &&
"Preprocess must be able to enter the main file.");
560 CB = MDC->getPPCallbacks();
565 MDC->attachToPreprocessor(PP);
566 CB = MDC->getPPCallbacks();
572 FileType, PrevFID, IDLocation);
580 Path.emplace_back(IDLocation,
ModuleID);
581 auto ModResult = CI.loadModule(IDLocation, Path,
Module::Hidden,
false);
583 assert(CB &&
"Must have PPCallbacks after module loading");
594 MDC->applyDiscoveredDependencies(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 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 llvm::Expected< CompilerInstanceWithContext > initializeOrError(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine)
Initializing the context and the compiler instance.
static std::optional< CompilerInstanceWithContext > initializeFromCommandline(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, DiagnosticConsumer &DC)
Initialize the tool's compiler instance from the commandline.
static const int32_t MaxNumOfQueries
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.
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.
std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service)
Creates a CompilerInvocation suitable for the dependency scanner.
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