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
15#include "clang/Driver/Driver.h"
17#include "llvm/ADT/IntrusiveRefCntPtr.h"
18#include "llvm/ADT/ScopeExit.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(StringRef 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;
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,
154 StringRef SpecificModuleCachePath,
155 bool Complain) override {
156
157 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
158 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
159 if (PrebuiltMapEntry.second)
160 PrebuiltModule.setInStableDir(!StableDirs.empty());
161
162 if (PrebuiltModule.isInStableDir())
163 PrebuiltModule.setInStableDir(areOptionsInStableDir(StableDirs, HSOpts));
164
165 return false;
166 }
167
168 /// Accumulate vfsoverlays used to build these prebuilt modules.
169 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
170 bool Complain) override {
171
172 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
173 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
174 if (PrebuiltMapEntry.second)
175 PrebuiltModule.setInStableDir(!StableDirs.empty());
176
177 PrebuiltModule.setVFS(
178 llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles));
179
180 return checkHeaderSearchPaths(
181 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
182 }
183
184private:
185 PrebuiltModuleFilesT &PrebuiltModuleFiles;
186 llvm::SmallVector<std::string> &NewModuleFiles;
187 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap;
188 const HeaderSearchOptions &ExistingHSOpts;
189 const LangOptions &ExistingLangOpts;
190 DiagnosticsEngine &Diags;
191 std::string CurrentFile;
192 const ArrayRef<StringRef> StableDirs;
193};
194
195/// Visit the given prebuilt module and collect all of the modules it
196/// transitively imports and contributing input files.
197static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
199 PrebuiltModuleFilesT &ModuleFiles,
200 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
201 DiagnosticsEngine &Diags,
202 const ArrayRef<StringRef> StableDirs) {
203 // List of module files to be processed.
205
206 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
208 Diags, StableDirs);
209
210 Listener.visitModuleFile(PrebuiltModuleFilename,
213 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
215 /*FindModuleFileExtensions=*/false, Listener,
216 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
217 return true;
218
219 while (!Worklist.empty()) {
220 Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule);
222 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
224 /*FindModuleFileExtensions=*/false, Listener,
225 /*ValidateDiagnosticOptions=*/false))
226 return true;
227 }
228 return false;
229}
230
231/// Transform arbitrary file name into an object-like file name.
232static std::string makeObjFileName(StringRef FileName) {
233 SmallString<128> ObjFileName(FileName);
234 llvm::sys::path::replace_extension(ObjFileName, "o");
235 return std::string(ObjFileName);
236}
237
238/// Deduce the dependency target based on the output file and input files.
239static std::string
240deduceDepTarget(const std::string &OutputFile,
241 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
242 if (OutputFile != "-")
243 return OutputFile;
244
245 if (InputFiles.empty() || !InputFiles.front().isFile())
246 return "clang-scan-deps\\ dependency";
247
248 return makeObjFileName(InputFiles.front().getFile());
249}
250
251// Clang implements -D and -U by splatting text into a predefines buffer. This
252// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
253// define the same macro, or adding C++ style comments before the macro name.
254//
255// This function checks that the first non-space characters in the macro
256// obviously form an identifier that can be uniqued on without lexing. Failing
257// to do this could lead to changing the final definition of a macro.
258//
259// We could set up a preprocessor and actually lex the name, but that's very
260// heavyweight for a situation that will almost never happen in practice.
261static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
262 StringRef Name = Macro.split("=").first.ltrim(" \t");
263 std::size_t I = 0;
264
265 auto FinishName = [&]() -> std::optional<StringRef> {
266 StringRef SimpleName = Name.slice(0, I);
267 if (SimpleName.empty())
268 return std::nullopt;
269 return SimpleName;
270 };
271
272 for (; I != Name.size(); ++I) {
273 switch (Name[I]) {
274 case '(': // Start of macro parameter list
275 case ' ': // End of macro name
276 case '\t':
277 return FinishName();
278 case '_':
279 continue;
280 default:
281 if (llvm::isAlnum(Name[I]))
282 continue;
283 return std::nullopt;
284 }
285 }
286 return FinishName();
287}
288
289static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
290 using MacroOpt = std::pair<StringRef, std::size_t>;
291 std::vector<MacroOpt> SimpleNames;
292 SimpleNames.reserve(PPOpts.Macros.size());
293 std::size_t Index = 0;
294 for (const auto &M : PPOpts.Macros) {
295 auto SName = getSimpleMacroName(M.first);
296 // Skip optimizing if we can't guarantee we can preserve relative order.
297 if (!SName)
298 return;
299 SimpleNames.emplace_back(*SName, Index);
300 ++Index;
301 }
302
303 llvm::stable_sort(SimpleNames, llvm::less_first());
304 // Keep the last instance of each macro name by going in reverse
305 auto NewEnd = std::unique(
306 SimpleNames.rbegin(), SimpleNames.rend(),
307 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
308 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
309
310 // Apply permutation.
311 decltype(PPOpts.Macros) NewMacros;
312 NewMacros.reserve(SimpleNames.size());
313 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
314 std::size_t OriginalIndex = SimpleNames[I].second;
315 // We still emit undefines here as they may be undefining a predefined macro
316 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
317 }
318 std::swap(PPOpts.Macros, NewMacros);
319}
320
321class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
322 DependencyScanningWorkerFilesystem *DepFS;
323
324public:
325 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
326 FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
327 auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
328 if (DFS) {
329 assert(!DepFS && "Found multiple scanning VFSs");
330 DepFS = DFS;
331 }
332 });
333 assert(DepFS && "Did not find scanning VFS");
334 }
335
336 std::unique_ptr<DependencyDirectivesGetter>
337 cloneFor(FileManager &FileMgr) override {
338 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
339 }
340
341 std::optional<ArrayRef<dependency_directives_scan::Directive>>
342 operator()(FileEntryRef File) override {
343 return DepFS->getDirectiveTokens(File.getName());
344 }
345};
346
347/// Sanitize diagnostic options for dependency scan.
348void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
349 // Don't print 'X warnings and Y errors generated'.
350 DiagOpts.ShowCarets = false;
351 // Don't write out diagnostic file.
352 DiagOpts.DiagnosticSerializationFile.clear();
353 // Don't emit warnings except for scanning specific warnings.
354 // TODO: It would be useful to add a more principled way to ignore all
355 // warnings that come from source code. The issue is that we need to
356 // ignore warnings that could be surpressed by
357 // `#pragma clang diagnostic`, while still allowing some scanning
358 // warnings for things we're not ready to turn into errors yet.
359 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
360 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
361 return llvm::StringSwitch<bool>(Warning)
362 .Cases({"pch-vfs-diff", "error=pch-vfs-diff"}, false)
363 .StartsWith("no-error=", false)
364 .Default(true);
365 });
366}
367} // namespace
368
369std::unique_ptr<DiagnosticOptions>
371 std::vector<const char *> CLI;
372 for (const std::string &Arg : CommandLine)
373 CLI.push_back(Arg.c_str());
374 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
375 sanitizeDiagOpts(*DiagOpts);
376 return DiagOpts;
377}
378
380 ArrayRef<std::string> CommandLine,
382 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
383 llvm::transform(CommandLine, CCommandLine.begin(),
384 [](const std::string &Str) { return Str.c_str(); });
385 DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
386 sanitizeDiagOpts(*DiagOpts);
388 /*ShouldOwnClient=*/false);
389}
390
391std::unique_ptr<CompilerInvocation>
393 DiagnosticsEngine &Diags) {
394 llvm::opt::ArgStringList Argv;
395 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
396 Argv.push_back(Str.c_str());
397
398 auto Invocation = std::make_unique<CompilerInvocation>();
399 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
400 // FIXME: Should we just go on like cc1_main does?
401 return nullptr;
402 }
403 return Invocation;
404}
405
407 CompilerInstance &ScanInstance,
409 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
411 ScanInstance.setBuildingModule(false);
412 ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
413 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
414 ScanInstance.createFileManager();
415 ScanInstance.createSourceManager();
416
417 // Use DepFS for getting the dependency directives if requested to do so.
419 DepFS->resetBypassedPathPrefix();
420 SmallString<256> ModulesCachePath;
423 ModulesCachePath);
424 if (!ModulesCachePath.empty())
425 DepFS->setBypassedPathPrefix(ModulesCachePath);
426
428 std::make_unique<ScanningDependencyDirectivesGetter>(
429 ScanInstance.getFileManager()));
430 }
431}
432
433/// Creates a CompilerInvocation suitable for the dependency scanner.
434static std::shared_ptr<CompilerInvocation>
436 const DependencyScanningService &Service) {
437 auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
438
439 sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts());
440
441 ScanInvocation->getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
442 true;
443
444 if (ScanInvocation->getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
445 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
447
448 ScanInvocation->getFrontendOpts().DisableFree = false;
449 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
450 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
451 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
452 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
453 // This will prevent us compiling individual modules asynchronously since
454 // FileManager is not thread-safe, but it does improve performance for now.
455 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
456 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
457 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
459
460 // Consider different header search and diagnostic options to create
461 // different modules. This avoids the unsound aliasing of module PCMs.
462 //
463 // TODO: Implement diagnostic bucketing to reduce the impact of strict
464 // context hashing.
465 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
466 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
467 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
468 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
469 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
470 true;
471 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
472
473 // Avoid some checks and module map parsing when loading PCM files.
474 ScanInvocation->getPreprocessorOpts().ModulesCheckRelocated = false;
475
476 // Ensure that the scanner does not create new dependency collectors,
477 // and thus won't write out the extra '.d' files to disk.
478 ScanInvocation->getDependencyOutputOpts() = {};
479
480 return ScanInvocation;
481}
482
483llvm::SmallVector<StringRef>
485 // Create a collection of stable directories derived from the ScanInstance
486 // for determining whether module dependencies would fully resolve from
487 // those directories.
489 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
490 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
491 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
492 return StableDirs;
493}
494
495std::optional<PrebuiltModulesAttrsMap>
497 CompilerInstance &ScanInstance, llvm::SmallVector<StringRef> &StableDirs) {
498 // Store a mapping of prebuilt module files and their properties like header
499 // search options. This will prevent the implicit build to create duplicate
500 // modules and will force reuse of the existing prebuilt module files
501 // instead.
502 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
503
504 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
505 if (visitPrebuiltModule(
506 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
508 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
509 return {};
510
511 return PrebuiltModulesASTMap;
512}
513
514/// Creates dependency output options to be reported to the dependency consumer,
515/// deducing missing information if necessary.
516static std::unique_ptr<DependencyOutputOptions>
518 auto Opts = std::make_unique<DependencyOutputOptions>(
519 Invocation.getDependencyOutputOpts());
520 // We need at least one -MT equivalent for the generator of make dependency
521 // files to work.
522 if (Opts->Targets.empty())
523 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
524 Invocation.getFrontendOpts().Inputs)};
525 Opts->IncludeSystemHeaders = true;
526
527 return Opts;
528}
529
530std::shared_ptr<ModuleDepCollector>
532 CompilerInstance &ScanInstance,
533 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
534 StringRef WorkingDirectory, DependencyConsumer &Consumer,
536 DependencyActionController &Controller,
537 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
538 llvm::SmallVector<StringRef> &StableDirs) {
539 std::shared_ptr<ModuleDepCollector> MDC;
540 switch (Service.getOpts().Format) {
542 ScanInstance.addDependencyCollector(
543 std::make_shared<DependencyConsumerForwarder>(
544 std::move(DepOutputOpts), WorkingDirectory, Consumer));
545 break;
548 MDC = std::make_shared<ModuleDepCollector>(
549 Service, std::move(DepOutputOpts), ScanInstance, Consumer, Controller,
550 Inv, std::move(PrebuiltModulesASTMap), StableDirs);
551 ScanInstance.addDependencyCollector(MDC);
552 break;
553 }
554
555 return MDC;
556}
557
558/// Manages (and terminates) the asynchronous compilation of modules.
560 std::mutex Mutex;
561 bool Stop = false;
562 // FIXME: Have the service own a thread pool and use that instead.
563 std::vector<std::thread> Compiles;
564
565public:
566 /// Registers the module compilation, unless this instance is about to be
567 /// destroyed.
568 void add(llvm::unique_function<void()> Compile) {
569 std::lock_guard<std::mutex> Lock(Mutex);
570 if (!Stop)
571 Compiles.emplace_back(std::move(Compile));
572 }
573
575 {
576 // Prevent registration of further module compiles.
577 std::lock_guard<std::mutex> Lock(Mutex);
578 Stop = true;
579 }
580
581 // Wait for outstanding module compiles to finish.
582 for (std::thread &Compile : Compiles)
583 Compile.join();
584 }
585};
586
597
598/// The preprocessor callback that takes care of initiating an asynchronous
599/// module compilation if needed.
604
608
609 void moduleLoadSkipped(Module *M) override {
610 M = M->getTopLevelModule();
611
612 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
613 ModuleCache &ModCache = CI.getModuleCache();
614 std::string ModuleFileName = HS.getCachedModuleFileName(M);
615
616 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
617 // Someone else already built/validated the PCM.
618 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
619 return;
620
621 if (!CI.getASTReader())
622 CI.createASTReader();
624 // Only calling ReadASTCore() to avoid the expensive eager deserialization
625 // of the clang::Module objects in ReadAST().
626 // FIXME: Consider doing this in the new thread depending on how expensive
627 // the read turns out to be.
628 switch (CI.getASTReader()->ReadASTCore(
630 nullptr, Imported, {}, {}, {},
634 // We successfully read a valid, up-to-date PCM.
635 // FIXME: This could update the timestamp. Regular calls to
636 // ASTReader::ReadAST() would do so unless they encountered corrupted
637 // AST block, corrupted extension block, or did not read the expected
638 // top-level module.
639 return;
642 // The most interesting case.
643 break;
644 default:
645 // Let the regular scan diagnose this.
646 return;
647 }
648
649 ModCache.prepareForGetLock(ModuleFileName);
650 auto Lock = ModCache.getLock(ModuleFileName);
651 bool Owned;
652 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
653 // Someone else is building the PCM right now.
654 if (!LockErr && !Owned)
655 return;
656 // We should build the PCM.
658 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
659 Service.getSharedCache(), Service.getOpts().MakeVFS());
660 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
661 CI.getDiagnostics(), std::move(VFS));
662 auto DC = std::make_unique<DiagnosticConsumer>();
663 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries());
664 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
665 std::move(MC));
666 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
667 CloneConfig);
668 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
669 CloneConfig);
670
671 // Note: This lock belongs to a module cache that might not outlive the
672 // thread. This works, because the in-process lock only refers to an object
673 // managed by the service, which does outlive the thread.
674 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
675 ModCI2 = std::move(ModCI2), DC = std::move(DC),
677 llvm::CrashRecoveryContext CRC;
678 (void)CRC.RunSafely([&] {
679 // Quickly discovers and compiles modules for the real scan below.
680 SingleModuleWithAsyncModuleCompiles Action1(*Service, *Compiles);
681 (void)ModCI1->ExecuteAction(Action1);
682 // The real scan below.
683 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
684 GenerateModuleFromModuleMapAction Action2;
685 (void)ModCI2->ExecuteAction(Action2);
686 });
687 });
688 }
689};
690
691/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
692/// modules asynchronously without blocking or importing them.
708
710 CompilerInstance &CI) {
713 std::make_unique<AsyncModuleCompile>(CI, Service, Compiles));
714 return true;
715}
716
718 std::string Executable,
719 std::unique_ptr<CompilerInvocation> OriginalInvocation,
721 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
722 DiagnosticConsumer *DiagConsumer) {
723 // Making sure that we canonicalize the defines early to avoid unnecessary
724 // variants in both the scanner and in the resulting explicit command lines.
725 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
726 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
727
728 if (Scanned) {
729 // Scanning runs once for the first -cc1 invocation in a chain of driver
730 // jobs. For any dependent jobs, reuse the scanning result and just
731 // update the new invocation.
732 // FIXME: to support multi-arch builds, each arch requires a separate scan
733 if (MDC)
734 MDC->applyDiscoveredDependencies(*OriginalInvocation);
735 Consumer.handleBuildCommand(
736 {Executable, OriginalInvocation->getCC1CommandLine()});
737 return true;
738 }
739
740 Scanned = true;
741
742 // Create a compiler instance to handle the actual work.
743 auto ScanInvocation =
744 createScanCompilerInvocation(*OriginalInvocation, Service);
745
746 // Quickly discovers and compiles modules for the real scan below.
747 std::optional<AsyncModuleCompiles> AsyncCompiles;
748 if (Service.getOpts().AsyncScanModules) {
749 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
750 auto ScanInstanceStorage = std::make_unique<CompilerInstance>(
751 std::make_shared<CompilerInvocation>(*ScanInvocation), PCHContainerOps,
752 std::move(ModCache));
753 CompilerInstance &ScanInstance = *ScanInstanceStorage;
754
755 DiagnosticConsumer DiagConsumer;
756 initializeScanCompilerInstance(ScanInstance, FS, &DiagConsumer, Service,
757 DepFS);
758
759 // FIXME: Do this only once.
760 SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
761 auto MaybePrebuiltModulesASTMap =
762 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
763 if (!MaybePrebuiltModulesASTMap)
764 return false;
765
766 // Normally this would be handled by GeneratePCHAction
768 ScanInstance.getLangOpts().CompilingPCH = true;
769
770 AsyncCompiles.emplace();
771 SingleTUWithAsyncModuleCompiles Action(Service, *AsyncCompiles);
772 (void)ScanInstance.ExecuteAction(Action);
773 }
774
775 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
776 ScanInstanceStorage.emplace(std::move(ScanInvocation),
777 std::move(PCHContainerOps), std::move(ModCache));
778 CompilerInstance &ScanInstance = *ScanInstanceStorage;
779
780 assert(!DiagConsumerFinished && "attempt to reuse finished consumer");
781 initializeScanCompilerInstance(ScanInstance, FS, DiagConsumer, Service,
782 DepFS);
783
784 llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
785 auto MaybePrebuiltModulesASTMap =
786 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
787 if (!MaybePrebuiltModulesASTMap)
788 return false;
789
790 auto DepOutputOpts = createDependencyOutputOptions(*OriginalInvocation);
791
793 ScanInstance, std::move(DepOutputOpts), WorkingDirectory, Consumer,
794 Service, *OriginalInvocation, Controller, *MaybePrebuiltModulesASTMap,
795 StableDirs);
796
797 if (ScanInstance.getDiagnostics().hasErrorOccurred())
798 return false;
799
801 const bool Result = ScanInstance.ExecuteAction(Action);
802
803 // ExecuteAction is responsible for calling finish.
804 DiagConsumerFinished = true;
805
806 if (Result) {
807 if (MDC)
808 MDC->applyDiscoveredDependencies(*OriginalInvocation);
809 Consumer.handleBuildCommand(
810 {Executable, OriginalInvocation->getCC1CommandLine()});
811 }
812
813 return Result;
814}
815
817 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
819 assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!");
820 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
821 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
822
823#ifndef NDEBUG
824 assert(OverlayFS && "OverlayFS required!");
825 bool SawDepFS = false;
826 OverlayFS->visit([&](llvm::vfs::FileSystem &VFS) {
827 SawDepFS |= &VFS == Worker.DepFS.get();
828 });
829 assert(SawDepFS && "OverlayFS not based on DepFS");
830#endif
831
832 OriginalInvocation = createCompilerInvocation(
833 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
834 if (!OriginalInvocation) {
835 DiagEngineWithCmdAndOpts->DiagEngine->Report(
836 diag::err_fe_expected_compiler_job)
837 << llvm::join(CommandLine, " ");
838 return false;
839 }
840
841 if (any(Worker.Service.getOpts().OptimizeArgs &
843 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
844
845 // Create the CompilerInstance.
846 std::shared_ptr<ModuleCache> ModCache =
847 makeInProcessModuleCache(Worker.Service.getModuleCacheEntries());
848 CIPtr = std::make_unique<CompilerInstance>(
849 createScanCompilerInvocation(*OriginalInvocation, Worker.Service),
850 Worker.PCHContainerOps, std::move(ModCache));
851 auto &CI = *CIPtr;
852
854 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
855 Worker.Service, Worker.DepFS);
856
857 StableDirs = getInitialStableDirs(CI);
858 auto MaybePrebuiltModulesASTMap =
859 computePrebuiltModulesASTMap(CI, StableDirs);
860 if (!MaybePrebuiltModulesASTMap)
861 return false;
862
863 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
864 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
865
866 // We do not create the target in initializeScanCompilerInstance because
867 // setting it here is unique for by-name lookups. We create the target only
868 // once here, and the information is reused for all computeDependencies calls.
869 // We do not need to call createTarget explicitly if we go through
870 // CompilerInstance::ExecuteAction to perform scanning.
871 CI.createTarget();
872
873 return true;
874}
875
877 StringRef ModuleName, DependencyConsumer &Consumer,
878 DependencyActionController &Controller) {
879 assert(CIPtr && "CIPtr must be initialized before calling this method");
880 auto &CI = *CIPtr;
881
882 // We need to reset the diagnostics, so that the diagnostics issued
883 // during a previous computeDependencies call do not affect the current call.
884 // If we do not reset, we may inherit fatal errors from a previous call.
885 CI.getDiagnostics().Reset();
886
887 // We create this cleanup object because computeDependencies may exit
888 // early with errors.
889 llvm::scope_exit CleanUp([&]() {
891 // The preprocessor may not be created at the entry of this method,
892 // but it must have been created when this method returns, whether
893 // there are errors during scanning or not.
895 });
896
898 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
899 Worker.Service,
900 /* The MDC's constructor makes a copy of the OriginalInvocation, so
901 we can pass it in without worrying that it might be changed across
902 invocations of computeDependencies. */
903 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
904
905 if (!SrcLocOffset) {
906 // When SrcLocOffset is zero, we are at the beginning of the fake source
907 // file. In this case, we call BeginSourceFile to initialize.
908 std::unique_ptr<FrontendAction> Action =
909 std::make_unique<PreprocessOnlyAction>();
910 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
911 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
912 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
913 (void)ActionBeginSucceeded;
914 }
915
916 Preprocessor &PP = CI.getPreprocessor();
918 FileID MainFileID = SM.getMainFileID();
919 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
920 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
921 PPCallbacks *CB = nullptr;
922 if (!SrcLocOffset) {
923 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
924 // the preprocessor.
925 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
926 assert(!PPFailed && "Preprocess must be able to enter the main file.");
927 (void)PPFailed;
928 CB = MDC->getPPCallbacks();
929 } else {
930 // When SrcLocOffset is non-zero, the preprocessor has already been
931 // initialized through a previous call of computeDependencies. We want to
932 // preserve the PP's state, hence we do not call EnterSourceFile again.
933 MDC->attachToPreprocessor(PP);
934 CB = MDC->getPPCallbacks();
935
936 FileID PrevFID;
937 SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation);
938 CB->LexedFileChanged(MainFileID,
940 FileType, PrevFID, IDLocation);
941 }
942
943 // FIXME: Scan modules asynchronously here as well.
944
945 SrcLocOffset++;
947 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
948 Path.emplace_back(IDLocation, ModuleID);
949 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
950
951 assert(CB && "Must have PPCallbacks after module loading");
952 CB->moduleImport(SourceLocation(), Path, ModResult);
953 // Note that we are calling the CB's EndOfMainFile function, which
954 // forwards the results to the dependency consumer.
955 // It does not indicate the end of processing the fake file.
956 CB->EndOfMainFile();
957
958 if (!ModResult)
959 return false;
960
961 CompilerInvocation ModuleInvocation(*OriginalInvocation);
962 MDC->applyDiscoveredDependencies(ModuleInvocation);
963 Consumer.handleBuildCommand(
964 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
965
966 return true;
967}
968
970 DiagConsumer->finish();
971 return true;
972}
static std::unique_ptr< DependencyOutputOptions > createDependencyOutputOptions(const CompilerInvocation &Invocation)
Creates dependency output options to be reported to the dependency consumer, deducing missing informa...
static std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service)
Creates a CompilerInvocation suitable for the dependency scanner.
#define SM(sm)
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:1835
@ 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:1839
@ 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:1852
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:453
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition ASTReader.h:463
@ Missing
The AST file was missing.
Definition ASTReader.h:459
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.
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override
Attempt to load the given module.
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)
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.
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:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
Definition Diagnostic.h:880
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
llvm::vfs::FileSystem & getVirtualFileSystem() const
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,...
std::string getCachedModuleFileName(Module *Module)
Retrieve the name of the cached module file that should be used to load the given module.
One of these records is kept for each identifier that is lexed.
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:25
virtual void prepareForGetLock(StringRef ModuleFilename)=0
May perform any work that only needs to be performed once for multiple calls getLock() with the same ...
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.
void setBuildingModule(bool BuildingModuleFlag)
Flag indicating whether this instance is building a module.
Describes a module or submodule.
Definition Module.h:144
@ Hidden
All of the names in this module are hidden.
Definition Module.h:445
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition Module.h:722
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
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.
Definition PPCallbacks.h:72
virtual void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported)
Callback invoked whenever there was an explicit module-import syntax.
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
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...
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
SourceManager & getSourceManager() const
Preprocessor-based frontend action that also loads PCH files.
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.
The base class of the type hierarchy.
Definition TypeBase.h:1839
bool initialize(std::unique_ptr< DiagnosticsEngineWithDiagOpts > DiagEngineWithDiagOpts, IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS)
bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller)
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
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
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.
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)
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.
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)
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.
void moduleLoadSkipped(Module *M) override
Callback invoked whenever a module load was skipped due to enabled single-module-parse-mode.
AsyncModuleCompiles & Compiles
AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service, AsyncModuleCompiles &Compiles)
DependencyScanningService & Service
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service, 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.
DependencyScanningService & Service
SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service, AsyncModuleCompiles &Compiles)
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)
This is used to identify a specific module.