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 Dependencies.push_back(std::string(
File));
47 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)
override {}
48 void handleModuleDependency(ModuleDeps MD)
override {}
49 void handleDirectModuleDependency(ModuleID ID)
override {}
50 void handleVisibleModule(std::string ModuleName)
override {}
51 void handleContextHash(std::string Hash)
override {}
53 void printDependencies(std::string &S) {
54 assert(Opts &&
"Handled dependency output options.");
56 class DependencyPrinter :
public DependencyFileGenerator {
58 DependencyPrinter(DependencyOutputOptions &Opts,
59 ArrayRef<std::string> Dependencies)
60 : DependencyFileGenerator(Opts) {
61 for (
const auto &Dep : Dependencies)
65 void printDependencies(std::string &S) {
66 llvm::raw_string_ostream
OS(S);
67 outputDependencyFile(OS);
71 DependencyPrinter
Generator(*Opts, Dependencies);
76 std::unique_ptr<DependencyOutputOptions> Opts;
77 std::vector<std::string> Dependencies;
81static std::pair<std::unique_ptr<driver::Driver>,
82 std::unique_ptr<driver::Compilation>>
85 llvm::BumpPtrAllocator &Alloc) {
87 Argv.reserve(ArgStrs.size());
88 for (
const std::string &Arg : ArgStrs)
89 Argv.push_back(Arg.c_str());
91 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
92 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
93 "clang LLVM compiler", FS);
94 Driver->setTitle(
"clang_based_tool");
101 Diags.
Report(diag::err_drv_expand_response_file)
102 << llvm::toString(std::move(E));
103 return std::make_pair(
nullptr,
nullptr);
106 std::unique_ptr<driver::Compilation> Compilation(
107 Driver->BuildCompilation(Argv));
109 return std::make_pair(
nullptr,
nullptr);
111 if (Compilation->containsError())
112 return std::make_pair(
nullptr,
nullptr);
114 if (Compilation->getJobs().empty()) {
115 Diags.
Report(diag::err_fe_expected_compiler_job)
116 << llvm::join(ArgStrs,
" ");
117 return std::make_pair(
nullptr,
nullptr);
120 return std::make_pair(std::move(Driver), std::move(Compilation));
129 Out.reserve(Args.size() + 1);
131 llvm::append_range(Out, Args);
145 FS->setCurrentWorkingDirectory(WorkingDirectory);
151 llvm::BumpPtrAllocator Alloc;
152 auto DiagEngineWithDiagOpts =
155 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
160 for (
const auto &Cmd : Compilation->getJobs())
163 FrontendCommandLines.begin(), FrontendCommandLines.end());
165 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
166 Consumer, Controller, DiagConsumer,
172 return llvm::make_error<llvm::StringError>(
173 DiagPrinterWithOS.
DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
181 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1");
182 return IsCC1Input ?
Worker.computeDependencies(WorkingDirectory, CommandLine,
183 Consumer, Controller,
184 DiagConsumer, OverlayFS)
186 Worker, WorkingDirectory, CommandLine, Consumer,
187 Controller, DiagConsumer, OverlayFS);
190std::optional<std::string>
194 MakeDependencyPrinterConsumer DepConsumer;
200 DepConsumer.printDependencies(Output);
207 class P1689ModuleDependencyPrinterConsumer
208 :
public MakeDependencyPrinterConsumer {
210 P1689ModuleDependencyPrinterConsumer(
P1689Rule &Rule,
212 : Filename(
Command.Filename), Rule(Rule) {
213 Rule.PrimaryOutput =
Command.Output;
216 void handleProvidedAndRequiredStdCXXModules(
217 std::optional<P1689ModuleInfo> Provided,
218 std::vector<P1689ModuleInfo> Requires)
override {
219 Rule.Provides = std::move(Provided);
221 Rule.Provides->SourcePath = Filename.str();
222 Rule.Requires = std::move(Requires);
225 StringRef getMakeFormatDependencyOutputPath() {
228 return Opts->OutputFile;
239 std::string lookupModuleOutput(
const ModuleDeps &,
244 std::unique_ptr<DependencyActionController> clone()
const override {
245 return std::make_unique<P1689ActionController>();
250 P1689ModuleDependencyPrinterConsumer Consumer(Rule,
Command);
251 P1689ActionController Controller;
253 Controller, DiagConsumer))
256 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
257 if (!MakeformatOutputPath.empty())
258 Consumer.printDependencies(MakeformatOutput);
262static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
263 std::vector<std::string>>
266 StringRef WorkingDirectory,
267 llvm::MemoryBufferRef TUBuffer) {
269 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
272 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
273 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
274 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
275 auto InputPath = TUBuffer.getBufferIdentifier();
277 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
280 OverlayFS->pushOverlay(InMemoryOverlay);
281 std::vector<std::string> ModifiedCommandLine(CommandLine);
282 ModifiedCommandLine.emplace_back(InputPath);
284 return std::make_pair(OverlayFS, ModifiedCommandLine);
287static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
288 std::vector<std::string>>
291 StringRef WorkingDirectory) {
293 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
299 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
300 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
301 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
302 StringRef FakeInputPath(
"module-include.input");
306 static const std::string FakeInput(
308 InMemoryFS->addFile(FakeInputPath, 0,
309 llvm::MemoryBuffer::getMemBuffer(FakeInput));
311 OverlayFS->pushOverlay(InMemoryOverlay);
313 std::vector<std::string> ModifiedCommandLine(CommandLine);
314 ModifiedCommandLine.emplace_back(FakeInputPath);
316 return std::make_pair(OverlayFS, ModifiedCommandLine);
319std::optional<TranslationUnitDeps>
323 const llvm::DenseSet<ModuleID> &AlreadySeen,
325 std::optional<llvm::MemoryBufferRef> TUBuffer) {
332 std::vector<std::string> CommandLineWithTUBufferInput;
334 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
337 CommandLine = CommandLineWithTUBufferInput;
341 DiagConsumer, OverlayFS))
349 const llvm::DenseSet<ModuleID> &AlreadySeen,
352 *
this, CWD, CommandLine, LookupModuleOutput);
353 if (
auto Error = MaybeCIWithContext.takeError())
356 return MaybeCIWithContext->computeDependenciesByNameOrError(
357 ModuleName, AlreadySeen, LookupModuleOutput);
366 llvm::BumpPtrAllocator Alloc;
367 const auto [Driver, Compilation] =
373 return StringRef(Cmd.getCreator().getName()) ==
"clang";
376 const auto &Jobs = Compilation->getJobs();
377 if (
const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
382std::optional<CompilerInstanceWithContext>
387 auto [OverlayFS, ModifiedCommandLine] =
389 auto DiagEngineWithCmdAndOpts =
390 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
393 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
396 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
397 if (!CIWithContext.initialize(
398 Controller, std::move(DiagEngineWithCmdAndOpts), OverlayFS))
400 return std::move(CIWithContext);
407 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
411 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
412 MaybeFirstCC1->end());
413 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
414 std::move(CC1CommandLine));
415 if (!CIWithContext.initialize(Controller, std::move(DiagEngineWithCmdAndOpts),
418 return std::move(CIWithContext);
430 auto DiagPrinterWithOS =
431 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
434 DiagPrinterWithOS->DiagPrinter);
436 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
437 return std::move(*
Result);
444 StringRef ModuleName,
const llvm::DenseSet<ModuleID> &AlreadySeen,
450 DiagPrinterWithOS->DiagnosticOutput.clear();
456bool CompilerInstanceWithContext::initialize(
458 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
460 assert(DiagEngineWithDiagOpts &&
"Valid diagnostics engine required!");
461 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
462 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
465 assert(OverlayFS &&
"OverlayFS required!");
466 bool SawDepFS =
false;
467 OverlayFS->visit([&](llvm::vfs::FileSystem &
VFS) {
470 assert(SawDepFS &&
"OverlayFS not based on DepFS");
474 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
475 if (!OriginalInvocation) {
476 DiagEngineWithCmdAndOpts->DiagEngine->Report(
477 diag::err_fe_expected_compiler_job)
478 << llvm::join(CommandLine,
" ");
482 if (
any(
Worker.Service.getOpts().OptimizeArgs &
483 ScanningOptimizations::Macros))
487 std::shared_ptr<ModuleCache> ModCache =
489 CIPtr = std::make_unique<CompilerInstance>(
492 Worker.PCHContainerOps, std::move(ModCache));
496 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
500 auto MaybePrebuiltModulesASTMap =
502 if (!MaybePrebuiltModulesASTMap)
505 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
522 llvm::report_fatal_error(
"exceeded maximum by-name scans for worker");
524 assert(CIPtr &&
"CIPtr must be initialized before calling this method");
530 CI.getDiagnostics().Reset();
534 llvm::scope_exit CleanUp([&]() {
535 CI.clearDependencyCollectors();
539 CI.getPreprocessor().removePPCallbacks();
543 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
548 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
551 if (!Controller.
initialize(CI, ModuleInvocation))
557 std::unique_ptr<FrontendAction> Action =
558 std::make_unique<PreprocessOnlyAction>();
559 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
560 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
561 assert(ActionBeginSucceeded &&
"Action BeginSourceFile must succeed");
562 (void)ActionBeginSucceeded;
567 FileID MainFileID =
SM.getMainFileID();
575 assert(!PPFailed &&
"Preprocess must be able to enter the main file.");
577 CB = MDC->getPPCallbacks();
582 MDC->attachToPreprocessor(PP);
583 CB = MDC->getPPCallbacks();
589 FileType, PrevFID, IDLocation);
597 Path.emplace_back(IDLocation,
ModuleID);
598 auto ModResult = CI.loadModule(IDLocation, Path,
Module::Hidden,
false);
600 assert(CB &&
"Must have PPCallbacks after module loading");
610 MDC->applyDiscoveredDependencies(ModuleInvocation);
612 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