clang 24.0.0git
DependencyScanningWorker.cpp
Go to the documentation of this file.
1//===- DependencyScanningWorker.cpp - Thread-Safe Scanning Worker ---------===//
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
20#include "llvm/ADT/IntrusiveRefCntPtr.h"
21#include "llvm/ADT/ScopeExit.h"
22#include "llvm/Option/Option.h"
23#include "llvm/Support/AdvisoryLock.h"
24#include "llvm/Support/CrashRecoveryContext.h"
25#include "llvm/Support/VirtualFileSystem.h"
26#include "llvm/TargetParser/Host.h"
27#include <mutex>
28#include <thread>
29
30using namespace clang;
31using namespace dependencies;
32
34 const HeaderSearchOptions &ExistingHSOpts,
35 DiagnosticsEngine *Diags,
36 const LangOptions &LangOpts) {
37 if (LangOpts.Modules) {
38 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
39 if (Diags) {
40 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
41 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
42 if (VFSOverlays.empty()) {
43 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
44 } else {
45 std::string Files = llvm::join(VFSOverlays, "\n");
46 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
47 }
48 };
49 VFSNote(0, HSOpts.VFSOverlayFiles);
50 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
51 }
52 }
53 }
54 return false;
55}
56namespace {
57using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
58
59/// A listener that collects the imported modules and the input
60/// files. While visiting, collect vfsoverlays and file inputs that determine
61/// whether prebuilt modules fully resolve in stable directories.
62class PrebuiltModuleListener : public ASTReaderListener {
63public:
64 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
65 llvm::SmallVector<std::string> &NewModuleFiles,
66 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
67 const HeaderSearchOptions &HSOpts,
68 const LangOptions &LangOpts, DiagnosticsEngine &Diags,
69 const ArrayRef<StringRef> StableDirs)
70 : PrebuiltModuleFiles(PrebuiltModuleFiles),
71 NewModuleFiles(NewModuleFiles),
72 PrebuiltModulesASTMap(PrebuiltModulesASTMap), ExistingHSOpts(HSOpts),
73 ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
74
75 bool needsImportVisitation() const override { return true; }
76 bool needsInputFileVisitation() override { return true; }
77 bool needsSystemInputFileVisitation() override { return true; }
78
79 /// Accumulate the modules are transitively depended on by the initial
80 /// prebuilt module.
81 void visitImport(StringRef ModuleName, StringRef Filename) override {
82 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
83 NewModuleFiles.push_back(Filename.str());
84
85 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(Filename);
86 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
87 if (PrebuiltMapEntry.second)
88 PrebuiltModule.setInStableDir(!StableDirs.empty());
89
90 if (auto It = PrebuiltModulesASTMap.find(CurrentFile);
91 It != PrebuiltModulesASTMap.end() && CurrentFile != Filename)
92 PrebuiltModule.addDependent(It->getKey());
93 }
94
95 /// For each input file discovered, check whether it's external path is in a
96 /// stable directory. Traversal is stopped if the current module is not
97 /// considered stable.
98 bool visitInputFileAsRequested(StringRef FilenameAsRequested,
99 StringRef Filename, bool isSystem,
100 bool isOverridden, time_t StoredTime,
101 bool isExplicitModule) override {
102 if (StableDirs.empty())
103 return false;
104 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
105 if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end()) ||
106 (!PrebuiltEntryIt->second.isInStableDir()))
107 return false;
108
109 PrebuiltEntryIt->second.setInStableDir(
110 isPathInStableDir(StableDirs, Filename));
111 return PrebuiltEntryIt->second.isInStableDir();
112 }
113
114 /// Update which module that is being actively traversed.
115 void visitModuleFile(ModuleFileName Filename, serialization::ModuleKind Kind,
116 bool DirectlyImported) override {
117 // If the CurrentFile is not
118 // considered stable, update any of it's transitive dependents.
119 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
120 if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end()) &&
121 !PrebuiltEntryIt->second.isInStableDir())
122 PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
123 PrebuiltModulesASTMap);
124 CurrentFile = Filename.str();
125 }
126
127 /// Check the header search options for a given module when considering
128 /// if the module comes from stable directories.
129 bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
130 StringRef ModuleFilename, StringRef ContextHash,
131 bool Complain) override {
132
133 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
134 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
135 if (PrebuiltMapEntry.second)
136 PrebuiltModule.setInStableDir(!StableDirs.empty());
137
138 if (PrebuiltModule.isInStableDir())
139 PrebuiltModule.setInStableDir(areOptionsInStableDir(StableDirs, HSOpts));
140
141 return false;
142 }
143
144 /// Accumulate vfsoverlays used to build these prebuilt modules.
145 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
146 bool Complain) override {
147
148 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
149 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
150 if (PrebuiltMapEntry.second)
151 PrebuiltModule.setInStableDir(!StableDirs.empty());
152
153 PrebuiltModule.setVFS(
154 llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles));
155
157 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
158 }
159
160private:
161 PrebuiltModuleFilesT &PrebuiltModuleFiles;
162 llvm::SmallVector<std::string> &NewModuleFiles;
163 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap;
164 const HeaderSearchOptions &ExistingHSOpts;
165 const LangOptions &ExistingLangOpts;
166 DiagnosticsEngine &Diags;
167 std::string CurrentFile;
168 const ArrayRef<StringRef> StableDirs;
169};
170} // namespace
171
172/// Visit the given prebuilt module and collect all of the modules it
173/// transitively imports and contributing input files.
174static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
176 PrebuiltModuleFilesT &ModuleFiles,
177 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
178 DiagnosticsEngine &Diags,
179 const ArrayRef<StringRef> StableDirs) {
180 // List of module files to be processed.
182
183 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
185 Diags, StableDirs);
186
187 Listener.visitModuleFile(ModuleFileName::makeExplicit(PrebuiltModuleFilename),
189 /*DirectlyImported=*/true);
191 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
193 /*FindModuleFileExtensions=*/false, Listener,
194 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
195 return true;
196
197 while (!Worklist.empty()) {
198 // FIXME: This is assuming the PCH only refers to explicitly-built modules,
199 // which technically is not guaranteed. To remove the assumption, we'd need
200 // to also rework how the module files are handled to the scan, specifically
201 // change the values of HeaderSearchOptions::PrebuiltModuleFiles from plain
202 // paths to ModuleFileName.
203 Listener.visitModuleFile(ModuleFileName::makeExplicit(Worklist.back()),
205 /*DirectlyImported=*/false);
207 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
209 /*FindModuleFileExtensions=*/false, Listener,
210 /*ValidateDiagnosticOptions=*/false))
211 return true;
212 }
213 return false;
214}
215
216/// Transform arbitrary file name into an object-like file name.
217static std::string makeObjFileName(StringRef FileName) {
218 SmallString<128> ObjFileName(FileName);
219 llvm::sys::path::replace_extension(ObjFileName, "o");
220 return std::string(ObjFileName);
221}
222
223/// Deduce the dependency target based on the output file and input files.
224static std::string
225deduceDepTarget(const std::string &OutputFile,
226 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
227 if (OutputFile != "-")
228 return OutputFile;
229
230 if (InputFiles.empty() || !InputFiles.front().isFile())
231 return "clang-scan-deps\\ dependency";
232
233 return makeObjFileName(InputFiles.front().getFile());
234}
235
236// Clang implements -D and -U by splatting text into a predefines buffer. This
237// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
238// define the same macro, or adding C++ style comments before the macro name.
239//
240// This function checks that the first non-space characters in the macro
241// obviously form an identifier that can be uniqued on without lexing. Failing
242// to do this could lead to changing the final definition of a macro.
243//
244// We could set up a preprocessor and actually lex the name, but that's very
245// heavyweight for a situation that will almost never happen in practice.
246static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
247 StringRef Name = Macro.split("=").first.ltrim(" \t");
248 std::size_t I = 0;
249
250 auto FinishName = [&]() -> std::optional<StringRef> {
251 StringRef SimpleName = Name.slice(0, I);
252 if (SimpleName.empty())
253 return std::nullopt;
254 return SimpleName;
255 };
256
257 for (; I != Name.size(); ++I) {
258 switch (Name[I]) {
259 case '(': // Start of macro parameter list
260 case ' ': // End of macro name
261 case '\t':
262 return FinishName();
263 case '_':
264 continue;
265 default:
266 if (llvm::isAlnum(Name[I]))
267 continue;
268 return std::nullopt;
269 }
270 }
271 return FinishName();
272}
273
275 using MacroOpt = std::pair<StringRef, std::size_t>;
276 std::vector<MacroOpt> SimpleNames;
277 SimpleNames.reserve(PPOpts.Macros.size());
278 std::size_t Index = 0;
279 for (const auto &M : PPOpts.Macros) {
280 auto SName = getSimpleMacroName(M.first);
281 // Skip optimizing if we can't guarantee we can preserve relative order.
282 if (!SName)
283 return;
284 SimpleNames.emplace_back(*SName, Index);
285 ++Index;
286 }
287
288 llvm::stable_sort(SimpleNames, llvm::less_first());
289 // Keep the last instance of each macro name by going in reverse
290 auto NewEnd = std::unique(
291 SimpleNames.rbegin(), SimpleNames.rend(),
292 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
293 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
294
295 // Apply permutation.
296 decltype(PPOpts.Macros) NewMacros;
297 NewMacros.reserve(SimpleNames.size());
298 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
299 std::size_t OriginalIndex = SimpleNames[I].second;
300 // We still emit undefines here as they may be undefining a predefined macro
301 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
302 }
303 std::swap(PPOpts.Macros, NewMacros);
304}
305
306namespace {
307class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
308 DependencyScanningWorkerFilesystem *DepFS;
309
310public:
311 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
312 FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
313 auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
314 if (DFS) {
315 assert(!DepFS && "Found multiple scanning VFSs");
316 DepFS = DFS;
317 }
318 });
319 assert(DepFS && "Did not find scanning VFS");
320 }
321
322 std::unique_ptr<DependencyDirectivesGetter>
323 cloneFor(FileManager &FileMgr) override {
324 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
325 }
326
327 std::optional<ArrayRef<dependency_directives_scan::Directive>>
328 operator()(FileEntryRef File) override {
329 return DepFS->getDirectiveTokens(File.getName());
330 }
331};
332} // namespace
333
334/// Sanitize diagnostic options for dependency scan.
335static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
336 // Don't print 'X warnings and Y errors generated'.
337 DiagOpts.ShowCarets = false;
338 // Don't write out diagnostic file.
339 DiagOpts.DiagnosticSerializationFile.clear();
340 // Don't emit warnings except for scanning specific warnings.
341 // TODO: It would be useful to add a more principled way to ignore all
342 // warnings that come from source code. The issue is that we need to
343 // ignore warnings that could be surpressed by
344 // `#pragma clang diagnostic`, while still allowing some scanning
345 // warnings for things we're not ready to turn into errors yet.
346 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
347 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
348 return llvm::StringSwitch<bool>(Warning)
349 .Cases({"pch-vfs-diff", "error=pch-vfs-diff"}, false)
350 .StartsWith("no-error=", false)
351 .Default(true);
352 });
353}
354
355static std::unique_ptr<CompilerInvocation>
357 DiagnosticsEngine &Diags) {
358 llvm::opt::ArgStringList Argv;
359 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
360 Argv.push_back(Str.c_str());
361
362 auto Invocation = std::make_unique<CompilerInvocation>();
363 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
364 // FIXME: Should we just go on like cc1_main does?
365 return nullptr;
366 }
367 return Invocation;
368}
369
371 CompilerInstance &ScanInstance,
373 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
375 ScanInstance.setBuildingModule(false);
376 ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
377 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
378 if (!Service.getOpts().EmitWarnings)
379 ScanInstance.getDiagnostics().setIgnoreAllWarnings(true);
380 ScanInstance.createFileManager();
381 ScanInstance.createSourceManager();
382
383 // Use DepFS for getting the dependency directives if requested to do so.
384 if (Service.getOpts().Mode == ScanningMode::DependencyDirectivesScan)
386 std::make_unique<ScanningDependencyDirectivesGetter>(
387 ScanInstance.getFileManager()));
388}
389
390static std::shared_ptr<CompilerInvocation>
392 const DependencyScanningService &Service,
393 DependencyActionController &Controller) {
394 auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
395
396 sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts());
397
398 ScanInvocation->getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
399 true;
400
401 if (ScanInvocation->getHeaderSearchOpts()
402 .ModulesValidateOncePerBuildSession ||
404 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
407 ScanInvocation->getHeaderSearchOpts().ModulesValidateDirectoryDependencies =
408 true;
409
410 ScanInvocation->getFrontendOpts().DisableFree = false;
411 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
412 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
413 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
414 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
415 // This will prevent us compiling individual modules asynchronously since
416 // FileManager is not thread-safe, but it does improve performance for now.
417 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
418 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
419 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
420 any(Service.getOpts().OptimizeArgs & ScanningOptimizations::VFS);
421
422 // Consider different header search and diagnostic options to create
423 // different modules. This avoids the unsound aliasing of module PCMs.
424 //
425 // TODO: Implement diagnostic bucketing to reduce the impact of strict
426 // context hashing.
427 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
428 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
429 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
430 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
431 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
432 true;
433 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
434
435 // FIXME: Do this even with PCHs by marking the option as something like
436 // "preprocessor benign" in LangOptions.def so that it passes the
437 // compatibility checks in ASTReader.
438 if (ScanInvocation->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
439 // Application extension only affects the handling of availability
440 // attributes, which cannot change the dependencies.
441 ScanInvocation->getLangOpts().AppExt = false;
442 }
443
444 // Ensure that the scanner does not create new dependency collectors,
445 // and thus won't write out the extra '.d' files to disk.
446 ScanInvocation->getDependencyOutputOpts() = {};
447
448 Controller.initializeScanInvocation(*ScanInvocation);
449
450 return ScanInvocation;
451}
452
455 // Create a collection of stable directories derived from the ScanInstance
456 // for determining whether module dependencies would fully resolve from
457 // those directories.
459 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
460 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
461 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
462 return StableDirs;
463}
464
465static std::optional<PrebuiltModulesAttrsMap>
467 llvm::SmallVector<StringRef> &StableDirs) {
468 // Store a mapping of prebuilt module files and their properties like header
469 // search options. This will prevent the implicit build to create duplicate
470 // modules and will force reuse of the existing prebuilt module files
471 // instead.
472 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
473
474 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
476 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
478 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
479 return {};
480
481 return PrebuiltModulesASTMap;
482}
483
484static std::unique_ptr<DependencyOutputOptions>
486 auto Opts = std::make_unique<DependencyOutputOptions>(
487 Invocation.getDependencyOutputOpts());
488 // We need at least one -MT equivalent for the generator of make dependency
489 // files to work.
490 if (Opts->Targets.empty())
491 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
492 Invocation.getFrontendOpts().Inputs)};
493 Opts->IncludeSystemHeaders = true;
494
495 return Opts;
496}
497
498static std::shared_ptr<ModuleDepCollector>
500 CompilerInstance &ScanInstance,
501 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
503 DependencyActionController &Controller,
504 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
505 SmallVector<StringRef> &StableDirs) {
506 auto MDC = std::make_shared<ModuleDepCollector>(
507 Service, std::move(DepOutputOpts), ScanInstance, Controller, Inv,
508 std::move(PrebuiltModulesASTMap), StableDirs);
509 ScanInstance.addDependencyCollector(MDC);
510 return MDC;
511}
512
513namespace {
514/// Manages (and terminates) the asynchronous compilation of modules.
515class AsyncModuleCompiles {
516 std::mutex Mutex;
517 bool Stop = false;
518 // FIXME: Have the service own a thread pool and use that instead.
519 std::vector<std::thread> Compiles;
520
521public:
522 /// Registers the module compilation, unless this instance is about to be
523 /// destroyed.
524 void add(llvm::unique_function<void()> Compile) {
525 std::lock_guard<std::mutex> Lock(Mutex);
526 if (!Stop)
527 Compiles.emplace_back(std::move(Compile));
528 }
529
530 ~AsyncModuleCompiles() {
531 {
532 std::lock_guard<std::mutex> Lock(Mutex);
533 Stop = true;
534 }
535 for (std::thread &Compile : Compiles)
536 Compile.join();
537 }
538};
539
540struct SingleModuleWithAsyncModuleCompiles : PreprocessOnlyAction {
541 DependencyScanningService &Service;
542 DependencyActionController &Controller;
543 AsyncModuleCompiles &Compiles;
544
545 SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service,
546 DependencyActionController &Controller,
547 AsyncModuleCompiles &Compiles)
548 : Service(Service), Controller(Controller), Compiles(Compiles) {}
549
550 bool BeginSourceFileAction(CompilerInstance &CI) override;
551};
552
553/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
554/// modules asynchronously without blocking or importing them.
555struct SingleTUWithAsyncModuleCompiles : PreprocessOnlyAction {
556 DependencyScanningService &Service;
557 DependencyActionController &Controller;
558 AsyncModuleCompiles &Compiles;
559
560 SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service,
561 DependencyActionController &Controller,
562 AsyncModuleCompiles &Compiles)
563 : Service(Service), Controller(Controller), Compiles(Compiles) {}
564
565 bool BeginSourceFileAction(CompilerInstance &CI) override;
566};
567
568/// The preprocessor callback that takes care of initiating an asynchronous
569/// module compilation if needed.
570struct AsyncModuleCompile : PPCallbacks {
571 CompilerInstance &CI;
572 DependencyScanningService &Service;
573 DependencyActionController &Controller;
574 AsyncModuleCompiles &Compiles;
575
576 AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service,
577 DependencyActionController &Controller,
578 AsyncModuleCompiles &Compiles)
579 : CI(CI), Service(Service), Controller(Controller), Compiles(Compiles) {}
580
581 void moduleLoadSkipped(Module *M) override {
582 M = M->getTopLevelModule();
583
584 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
585 ModuleCache &ModCache = CI.getModuleCache();
586 ModuleFileName ModuleFileName = HS.getCachedModuleFileName(M);
587
588 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
589 // Someone else already built/validated the PCM.
590 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
591 return;
592
593 if (!CI.getASTReader())
594 CI.createASTReader();
595 SmallVector<ASTReader::ImportedModule, 0> Imported;
596 // Only calling ReadASTCore() to avoid the expensive eager deserialization
597 // of the clang::Module objects in ReadAST().
598 // FIXME: Consider doing this in the new thread depending on how expensive
599 // the read turns out to be.
600 switch (CI.getASTReader()->ReadASTCore(
601 ModuleFileName, serialization::MK_ImplicitModule, SourceLocation(),
602 nullptr, Imported, {}, {}, {},
606 // We successfully read a valid, up-to-date PCM.
607 // FIXME: This could update the timestamp. Regular calls to
608 // ASTReader::ReadAST() would do so unless they encountered corrupted
609 // AST block, corrupted extension block, or did not read the expected
610 // top-level module.
611 return;
614 // The most interesting case.
615 break;
616 default:
617 // Let the regular scan diagnose this.
618 return;
619 }
620
621 auto Lock = ModCache.getLock(ModuleFileName);
622 bool Owned;
623 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
624 // Someone else is building the PCM right now.
625 if (!LockErr && !Owned)
626 return;
627 // We should build the PCM.
628 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
629 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
630 Service, Service.getOpts().MakeVFS());
631 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
632 CI.getDiagnostics(), std::move(VFS));
633 auto DC = std::make_unique<DiagnosticConsumer>();
634 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries(),
635 Service.getLogger());
636 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
637 std::move(MC));
638 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
639 CloneConfig);
640 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
641 CloneConfig);
642
643 auto ModController = Controller.clone();
644
645 // Note: This lock belongs to a module cache that might not outlive the
646 // thread. This works, because the in-process lock only refers to an object
647 // managed by the service, which does outlive the thread.
648 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
649 ModCI2 = std::move(ModCI2), DC = std::move(DC),
650 ModController = std::move(ModController), Service = &Service,
651 Compiles = &Compiles] {
652 llvm::CrashRecoveryContext CRC;
653 (void)CRC.RunSafely([&] {
654 // Quickly discovers and compiles modules for the real scan below.
655 SingleModuleWithAsyncModuleCompiles Action1(*Service, *ModController,
656 *Compiles);
657 (void)ModCI1->ExecuteAction(Action1);
658 // The real scan below.
659 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
660 GenerateModuleFromModuleMapAction Action2;
661 (void)ModCI2->ExecuteAction(Action2);
662 });
663 });
664 }
665};
666
667bool SingleModuleWithAsyncModuleCompiles::BeginSourceFileAction(
668 CompilerInstance &CI) {
671 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
672 return true;
673}
674
675bool SingleTUWithAsyncModuleCompiles::BeginSourceFileAction(
676 CompilerInstance &CI) {
679 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
680 return true;
681}
682} // namespace
683
686 DependencyActionController &Controller,
687 AsyncModuleCompiles &Compiles) {
688 SingleTUWithAsyncModuleCompiles Action(Service, Controller, Compiles);
689 (void)PrescanCI.ExecuteAction(Action);
690}
691
692namespace clang {
693namespace dependencies {
694
695std::unique_ptr<DiagnosticOptions>
697 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
698 llvm::transform(CommandLine, CCommandLine.begin(),
699 [](const std::string &Str) { return Str.c_str(); });
700 auto DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
701 sanitizeDiagOpts(*DiagOpts);
702 return DiagOpts;
703}
704
705class CompilerInstanceWithContext {
706 // Context
708 llvm::StringRef CWD;
709 std::vector<std::string> CommandLine;
710
711 // Context - compiler invocation
712 std::unique_ptr<CompilerInvocation> OriginalInvocation;
713
714 // Context - output options
715 std::unique_ptr<DependencyOutputOptions> OutputOpts;
716
717 // Context - stable directory handling
719 PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
720
721 // Context - used by AsyncScan's prescan pass
723
724 // Compiler Instance
725 std::unique_ptr<CompilerInstance> CIPtr;
726
727 // Source location offset.
728 int32_t SrcLocOffset = 0;
729
730 CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
732 : Worker(Worker), CWD(CWD), CommandLine(CMD.begin(), CMD.end()) {}
733
734 bool initialize(DependencyActionController &Controller,
735 DiagnosticsEngine &DiagEngine,
737 {
738 auto LogLine = Worker.Service.getLogger().log();
739 LogLine.logArray("init_compiler_instance_with_context:", " ",
740 CommandLine);
741 }
742
743 ScanFS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
744 OriginalInvocation = createCompilerInvocation(CommandLine, DiagEngine);
745 if (!OriginalInvocation) {
746 DiagEngine.Report(diag::err_fe_expected_compiler_job)
747 << llvm::join(CommandLine, " ");
748 return false;
749 }
750
751 return initializeScanInstance(Controller, DiagEngine.getClient());
752 }
753
754 bool initializeScanInstance(DependencyActionController &Controller,
755 DiagnosticConsumer *DiagConsumer) {
756 assert(OriginalInvocation && ScanFS &&
757 "OriginalInvocation and ScanFS must be set before this call");
758
759 if (any(Worker.Service.getOpts().OptimizeArgs &
761 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
762
763 // Create the CompilerInstance.
764 std::shared_ptr<ModuleCache> ModCache = makeInProcessModuleCache(
765 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
766 CIPtr = std::make_unique<CompilerInstance>(
767 createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
768 Controller),
769 Worker.PCHContainerOps, std::move(ModCache));
770 auto &CI = *CIPtr;
771
772 initializeScanCompilerInstance(CI, ScanFS, DiagConsumer, Worker.Service,
773 Worker.DepFS);
774
775 StableDirs = getInitialStableDirs(CI);
776 auto MaybePrebuiltModulesASTMap =
777 computePrebuiltModulesASTMap(CI, StableDirs);
778 if (!MaybePrebuiltModulesASTMap)
779 return false;
780
781 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
782 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
783
784 // We do not create the target in initializeScanCompilerInstance because
785 // setting it here is unique for by-name lookups. We create the target only
786 // once here, and the information is reused for all computeDependencies
787 // calls. We do not need to call createTarget explicitly if we go through
788 // CompilerInstance::ExecuteAction to perform scanning.
789 return CI.createTarget();
790 }
791
792 bool prescanModulesAsync(AsyncModuleCompiles &Compiles,
793 DependencyActionController &Controller) {
794 auto ModCache = makeInProcessModuleCache(
795 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
796 CompilerInstance PrescanCI(
797 std::make_shared<CompilerInvocation>(CIPtr->getInvocation()),
798 Worker.PCHContainerOps, std::move(ModCache));
799
800 DiagnosticConsumer DiagConsumer;
801 initializeScanCompilerInstance(PrescanCI, ScanFS, &DiagConsumer,
802 Worker.Service, Worker.DepFS);
803
804 // FIXME: reuse the StableDirs/PrebuiltModuleASTMap computed in
805 // initialize().
806 SmallVector<StringRef> PrescanStableDirs = getInitialStableDirs(PrescanCI);
807 if (!computePrebuiltModulesASTMap(PrescanCI, PrescanStableDirs))
808 return false;
809
811 PrescanCI.getLangOpts().CompilingPCH = true;
812
813 runTUModulePrescan(PrescanCI, Worker.Service, Controller, Compiles);
814 return true;
815 }
816
817public:
818 static std::optional<CompilerInstanceWithContext>
820 DependencyScanningWorker &Worker, StringRef CWD,
821 ArrayRef<std::string> CC1CommandLine, DiagnosticsEngine &DiagEngine,
823 DependencyActionController &Controller) {
824 CompilerInstanceWithContext CIWC(Worker, CWD, CC1CommandLine);
825 if (!CIWC.initialize(Controller, DiagEngine, std::move(OverlayFS)))
826 return std::nullopt;
827 return std::move(CIWC);
828 }
829
830 bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,
831 DependencyActionController &Controller) {
832 Worker.Service.getLogger().log() << "start scan_by_name: " << ModuleName;
833 llvm::scope_exit ExitLogging([&] {
834 Worker.Service.getLogger().log() << "finish scan_by_name: " << ModuleName;
835 });
837 llvm::report_fatal_error("exceeded maximum by-name scans for worker");
838
839 assert(CIPtr && "CIPtr must be initialized before calling this method");
840 auto &CI = *CIPtr;
841
842 // We need to reset the diagnostics, so that the diagnostics issued
843 // during a previous computeDependencies call do not affect the current
844 // call. If we do not reset, we may inherit fatal errors from a previous
845 // call.
846 CI.getDiagnostics().Reset();
847
848 // We create this cleanup object because computeDependencies may exit
849 // early with errors.
850 llvm::scope_exit CleanUp([&]() {
852 // The preprocessor may not be created at the entry of this method,
853 // but it must have been created when this method returns, whether
854 // there are errors during scanning or not.
856 });
857
859 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
860 Worker.Service,
861 /* The MDC's constructor makes a copy of the OriginalInvocation, so
862 we can pass it in without worrying that it might be changed across
863 invocations of computeDependencies. */
864 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
865
866 CompilerInvocation ModuleInvocation(*OriginalInvocation);
867 if (!Controller.initialize(CI, ModuleInvocation))
868 return false;
869
870 if (!SrcLocOffset) {
871 // When SrcLocOffset is zero, we are at the beginning of the fake source
872 // file. In this case, we call BeginSourceFile to initialize.
873 std::unique_ptr<FrontendAction> Action =
874 std::make_unique<PreprocessOnlyAction>();
875 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
876 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
877 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
878 (void)ActionBeginSucceeded;
879 }
880
881 Preprocessor &PP = CI.getPreprocessor();
883 FileID MainFileID = SM.getMainFileID();
884 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
885 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
886 PPCallbacks *CB = nullptr;
887 if (!SrcLocOffset) {
888 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
889 // the preprocessor.
890 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
891 assert(!PPFailed && "Preprocess must be able to enter the main file.");
892 (void)PPFailed;
893 CB = MDC->getPPCallbacks();
894 } else {
895 // When SrcLocOffset is non-zero, the preprocessor has already been
896 // initialized through a previous call of computeDependencies. We want to
897 // preserve the PP's state, hence we do not call EnterSourceFile again.
898 MDC->attachToPreprocessor(PP);
899 CB = MDC->getPPCallbacks();
900
901 FileID PrevFID;
903 SM.getFileCharacteristic(IDLocation);
904 CB->LexedFileChanged(MainFileID,
906 FileType, PrevFID, IDLocation);
907 }
908
909 // FIXME: Scan modules asynchronously here as well.
910
911 SrcLocOffset++;
913 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
914 Path.emplace_back(IDLocation, ModuleID);
915 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
916
917 assert(CB && "Must have PPCallbacks after module loading");
918 CB->moduleImport(SourceLocation(), Path, ModResult);
919
920 if (!ModResult)
921 return false;
922
924 return false;
925
926 MDC->run(Consumer);
927 MDC->applyDiscoveredDependencies(ModuleInvocation);
928
929 bool Success = ModuleInvocation.withCowRef<bool>(
930 [&](CowCompilerInvocation &CowModuleInvocation) {
931 return Controller.finalize(CI, CowModuleInvocation);
932 });
933 if (!Success)
934 return false;
935
936 Consumer.handleBuildCommand(
937 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
938
939 return true;
940 }
941
942 std::shared_ptr<ModuleDepCollector>
944 DependencyActionController &Controller) {
945 assert(CIPtr && "CIPtr must be initialized before calling this method");
946 auto &CI = *CIPtr;
947
948 std::optional<AsyncModuleCompiles> AsyncCompiles;
949 if (Worker.Service.getOpts().AsyncScanModules) {
950 AsyncCompiles.emplace();
951 if (!prescanModulesAsync(*AsyncCompiles, Controller))
952 return nullptr;
953 }
954
956 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
957 Worker.Service, *OriginalInvocation, Controller, PrebuiltModuleASTMap,
958 StableDirs);
959
961 return nullptr;
962
963 if (!Controller.initialize(CI, *OriginalInvocation))
964 return nullptr;
965
967 if (!CI.ExecuteAction(Action))
968 return nullptr;
969
970 MDC->run(Consumer);
971 if (!applyAndReport(*MDC, *OriginalInvocation, Consumer, Controller,
972 CommandLine[0]))
973 return nullptr;
974 return MDC;
975 }
976
978 CompilerInvocation &ModuleInvocation,
979 DependencyConsumer &Consumer,
980 DependencyActionController &Controller,
981 StringRef Executable) {
982 MDC.applyDiscoveredDependencies(ModuleInvocation);
983 bool Success = ModuleInvocation.withCowRef<bool>(
984 [&](CowCompilerInvocation &CowModuleInvocation) {
985 return Controller.finalize(*CIPtr, CowModuleInvocation);
986 });
987 if (!Success)
988 return false;
989 Consumer.handleBuildCommand(
990 {Executable.str(), ModuleInvocation.getCC1CommandLine()});
991 return true;
992 }
993};
994} // namespace dependencies
995} // namespace clang
996
999 : Service(Service) {
1000 PCHContainerOps = std::make_shared<PCHContainerOperations>();
1001 // We need to read object files from PCH built outside the scanner.
1002 PCHContainerOps->registerReader(
1003 std::make_unique<ObjectFilePCHContainerReader>());
1004 // The scanner itself writes only raw ast files.
1005 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
1006
1007 auto BaseFS = Service.getOpts().MakeVFS();
1008
1009 if (Service.getOpts().TraceVFS) {
1010 TracingFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
1011 std::move(BaseFS));
1012 BaseFS = TracingFS;
1013 }
1014
1015 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
1016 Service, std::move(BaseFS));
1017}
1018
1020
1023 StringRef WorkingDirectory,
1026 if (OverlayFS) {
1027 auto NewFS =
1028 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(FS));
1029 NewFS->pushOverlay(std::move(OverlayFS));
1030 FS = std::move(NewFS);
1031 }
1032 FS->setCurrentWorkingDirectory(WorkingDirectory);
1033 return FS;
1034}
1035
1037 StringRef WorkingDirectory, ArrayRef<ArrayRef<std::string>> CommandLines,
1038 DependencyConsumer &DepConsumer, DependencyActionController &Controller,
1039 DiagnosticConsumer &DiagConsumer,
1041 auto FS = makeEffectiveVFS(WorkingDirectory, OverlayFS);
1042
1043 bool Scanned = false;
1044 std::shared_ptr<ModuleDepCollector> MDC;
1045 std::optional<CompilerInstanceWithContext> CIWC;
1046
1047 const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) {
1048 if (StringRef(Cmd[1]) != "-cc1") {
1049 // Non-clang command. Just pass through to the dependency consumer.
1050 DepConsumer.handleBuildCommand(
1051 {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}});
1052 return true;
1053 }
1054
1055 Service.getLogger().log().logArray("starting scanning command:", " ", Cmd);
1056 llvm::scope_exit ExitLogging([&] {
1057 Service.getLogger().log().logArray("finished scanning command:", " ",
1058 Cmd);
1059 });
1060
1061 auto DiagOpts = createScanningDiagOptions(Cmd);
1062 auto DiagEngine =
1063 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
1064 /*ShouldOwnClient=*/false);
1065 if (!Scanned) {
1066 // Scanning runs once for the first -cc1 invocation in a chain of driver
1067 // jobs.
1068 // For any dependent jobs, reuse the scanning result and just update the
1069 // new invocation.
1070 // FIXME: to support multi-arch builds, each arch requires a separate
1071 // scan.
1072 Scanned = true;
1074 *this, WorkingDirectory, Cmd, *DiagEngine, OverlayFS, Controller);
1075 if (!Result)
1076 return false;
1077 CIWC.emplace(std::move(*Result));
1078 MDC = CIWC->scanTranslationUnit(DepConsumer, Controller);
1079 return MDC != nullptr;
1080 }
1081
1082 auto Invocation = createCompilerInvocation(Cmd, *DiagEngine);
1083 if (!Invocation)
1084 return false;
1085
1086 // The first cc1 is canonicalized in initializeScanInstance; each sibling
1087 // invocation must likewise be canonicalized before its cc1 command line is
1088 // emitted. This is mostly relevant for multi-arch jobs where we currently
1089 // do not do re-scans.
1090 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
1091 canonicalizeDefines(Invocation->getPreprocessorOpts());
1092
1093 assert(CIWC && "Must have an initialized CIWC");
1094 return CIWC->applyAndReport(*MDC, *Invocation, DepConsumer, Controller,
1095 Cmd.front());
1096 });
1097
1098 return Success && Scanned;
1099}
1100
1102 StringRef CWD, ArrayRef<std::string> CC1CommandLine,
1104 DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
1105 llvm::function_ref<std::optional<std::string>()> getNextName,
1106 DependencyConsumer &DepConsumer) {
1107 auto FS = makeEffectiveVFS(CWD, OverlayFS);
1108 auto DiagOpts = createScanningDiagOptions(CC1CommandLine);
1109 auto DiagEngine =
1110 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
1111 /*ShouldOwnClient=*/false);
1112 std::optional<CompilerInstanceWithContext> CIWC =
1114 *this, CWD, CC1CommandLine, *DiagEngine, std::move(OverlayFS),
1115 Controller);
1116 if (!CIWC)
1117 return false;
1118
1119 bool AllScansSucceeded = true;
1120 while (std::optional<std::string> NextName = getNextName()) {
1121 bool Success =
1122 CIWC->computeDependencies(*NextName, DepConsumer, Controller);
1123 DepConsumer.finishQuery(*NextName, Success);
1124 AllScansSucceeded = AllScansSucceeded && Success;
1125 }
1126 return AllScansSucceeded;
1127}
Defines the Diagnostic-related interfaces.
static std::shared_ptr< ModuleDepCollector > initializeScanInstanceDependencyCollector(CompilerInstance &ScanInstance, std::unique_ptr< DependencyOutputOptions > DepOutputOpts, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, SmallVector< StringRef > &StableDirs)
static std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
static std::unique_ptr< DependencyOutputOptions > createDependencyOutputOptions(const CompilerInvocation &Invocation)
static std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service, DependencyActionController &Controller)
static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts, const HeaderSearchOptions &ExistingHSOpts, DiagnosticsEngine *Diags, const LangOptions &LangOpts)
static std::string deduceDepTarget(const std::string &OutputFile, const SmallVectorImpl< FrontendInputFile > &InputFiles)
Deduce the dependency target based on the output file and input files.
static std::optional< PrebuiltModulesAttrsMap > computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, llvm::SmallVector< StringRef > &StableDirs)
static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename, CompilerInstance &CI, PrebuiltModuleFilesT &ModuleFiles, PrebuiltModulesAttrsMap &PrebuiltModulesASTMap, DiagnosticsEngine &Diags, const ArrayRef< StringRef > StableDirs)
Visit the given prebuilt module and collect all of the modules it transitively imports and contributi...
static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts)
Sanitize diagnostic options for dependency scan.
static void runTUModulePrescan(CompilerInstance &PrescanCI, DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
static void initializeScanCompilerInstance(CompilerInstance &ScanInstance, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr< DependencyScanningWorkerFilesystem > DepFS)
static llvm::SmallVector< StringRef > getInitialStableDirs(const CompilerInstance &ScanInstance)
static void canonicalizeDefines(PreprocessorOptions &PPOpts)
static std::string makeObjFileName(StringRef FileName)
Transform arbitrary file name into an object-like file name.
static std::optional< StringRef > getSimpleMacroName(StringRef Macro)
Defines the clang::Preprocessor interface.
This file declares semantic analysis for OpenACC constructs and clauses.
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:1828
@ 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:1832
@ 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:1845
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
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()
R withCowRef(llvm::function_ref< R(CowCompilerInvocation &)> Fn)
Invokes the Fn with CowCompilerInvocation representing this.
FrontendOptions & getFrontendOpts()
Same as CompilerInvocation, but with copy-on-write optimization.
Functor that returns the dependency directives for a given file.
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:241
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
Definition Diagnostic.h:913
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition Diagnostic.h:721
DiagnosticConsumer * getClient()
Definition Diagnostic.h:645
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::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.).
ModuleFileName 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...
void logArray(StringRef Prefix, StringRef Sep, const RangeT &Arr)
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.
static ModuleFileName makeExplicit(std::string Name)
Creates a file name for an explicit module.
Definition Module.h:142
StringRef str() const
Returns the plain module file name.
Definition Module.h:188
void setBuildingModule(bool BuildingModuleFlag)
Flag indicating whether this instance is building a module.
@ Hidden
All of the names in this module are hidden.
Definition Module.h:648
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition Module.h:943
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
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.
FileID getMainFileID() const
Returns the FileID of the main source file.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
The base class of the type hierarchy.
Definition TypeBase.h:1879
std::shared_ptr< ModuleDepCollector > scanTranslationUnit(DependencyConsumer &Consumer, DependencyActionController &Controller)
bool applyAndReport(ModuleDepCollector &MDC, CompilerInvocation &ModuleInvocation, DependencyConsumer &Consumer, DependencyActionController &Controller, StringRef Executable)
bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller)
static std::optional< CompilerInstanceWithContext > initializeFromCC1Commandline(DependencyScanningWorker &Worker, StringRef CWD, ArrayRef< std::string > CC1CommandLine, DiagnosticsEngine &DiagEngine, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS, DependencyActionController &Controller)
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.
virtual bool initialize(CompilerInstance &ScanInstance, CompilerInvocation &NewInvocation)
Initializes the scan instance and modifies the resulting TU invocation.
virtual bool finalize(CompilerInstance &ScanInstance, CowCompilerInvocation &NewInvocation)
Finalizes the scan instance and modifies the resulting TU invocation.
virtual void handleBuildCommand(Command Cmd)
virtual void finishQuery(StringRef ModuleName, bool Success)
The dependency scanning service contains shared configuration and state that is used by the individua...
const DependencyScanningServiceOptions & getOpts() const
An individual dependency scanning worker that is able to run on its own thread.
DependencyScanningWorker(DependencyScanningService &Service)
Construct a dependency scanning worker.
bool computeDependenciesByName(StringRef CWD, ArrayRef< std::string > CC1CommandLine, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS, DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller, llvm::function_ref< std::optional< std::string >()> getNextName, DependencyConsumer &DepConsumer)
By-name scanning over a single cc1 command line.
bool computeDependencies(StringRef WorkingDirectory, ArrayRef< ArrayRef< std::string > > CommandLines, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS=nullptr)
Run the dependency scanning tool for all given frontend command-lines, and report the discovered depe...
IntrusiveRefCntPtr< llvm::vfs::FileSystem > makeEffectiveVFS(StringRef WorkingDirectory, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS=nullptr) const
Creates the effective VFS that will be used for the scan.
Collects modular and non-modular dependencies of the main file by attaching ModuleDepCollectorPP to t...
void applyDiscoveredDependencies(CompilerInvocation &CI)
Apply any changes implied by the discovered dependencies to the given invocation, (e....
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...
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.
@ HeaderSearch
Remove unused header search paths including header maps.
llvm::StringMap< PrebuiltModuleASTAttrs > PrebuiltModulesAttrsMap
Attributes loaded from AST files of prebuilt modules collected prior to ModuleDepCollector creation.
std::unique_ptr< DiagnosticOptions > createScanningDiagOptions(ArrayRef< std::string > CommandLine)
std::shared_ptr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries, AtomicLineLogger &Logger)
bool isPathInStableDir(const ArrayRef< StringRef > Directories, const StringRef Input)
Determine if Input can be resolved within a stable directory.
@ GeneratePCH
Generate pre-compiled header.
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:44
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition ModuleFile.h:49
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition ModuleFile.h:46
Top level wrappers for InstallAPI frontend operations.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
Definition Parser.h:65
@ Worker
'worker' clause, allowed on 'loop', Combined, and 'routine' directives.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
Definition Linkage.h:54
@ Result
The result type of a method or function.
Definition TypeBase.h:906
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
unsigned long uint64_t
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
ScanningMode Mode
Whether to use optimized dependency directive scan or full preprocessing.
bool ValidateAgainstInvalidatedPaths
Whether scanning modules validate their directory deps against paths reported via DependencyScanningS...
bool EmitWarnings
Whether the scanner should emit warnings.
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.
This is used to identify a specific module.