clang 23.0.0git
DependencyScannerImpl.cpp
Go to the documentation of this file.
1//===- DependencyScannerImpl.cpp - Implements module dependency scanning --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
16#include "llvm/ADT/IntrusiveRefCntPtr.h"
17#include "llvm/ADT/ScopeExit.h"
18#include "llvm/Option/Option.h"
19#include "llvm/Support/AdvisoryLock.h"
20#include "llvm/Support/CrashRecoveryContext.h"
21#include "llvm/Support/VirtualFileSystem.h"
22#include "llvm/TargetParser/Host.h"
23
24#include <mutex>
25#include <thread>
26
27using namespace clang;
28using namespace dependencies;
29
30namespace {
31/// Forwards the gatherered dependencies to the consumer.
32class DependencyConsumerForwarder : public DependencyFileGenerator {
33public:
34 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
35 StringRef WorkingDirectory, DependencyConsumer &C)
36 : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
37 Opts(std::move(Opts)), C(C) {}
38
39 void finishedMainFile(DiagnosticsEngine &Diags) override {
40 C.handleDependencyOutputOpts(*Opts);
41 llvm::SmallString<256> CanonPath;
42 for (const auto &File : getDependencies()) {
43 CanonPath = File;
44 llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
45 llvm::sys::path::make_absolute(WorkingDirectory, CanonPath);
46 C.handleFileDependency(CanonPath);
47 }
48 }
49
50private:
51 StringRef WorkingDirectory;
52 std::unique_ptr<DependencyOutputOptions> Opts;
53 DependencyConsumer &C;
54};
55
56static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
57 const HeaderSearchOptions &ExistingHSOpts,
58 DiagnosticsEngine *Diags,
59 const LangOptions &LangOpts) {
60 if (LangOpts.Modules) {
61 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
62 if (Diags) {
63 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
64 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
65 if (VFSOverlays.empty()) {
66 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
67 } else {
68 std::string Files = llvm::join(VFSOverlays, "\n");
69 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
70 }
71 };
72 VFSNote(0, HSOpts.VFSOverlayFiles);
73 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
74 }
75 }
76 }
77 return false;
78}
79
80using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
81
82/// A listener that collects the imported modules and the input
83/// files. While visiting, collect vfsoverlays and file inputs that determine
84/// whether prebuilt modules fully resolve in stable directories.
85class PrebuiltModuleListener : public ASTReaderListener {
86public:
87 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
88 llvm::SmallVector<std::string> &NewModuleFiles,
89 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
90 const HeaderSearchOptions &HSOpts,
91 const LangOptions &LangOpts, DiagnosticsEngine &Diags,
92 const ArrayRef<StringRef> StableDirs)
93 : PrebuiltModuleFiles(PrebuiltModuleFiles),
94 NewModuleFiles(NewModuleFiles),
95 PrebuiltModulesASTMap(PrebuiltModulesASTMap), ExistingHSOpts(HSOpts),
96 ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
97
98 bool needsImportVisitation() const override { return true; }
99 bool needsInputFileVisitation() override { return true; }
100 bool needsSystemInputFileVisitation() override { return true; }
101
102 /// Accumulate the modules are transitively depended on by the initial
103 /// prebuilt module.
104 void visitImport(StringRef ModuleName, StringRef Filename) override {
105 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
106 NewModuleFiles.push_back(Filename.str());
107
108 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(Filename);
109 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
110 if (PrebuiltMapEntry.second)
111 PrebuiltModule.setInStableDir(!StableDirs.empty());
112
113 if (auto It = PrebuiltModulesASTMap.find(CurrentFile);
114 It != PrebuiltModulesASTMap.end() && CurrentFile != Filename)
115 PrebuiltModule.addDependent(It->getKey());
116 }
117
118 /// For each input file discovered, check whether it's external path is in a
119 /// stable directory. Traversal is stopped if the current module is not
120 /// considered stable.
121 bool visitInputFileAsRequested(StringRef FilenameAsRequested,
122 StringRef Filename, bool isSystem,
123 bool isOverridden, time_t StoredTime,
124 bool isExplicitModule) override {
125 if (StableDirs.empty())
126 return false;
127 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
128 if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end()) ||
129 (!PrebuiltEntryIt->second.isInStableDir()))
130 return false;
131
132 PrebuiltEntryIt->second.setInStableDir(
133 isPathInStableDir(StableDirs, Filename));
134 return PrebuiltEntryIt->second.isInStableDir();
135 }
136
137 /// Update which module that is being actively traversed.
138 void visitModuleFile(ModuleFileName Filename,
139 serialization::ModuleKind Kind) override {
140 // If the CurrentFile is not
141 // considered stable, update any of it's transitive dependents.
142 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
143 if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end()) &&
144 !PrebuiltEntryIt->second.isInStableDir())
145 PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
146 PrebuiltModulesASTMap);
147 CurrentFile = Filename.str();
148 }
149
150 /// Check the header search options for a given module when considering
151 /// if the module comes from stable directories.
152 bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
153 StringRef ModuleFilename, StringRef ContextHash,
154 bool Complain) override {
155
156 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
157 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
158 if (PrebuiltMapEntry.second)
159 PrebuiltModule.setInStableDir(!StableDirs.empty());
160
161 if (PrebuiltModule.isInStableDir())
162 PrebuiltModule.setInStableDir(areOptionsInStableDir(StableDirs, HSOpts));
163
164 return false;
165 }
166
167 /// Accumulate vfsoverlays used to build these prebuilt modules.
168 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
169 bool Complain) override {
170
171 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
172 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
173 if (PrebuiltMapEntry.second)
174 PrebuiltModule.setInStableDir(!StableDirs.empty());
175
176 PrebuiltModule.setVFS(
177 llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles));
178
179 return checkHeaderSearchPaths(
180 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
181 }
182
183private:
184 PrebuiltModuleFilesT &PrebuiltModuleFiles;
185 llvm::SmallVector<std::string> &NewModuleFiles;
186 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap;
187 const HeaderSearchOptions &ExistingHSOpts;
188 const LangOptions &ExistingLangOpts;
189 DiagnosticsEngine &Diags;
190 std::string CurrentFile;
191 const ArrayRef<StringRef> StableDirs;
192};
193
194/// Visit the given prebuilt module and collect all of the modules it
195/// transitively imports and contributing input files.
196static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
198 PrebuiltModuleFilesT &ModuleFiles,
199 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
200 DiagnosticsEngine &Diags,
201 const ArrayRef<StringRef> StableDirs) {
202 // List of module files to be processed.
204
205 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
207 Diags, StableDirs);
208
209 Listener.visitModuleFile(ModuleFileName::makeExplicit(PrebuiltModuleFilename),
212 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
214 /*FindModuleFileExtensions=*/false, Listener,
215 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
216 return true;
217
218 while (!Worklist.empty()) {
219 // FIXME: This is assuming the PCH only refers to explicitly-built modules,
220 // which technically is not guaranteed. To remove the assumption, we'd need
221 // to also rework how the module files are handled to the scan, specifically
222 // change the values of HeaderSearchOptions::PrebuiltModuleFiles from plain
223 // paths to ModuleFileName.
224 Listener.visitModuleFile(ModuleFileName::makeExplicit(Worklist.back()),
227 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
229 /*FindModuleFileExtensions=*/false, Listener,
230 /*ValidateDiagnosticOptions=*/false))
231 return true;
232 }
233 return false;
234}
235
236/// Transform arbitrary file name into an object-like file name.
237static std::string makeObjFileName(StringRef FileName) {
238 SmallString<128> ObjFileName(FileName);
239 llvm::sys::path::replace_extension(ObjFileName, "o");
240 return std::string(ObjFileName);
241}
242
243/// Deduce the dependency target based on the output file and input files.
244static std::string
245deduceDepTarget(const std::string &OutputFile,
246 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
247 if (OutputFile != "-")
248 return OutputFile;
249
250 if (InputFiles.empty() || !InputFiles.front().isFile())
251 return "clang-scan-deps\\ dependency";
252
253 return makeObjFileName(InputFiles.front().getFile());
254}
255
256// Clang implements -D and -U by splatting text into a predefines buffer. This
257// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
258// define the same macro, or adding C++ style comments before the macro name.
259//
260// This function checks that the first non-space characters in the macro
261// obviously form an identifier that can be uniqued on without lexing. Failing
262// to do this could lead to changing the final definition of a macro.
263//
264// We could set up a preprocessor and actually lex the name, but that's very
265// heavyweight for a situation that will almost never happen in practice.
266static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
267 StringRef Name = Macro.split("=").first.ltrim(" \t");
268 std::size_t I = 0;
269
270 auto FinishName = [&]() -> std::optional<StringRef> {
271 StringRef SimpleName = Name.slice(0, I);
272 if (SimpleName.empty())
273 return std::nullopt;
274 return SimpleName;
275 };
276
277 for (; I != Name.size(); ++I) {
278 switch (Name[I]) {
279 case '(': // Start of macro parameter list
280 case ' ': // End of macro name
281 case '\t':
282 return FinishName();
283 case '_':
284 continue;
285 default:
286 if (llvm::isAlnum(Name[I]))
287 continue;
288 return std::nullopt;
289 }
290 }
291 return FinishName();
292}
293} // namespace
294
296 using MacroOpt = std::pair<StringRef, std::size_t>;
297 std::vector<MacroOpt> SimpleNames;
298 SimpleNames.reserve(PPOpts.Macros.size());
299 std::size_t Index = 0;
300 for (const auto &M : PPOpts.Macros) {
301 auto SName = getSimpleMacroName(M.first);
302 // Skip optimizing if we can't guarantee we can preserve relative order.
303 if (!SName)
304 return;
305 SimpleNames.emplace_back(*SName, Index);
306 ++Index;
307 }
308
309 llvm::stable_sort(SimpleNames, llvm::less_first());
310 // Keep the last instance of each macro name by going in reverse
311 auto NewEnd = std::unique(
312 SimpleNames.rbegin(), SimpleNames.rend(),
313 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
314 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
315
316 // Apply permutation.
317 decltype(PPOpts.Macros) NewMacros;
318 NewMacros.reserve(SimpleNames.size());
319 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
320 std::size_t OriginalIndex = SimpleNames[I].second;
321 // We still emit undefines here as they may be undefining a predefined macro
322 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
323 }
324 std::swap(PPOpts.Macros, NewMacros);
325}
326
327namespace {
328class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
330
331public:
332 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
333 FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
334 auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
335 if (DFS) {
336 assert(!DepFS && "Found multiple scanning VFSs");
337 DepFS = DFS;
338 }
339 });
340 assert(DepFS && "Did not find scanning VFS");
341 }
342
343 std::unique_ptr<DependencyDirectivesGetter>
344 cloneFor(FileManager &FileMgr) override {
345 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
346 }
347
348 std::optional<ArrayRef<dependency_directives_scan::Directive>>
349 operator()(FileEntryRef File) override {
350 return DepFS->getDirectiveTokens(File.getName());
351 }
352};
353
354/// Sanitize diagnostic options for dependency scan.
355void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
356 // Don't print 'X warnings and Y errors generated'.
357 DiagOpts.ShowCarets = false;
358 // Don't write out diagnostic file.
359 DiagOpts.DiagnosticSerializationFile.clear();
360 // Don't emit warnings except for scanning specific warnings.
361 // TODO: It would be useful to add a more principled way to ignore all
362 // warnings that come from source code. The issue is that we need to
363 // ignore warnings that could be surpressed by
364 // `#pragma clang diagnostic`, while still allowing some scanning
365 // warnings for things we're not ready to turn into errors yet.
366 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
367 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
368 return llvm::StringSwitch<bool>(Warning)
369 .Cases({"pch-vfs-diff", "error=pch-vfs-diff"}, false)
370 .StartsWith("no-error=", false)
371 .Default(true);
372 });
373}
374} // namespace
375
376std::unique_ptr<DiagnosticOptions>
378 std::vector<const char *> CLI;
379 for (const std::string &Arg : CommandLine)
380 CLI.push_back(Arg.c_str());
381 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
382 sanitizeDiagOpts(*DiagOpts);
383 return DiagOpts;
384}
385
387 ArrayRef<std::string> CommandLine,
389 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
390 llvm::transform(CommandLine, CCommandLine.begin(),
391 [](const std::string &Str) { return Str.c_str(); });
392 DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
393 sanitizeDiagOpts(*DiagOpts);
395 /*ShouldOwnClient=*/false);
396}
397
398std::unique_ptr<CompilerInvocation>
400 DiagnosticsEngine &Diags) {
401 llvm::opt::ArgStringList Argv;
402 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
403 Argv.push_back(Str.c_str());
404
405 auto Invocation = std::make_unique<CompilerInvocation>();
406 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
407 // FIXME: Should we just go on like cc1_main does?
408 return nullptr;
409 }
410 return Invocation;
411}
412
414 CompilerInstance &ScanInstance,
416 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
418 ScanInstance.setBuildingModule(false);
419 ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
420 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
422 ScanInstance.getDiagnostics().setIgnoreAllWarnings(true);
423 ScanInstance.createFileManager();
424 ScanInstance.createSourceManager();
425
426 // Use DepFS for getting the dependency directives if requested to do so.
428 DepFS->resetBypassedPathPrefix();
429 SmallString<256> ModulesCachePath;
432 ModulesCachePath);
433 if (!ModulesCachePath.empty())
434 DepFS->setBypassedPathPrefix(ModulesCachePath);
435
437 std::make_unique<ScanningDependencyDirectivesGetter>(
438 ScanInstance.getFileManager()));
439 }
440}
441
442std::shared_ptr<CompilerInvocation> dependencies::createScanCompilerInvocation(
443 const CompilerInvocation &Invocation,
444 const DependencyScanningService &Service,
445 DependencyActionController &Controller) {
446 auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
447
448 sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts());
449
450 ScanInvocation->getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
451 true;
452
453 if (ScanInvocation->getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
454 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
456
457 ScanInvocation->getFrontendOpts().DisableFree = false;
458 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
459 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
460 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
461 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
462 // This will prevent us compiling individual modules asynchronously since
463 // FileManager is not thread-safe, but it does improve performance for now.
464 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
465 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
466 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
468
469 // Consider different header search and diagnostic options to create
470 // different modules. This avoids the unsound aliasing of module PCMs.
471 //
472 // TODO: Implement diagnostic bucketing to reduce the impact of strict
473 // context hashing.
474 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
475 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
476 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
477 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
478 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
479 true;
480 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
481
482 // Ensure that the scanner does not create new dependency collectors,
483 // and thus won't write out the extra '.d' files to disk.
484 ScanInvocation->getDependencyOutputOpts() = {};
485
486 Controller.initializeScanInvocation(*ScanInvocation);
487
488 return ScanInvocation;
489}
490
493 // Create a collection of stable directories derived from the ScanInstance
494 // for determining whether module dependencies would fully resolve from
495 // those directories.
497 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
498 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
499 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
500 return StableDirs;
501}
502
503std::optional<PrebuiltModulesAttrsMap>
505 CompilerInstance &ScanInstance, llvm::SmallVector<StringRef> &StableDirs) {
506 // Store a mapping of prebuilt module files and their properties like header
507 // search options. This will prevent the implicit build to create duplicate
508 // modules and will force reuse of the existing prebuilt module files
509 // instead.
510 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
511
512 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
513 if (visitPrebuiltModule(
514 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
516 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
517 return {};
518
519 return PrebuiltModulesASTMap;
520}
521
522std::unique_ptr<DependencyOutputOptions>
524 const CompilerInvocation &Invocation) {
525 auto Opts = std::make_unique<DependencyOutputOptions>(
526 Invocation.getDependencyOutputOpts());
527 // We need at least one -MT equivalent for the generator of make dependency
528 // files to work.
529 if (Opts->Targets.empty())
530 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
531 Invocation.getFrontendOpts().Inputs)};
532 Opts->IncludeSystemHeaders = true;
533
534 return Opts;
535}
536
537std::shared_ptr<ModuleDepCollector>
539 CompilerInstance &ScanInstance,
540 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
541 StringRef WorkingDirectory, DependencyConsumer &Consumer,
543 DependencyActionController &Controller,
544 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
545 llvm::SmallVector<StringRef> &StableDirs) {
546 std::shared_ptr<ModuleDepCollector> MDC;
547 switch (Service.getOpts().Format) {
549 ScanInstance.addDependencyCollector(
550 std::make_shared<DependencyConsumerForwarder>(
551 std::move(DepOutputOpts), WorkingDirectory, Consumer));
552 break;
555 MDC = std::make_shared<ModuleDepCollector>(
556 Service, std::move(DepOutputOpts), ScanInstance, Consumer, Controller,
557 Inv, std::move(PrebuiltModulesASTMap), StableDirs);
558 ScanInstance.addDependencyCollector(MDC);
559 break;
560 }
561
562 return MDC;
563}
564
565/// Manages (and terminates) the asynchronous compilation of modules.
567 std::mutex Mutex;
568 bool Stop = false;
569 // FIXME: Have the service own a thread pool and use that instead.
570 std::vector<std::thread> Compiles;
571
572public:
573 /// Registers the module compilation, unless this instance is about to be
574 /// destroyed.
575 void add(llvm::unique_function<void()> Compile) {
576 std::lock_guard<std::mutex> Lock(Mutex);
577 if (!Stop)
578 Compiles.emplace_back(std::move(Compile));
579 }
580
582 {
583 // Prevent registration of further module compiles.
584 std::lock_guard<std::mutex> Lock(Mutex);
585 Stop = true;
586 }
587
588 // Wait for outstanding module compiles to finish.
589 for (std::thread &Compile : Compiles)
590 Compile.join();
591 }
592};
593
606
607/// The preprocessor callback that takes care of initiating an asynchronous
608/// module compilation if needed.
614
619
620 void moduleLoadSkipped(Module *M) override {
621 M = M->getTopLevelModule();
622
623 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
624 ModuleCache &ModCache = CI.getModuleCache();
626
627 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
628 // Someone else already built/validated the PCM.
629 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
630 return;
631
632 if (!CI.getASTReader())
633 CI.createASTReader();
635 // Only calling ReadASTCore() to avoid the expensive eager deserialization
636 // of the clang::Module objects in ReadAST().
637 // FIXME: Consider doing this in the new thread depending on how expensive
638 // the read turns out to be.
639 switch (CI.getASTReader()->ReadASTCore(
641 nullptr, Imported, {}, {}, {},
645 // We successfully read a valid, up-to-date PCM.
646 // FIXME: This could update the timestamp. Regular calls to
647 // ASTReader::ReadAST() would do so unless they encountered corrupted
648 // AST block, corrupted extension block, or did not read the expected
649 // top-level module.
650 return;
653 // The most interesting case.
654 break;
655 default:
656 // Let the regular scan diagnose this.
657 return;
658 }
659
660 auto Lock = ModCache.getLock(ModuleFileName);
661 bool Owned;
662 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
663 // Someone else is building the PCM right now.
664 if (!LockErr && !Owned)
665 return;
666 // We should build the PCM.
668 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
669 Service.getSharedCache(), Service.getOpts().MakeVFS());
670 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
671 CI.getDiagnostics(), std::move(VFS));
672 auto DC = std::make_unique<DiagnosticConsumer>();
673 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries());
674 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
675 std::move(MC));
676 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
677 CloneConfig);
678 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
679 CloneConfig);
680
681 auto ModController = Controller.clone();
682
683 // Note: This lock belongs to a module cache that might not outlive the
684 // thread. This works, because the in-process lock only refers to an object
685 // managed by the service, which does outlive the thread.
686 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
687 ModCI2 = std::move(ModCI2), DC = std::move(DC),
688 ModController = std::move(ModController), Service = &Service,
689 Compiles = &Compiles] {
690 llvm::CrashRecoveryContext CRC;
691 (void)CRC.RunSafely([&] {
692 // Quickly discovers and compiles modules for the real scan below.
693 SingleModuleWithAsyncModuleCompiles Action1(*Service, *ModController,
694 *Compiles);
695 (void)ModCI1->ExecuteAction(Action1);
696 // The real scan below.
697 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
698 GenerateModuleFromModuleMapAction Action2;
699 (void)ModCI2->ExecuteAction(Action2);
700 });
701 });
702 }
703};
704
705/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
706/// modules asynchronously without blocking or importing them.
724
726 CompilerInstance &CI) {
729 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
730 return true;
731}
732
734 std::string Executable,
735 std::unique_ptr<CompilerInvocation> OriginalInvocation,
737 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
738 DiagnosticConsumer *DiagConsumer) {
739 // Making sure that we canonicalize the defines early to avoid unnecessary
740 // variants in both the scanner and in the resulting explicit command lines.
741 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
742 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
743
744 if (Scanned) {
745 CompilerInstance &ScanInstance = *ScanInstanceStorage;
746
747 // Scanning runs once for the first -cc1 invocation in a chain of driver
748 // jobs. For any dependent jobs, reuse the scanning result and just
749 // update the new invocation.
750 // FIXME: to support multi-arch builds, each arch requires a separate scan
751 if (MDC)
752 MDC->applyDiscoveredDependencies(*OriginalInvocation);
753
754 if (!Controller.finalize(ScanInstance, *OriginalInvocation))
755 return false;
756
757 Consumer.handleBuildCommand(
758 {Executable, OriginalInvocation->getCC1CommandLine()});
759 return true;
760 }
761
762 Scanned = true;
763
764 // Create a compiler instance to handle the actual work.
765 auto ScanInvocation =
766 createScanCompilerInvocation(*OriginalInvocation, Service, Controller);
767
768 // Quickly discovers and compiles modules for the real scan below.
769 std::optional<AsyncModuleCompiles> AsyncCompiles;
770 if (Service.getOpts().AsyncScanModules) {
771 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
772 auto ScanInstanceStorage = std::make_unique<CompilerInstance>(
773 std::make_shared<CompilerInvocation>(*ScanInvocation), PCHContainerOps,
774 std::move(ModCache));
775 CompilerInstance &ScanInstance = *ScanInstanceStorage;
776
777 DiagnosticConsumer DiagConsumer;
778 initializeScanCompilerInstance(ScanInstance, FS, &DiagConsumer, Service,
779 DepFS);
780
781 // FIXME: Do this only once.
782 SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
783 auto MaybePrebuiltModulesASTMap =
784 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
785 if (!MaybePrebuiltModulesASTMap)
786 return false;
787
788 // Normally this would be handled by GeneratePCHAction
790 ScanInstance.getLangOpts().CompilingPCH = true;
791
792 AsyncCompiles.emplace();
793 SingleTUWithAsyncModuleCompiles Action(Service, Controller, *AsyncCompiles);
794 (void)ScanInstance.ExecuteAction(Action);
795 }
796
797 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
798 ScanInstanceStorage.emplace(std::move(ScanInvocation),
799 std::move(PCHContainerOps), std::move(ModCache));
800 CompilerInstance &ScanInstance = *ScanInstanceStorage;
801
802 initializeScanCompilerInstance(ScanInstance, FS, DiagConsumer, Service,
803 DepFS);
804
805 llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
806 auto MaybePrebuiltModulesASTMap =
807 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
808 if (!MaybePrebuiltModulesASTMap)
809 return false;
810
811 auto DepOutputOpts = createDependencyOutputOptions(*OriginalInvocation);
812
814 ScanInstance, std::move(DepOutputOpts), WorkingDirectory, Consumer,
815 Service, *OriginalInvocation, Controller, *MaybePrebuiltModulesASTMap,
816 StableDirs);
817
818 if (ScanInstance.getDiagnostics().hasErrorOccurred())
819 return false;
820
821 if (!Controller.initialize(ScanInstance, *OriginalInvocation))
822 return false;
823
825 const bool Result = ScanInstance.ExecuteAction(Action);
826
827 if (Result) {
828 if (MDC)
829 MDC->applyDiscoveredDependencies(*OriginalInvocation);
830
831 if (!Controller.finalize(ScanInstance, *OriginalInvocation))
832 return false;
833
834 Consumer.handleBuildCommand(
835 {Executable, OriginalInvocation->getCC1CommandLine()});
836 }
837
838 return Result;
839}
Manages (and terminates) the asynchronous compilation of modules.
void add(llvm::unique_function< void()> Compile)
Registers the module compilation, unless this instance is about to be destroyed.
Abstract interface for callback invocations by the ASTReader.
Definition ASTReader.h:117
@ ARR_Missing
The client can handle an AST file that cannot load because it is missing.
Definition ASTReader.h:1853
@ ARR_OutOfDate
The client can handle an AST file that cannot load because it is out-of-date relative to its input fi...
Definition ASTReader.h:1857
@ ARR_TreatModuleWithErrorsAsOutOfDate
If a module file is marked with errors treat it as out-of-date so the caller can rebuild it.
Definition ASTReader.h:1870
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.
@ Success
The control block was read successfully.
Definition ASTReader.h:450
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition ASTReader.h:460
@ Missing
The AST file was missing.
Definition ASTReader.h:456
Configuration object for making the result of cloneForModuleCompile() thread-safe.
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)
Preprocessor & getPreprocessor() const
Return the current preprocessor.
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()
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.
void setDependencyDirectivesGetter(std::unique_ptr< DependencyDirectivesGetter > Getter)
Helper class for holding the data necessary to invoke the compiler.
PreprocessorOptions & getPreprocessorOpts()
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()
FrontendOptions & getFrontendOpts()
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...
Definition Utils.h:104
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.
Definition Diagnostic.h:233
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
Definition Diagnostic.h:881
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition Diagnostic.h:689
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:53
std::string OutputFile
The output file, if any.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
frontend::ActionKind ProgramAction
The frontend action to perform.
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
std::map< std::string, std::string, std::less<> > PrebuiltModuleFiles
The mapping of module names to prebuilt module files.
std::string Sysroot
If non-empty, the directory to use as a "virtual system root" for include paths.
std::string ModuleCachePath
The directory used for the module cache.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
std::string ResourceDir
The directory which holds the compiler resource files (builtin includes, etc.).
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
ModuleFileName getCachedModuleFileName(Module *Module)
Retrieve the name of the cached module file that should be used to load the given module.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:30
virtual std::time_t getModuleTimestamp(StringRef ModuleFilename)=0
Returns the timestamp denoting the last time inputs of the module file were validated.
virtual std::unique_ptr< llvm::AdvisoryLock > getLock(StringRef ModuleFilename)=0
Returns lock for the given module file. The lock is initially unlocked.
Identifies a module file to be loaded.
Definition Module.h:102
static ModuleFileName makeExplicit(std::string Name)
Creates a file name for an explicit module.
Definition Module.h:111
StringRef str() const
Returns the plain module file name.
Definition Module.h:144
void setBuildingModule(bool BuildingModuleFlag)
Flag indicating whether this instance is building a module.
Describes a module or submodule.
Definition Module.h:246
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition Module.h:825
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool SingleModuleParseMode
When enabled, preprocessor is in a mode for parsing a single module only.
std::vector< std::pair< std::string, bool > > Macros
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Preprocessor-based frontend action that also loads PCH files.
Encodes a location in the source.
The base class of the type hierarchy.
Definition TypeBase.h:1866
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
virtual void initializeScanInvocation(CompilerInvocation &ScanInvocation)
Initializes the scan invocation.
bool runInvocation(std::string Executable, std::unique_ptr< CompilerInvocation > Invocation, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)
The dependency scanning service contains shared configuration and state that is used by the individua...
const DependencyScanningServiceOptions & getOpts() const
A virtual file system optimized for the dependency discovery.
void setVFS(llvm::StringSet<> &&VFS)
Update the VFSMap to the one discovered from serializing the AST file.
bool isInStableDir() const
Read-only access to whether the module is made up of dependencies in stable directories.
void addDependent(StringRef ModuleFile)
Add a direct dependent module file, so it can be updated if the current module is from stable directo...
void setInStableDir(bool V=false)
Update whether the prebuilt module resolves entirely in a stable directories.
SmallVector< StringRef > getInitialStableDirs(const CompilerInstance &ScanInstance)
bool areOptionsInStableDir(const ArrayRef< StringRef > Directories, const HeaderSearchOptions &HSOpts)
Determine if options collected from a module's compilation can safely be considered as stable.
@ 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)
llvm::StringMap< PrebuiltModuleASTAttrs > PrebuiltModulesAttrsMap
Attributes loaded from AST files of prebuilt modules collected prior to ModuleDepCollector creation.
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::unique_ptr< DiagnosticOptions > createDiagOptions(ArrayRef< std::string > CommandLine)
bool isPathInStableDir(const ArrayRef< StringRef > Directories, const StringRef Input)
Determine if Input can be resolved within a stable directory.
@ Make
This is the Makefile compatible dep format.
@ Full
This outputs the full clang module dependency graph suitable for use for explicitly building modules.
@ P1689
This outputs the dependency graph for standard c++ modules in P1689R5 format.
@ DependencyDirectivesScan
This mode is used to compute the dependencies by running the preprocessor with special kind of lexing...
@ GeneratePCH
Generate pre-compiled header.
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:43
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition ModuleFile.h:48
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition ModuleFile.h:45
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.
Definition TypeBase.h:905
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
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.
DependencyActionController & Controller
AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
void moduleLoadSkipped(Module *M) override
Callback invoked whenever a module load was skipped due to enabled single-module-parse-mode.
AsyncModuleCompiles & Compiles
DependencyScanningService & Service
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
Runs the preprocessor on a TU with single-module-parse-mode and compiles modules asynchronously witho...
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
DependencyScanningService & Service
DependencyActionController & Controller
ScanningMode Mode
Whether to use optimized dependency directive scan or full preprocessing.
std::time_t BuildSessionTimestamp
The build session timestamp for validate-once-per-build-session logic.
ScanningOptimizations OptimizeArgs
How to optimize resulting explicit module command lines.
ScanningOutputFormat Format
What output format are we expected to produce.
IntrusiveRefCntPtr< DiagnosticsEngine > DiagEngine
DiagnosticsEngineWithDiagOpts(ArrayRef< std::string > CommandLine, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer &DC)