15#include "llvm/Support/BLAKE3.h"
16#include "llvm/Support/StringSaver.h"
20using namespace tooling;
21using namespace dependencies;
27 std::vector<HeaderSearchOptions::Entry> Entries = Opts.
UserEntries;
30 llvm::BitVector SearchPathUsage(Entries.size());
42 for (
auto Idx : SearchPathUsage.set_bits())
46static std::vector<std::string>
splitString(std::string S,
char Separator) {
48 StringRef(S).split(Segments, Separator, -1,
false);
49 std::vector<std::string> Result;
50 Result.reserve(Segments.size());
51 for (StringRef Segment : Segments)
52 Result.push_back(Segment.str());
82ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
128 auto CurrentModuleMapEntry =
130 assert(CurrentModuleMapEntry &&
"module map file entry not found");
136 assert(ModuleMapEntry &&
"module map file entry not found");
143 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
148 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
149 !DepModuleMapFiles.contains(*ModuleMapEntry))
166 [&CI](
const std::pair<std::string, bool> &Def) {
167 StringRef MacroDef = Def.first;
168 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
169 llvm::CachedHashString(MacroDef.split(
'=').first));
183 for (
const ModuleID &MID : ClangModuleDeps) {
185 assert(MD &&
"Inconsistent dependency info");
188 assert(FE &&
"Missing module map file that was previously found");
189 ModuleMapFiles.insert(*FE);
191 return ModuleMapFiles;
194void ModuleDepCollector::addModuleMapFiles(
196 if (EagerLoadModules)
199 for (
const ModuleID &MID : ClangModuleDeps) {
201 assert(MD &&
"Inconsistent dependency info");
206void ModuleDepCollector::addModuleFiles(
208 for (
const ModuleID &MID : ClangModuleDeps) {
209 std::string PCMPath =
211 if (EagerLoadModules)
215 {MID.ModuleName, std::move(PCMPath)});
241 CurrentModuleMap->getNameAsRequested());
244 for (
const auto &KV : ModularDeps)
245 if (KV.second->ImportedByMainFile)
246 DirectDeps.push_back(KV.second->ID);
249 addModuleMapFiles(CI, DirectDeps);
251 addModuleFiles(CI, DirectDeps);
253 for (
const auto &KV : DirectPrebuiltModularDeps)
260 bool EagerLoadModules) {
261 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
262 llvm::support::endianness::native>
273 llvm::BumpPtrAllocator Alloc;
274 llvm::StringSaver Saver(Alloc);
276 Args, [&](
const Twine &Arg) {
return Saver.save(Arg).data(); });
277 HashBuilder.addRange(Args);
285 HashBuilder.add(ID.ModuleName);
286 HashBuilder.add(ID.ContextHash);
289 HashBuilder.add(EagerLoadModules);
291 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
292 std::array<uint64_t, 2> Words;
293 static_assert(
sizeof(Hash) ==
sizeof(Words),
"Hash must match Words");
294 std::memcpy(Words.data(), Hash.data(),
sizeof(Hash));
295 return toString(llvm::APInt(
sizeof(Words) * 8, Words), 36,
false);
301 bool Inserted = ModuleDepsByID.insert({Deps.
ID, &Deps}).second;
303 assert(Inserted &&
"duplicate module mapping");
316 if (MDC.ContextHash.empty()) {
326 if (std::optional<StringRef>
Filename =
SM.getNonBuiltinFilenameForID(FID))
327 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*
Filename));
333 StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
335 if (!
File && !Imported) {
338 MDC.addFileDep(FileName);
340 handleImport(Imported);
348 RequiredModule.
ModuleName = Path[0].first->getName().str();
350 MDC.RequiredStdCXXModules.push_back(RequiredModule);
354 handleImport(Imported);
357void ModuleDepCollectorPP::handleImport(
const Module *Imported) {
363 if (MDC.isPrebuiltModule(TopLevelModule))
364 MDC.DirectPrebuiltModularDeps.insert(
367 DirectModularDeps.insert(TopLevelModule);
377 if (PP.isInNamedModule()) {
379 ProvidedModule.
ModuleName = PP.getNamedModuleName();
385 if (PP.isInImplementationUnit())
386 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
388 MDC.ProvidedStdCXXModule = ProvidedModule;
396 if (!MDC.isPrebuiltModule(M))
397 DirectModularDeps.insert(M);
399 for (
const Module *M : DirectModularDeps)
400 handleTopLevelModule(M);
404 if (MDC.IsStdModuleP1689Format)
406 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
408 for (
auto &&I : MDC.ModularDeps)
411 for (
auto &&I : MDC.FileDeps)
414 for (
auto &&I : MDC.DirectPrebuiltModularDeps)
418std::optional<ModuleID>
419ModuleDepCollectorPP::handleTopLevelModule(
const Module *M) {
430 auto ModI = MDC.ModularDeps.insert({M,
nullptr});
432 return ModI.first->second->ID;
434 ModI.first->second = std::make_unique<ModuleDeps>();
453 MDC.ScanInstance.
getASTReader()->getModuleManager().lookup(
462 if (IF.
getFile()->getName().endswith(
"__inferred_module.map")) {
463 MDC.addFileDep(MD, ModuleMap->getName());
466 MDC.addFileDep(MD, IF.
getFile()->getName());
470 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
471 addAllSubmoduleDeps(M, MD, SeenDeps);
472 addAllAffectingClangModules(M, MD, SeenDeps);
474 MDC.ScanInstance.
getASTReader()->visitTopLevelModuleMaps(
483 if (MDC.OptimizeArgs)
488 MDC.associateWithContextHash(CI, MD);
491 MDC.addOutputPaths(CI, MD);
499 llvm::function_ref<
void(
const Module *)> F) {
504 llvm::stable_sort(Submodules, [](
const Module *A,
const Module *B) {
507 for (
const Module *SubM : Submodules)
511void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
514 addModulePrebuiltDeps(M, MD, SeenSubmodules);
517 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
521void ModuleDepCollectorPP::addModulePrebuiltDeps(
526 if (MDC.isPrebuiltModule(
Import->getTopLevelModule()))
527 if (SeenSubmodules.insert(
Import->getTopLevelModule()).second)
531void ModuleDepCollectorPP::addAllSubmoduleDeps(
534 addModuleDep(M, MD, AddedModules);
537 addAllSubmoduleDeps(SubM, MD, AddedModules);
541void ModuleDepCollectorPP::addModuleDep(
546 !MDC.isPrebuiltModule(
Import)) {
547 if (
auto ImportID = handleTopLevelModule(
Import->getTopLevelModule()))
548 if (AddedModules.insert(
Import->getTopLevelModule()).second)
554void ModuleDepCollectorPP::addAllAffectingClangModules(
557 addAffectingClangModule(M, MD, AddedModules);
560 addAllAffectingClangModules(SubM, MD, AddedModules);
563void ModuleDepCollectorPP::addAffectingClangModule(
568 "Not quite import not top-level module");
570 !MDC.isPrebuiltModule(Affecting)) {
571 if (
auto ImportID = handleTopLevelModule(Affecting))
572 if (AddedModules.insert(Affecting).second)
579 std::unique_ptr<DependencyOutputOptions> Opts,
582 bool OptimizeArgs,
bool EagerLoadModules,
bool IsStdModuleP1689Format)
583 : ScanInstance(ScanInstance), Consumer(
C), Controller(Controller),
584 Opts(
std::move(Opts)), OriginalInvocation(
std::move(OriginalCI)),
585 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
586 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
594bool ModuleDepCollector::isPrebuiltModule(
const Module *M) {
596 const auto &PrebuiltModuleFiles =
598 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
599 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
601 assert(
"Prebuilt module came from the expected AST file" &&
602 PrebuiltModuleFileIt->second == M->
getASTFile()->getName());
608 if (llvm::sys::path::is_absolute(Path) &&
609 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
611 Storage.assign(Path.begin(), Path.end());
613 llvm::sys::path::make_preferred(Storage);
614 return StringRef(Storage.data(), Storage.size());
617void ModuleDepCollector::addFileDep(StringRef Path) {
620 FileDeps.push_back(std::string(Path));
623void ModuleDepCollector::addFileDep(
ModuleDeps &MD, StringRef Path) {
llvm::DenseSet< const void * > Visited
static std::vector< std::string > splitString(std::string S, char Separator)
static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, SmallVectorImpl< char > &Storage)
static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader, const serialization::ModuleFile &MF)
static std::string getModuleContextHash(const ModuleDeps &MD, const CompilerInvocation &CI, bool EagerLoadModules)
static void forEachSubmoduleSorted(const Module *M, llvm::function_ref< void(const Module *)> F)
static bool needsModules(FrontendInputFile FIF)
Defines the clang::Preprocessor interface.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Reads an AST files chain containing the contents of a translation unit.
Represents a character-granular source range.
std::string CoverageNotesFile
The filename with path we use for coverage notes files.
std::string CoverageDataFile
The filename with path we use for coverage data files.
std::string DebugCompilationDir
The string to embed in debug information as the current working directory.
std::string MainFileName
The user provided name for the "main file", if non-empty.
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
std::string DwarfDebugFlags
The string to embed in the debug information for the compile unit, if non-empty.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileManager & getFileManager() const
Return the current file manager to the caller.
IntrusiveRefCntPtr< ASTReader > getASTReader() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
SourceManager & getSourceManager() const
Return the current source manager.
PreprocessorOptions & getPreprocessorOpts()
DiagnosticOptions & getDiagnosticOpts() const
LangOptions * getLangOpts()
HeaderSearchOptions & getHeaderSearchOpts()
CodeGenOptions & getCodeGenOpts()
DependencyOutputOptions & getDependencyOutputOpts()
FrontendOptions & getFrontendOpts()
Helper class for holding the data necessary to invoke the compiler.
void clearImplicitModuleBuildOptions()
Disable implicit modules and canonicalize options that are only used by implicit modules.
void resetNonModularOptions()
Reset all of the options that are not considered when building a module.
void generateCC1CommandLine(llvm::SmallVectorImpl< const char * > &Args, StringAllocator SA) const
Generate cc1-compatible command line arguments from this instance.
std::string getModuleHash() const
Retrieve a module hash string that is suitable for uniquely identifying the conditions under which th...
std::vector< std::string > getCC1CommandLine() const
Generate cc1-compatible command line arguments from this instance, wrapping the result as a std::vect...
std::string OutputFile
The file to write dependency output to.
std::vector< std::string > Targets
A list of names to use as the targets in the dependency file; this list must contain at least one ent...
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getNameAsRequested() const
The name of this FileEntry, as originally requested without applying any remappings for VFS 'use-exte...
StringRef getName() const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
InputKind DashX
The input kind, either specified via -x argument or deduced from the input file name.
std::vector< std::string > ModuleFiles
The list of additional prebuilt module files to load before processing the input.
unsigned IsSystemModule
When using -emit-module, treat the modulemap as a system module.
std::string OutputFile
The output file, if any.
enum clang::FrontendOptions::@191 ARCMTAction
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
frontend::ActionKind ProgramAction
The frontend action to perform.
std::vector< std::string > ModuleMapFiles
The list of module map files to load before processing the input.
std::string ModuleName
The module currently being compiled as specified by -fmodule-name.
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
Get the module map file that (along with the module name) uniquely identifies this module.
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
Describes a module or submodule.
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
std::string Name
The name of this module.
llvm::iterator_range< submodule_iterator > submodules()
llvm::SmallSetVector< Module *, 2 > AffectingClangModules
The set of top-level modules that affected the compilation of this module, but were not imported.
OptionalFileEntryRefDegradesToFileEntryPtr getASTFile() const
The serialized AST file for this module, if one was created.
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
std::vector< std::pair< std::string, bool > > Macros
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool isInImportingCXXNamedModules() const
If we're importing a standard C++20 Named Modules.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Module * getCurrentModuleImplementation()
Retrieves the module whose implementation we're current compiling, if any.
HeaderSearch & getHeaderSearchInfo() const
const llvm::SmallSetVector< Module *, 2 > & getAffectingClangModules() const
Get the set of top-level clang modules that affected preprocessing, but were not imported.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
FileID getMainFileID() const
Returns the FileID of the main source file.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Token - This structure provides full information about a lexed token.
Information about a module that has been loaded by the ASTReader.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module depends on.
llvm::BitVector SearchPathUsage
The bit vector denoting usage of each header search entry (true = used).
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
@ GenerateModule
Generate pre-compiled module from a module map.
const unsigned VERSION_MINOR
AST file minor version number supported by this version of Clang.
const unsigned VERSION_MAJOR
AST file major version number supported by this version of Clang.
void quoteMakeTarget(StringRef Target, SmallVectorImpl< char > &Res)
Quote target names for inclusion in GNU Make dependency files.
@ C
Languages that the frontend can parse and compile.
@ LLVM_IR
LLVM IR: we accept this so that we can run the optimizer on it, and compile it to assembly or object ...
@ Asm
Assembly: we accept this only so that we can preprocess it.
std::string getClangFullRepositoryVersion()
Retrieves the full repository version that is an amalgamation of the information in getClangRepositor...