15#include "llvm/TargetParser/Host.h"
25 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
26 StringRef WorkingDirectory, DependencyConsumer &C)
27 : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
28 Opts(std::move(Opts)), C(C) {}
30 void finishedMainFile(DiagnosticsEngine &Diags)
override {
31 C.handleDependencyOutputOpts(*Opts);
32 llvm::SmallString<256> CanonPath;
33 for (
const auto &
File : getDependencies()) {
35 llvm::sys::path::remove_dots(CanonPath,
true);
36 llvm::sys::path::make_absolute(WorkingDirectory, CanonPath);
37 C.handleFileDependency(CanonPath);
42 StringRef WorkingDirectory;
43 std::unique_ptr<DependencyOutputOptions> Opts;
44 DependencyConsumer &C;
51 if (LangOpts.Modules) {
54 Diags->
Report(diag::warn_pch_vfsoverlay_mismatch);
56 if (VFSOverlays.empty()) {
57 Diags->
Report(diag::note_pch_vfsoverlay_empty) <<
Type;
59 std::string Files = llvm::join(VFSOverlays,
"\n");
60 Diags->
Report(diag::note_pch_vfsoverlay_files) <<
Type << Files;
78 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
79 llvm::SmallVector<std::string> &NewModuleFiles,
81 const HeaderSearchOptions &HSOpts,
82 const LangOptions &LangOpts, DiagnosticsEngine &Diags,
83 const ArrayRef<StringRef> StableDirs)
84 : PrebuiltModuleFiles(PrebuiltModuleFiles),
85 NewModuleFiles(NewModuleFiles),
86 PrebuiltModulesASTMap(PrebuiltModulesASTMap), ExistingHSOpts(HSOpts),
87 ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
89 bool needsImportVisitation()
const override {
return true; }
90 bool needsInputFileVisitation()
override {
return true; }
91 bool needsSystemInputFileVisitation()
override {
return true; }
95 void visitImport(StringRef ModuleName, StringRef Filename)
override {
96 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
97 NewModuleFiles.push_back(Filename.str());
99 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(Filename);
100 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
101 if (PrebuiltMapEntry.second)
104 if (
auto It = PrebuiltModulesASTMap.find(CurrentFile);
105 It != PrebuiltModulesASTMap.end() && CurrentFile != Filename)
112 bool visitInputFileAsRequested(StringRef FilenameAsRequested,
113 StringRef Filename,
bool isSystem,
115 bool isExplicitModule)
override {
116 if (StableDirs.empty())
118 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
119 if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end()) ||
120 (!PrebuiltEntryIt->second.isInStableDir()))
123 PrebuiltEntryIt->second.setInStableDir(
125 return PrebuiltEntryIt->second.isInStableDir();
129 void visitModuleFile(StringRef Filename,
133 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
134 if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end()) &&
135 !PrebuiltEntryIt->second.isInStableDir())
136 PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
137 PrebuiltModulesASTMap);
138 CurrentFile = Filename;
143 bool ReadHeaderSearchOptions(
const HeaderSearchOptions &HSOpts,
144 StringRef ModuleFilename,
145 StringRef SpecificModuleCachePath,
146 bool Complain)
override {
148 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
149 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
150 if (PrebuiltMapEntry.second)
160 bool ReadHeaderSearchPaths(
const HeaderSearchOptions &HSOpts,
161 bool Complain)
override {
163 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
164 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
165 if (PrebuiltMapEntry.second)
171 return checkHeaderSearchPaths(
172 HSOpts, ExistingHSOpts, Complain ? &Diags :
nullptr, ExistingLangOpts);
176 PrebuiltModuleFilesT &PrebuiltModuleFiles;
177 llvm::SmallVector<std::string> &NewModuleFiles;
179 const HeaderSearchOptions &ExistingHSOpts;
180 const LangOptions &ExistingLangOpts;
181 DiagnosticsEngine &Diags;
182 std::string CurrentFile;
183 const ArrayRef<StringRef> StableDirs;
188static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
190 PrebuiltModuleFilesT &ModuleFiles,
197 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
201 Listener.visitModuleFile(PrebuiltModuleFilename,
210 while (!Worklist.empty()) {
223static std::string makeObjFileName(StringRef
FileName) {
225 llvm::sys::path::replace_extension(ObjFileName,
"o");
226 return std::string(ObjFileName);
231deduceDepTarget(
const std::string &OutputFile,
233 if (OutputFile !=
"-")
236 if (InputFiles.empty() || !InputFiles.front().isFile())
237 return "clang-scan-deps\\ dependency";
239 return makeObjFileName(InputFiles.front().getFile());
252static std::optional<StringRef> getSimpleMacroName(StringRef
Macro) {
253 StringRef Name =
Macro.split(
"=").first.ltrim(
" \t");
256 auto FinishName = [&]() -> std::optional<StringRef> {
257 StringRef SimpleName = Name.slice(0, I);
258 if (SimpleName.empty())
263 for (; I != Name.size(); ++I) {
272 if (llvm::isAlnum(Name[I]))
281 using MacroOpt = std::pair<StringRef, std::size_t>;
282 std::vector<MacroOpt> SimpleNames;
283 SimpleNames.reserve(PPOpts.
Macros.size());
284 std::size_t Index = 0;
285 for (
const auto &M : PPOpts.
Macros) {
286 auto SName = getSimpleMacroName(M.first);
290 SimpleNames.emplace_back(*SName, Index);
294 llvm::stable_sort(SimpleNames, llvm::less_first());
296 auto NewEnd = std::unique(
297 SimpleNames.rbegin(), SimpleNames.rend(),
298 [](
const MacroOpt &A,
const MacroOpt &B) { return A.first == B.first; });
299 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
302 decltype(PPOpts.
Macros) NewMacros;
303 NewMacros.reserve(SimpleNames.size());
304 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
305 std::size_t OriginalIndex = SimpleNames[I].second;
307 NewMacros.push_back(std::move(PPOpts.
Macros[OriginalIndex]));
309 std::swap(PPOpts.
Macros, NewMacros);
313 DependencyScanningWorkerFilesystem *DepFS;
316 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(
nullptr) {
318 auto *
DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
320 assert(!DepFS &&
"Found multiple scanning VFSs");
324 assert(DepFS &&
"Did not find scanning VFS");
327 std::unique_ptr<DependencyDirectivesGetter>
328 cloneFor(FileManager &FileMgr)
override {
329 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
332 std::optional<ArrayRef<dependency_directives_scan::Directive>>
333 operator()(FileEntryRef
File)
override {
334 return DepFS->getDirectiveTokens(
File.getName());
341 DiagOpts.ShowCarets =
false;
352 return llvm::StringSwitch<bool>(Warning)
353 .Cases(
"pch-vfs-diff",
"error=pch-vfs-diff", false)
354 .StartsWith(
"no-error=", false)
361std::unique_ptr<DiagnosticOptions>
363 std::vector<const char *> CLI;
364 for (
const std::string &Arg : CommandLine)
365 CLI.push_back(Arg.c_str());
367 sanitizeDiagOpts(*DiagOpts);
374 std::vector<const char *> CCommandLine(CommandLine.size(),
nullptr);
375 llvm::transform(CommandLine, CCommandLine.begin(),
376 [](
const std::string &Str) { return Str.c_str(); });
383std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
387 Argv.reserve(ArgStrs.size());
388 for (
const std::string &Arg : ArgStrs)
389 Argv.push_back(Arg.c_str());
391 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
392 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
393 "clang LLVM compiler", FS);
394 Driver->setTitle(
"clang_based_tool");
396 llvm::BumpPtrAllocator Alloc;
402 Diags.
Report(diag::err_drv_expand_response_file)
403 << llvm::toString(std::move(E));
404 return std::make_pair(
nullptr,
nullptr);
407 std::unique_ptr<driver::Compilation> Compilation(
408 Driver->BuildCompilation(Argv));
410 return std::make_pair(
nullptr,
nullptr);
412 if (Compilation->containsError())
413 return std::make_pair(
nullptr,
nullptr);
415 return std::make_pair(std::move(Driver), std::move(Compilation));
418std::unique_ptr<CompilerInvocation>
421 llvm::opt::ArgStringList Argv;
422 for (
const std::string &Str :
ArrayRef(CommandLine).drop_front())
423 Argv.push_back(Str.c_str());
425 auto Invocation = std::make_unique<CompilerInvocation>();
433std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
436 StringRef WorkingDirectory,
437 llvm::MemoryBufferRef TUBuffer) {
439 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
443 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
444 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
445 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
446 auto InputPath = TUBuffer.getBufferIdentifier();
448 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
451 OverlayFS->pushOverlay(InMemoryOverlay);
452 ModifiedFS = OverlayFS;
453 std::vector<std::string> ModifiedCommandLine(CommandLine);
454 ModifiedCommandLine.emplace_back(InputPath);
456 return std::make_pair(ModifiedFS, ModifiedCommandLine);
459std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
462 StringRef WorkingDirectory, StringRef ModuleName) {
464 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
470 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
471 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
472 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
475 llvm::sys::fs::createUniquePath(ModuleName +
"-%%%%%%%%.input", FakeInputPath,
477 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(
""));
479 OverlayFS->pushOverlay(InMemoryOverlay);
481 std::vector<std::string> ModifiedCommandLine(CommandLine);
482 ModifiedCommandLine.emplace_back(FakeInputPath);
484 return std::make_pair(OverlayFS, ModifiedCommandLine);
526 DepFS->resetBypassedPathPrefix();
532 DepFS->setBypassedPathPrefix(ModulesCachePath);
536 std::make_unique<ScanningDependencyDirectivesGetter>(
567 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
572std::optional<PrebuiltModulesAttrsMap>
582 if (visitPrebuiltModule(
585 PrebuiltModulesASTMap, ScanInstance.
getDiagnostics(), StableDirs))
588 return PrebuiltModulesASTMap;
591std::unique_ptr<DependencyOutputOptions>
597 auto Opts = std::make_unique<DependencyOutputOptions>();
601 if (Opts->Targets.empty())
604 Opts->IncludeSystemHeaders =
true;
611 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
617 std::shared_ptr<ModuleDepCollector> MDC;
621 std::make_shared<DependencyConsumerForwarder>(
622 std::move(DepOutputOpts), WorkingDirectory, Consumer));
626 MDC = std::make_shared<ModuleDepCollector>(
627 Service, std::move(DepOutputOpts), ScanInstance, Consumer, Controller,
628 Inv, std::move(PrebuiltModulesASTMap), StableDirs);
638 std::unique_ptr<CompilerInvocation> Invocation,
640 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
646 canonicalizeDefines(Invocation->getPreprocessorOpts());
656 setLastCC1Arguments(std::move(OriginalInvocation));
664 ScanInstanceStorage.emplace(std::move(Invocation), std::move(PCHContainerOps),
668 assert(!DiagConsumerFinished &&
"attempt to reuse finished consumer");
674 auto MaybePrebuiltModulesASTMap =
676 if (!MaybePrebuiltModulesASTMap)
682 ScanInstance, std::move(DepOutputOpts), WorkingDirectory, Consumer,
683 Service, OriginalInvocation, Controller, *MaybePrebuiltModulesASTMap,
686 std::unique_ptr<FrontendAction> Action;
689 Action = std::make_unique<PreprocessOnlyAction>();
691 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
693 Action = std::make_unique<ReadPCHAndPreprocessAction>();
701 DiagConsumerFinished =
true;
704 setLastCC1Arguments(std::move(OriginalInvocation));
Abstract interface for callback invocations by the ASTReader.
@ ARR_OutOfDate
The client can handle an AST file that cannot load because it is out-of-date relative to its input fi...
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities=ARR_ConfigurationMismatch|ARR_OutOfDate)
Read the control block for the named AST file.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
void createFileManager()
Create the file manager and replace any existing one with it.
FileManager & getFileManager() const
Return the current file manager to the caller.
ModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
void createVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS=llvm::vfs::getRealFileSystem(), DiagnosticConsumer *DC=nullptr)
Create a virtual file system instance based on the invocation.
FrontendOptions & getFrontendOpts()
bool hasDiagnostics() const
HeaderSearchOptions & getHeaderSearchOpts()
void createSourceManager()
Create the source manager and replace any existing one with it.
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
DiagnosticOptions & getDiagnosticOpts()
LangOptions & getLangOpts()
void setDependencyDirectivesGetter(std::unique_ptr< DependencyDirectivesGetter > Getter)
Helper class for holding the data necessary to invoke the compiler.
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
DependencyOutputOptions & getDependencyOutputOpts()
Functor that returns the dependency directives for a given file.
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Options for controlling the compiler diagnostics engine.
std::vector< std::string > Warnings
The list of -W... options used to alter the diagnostic mappings, with the prefixes removed.
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
llvm::vfs::FileSystem & getVirtualFileSystem() const
unsigned ModulesShareFileManager
Whether to share the FileManager when building modules.
std::string OutputFile
The output file, if any.
unsigned GenReducedBMI
Whether to generate reduced BMI for C++20 named modules.
std::string ModuleOutputPath
Output Path for module output file.
unsigned GenerateGlobalModuleIndex
Whether we can generate the global module index if needed.
unsigned DisableFree
Disable memory freeing on exit.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
unsigned UseGlobalModuleIndex
Whether we can use the global module index if available.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
void setBuildingModule(bool BuildingModuleFlag)
Flag indicating whether this instance is building a module.
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
bool ModulesCheckRelocated
Perform extra checks when loading PCM files for mutable file systems.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool AllowPCHWithDifferentModulesCachePath
When true, a PCH with modules cache path different to the current compilation will not be rejected.
std::vector< std::pair< std::string, bool > > Macros
The base class of the type hierarchy.
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.
ModuleKind
Specifies the kind of module that has been loaded.
@ MK_ExplicitModule
File is an explicitly-loaded module.
The JSON file list parser is used to communicate input to InstallAPI.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Result
The result type of a method or function.
void normalizeModuleCachePath(FileManager &FileMgr, StringRef Path, SmallVectorImpl< char > &NormalizedPath)
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.