24#include "llvm/ADT/StringSet.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/raw_ostream.h"
33struct DepCollectorPPCallbacks :
public PPCallbacks {
34 DependencyCollector &DepCollector;
36 DepCollectorPPCallbacks(DependencyCollector &L, Preprocessor &PP)
37 : DepCollector(L), PP(PP) {}
39 void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
41 SourceLocation Loc)
override {
42 if (Reason != PPCallbacks::LexedFileChangeReason::EnterFile)
48 if (std::optional<StringRef> Filename =
49 PP.getSourceManager().getNonBuiltinFilenameForID(FID))
50 DepCollector.maybeAddDependency(
51 llvm::sys::path::remove_leading_dotslash(*Filename),
56 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
59 llvm::sys::path::remove_leading_dotslash(SkippedFile.
getName());
60 DepCollector.maybeAddDependency(Filename,
false,
67 void EmbedDirective(SourceLocation, StringRef,
bool,
69 const LexEmbedParametersResult &)
override {
70 assert(
File &&
"expected to only be called when the file is found");
72 llvm::sys::path::remove_leading_dotslash(
File->getName());
73 DepCollector.maybeAddDependency(
FileName,
81 bool EmbedFileNotFound(StringRef
FileName)
override {
82 DepCollector.maybeAddDependency(
83 llvm::sys::path::remove_leading_dotslash(
FileName),
93 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
95 CharSourceRange FilenameRange,
97 StringRef RelativePath,
const Module *SuggestedModule,
101 DepCollector.maybeAddDependency(
FileName,
false,
109 void HasEmbed(SourceLocation, StringRef,
bool,
114 llvm::sys::path::remove_leading_dotslash(
File->getName());
115 DepCollector.maybeAddDependency(Filename,
122 void HasInclude(SourceLocation Loc, StringRef SpelledFilename,
bool IsAngled,
128 llvm::sys::path::remove_leading_dotslash(
File->getName());
129 DepCollector.maybeAddDependency(Filename,
false,
136 void EndOfMainFile()
override {
137 DepCollector.finishedMainFile(PP.getDiagnostics());
142 DependencyCollector &DepCollector;
143 DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
145 void moduleMapFileRead(SourceLocation Loc, FileEntryRef Entry,
146 bool IsSystem)
override {
147 StringRef Filename = Entry.
getName();
148 DepCollector.maybeAddDependency(Filename,
false,
157 DependencyCollector &DepCollector;
158 FileManager &FileMgr;
159 DepCollectorASTListener(DependencyCollector &L, FileManager &FileMgr)
160 : DepCollector(L), FileMgr(FileMgr) {}
161 bool needsInputFileVisitation()
override {
return true; }
162 bool needsSystemInputFileVisitation()
override {
163 return DepCollector.needSystemDependencies();
166 bool DirectlyImported)
override {
167 DepCollector.maybeAddDependency(Filename,
true,
172 bool visitInputFile(StringRef Filename,
bool IsSystem,
173 bool IsOverridden,
bool IsExplicitModule)
override {
174 if (IsOverridden || IsExplicitModule)
179 if (
auto FE = FileMgr.getOptionalFileRef(Filename))
180 Filename = FE->getName();
182 DepCollector.maybeAddDependency(Filename,
true, IsSystem,
192 bool FromModule,
bool IsSystem,
194 bool IsDirectModuleImport,
196 if (
sawDependency(Filename, FromModule, IsSystem, IsModuleFile,
197 IsDirectModuleImport, IsMissing))
202 StringRef SearchPath;
206 llvm::sys::path::native(TmpPath);
207 std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
208 SearchPath = TmpPath.str();
210 SearchPath = Filename;
213 if (Seen.insert(SearchPath).second) {
214 Dependencies.push_back(std::string(Filename));
221 return Filename ==
"<built-in>";
225 bool IsSystem,
bool IsModuleFile,
226 bool IsDirectModuleImport,
234 PP.
addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*
this, PP));
236 std::make_unique<DepCollectorMMCallbacks>(*
this));
240 std::make_unique<DepCollectorASTListener>(*
this, R.getFileManager()));
245 : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
246 IncludeSystemHeaders(Opts.IncludeSystemHeaders),
247 PhonyTarget(Opts.UsePhonyTargets),
248 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(
false),
251 OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
252 for (
const auto &ExtraDep : Opts.
ExtraDeps) {
253 if (addDependency(ExtraDep.first))
260 if (AddMissingHeaderDeps)
267 bool IsSystem,
bool IsModuleFile,
268 bool IsDirectModuleImport,
272 if (AddMissingHeaderDeps)
274 SeenMissingHeader =
true;
280 if (IncludeModuleFiles ==
MFDK_Direct && !IsDirectModuleImport)
287 if (IncludeSystemHeaders)
298 if (SeenMissingHeader) {
299 llvm::sys::fs::remove(OutputFile);
304 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
306 Diags.
Report(diag::err_fe_error_opening) << OutputFile << EC.message();
315 PhonyTarget, InputFileIndex);
static bool isSpecialFilename(StringRef Filename)
Defines the clang::FileManager interface and associated types.
llvm::MachO::FileType FileType
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
Abstract interface for callback invocations by the ASTReader.
Reads an AST files chain containing the contents of a translation unit.
bool addDependency(StringRef Filename)
Return true if the filename was added to the list of dependencies, false otherwise.
virtual void attachToPreprocessor(Preprocessor &PP)
virtual void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsDirectModuleImport, bool IsMissing)
Add a dependency Filename if it has not been seen before and sawDependency() returns true.
ArrayRef< std::string > getDependencies() const
virtual void attachToASTReader(ASTReader &R)
virtual ~DependencyCollector()
virtual bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsDirectModuleImport, bool IsMissing)
Called when a new file is seen.
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
void outputDependencyFile(llvm::raw_ostream &OS)
void attachToPreprocessor(Preprocessor &PP) override
void finishedMainFile(DiagnosticsEngine &Diags) override
Called when the end of the main file is reached.
bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsDirectModuleImport, bool IsMissing) final
Called when a new file is seen.
DependencyFileGenerator(const DependencyOutputOptions &Opts)
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
std::vector< std::pair< std::string, ExtraDepKind > > ExtraDeps
A list of extra dependencies (filename and kind) to be used for every target.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
StringRef getName() const
The name of this FileEntry.
A mechanism to observe the actions of the module map loader as it reads module map files.
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
HeaderSearch & getHeaderSearchInfo() const
void SetSuppressIncludeNotFoundError(bool Suppress)
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
ModuleKind
Specifies the kind of module that has been loaded.
Top level wrappers for InstallAPI frontend operations.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
ModuleFileDepsKind
ModuleFileDepsKind - Whether to include module file dependencies.
@ MFDK_Direct
Include only directly imported module file dependencies.
@ MFDK_None
Do not include module file dependencies.
void printMakeDependencyFile(llvm::raw_ostream &OS, llvm::ArrayRef< std::string > Targets, llvm::ArrayRef< std::string > Files, DependencyOutputFormat Format=DependencyOutputFormat::Make, bool PhonyTargets=false, unsigned InputFileIndex=0)
Write Make-style dependency output to the output stream, in the form: target1 target2 ....